From 26e09279f3cd12324657011c640972e297928f53 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Mon, 3 May 2021 16:42:46 +0200 Subject: cmake: Nearly full cmake build Had to rename a lot of things to conform with the standard Qt module layout that the cmake system expects: - all non-manual tests were moved to a sub-dir named auto/ - the benchmark was moved to tests/ - the 3rdparty folder was moved into src/ Other changes: - libyaml was updated to 2.2.5 while fixing a weird build issue that led to crashes on 64bit systems. - fixed build issues with the new 8.1 MingW compiler. - added support for QT_NO_OPENGL builds. The remaining issues are: - examples still don't build with qmake due to a potential bug in module.pri generation. - tests do run, but the test data is not generated yet dynamically. - qml-only tests are not built and run yet. - qml-only examples are not built yet. Fixes: AUTOSUITE-1632 Change-Id: Ic5fe0148e738b05835c73bed78e624b55861b75e Reviewed-by: Qt CI Bot Reviewed-by: Dominik Holland --- .cmake.conf | 1 + 3rdparty/README.md | 73 - 3rdparty/libarchive.pri | 9 - 3rdparty/libarchive/COPYING | 59 - 3rdparty/libarchive/INSTALL | 35 - 3rdparty/libarchive/NEWS | 687 ---- 3rdparty/libarchive/README.md | 222 - 3rdparty/libarchive/config-android.h | 153 - 3rdparty/libarchive/config-ios.h | 1098 ----- 3rdparty/libarchive/config-macos.h | 1098 ----- 3rdparty/libarchive/config-unix.h | 1096 ----- 3rdparty/libarchive/config-windows.h | 1149 ------ 3rdparty/libarchive/libarchive.pro | 126 - 3rdparty/libarchive/libarchive/android_lf.h | 47 - 3rdparty/libarchive/libarchive/archive.h | 1187 ------ 3rdparty/libarchive/libarchive/archive_acl.c | 2069 ---------- .../libarchive/libarchive/archive_acl_private.h | 83 - .../libarchive/libarchive/archive_check_magic.c | 175 - 3rdparty/libarchive/libarchive/archive_cmdline.c | 227 - .../libarchive/archive_cmdline_private.h | 47 - 3rdparty/libarchive/libarchive/archive_crc32.h | 78 - 3rdparty/libarchive/libarchive/archive_endian.h | 196 - 3rdparty/libarchive/libarchive/archive_entry.c | 2038 --------- 3rdparty/libarchive/libarchive/archive_entry.h | 702 ---- .../libarchive/archive_entry_copy_bhfi.c | 75 - .../libarchive/archive_entry_copy_stat.c | 83 - .../libarchive/archive_entry_link_resolver.c | 447 -- .../libarchive/libarchive/archive_entry_locale.h | 92 - .../libarchive/libarchive/archive_entry_private.h | 181 - .../libarchive/libarchive/archive_entry_sparse.c | 156 - .../libarchive/libarchive/archive_entry_stat.c | 118 - .../libarchive/libarchive/archive_entry_strmode.c | 87 - .../libarchive/libarchive/archive_entry_xattr.c | 156 - 3rdparty/libarchive/libarchive/archive_getdate.c | 1038 ----- 3rdparty/libarchive/libarchive/archive_getdate.h | 39 - 3rdparty/libarchive/libarchive/archive_match.c | 1846 --------- 3rdparty/libarchive/libarchive/archive_options.c | 218 - .../libarchive/archive_options_private.h | 47 - 3rdparty/libarchive/libarchive/archive_pack_dev.h | 49 - 3rdparty/libarchive/libarchive/archive_pathmatch.c | 459 --- 3rdparty/libarchive/libarchive/archive_pathmatch.h | 52 - 3rdparty/libarchive/libarchive/archive_platform.h | 183 - .../libarchive/libarchive/archive_platform_acl.h | 49 - 3rdparty/libarchive/libarchive/archive_ppmd7.c | 1168 ------ .../libarchive/libarchive/archive_ppmd7_private.h | 119 - .../libarchive/libarchive/archive_ppmd_private.h | 158 - 3rdparty/libarchive/libarchive/archive_private.h | 171 - 3rdparty/libarchive/libarchive/archive_random.c | 272 -- .../libarchive/libarchive/archive_random_private.h | 36 - 3rdparty/libarchive/libarchive/archive_rb.c | 709 ---- 3rdparty/libarchive/libarchive/archive_rb.h | 100 - 3rdparty/libarchive/libarchive/archive_read.c | 1739 -------- .../libarchive/archive_read_append_filter.c | 200 - .../libarchive/archive_read_data_into_fd.c | 139 - .../libarchive/archive_read_disk_entry_from_file.c | 1041 ----- .../libarchive/archive_read_disk_posix.c | 2661 ------------ .../libarchive/archive_read_disk_private.h | 98 - .../archive_read_disk_set_standard_lookup.c | 313 -- .../libarchive/archive_read_disk_windows.c | 2298 ----------- .../libarchive/libarchive/archive_read_extract.c | 60 - .../libarchive/libarchive/archive_read_open_fd.c | 211 - .../libarchive/libarchive/archive_read_open_file.c | 181 - .../libarchive/archive_read_open_filename.c | 582 --- .../libarchive/archive_read_open_memory.c | 186 - .../libarchive/libarchive/archive_read_private.h | 263 -- .../libarchive/archive_read_set_format.c | 105 - .../libarchive/archive_read_set_options.c | 155 - .../libarchive/archive_read_support_filter_bzip2.c | 371 -- .../libarchive/archive_read_support_filter_gzip.c | 477 --- .../libarchive/archive_read_support_filter_none.c | 52 - .../archive_read_support_filter_program.c | 518 --- .../libarchive/archive_read_support_filter_xz.c | 796 ---- .../archive_read_support_format_by_code.c | 74 - .../libarchive/archive_read_support_format_empty.c | 96 - .../libarchive/archive_read_support_format_tar.c | 2883 ------------- 3rdparty/libarchive/libarchive/archive_string.c | 4207 ------------------- 3rdparty/libarchive/libarchive/archive_string.h | 243 -- .../libarchive/archive_string_composition.h | 2292 ----------- .../libarchive/libarchive/archive_string_sprintf.c | 192 - 3rdparty/libarchive/libarchive/archive_util.c | 585 --- 3rdparty/libarchive/libarchive/archive_virtual.c | 162 - 3rdparty/libarchive/libarchive/archive_windows.c | 908 ---- 3rdparty/libarchive/libarchive/archive_windows.h | 318 -- 3rdparty/libarchive/libarchive/archive_write.c | 734 ---- .../libarchive/archive_write_add_filter.c | 71 - .../archive_write_add_filter_b64encode.c | 314 -- .../libarchive/archive_write_add_filter_by_name.c | 76 - .../libarchive/archive_write_add_filter_bzip2.c | 407 -- .../libarchive/archive_write_add_filter_gzip.c | 442 -- .../libarchive/archive_write_add_filter_none.c | 43 - .../libarchive/archive_write_add_filter_program.c | 415 -- .../libarchive/archive_write_add_filter_xz.c | 547 --- .../libarchive/archive_write_disk_posix.c | 4327 -------------------- .../libarchive/archive_write_disk_private.h | 45 - .../archive_write_disk_set_standard_lookup.c | 265 -- .../libarchive/archive_write_disk_windows.c | 2511 ------------ .../libarchive/libarchive/archive_write_open_fd.c | 144 - .../libarchive/archive_write_open_file.c | 109 - .../libarchive/archive_write_open_filename.c | 253 -- .../libarchive/archive_write_open_memory.c | 113 - .../libarchive/libarchive/archive_write_private.h | 160 - .../libarchive/archive_write_set_format.c | 78 - .../libarchive/archive_write_set_format_by_name.c | 92 - .../libarchive/archive_write_set_format_gnutar.c | 763 ---- .../libarchive/archive_write_set_format_ustar.c | 763 ---- .../libarchive/archive_write_set_options.c | 130 - 3rdparty/libarchive/libarchive/config_freebsd.h | 259 -- 3rdparty/libarchive/libarchive/filter_fork.h | 41 - 3rdparty/libarchive/libarchive/filter_fork_posix.c | 238 -- .../libarchive/libarchive/filter_fork_windows.c | 190 - 3rdparty/libarchive/qt_attribution.json | 15 - 3rdparty/libbacktrace.pri | 2 - 3rdparty/libbacktrace/LICENSE | 30 - 3rdparty/libbacktrace/README.md | 25 - 3rdparty/libbacktrace/auxincl/dwarf2.h | 109 - 3rdparty/libbacktrace/auxincl/filenames.h | 41 - 3rdparty/libbacktrace/libbacktrace.pro | 47 - 3rdparty/libbacktrace/libbacktrace/ChangeLog | 590 --- 3rdparty/libbacktrace/libbacktrace/README | 23 - 3rdparty/libbacktrace/libbacktrace/atomic.c | 113 - .../libbacktrace/backtrace-supported.h | 3 - 3rdparty/libbacktrace/libbacktrace/backtrace.c | 129 - 3rdparty/libbacktrace/libbacktrace/backtrace.h | 188 - 3rdparty/libbacktrace/libbacktrace/config.h | 9 - 3rdparty/libbacktrace/libbacktrace/dwarf.c | 4280 ------------------- 3rdparty/libbacktrace/libbacktrace/elf.c | 3435 ---------------- 3rdparty/libbacktrace/libbacktrace/fileline.c | 201 - 3rdparty/libbacktrace/libbacktrace/internal.h | 338 -- 3rdparty/libbacktrace/libbacktrace/macho.c | 1471 ------- 3rdparty/libbacktrace/libbacktrace/mmap.c | 327 -- 3rdparty/libbacktrace/libbacktrace/mmapio.c | 106 - 3rdparty/libbacktrace/libbacktrace/posix.c | 100 - 3rdparty/libbacktrace/libbacktrace/print.c | 92 - 3rdparty/libbacktrace/libbacktrace/simple.c | 108 - 3rdparty/libbacktrace/libbacktrace/sort.c | 108 - 3rdparty/libbacktrace/libbacktrace/state.c | 72 - 3rdparty/libbacktrace/qt_attribution.json | 15 - 3rdparty/libyaml.pri | 7 - 3rdparty/libyaml/LICENSE | 20 - 3rdparty/libyaml/README | 27 - 3rdparty/libyaml/include/yaml.h | 1978 --------- 3rdparty/libyaml/libyaml.pro | 40 - 3rdparty/libyaml/qt_attribution.json | 16 - 3rdparty/libyaml/src/api.c | 1393 ------- 3rdparty/libyaml/src/dumper.c | 394 -- 3rdparty/libyaml/src/emitter.c | 2324 ----------- 3rdparty/libyaml/src/loader.c | 444 -- 3rdparty/libyaml/src/parser.c | 1372 ------- 3rdparty/libyaml/src/reader.c | 469 --- 3rdparty/libyaml/src/scanner.c | 3589 ---------------- 3rdparty/libyaml/src/writer.c | 141 - 3rdparty/libyaml/src/yaml_private.h | 684 ---- 3rdparty/libyaml/win32/config.h | 4 - 3rdparty/libz.pri | 8 - 3rdparty/stackwalker.pri | 2 - 3rdparty/stackwalker/LICENSE | 25 - 3rdparty/stackwalker/qt_attribution.json | 15 - 3rdparty/stackwalker/stackwalker.cpp | 1469 ------- 3rdparty/stackwalker/stackwalker.h | 255 -- 3rdparty/stackwalker/stackwalker.pro | 26 - CMakeLists.txt | 44 + benchmarks/appman-bench/README | 21 - benchmarks/appman-bench/am-config.yaml | 24 - benchmarks/appman-bench/appman-bench.pro | 10 - benchmarks/appman-bench/run.sh | 139 - benchmarks/appman-bench/system-ui/main.qml | 229 -- .../appman-bench/templates/appman-qml/icon.png | Bin 1486 -> 0 bytes .../appman-bench/templates/appman-qml/info.yaml | 9 - .../appman-bench/templates/appman-qml/main.qml | 79 - .../appman-bench/templates/qmlscene/icon.png | Bin 1486 -> 0 bytes .../appman-bench/templates/qmlscene/info.yaml | 13 - .../appman-bench/templates/qmlscene/main.qml | 72 - benchmarks/appman-bench/tests/controls2.qml | 57 - benchmarks/appman-bench/tests/rect.qml | 57 - benchmarks/appman-bench/tests/repeater.qml | 70 - benchmarks/appman-bench/tests/shader.qml | 89 - benchmarks/benchmarks.pro | 5 - cmake/FindWrapLibArchive.cmake | 18 + cmake/FindWrapLibYaml.cmake | 19 + cmake/QtAppManHelpers.cmake | 21 + coin/module_config.yaml | 23 + config.tests/libarchive/libarchive.pro | 8 - config.tests/libarchive/main.cpp | 40 - config.tests/libyaml/libyaml.pro | 8 - config.tests/libyaml/main.cpp | 40 - config.tests/touchemulation/main.cpp | 39 - config.tests/touchemulation/touchemulation.pro | 8 - configure.cmake | 21 + dependencies.yaml | 9 +- doc/CMakeLists.txt | 2 + examples/CMakeLists.txt | 7 + examples/applicationmanager/CMakeLists.txt | 15 + .../animated-windows/CMakeLists.txt | 35 + .../application-features/CMakeLists.txt | 30 + .../application-features/imports/CMakeLists.txt | 3 + .../imports/terminator2/CMakeLists.txt | 48 + .../application-features/native/CMakeLists.txt | 5 + .../native/widgets/CMakeLists.txt | 41 + examples/applicationmanager/applicationmanager.pro | 2 + .../custom-appman/CMakeLists.txt | 40 + .../applicationmanager/frame-timer/CMakeLists.txt | 35 + .../applicationmanager/hello-world/CMakeLists.txt | 35 + .../launch-intents/CMakeLists.txt | 35 + .../applicationmanager/minidesk/CMakeLists.txt | 35 + .../applicationmanager/multi-views/CMakeLists.txt | 35 + .../process-status/CMakeLists.txt | 35 + .../softwarecontainer-plugin/CMakeLists.txt | 39 + .../startup-plugin/CMakeLists.txt | 37 + qmake-features/CMakeLists.txt | 2 + qt_cmdline.cmake | 2 + src/3rdparty/CMakeLists.txt | 15 + src/3rdparty/README.md | 73 + src/3rdparty/libarchive/CMakeLists.txt | 158 + src/3rdparty/libarchive/COPYING | 59 + src/3rdparty/libarchive/INSTALL | 35 + src/3rdparty/libarchive/NEWS | 687 ++++ src/3rdparty/libarchive/README.md | 222 + src/3rdparty/libarchive/config-android.h | 153 + src/3rdparty/libarchive/config-ios.h | 1098 +++++ src/3rdparty/libarchive/config-macos.h | 1098 +++++ src/3rdparty/libarchive/config-unix.h | 1096 +++++ src/3rdparty/libarchive/config-windows.h | 1149 ++++++ src/3rdparty/libarchive/libarchive.pro | 126 + src/3rdparty/libarchive/libarchive/android_lf.h | 47 + src/3rdparty/libarchive/libarchive/archive.h | 1187 ++++++ src/3rdparty/libarchive/libarchive/archive_acl.c | 2069 ++++++++++ .../libarchive/libarchive/archive_acl_private.h | 83 + .../libarchive/libarchive/archive_check_magic.c | 175 + .../libarchive/libarchive/archive_cmdline.c | 227 + .../libarchive/archive_cmdline_private.h | 47 + src/3rdparty/libarchive/libarchive/archive_crc32.h | 78 + .../libarchive/libarchive/archive_endian.h | 196 + src/3rdparty/libarchive/libarchive/archive_entry.c | 2038 +++++++++ src/3rdparty/libarchive/libarchive/archive_entry.h | 702 ++++ .../libarchive/archive_entry_copy_bhfi.c | 75 + .../libarchive/archive_entry_copy_stat.c | 83 + .../libarchive/archive_entry_link_resolver.c | 447 ++ .../libarchive/libarchive/archive_entry_locale.h | 92 + .../libarchive/libarchive/archive_entry_private.h | 181 + .../libarchive/libarchive/archive_entry_sparse.c | 156 + .../libarchive/libarchive/archive_entry_stat.c | 118 + .../libarchive/libarchive/archive_entry_strmode.c | 87 + .../libarchive/libarchive/archive_entry_xattr.c | 156 + .../libarchive/libarchive/archive_getdate.c | 1038 +++++ .../libarchive/libarchive/archive_getdate.h | 39 + src/3rdparty/libarchive/libarchive/archive_match.c | 1846 +++++++++ .../libarchive/libarchive/archive_options.c | 218 + .../libarchive/archive_options_private.h | 47 + .../libarchive/libarchive/archive_pack_dev.h | 49 + .../libarchive/libarchive/archive_pathmatch.c | 459 +++ .../libarchive/libarchive/archive_pathmatch.h | 52 + .../libarchive/libarchive/archive_platform.h | 183 + .../libarchive/libarchive/archive_platform_acl.h | 49 + src/3rdparty/libarchive/libarchive/archive_ppmd7.c | 1168 ++++++ .../libarchive/libarchive/archive_ppmd7_private.h | 119 + .../libarchive/libarchive/archive_ppmd_private.h | 158 + .../libarchive/libarchive/archive_private.h | 171 + .../libarchive/libarchive/archive_random.c | 272 ++ .../libarchive/libarchive/archive_random_private.h | 36 + src/3rdparty/libarchive/libarchive/archive_rb.c | 709 ++++ src/3rdparty/libarchive/libarchive/archive_rb.h | 100 + src/3rdparty/libarchive/libarchive/archive_read.c | 1739 ++++++++ .../libarchive/archive_read_append_filter.c | 200 + .../libarchive/archive_read_data_into_fd.c | 139 + .../libarchive/archive_read_disk_entry_from_file.c | 1041 +++++ .../libarchive/archive_read_disk_posix.c | 2661 ++++++++++++ .../libarchive/archive_read_disk_private.h | 98 + .../archive_read_disk_set_standard_lookup.c | 313 ++ .../libarchive/archive_read_disk_windows.c | 2298 +++++++++++ .../libarchive/libarchive/archive_read_extract.c | 60 + .../libarchive/libarchive/archive_read_open_fd.c | 211 + .../libarchive/libarchive/archive_read_open_file.c | 181 + .../libarchive/archive_read_open_filename.c | 582 +++ .../libarchive/archive_read_open_memory.c | 186 + .../libarchive/libarchive/archive_read_private.h | 263 ++ .../libarchive/archive_read_set_format.c | 105 + .../libarchive/archive_read_set_options.c | 155 + .../libarchive/archive_read_support_filter_bzip2.c | 371 ++ .../libarchive/archive_read_support_filter_gzip.c | 477 +++ .../libarchive/archive_read_support_filter_none.c | 52 + .../archive_read_support_filter_program.c | 518 +++ .../libarchive/archive_read_support_filter_xz.c | 796 ++++ .../archive_read_support_format_by_code.c | 74 + .../libarchive/archive_read_support_format_empty.c | 96 + .../libarchive/archive_read_support_format_tar.c | 2883 +++++++++++++ .../libarchive/libarchive/archive_string.c | 4207 +++++++++++++++++++ .../libarchive/libarchive/archive_string.h | 243 ++ .../libarchive/archive_string_composition.h | 2292 +++++++++++ .../libarchive/libarchive/archive_string_sprintf.c | 192 + src/3rdparty/libarchive/libarchive/archive_util.c | 585 +++ .../libarchive/libarchive/archive_virtual.c | 162 + .../libarchive/libarchive/archive_windows.c | 908 ++++ .../libarchive/libarchive/archive_windows.h | 318 ++ src/3rdparty/libarchive/libarchive/archive_write.c | 734 ++++ .../libarchive/archive_write_add_filter.c | 71 + .../archive_write_add_filter_b64encode.c | 314 ++ .../libarchive/archive_write_add_filter_by_name.c | 76 + .../libarchive/archive_write_add_filter_bzip2.c | 407 ++ .../libarchive/archive_write_add_filter_gzip.c | 442 ++ .../libarchive/archive_write_add_filter_none.c | 43 + .../libarchive/archive_write_add_filter_program.c | 415 ++ .../libarchive/archive_write_add_filter_xz.c | 547 +++ .../libarchive/archive_write_disk_posix.c | 4327 ++++++++++++++++++++ .../libarchive/archive_write_disk_private.h | 45 + .../archive_write_disk_set_standard_lookup.c | 265 ++ .../libarchive/archive_write_disk_windows.c | 2511 ++++++++++++ .../libarchive/libarchive/archive_write_open_fd.c | 144 + .../libarchive/archive_write_open_file.c | 109 + .../libarchive/archive_write_open_filename.c | 253 ++ .../libarchive/archive_write_open_memory.c | 113 + .../libarchive/libarchive/archive_write_private.h | 160 + .../libarchive/archive_write_set_format.c | 78 + .../libarchive/archive_write_set_format_by_name.c | 92 + .../libarchive/archive_write_set_format_gnutar.c | 763 ++++ .../libarchive/archive_write_set_format_ustar.c | 763 ++++ .../libarchive/archive_write_set_options.c | 130 + .../libarchive/libarchive/config_freebsd.h | 259 ++ src/3rdparty/libarchive/libarchive/filter_fork.h | 41 + .../libarchive/libarchive/filter_fork_posix.c | 238 ++ .../libarchive/libarchive/filter_fork_windows.c | 190 + src/3rdparty/libarchive/qt_attribution.json | 15 + src/3rdparty/libbacktrace/CMakeLists.txt | 53 + src/3rdparty/libbacktrace/LICENSE | 30 + src/3rdparty/libbacktrace/README.md | 25 + src/3rdparty/libbacktrace/auxincl/dwarf2.h | 109 + src/3rdparty/libbacktrace/auxincl/filenames.h | 41 + src/3rdparty/libbacktrace/libbacktrace.pro | 47 + src/3rdparty/libbacktrace/libbacktrace/ChangeLog | 590 +++ src/3rdparty/libbacktrace/libbacktrace/README | 23 + src/3rdparty/libbacktrace/libbacktrace/atomic.c | 113 + .../libbacktrace/backtrace-supported.h | 3 + src/3rdparty/libbacktrace/libbacktrace/backtrace.c | 129 + src/3rdparty/libbacktrace/libbacktrace/backtrace.h | 188 + src/3rdparty/libbacktrace/libbacktrace/config.h | 9 + src/3rdparty/libbacktrace/libbacktrace/dwarf.c | 4280 +++++++++++++++++++ src/3rdparty/libbacktrace/libbacktrace/elf.c | 3435 ++++++++++++++++ src/3rdparty/libbacktrace/libbacktrace/fileline.c | 201 + src/3rdparty/libbacktrace/libbacktrace/internal.h | 338 ++ src/3rdparty/libbacktrace/libbacktrace/macho.c | 1471 +++++++ src/3rdparty/libbacktrace/libbacktrace/mmap.c | 327 ++ src/3rdparty/libbacktrace/libbacktrace/mmapio.c | 106 + src/3rdparty/libbacktrace/libbacktrace/posix.c | 100 + src/3rdparty/libbacktrace/libbacktrace/print.c | 92 + src/3rdparty/libbacktrace/libbacktrace/simple.c | 108 + src/3rdparty/libbacktrace/libbacktrace/sort.c | 108 + src/3rdparty/libbacktrace/libbacktrace/state.c | 72 + src/3rdparty/libbacktrace/qt_attribution.json | 15 + src/3rdparty/libyaml/CMakeLists.txt | 43 + src/3rdparty/libyaml/LICENSE | 20 + src/3rdparty/libyaml/README | 27 + src/3rdparty/libyaml/include/yaml.h | 1985 +++++++++ src/3rdparty/libyaml/libyaml.pro | 40 + src/3rdparty/libyaml/qt_attribution.json | 16 + src/3rdparty/libyaml/src/api.c | 1401 +++++++ src/3rdparty/libyaml/src/dumper.c | 394 ++ src/3rdparty/libyaml/src/emitter.c | 2358 +++++++++++ src/3rdparty/libyaml/src/loader.c | 544 +++ src/3rdparty/libyaml/src/parser.c | 1375 +++++++ src/3rdparty/libyaml/src/reader.c | 469 +++ src/3rdparty/libyaml/src/scanner.c | 3598 ++++++++++++++++ src/3rdparty/libyaml/src/writer.c | 141 + src/3rdparty/libyaml/src/yaml_private.h | 684 ++++ src/3rdparty/libyaml/win32/config.h | 4 + src/3rdparty/stackwalker/CMakeLists.txt | 24 + src/3rdparty/stackwalker/LICENSE | 25 + src/3rdparty/stackwalker/qt_attribution.json | 15 + src/3rdparty/stackwalker/stackwalker.cpp | 1469 +++++++ src/3rdparty/stackwalker/stackwalker.h | 255 ++ src/3rdparty/stackwalker/stackwalker.pro | 26 + src/CMakeLists.txt | 57 + src/application-lib/CMakeLists.txt | 29 + src/common-lib/CMakeLists.txt | 77 + src/common-lib/common-lib.pro | 6 +- src/common-lib/configure.cmake | 74 + src/common-lib/crashhandler.cpp | 9 +- src/common-lib/global.h | 3 +- src/common-lib/qt_cmdline.cmake | 8 + src/crypto-lib/CMakeLists.txt | 50 + src/dbus-lib/CMakeLists.txt | 66 + src/intent-client-lib/CMakeLists.txt | 26 + src/intent-server-lib/CMakeLists.txt | 27 + src/launcher-lib/CMakeLists.txt | 60 + src/main-lib/CMakeLists.txt | 55 + src/main-lib/main.h | 3 +- src/manager-lib/CMakeLists.txt | 90 + src/manager-lib/applicationipcinterface.cpp | 4 + src/manager-lib/scopeutilities.h | 3 +- src/monitor-lib/CMakeLists.txt | 28 + src/monitor-lib/systemreader.cpp | 2 + src/notification-lib/CMakeLists.txt | 22 + src/package-lib/CMakeLists.txt | 37 + src/package-lib/configure.cmake | 23 + src/package-lib/qt_cmdline.cmake | 1 + src/plugin-interfaces/CMakeLists.txt | 20 + src/shared-main-lib/CMakeLists.txt | 33 + src/shared-main-lib/sharedmain.cpp | 11 + src/tools/appman/CMakeLists.txt | 32 + src/tools/controller/CMakeLists.txt | 29 + src/tools/dumpqmltypes/CMakeLists.txt | 41 + src/tools/launcher-qml/CMakeLists.txt | 31 + src/tools/launcher-qml/launcher-qml.cpp | 3 +- src/tools/packager/CMakeLists.txt | 21 + src/tools/testrunner/CMakeLists.txt | 34 + src/tools/uploader/CMakeLists.txt | 20 + src/window-lib/CMakeLists.txt | 59 + src/window-lib/configure.cmake | 29 + src/window-lib/qt_cmdline.cmake | 1 + src/window-lib/touchemulation_x11_p.h | 1 + tests/CMakeLists.txt | 10 + tests/application/application.pro | 13 - tests/application/icon.png | Bin 68 -> 0 bytes tests/application/info.yaml | 10 - tests/application/tst_application.cpp | 135 - tests/application/tst_application.qrc | 5 - tests/applicationinfo/applicationinfo.pro | 10 - tests/applicationinfo/tst_applicationinfo.cpp | 216 - .../applicationinstaller/applicationinstaller.pro | 13 - .../tst_applicationinstaller.cpp | 793 ---- tests/auto/CMakeLists.txt | 23 + tests/auto/application/CMakeLists.txt | 30 + tests/auto/application/application.pro | 13 + tests/auto/application/icon.png | Bin 0 -> 68 bytes tests/auto/application/info.yaml | 10 + tests/auto/application/tst_application.cpp | 135 + tests/auto/application/tst_application.qrc | 5 + tests/auto/applicationinfo/CMakeLists.txt | 21 + tests/auto/applicationinfo/applicationinfo.pro | 10 + tests/auto/applicationinfo/tst_applicationinfo.cpp | 219 + tests/auto/applicationinstaller/CMakeLists.txt | 25 + .../applicationinstaller/applicationinstaller.pro | 13 + .../tst_applicationinstaller.cpp | 793 ++++ tests/auto/configuration/CMakeLists.txt | 31 + tests/auto/configuration/configuration.pro | 12 + tests/auto/configuration/data/config1.yaml | 98 + tests/auto/configuration/data/config2.yaml | 88 + tests/auto/configuration/data/empty.yaml | 3 + tests/auto/configuration/tst_configuration.cpp | 523 +++ tests/auto/cryptography/CMakeLists.txt | 20 + tests/auto/cryptography/cryptography.pro | 7 + tests/auto/cryptography/tst_cryptography.cpp | 62 + tests/auto/debugwrapper/CMakeLists.txt | 19 + tests/auto/debugwrapper/debugwrapper.pro | 8 + tests/auto/debugwrapper/tst_debugwrapper.cpp | 151 + tests/auto/error-checking.h | 45 + tests/auto/installationreport/CMakeLists.txt | 21 + .../auto/installationreport/installationreport.pro | 10 + .../installationreport/tst_installationreport.cpp | 118 + tests/auto/main/CMakeLists.txt | 39 + tests/auto/main/am-config.yaml | 10 + .../main/builtin-apps/hello-world.red/icon.png | Bin 0 -> 1027 bytes .../main/builtin-apps/hello-world.red/info.yaml | 24 + .../main/builtin-apps/hello-world.red/main.qml | 11 + .../apps/hello-world.red/.installation-report.yaml | 14 + .../apps/hello-world.red/icon.png | Bin 0 -> 1027 bytes .../apps/hello-world.red/info.yaml | 9 + .../apps/hello-world.red/main.qml | 11 + .../docs/hello-world.red/placeholder | 0 .../manifests/hello-world.red/icon.png | Bin 0 -> 1027 bytes .../manifests/hello-world.red/info.yaml | 9 + tests/auto/main/dummy.qml | 3 + tests/auto/main/main.pro | 20 + tests/auto/main/main.qrc | 5 + tests/auto/main/tst_main.cpp | 384 ++ tests/auto/packagecreator/CMakeLists.txt | 21 + tests/auto/packagecreator/packagecreator.pro | 10 + tests/auto/packagecreator/tst_packagecreator.cpp | 188 + tests/auto/packageextractor/CMakeLists.txt | 21 + tests/auto/packageextractor/packageextractor.pro | 10 + .../auto/packageextractor/tst_packageextractor.cpp | 312 ++ tests/auto/packager-tool/CMakeLists.txt | 23 + tests/auto/packager-tool/packager-tool.pro | 15 + tests/auto/packager-tool/tst_packager-tool.cpp | 414 ++ tests/auto/processreader/CMakeLists.txt | 23 + tests/auto/processreader/advanced.smaps | 252 ++ tests/auto/processreader/basic.smaps | 352 ++ tests/auto/processreader/invalid.smaps | 16 + tests/auto/processreader/processreader.pro | 11 + tests/auto/processreader/tst_processreader.cpp | 144 + tests/auto/qml/CMakeLists.txt | 18 + tests/auto/qml/configs/CMakeLists.txt | 23 + tests/auto/qml/configs/am-config-nodbus.yaml | 6 + tests/auto/qml/configs/am-config.yaml | 11 + .../auto/qml/configs/apps/test.configs.app/app.qml | 78 + .../qml/configs/apps/test.configs.app/icon.png | Bin 0 -> 1486 bytes .../qml/configs/apps/test.configs.app/info.yaml | 9 + tests/auto/qml/configs/configs.pro | 15 + tests/auto/qml/configs/tst_configs.qml | 116 + tests/auto/qml/crash/CMakeLists.txt | 17 + tests/auto/qml/crash/am-config.yaml | 8 + tests/auto/qml/crash/apps/tld.test.crash/app.qml | 57 + tests/auto/qml/crash/apps/tld.test.crash/icon.png | Bin 0 -> 1486 bytes tests/auto/qml/crash/apps/tld.test.crash/info.yaml | 12 + .../apps/tld.test.crash/terminator2/CMakeLists.txt | 30 + .../tld.test.crash/terminator2/Terminator/qmldir | 2 + .../crash/apps/tld.test.crash/terminator2/qmldir | 2 + .../tld.test.crash/terminator2/qmlterminator2.cpp | 114 + .../tld.test.crash/terminator2/qmlterminator2.h | 75 + .../tld.test.crash/terminator2/terminator2.pro | 18 + tests/auto/qml/crash/crash.pro | 5 + tests/auto/qml/crash/tst_crash.qml | 83 + tests/auto/qml/installer/CMakeLists.txt | 16 + tests/auto/qml/installer/am-config.yaml | 10 + .../qml/installer/apps/hello-world.red/app1.qml | 35 + .../qml/installer/apps/hello-world.red/icon1.png | Bin 0 -> 1486 bytes .../qml/installer/apps/hello-world.red/info.yaml | 10 + tests/auto/qml/installer/installer.pro | 6 + tests/auto/qml/installer/tst_installer.qml | 252 ++ tests/auto/qml/intents/CMakeLists.txt | 23 + tests/auto/qml/intents/am-config-quick.yaml | 6 + tests/auto/qml/intents/am-config.yaml | 23 + .../qml/intents/apps/cannot-start/cannot-start | 1 + tests/auto/qml/intents/apps/cannot-start/icon.png | Bin 0 -> 5138 bytes tests/auto/qml/intents/apps/cannot-start/info.yaml | 12 + tests/auto/qml/intents/apps/intents1/icon.png | Bin 0 -> 5138 bytes tests/auto/qml/intents/apps/intents1/info.yaml | 20 + tests/auto/qml/intents/apps/intents1/intents1.qml | 59 + tests/auto/qml/intents/apps/intents2/icon.png | Bin 0 -> 5138 bytes tests/auto/qml/intents/apps/intents2/info.yaml | 16 + tests/auto/qml/intents/apps/intents2/intents2.qml | 54 + tests/auto/qml/intents/intents.pro | 12 + tests/auto/qml/intents/tst_intents.qml | 241 ++ tests/auto/qml/lifecycle/CMakeLists.txt | 16 + tests/auto/qml/lifecycle/am-config.yaml | 8 + .../qml/lifecycle/apps/tld.test.lifecycle/app.qml | 39 + .../qml/lifecycle/apps/tld.test.lifecycle/icon.png | Bin 0 -> 1486 bytes .../lifecycle/apps/tld.test.lifecycle/info.yaml | 9 + tests/auto/qml/lifecycle/lifecycle.pro | 5 + tests/auto/qml/lifecycle/tst_lifecycle.qml | 134 + tests/auto/qml/processtitle/CMakeLists.txt | 17 + tests/auto/qml/processtitle/am-config-quick.yaml | 10 + tests/auto/qml/processtitle/am-config.yaml | 5 + .../app.qml | 39 + .../icon.png | Bin 0 -> 1486 bytes .../info.yaml | 9 + .../apps/test.processtitle.app/app.qml | 39 + .../apps/test.processtitle.app/icon.png | Bin 0 -> 1486 bytes .../apps/test.processtitle.app/info.yaml | 9 + tests/auto/qml/processtitle/processtitle.pro | 7 + tests/auto/qml/processtitle/tst_processtitle.qml | 105 + tests/auto/qml/qml.pro | 20 + tests/auto/qml/quicklaunch/CMakeLists.txt | 16 + tests/auto/qml/quicklaunch/am-config.yaml | 9 + .../quicklaunch/apps/tld.test.quicklaunch/app.qml | 42 + .../quicklaunch/apps/tld.test.quicklaunch/icon.png | Bin 0 -> 1486 bytes .../apps/tld.test.quicklaunch/info.yaml | 10 + tests/auto/qml/quicklaunch/quicklaunch.pro | 5 + tests/auto/qml/quicklaunch/tst_quicklaunch.qml | 89 + tests/auto/qml/resources/CMakeLists.txt | 37 + tests/auto/qml/resources/am-config.yaml | 22 + tests/auto/qml/resources/appcommon/CMakeLists.txt | 2 + tests/auto/qml/resources/appcommon/Quicklaunch.qml | 36 + tests/auto/qml/resources/appcommon/appcommon.pro | 7 + .../auto/qml/resources/appcommon/appcommonfile.qrc | 7 + .../resources/appcommon/qml/common/CommonObj.qml | 35 + .../auto/qml/resources/appcommon/qml/common/qmldir | 2 + tests/auto/qml/resources/apps/app1/CMakeLists.txt | 32 + tests/auto/qml/resources/apps/app1/app1.pro | 11 + tests/auto/qml/resources/apps/app1/app1.qml | 39 + tests/auto/qml/resources/apps/app1/app1file.qrc | 7 + tests/auto/qml/resources/apps/app1/app1plugin.qrc | 5 + tests/auto/qml/resources/apps/app1/icon.png | Bin 0 -> 1486 bytes tests/auto/qml/resources/apps/app1/info.yaml | 17 + .../qml/resources/apps/app1/qml/forms/AquaRect.qml | 35 + .../resources/apps/app1/qml/forms/YellowRect.qml | 35 + .../auto/qml/resources/apps/app1/qml/forms/qmldir | 4 + tests/auto/qml/resources/apps/app2/BlueRect.qml | 35 + tests/auto/qml/resources/apps/app2/CMakeLists.txt | 2 + tests/auto/qml/resources/apps/app2/app2.pro | 8 + tests/auto/qml/resources/apps/app2/app2.qml | 46 + tests/auto/qml/resources/apps/app2/app2.qrc | 6 + tests/auto/qml/resources/apps/app2/icon.png | Bin 0 -> 1486 bytes tests/auto/qml/resources/apps/app2/info.yaml | 15 + .../apps/app2/qml/appwidgets/GreenRect.qml | 35 + .../qml/resources/apps/app2/qml/appwidgets/qmldir | 2 + .../auto/qml/resources/qml/widgets/MagentaRect.qml | 35 + tests/auto/qml/resources/qml/widgets/RedRect.qml | 35 + tests/auto/qml/resources/qml/widgets/qmldir | 3 + .../qml/resources/relative/elements/LinenRect.qml | 35 + tests/auto/qml/resources/relative/elements/qmldir | 2 + tests/auto/qml/resources/resources.pro | 5 + tests/auto/qml/resources/systemuifile.qrc | 6 + tests/auto/qml/resources/systemuiplugin.qrc | 5 + tests/auto/qml/resources/test.pro | 18 + tests/auto/qml/resources/tst_resource.qml | 81 + tests/auto/qml/simple/CMakeLists.txt | 16 + tests/auto/qml/simple/am-config.yaml | 56 + .../auto/qml/simple/apps/tld.test.simple1/app1.qml | 50 + .../auto/qml/simple/apps/tld.test.simple1/icon.png | Bin 0 -> 5138 bytes .../qml/simple/apps/tld.test.simple1/info.yaml | 23 + .../auto/qml/simple/apps/tld.test.simple2/app.qml | 50 + .../auto/qml/simple/apps/tld.test.simple2/icon.png | Bin 0 -> 5138 bytes .../qml/simple/apps/tld.test.simple2/info.yaml | 13 + tests/auto/qml/simple/simple.pro | 5 + tests/auto/qml/simple/text-file.txt | 1 + tests/auto/qml/simple/tst_applicationmanager.qml | 487 +++ tests/auto/qml/windowitem/CMakeLists.txt | 16 + tests/auto/qml/windowitem/am-config.yaml | 13 + .../windowitem/apps/test.windowitem.app/icon.png | Bin 0 -> 1486 bytes .../windowitem/apps/test.windowitem.app/info.yaml | 9 + .../windowitem/apps/test.windowitem.app/main.qml | 64 + .../apps/test.windowitem.multiwin/icon.png | Bin 0 -> 1486 bytes .../apps/test.windowitem.multiwin/info.yaml | 9 + .../apps/test.windowitem.multiwin/main.qml | 49 + tests/auto/qml/windowitem/tst_windowitem.qml | 482 +++ tests/auto/qml/windowitem/windowitem.pro | 5 + tests/auto/qml/windowitem2/CMakeLists.txt | 16 + tests/auto/qml/windowitem2/am-config.yaml | 11 + .../windowitem2/apps/test.windowitem2.app/icon.png | Bin 0 -> 1486 bytes .../apps/test.windowitem2.app/info.yaml | 9 + .../windowitem2/apps/test.windowitem2.app/main.qml | 40 + tests/auto/qml/windowitem2/tst_windowitem2.qml | 130 + tests/auto/qml/windowitem2/windowitem2.pro | 5 + tests/auto/qml/windowmanager/CMakeLists.txt | 15 + .../qml/windowmanager/IviApplicationExtension.qml | 43 + tests/auto/qml/windowmanager/tst_windowmanager.qml | 66 + tests/auto/qml/windowmanager/windowmanager.pro | 5 + tests/auto/qml/windowmapping/CMakeLists.txt | 16 + tests/auto/qml/windowmapping/am-config.yaml | 11 + .../windowmapping/apps/test.winmap.amwin/amwin.qml | 57 + .../windowmapping/apps/test.winmap.amwin/icon.png | Bin 0 -> 1486 bytes .../windowmapping/apps/test.winmap.amwin/info.yaml | 9 + .../apps/test.winmap.amwin2/amwin2.qml | 69 + .../windowmapping/apps/test.winmap.amwin2/icon.png | Bin 0 -> 1486 bytes .../apps/test.winmap.amwin2/info.yaml | 9 + .../apps/test.winmap.loader/SubWin.qml | 37 + .../windowmapping/apps/test.winmap.loader/icon.png | Bin 0 -> 1486 bytes .../apps/test.winmap.loader/info.yaml | 9 + .../apps/test.winmap.loader/loader.qml | 54 + .../windowmapping/apps/test.winmap.ping/icon.png | Bin 0 -> 1486 bytes .../windowmapping/apps/test.winmap.ping/info.yaml | 9 + .../windowmapping/apps/test.winmap.ping/ping.qml | 44 + .../apps/test.winmap.qtobject/icon.png | Bin 0 -> 1486 bytes .../apps/test.winmap.qtobject/info.yaml | 9 + .../apps/test.winmap.qtobject/qtobject.qml | 60 + .../apps/test.winmap.rectangle/icon.png | Bin 0 -> 1486 bytes .../apps/test.winmap.rectangle/info.yaml | 9 + .../apps/test.winmap.rectangle/rectangle.qml | 55 + .../windowmapping/apps/test.winmap.window/icon.png | Bin 0 -> 1486 bytes .../apps/test.winmap.window/info.yaml | 9 + .../apps/test.winmap.window/window.qml | 57 + tests/auto/qml/windowmapping/tst_windowmapping.qml | 321 ++ tests/auto/qml/windowmapping/windowmapping.pro | 12 + tests/auto/runtime/CMakeLists.txt | 22 + tests/auto/runtime/runtime.pro | 11 + tests/auto/runtime/tst_runtime.cpp | 177 + tests/auto/signature/CMakeLists.txt | 41 + tests/auto/signature/create-test-data.sh | 40 + tests/auto/signature/signature-openssl.p7 | Bin 0 -> 2555 bytes .../auto/signature/signature-securityframework.p7 | Bin 0 -> 3210 bytes tests/auto/signature/signature-wincrypt.p7 | Bin 0 -> 2316 bytes tests/auto/signature/signature.pro | 11 + tests/auto/signature/signing-no-key.p12 | Bin 0 -> 2144 bytes tests/auto/signature/signing.p12 | Bin 0 -> 3628 bytes tests/auto/signature/tst_signature.cpp | 171 + tests/auto/signature/tst_signature.qrc | 10 + tests/auto/signature/verifying.crt | 105 + tests/auto/sudo/CMakeLists.txt | 23 + tests/auto/sudo/sudo.pro | 11 + tests/auto/sudo/tst_sudo.cpp | 148 + tests/auto/systemreader/CMakeLists.txt | 23 + tests/auto/systemreader/root/proc/1234/cgroup | 13 + .../run-u5853.scope/memory.limit_in_bytes | 1 + .../system.slice/run-u5853.scope/memory.stat | 33 + tests/auto/systemreader/systemreader.pro | 11 + tests/auto/systemreader/tst_systemreader.cpp | 78 + tests/auto/tests.pri | 11 + tests/auto/tests.pro | 56 + tests/auto/utilities/CMakeLists.txt | 19 + tests/auto/utilities/tst_utilities.cpp | 54 + tests/auto/utilities/utilities.pro | 7 + tests/auto/yaml/CMakeLists.txt | 34 + tests/auto/yaml/data/cache1.yaml | 13 + tests/auto/yaml/data/cache2.yaml | 14 + tests/auto/yaml/data/test.yaml | 45 + tests/auto/yaml/tst_yaml.cpp | 408 ++ tests/auto/yaml/yaml.pro | 12 + tests/benchmarks/CMakeLists.txt | 2 + tests/benchmarks/appman-bench/CMakeLists.txt | 2 + tests/benchmarks/appman-bench/README | 21 + tests/benchmarks/appman-bench/am-config.yaml | 24 + tests/benchmarks/appman-bench/appman-bench.pro | 10 + tests/benchmarks/appman-bench/run.sh | 139 + tests/benchmarks/appman-bench/system-ui/main.qml | 229 ++ .../appman-bench/templates/appman-qml/icon.png | Bin 0 -> 1486 bytes .../appman-bench/templates/appman-qml/info.yaml | 9 + .../appman-bench/templates/appman-qml/main.qml | 79 + .../appman-bench/templates/qmlscene/icon.png | Bin 0 -> 1486 bytes .../appman-bench/templates/qmlscene/info.yaml | 13 + .../appman-bench/templates/qmlscene/main.qml | 72 + tests/benchmarks/appman-bench/tests/controls2.qml | 57 + tests/benchmarks/appman-bench/tests/rect.qml | 57 + tests/benchmarks/appman-bench/tests/repeater.qml | 70 + tests/benchmarks/appman-bench/tests/shader.qml | 89 + tests/benchmarks/benchmarks.pro | 5 + tests/configuration/configuration.pro | 12 - tests/configuration/data/config1.yaml | 98 - tests/configuration/data/config2.yaml | 88 - tests/configuration/data/empty.yaml | 3 - tests/configuration/tst_configuration.cpp | 523 --- tests/cryptography/cryptography.pro | 7 - tests/cryptography/tst_cryptography.cpp | 62 - .../data/certificates/create-test-certificates.sh | 0 tests/data/create-test-packages.sh | 0 tests/debugwrapper/debugwrapper.pro | 8 - tests/debugwrapper/tst_debugwrapper.cpp | 151 - tests/error-checking.h | 45 - tests/installationreport/installationreport.pro | 10 - .../installationreport/tst_installationreport.cpp | 118 - tests/main/am-config.yaml | 10 - tests/main/builtin-apps/hello-world.red/icon.png | Bin 1027 -> 0 bytes tests/main/builtin-apps/hello-world.red/info.yaml | 24 - tests/main/builtin-apps/hello-world.red/main.qml | 11 - .../apps/hello-world.red/.installation-report.yaml | 14 - .../apps/hello-world.red/icon.png | Bin 1027 -> 0 bytes .../apps/hello-world.red/info.yaml | 9 - .../apps/hello-world.red/main.qml | 11 - .../docs/hello-world.red/placeholder | 0 .../manifests/hello-world.red/icon.png | Bin 1027 -> 0 bytes .../manifests/hello-world.red/info.yaml | 9 - tests/main/dummy.qml | 3 - tests/main/main.pro | 20 - tests/main/main.qrc | 5 - tests/main/tst_main.cpp | 384 -- tests/manual/CMakeLists.txt | 2 + tests/manual/monitormodel/CMakeLists.txt | 2 + tests/packagecreator/packagecreator.pro | 10 - tests/packagecreator/tst_packagecreator.cpp | 185 - tests/packageextractor/packageextractor.pro | 10 - tests/packageextractor/tst_packageextractor.cpp | 312 -- tests/packager-tool/packager-tool.pro | 15 - tests/packager-tool/tst_packager-tool.cpp | 414 -- tests/processreader/advanced.smaps | 252 -- tests/processreader/basic.smaps | 352 -- tests/processreader/invalid.smaps | 16 - tests/processreader/processreader.pro | 11 - tests/processreader/tst_processreader.cpp | 144 - tests/qml/configs/am-config-nodbus.yaml | 6 - tests/qml/configs/am-config.yaml | 11 - tests/qml/configs/apps/test.configs.app/app.qml | 78 - tests/qml/configs/apps/test.configs.app/icon.png | Bin 1486 -> 0 bytes tests/qml/configs/apps/test.configs.app/info.yaml | 9 - tests/qml/configs/configs.pro | 15 - tests/qml/configs/tst_configs.qml | 116 - tests/qml/crash/am-config.yaml | 8 - tests/qml/crash/apps/tld.test.crash/app.qml | 57 - tests/qml/crash/apps/tld.test.crash/icon.png | Bin 1486 -> 0 bytes tests/qml/crash/apps/tld.test.crash/info.yaml | 12 - .../crash/apps/tld.test.crash/terminator2/qmldir | 2 - .../tld.test.crash/terminator2/qmlterminator2.cpp | 114 - .../tld.test.crash/terminator2/qmlterminator2.h | 75 - .../tld.test.crash/terminator2/terminator2.pro | 18 - tests/qml/crash/crash.pro | 5 - tests/qml/crash/tst_crash.qml | 83 - tests/qml/installer/am-config.yaml | 10 - tests/qml/installer/apps/hello-world.red/app1.qml | 35 - tests/qml/installer/apps/hello-world.red/icon1.png | Bin 1486 -> 0 bytes tests/qml/installer/apps/hello-world.red/info.yaml | 10 - tests/qml/installer/installer.pro | 6 - tests/qml/installer/tst_installer.qml | 252 -- tests/qml/intents/am-config-quick.yaml | 6 - tests/qml/intents/am-config.yaml | 23 - tests/qml/intents/apps/cannot-start/cannot-start | 1 - tests/qml/intents/apps/cannot-start/icon.png | Bin 5138 -> 0 bytes tests/qml/intents/apps/cannot-start/info.yaml | 12 - tests/qml/intents/apps/intents1/icon.png | Bin 5138 -> 0 bytes tests/qml/intents/apps/intents1/info.yaml | 20 - tests/qml/intents/apps/intents1/intents1.qml | 59 - tests/qml/intents/apps/intents2/icon.png | Bin 5138 -> 0 bytes tests/qml/intents/apps/intents2/info.yaml | 16 - tests/qml/intents/apps/intents2/intents2.qml | 54 - tests/qml/intents/intents.pro | 12 - tests/qml/intents/tst_intents.qml | 241 -- tests/qml/lifecycle/am-config.yaml | 8 - .../qml/lifecycle/apps/tld.test.lifecycle/app.qml | 39 - .../qml/lifecycle/apps/tld.test.lifecycle/icon.png | Bin 1486 -> 0 bytes .../lifecycle/apps/tld.test.lifecycle/info.yaml | 9 - tests/qml/lifecycle/lifecycle.pro | 5 - tests/qml/lifecycle/tst_lifecycle.qml | 134 - tests/qml/processtitle/am-config-quick.yaml | 10 - tests/qml/processtitle/am-config.yaml | 5 - .../app.qml | 39 - .../icon.png | Bin 1486 -> 0 bytes .../info.yaml | 9 - .../apps/test.processtitle.app/app.qml | 39 - .../apps/test.processtitle.app/icon.png | Bin 1486 -> 0 bytes .../apps/test.processtitle.app/info.yaml | 9 - tests/qml/processtitle/processtitle.pro | 7 - tests/qml/processtitle/tst_processtitle.qml | 105 - tests/qml/qml.pro | 20 - tests/qml/quicklaunch/am-config.yaml | 9 - .../quicklaunch/apps/tld.test.quicklaunch/app.qml | 42 - .../quicklaunch/apps/tld.test.quicklaunch/icon.png | Bin 1486 -> 0 bytes .../apps/tld.test.quicklaunch/info.yaml | 10 - tests/qml/quicklaunch/quicklaunch.pro | 5 - tests/qml/quicklaunch/tst_quicklaunch.qml | 89 - tests/qml/resources/am-config.yaml | 22 - tests/qml/resources/appcommon/Quicklaunch.qml | 36 - tests/qml/resources/appcommon/appcommon.pro | 7 - tests/qml/resources/appcommon/appcommonfile.qrc | 7 - .../resources/appcommon/qml/common/CommonObj.qml | 35 - tests/qml/resources/appcommon/qml/common/qmldir | 2 - tests/qml/resources/apps/app1/app1.pro | 11 - tests/qml/resources/apps/app1/app1.qml | 39 - tests/qml/resources/apps/app1/app1file.qrc | 7 - tests/qml/resources/apps/app1/app1plugin.qrc | 5 - tests/qml/resources/apps/app1/icon.png | Bin 1486 -> 0 bytes tests/qml/resources/apps/app1/info.yaml | 17 - .../qml/resources/apps/app1/qml/forms/AquaRect.qml | 35 - .../resources/apps/app1/qml/forms/YellowRect.qml | 35 - tests/qml/resources/apps/app1/qml/forms/qmldir | 4 - tests/qml/resources/apps/app2/BlueRect.qml | 35 - tests/qml/resources/apps/app2/app2.pro | 8 - tests/qml/resources/apps/app2/app2.qml | 46 - tests/qml/resources/apps/app2/app2.qrc | 6 - tests/qml/resources/apps/app2/icon.png | Bin 1486 -> 0 bytes tests/qml/resources/apps/app2/info.yaml | 15 - .../apps/app2/qml/appwidgets/GreenRect.qml | 35 - .../qml/resources/apps/app2/qml/appwidgets/qmldir | 2 - tests/qml/resources/qml/widgets/MagentaRect.qml | 35 - tests/qml/resources/qml/widgets/RedRect.qml | 35 - tests/qml/resources/qml/widgets/qmldir | 3 - .../qml/resources/relative/elements/LinenRect.qml | 35 - tests/qml/resources/relative/elements/qmldir | 2 - tests/qml/resources/resources.pro | 5 - tests/qml/resources/systemuifile.qrc | 6 - tests/qml/resources/systemuiplugin.qrc | 5 - tests/qml/resources/test.pro | 18 - tests/qml/resources/tst_resource.qml | 81 - tests/qml/simple/am-config.yaml | 56 - tests/qml/simple/apps/tld.test.simple1/app1.qml | 50 - tests/qml/simple/apps/tld.test.simple1/icon.png | Bin 5138 -> 0 bytes tests/qml/simple/apps/tld.test.simple1/info.yaml | 23 - tests/qml/simple/apps/tld.test.simple2/app.qml | 50 - tests/qml/simple/apps/tld.test.simple2/icon.png | Bin 5138 -> 0 bytes tests/qml/simple/apps/tld.test.simple2/info.yaml | 13 - tests/qml/simple/simple.pro | 5 - tests/qml/simple/text-file.txt | 1 - tests/qml/simple/tst_applicationmanager.qml | 487 --- tests/qml/windowitem/am-config.yaml | 13 - .../windowitem/apps/test.windowitem.app/icon.png | Bin 1486 -> 0 bytes .../windowitem/apps/test.windowitem.app/info.yaml | 9 - .../windowitem/apps/test.windowitem.app/main.qml | 64 - .../apps/test.windowitem.multiwin/icon.png | Bin 1486 -> 0 bytes .../apps/test.windowitem.multiwin/info.yaml | 9 - .../apps/test.windowitem.multiwin/main.qml | 49 - tests/qml/windowitem/tst_windowitem.qml | 482 --- tests/qml/windowitem/windowitem.pro | 5 - tests/qml/windowitem2/am-config.yaml | 11 - .../windowitem2/apps/test.windowitem2.app/icon.png | Bin 1486 -> 0 bytes .../apps/test.windowitem2.app/info.yaml | 9 - .../windowitem2/apps/test.windowitem2.app/main.qml | 40 - tests/qml/windowitem2/tst_windowitem2.qml | 130 - tests/qml/windowitem2/windowitem2.pro | 5 - .../qml/windowmanager/IviApplicationExtension.qml | 43 - tests/qml/windowmanager/tst_windowmanager.qml | 66 - tests/qml/windowmanager/windowmanager.pro | 5 - tests/qml/windowmapping/am-config.yaml | 11 - .../windowmapping/apps/test.winmap.amwin/amwin.qml | 57 - .../windowmapping/apps/test.winmap.amwin/icon.png | Bin 1486 -> 0 bytes .../windowmapping/apps/test.winmap.amwin/info.yaml | 9 - .../apps/test.winmap.amwin2/amwin2.qml | 69 - .../windowmapping/apps/test.winmap.amwin2/icon.png | Bin 1486 -> 0 bytes .../apps/test.winmap.amwin2/info.yaml | 9 - .../apps/test.winmap.loader/SubWin.qml | 37 - .../windowmapping/apps/test.winmap.loader/icon.png | Bin 1486 -> 0 bytes .../apps/test.winmap.loader/info.yaml | 9 - .../apps/test.winmap.loader/loader.qml | 54 - .../windowmapping/apps/test.winmap.ping/icon.png | Bin 1486 -> 0 bytes .../windowmapping/apps/test.winmap.ping/info.yaml | 9 - .../windowmapping/apps/test.winmap.ping/ping.qml | 44 - .../apps/test.winmap.qtobject/icon.png | Bin 1486 -> 0 bytes .../apps/test.winmap.qtobject/info.yaml | 9 - .../apps/test.winmap.qtobject/qtobject.qml | 60 - .../apps/test.winmap.rectangle/icon.png | Bin 1486 -> 0 bytes .../apps/test.winmap.rectangle/info.yaml | 9 - .../apps/test.winmap.rectangle/rectangle.qml | 55 - .../windowmapping/apps/test.winmap.window/icon.png | Bin 1486 -> 0 bytes .../apps/test.winmap.window/info.yaml | 9 - .../apps/test.winmap.window/window.qml | 57 - tests/qml/windowmapping/tst_windowmapping.qml | 321 -- tests/qml/windowmapping/windowmapping.pro | 12 - tests/runtime/runtime.pro | 11 - tests/runtime/tst_runtime.cpp | 177 - tests/signature/create-test-data.sh | 40 - tests/signature/signature-openssl.p7 | Bin 2555 -> 0 bytes tests/signature/signature-securityframework.p7 | Bin 3210 -> 0 bytes tests/signature/signature-wincrypt.p7 | Bin 2316 -> 0 bytes tests/signature/signature.pro | 11 - tests/signature/signing-no-key.p12 | Bin 2144 -> 0 bytes tests/signature/signing.p12 | Bin 3628 -> 0 bytes tests/signature/tst_signature.cpp | 171 - tests/signature/tst_signature.qrc | 10 - tests/signature/verifying.crt | 105 - tests/sudo/sudo.pro | 11 - tests/sudo/tst_sudo.cpp | 148 - tests/systemreader/root/proc/1234/cgroup | 13 - .../run-u5853.scope/memory.limit_in_bytes | 1 - .../system.slice/run-u5853.scope/memory.stat | 33 - tests/systemreader/systemreader.pro | 11 - tests/systemreader/tst_systemreader.cpp | 78 - tests/tests.pri | 11 - tests/tests.pro | 56 - tests/utilities/tst_utilities.cpp | 54 - tests/utilities/utilities.pro | 7 - tests/yaml/data/cache1.yaml | 13 - tests/yaml/data/cache2.yaml | 14 - tests/yaml/data/test.yaml | 45 - tests/yaml/tst_yaml.cpp | 408 -- tests/yaml/yaml.pro | 12 - 909 files changed, 100335 insertions(+), 97446 deletions(-) create mode 100644 .cmake.conf delete mode 100644 3rdparty/README.md delete mode 100644 3rdparty/libarchive.pri delete mode 100644 3rdparty/libarchive/COPYING delete mode 100644 3rdparty/libarchive/INSTALL delete mode 100644 3rdparty/libarchive/NEWS delete mode 100644 3rdparty/libarchive/README.md delete mode 100644 3rdparty/libarchive/config-android.h delete mode 100644 3rdparty/libarchive/config-ios.h delete mode 100644 3rdparty/libarchive/config-macos.h delete mode 100644 3rdparty/libarchive/config-unix.h delete mode 100644 3rdparty/libarchive/config-windows.h delete mode 100644 3rdparty/libarchive/libarchive.pro delete mode 100644 3rdparty/libarchive/libarchive/android_lf.h delete mode 100644 3rdparty/libarchive/libarchive/archive.h delete mode 100644 3rdparty/libarchive/libarchive/archive_acl.c delete mode 100644 3rdparty/libarchive/libarchive/archive_acl_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_check_magic.c delete mode 100644 3rdparty/libarchive/libarchive/archive_cmdline.c delete mode 100644 3rdparty/libarchive/libarchive/archive_cmdline_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_crc32.h delete mode 100644 3rdparty/libarchive/libarchive/archive_endian.h delete mode 100644 3rdparty/libarchive/libarchive/archive_entry.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry.h delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_copy_stat.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_link_resolver.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_locale.h delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_sparse.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_stat.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_strmode.c delete mode 100644 3rdparty/libarchive/libarchive/archive_entry_xattr.c delete mode 100644 3rdparty/libarchive/libarchive/archive_getdate.c delete mode 100644 3rdparty/libarchive/libarchive/archive_getdate.h delete mode 100644 3rdparty/libarchive/libarchive/archive_match.c delete mode 100644 3rdparty/libarchive/libarchive/archive_options.c delete mode 100644 3rdparty/libarchive/libarchive/archive_options_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_pack_dev.h delete mode 100644 3rdparty/libarchive/libarchive/archive_pathmatch.c delete mode 100644 3rdparty/libarchive/libarchive/archive_pathmatch.h delete mode 100644 3rdparty/libarchive/libarchive/archive_platform.h delete mode 100644 3rdparty/libarchive/libarchive/archive_platform_acl.h delete mode 100644 3rdparty/libarchive/libarchive/archive_ppmd7.c delete mode 100644 3rdparty/libarchive/libarchive/archive_ppmd7_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_ppmd_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_random.c delete mode 100644 3rdparty/libarchive/libarchive/archive_random_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_rb.c delete mode 100644 3rdparty/libarchive/libarchive/archive_rb.h delete mode 100644 3rdparty/libarchive/libarchive/archive_read.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_append_filter.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_data_into_fd.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_disk_posix.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_disk_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_disk_windows.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_extract.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_open_fd.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_open_file.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_open_filename.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_open_memory.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_read_set_format.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_set_options.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_filter_none.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_filter_program.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_format_empty.c delete mode 100644 3rdparty/libarchive/libarchive/archive_read_support_format_tar.c delete mode 100644 3rdparty/libarchive/libarchive/archive_string.c delete mode 100644 3rdparty/libarchive/libarchive/archive_string.h delete mode 100644 3rdparty/libarchive/libarchive/archive_string_composition.h delete mode 100644 3rdparty/libarchive/libarchive/archive_string_sprintf.c delete mode 100644 3rdparty/libarchive/libarchive/archive_util.c delete mode 100644 3rdparty/libarchive/libarchive/archive_virtual.c delete mode 100644 3rdparty/libarchive/libarchive/archive_windows.c delete mode 100644 3rdparty/libarchive/libarchive/archive_windows.h delete mode 100644 3rdparty/libarchive/libarchive/archive_write.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_none.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_program.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_disk_posix.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_disk_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_disk_windows.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_open_fd.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_open_file.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_open_filename.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_open_memory.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_private.h delete mode 100644 3rdparty/libarchive/libarchive/archive_write_set_format.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c delete mode 100644 3rdparty/libarchive/libarchive/archive_write_set_options.c delete mode 100644 3rdparty/libarchive/libarchive/config_freebsd.h delete mode 100644 3rdparty/libarchive/libarchive/filter_fork.h delete mode 100644 3rdparty/libarchive/libarchive/filter_fork_posix.c delete mode 100644 3rdparty/libarchive/libarchive/filter_fork_windows.c delete mode 100644 3rdparty/libarchive/qt_attribution.json delete mode 100644 3rdparty/libbacktrace.pri delete mode 100644 3rdparty/libbacktrace/LICENSE delete mode 100644 3rdparty/libbacktrace/README.md delete mode 100644 3rdparty/libbacktrace/auxincl/dwarf2.h delete mode 100644 3rdparty/libbacktrace/auxincl/filenames.h delete mode 100644 3rdparty/libbacktrace/libbacktrace.pro delete mode 100644 3rdparty/libbacktrace/libbacktrace/ChangeLog delete mode 100644 3rdparty/libbacktrace/libbacktrace/README delete mode 100644 3rdparty/libbacktrace/libbacktrace/atomic.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/backtrace-supported.h delete mode 100644 3rdparty/libbacktrace/libbacktrace/backtrace.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/backtrace.h delete mode 100644 3rdparty/libbacktrace/libbacktrace/config.h delete mode 100644 3rdparty/libbacktrace/libbacktrace/dwarf.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/elf.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/fileline.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/internal.h delete mode 100644 3rdparty/libbacktrace/libbacktrace/macho.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/mmap.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/mmapio.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/posix.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/print.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/simple.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/sort.c delete mode 100644 3rdparty/libbacktrace/libbacktrace/state.c delete mode 100644 3rdparty/libbacktrace/qt_attribution.json delete mode 100644 3rdparty/libyaml.pri delete mode 100644 3rdparty/libyaml/LICENSE delete mode 100644 3rdparty/libyaml/README delete mode 100644 3rdparty/libyaml/include/yaml.h delete mode 100644 3rdparty/libyaml/libyaml.pro delete mode 100644 3rdparty/libyaml/qt_attribution.json delete mode 100644 3rdparty/libyaml/src/api.c delete mode 100644 3rdparty/libyaml/src/dumper.c delete mode 100644 3rdparty/libyaml/src/emitter.c delete mode 100644 3rdparty/libyaml/src/loader.c delete mode 100644 3rdparty/libyaml/src/parser.c delete mode 100644 3rdparty/libyaml/src/reader.c delete mode 100644 3rdparty/libyaml/src/scanner.c delete mode 100644 3rdparty/libyaml/src/writer.c delete mode 100644 3rdparty/libyaml/src/yaml_private.h delete mode 100644 3rdparty/libyaml/win32/config.h delete mode 100644 3rdparty/libz.pri delete mode 100644 3rdparty/stackwalker.pri delete mode 100644 3rdparty/stackwalker/LICENSE delete mode 100644 3rdparty/stackwalker/qt_attribution.json delete mode 100644 3rdparty/stackwalker/stackwalker.cpp delete mode 100644 3rdparty/stackwalker/stackwalker.h delete mode 100644 3rdparty/stackwalker/stackwalker.pro create mode 100644 CMakeLists.txt delete mode 100644 benchmarks/appman-bench/README delete mode 100644 benchmarks/appman-bench/am-config.yaml delete mode 100644 benchmarks/appman-bench/appman-bench.pro delete mode 100644 benchmarks/appman-bench/run.sh delete mode 100644 benchmarks/appman-bench/system-ui/main.qml delete mode 100644 benchmarks/appman-bench/templates/appman-qml/icon.png delete mode 100644 benchmarks/appman-bench/templates/appman-qml/info.yaml delete mode 100644 benchmarks/appman-bench/templates/appman-qml/main.qml delete mode 100644 benchmarks/appman-bench/templates/qmlscene/icon.png delete mode 100644 benchmarks/appman-bench/templates/qmlscene/info.yaml delete mode 100644 benchmarks/appman-bench/templates/qmlscene/main.qml delete mode 100644 benchmarks/appman-bench/tests/controls2.qml delete mode 100644 benchmarks/appman-bench/tests/rect.qml delete mode 100644 benchmarks/appman-bench/tests/repeater.qml delete mode 100644 benchmarks/appman-bench/tests/shader.qml delete mode 100644 benchmarks/benchmarks.pro create mode 100644 cmake/FindWrapLibArchive.cmake create mode 100644 cmake/FindWrapLibYaml.cmake create mode 100644 cmake/QtAppManHelpers.cmake create mode 100644 coin/module_config.yaml delete mode 100644 config.tests/libarchive/libarchive.pro delete mode 100644 config.tests/libarchive/main.cpp delete mode 100644 config.tests/libyaml/libyaml.pro delete mode 100644 config.tests/libyaml/main.cpp delete mode 100644 config.tests/touchemulation/main.cpp delete mode 100644 config.tests/touchemulation/touchemulation.pro create mode 100644 configure.cmake create mode 100644 doc/CMakeLists.txt create mode 100644 examples/CMakeLists.txt create mode 100644 examples/applicationmanager/CMakeLists.txt create mode 100644 examples/applicationmanager/animated-windows/CMakeLists.txt create mode 100644 examples/applicationmanager/application-features/CMakeLists.txt create mode 100644 examples/applicationmanager/application-features/imports/CMakeLists.txt create mode 100644 examples/applicationmanager/application-features/imports/terminator2/CMakeLists.txt create mode 100644 examples/applicationmanager/application-features/native/CMakeLists.txt create mode 100644 examples/applicationmanager/application-features/native/widgets/CMakeLists.txt create mode 100644 examples/applicationmanager/custom-appman/CMakeLists.txt create mode 100644 examples/applicationmanager/frame-timer/CMakeLists.txt create mode 100644 examples/applicationmanager/hello-world/CMakeLists.txt create mode 100644 examples/applicationmanager/launch-intents/CMakeLists.txt create mode 100644 examples/applicationmanager/minidesk/CMakeLists.txt create mode 100644 examples/applicationmanager/multi-views/CMakeLists.txt create mode 100644 examples/applicationmanager/process-status/CMakeLists.txt create mode 100644 examples/applicationmanager/softwarecontainer-plugin/CMakeLists.txt create mode 100644 examples/applicationmanager/startup-plugin/CMakeLists.txt create mode 100644 qmake-features/CMakeLists.txt create mode 100644 qt_cmdline.cmake create mode 100644 src/3rdparty/CMakeLists.txt create mode 100644 src/3rdparty/README.md create mode 100644 src/3rdparty/libarchive/CMakeLists.txt create mode 100644 src/3rdparty/libarchive/COPYING create mode 100644 src/3rdparty/libarchive/INSTALL create mode 100644 src/3rdparty/libarchive/NEWS create mode 100644 src/3rdparty/libarchive/README.md create mode 100644 src/3rdparty/libarchive/config-android.h create mode 100644 src/3rdparty/libarchive/config-ios.h create mode 100644 src/3rdparty/libarchive/config-macos.h create mode 100644 src/3rdparty/libarchive/config-unix.h create mode 100644 src/3rdparty/libarchive/config-windows.h create mode 100644 src/3rdparty/libarchive/libarchive.pro create mode 100644 src/3rdparty/libarchive/libarchive/android_lf.h create mode 100644 src/3rdparty/libarchive/libarchive/archive.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_acl.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_acl_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_check_magic.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_cmdline.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_cmdline_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_crc32.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_endian.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_locale.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_sparse.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_stat.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_strmode.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_entry_xattr.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_getdate.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_getdate.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_match.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_options.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_options_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_pack_dev.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_pathmatch.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_pathmatch.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_platform.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_platform_acl.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_ppmd7.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_ppmd7_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_ppmd_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_random.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_random_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_rb.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_rb.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_read.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_append_filter.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_disk_posix.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_disk_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_disk_windows.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_extract.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_open_fd.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_open_file.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_open_filename.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_open_memory.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_set_format.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_set_options.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_string.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_string.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_string_composition.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_string_sprintf.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_util.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_virtual.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_windows.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_windows.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_write.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_disk_posix.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_disk_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_disk_windows.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_open_fd.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_open_file.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_open_filename.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_open_memory.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_private.h create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_set_format.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c create mode 100644 src/3rdparty/libarchive/libarchive/archive_write_set_options.c create mode 100644 src/3rdparty/libarchive/libarchive/config_freebsd.h create mode 100644 src/3rdparty/libarchive/libarchive/filter_fork.h create mode 100644 src/3rdparty/libarchive/libarchive/filter_fork_posix.c create mode 100644 src/3rdparty/libarchive/libarchive/filter_fork_windows.c create mode 100644 src/3rdparty/libarchive/qt_attribution.json create mode 100644 src/3rdparty/libbacktrace/CMakeLists.txt create mode 100644 src/3rdparty/libbacktrace/LICENSE create mode 100644 src/3rdparty/libbacktrace/README.md create mode 100644 src/3rdparty/libbacktrace/auxincl/dwarf2.h create mode 100644 src/3rdparty/libbacktrace/auxincl/filenames.h create mode 100644 src/3rdparty/libbacktrace/libbacktrace.pro create mode 100644 src/3rdparty/libbacktrace/libbacktrace/ChangeLog create mode 100644 src/3rdparty/libbacktrace/libbacktrace/README create mode 100644 src/3rdparty/libbacktrace/libbacktrace/atomic.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h create mode 100644 src/3rdparty/libbacktrace/libbacktrace/backtrace.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/backtrace.h create mode 100644 src/3rdparty/libbacktrace/libbacktrace/config.h create mode 100644 src/3rdparty/libbacktrace/libbacktrace/dwarf.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/elf.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/fileline.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/internal.h create mode 100644 src/3rdparty/libbacktrace/libbacktrace/macho.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/mmap.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/mmapio.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/posix.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/print.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/simple.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/sort.c create mode 100644 src/3rdparty/libbacktrace/libbacktrace/state.c create mode 100644 src/3rdparty/libbacktrace/qt_attribution.json create mode 100644 src/3rdparty/libyaml/CMakeLists.txt create mode 100644 src/3rdparty/libyaml/LICENSE create mode 100644 src/3rdparty/libyaml/README create mode 100644 src/3rdparty/libyaml/include/yaml.h create mode 100644 src/3rdparty/libyaml/libyaml.pro create mode 100644 src/3rdparty/libyaml/qt_attribution.json create mode 100644 src/3rdparty/libyaml/src/api.c create mode 100644 src/3rdparty/libyaml/src/dumper.c create mode 100644 src/3rdparty/libyaml/src/emitter.c create mode 100644 src/3rdparty/libyaml/src/loader.c create mode 100644 src/3rdparty/libyaml/src/parser.c create mode 100644 src/3rdparty/libyaml/src/reader.c create mode 100644 src/3rdparty/libyaml/src/scanner.c create mode 100644 src/3rdparty/libyaml/src/writer.c create mode 100644 src/3rdparty/libyaml/src/yaml_private.h create mode 100644 src/3rdparty/libyaml/win32/config.h create mode 100644 src/3rdparty/stackwalker/CMakeLists.txt create mode 100644 src/3rdparty/stackwalker/LICENSE create mode 100644 src/3rdparty/stackwalker/qt_attribution.json create mode 100644 src/3rdparty/stackwalker/stackwalker.cpp create mode 100644 src/3rdparty/stackwalker/stackwalker.h create mode 100644 src/3rdparty/stackwalker/stackwalker.pro create mode 100644 src/CMakeLists.txt create mode 100644 src/application-lib/CMakeLists.txt create mode 100644 src/common-lib/CMakeLists.txt create mode 100644 src/common-lib/configure.cmake create mode 100644 src/common-lib/qt_cmdline.cmake create mode 100644 src/crypto-lib/CMakeLists.txt create mode 100644 src/dbus-lib/CMakeLists.txt create mode 100644 src/intent-client-lib/CMakeLists.txt create mode 100644 src/intent-server-lib/CMakeLists.txt create mode 100644 src/launcher-lib/CMakeLists.txt create mode 100644 src/main-lib/CMakeLists.txt create mode 100644 src/manager-lib/CMakeLists.txt create mode 100644 src/monitor-lib/CMakeLists.txt create mode 100644 src/notification-lib/CMakeLists.txt create mode 100644 src/package-lib/CMakeLists.txt create mode 100644 src/package-lib/configure.cmake create mode 100644 src/package-lib/qt_cmdline.cmake create mode 100644 src/plugin-interfaces/CMakeLists.txt create mode 100644 src/shared-main-lib/CMakeLists.txt create mode 100644 src/tools/appman/CMakeLists.txt create mode 100644 src/tools/controller/CMakeLists.txt create mode 100644 src/tools/dumpqmltypes/CMakeLists.txt create mode 100644 src/tools/launcher-qml/CMakeLists.txt create mode 100644 src/tools/packager/CMakeLists.txt create mode 100644 src/tools/testrunner/CMakeLists.txt create mode 100644 src/tools/uploader/CMakeLists.txt create mode 100644 src/window-lib/CMakeLists.txt create mode 100644 src/window-lib/configure.cmake create mode 100644 src/window-lib/qt_cmdline.cmake create mode 100644 tests/CMakeLists.txt delete mode 100644 tests/application/application.pro delete mode 100644 tests/application/icon.png delete mode 100644 tests/application/info.yaml delete mode 100644 tests/application/tst_application.cpp delete mode 100644 tests/application/tst_application.qrc delete mode 100644 tests/applicationinfo/applicationinfo.pro delete mode 100644 tests/applicationinfo/tst_applicationinfo.cpp delete mode 100644 tests/applicationinstaller/applicationinstaller.pro delete mode 100644 tests/applicationinstaller/tst_applicationinstaller.cpp create mode 100644 tests/auto/CMakeLists.txt create mode 100644 tests/auto/application/CMakeLists.txt create mode 100644 tests/auto/application/application.pro create mode 100644 tests/auto/application/icon.png create mode 100644 tests/auto/application/info.yaml create mode 100644 tests/auto/application/tst_application.cpp create mode 100644 tests/auto/application/tst_application.qrc create mode 100644 tests/auto/applicationinfo/CMakeLists.txt create mode 100644 tests/auto/applicationinfo/applicationinfo.pro create mode 100644 tests/auto/applicationinfo/tst_applicationinfo.cpp create mode 100644 tests/auto/applicationinstaller/CMakeLists.txt create mode 100644 tests/auto/applicationinstaller/applicationinstaller.pro create mode 100644 tests/auto/applicationinstaller/tst_applicationinstaller.cpp create mode 100644 tests/auto/configuration/CMakeLists.txt create mode 100644 tests/auto/configuration/configuration.pro create mode 100644 tests/auto/configuration/data/config1.yaml create mode 100644 tests/auto/configuration/data/config2.yaml create mode 100644 tests/auto/configuration/data/empty.yaml create mode 100644 tests/auto/configuration/tst_configuration.cpp create mode 100644 tests/auto/cryptography/CMakeLists.txt create mode 100644 tests/auto/cryptography/cryptography.pro create mode 100644 tests/auto/cryptography/tst_cryptography.cpp create mode 100644 tests/auto/debugwrapper/CMakeLists.txt create mode 100644 tests/auto/debugwrapper/debugwrapper.pro create mode 100644 tests/auto/debugwrapper/tst_debugwrapper.cpp create mode 100644 tests/auto/error-checking.h create mode 100644 tests/auto/installationreport/CMakeLists.txt create mode 100644 tests/auto/installationreport/installationreport.pro create mode 100644 tests/auto/installationreport/tst_installationreport.cpp create mode 100644 tests/auto/main/CMakeLists.txt create mode 100644 tests/auto/main/am-config.yaml create mode 100644 tests/auto/main/builtin-apps/hello-world.red/icon.png create mode 100644 tests/auto/main/builtin-apps/hello-world.red/info.yaml create mode 100644 tests/auto/main/builtin-apps/hello-world.red/main.qml create mode 100644 tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml create mode 100644 tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/icon.png create mode 100644 tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml create mode 100644 tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/main.qml create mode 100644 tests/auto/main/dir-with-update-already-installed/docs/hello-world.red/placeholder create mode 100644 tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png create mode 100644 tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml create mode 100644 tests/auto/main/dummy.qml create mode 100644 tests/auto/main/main.pro create mode 100644 tests/auto/main/main.qrc create mode 100644 tests/auto/main/tst_main.cpp create mode 100644 tests/auto/packagecreator/CMakeLists.txt create mode 100644 tests/auto/packagecreator/packagecreator.pro create mode 100644 tests/auto/packagecreator/tst_packagecreator.cpp create mode 100644 tests/auto/packageextractor/CMakeLists.txt create mode 100644 tests/auto/packageextractor/packageextractor.pro create mode 100644 tests/auto/packageextractor/tst_packageextractor.cpp create mode 100644 tests/auto/packager-tool/CMakeLists.txt create mode 100644 tests/auto/packager-tool/packager-tool.pro create mode 100644 tests/auto/packager-tool/tst_packager-tool.cpp create mode 100644 tests/auto/processreader/CMakeLists.txt create mode 100644 tests/auto/processreader/advanced.smaps create mode 100644 tests/auto/processreader/basic.smaps create mode 100644 tests/auto/processreader/invalid.smaps create mode 100644 tests/auto/processreader/processreader.pro create mode 100644 tests/auto/processreader/tst_processreader.cpp create mode 100644 tests/auto/qml/CMakeLists.txt create mode 100644 tests/auto/qml/configs/CMakeLists.txt create mode 100644 tests/auto/qml/configs/am-config-nodbus.yaml create mode 100644 tests/auto/qml/configs/am-config.yaml create mode 100644 tests/auto/qml/configs/apps/test.configs.app/app.qml create mode 100644 tests/auto/qml/configs/apps/test.configs.app/icon.png create mode 100644 tests/auto/qml/configs/apps/test.configs.app/info.yaml create mode 100644 tests/auto/qml/configs/configs.pro create mode 100644 tests/auto/qml/configs/tst_configs.qml create mode 100644 tests/auto/qml/crash/CMakeLists.txt create mode 100644 tests/auto/qml/crash/am-config.yaml create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/app.qml create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/icon.png create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/info.yaml create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/CMakeLists.txt create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/Terminator/qmldir create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmldir create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h create mode 100644 tests/auto/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro create mode 100644 tests/auto/qml/crash/crash.pro create mode 100644 tests/auto/qml/crash/tst_crash.qml create mode 100644 tests/auto/qml/installer/CMakeLists.txt create mode 100644 tests/auto/qml/installer/am-config.yaml create mode 100644 tests/auto/qml/installer/apps/hello-world.red/app1.qml create mode 100644 tests/auto/qml/installer/apps/hello-world.red/icon1.png create mode 100644 tests/auto/qml/installer/apps/hello-world.red/info.yaml create mode 100644 tests/auto/qml/installer/installer.pro create mode 100644 tests/auto/qml/installer/tst_installer.qml create mode 100644 tests/auto/qml/intents/CMakeLists.txt create mode 100644 tests/auto/qml/intents/am-config-quick.yaml create mode 100644 tests/auto/qml/intents/am-config.yaml create mode 100644 tests/auto/qml/intents/apps/cannot-start/cannot-start create mode 100644 tests/auto/qml/intents/apps/cannot-start/icon.png create mode 100644 tests/auto/qml/intents/apps/cannot-start/info.yaml create mode 100644 tests/auto/qml/intents/apps/intents1/icon.png create mode 100644 tests/auto/qml/intents/apps/intents1/info.yaml create mode 100644 tests/auto/qml/intents/apps/intents1/intents1.qml create mode 100644 tests/auto/qml/intents/apps/intents2/icon.png create mode 100644 tests/auto/qml/intents/apps/intents2/info.yaml create mode 100644 tests/auto/qml/intents/apps/intents2/intents2.qml create mode 100644 tests/auto/qml/intents/intents.pro create mode 100644 tests/auto/qml/intents/tst_intents.qml create mode 100644 tests/auto/qml/lifecycle/CMakeLists.txt create mode 100644 tests/auto/qml/lifecycle/am-config.yaml create mode 100644 tests/auto/qml/lifecycle/apps/tld.test.lifecycle/app.qml create mode 100644 tests/auto/qml/lifecycle/apps/tld.test.lifecycle/icon.png create mode 100644 tests/auto/qml/lifecycle/apps/tld.test.lifecycle/info.yaml create mode 100644 tests/auto/qml/lifecycle/lifecycle.pro create mode 100644 tests/auto/qml/lifecycle/tst_lifecycle.qml create mode 100644 tests/auto/qml/processtitle/CMakeLists.txt create mode 100644 tests/auto/qml/processtitle/am-config-quick.yaml create mode 100644 tests/auto/qml/processtitle/am-config.yaml create mode 100644 tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml create mode 100644 tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png create mode 100644 tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml create mode 100644 tests/auto/qml/processtitle/apps/test.processtitle.app/app.qml create mode 100644 tests/auto/qml/processtitle/apps/test.processtitle.app/icon.png create mode 100644 tests/auto/qml/processtitle/apps/test.processtitle.app/info.yaml create mode 100644 tests/auto/qml/processtitle/processtitle.pro create mode 100644 tests/auto/qml/processtitle/tst_processtitle.qml create mode 100644 tests/auto/qml/qml.pro create mode 100644 tests/auto/qml/quicklaunch/CMakeLists.txt create mode 100644 tests/auto/qml/quicklaunch/am-config.yaml create mode 100644 tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml create mode 100644 tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png create mode 100644 tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml create mode 100644 tests/auto/qml/quicklaunch/quicklaunch.pro create mode 100644 tests/auto/qml/quicklaunch/tst_quicklaunch.qml create mode 100644 tests/auto/qml/resources/CMakeLists.txt create mode 100644 tests/auto/qml/resources/am-config.yaml create mode 100644 tests/auto/qml/resources/appcommon/CMakeLists.txt create mode 100644 tests/auto/qml/resources/appcommon/Quicklaunch.qml create mode 100644 tests/auto/qml/resources/appcommon/appcommon.pro create mode 100644 tests/auto/qml/resources/appcommon/appcommonfile.qrc create mode 100644 tests/auto/qml/resources/appcommon/qml/common/CommonObj.qml create mode 100644 tests/auto/qml/resources/appcommon/qml/common/qmldir create mode 100644 tests/auto/qml/resources/apps/app1/CMakeLists.txt create mode 100644 tests/auto/qml/resources/apps/app1/app1.pro create mode 100644 tests/auto/qml/resources/apps/app1/app1.qml create mode 100644 tests/auto/qml/resources/apps/app1/app1file.qrc create mode 100644 tests/auto/qml/resources/apps/app1/app1plugin.qrc create mode 100644 tests/auto/qml/resources/apps/app1/icon.png create mode 100644 tests/auto/qml/resources/apps/app1/info.yaml create mode 100644 tests/auto/qml/resources/apps/app1/qml/forms/AquaRect.qml create mode 100644 tests/auto/qml/resources/apps/app1/qml/forms/YellowRect.qml create mode 100644 tests/auto/qml/resources/apps/app1/qml/forms/qmldir create mode 100644 tests/auto/qml/resources/apps/app2/BlueRect.qml create mode 100644 tests/auto/qml/resources/apps/app2/CMakeLists.txt create mode 100644 tests/auto/qml/resources/apps/app2/app2.pro create mode 100644 tests/auto/qml/resources/apps/app2/app2.qml create mode 100644 tests/auto/qml/resources/apps/app2/app2.qrc create mode 100644 tests/auto/qml/resources/apps/app2/icon.png create mode 100644 tests/auto/qml/resources/apps/app2/info.yaml create mode 100644 tests/auto/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml create mode 100644 tests/auto/qml/resources/apps/app2/qml/appwidgets/qmldir create mode 100644 tests/auto/qml/resources/qml/widgets/MagentaRect.qml create mode 100644 tests/auto/qml/resources/qml/widgets/RedRect.qml create mode 100644 tests/auto/qml/resources/qml/widgets/qmldir create mode 100644 tests/auto/qml/resources/relative/elements/LinenRect.qml create mode 100644 tests/auto/qml/resources/relative/elements/qmldir create mode 100644 tests/auto/qml/resources/resources.pro create mode 100644 tests/auto/qml/resources/systemuifile.qrc create mode 100644 tests/auto/qml/resources/systemuiplugin.qrc create mode 100644 tests/auto/qml/resources/test.pro create mode 100644 tests/auto/qml/resources/tst_resource.qml create mode 100644 tests/auto/qml/simple/CMakeLists.txt create mode 100644 tests/auto/qml/simple/am-config.yaml create mode 100644 tests/auto/qml/simple/apps/tld.test.simple1/app1.qml create mode 100644 tests/auto/qml/simple/apps/tld.test.simple1/icon.png create mode 100644 tests/auto/qml/simple/apps/tld.test.simple1/info.yaml create mode 100644 tests/auto/qml/simple/apps/tld.test.simple2/app.qml create mode 100644 tests/auto/qml/simple/apps/tld.test.simple2/icon.png create mode 100644 tests/auto/qml/simple/apps/tld.test.simple2/info.yaml create mode 100644 tests/auto/qml/simple/simple.pro create mode 100644 tests/auto/qml/simple/text-file.txt create mode 100644 tests/auto/qml/simple/tst_applicationmanager.qml create mode 100644 tests/auto/qml/windowitem/CMakeLists.txt create mode 100644 tests/auto/qml/windowitem/am-config.yaml create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.app/icon.png create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.app/info.yaml create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.app/main.qml create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.multiwin/icon.png create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.multiwin/info.yaml create mode 100644 tests/auto/qml/windowitem/apps/test.windowitem.multiwin/main.qml create mode 100644 tests/auto/qml/windowitem/tst_windowitem.qml create mode 100644 tests/auto/qml/windowitem/windowitem.pro create mode 100644 tests/auto/qml/windowitem2/CMakeLists.txt create mode 100644 tests/auto/qml/windowitem2/am-config.yaml create mode 100644 tests/auto/qml/windowitem2/apps/test.windowitem2.app/icon.png create mode 100644 tests/auto/qml/windowitem2/apps/test.windowitem2.app/info.yaml create mode 100644 tests/auto/qml/windowitem2/apps/test.windowitem2.app/main.qml create mode 100644 tests/auto/qml/windowitem2/tst_windowitem2.qml create mode 100644 tests/auto/qml/windowitem2/windowitem2.pro create mode 100644 tests/auto/qml/windowmanager/CMakeLists.txt create mode 100644 tests/auto/qml/windowmanager/IviApplicationExtension.qml create mode 100644 tests/auto/qml/windowmanager/tst_windowmanager.qml create mode 100644 tests/auto/qml/windowmanager/windowmanager.pro create mode 100644 tests/auto/qml/windowmapping/CMakeLists.txt create mode 100644 tests/auto/qml/windowmapping/am-config.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin/amwin.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin2/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.amwin2/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.loader/SubWin.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.loader/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.loader/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.loader/loader.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.ping/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.ping/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.ping/ping.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.qtobject/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.qtobject/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.rectangle/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.rectangle/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.window/icon.png create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.window/info.yaml create mode 100644 tests/auto/qml/windowmapping/apps/test.winmap.window/window.qml create mode 100644 tests/auto/qml/windowmapping/tst_windowmapping.qml create mode 100644 tests/auto/qml/windowmapping/windowmapping.pro create mode 100644 tests/auto/runtime/CMakeLists.txt create mode 100644 tests/auto/runtime/runtime.pro create mode 100644 tests/auto/runtime/tst_runtime.cpp create mode 100644 tests/auto/signature/CMakeLists.txt create mode 100644 tests/auto/signature/create-test-data.sh create mode 100644 tests/auto/signature/signature-openssl.p7 create mode 100644 tests/auto/signature/signature-securityframework.p7 create mode 100644 tests/auto/signature/signature-wincrypt.p7 create mode 100644 tests/auto/signature/signature.pro create mode 100644 tests/auto/signature/signing-no-key.p12 create mode 100644 tests/auto/signature/signing.p12 create mode 100644 tests/auto/signature/tst_signature.cpp create mode 100644 tests/auto/signature/tst_signature.qrc create mode 100644 tests/auto/signature/verifying.crt create mode 100644 tests/auto/sudo/CMakeLists.txt create mode 100644 tests/auto/sudo/sudo.pro create mode 100644 tests/auto/sudo/tst_sudo.cpp create mode 100644 tests/auto/systemreader/CMakeLists.txt create mode 100644 tests/auto/systemreader/root/proc/1234/cgroup create mode 100644 tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes create mode 100644 tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat create mode 100644 tests/auto/systemreader/systemreader.pro create mode 100644 tests/auto/systemreader/tst_systemreader.cpp create mode 100644 tests/auto/tests.pri create mode 100644 tests/auto/tests.pro create mode 100644 tests/auto/utilities/CMakeLists.txt create mode 100644 tests/auto/utilities/tst_utilities.cpp create mode 100644 tests/auto/utilities/utilities.pro create mode 100644 tests/auto/yaml/CMakeLists.txt create mode 100644 tests/auto/yaml/data/cache1.yaml create mode 100644 tests/auto/yaml/data/cache2.yaml create mode 100644 tests/auto/yaml/data/test.yaml create mode 100644 tests/auto/yaml/tst_yaml.cpp create mode 100644 tests/auto/yaml/yaml.pro create mode 100644 tests/benchmarks/CMakeLists.txt create mode 100644 tests/benchmarks/appman-bench/CMakeLists.txt create mode 100644 tests/benchmarks/appman-bench/README create mode 100644 tests/benchmarks/appman-bench/am-config.yaml create mode 100644 tests/benchmarks/appman-bench/appman-bench.pro create mode 100644 tests/benchmarks/appman-bench/run.sh create mode 100644 tests/benchmarks/appman-bench/system-ui/main.qml create mode 100644 tests/benchmarks/appman-bench/templates/appman-qml/icon.png create mode 100644 tests/benchmarks/appman-bench/templates/appman-qml/info.yaml create mode 100644 tests/benchmarks/appman-bench/templates/appman-qml/main.qml create mode 100644 tests/benchmarks/appman-bench/templates/qmlscene/icon.png create mode 100644 tests/benchmarks/appman-bench/templates/qmlscene/info.yaml create mode 100644 tests/benchmarks/appman-bench/templates/qmlscene/main.qml create mode 100644 tests/benchmarks/appman-bench/tests/controls2.qml create mode 100644 tests/benchmarks/appman-bench/tests/rect.qml create mode 100644 tests/benchmarks/appman-bench/tests/repeater.qml create mode 100644 tests/benchmarks/appman-bench/tests/shader.qml create mode 100644 tests/benchmarks/benchmarks.pro delete mode 100644 tests/configuration/configuration.pro delete mode 100644 tests/configuration/data/config1.yaml delete mode 100644 tests/configuration/data/config2.yaml delete mode 100644 tests/configuration/data/empty.yaml delete mode 100644 tests/configuration/tst_configuration.cpp delete mode 100644 tests/cryptography/cryptography.pro delete mode 100644 tests/cryptography/tst_cryptography.cpp mode change 100644 => 100755 tests/data/certificates/create-test-certificates.sh mode change 100644 => 100755 tests/data/create-test-packages.sh delete mode 100644 tests/debugwrapper/debugwrapper.pro delete mode 100644 tests/debugwrapper/tst_debugwrapper.cpp delete mode 100644 tests/error-checking.h delete mode 100644 tests/installationreport/installationreport.pro delete mode 100644 tests/installationreport/tst_installationreport.cpp delete mode 100644 tests/main/am-config.yaml delete mode 100644 tests/main/builtin-apps/hello-world.red/icon.png delete mode 100644 tests/main/builtin-apps/hello-world.red/info.yaml delete mode 100644 tests/main/builtin-apps/hello-world.red/main.qml delete mode 100644 tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml delete mode 100644 tests/main/dir-with-update-already-installed/apps/hello-world.red/icon.png delete mode 100644 tests/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml delete mode 100644 tests/main/dir-with-update-already-installed/apps/hello-world.red/main.qml delete mode 100644 tests/main/dir-with-update-already-installed/docs/hello-world.red/placeholder delete mode 100644 tests/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png delete mode 100644 tests/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml delete mode 100644 tests/main/dummy.qml delete mode 100644 tests/main/main.pro delete mode 100644 tests/main/main.qrc delete mode 100644 tests/main/tst_main.cpp create mode 100644 tests/manual/CMakeLists.txt create mode 100644 tests/manual/monitormodel/CMakeLists.txt delete mode 100644 tests/packagecreator/packagecreator.pro delete mode 100644 tests/packagecreator/tst_packagecreator.cpp delete mode 100644 tests/packageextractor/packageextractor.pro delete mode 100644 tests/packageextractor/tst_packageextractor.cpp delete mode 100644 tests/packager-tool/packager-tool.pro delete mode 100644 tests/packager-tool/tst_packager-tool.cpp delete mode 100644 tests/processreader/advanced.smaps delete mode 100644 tests/processreader/basic.smaps delete mode 100644 tests/processreader/invalid.smaps delete mode 100644 tests/processreader/processreader.pro delete mode 100644 tests/processreader/tst_processreader.cpp delete mode 100644 tests/qml/configs/am-config-nodbus.yaml delete mode 100644 tests/qml/configs/am-config.yaml delete mode 100644 tests/qml/configs/apps/test.configs.app/app.qml delete mode 100644 tests/qml/configs/apps/test.configs.app/icon.png delete mode 100644 tests/qml/configs/apps/test.configs.app/info.yaml delete mode 100644 tests/qml/configs/configs.pro delete mode 100644 tests/qml/configs/tst_configs.qml delete mode 100644 tests/qml/crash/am-config.yaml delete mode 100644 tests/qml/crash/apps/tld.test.crash/app.qml delete mode 100644 tests/qml/crash/apps/tld.test.crash/icon.png delete mode 100644 tests/qml/crash/apps/tld.test.crash/info.yaml delete mode 100644 tests/qml/crash/apps/tld.test.crash/terminator2/qmldir delete mode 100644 tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp delete mode 100644 tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h delete mode 100644 tests/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro delete mode 100644 tests/qml/crash/crash.pro delete mode 100644 tests/qml/crash/tst_crash.qml delete mode 100644 tests/qml/installer/am-config.yaml delete mode 100644 tests/qml/installer/apps/hello-world.red/app1.qml delete mode 100644 tests/qml/installer/apps/hello-world.red/icon1.png delete mode 100644 tests/qml/installer/apps/hello-world.red/info.yaml delete mode 100644 tests/qml/installer/installer.pro delete mode 100644 tests/qml/installer/tst_installer.qml delete mode 100644 tests/qml/intents/am-config-quick.yaml delete mode 100644 tests/qml/intents/am-config.yaml delete mode 100644 tests/qml/intents/apps/cannot-start/cannot-start delete mode 100644 tests/qml/intents/apps/cannot-start/icon.png delete mode 100644 tests/qml/intents/apps/cannot-start/info.yaml delete mode 100644 tests/qml/intents/apps/intents1/icon.png delete mode 100644 tests/qml/intents/apps/intents1/info.yaml delete mode 100644 tests/qml/intents/apps/intents1/intents1.qml delete mode 100644 tests/qml/intents/apps/intents2/icon.png delete mode 100644 tests/qml/intents/apps/intents2/info.yaml delete mode 100644 tests/qml/intents/apps/intents2/intents2.qml delete mode 100644 tests/qml/intents/intents.pro delete mode 100644 tests/qml/intents/tst_intents.qml delete mode 100644 tests/qml/lifecycle/am-config.yaml delete mode 100644 tests/qml/lifecycle/apps/tld.test.lifecycle/app.qml delete mode 100644 tests/qml/lifecycle/apps/tld.test.lifecycle/icon.png delete mode 100644 tests/qml/lifecycle/apps/tld.test.lifecycle/info.yaml delete mode 100644 tests/qml/lifecycle/lifecycle.pro delete mode 100644 tests/qml/lifecycle/tst_lifecycle.qml delete mode 100644 tests/qml/processtitle/am-config-quick.yaml delete mode 100644 tests/qml/processtitle/am-config.yaml delete mode 100644 tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml delete mode 100644 tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png delete mode 100644 tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml delete mode 100644 tests/qml/processtitle/apps/test.processtitle.app/app.qml delete mode 100644 tests/qml/processtitle/apps/test.processtitle.app/icon.png delete mode 100644 tests/qml/processtitle/apps/test.processtitle.app/info.yaml delete mode 100644 tests/qml/processtitle/processtitle.pro delete mode 100644 tests/qml/processtitle/tst_processtitle.qml delete mode 100644 tests/qml/qml.pro delete mode 100644 tests/qml/quicklaunch/am-config.yaml delete mode 100644 tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml delete mode 100644 tests/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png delete mode 100644 tests/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml delete mode 100644 tests/qml/quicklaunch/quicklaunch.pro delete mode 100644 tests/qml/quicklaunch/tst_quicklaunch.qml delete mode 100644 tests/qml/resources/am-config.yaml delete mode 100644 tests/qml/resources/appcommon/Quicklaunch.qml delete mode 100644 tests/qml/resources/appcommon/appcommon.pro delete mode 100644 tests/qml/resources/appcommon/appcommonfile.qrc delete mode 100644 tests/qml/resources/appcommon/qml/common/CommonObj.qml delete mode 100644 tests/qml/resources/appcommon/qml/common/qmldir delete mode 100644 tests/qml/resources/apps/app1/app1.pro delete mode 100644 tests/qml/resources/apps/app1/app1.qml delete mode 100644 tests/qml/resources/apps/app1/app1file.qrc delete mode 100644 tests/qml/resources/apps/app1/app1plugin.qrc delete mode 100644 tests/qml/resources/apps/app1/icon.png delete mode 100644 tests/qml/resources/apps/app1/info.yaml delete mode 100644 tests/qml/resources/apps/app1/qml/forms/AquaRect.qml delete mode 100644 tests/qml/resources/apps/app1/qml/forms/YellowRect.qml delete mode 100644 tests/qml/resources/apps/app1/qml/forms/qmldir delete mode 100644 tests/qml/resources/apps/app2/BlueRect.qml delete mode 100644 tests/qml/resources/apps/app2/app2.pro delete mode 100644 tests/qml/resources/apps/app2/app2.qml delete mode 100644 tests/qml/resources/apps/app2/app2.qrc delete mode 100644 tests/qml/resources/apps/app2/icon.png delete mode 100644 tests/qml/resources/apps/app2/info.yaml delete mode 100644 tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml delete mode 100644 tests/qml/resources/apps/app2/qml/appwidgets/qmldir delete mode 100644 tests/qml/resources/qml/widgets/MagentaRect.qml delete mode 100644 tests/qml/resources/qml/widgets/RedRect.qml delete mode 100644 tests/qml/resources/qml/widgets/qmldir delete mode 100644 tests/qml/resources/relative/elements/LinenRect.qml delete mode 100644 tests/qml/resources/relative/elements/qmldir delete mode 100644 tests/qml/resources/resources.pro delete mode 100644 tests/qml/resources/systemuifile.qrc delete mode 100644 tests/qml/resources/systemuiplugin.qrc delete mode 100644 tests/qml/resources/test.pro delete mode 100644 tests/qml/resources/tst_resource.qml delete mode 100644 tests/qml/simple/am-config.yaml delete mode 100644 tests/qml/simple/apps/tld.test.simple1/app1.qml delete mode 100644 tests/qml/simple/apps/tld.test.simple1/icon.png delete mode 100644 tests/qml/simple/apps/tld.test.simple1/info.yaml delete mode 100644 tests/qml/simple/apps/tld.test.simple2/app.qml delete mode 100644 tests/qml/simple/apps/tld.test.simple2/icon.png delete mode 100644 tests/qml/simple/apps/tld.test.simple2/info.yaml delete mode 100644 tests/qml/simple/simple.pro delete mode 100644 tests/qml/simple/text-file.txt delete mode 100644 tests/qml/simple/tst_applicationmanager.qml delete mode 100644 tests/qml/windowitem/am-config.yaml delete mode 100644 tests/qml/windowitem/apps/test.windowitem.app/icon.png delete mode 100644 tests/qml/windowitem/apps/test.windowitem.app/info.yaml delete mode 100644 tests/qml/windowitem/apps/test.windowitem.app/main.qml delete mode 100644 tests/qml/windowitem/apps/test.windowitem.multiwin/icon.png delete mode 100644 tests/qml/windowitem/apps/test.windowitem.multiwin/info.yaml delete mode 100644 tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml delete mode 100644 tests/qml/windowitem/tst_windowitem.qml delete mode 100644 tests/qml/windowitem/windowitem.pro delete mode 100644 tests/qml/windowitem2/am-config.yaml delete mode 100644 tests/qml/windowitem2/apps/test.windowitem2.app/icon.png delete mode 100644 tests/qml/windowitem2/apps/test.windowitem2.app/info.yaml delete mode 100644 tests/qml/windowitem2/apps/test.windowitem2.app/main.qml delete mode 100644 tests/qml/windowitem2/tst_windowitem2.qml delete mode 100644 tests/qml/windowitem2/windowitem2.pro delete mode 100644 tests/qml/windowmanager/IviApplicationExtension.qml delete mode 100644 tests/qml/windowmanager/tst_windowmanager.qml delete mode 100644 tests/qml/windowmanager/windowmanager.pro delete mode 100644 tests/qml/windowmapping/am-config.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin2/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.amwin2/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.loader/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.loader/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.loader/loader.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.ping/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.ping/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.ping/ping.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.qtobject/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.qtobject/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.rectangle/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.rectangle/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.window/icon.png delete mode 100644 tests/qml/windowmapping/apps/test.winmap.window/info.yaml delete mode 100644 tests/qml/windowmapping/apps/test.winmap.window/window.qml delete mode 100644 tests/qml/windowmapping/tst_windowmapping.qml delete mode 100644 tests/qml/windowmapping/windowmapping.pro delete mode 100644 tests/runtime/runtime.pro delete mode 100644 tests/runtime/tst_runtime.cpp delete mode 100644 tests/signature/create-test-data.sh delete mode 100644 tests/signature/signature-openssl.p7 delete mode 100644 tests/signature/signature-securityframework.p7 delete mode 100644 tests/signature/signature-wincrypt.p7 delete mode 100644 tests/signature/signature.pro delete mode 100644 tests/signature/signing-no-key.p12 delete mode 100644 tests/signature/signing.p12 delete mode 100644 tests/signature/tst_signature.cpp delete mode 100644 tests/signature/tst_signature.qrc delete mode 100644 tests/signature/verifying.crt delete mode 100644 tests/sudo/sudo.pro delete mode 100644 tests/sudo/tst_sudo.cpp delete mode 100644 tests/systemreader/root/proc/1234/cgroup delete mode 100644 tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes delete mode 100644 tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat delete mode 100644 tests/systemreader/systemreader.pro delete mode 100644 tests/systemreader/tst_systemreader.cpp delete mode 100644 tests/tests.pri delete mode 100644 tests/tests.pro delete mode 100644 tests/utilities/tst_utilities.cpp delete mode 100644 tests/utilities/utilities.pro delete mode 100644 tests/yaml/data/cache1.yaml delete mode 100644 tests/yaml/data/cache2.yaml delete mode 100644 tests/yaml/data/test.yaml delete mode 100644 tests/yaml/tst_yaml.cpp delete mode 100644 tests/yaml/yaml.pro diff --git a/.cmake.conf b/.cmake.conf new file mode 100644 index 00000000..4e73b3d6 --- /dev/null +++ b/.cmake.conf @@ -0,0 +1 @@ +set(QT_REPO_MODULE_VERSION "6.2.0") diff --git a/3rdparty/README.md b/3rdparty/README.md deleted file mode 100644 index 26baa958..00000000 --- a/3rdparty/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## How to recreate the qmake base buildsystem for the 3rd-party stuff - -## openssl - -### Linux - -* `./config no-asm no-idea` -* `make` -* `cp crypto/buildinf.h libcrypto-include-unix` -* `cp include/openssl/opensslconf.h libcrypto-include-unix/openssl` - -### Mac OS X - -* `./Configure darwin64-x86_64-cc no-asm no-idea` -* `make depend` -* `make` -* `cp crypto/buildinf.h libcrypto-include-osx` -* `cp include/openssl/opensslconf.h libcrypto-include-osx/openssl` - -### Windows -* `perl Configure VC-WIN32 no-asm no-idea` -* `ms\do_ms.bat` -* `nmake -f ms\nt.mak` -* `copy /Y crypto\buildinf.h libarchive-include-win32` -* `copy /Y inc32\openssl\*.h libarchive-include-win32\openssl` - - -## xz - -### Linux -* ` ./configure --disable-shared --enable-threads=no --disable-assembler --disable-xz --disable-xzdec - --disable-lzmadec --disable-lzmainfo --disable-lzma-links --disable-scripts --disable-doc` -* `cp config.h config-unix.h` -* `echo "#include PLATFORM_CONFIG_H" >config.h` - -### Mac OS X -* ` ./configure --disable-shared --enable-threads=no --disable-assembler --disable-xz --disable-xzdec - --disable-lzmadec --disable-lzmainfo --disable-lzma-links --disable-scripts --disable-doc` -* `cp config.h config-osx.h` -* `echo "#include PLATFORM_CONFIG_H" >config.h` - -### Windows -* `copy /Y windows\config.h config-windows.h` -* `echo #include PLATFORM_CONFIG_H >config.h` - - -## libarchive - -### Linux -* `./configure --disable-shared --disable-bsdtar --disable-bsdcpio --disable-xattr --disable-acl - --without-bz2lib --without-lzmadec --without-lzo2 --without-nettle --without-openssl - --without-xml2 --without-expat` -* `cp config.h config-unix.h` -* `rm -rf CMakeLists.txt Makefile.* aclocal.m4 config.h.in configure* build/ contrib doc examples cpio libarchive_fe/ tar test_utils libarchive/CMakeLists.txt libarchive/test libarchive/*.5 libarchive/*.3` - -### Mac OS X -* `./configure --disable-shared --disable-bsdtar --disable-bsdcpio --disable-xattr --disable-acl - --without-bz2lib --without-lzmadec --without-lzo2 --without-nettle --without-openssl - --without-xml2 --without-expat` -* `cp config.h config-osx.h` - -### Windows -Prerequisite: build zlib 1.2.8 - -* `mkdir cbuild` -* `cd cbuild` -* `cmake -DENABLE_TAR=OFF -DENABLE_CPIO=OFF -DENABLE_XATTR=OFF -DENABLE_ACL=OFF -DENABLE_TEST=OFF - -DENABLE_OPENSSL=OFF -DZLIB_LIBRARY=..\..\zlib-1.2.8\release\z.lib -DZLIB_INCLUDE_DIR=..\..\zlib-1.2.8` -* `copy /Y config.h config-windows.h` - -## libyaml - -* `rm -rf CMakeLists.txt Makefile.* aclocal.m4 config* doc tests win32 yaml-0.1.pc.in include/Makefile.* src/Makefile.*` diff --git a/3rdparty/libarchive.pri b/3rdparty/libarchive.pri deleted file mode 100644 index ad1e0bc6..00000000 --- a/3rdparty/libarchive.pri +++ /dev/null @@ -1,9 +0,0 @@ - -include(libz.pri) - -!config_libarchive|no-system-libarchive { - QMAKE_USE_PRIVATE += archive -} else { - PKGCONFIG_PRIVATE += "'libarchive >= 3.1.2'" - CONFIG *= link_pkgconfig -} diff --git a/3rdparty/libarchive/COPYING b/3rdparty/libarchive/COPYING deleted file mode 100644 index 93952b77..00000000 --- a/3rdparty/libarchive/COPYING +++ /dev/null @@ -1,59 +0,0 @@ -The libarchive distribution as a whole is Copyright by Tim Kientzle -and is subject to the copyright notice reproduced at the bottom of -this file. - -Each individual file in this distribution should have a clear -copyright/licensing statement at the beginning of the file. If any do -not, please let me know and I will rectify it. The following is -intended to summarize the copyright status of the individual files; -the actual statements in the files are controlling. - -* Except as listed below, all C sources (including .c and .h files) - and documentation files are subject to the copyright notice reproduced - at the bottom of this file. - -* The following source files are also subject in whole or in part to - a 3-clause UC Regents copyright; please read the individual source - files for details: - libarchive/archive_entry.c - libarchive/archive_read_support_filter_compress.c - libarchive/archive_write_add_filter_compress.c - libarchive/mtree.5 - -* The following source files are in the public domain: - libarchive/archive_getdate.c - -* The build files---including Makefiles, configure scripts, - and auxiliary scripts used as part of the compile process---have - widely varying licensing terms. Please check individual files before - distributing them to see if those restrictions apply to you. - -I intend for all new source code to use the license below and hope over -time to replace code with other licenses with new implementations that -do use the license below. The varying licensing of the build scripts -seems to be an unavoidable mess. - - -Copyright (c) 2003-2009 -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer - in this position and unchanged. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3rdparty/libarchive/INSTALL b/3rdparty/libarchive/INSTALL deleted file mode 100644 index 2fafbd50..00000000 --- a/3rdparty/libarchive/INSTALL +++ /dev/null @@ -1,35 +0,0 @@ -More complete build documentation is available on the libarchive -Wiki: https://github.com/libarchive/libarchive/wiki - -On most Unix-like systems, you should be able to install libarchive, -bsdtar, and bsdcpio using the following common steps: - ./configure - make - make install - -If you need to customize the target directories or otherwise adjust -the build setting, use - ./configure --help -to list the configure options. - -If you are developing libarchive and need to update the -configure script and other build files: - /bin/sh build/autogen.sh - -To create a distribution, please use the 'distcheck' target: - /bin/sh build/autogen.sh && ./configure && make distcheck - -On Unix-like and non-Unix-like systems, use the "cmake" utility (available from -http://cmake.org/) to generate suitable build files for your platform. -Cmake requires the name of the directory containing CmakeLists.txt and -the "generator" to use for your build environment. For example, to -build with Xcode on Mac OS, you can use the following command: - cmake -G "Xcode" ~/libarchive-download-dir/ -The result will be appropriate makefiles, solution files, or project -files that can be used with the corresponding development tool. -The default on Unix-like systems is to generate Makefiles, so you -can also use cmake instead of the configure script: - cmake ~/libarchive-download-dir/ - make - make install -See the libarchive Wiki or the cmake site for further documentation. diff --git a/3rdparty/libarchive/NEWS b/3rdparty/libarchive/NEWS deleted file mode 100644 index 9527e662..00000000 --- a/3rdparty/libarchive/NEWS +++ /dev/null @@ -1,687 +0,0 @@ -Jul 09, 2017: libarchive 3.3.2 released - -Mar 16, 2017: NFSv4 ACL support for Linux (librichacl) - -Feb 26, 2017: libarchive 3.3.1 released - Security & Feature release - -Feb 19, 2017: libarchive 3.3.0 released - Security & Feature release - -Jan 29, 2017: Limited NFSv4 ACL support for Mac OS (Darwin) - -Jan 10, 2017: POSIX.1e and NFSv4 ACL support for Solaris and derivates - -Dec 27, 2016: NFSv4 ACL read and write support for pax - Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w() - -Nov, 2016: libarchive is now being tested by the OSS-Fuzz project - -Oct 26, 2016: Remove liblzmadec support - -Oct 23, 2016: libarchive 3.2.2 released - Security release - -Jun 20, 2016: libarchive 3.2.1 released - This fixes a handful of security and other critical issues with 3.2.0 - -May 01, 2016: libarchive 3.2.0 released - -Apr 09, 2016: libarchive 3.1.901a released - Another test release in preparation for 3.2.0 - -Feb 13, 2016: libarchive 3.1.900a released - This is a test release in preparation for 3.2.0 - -Oct 21, 2015: Preliminary port to OSF - -Apr 11, 2015: libarchive's issue tracker is now hosted at GitHub. - https://github.com/libarchive/libarchive/issues - -Early 2015: Many fixes to crash and overflow bugs thanks to Hanno Boeck - -Oct 13, 2014: Zip encryption and decryption support - -Aug 13, 2014: Add support for lz4 compression. - -Jun 10, 2014: Add warc format support - -May 3, 2014: Add experimental Zip streaming extension - -Apr 6, 2014: Add bsdcat command-line tool - -Jan 12, 2014: Add Zip64 support - -Dec 1, 2013: Rewrite Zip write logic - -Jul 1, 2013: Add ability to detect encrypted entries for many formats - (This does not add the ability to *decrypt* those entries, however) - -Feb 23, 2013: "raw" write support added - -Feb 09, 2013: libarchive 3.1.2 released - -Jan 28, 2013: libarchive's new website moved to http://www.libarchive.org. - -Jan 13, 2013: libarchive 3.1.1 released - -Jan 13, 2013: libarchive 3.1.0 released - -Dec 07, 2012: Implement functions to manually set the format and filters used. - -Nov 11, 2012: Add support for __MACOSX directory in Zip archives, which resource - forks are stored in. - -Oct 20, 2012: Add support for writing v7 tar format. - -Oct 09, 2012: Add support for grzip compression. - -Oct 07, 2012: Introduce b64encode filter. -Oct 07, 2012: Introduce uuencode filter. - -Oct 06, 2012: Add support for lzop. - -Sep 27, 2012: Implement function used to seek within data blocks. - (Currently only supported for uncompressed RAR archives). - -Apr 22, 2012: Add basic archive read and write filter support for lrzip. - -Mar 27, 2012: libarchive 3.0.4 released - -Feb 05, 2012: libarchive development now hosted at GitHub. - http://libarchive.github.com/ -Feb 05, 2012: libarchive's issue tracker remains at Google Code. - http://code.google.com/p/libarchive/issues/list -Feb 05, 2012: libarchive's mailing lists remain at Google Groups. - -Dec 24, 2011: libarchive 3.0.2 released -Dec 23, 2011: Various fixes merged from FreeBSD -Dec 23, 2011: Symlink support in Zip reader and writer -Dec 23, 2011: Robustness fixes to 7Zip reader - -Nov 27, 2011: libarchive 3.0.1b released - -Nov 26, 2011: 7Zip reader -Nov 26, 2011: Small fixes to ISO and Zip to improve robustness with corrupted input -Nov 24, 2011: Improve streaming Zip reader's support for uncompressed entries -Nov 20, 2011: New seeking Zip reader supports SFX Zip archives -Nov 20, 2011: Build fixes on Windows - -Nov 13, 2011: libarchive 3.0.0a released - -Nov 06, 2011: Update shared-library version calculations for libarchive 3.x -Sep 04, 2011: Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions -Aug 18, 2011: Fix reading ISO images built by NetBSD's mkisofs -Aug 15, 2011: Old archive_read_support_compression_XXX functions are deprecated and - will disappear in libarchive 4.0. -Jun 26, 2011: RAR reader -Jun 16, 2011: Add tar:compat-2x option to emulate broken libarchive 2.x - handling of pax UTF-8 headers -Apr 25, 2011: Refactor read_open() into a collection of single-item setters; - support the old interfaces as wrappers -Apr 12, 2011: Split disk writer into separate POSIX and Windows implementations -Apr 10, 2011: Improvements to character translations on Windows. -Mar 30, 2011: More work to return errors instead of calling abort() -Mar 23, 2011: Add charset option to many writers to control MBCS filenames -Mar 17, 2011: Overhauled support for per-format extension options -Mar 17, 2011: Track character set used for mbcs strings, support - translating to/from user-specified locale -Mar 09, 2011: Recognize mtree files without requiring a signature -Mar 06, 2011: Use iconv to convert to/from Unicode instead of making bad - assumptions about the C90 character set translation functions -Feb 17, 2011: Fixes for AIX, TRU64, and other platforms -Dec 22, 2010: CAB reader -Dec 20, 2010: LHA/LZH reader -Jul 03, 2010: minitar example demonstrates archive_read_disk directory traversal -Jun 29, 2010: Many improvements to ISO reader compatibility -Jun 26, 2010: Use larger buffers when copy files into an archive -Jun 18, 2010: Reimplement Mac OS extensions in libarchive -Jun 09, 2010: archive_read_disk now supports traversals -May 28, 2010: XAR writer -May 16, 2010: Fix ^T handling; don't exit on interrupted reads and writes -May 09, 2010: Improved detection of platform-specific crypto support -May 04, 2010: lzip read and write filters -May 01, 2010: New options: tar --gid --gname --uid --uname -Apr 28, 2010: Use Red-black tree for ISO reader/writer to improve performance -Apr 17, 2010: Minimal writer for legacy GNU tar format -Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs. -Mar 06, 2010: Fix build when an older libarchive is already installed -Feb 28, 2010: Relax handling of state failures; misuse by clients now generally - results in a sticky ARCHIVE_FATAL rather than a visit to abort() -Feb 25, 2010: ISO writer -Feb 21, 2010: Split many man pages into smaller chunks. -Feb 21, 2010: Performance: Cheat on block sizes when reading archives from disk. -Feb 21, 2010: Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t -Feb 20, 2010: Document new ACL functions. -Feb 19, 2010: Support multiple write filters -Feb 07, 2010: Remove some legacy libarchive 1.x APIs -Feb 04, 2010: Read afio headers -Feb 02, 2010: Archive sparse files compatibly with GNU tar -Feb 01, 2010: Integrate Apple extensions for Mac OS extended attributes into bsdtar -Jan 31, 2010: Support cpio -V - -Feb 04, 2010: libarchive 2.8.0 released -Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o' -Jan 17, 2010: Don't use futimes() on Cygwin - -Jan 02, 2010: libarchive 2.7.902a released (test release for 2.8) -Jan 02, 2010: Fix tar/test/test_windows on MinGW -Jan 02, 2010: Fix memory leaks in libarchive tests -Jan 01, 2010: Fix memory leak when filter startup fails - -Dec 27, 2009: libarchive 2.7.901a released (test release for 2.8) - -Aug 04, 2009: libarchive 2.7.1 released -Jul 20, 2009: Suppress bogus warning about unxz -Jul 19, 2009: Support Cygwin 1.7 -Jun 11, 2009: Support lzma/xz files compressed with larger buffer sizes. -May 24, 2009: Handle gzip files signed with OpenBSD "gzsig" program. -May 07, 2009: Avoid false failures when reading from pipe. - -Apr 16, 2009: libarchive 2.7.0 released - -Apr 10, 2009: libarchive 2.6.992a released -Apr 09, 2009: Fix SIGPIPE issue building with MSVC. -Apr 09, 2009: Fix several minor memory leaks in libarchive and libarchive_test - -Apr 08, 2009: libarchive 2.6.991a released -Apr 07, 2009: Additional tests added to bsdcpio_test - -Apr 01, 2009: libarchive 2.6.990a released -Apr 01, 2009: Use command-line gunzip, bunzip2, unxz, unlzma for - decompression if the library is built without suitable - libraries. The setup functions return ARCHIVE_WARN - in this case so clients can adapt if necessary. -Apr 01, 2009: Use getpw*_r and getgr*_r functions for thread-safety. -Mar 24, 2009: Add archive_read_next_header2(), which is up to 25% - more efficient for some clients; from Brian Harring. -Mar 22, 2009: PDF versions of manpages are now included in the distribution. -Mar, 2009: Major work to improve Cygwin build by Charles Wilson. -Feb/Mar, 2009: Major work on cmake build support, mostly by Michihiro NAKAJIMA. -Feb/Mar, 2009: Major work on Visual Studio support by Michihiro NAKAJIMA. - All tests now pass. -Feb 25, 2009: Fix Debian Bug #516577 -Feb 21, 2009: Yacc is no longer needed to build; date parser rewritten in C. -Jan/Feb, 2009: Mtree work by Michihiro. -Feb, 2009: Joliet support by Andreas Henriksson. -Jan/Feb, 2009: New options framework by Michihiro. -Feb, 2009: High-res timestamps on Tru64, AIX, and GNU Hurd, by Björn Jacke. -Jan 18, 2009: Extended attributes work on FreeBSD and Linux now with pax format. -Jan 07, 2009: New archive_read_disk_entry_from_file() knows about ACLs, - extended attributes, etc so that bsdtar and bsdcpio don't require - such system-specific knowledge. -Jan 03, 2009: Read filter system extensively refactored. In particular, - read filter pipelines are now built out automatically and individual - filters should be much easier to implement. Documentation on the - Googlecode Wiki explains how to implement new filters. -Dec 28, 2008: Many Windows/Visual Studio fixes from Michihiro NAKAJIMA. - -Dec 28, 2008: Main libarchive development moved from FreeBSD Perforce - server to Google Code. This should make it easier for more - people to participate in libarchive development. - -Dec 28, 2008: libarchive 2.6.0 released -Dec 25, 2008: libarchive 2.5.905a released -Dec 10, 2008: libarchive 2.5.904a released -Dec 04, 2008: libarchive 2.5.903a released -Nov 09, 2008: libarchive 2.5.902a released -Nov 08, 2008: libarchive 2.5.901a released -Nov 08, 2008: Start of pre-release testing for libarchive 2.6 - -Nov 07, 2008: Read filter refactor: The decompression routines just - consume and produce arbitrarily-sized blocks. The reblocking - from read_support_compression_none() has been pulled into the - read core. Also, the decompression bid now makes multiple - passes and stacks read filters. -Oct 21, 2008: bsdcpio: New command-line parser. -Oct 19, 2008: Internal read_ahead change: short reads are now an error -Oct 06, 2008: bsdtar: option parser no longer uses getopt_long(), - gives consistent option parsing on all platforms. -Sep 19, 2008: Jaakko Heinonen: shar utility built on libarchive -Sep 17, 2008: Pedro Giffuni: birthtime support -Sep 17, 2008: Miklos Vajna: lzma reader and test. Note: I still have - some concerns about the auto-detection (LZMA file format - doesn't support auto-detection well), so this is not yet - enabled under archive_read_support_compression_all(). For - now, you must call archive_read_support_compression_lzma() if - you want LZMA read support. -Sep 11, 2008: Ivailo Petrov: Many fixes to Windows build, new solution files -Jul 26, 2008: archive_entry now tracks which values have not been set. - This helps zip extraction (file size is often "unknown") and - time restores (tar usually doesn't know atime). -Jul 26, 2008: Joerg Sonnenberger: Performance improvements to shar writer -Jul 25, 2008: Joerg Sonnenberger: mtree write support - -Jul 02, 2008: libarchive 2.5.5 released - -Jul 02, 2008: libarchive 2.5.5b released -Jul 01, 2008: bsdcpio is being used by enough people, we can call it 1.0.0 now -Jun 20, 2008: bsdcpio: If a -l link fails with EXDEV, copy the file instead -Jun 19, 2008: bsdcpio: additional long options for better GNU cpio compat -Jun 15, 2008: Many small portability and bugfixes since 2.5.4b. - -May 25, 2008: libarchive 2.5.4b released -May 21, 2008: Joerg Sonnenberger: fix bsdtar hardlink handling for newc format - -May 21, 2008: More progress on Windows building. Thanks to "Scott" - for the Windows makefiles, thanks to Kees Zeelenberg for - code contributions. - -May 21, 2008: Fix a number of non-exploitable integer and buffer overflows, - thanks to David Remahl at Apple for pointing these out. - -May 21, 2008: Colin Percival: SIGINFO or SIGUSR1 to bsdtar prints progress info - -May 16, 2008: bsdtar's test harness no longer depends on file ordering. - This was causing spurious test failures on a lot of systems. - Thanks to Bernhard R. Link for the diagnosis. - -May 14, 2008: Joerg Sonnenberger: -s substitution support for bsdtar - -May 13, 2008: Joerg Sonnenberger: Many mtree improvements - -May 11, 2008: Joerg Sonnenberger: fix hardlink extraction when - hardlinks have different permissions from original file - -April 30, 2008: Primary libarchive work has been moved into the FreeBSD - project's Perforce repository: http://perforce.freebsd.org/ - The libarchive project can be browsed at - //depot/user/kientzle/libarchive-portable - Direct link: http://preview.tinyurl.com/46mdgr - -May 04, 2008: libarchive 2.5.3b released - * libarchive: Several fixes to link resolver to address bsdcpio crashes - * bsdcpio: -p hardlink handling fixes - * tar/pax: Ensure ustar dirnames end in '/'; be more careful about - measuring filenames when deciding what pathname fields to use - * libarchive: Mark which entry strings are set; be accurate about - distinguishing empty strings ("") from unset ones (NULL) - * tar: Don't crash reading entries with empty filenames - * libarchive_test, bsdtar_test, bsdcpio_test: Better defaults: - run all tests, delete temp dirs, summarize repeated failures - * -no-undefined to libtool for Cygwin - * libarchive_test: Skip large file tests on systems with 32-bit off_t - * iso9660: Don't bother trying to find the body of an empty file; - this works around strange behavior from some ISO9660 writers - * tar: allow -r -T to be used together - * tar: allow --format with -r or -u - * libarchive: Don't build archive.h - -May 04, 2008: Simplified building: archive.h is no longer constructed - This may require additional #if conditionals on some platforms. - -Mar 30, 2008: libarchive 2.5.1b released - -Mar 15, 2008: libarchive 2.5.0b released -Mar 15, 2008: bsdcpio now seems to correctly write hardlinks into newc, - ustar, and old cpio archives. Just a little more testing before - bsdcpio 1.0 becomes a reality. -Mar 15, 2008: I think the new linkify() interface is finally handling - all known hardlink strategies. -Mar 15, 2008: Mtree read fixes from Joerg Sonnenberger. -Mar 15, 2008: Many new bsdtar and bsdcpio options from Joerg Sonnenberger. -Mar 15, 2008: test harnesses no longer require uudecode; they - now have built-in decoding logic that decodes the reference - files as they are needed. - -Mar 14, 2008: libarchive 2.4.14 released; identical to 2.4.13 except for - a point fix for gname/uname mixup in pax format that was introduced - with the UTF-8 fixes. - -Feb 26, 2008: libarchive 2.4.13 released -Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted - to/from UTF-8. Implement "hdrcharset" attribute from SUS-2008. -Feb 25, 2008: Fix name clash on NetBSD. -Feb 18, 2008: Fix writing empty 'ar' archives, per Kai Wang -Feb 18, 2008: [bsdtar] Permit appending on block devices. -Feb 09, 2008: New "linkify" resolver to help with newc hardlink writing; - bsdcpio still needs to be converted to use this. -Feb 02, 2008: Windows compatibility fixes from Ivailo Petrov, Kees Zeelenberg -Jan 30, 2008: Ignore hardlink size for non-POSIX tar archives. - -Jan 22, 2008: libarchive 2.4.12 released -Jan 22, 2008: Fix bad padding when writing symlinks to newc cpio archives. -Jan 22, 2008: Verify bsdcpio_test by getting it to work against GNU cpio 2.9. - bsdcpio_test complains about missing options (-y and -z), format - of informational messages (--version, --help), and a minor formatting - issue in odc format output. After this update, bsdcpio_test uncovered - several more cosmetic issues in bsdcpio, all now fixed. -Jan 22, 2008: Experimental support for self-extracting Zip archives. -Jan 22, 2008: Extend hardlink restore strategy to work correctly with - hardlinks extracted from newc cpio files. (Which store the body - only with the last occurrence of a link.) - -Dec 30, 2007: libarchive 2.4.11 released -Dec 30, 2007: Fixed a compile error in bsdcpio on some systems. - -Dec 29, 2007: libarchive 2.4.10 released -Dec 29, 2007: bsdcpio 0.9.0 is ready for wider use. -Dec 29, 2007: Completed initial test harness for bsdcpio. - -Dec 22, 2007: libarchive 2.4.9 released -Dec 22, 2007: Implement the remaining options for bsdcpio: -a, -q, -L, -f, - pattern selection for -i and -it. - -Dec 13, 2007: libarchive 2.4.8 released -Dec 13, 2007: gzip and bzip2 compression now handle zero-byte writes correctly, - Thanks to Damien Golding for bringing this to my attention. - -Dec 12, 2007: libarchive 2.4.7 released - -Dec 10, 2007: libarchive 2.4.6 released -Dec 09, 2007: tar/test/test_copy.c verifies "tar -c | tar -x" copy pipeline -Dec 07, 2007: Fix a couple of minor memory leaks. - -Dec 04, 2007: libarchive 2.4.5 released -Dec 04, 2007: Fix cpio/test/test_write_odc by setting the umask first. - -Dec 03, 2007: libarchive 2.4.4 released -Dec 03, 2007: New configure options --disable-xattr and --disable-acl, - thanks to Samuli Suominen. - -Dec 03, 2007: libarchive 2.4.3 released -Dec 03, 2007: Thanks to Lapo Luchini for sending me a ZIP file that - libarchive couldn't handle. Fixed a bug in handling of - "length at end" flags in ZIP files. -Dec 03, 2007: Fixed bsdcpio -help, bsdtar -help tests. -Dec 02, 2007: First cut at real bsdtar test harness. - -Dec 02, 2007: libarchive 2.4.2 released - -Dec 02, 2007: libarchive 2.4.1 released -Dec 02, 2007: Minor fixes, rough cut of mdoc-to-man conversion for - man pages. - -Oct 30, 2007: libarchive 2.4.0 released -Oct 30, 2007: Minor compile fix thanks to Joerg Schilling. -Oct 30, 2007: Only run the format auction once at the beginning of the - archive. This is simpler and supports better error recovery. -Oct 29, 2007: Test support for very large entries in tar archives: - libarchive_test now exercises entries from 2GB up to 1TB. - -Oct 27, 2007: libarchive 2.3.5 released -Oct 27, 2007: Correct some unnecessary internal data copying in the - "compression none" reader and writer; this reduces user time - by up to 2/3 in some tests. (Thanks to Jan Psota for - publishing his performance test results to GNU tar's bug-tar - mailing list; those results pointed me towards this problem.) -Oct 27, 2007: Fix for skipping archive entries that are exactly - a multiple of 4G on 32-bit platforms. -Oct 25, 2007: Fix for reading very large (>8G) tar archives; this was - broken when I put in support for new GNU tar sparse formats. -Oct 20, 2007: Initial work on new pattern-matching code for cpio; I - hope this eventually replaces the code currently in bsdtar. - -Oct 08, 2007: libarchive 2.3.4 released -Oct 05, 2007: Continuing work on bsdcpio test suite. -Oct 05, 2007: New cpio.5 manpage, updates to "History" of bsdcpio.1 and - bsdtar.1 manpages. -Oct 05, 2007: Fix zip reader to immediately return EOF if you try - to read body of non-regular file. In particular, this fixes - bsdtar extraction of zip archives. - -Sep 30, 2007: libarchive 2.3.3 released -Sep 26, 2007: Rework Makefile.am so that the enable/disable options - actually do the right things. -Sep 26, 2007: cpio-odc and cpio-newc archives no longer write bodies - for non-regular files. -Sep 26, 2007: Test harness for bsdcpio is in place, needs more tests written. - This is much nicer than the ragtag collection of test scripts - that bsdtar has. - -Sep 20, 2007: libarchive 2.3.2 released -Sep 20, 2007: libarchive 2.3.1 broke bsdtar because the archive_write_data() - fix was implemented incorrectly. - -Sep 16, 2007: libarchive 2.3.1 released -Sep 16, 2007: Many fixes to bsdcpio 0.3: handle hardlinks with -p, recognize - block size on writing, fix a couple of segfaults. -Sep 16, 2007: Fixed return value from archive_write_data() when used - with archive_write_disk() to match the documentation and other - instances of this same function. -Sep 15, 2007: Add archive_entry_link_resolver, archive_entry_strmode - -Sep 11, 2007: libarchive 2.2.8 released -Sep 09, 2007: bsdcpio 0.2 supports most (not yet all) of the old POSIX spec. - -Sep 01, 2007: libarchive 2.2.7 released -Aug 31, 2007: Support for reading mtree files, including an mtree.5 manpage - (A little experimental still.) -Aug 18, 2007: Read gtar 1.17 --posix --sparse entries. -Aug 13, 2007: Refined suid/sgid restore handling; it is no longer - an error if suid/sgid bits are dropped when you request - perm restore but don't request owner restore. -Aug 06, 2007: Use --enable-bsdcpio if you want to try bsdcpio - -Aug 05, 2007: libarchive 2.2.6 released -Aug 05, 2007: New configure option --disable-bsdtar, thanks to Joerg - Sonnenberger. -Aug 05, 2007: Several bug fixes from FreeBSD CVS repo. - -Jul 13, 2007: libarchive 2.2.5 released - -Jul 12, 2007: libarchive 2.2.4 released -Jul 12, 2007: Thanks to Colin Percival's help in diagnosing and - fixing several critical security bugs. Details available at - http://security.freebsd.org/advisories/FreeBSD-SA-07:05.libarchive.asc - -May 26, 2007: libarchive 2.2.3 released -May 26, 2007: Fix memory leaks in ZIP reader and shar writer, add some - missing system headers to archive_entry.h, dead code cleanup - from Colin Percival, more tests for gzip/bzip2, fix an - EOF anomaly in bzip2 decompression. - -May 12, 2007: libarchive 2.2.2 released -May 12, 2007: Fix archive_write_disk permission restore by cloning - entry passed into write_header so that permission info is - still available at finish_entry time. (archive_read_extract() - worked okay because it held onto the passed-in entry, but - direct consumers of archive_write_disk would break). This - required fixing archive_entry_clone(), which now works and has - a reasonably complete test case. -May 10, 2007: Skeletal cpio implementation. - -May 06, 2007: libarchive 2.2.1 released -May 06, 2007: Flesh out a lot more of test_entry.c so as to catch - problems such as the device node breakage before releasing . -May 05, 2007: Fix a bad bug introduced in 2.1.9 that broke device - node entries in tar archives. -May 03, 2007: Move 'struct stat' out of archive_entry core as well. - This removes some portability headaches and fixes a bunch - of corner cases that arise when manipulating archives on - dissimilar systems. - -Apr 30, 2007: libarchive 2.1.10 released -Apr 31, 2007: Minor code cleanup. - -Apr 24, 2007: libarchive 2.1.9 released -Apr 24, 2007: Fix some recently-introduced problems with libraries - (Just let automake handle it and it all works much better.) - Finish isolating major()/minor()/makedev() in archive_entry.c. - -Apr 23, 2007: libarchive 2.1.8 released -Apr 23, 2007: Minor fixes found from building on MacOS X - -Apr 22, 2007: libarchive 2.1.7 released -Apr 22, 2007: Eliminated all uses of 'struct stat' from the - format readers/writers. This should improve portability; - 'struct stat' is now only used in archive_entry and in - code that actually touches the disk. - -Apr 17, 2007: libarchive 2.1.6 released - Libarchive now compiles and passes all tests on Interix. - -Apr 16, 2007: libarchive 2.1.5 released - -Apr 15, 2007: libarchive 2.1b2 released -Apr 15, 2007: New libarchive_internals.3 documentation of internal APIs. - Not complete, but should prove helpful. -Apr 15, 2007: Experimental "read_compress_program" and "write_compress_program" - for using libarchive with external compression. Not yet - well tested, and likely has portability issues. Feedback - appreciated. - -Apr 14, 2007: libarchive 2.0.31 released -Apr 14, 2007: More fixes for Interix, more 'ar' work - -Apr 14, 2007: libarchive 2.0.30 released -Apr 13, 2007: libarchive now enforces trailing '/' on dirs - written to tar archives - -Apr 11, 2007: libarchive 2.0.29 released -Apr 11, 2007: Make it easier to statically configure for different platforms. -Apr 11, 2007: Updated config.guess, config.sub, libtool - -Apr 06, 2007: libarchive 2.0.28 released -Apr 06, 2007: 'ar' format read/write support thanks to Kai Wang. - -Apr 01, 2007: libarchive 2.0.27 released -Mar 31, 2007: Several minor fixes from Colin Percival and Joerg Sonnenberger. - -Mar 12, 2007: libarchive 2.0.25 released -Mar 12, 2007: Fix broken --unlink flag. - -Mar 11, 2007: libarchive 2.0.24 released -Mar 10, 2007: Correct an ACL blunder that causes any ACL with an entry - that refers to a non-existent user or group to not be restored correctly. - The fix both makes the parser more tolerant (so that archives created - with the buggy ACLs can be read now) and corrects the ACL formatter. -Mar 10, 2007: More work on test portability to Linux. - -Mar 10, 2007: libarchive 2.0.22 released -Mar 10, 2007: Header cleanups; added linux/fs.h, removed - some unnecessary headers, added #include guards in bsdtar. - If you see any obvious compile failures from this, let me know. -Mar 10, 2007: Work on bsdtar test scripts: not yet robust enough - to enable as part of "make check", but getting better. -Mar 10, 2007: libarchive now returns ARCHIVE_FAILED when - a header write fails in a way that only affects this item. - Less bad than ARCHIVE_FATAL, but worse than ARCHIVE_WARN. - -Mar 07, 2007: libarchive 2.0.21 released -Mar 07, 2007: Add some ACL tests (only for the system-independent - portion of the ACL support for now). -Mar 07, 2007: tar's ability to read ACLs off disk got - turned off for FreeBSD; re-enable it. (ACL restores and - libarchive support for storing/reading ACLs from pax - archives was unaffected.) - -Mar 02, 2007: libarchive 2.0.20 released -Mar 2, 2007: It's not perfect, but it's pretty good. - Libarchive 2.0 is officially out of beta. - -Feb 28, 2007: libarchive 2.0b17 released -Feb 27, 2007: Make the GID restore checks more robust by checking - whether the current user has too few or too many privileges. - -Feb 26, 2007: libarchive 2.0b15 released -Feb 26, 2007: Don't lose symlinks when extracting from ISOs. - Thanks to Diego "Flameeyes" Pettenò for telling me about the - broken testcase on Gentoo that (finally!) led me to the cause - of this long-standing bug. - -Feb 26, 2007: libarchive 2.0b14 released -Feb 26, 2007: Fix a broken test on platforms that lack lchmod(). - -Feb 25, 2007: libarchive 2.0b13 released -Feb 25, 2007: Empty archives were being written as empty files, - without a proper end-of-archive marker. Fixed. - -Feb 23, 2007: libarchive 2.0b12 released -Feb 22, 2007: Basic security checks added: _EXTRACT_SECURE_NODOTDOT - and _EXTRACT_SECURE_SYMLINK. These checks used to be in bsdtar, - but they belong down in libarchive where they can be used by - other tools and where they can be better optimized. - -Feb 11, 2007: libarchive 2.0b11 released -Feb 10, 2007: Fixed a bunch of errors in libarchive's handling - of EXTRACT_PERM and EXTRACT_OWNER, especially relating - to SUID and SGID bits. - -Jan 31, 2007: libarchive 2.0b9 released -Jan 31, 2007: Added read support for "empty" archives as a - distinct archive format. Bsdtar uses this to handle, e.g., - "touch foo.tar; tar -rf foo.tar" - -Jan 22, 2007: libarchive 2.0b6 released -Jan 22, 2007: archive_write_disk API is now in place. It provides - a finer-grained interface than archive_read_extract. In particular, - you can use it to create objects on disk without having an archive - around (just feed it archive_entry objects describing what you - want to create), you can override the uname/gname-to-uid/gid lookups - (minitar uses this to avoid getpwXXX() and getgrXXX() bloat). - -Jan 09, 2007: libarchive 2.0a3 released -Jan 9, 2007: archive_extract is now much better; it handles the - most common cases with a minimal number of system calls. - Some features still need a lot of testing, especially corner - cases involving objects that already exist on disk. I expect - the next round of API overhaul will simplify building test cases. -Jan 9, 2007: a number of fixes thanks to Colin Percival, especially - corrections to the skip() framework and handling of large files. -Jan 9, 2007: Fixes for large ISOs. The code should correctly handle - very large ISOs with entries up to 4G. Thanks to Robert Sciuk - for pointing out these issues. - -Sep 05, 2006: libarchive 1.3.1 released -Sep 5, 2006: Bump version to 1.3 for new I/O wrappers. -Sep 4, 2006: New memory and FILE read/write wrappers. -Sep 4, 2006: libarchive test harness is now minimally functional; - it's located a few minor bugs in error-handling logic - -Aug 17, 2006: libarchive 1.2.54 released -Aug 17, 2006: Outline ABI changes for libarchive 2.0; these - are protected behind #ifdef's until I think I've found everything - that needs to change. -Aug 17, 2006: Fix error-handling in archive_read/write_close() - They weren't returning any errors before. -Aug 17, 2006: Fix recursive-add logic to not trigger if it's not set - Fixes a bug adding files when writing archive to pipe or when - using archive_write_open() directly. -Jul 2006: New "skip" handling improves performance extracting - single files from large uncompressed archives. - -Mar 21, 2006: 1.2.52 released -Mar 21, 2006: Fix -p on platforms that don't have platform-specific - extended attribute code. -Mar 20, 2006: Add NEWS file; fill in some older history from other - files. I'll try to keep this file up-to-date from now on. - -OLDER NEWS SUMMARIES - -Mar 19, 2006: libarchive 1.2.51 released -Mar 18, 2006: Many fixes to extended attribute support, including a redesign - of the storage format to simplify debugging. -Mar 12, 2006: Remove 'tp' support; it was a fun idea, but not worth - spending much time on. -Mar 11, 2006: Incorporated Jaakko Heinonen's still-experimental support - for extended attributes (Currently Linux-only.). -Mar 11, 2006: Reorganized distribution package: There is now one tar.gz - file that builds both libarchive and bsdtar. -Feb 13, 2006: Minor bug fixes: correctly read cpio device entries, write - Pax attribute entry names. -Nov 7, 2005: Experimental 'tp' format support in libarchive. Feedback - appreciated; this is not enabled by archive_read_support_format_all() - yet as I'm not quite content with the format detection heuristics. -Nov 7, 2005: Some more portability improvements thanks to Darin Broady, - minor bugfixes. -Oct 12, 2005: Use GNU libtool to build shared libraries on many systems. -Aug 9, 2005: Correctly detect that MacOS X does not have POSIX ACLs. -Apr 17, 2005: Kees Zeelenberg has ported libarchive and bsdtar to Windows: - http://gnuwin32.sourceforge.net/ -Apr 11, 2005: Extended Zip/Zip64 support thanks to Dan Nelson. -L/-h - fix from Jaakko Heinonen. -Mar 12, 2005: archive_read_extract can now handle very long - pathnames (I've tested with pathnames up to 1MB). -Mar 12, 2005: Marcus Geiger has written an article about libarchive - http://xsnil.antbear.org/2005/02/05/archive-mit-libarchive-verarbeiten/ - including examples of using it from Objective-C. His MoinX - http://moinx.antbear.org/ desktop Wiki uses - libarchive for archiving and restoring Wiki pages. -Jan 22, 2005: Preliminary ZIP extraction support, - new directory-walking code for bsdtar. -Jan 16, 2005: ISO9660 extraction code added; manpage corrections. -May 22, 2004: Many gtar-compatible long options have been added; almost - all FreeBSD ports extract correctly with bsdtar. -May 18, 2004: bsdtar can read Solaris, HP-UX, Unixware, star, gtar, - and pdtar archives. diff --git a/3rdparty/libarchive/README.md b/3rdparty/libarchive/README.md deleted file mode 100644 index be6c13b3..00000000 --- a/3rdparty/libarchive/README.md +++ /dev/null @@ -1,222 +0,0 @@ -# Welcome to libarchive! - -The libarchive project develops a portable, efficient C library that -can read and write streaming archives in a variety of formats. It -also includes implementations of the common `tar`, `cpio`, and `zcat` -command-line tools that use the libarchive library. - -## Questions? Issues? - -* http://www.libarchive.org is the home for ongoing - libarchive development, including documentation, - and links to the libarchive mailing lists. -* To report an issue, use the issue tracker at - https://github.com/libarchive/libarchive/issues -* To submit an enhancement to libarchive, please - submit a pull request via GitHub: https://github.com/libarchive/libarchive/pulls - -## Contents of the Distribution - -This distribution bundle includes the following major components: - -* **libarchive**: a library for reading and writing streaming archives -* **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built on libarchive -* **cpio**: the 'bsdcpio' program is a different interface to essentially the same functionality -* **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, xzcat, and such -* **examples**: Some small example programs that you may find useful. -* **examples/minitar**: a compact sample demonstrating use of libarchive. -* **contrib**: Various items sent to me by third parties; please contact the authors with any questions. - -The top-level directory contains the following information files: - -* **NEWS** - highlights of recent changes -* **COPYING** - what you can do with this -* **INSTALL** - installation instructions -* **README** - this file -* **CMakeLists.txt** - input for "cmake" build tool, see INSTALL -* **configure** - configuration script, see INSTALL for details. If your copy of the source lacks a `configure` script, you can try to construct it by running the script in `build/autogen.sh` (or use `cmake`). - -The following files in the top-level directory are used by the 'configure' script: -* `Makefile.am`, `aclocal.m4`, `configure.ac` - used to build this distribution, only needed by maintainers -* `Makefile.in`, `config.h.in` - templates used by configure script - -## Documentation - -In addition to the informational articles and documentation -in the online [libarchive Wiki](https://github.com/libarchive/libarchive/wiki), -the distribution also includes a number of manual pages: - - * bsdtar.1 explains the use of the bsdtar program - * bsdcpio.1 explains the use of the bsdcpio program - * bsdcat.1 explains the use of the bsdcat program - * libarchive.3 gives an overview of the library as a whole - * archive_read.3, archive_write.3, archive_write_disk.3, and - archive_read_disk.3 provide detailed calling sequences for the read - and write APIs - * archive_entry.3 details the "struct archive_entry" utility class - * archive_internals.3 provides some insight into libarchive's - internal structure and operation. - * libarchive-formats.5 documents the file formats supported by the library - * cpio.5, mtree.5, and tar.5 provide detailed information about these - popular archive formats, including hard-to-find details about - modern cpio and tar variants. - -The manual pages above are provided in the 'doc' directory in -a number of different formats. - -You should also read the copious comments in `archive.h` and the -source code for the sample programs for more details. Please let us -know about any errors or omissions you find. - -## Supported Formats - -Currently, the library automatically detects and reads the following fomats: - * Old V7 tar archives - * POSIX ustar - * GNU tar format (including GNU long filenames, long link names, and sparse files) - * Solaris 9 extended tar format (including ACLs) - * POSIX pax interchange format - * POSIX octet-oriented cpio - * SVR4 ASCII cpio - * POSIX octet-oriented cpio - * Binary cpio (big-endian or little-endian) - * ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions) - * ZIP archives (with uncompressed or "deflate" compressed entries, including support for encrypted Zip archives) - * GNU and BSD 'ar' archives - * 'mtree' format - * 7-Zip archives - * Microsoft CAB format - * LHA and LZH archives - * RAR archives (with some limitations due to RAR's proprietary status) - * XAR archives - -The library also detects and handles any of the following before evaluating the archive: - * uuencoded files - * files with RPM wrapper - * gzip compression - * bzip2 compression - * compress/LZW compression - * lzma, lzip, and xz compression - * lz4 compression - * lzop compression - -The library can create archives in any of the following formats: - * POSIX ustar - * POSIX pax interchange format - * "restricted" pax format, which will create ustar archives except for - entries that require pax extensions (for long filenames, ACLs, etc). - * Old GNU tar format - * Old V7 tar format - * POSIX octet-oriented cpio - * SVR4 "newc" cpio - * shar archives - * ZIP archives (with uncompressed or "deflate" compressed entries) - * GNU and BSD 'ar' archives - * 'mtree' format - * ISO9660 format - * 7-Zip archives - * XAR archives - -When creating archives, the result can be filtered with any of the following: - * uuencode - * gzip compression - * bzip2 compression - * compress/LZW compression - * lzma, lzip, and xz compression - * lz4 compression - * lzop compression - -## Notes about the Library Design - -The following notes address many of the most common -questions we are asked about libarchive: - -* This is a heavily stream-oriented system. That means that - it is optimized to read or write the archive in a single - pass from beginning to end. For example, this allows - libarchive to process archives too large to store on disk - by processing them on-the-fly as they are read from or - written to a network or tape drive. This also makes - libarchive useful for tools that need to produce - archives on-the-fly (such as webservers that provide - archived contents of a users account). - -* In-place modification and random access to the contents - of an archive are not directly supported. For some formats, - this is not an issue: For example, tar.gz archives are not - designed for random access. In some other cases, libarchive - can re-open an archive and scan it from the beginning quickly - enough to provide the needed abilities even without true - random access. Of course, some applications do require true - random access; those applications should consider alternatives - to libarchive. - -* The library is designed to be extended with new compression and - archive formats. The only requirement is that the format be - readable or writable as a stream and that each archive entry be - independent. There are articles on the libarchive Wiki explaining - how to extend libarchive. - -* On read, compression and format are always detected automatically. - -* The same API is used for all formats; in particular, it's very - easy for software using libarchive to transparently handle - any of libarchive's archiving formats. - -* Libarchive's automatic support for decompression can be used - without archiving by explicitly selecting the "raw" and "empty" - formats. - -* I've attempted to minimize static link pollution. If you don't - explicitly invoke a particular feature (such as support for a - particular compression or format), it won't get pulled in to - statically-linked programs. In particular, if you don't explicitly - enable a particular compression or decompression support, you won't - need to link against the corresponding compression or decompression - libraries. This also reduces the size of statically-linked - binaries in environments where that matters. - -* The library is generally _thread safe_ depending on the platform: - it does not define any global variables of its own. However, some - platforms do not provide fully thread-safe versions of key C library - functions. On those platforms, libarchive will use the non-thread-safe - functions. Patches to improve this are of great interest to us. - -* In particular, libarchive's modules to read or write a directory - tree do use `chdir()` to optimize the directory traversals. This - can cause problems for programs that expect to do disk access from - multiple threads. Of course, those modules are completely - optional and you can use the rest of libarchive without them. - -* The library is _not_ thread aware, however. It does no locking - or thread management of any kind. If you create a libarchive - object and need to access it from multiple threads, you will - need to provide your own locking. - -* On read, the library accepts whatever blocks you hand it. - Your read callback is free to pass the library a byte at a time - or mmap the entire archive and give it to the library at once. - On write, the library always produces correctly-blocked output. - -* The object-style approach allows you to have multiple archive streams - open at once. bsdtar uses this in its "@archive" extension. - -* The archive itself is read/written using callback functions. - You can read an archive directly from an in-memory buffer or - write it to a socket, if you wish. There are some utility - functions to provide easy-to-use "open file," etc, capabilities. - -* The read/write APIs are designed to allow individual entries - to be read or written to any data source: You can create - a block of data in memory and add it to a tar archive without - first writing a temporary file. You can also read an entry from - an archive and write the data directly to a socket. If you want - to read/write entries to disk, there are convenience functions to - make this especially easy. - -* Note: The "pax interchange format" is a POSIX standard extended tar - format that should be used when the older _ustar_ format is not - appropriate. It has many advantages over other tar formats - (including the legacy GNU tar format) and is widely supported by - current tar implementations. - diff --git a/3rdparty/libarchive/config-android.h b/3rdparty/libarchive/config-android.h deleted file mode 100644 index 037f1b60..00000000 --- a/3rdparty/libarchive/config-android.h +++ /dev/null @@ -1,153 +0,0 @@ -// hand-crafted until it compiled ;) - -#define HAVE_CHOWN 1 -#define HAVE_CHROOT 1 -#define HAVE_CTIME_R 1 -#define HAVE_CTYPE_H 1 -#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0 -#define HAVE_DECL_INT64_MAX 1 -#define HAVE_DECL_INT64_MIN 1 -#define HAVE_DECL_INT32_MAX 1 -#define HAVE_DECL_INT32_MIN 1 -#define HAVE_DECL_INTMAX_MAX 1 -#define HAVE_DECL_INTMAX_MIN 1 -#define HAVE_DECL_SIZE_MAX 1 -#define HAVE_DECL_SSIZE_MAX 1 -#define HAVE_DECL_STRERROR_R 1 -#define HAVE_DECL_UINT32_MAX 1 -#define HAVE_DECL_UINT64_MAX 1 -#define HAVE_DECL_UINTMAX_MAX 1 -#define HAVE_DIRENT_H 1 -#define HAVE_DIRFD 1 -#define HAVE_DLFCN_H 1 -#define HAVE_EILSEQ 1 -#define HAVE_ERRNO_H 1 -#define HAVE_FCHDIR 1 -#define HAVE_FCHMOD 1 -#define HAVE_FCHOWN 1 -#define HAVE_FCNTL 1 -#define HAVE_FCNTL_H 1 -#define HAVE_FDOPENDIR 1 -#define HAVE_FGETXATTR 1 -#define HAVE_FLISTXATTR 1 -#define HAVE_FORK 1 -#define HAVE_FSEEKO 1 -#define HAVE_FSETXATTR 1 -#define HAVE_FSTAT 1 -#define HAVE_FSTATAT 1 -//#define HAVE_FSTATFS 1 -//#define HAVE_FSTATVFS 1 -#define HAVE_FTRUNCATE 1 -#define HAVE_GETEUID 1 -#define HAVE_GETPID 1 -#define HAVE_GETPWNAM_R 1 -#define HAVE_GETPWUID_R 1 -#define HAVE_GETXATTR 1 -#define HAVE_GMTIME_R 1 -#define HAVE_GRP_H 1 -#define HAVE_INTMAX_T 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LCHOWN 1 -#define HAVE_LGETXATTR 1 -#define HAVE_LIBLZMA 1 -#define HAVE_LIBZ 1 -#define HAVE_LIMITS_H 1 -#define HAVE_LINK 1 -//#define HAVE_LINUX_FIEMAP_H 1 -#define HAVE_LINUX_FS_H 1 -#define HAVE_LINUX_MAGIC_H 1 -#define HAVE_LINUX_TYPES_H 1 -#define HAVE_LISTXATTR 1 -#define HAVE_LLISTXATTR 1 -#define HAVE_LOCALE_H 1 -#define HAVE_LOCALTIME_R 1 -#define HAVE_LONG_LONG_INT 1 -#define HAVE_LSETXATTR 1 -#define HAVE_LSTAT 1 -#define HAVE_MBRTOWC 1 -#define HAVE_MEMMOVE 1 -#define HAVE_MEMORY_H 1 -#define HAVE_MEMSET 1 -#define HAVE_MKDIR 1 -#define HAVE_MKFIFO 1 -#define HAVE_MKNOD 1 -#define HAVE_MKSTEMP 1 -#define HAVE_OPENAT 1 -#define HAVE_PATHS_H 1 -#define HAVE_PIPE 1 -#define HAVE_POLL 1 -#define HAVE_POLL_H 1 -#define HAVE_PTHREAD_H 1 -#define HAVE_PWD_H 1 -#define HAVE_READDIR_R 1 -#define HAVE_READLINK 1 -#define HAVE_READLINKAT 1 -#define HAVE_REGEX_H 1 -#define HAVE_SELECT 1 -#define HAVE_SETENV 1 -#define HAVE_SETLOCALE 1 -#define HAVE_SIGACTION 1 -#define HAVE_SIGNAL_H 1 -//#define HAVE_STATFS 1 -//#define HAVE_STATVFS 1 -#define HAVE_STDARG_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRCHR 1 -#define HAVE_STRDUP 1 -#define HAVE_STRERROR 1 -#define HAVE_STRERROR_R 1 -#define HAVE_STRFTIME 1 -#define HAVE_STRINGS_H 1 -#define HAVE_STRING_H 1 -#define HAVE_STRRCHR 1 -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 -//#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 -#define HAVE_STRUCT_TM_TM_GMTOFF 1 -#define HAVE_SYMLINK 1 -#define HAVE_SYS_CDEFS_H 1 -#define HAVE_SYS_IOCTL_H 1 -#define HAVE_SYS_MOUNT_H 1 -#define HAVE_SYS_PARAM_H 1 -#define HAVE_SYS_POLL_H 1 -#define HAVE_SYS_SELECT_H 1 -//#define HAVE_SYS_STATFS_H 1 -//#define HAVE_SYS_STATVFS_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_SYS_UTSNAME_H 1 -#define HAVE_SYS_VFS_H 1 -#define HAVE_SYS_WAIT_H 1 -//#define HAVE_SYS_XATTR_H 1 -#define HAVE_TIMEGM 1 -#define HAVE_TIME_H 1 -#define HAVE_TZSET 1 -#define HAVE_UINTMAX_T 1 -#define HAVE_UNISTD_H 1 -#define HAVE_UNSETENV 1 -#define HAVE_UNSIGNED_LONG_LONG 1 -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#define HAVE_UTIME 1 -#define HAVE_UTIMENSAT 1 -#define HAVE_UTIMES 1 -#define HAVE_UTIME_H 1 -#define HAVE_VFORK 1 -#define HAVE_VPRINTF 1 -#define HAVE_WCHAR_H 1 -#define HAVE_WCHAR_T 1 -#define HAVE_WCRTOMB 1 -#define HAVE_WCSCMP 1 -#define HAVE_WCSCPY 1 -#define HAVE_WCSLEN 1 -#define HAVE_WCTOMB 1 -#define HAVE_WCTYPE_H 1 -#define HAVE_WMEMCMP 1 -#define HAVE_WMEMCPY 1 -#define HAVE_ARC4RANDOM_BUF 1 -#define HAVE_ZLIB_H 1 -#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 -#define SIZEOF_WCHAR_T 4 -#define STDC_HEADERS 1 -#define STRERROR_R_CHAR_P 1 -#define TIME_WITH_SYS_TIME 1 diff --git a/3rdparty/libarchive/config-ios.h b/3rdparty/libarchive/config-ios.h deleted file mode 100644 index 2664e699..00000000 --- a/3rdparty/libarchive/config-ios.h +++ /dev/null @@ -1,1098 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1 - -/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_WIN */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1 - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1 - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1 - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1 - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ - -/* Version number of bsdcpio */ -#define BSDCPIO_VERSION_STRING "3.1.2" - -/* Version number of bsdtar */ -#define BSDTAR_VERSION_STRING "3.1.2" - -/* Define to 1 if you have the `acl_create_entry' function. */ -/* #undef HAVE_ACL_CREATE_ENTRY */ - -/* Define to 1 if you have the `acl_get_link' function. */ -/* #undef HAVE_ACL_GET_LINK */ - -/* Define to 1 if you have the `acl_get_link_np' function. */ -/* #undef HAVE_ACL_GET_LINK_NP */ - -/* Define to 1 if you have the `acl_get_perm' function. */ -/* #undef HAVE_ACL_GET_PERM */ - -/* Define to 1 if you have the `acl_get_perm_np' function. */ -/* #undef HAVE_ACL_GET_PERM_NP */ - -/* Define to 1 if you have the `acl_init' function. */ -/* #undef HAVE_ACL_INIT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ACL_LIBACL_H */ - -/* Define to 1 if the system has the type `acl_permset_t'. */ -/* #undef HAVE_ACL_PERMSET_T */ - -/* Define to 1 if you have the `acl_set_fd' function. */ -/* #undef HAVE_ACL_SET_FD */ - -/* Define to 1 if you have the `acl_set_fd_np' function. */ -/* #undef HAVE_ACL_SET_FD_NP */ - -/* Define to 1 if you have the `acl_set_file' function. */ -/* #undef HAVE_ACL_SET_FILE */ - -/* True for systems with POSIX ACL support */ -/* #undef HAVE_ACL_USER */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ATTR_XATTR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the `chflags' function. */ -#define HAVE_CHFLAGS 1 - -/* Define to 1 if you have the `chown' function. */ -#define HAVE_CHOWN 1 - -/* Define to 1 if you have the `chroot' function. */ -#define HAVE_CHROOT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_COPYFILE_H 1 - -/* Define to 1 if you have the `ctime_r' function. */ -#define HAVE_CTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the `cygwin_conv_path' function. */ -/* #undef HAVE_CYGWIN_CONV_PATH */ - -/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to - 0 if you don't. */ -/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ - -/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MAX 1 - -/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MIN 1 - -/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SIZE_MAX 1 - -/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SSIZE_MAX 1 - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -#define HAVE_DECL_STRERROR_R 1 - -/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT32_MAX 1 - -/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT64_MAX 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the `dirfd' function. */ -#define HAVE_DIRFD 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if nl_langinfo supports D_MD_ORDER */ -#define HAVE_D_MD_ORDER 1 - -/* A possible errno value for invalid file format errors */ -#define HAVE_EFTYPE 1 - -/* A possible errno value for invalid file format errors */ -#define HAVE_EILSEQ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXPAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXT2FS_EXT2_FS_H */ - -/* Define to 1 if you have the `extattr_get_file' function. */ -/* #undef HAVE_EXTATTR_GET_FILE */ - -/* Define to 1 if you have the `extattr_list_file' function. */ -/* #undef HAVE_EXTATTR_LIST_FILE */ - -/* Define to 1 if you have the `extattr_set_fd' function. */ -/* #undef HAVE_EXTATTR_SET_FD */ - -/* Define to 1 if you have the `extattr_set_file' function. */ -/* #undef HAVE_EXTATTR_SET_FILE */ - -/* Define to 1 if you have the `fchdir' function. */ -#define HAVE_FCHDIR 1 - -/* Define to 1 if you have the `fchflags' function. */ -#define HAVE_FCHFLAGS 1 - -/* Define to 1 if you have the `fchmod' function. */ -#define HAVE_FCHMOD 1 - -/* Define to 1 if you have the `fchown' function. */ -#define HAVE_FCHOWN 1 - -/* Define to 1 if you have the `fcntl' function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fdopendir' function. */ -/* #undef HAVE_FDOPENDIR */ - -/* Define to 1 if you have the `fgetea' function. */ -/* #undef HAVE_FGETEA */ - -/* Define to 1 if you have the `fgetxattr' function. */ -/* #undef HAVE_FGETXATTR */ - -/* Define to 1 if you have the `flistea' function. */ -/* #undef HAVE_FLISTEA */ - -/* Define to 1 if you have the `flistxattr' function. */ -/* #undef HAVE_FLISTXATTR */ - -/* Define to 1 if you have the `fork' function. */ -#define HAVE_FORK 1 - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `fsetea' function. */ -/* #undef HAVE_FSETEA */ - -/* Define to 1 if you have the `fsetxattr' function. */ -/* #undef HAVE_FSETXATTR */ - -/* Define to 1 if you have the `fstat' function. */ -#define HAVE_FSTAT 1 - -/* Define to 1 if you have the `fstatat' function. */ -/* #undef HAVE_FSTATAT */ - -/* Define to 1 if you have the `fstatfs' function. */ -#define HAVE_FSTATFS 1 - -/* Define to 1 if you have the `fstatvfs' function. */ -#define HAVE_FSTATVFS 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have the `futimens' function. */ -/* #undef HAVE_FUTIMENS */ - -/* Define to 1 if you have the `futimes' function. */ -#define HAVE_FUTIMES 1 - -/* Define to 1 if you have the `futimesat' function. */ -/* #undef HAVE_FUTIMESAT */ - -/* Define to 1 if you have the `getea' function. */ -/* #undef HAVE_GETEA */ - -/* Define to 1 if you have the `geteuid' function. */ -#define HAVE_GETEUID 1 - -/* Define to 1 if you have the `getgrgid_r' function. */ -#define HAVE_GETGRGID_R 1 - -/* Define to 1 if you have the `getgrnam_r' function. */ -#define HAVE_GETGRNAM_R 1 - -/* Define to 1 if you have the `getpid' function. */ -#define HAVE_GETPID 1 - -/* Define to 1 if you have the `getpwnam_r' function. */ -#define HAVE_GETPWNAM_R 1 - -/* Define to 1 if you have the `getpwuid_r' function. */ -#define HAVE_GETPWUID_R 1 - -/* Define to 1 if you have the `getvfsbyname' function. */ -#define HAVE_GETVFSBYNAME 1 - -/* Define to 1 if you have the `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the `gmtime_r' function. */ -#define HAVE_GMTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define if you have the iconv() function and it works. */ -#define HAVE_ICONV 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ICONV_H 1 - -/* Define to 1 if the system has the type `intmax_t'. */ -#define HAVE_INTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LANGINFO_H 1 - -/* Define to 1 if you have the `lchflags' function. */ -#define HAVE_LCHFLAGS 1 - -/* Define to 1 if you have the `lchmod' function. */ -#define HAVE_LCHMOD 1 - -/* Define to 1 if you have the `lchown' function. */ -#define HAVE_LCHOWN 1 - -/* Define to 1 if you have the `lgetea' function. */ -/* #undef HAVE_LGETEA */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `acl' library (-lacl). */ -/* #undef HAVE_LIBACL */ - -/* Define to 1 if you have the `attr' library (-lattr). */ -/* #undef HAVE_LIBATTR */ - -/* Define to 1 if you have the `bz2' library (-lbz2). */ -/* #undef HAVE_LIBBZ2 */ - -/* Define to 1 if you have the `charset' library (-lcharset). */ -/* #undef HAVE_LIBCHARSET */ - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -/* #undef HAVE_LIBCRYPTO */ - -/* Define to 1 if you have the `eay32' library (-leay32). */ -/* #undef HAVE_LIBEAY32 */ - -/* Define to 1 if you have the `eay64' library (-leay64). */ -/* #undef HAVE_LIBEAY64 */ - -/* Define to 1 if you have the `expat' library (-lexpat). */ -/* #undef HAVE_LIBEXPAT */ - -/* Define to 1 if you have the `lzma' library (-llzma). */ -/* #undef HAVE_LIBLZMA */ - -/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ -/* #undef HAVE_LIBLZMADEC */ - -/* Define to 1 if you have the `lzo2' library (-llzo2). */ -/* #undef HAVE_LIBLZO2 */ - -/* Define to 1 if you have the `md' library (-lmd). */ -/* #undef HAVE_LIBMD */ - -/* Define to 1 if you have the `nettle' library (-lnettle). */ -/* #undef HAVE_LIBNETTLE */ - -/* Define to 1 if you have the `pcre' library (-lpcre). */ -/* #undef HAVE_LIBPCRE */ - -/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ -/* #undef HAVE_LIBPCREPOSIX */ - -/* Define to 1 if you have the `regex' library (-lregex). */ -/* #undef HAVE_LIBREGEX */ - -/* Define to 1 if you have the `xml2' library (-lxml2). */ -/* #undef HAVE_LIBXML2 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLREADER_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLWRITER_H */ - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the `link' function. */ -#define HAVE_LINK 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FIEMAP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_MAGIC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_TYPES_H */ - -/* Define to 1 if you have the `listea' function. */ -/* #undef HAVE_LISTEA */ - -/* Define to 1 if you have the `listxattr' function. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistea' function. */ -/* #undef HAVE_LLISTEA */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LOCALCHARSET_H */ - -/* Define to 1 if you have the `locale_charset' function. */ -#define HAVE_LOCALE_CHARSET 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the system has the type `long long int'. */ -#define HAVE_LONG_LONG_INT 1 - -/* Define to 1 if you have the `lsetea' function. */ -/* #undef HAVE_LSETEA */ - -/* Define to 1 if you have the `lsetxattr' function. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if you have the `lstat' function. */ -#define HAVE_LSTAT 1 - -/* Define to 1 if `lstat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the `lutimes' function. */ -#define HAVE_LUTIMES 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMADEC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZO1X_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZOCONF_H */ - -/* Define to 1 if you have the `mbrtowc' function. */ -#define HAVE_MBRTOWC 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MD5_H */ - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the `mkfifo' function. */ -#define HAVE_MKFIFO 1 - -/* Define to 1 if you have the `mknod' function. */ -#define HAVE_MKNOD 1 - -/* Define to 1 if you have the `mkstemp' function. */ -#define HAVE_MKSTEMP 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_MD5_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_RIPEMD160_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_SHA_H */ - -/* Define to 1 if you have the `nl_langinfo' function. */ -#define HAVE_NL_LANGINFO 1 - -/* Define to 1 if you have the `openat' function. */ -/* #undef HAVE_OPENAT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_EVP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PATHS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PCREPOSIX_H */ - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have the `poll' function. */ -#define HAVE_POLL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_POLL_H 1 - -/* Define to 1 if you have the `posix_spawnp' function. */ -#define HAVE_POSIX_SPAWNP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have a POSIX compatible readdir_r */ -#define HAVE_READDIR_R 1 - -/* Define to 1 if you have the `readlink' function. */ -#define HAVE_READLINK 1 - -/* Define to 1 if you have the `readlinkat' function. */ -/* #undef HAVE_READLINKAT */ - -/* Define to 1 if you have the header file. */ -#define HAVE_REGEX_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RIPEMD_H */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `setenv' function. */ -#define HAVE_SETENV 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA256_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA512_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA_H */ - -/* Define to 1 if you have the `sigaction' function. */ -#define HAVE_SIGACTION 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SPAWN_H 1 - -/* Define to 1 if you have the `statfs' function. */ -#define HAVE_STATFS 1 - -/* Define to 1 if you have the `statvfs' function. */ -#define HAVE_STATVFS 1 - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strncpy_s' function. */ -/* #undef HAVE_STRNCPY_S */ - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ -/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ - -/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ -/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 - -/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 - -/* Define to 1 if `st_flags' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_FLAGS 1 - -/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 - -/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ - -/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ - -/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ - -/* Define to 1 if `st_umtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ - -/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ -#define HAVE_STRUCT_TM_TM_GMTOFF 1 - -/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ - -/* Define to 1 if you have the `symlink' function. */ -#define HAVE_SYMLINK 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_ACL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_CDEFS_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EXTATTR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_MOUNT_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_POLL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_STATFS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STATVFS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTSNAME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_VFS_H */ - -/* Define to 1 if you have that is POSIX.1 compatible. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the `timegm' function. */ -#define HAVE_TIMEGM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the `tzset' function. */ -#define HAVE_TZSET 1 - -/* Define to 1 if the system has the type `uintmax_t'. */ -#define HAVE_UINTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - -/* Define to 1 if the system has the type `unsigned long long'. */ -#define HAVE_UNSIGNED_LONG_LONG 1 - -/* Define to 1 if the system has the type `unsigned long long int'. */ -#define HAVE_UNSIGNED_LONG_LONG_INT 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimensat' function. */ -/* #undef HAVE_UTIMENSAT */ - -/* Define to 1 if you have the `utimes' function. */ -#define HAVE_UTIMES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if you have the `vfork' function. */ -#define HAVE_VFORK 1 - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if the system has the type `wchar_t'. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the `wcrtomb' function. */ -#define HAVE_WCRTOMB 1 - -/* Define to 1 if you have the `wcscmp' function. */ -#define HAVE_WCSCMP 1 - -/* Define to 1 if you have the `wcscpy' function. */ -#define HAVE_WCSCPY 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define to 1 if you have the `wctomb' function. */ -#define HAVE_WCTOMB 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINCRYPT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINIOCTL_H */ - -/* Define to 1 if you have the `wmemcmp' function. */ -#define HAVE_WMEMCMP 1 - -/* Define to 1 if you have the `wmemcpy' function. */ -#define HAVE_WMEMCPY 1 - -/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ -/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Define to 1 if you have the `_ctime64_s' function. */ -/* #undef HAVE__CTIME64_S */ - -/* Define to 1 if you have the `_fseeki64' function. */ -/* #undef HAVE__FSEEKI64 */ - -/* Define to 1 if you have the `_get_timezone' function. */ -/* #undef HAVE__GET_TIMEZONE */ - -/* Define to 1 if you have the `_localtime64_s' function. */ -/* #undef HAVE__LOCALTIME64_S */ - -/* Define to 1 if you have the `_mkgmtime64' function. */ -/* #undef HAVE__MKGMTIME64 */ - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Version number of libarchive as a single integer */ -#define LIBARCHIVE_VERSION_NUMBER "3001002" - -/* Version number of libarchive */ -#define LIBARCHIVE_VERSION_STRING "3.1.2" - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Name of package */ -#define PACKAGE "libarchive" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libarchive" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libarchive 3.1.2" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libarchive" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "3.1.2" - -/* Define to 1 if PCRE_STATIC needs to be defined. */ -/* #undef PCRE_STATIC */ - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if strerror_r returns char *. */ -/* #undef STRERROR_R_CHAR_P */ - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif - - -/* Version number of package */ -#define VERSION "3.1.2" - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef WINVER */ - -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT32_T */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define for Solaris 2.5.1 so the uint8_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT8_T */ - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef _WIN32_WINNT */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to match typeof st_gid field of struct stat if doesn't - define. */ -/* #undef gid_t */ - -/* Define to `unsigned long' if does not define. */ -/* #undef id_t */ - -/* Define to the type of a signed integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int16_t */ - -/* Define to the type of a signed integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int32_t */ - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int64_t */ - -/* Define to the widest signed integer type if and do - not define. */ -/* #undef intmax_t */ - -/* Define to `int' if does not define. */ -/* #undef mode_t */ - -/* Define to `long long' if does not define. */ -/* #undef off_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to match typeof st_uid field of struct stat if doesn't - define. */ -/* #undef uid_t */ - -/* Define to the type of an unsigned integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint16_t */ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint32_t */ - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint64_t */ - -/* Define to the type of an unsigned integer type of width exactly 8 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint8_t */ - -/* Define to the widest unsigned integer type if and - do not define. */ -/* #undef uintmax_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef uintptr_t */ - -#define HAVE_ARC4RANDOM_BUF 1 diff --git a/3rdparty/libarchive/config-macos.h b/3rdparty/libarchive/config-macos.h deleted file mode 100644 index 85294b2e..00000000 --- a/3rdparty/libarchive/config-macos.h +++ /dev/null @@ -1,1098 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1 - -/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_WIN */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1 - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1 - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1 - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ -#define ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1 - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ - -/* Version number of bsdcpio */ -#define BSDCPIO_VERSION_STRING "3.1.2" - -/* Version number of bsdtar */ -#define BSDTAR_VERSION_STRING "3.1.2" - -/* Define to 1 if you have the `acl_create_entry' function. */ -/* #undef HAVE_ACL_CREATE_ENTRY */ - -/* Define to 1 if you have the `acl_get_link' function. */ -/* #undef HAVE_ACL_GET_LINK */ - -/* Define to 1 if you have the `acl_get_link_np' function. */ -/* #undef HAVE_ACL_GET_LINK_NP */ - -/* Define to 1 if you have the `acl_get_perm' function. */ -/* #undef HAVE_ACL_GET_PERM */ - -/* Define to 1 if you have the `acl_get_perm_np' function. */ -/* #undef HAVE_ACL_GET_PERM_NP */ - -/* Define to 1 if you have the `acl_init' function. */ -/* #undef HAVE_ACL_INIT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ACL_LIBACL_H */ - -/* Define to 1 if the system has the type `acl_permset_t'. */ -/* #undef HAVE_ACL_PERMSET_T */ - -/* Define to 1 if you have the `acl_set_fd' function. */ -/* #undef HAVE_ACL_SET_FD */ - -/* Define to 1 if you have the `acl_set_fd_np' function. */ -/* #undef HAVE_ACL_SET_FD_NP */ - -/* Define to 1 if you have the `acl_set_file' function. */ -/* #undef HAVE_ACL_SET_FILE */ - -/* True for systems with POSIX ACL support */ -/* #undef HAVE_ACL_USER */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ATTR_XATTR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the `chflags' function. */ -#define HAVE_CHFLAGS 1 - -/* Define to 1 if you have the `chown' function. */ -#define HAVE_CHOWN 1 - -/* Define to 1 if you have the `chroot' function. */ -#define HAVE_CHROOT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_COPYFILE_H 1 - -/* Define to 1 if you have the `ctime_r' function. */ -#define HAVE_CTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the `cygwin_conv_path' function. */ -/* #undef HAVE_CYGWIN_CONV_PATH */ - -/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to - 0 if you don't. */ -/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ - -/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MAX 1 - -/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MIN 1 - -/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SIZE_MAX 1 - -/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SSIZE_MAX 1 - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -#define HAVE_DECL_STRERROR_R 1 - -/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT32_MAX 1 - -/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT64_MAX 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the `dirfd' function. */ -#define HAVE_DIRFD 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if nl_langinfo supports D_MD_ORDER */ -#define HAVE_D_MD_ORDER 1 - -/* A possible errno value for invalid file format errors */ -#define HAVE_EFTYPE 1 - -/* A possible errno value for invalid file format errors */ -#define HAVE_EILSEQ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXPAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXT2FS_EXT2_FS_H */ - -/* Define to 1 if you have the `extattr_get_file' function. */ -/* #undef HAVE_EXTATTR_GET_FILE */ - -/* Define to 1 if you have the `extattr_list_file' function. */ -/* #undef HAVE_EXTATTR_LIST_FILE */ - -/* Define to 1 if you have the `extattr_set_fd' function. */ -/* #undef HAVE_EXTATTR_SET_FD */ - -/* Define to 1 if you have the `extattr_set_file' function. */ -/* #undef HAVE_EXTATTR_SET_FILE */ - -/* Define to 1 if you have the `fchdir' function. */ -#define HAVE_FCHDIR 1 - -/* Define to 1 if you have the `fchflags' function. */ -#define HAVE_FCHFLAGS 1 - -/* Define to 1 if you have the `fchmod' function. */ -#define HAVE_FCHMOD 1 - -/* Define to 1 if you have the `fchown' function. */ -#define HAVE_FCHOWN 1 - -/* Define to 1 if you have the `fcntl' function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fdopendir' function. */ -/* #undef HAVE_FDOPENDIR */ - -/* Define to 1 if you have the `fgetea' function. */ -/* #undef HAVE_FGETEA */ - -/* Define to 1 if you have the `fgetxattr' function. */ -/* #undef HAVE_FGETXATTR */ - -/* Define to 1 if you have the `flistea' function. */ -/* #undef HAVE_FLISTEA */ - -/* Define to 1 if you have the `flistxattr' function. */ -/* #undef HAVE_FLISTXATTR */ - -/* Define to 1 if you have the `fork' function. */ -#define HAVE_FORK 1 - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `fsetea' function. */ -/* #undef HAVE_FSETEA */ - -/* Define to 1 if you have the `fsetxattr' function. */ -/* #undef HAVE_FSETXATTR */ - -/* Define to 1 if you have the `fstat' function. */ -#define HAVE_FSTAT 1 - -/* Define to 1 if you have the `fstatat' function. */ -/* #undef HAVE_FSTATAT */ - -/* Define to 1 if you have the `fstatfs' function. */ -#define HAVE_FSTATFS 1 - -/* Define to 1 if you have the `fstatvfs' function. */ -#define HAVE_FSTATVFS 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have the `futimens' function. */ -/* #undef HAVE_FUTIMENS */ - -/* Define to 1 if you have the `futimes' function. */ -#define HAVE_FUTIMES 1 - -/* Define to 1 if you have the `futimesat' function. */ -/* #undef HAVE_FUTIMESAT */ - -/* Define to 1 if you have the `getea' function. */ -/* #undef HAVE_GETEA */ - -/* Define to 1 if you have the `geteuid' function. */ -#define HAVE_GETEUID 1 - -/* Define to 1 if you have the `getgrgid_r' function. */ -#define HAVE_GETGRGID_R 1 - -/* Define to 1 if you have the `getgrnam_r' function. */ -#define HAVE_GETGRNAM_R 1 - -/* Define to 1 if you have the `getpid' function. */ -#define HAVE_GETPID 1 - -/* Define to 1 if you have the `getpwnam_r' function. */ -#define HAVE_GETPWNAM_R 1 - -/* Define to 1 if you have the `getpwuid_r' function. */ -#define HAVE_GETPWUID_R 1 - -/* Define to 1 if you have the `getvfsbyname' function. */ -#define HAVE_GETVFSBYNAME 1 - -/* Define to 1 if you have the `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the `gmtime_r' function. */ -#define HAVE_GMTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define if you have the iconv() function and it works. */ -#define HAVE_ICONV 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ICONV_H 1 - -/* Define to 1 if the system has the type `intmax_t'. */ -#define HAVE_INTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LANGINFO_H 1 - -/* Define to 1 if you have the `lchflags' function. */ -#define HAVE_LCHFLAGS 1 - -/* Define to 1 if you have the `lchmod' function. */ -#define HAVE_LCHMOD 1 - -/* Define to 1 if you have the `lchown' function. */ -#define HAVE_LCHOWN 1 - -/* Define to 1 if you have the `lgetea' function. */ -/* #undef HAVE_LGETEA */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `acl' library (-lacl). */ -/* #undef HAVE_LIBACL */ - -/* Define to 1 if you have the `attr' library (-lattr). */ -/* #undef HAVE_LIBATTR */ - -/* Define to 1 if you have the `bz2' library (-lbz2). */ -/* #undef HAVE_LIBBZ2 */ - -/* Define to 1 if you have the `charset' library (-lcharset). */ -/* #undef HAVE_LIBCHARSET */ - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -/* #undef HAVE_LIBCRYPTO */ - -/* Define to 1 if you have the `eay32' library (-leay32). */ -/* #undef HAVE_LIBEAY32 */ - -/* Define to 1 if you have the `eay64' library (-leay64). */ -/* #undef HAVE_LIBEAY64 */ - -/* Define to 1 if you have the `expat' library (-lexpat). */ -/* #undef HAVE_LIBEXPAT */ - -/* Define to 1 if you have the `lzma' library (-llzma). */ -/* #undef HAVE_LIBLZMA */ - -/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ -/* #undef HAVE_LIBLZMADEC */ - -/* Define to 1 if you have the `lzo2' library (-llzo2). */ -/* #undef HAVE_LIBLZO2 */ - -/* Define to 1 if you have the `md' library (-lmd). */ -/* #undef HAVE_LIBMD */ - -/* Define to 1 if you have the `nettle' library (-lnettle). */ -/* #undef HAVE_LIBNETTLE */ - -/* Define to 1 if you have the `pcre' library (-lpcre). */ -/* #undef HAVE_LIBPCRE */ - -/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ -/* #undef HAVE_LIBPCREPOSIX */ - -/* Define to 1 if you have the `regex' library (-lregex). */ -/* #undef HAVE_LIBREGEX */ - -/* Define to 1 if you have the `xml2' library (-lxml2). */ -/* #undef HAVE_LIBXML2 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLREADER_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLWRITER_H */ - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the `link' function. */ -#define HAVE_LINK 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FIEMAP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_MAGIC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_TYPES_H */ - -/* Define to 1 if you have the `listea' function. */ -/* #undef HAVE_LISTEA */ - -/* Define to 1 if you have the `listxattr' function. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistea' function. */ -/* #undef HAVE_LLISTEA */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALCHARSET_H 1 - -/* Define to 1 if you have the `locale_charset' function. */ -#define HAVE_LOCALE_CHARSET 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the system has the type `long long int'. */ -#define HAVE_LONG_LONG_INT 1 - -/* Define to 1 if you have the `lsetea' function. */ -/* #undef HAVE_LSETEA */ - -/* Define to 1 if you have the `lsetxattr' function. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if you have the `lstat' function. */ -#define HAVE_LSTAT 1 - -/* Define to 1 if `lstat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the `lutimes' function. */ -#define HAVE_LUTIMES 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMADEC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZO1X_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZOCONF_H */ - -/* Define to 1 if you have the `mbrtowc' function. */ -#define HAVE_MBRTOWC 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MD5_H */ - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the `mkfifo' function. */ -#define HAVE_MKFIFO 1 - -/* Define to 1 if you have the `mknod' function. */ -#define HAVE_MKNOD 1 - -/* Define to 1 if you have the `mkstemp' function. */ -#define HAVE_MKSTEMP 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_MD5_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_RIPEMD160_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_SHA_H */ - -/* Define to 1 if you have the `nl_langinfo' function. */ -#define HAVE_NL_LANGINFO 1 - -/* Define to 1 if you have the `openat' function. */ -/* #undef HAVE_OPENAT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_EVP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PATHS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PCREPOSIX_H */ - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have the `poll' function. */ -#define HAVE_POLL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_POLL_H 1 - -/* Define to 1 if you have the `posix_spawnp' function. */ -#define HAVE_POSIX_SPAWNP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have a POSIX compatible readdir_r */ -#define HAVE_READDIR_R 1 - -/* Define to 1 if you have the `readlink' function. */ -#define HAVE_READLINK 1 - -/* Define to 1 if you have the `readlinkat' function. */ -/* #undef HAVE_READLINKAT */ - -/* Define to 1 if you have the header file. */ -#define HAVE_REGEX_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RIPEMD_H */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `setenv' function. */ -#define HAVE_SETENV 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA256_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA512_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA_H */ - -/* Define to 1 if you have the `sigaction' function. */ -#define HAVE_SIGACTION 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SPAWN_H 1 - -/* Define to 1 if you have the `statfs' function. */ -#define HAVE_STATFS 1 - -/* Define to 1 if you have the `statvfs' function. */ -#define HAVE_STATVFS 1 - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strncpy_s' function. */ -/* #undef HAVE_STRNCPY_S */ - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ -/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ - -/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ -/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 - -/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 - -/* Define to 1 if `st_flags' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_FLAGS 1 - -/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 - -/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ - -/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ - -/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ - -/* Define to 1 if `st_umtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ - -/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ -#define HAVE_STRUCT_TM_TM_GMTOFF 1 - -/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ - -/* Define to 1 if you have the `symlink' function. */ -#define HAVE_SYMLINK 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_ACL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_CDEFS_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EXTATTR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_MOUNT_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_POLL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_STATFS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STATVFS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTSNAME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_VFS_H */ - -/* Define to 1 if you have that is POSIX.1 compatible. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the `timegm' function. */ -#define HAVE_TIMEGM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the `tzset' function. */ -#define HAVE_TZSET 1 - -/* Define to 1 if the system has the type `uintmax_t'. */ -#define HAVE_UINTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - -/* Define to 1 if the system has the type `unsigned long long'. */ -#define HAVE_UNSIGNED_LONG_LONG 1 - -/* Define to 1 if the system has the type `unsigned long long int'. */ -#define HAVE_UNSIGNED_LONG_LONG_INT 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimensat' function. */ -/* #undef HAVE_UTIMENSAT */ - -/* Define to 1 if you have the `utimes' function. */ -#define HAVE_UTIMES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if you have the `vfork' function. */ -#define HAVE_VFORK 1 - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if the system has the type `wchar_t'. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the `wcrtomb' function. */ -#define HAVE_WCRTOMB 1 - -/* Define to 1 if you have the `wcscmp' function. */ -#define HAVE_WCSCMP 1 - -/* Define to 1 if you have the `wcscpy' function. */ -#define HAVE_WCSCPY 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define to 1 if you have the `wctomb' function. */ -#define HAVE_WCTOMB 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINCRYPT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINIOCTL_H */ - -/* Define to 1 if you have the `wmemcmp' function. */ -#define HAVE_WMEMCMP 1 - -/* Define to 1 if you have the `wmemcpy' function. */ -#define HAVE_WMEMCPY 1 - -/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ -/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Define to 1 if you have the `_ctime64_s' function. */ -/* #undef HAVE__CTIME64_S */ - -/* Define to 1 if you have the `_fseeki64' function. */ -/* #undef HAVE__FSEEKI64 */ - -/* Define to 1 if you have the `_get_timezone' function. */ -/* #undef HAVE__GET_TIMEZONE */ - -/* Define to 1 if you have the `_localtime64_s' function. */ -/* #undef HAVE__LOCALTIME64_S */ - -/* Define to 1 if you have the `_mkgmtime64' function. */ -/* #undef HAVE__MKGMTIME64 */ - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Version number of libarchive as a single integer */ -#define LIBARCHIVE_VERSION_NUMBER "3001002" - -/* Version number of libarchive */ -#define LIBARCHIVE_VERSION_STRING "3.1.2" - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Name of package */ -#define PACKAGE "libarchive" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libarchive" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libarchive 3.1.2" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libarchive" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "3.1.2" - -/* Define to 1 if PCRE_STATIC needs to be defined. */ -/* #undef PCRE_STATIC */ - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if strerror_r returns char *. */ -/* #undef STRERROR_R_CHAR_P */ - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif - - -/* Version number of package */ -#define VERSION "3.1.2" - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef WINVER */ - -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT32_T */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define for Solaris 2.5.1 so the uint8_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT8_T */ - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef _WIN32_WINNT */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to match typeof st_gid field of struct stat if doesn't - define. */ -/* #undef gid_t */ - -/* Define to `unsigned long' if does not define. */ -/* #undef id_t */ - -/* Define to the type of a signed integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int16_t */ - -/* Define to the type of a signed integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int32_t */ - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int64_t */ - -/* Define to the widest signed integer type if and do - not define. */ -/* #undef intmax_t */ - -/* Define to `int' if does not define. */ -/* #undef mode_t */ - -/* Define to `long long' if does not define. */ -/* #undef off_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to match typeof st_uid field of struct stat if doesn't - define. */ -/* #undef uid_t */ - -/* Define to the type of an unsigned integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint16_t */ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint32_t */ - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint64_t */ - -/* Define to the type of an unsigned integer type of width exactly 8 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint8_t */ - -/* Define to the widest unsigned integer type if and - do not define. */ -/* #undef uintmax_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef uintptr_t */ - -#define HAVE_ARC4RANDOM_BUF 1 diff --git a/3rdparty/libarchive/config-unix.h b/3rdparty/libarchive/config-unix.h deleted file mode 100644 index b82ec002..00000000 --- a/3rdparty/libarchive/config-unix.h +++ /dev/null @@ -1,1096 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_WIN */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ - -/* Version number of bsdcpio */ -#define BSDCPIO_VERSION_STRING "3.1.2" - -/* Version number of bsdtar */ -#define BSDTAR_VERSION_STRING "3.1.2" - -/* Define to 1 if you have the `acl_create_entry' function. */ -/* #undef HAVE_ACL_CREATE_ENTRY */ - -/* Define to 1 if you have the `acl_get_link' function. */ -/* #undef HAVE_ACL_GET_LINK */ - -/* Define to 1 if you have the `acl_get_link_np' function. */ -/* #undef HAVE_ACL_GET_LINK_NP */ - -/* Define to 1 if you have the `acl_get_perm' function. */ -/* #undef HAVE_ACL_GET_PERM */ - -/* Define to 1 if you have the `acl_get_perm_np' function. */ -/* #undef HAVE_ACL_GET_PERM_NP */ - -/* Define to 1 if you have the `acl_init' function. */ -/* #undef HAVE_ACL_INIT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ACL_LIBACL_H */ - -/* Define to 1 if the system has the type `acl_permset_t'. */ -/* #undef HAVE_ACL_PERMSET_T */ - -/* Define to 1 if you have the `acl_set_fd' function. */ -/* #undef HAVE_ACL_SET_FD */ - -/* Define to 1 if you have the `acl_set_fd_np' function. */ -/* #undef HAVE_ACL_SET_FD_NP */ - -/* Define to 1 if you have the `acl_set_file' function. */ -/* #undef HAVE_ACL_SET_FILE */ - -/* True for systems with POSIX ACL support */ -/* #undef HAVE_ACL_USER */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ATTR_XATTR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the `chflags' function. */ -/* #undef HAVE_CHFLAGS */ - -/* Define to 1 if you have the `chown' function. */ -#define HAVE_CHOWN 1 - -/* Define to 1 if you have the `chroot' function. */ -#define HAVE_CHROOT 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_COPYFILE_H */ - -/* Define to 1 if you have the `ctime_r' function. */ -#define HAVE_CTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the `cygwin_conv_path' function. */ -/* #undef HAVE_CYGWIN_CONV_PATH */ - -/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to - 0 if you don't. */ -/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ - -/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MAX 1 - -/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MIN 1 - -/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SIZE_MAX 1 - -/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SSIZE_MAX 1 - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -#define HAVE_DECL_STRERROR_R 1 - -/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT32_MAX 1 - -/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT64_MAX 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the `dirfd' function. */ -#define HAVE_DIRFD 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if nl_langinfo supports D_MD_ORDER */ -/* #undef HAVE_D_MD_ORDER */ - -/* A possible errno value for invalid file format errors */ -/* #undef HAVE_EFTYPE */ - -/* A possible errno value for invalid file format errors */ -#define HAVE_EILSEQ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXPAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXT2FS_EXT2_FS_H */ - -/* Define to 1 if you have the `extattr_get_file' function. */ -/* #undef HAVE_EXTATTR_GET_FILE */ - -/* Define to 1 if you have the `extattr_list_file' function. */ -/* #undef HAVE_EXTATTR_LIST_FILE */ - -/* Define to 1 if you have the `extattr_set_fd' function. */ -/* #undef HAVE_EXTATTR_SET_FD */ - -/* Define to 1 if you have the `extattr_set_file' function. */ -/* #undef HAVE_EXTATTR_SET_FILE */ - -/* Define to 1 if you have the `fchdir' function. */ -#define HAVE_FCHDIR 1 - -/* Define to 1 if you have the `fchflags' function. */ -/* #undef HAVE_FCHFLAGS */ - -/* Define to 1 if you have the `fchmod' function. */ -#define HAVE_FCHMOD 1 - -/* Define to 1 if you have the `fchown' function. */ -#define HAVE_FCHOWN 1 - -/* Define to 1 if you have the `fcntl' function. */ -#define HAVE_FCNTL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fdopendir' function. */ -#define HAVE_FDOPENDIR 1 - -/* Define to 1 if you have the `fgetea' function. */ -/* #undef HAVE_FGETEA */ - -/* Define to 1 if you have the `fgetxattr' function. */ -/* #undef HAVE_FGETXATTR */ - -/* Define to 1 if you have the `flistea' function. */ -/* #undef HAVE_FLISTEA */ - -/* Define to 1 if you have the `flistxattr' function. */ -/* #undef HAVE_FLISTXATTR */ - -/* Define to 1 if you have the `fork' function. */ -#define HAVE_FORK 1 - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `fsetea' function. */ -/* #undef HAVE_FSETEA */ - -/* Define to 1 if you have the `fsetxattr' function. */ -/* #undef HAVE_FSETXATTR */ - -/* Define to 1 if you have the `fstat' function. */ -#define HAVE_FSTAT 1 - -/* Define to 1 if you have the `fstatat' function. */ -#define HAVE_FSTATAT 1 - -/* Define to 1 if you have the `fstatfs' function. */ -#define HAVE_FSTATFS 1 - -/* Define to 1 if you have the `fstatvfs' function. */ -#define HAVE_FSTATVFS 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have the `futimens' function. */ -#define HAVE_FUTIMENS 1 - -/* Define to 1 if you have the `futimes' function. */ -#define HAVE_FUTIMES 1 - -/* Define to 1 if you have the `futimesat' function. */ -#define HAVE_FUTIMESAT 1 - -/* Define to 1 if you have the `getea' function. */ -/* #undef HAVE_GETEA */ - -/* Define to 1 if you have the `geteuid' function. */ -#define HAVE_GETEUID 1 - -/* Define to 1 if you have the `getgrgid_r' function. */ -#define HAVE_GETGRGID_R 1 - -/* Define to 1 if you have the `getgrnam_r' function. */ -#define HAVE_GETGRNAM_R 1 - -/* Define to 1 if you have the `getpid' function. */ -#define HAVE_GETPID 1 - -/* Define to 1 if you have the `getpwnam_r' function. */ -#define HAVE_GETPWNAM_R 1 - -/* Define to 1 if you have the `getpwuid_r' function. */ -#define HAVE_GETPWUID_R 1 - -/* Define to 1 if you have the `getvfsbyname' function. */ -/* #undef HAVE_GETVFSBYNAME */ - -/* Define to 1 if you have the `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the `gmtime_r' function. */ -#define HAVE_GMTIME_R 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define if you have the iconv() function and it works. */ -#define HAVE_ICONV 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ICONV_H 1 - -/* Define to 1 if the system has the type `intmax_t'. */ -#define HAVE_INTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LANGINFO_H 1 - -/* Define to 1 if you have the `lchflags' function. */ -/* #undef HAVE_LCHFLAGS */ - -/* Define to 1 if you have the `lchmod' function. */ -/* #undef HAVE_LCHMOD */ - -/* Define to 1 if you have the `lchown' function. */ -#define HAVE_LCHOWN 1 - -/* Define to 1 if you have the `lgetea' function. */ -/* #undef HAVE_LGETEA */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `acl' library (-lacl). */ -/* #undef HAVE_LIBACL */ - -/* Define to 1 if you have the `attr' library (-lattr). */ -/* #undef HAVE_LIBATTR */ - -/* Define to 1 if you have the `bz2' library (-lbz2). */ -/* #undef HAVE_LIBBZ2 */ - -/* Define to 1 if you have the `charset' library (-lcharset). */ -/* #undef HAVE_LIBCHARSET */ - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -/* #undef HAVE_LIBCRYPTO */ - -/* Define to 1 if you have the `eay32' library (-leay32). */ -/* #undef HAVE_LIBEAY32 */ - -/* Define to 1 if you have the `eay64' library (-leay64). */ -/* #undef HAVE_LIBEAY64 */ - -/* Define to 1 if you have the `expat' library (-lexpat). */ -/* #undef HAVE_LIBEXPAT */ - -/* Define to 1 if you have the `lzma' library (-llzma). */ -/* #undef HAVE_LIBLZMA */ - -/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ -/* #undef HAVE_LIBLZMADEC */ - -/* Define to 1 if you have the `lzo2' library (-llzo2). */ -/* #undef HAVE_LIBLZO2 */ - -/* Define to 1 if you have the `md' library (-lmd). */ -/* #undef HAVE_LIBMD */ - -/* Define to 1 if you have the `nettle' library (-lnettle). */ -/* #undef HAVE_LIBNETTLE */ - -/* Define to 1 if you have the `pcre' library (-lpcre). */ -/* #undef HAVE_LIBPCRE */ - -/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ -/* #undef HAVE_LIBPCREPOSIX */ - -/* Define to 1 if you have the `regex' library (-lregex). */ -/* #undef HAVE_LIBREGEX */ - -/* Define to 1 if you have the `xml2' library (-lxml2). */ -/* #undef HAVE_LIBXML2 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLREADER_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLWRITER_H */ - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the `link' function. */ -#define HAVE_LINK 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_FIEMAP_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_FS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_MAGIC_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_TYPES_H 1 - -/* Define to 1 if you have the `listea' function. */ -/* #undef HAVE_LISTEA */ - -/* Define to 1 if you have the `listxattr' function. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistea' function. */ -/* #undef HAVE_LLISTEA */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LOCALCHARSET_H */ - -/* Define to 1 if you have the `locale_charset' function. */ -/* #undef HAVE_LOCALE_CHARSET */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if the system has the type `long long int'. */ -#define HAVE_LONG_LONG_INT 1 - -/* Define to 1 if you have the `lsetea' function. */ -/* #undef HAVE_LSETEA */ - -/* Define to 1 if you have the `lsetxattr' function. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if you have the `lstat' function. */ -#define HAVE_LSTAT 1 - -/* Define to 1 if `lstat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the `lutimes' function. */ -#define HAVE_LUTIMES 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMADEC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZO1X_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZOCONF_H */ - -/* Define to 1 if you have the `mbrtowc' function. */ -#define HAVE_MBRTOWC 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MD5_H */ - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the `mkfifo' function. */ -#define HAVE_MKFIFO 1 - -/* Define to 1 if you have the `mknod' function. */ -#define HAVE_MKNOD 1 - -/* Define to 1 if you have the `mkstemp' function. */ -#define HAVE_MKSTEMP 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_MD5_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_RIPEMD160_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_SHA_H */ - -/* Define to 1 if you have the `nl_langinfo' function. */ -#define HAVE_NL_LANGINFO 1 - -/* Define to 1 if you have the `openat' function. */ -#define HAVE_OPENAT 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_EVP_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PATHS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PCREPOSIX_H */ - -/* Define to 1 if you have the `pipe' function. */ -#define HAVE_PIPE 1 - -/* Define to 1 if you have the `poll' function. */ -#define HAVE_POLL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_POLL_H 1 - -/* Define to 1 if you have the `posix_spawnp' function. */ -#define HAVE_POSIX_SPAWNP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have a POSIX compatible readdir_r */ -#define HAVE_READDIR_R 1 - -/* Define to 1 if you have the `readlink' function. */ -#define HAVE_READLINK 1 - -/* Define to 1 if you have the `readlinkat' function. */ -#define HAVE_READLINKAT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_REGEX_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RIPEMD_H */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `setenv' function. */ -#define HAVE_SETENV 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA256_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA512_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHA_H */ - -/* Define to 1 if you have the `sigaction' function. */ -#define HAVE_SIGACTION 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SPAWN_H 1 - -/* Define to 1 if you have the `statfs' function. */ -#define HAVE_STATFS 1 - -/* Define to 1 if you have the `statvfs' function. */ -#define HAVE_STATVFS 1 - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strncpy_s' function. */ -/* #undef HAVE_STRNCPY_S */ - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ -/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ - -/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ -/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ - -/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */ - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 - -/* Define to 1 if `st_flags' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ - -/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */ - -/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ - -/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ - -/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 - -/* Define to 1 if `st_umtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ - -/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ -#define HAVE_STRUCT_TM_TM_GMTOFF 1 - -/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ - -/* Define to 1 if you have the `symlink' function. */ -#define HAVE_SYMLINK 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ACL_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_CDEFS_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EXTATTR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_MOUNT_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_POLL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STATFS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STATVFS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTSNAME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_VFS_H 1 - -/* Define to 1 if you have that is POSIX.1 compatible. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the `timegm' function. */ -#define HAVE_TIMEGM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the `tzset' function. */ -#define HAVE_TZSET 1 - -/* Define to 1 if the system has the type `uintmax_t'. */ -#define HAVE_UINTMAX_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - -/* Define to 1 if the system has the type `unsigned long long'. */ -#define HAVE_UNSIGNED_LONG_LONG 1 - -/* Define to 1 if the system has the type `unsigned long long int'. */ -#define HAVE_UNSIGNED_LONG_LONG_INT 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimensat' function. */ -#define HAVE_UTIMENSAT 1 - -/* Define to 1 if you have the `utimes' function. */ -#define HAVE_UTIMES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if you have the `vfork' function. */ -#define HAVE_VFORK 1 - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if the system has the type `wchar_t'. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the `wcrtomb' function. */ -#define HAVE_WCRTOMB 1 - -/* Define to 1 if you have the `wcscmp' function. */ -#define HAVE_WCSCMP 1 - -/* Define to 1 if you have the `wcscpy' function. */ -#define HAVE_WCSCPY 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define to 1 if you have the `wctomb' function. */ -#define HAVE_WCTOMB 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINCRYPT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINIOCTL_H */ - -/* Define to 1 if you have the `wmemcmp' function. */ -#define HAVE_WMEMCMP 1 - -/* Define to 1 if you have the `wmemcpy' function. */ -#define HAVE_WMEMCPY 1 - -/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ -#define HAVE_WORKING_EXT2_IOC_GETFLAGS 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Define to 1 if you have the `_ctime64_s' function. */ -/* #undef HAVE__CTIME64_S */ - -/* Define to 1 if you have the `_fseeki64' function. */ -/* #undef HAVE__FSEEKI64 */ - -/* Define to 1 if you have the `_get_timezone' function. */ -/* #undef HAVE__GET_TIMEZONE */ - -/* Define to 1 if you have the `_localtime64_s' function. */ -/* #undef HAVE__LOCALTIME64_S */ - -/* Define to 1 if you have the `_mkgmtime64' function. */ -/* #undef HAVE__MKGMTIME64 */ - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Version number of libarchive as a single integer */ -#define LIBARCHIVE_VERSION_NUMBER "3001002" - -/* Version number of libarchive */ -#define LIBARCHIVE_VERSION_STRING "3.1.2" - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Name of package */ -#define PACKAGE "libarchive" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libarchive" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libarchive 3.1.2" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libarchive" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "3.1.2" - -/* Define to 1 if PCRE_STATIC needs to be defined. */ -/* #undef PCRE_STATIC */ - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if strerror_r returns char *. */ -#define STRERROR_R_CHAR_P 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif - - -/* Version number of package */ -#define VERSION "3.1.2" - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef WINVER */ - -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#define _FILE_OFFSET_BITS 64 - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT32_T */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define for Solaris 2.5.1 so the uint8_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT8_T */ - -/* Define to '0x0500' for Windows 2000 APIs. */ -/* #undef _WIN32_WINNT */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to match typeof st_gid field of struct stat if doesn't - define. */ -/* #undef gid_t */ - -/* Define to `unsigned long' if does not define. */ -/* #undef id_t */ - -/* Define to the type of a signed integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int16_t */ - -/* Define to the type of a signed integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int32_t */ - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int64_t */ - -/* Define to the widest signed integer type if and do - not define. */ -/* #undef intmax_t */ - -/* Define to `int' if does not define. */ -/* #undef mode_t */ - -/* Define to `long long' if does not define. */ -/* #undef off_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to match typeof st_uid field of struct stat if doesn't - define. */ -/* #undef uid_t */ - -/* Define to the type of an unsigned integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint16_t */ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint32_t */ - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint64_t */ - -/* Define to the type of an unsigned integer type of width exactly 8 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint8_t */ - -/* Define to the widest unsigned integer type if and - do not define. */ -/* #undef uintmax_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef uintptr_t */ diff --git a/3rdparty/libarchive/config-windows.h b/3rdparty/libarchive/config-windows.h deleted file mode 100644 index 6019e58c..00000000 --- a/3rdparty/libarchive/config-windows.h +++ /dev/null @@ -1,1149 +0,0 @@ -/* config.h. Generated from build/cmake/config.h.in by cmake configure */ - -/* - * Ensure we have C99-style int64_t, etc, all defined. - */ - -/* First, we need to know if the system has already defined them. */ -#define HAVE_INT16_T -#define HAVE_INT32_T -#define HAVE_INT64_T -#define HAVE_INTMAX_T - -#define HAVE_UINT8_T -#define HAVE_UINT16_T -#define HAVE_UINT32_T -#define HAVE_UINT64_T -#define HAVE_UINTMAX_T - -/* We might have the types we want under other spellings. */ -#define HAVE___INT64 -/* #undef HAVE_U_INT64_T */ -#define HAVE_UNSIGNED___INT64 - -/* The sizes of various standard integer types. */ -#define SIZE_OF_SHORT 2 -#define SIZE_OF_INT 4 -#define SIZE_OF_LONG 4 -#define SIZE_OF_LONG_LONG 8 -#define SIZE_OF_UNSIGNED_SHORT 2 -#define SIZE_OF_UNSIGNED 4 -#define SIZE_OF_UNSIGNED_LONG 4 -#define SIZE_OF_UNSIGNED_LONG_LONG 8 - -/* - * If we lack int64_t, define it to the first of __int64, int, long, and long long - * that exists and is the right size. - */ -#if !defined(HAVE_INT64_T) && defined(HAVE___INT64) -typedef __int64 int64_t; -#define HAVE_INT64_T -#endif - -#if !defined(HAVE_INT64_T) && SIZE_OF_INT == 8 -typedef int int64_t; -#define HAVE_INT64_T -#endif - -#if !defined(HAVE_INT64_T) && SIZE_OF_LONG == 8 -typedef long int64_t; -#define HAVE_INT64_T -#endif - -#if !defined(HAVE_INT64_T) && SIZE_OF_LONG_LONG == 8 -typedef long long int64_t; -#define HAVE_INT64_T -#endif - -#if !defined(HAVE_INT64_T) -#error No 64-bit integer type was found. -#endif - -/* - * Similarly for int32_t - */ -#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4 -typedef long int32_t; -#define HAVE_INT32_T -#endif - -#if !defined(HAVE_INT32_T) && SIZE_OF_LONG == 4 -typedef long int32_t; -#define HAVE_INT32_T -#endif - -#if !defined(HAVE_INT32_T) -#error No 32-bit integer type was found. -#endif - -/* - * Similarly for int16_t - */ -#if !defined(HAVE_INT16_T) && SIZE_OF_INT == 2 -typedef int int16_t; -#define HAVE_INT16_T -#endif - -#if !defined(HAVE_INT16_T) && SIZE_OF_SHORT == 2 -typedef short int16_t; -#define HAVE_INT16_T -#endif - -#if !defined(HAVE_INT16_T) -#error No 16-bit integer type was found. -#endif - -/* - * Similarly for uint64_t - */ -#if !defined(HAVE_UINT64_T) && defined(HAVE_UNSIGNED___INT64) -typedef unsigned __int64 uint64_t; -#define HAVE_UINT64_T -#endif - -#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED == 8 -typedef unsigned uint64_t; -#define HAVE_UINT64_T -#endif - -#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG == 8 -typedef unsigned long uint64_t; -#define HAVE_UINT64_T -#endif - -#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG_LONG == 8 -typedef unsigned long long uint64_t; -#define HAVE_UINT64_T -#endif - -#if !defined(HAVE_UINT64_T) -#error No 64-bit unsigned integer type was found. -#endif - - -/* - * Similarly for uint32_t - */ -#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED == 4 -typedef unsigned uint32_t; -#define HAVE_UINT32_T -#endif - -#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED_LONG == 4 -typedef unsigned long uint32_t; -#define HAVE_UINT32_T -#endif - -#if !defined(HAVE_UINT32_T) -#error No 32-bit unsigned integer type was found. -#endif - -/* - * Similarly for uint16_t - */ -#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED == 2 -typedef unsigned uint16_t; -#define HAVE_UINT16_T -#endif - -#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED_SHORT == 2 -typedef unsigned short uint16_t; -#define HAVE_UINT16_T -#endif - -#if !defined(HAVE_UINT16_T) -#error No 16-bit unsigned integer type was found. -#endif - -/* - * Similarly for uint8_t - */ -#if !defined(HAVE_UINT8_T) -typedef unsigned char uint8_t; -#define HAVE_UINT8_T -#endif - -#if !defined(HAVE_UINT16_T) -#error No 8-bit unsigned integer type was found. -#endif - -/* Define intmax_t and uintmax_t if they are not already defined. */ -#if !defined(HAVE_INTMAX_T) -typedef int64_t intmax_t; -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#endif - -#if !defined(HAVE_UINTMAX_T) -typedef uint64_t uintmax_t; -#endif - -/* Define ZLIB_WINAPI if zlib was built on Visual Studio. */ -/* #undef ZLIB_WINAPI */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ - -/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ -#define ARCHIVE_CRYPTO_MD5_WIN 1 - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ - -/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ - -/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ -#define ARCHIVE_CRYPTO_SHA1_WIN 1 - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ - -/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ - -/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ - -/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ -/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ - -/* Version number of bsdcpio */ -#define BSDCPIO_VERSION_STRING "3.1.2" - -/* Version number of bsdtar */ -#define BSDTAR_VERSION_STRING "3.1.2" - -/* Define to 1 if you have the `acl_create_entry' function. */ -/* #undef HAVE_ACL_CREATE_ENTRY */ - -/* Define to 1 if you have the `acl_get_link' function. */ -/* #undef HAVE_ACL_GET_LINK */ - -/* Define to 1 if you have the `acl_get_link_np' function. */ -/* #undef HAVE_ACL_GET_LINK_NP */ - -/* Define to 1 if you have the `acl_get_perm' function. */ -/* #undef HAVE_ACL_GET_PERM */ - -/* Define to 1 if you have the `acl_get_perm_np' function. */ -/* #undef HAVE_ACL_GET_PERM_NP */ - -/* Define to 1 if you have the `acl_init' function. */ -/* #undef HAVE_ACL_INIT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ACL_LIBACL_H */ - -/* Define to 1 if the system has the type `acl_permset_t'. */ -/* #undef HAVE_ACL_PERMSET_T */ - -/* Define to 1 if you have the `acl_set_fd' function. */ -/* #undef HAVE_ACL_SET_FD */ - -/* Define to 1 if you have the `acl_set_fd_np' function. */ -/* #undef HAVE_ACL_SET_FD_NP */ - -/* Define to 1 if you have the `acl_set_file' function. */ -/* #undef HAVE_ACL_SET_FILE */ - -/* True for systems with POSIX ACL support */ -/* #undef HAVE_ACL_USER */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ATTR_XATTR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BSDXML_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the `chflags' function. */ -/* #undef HAVE_CHFLAGS */ - -/* Define to 1 if you have the `chown' function. */ -/* #undef HAVE_CHOWN */ - -/* Define to 1 if you have the `chroot' function. */ -/* #undef HAVE_CHROOT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_COPYFILE_H */ - -/* Define to 1 if you have the `ctime_r' function. */ -/* #undef HAVE_CTIME_R */ - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the `cygwin_conv_path' function. */ -/* #undef HAVE_CYGWIN_CONV_PATH */ - -/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MAX 1 - -/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you - don't. */ -#define HAVE_DECL_INT64_MIN 1 - -/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_SIZE_MAX 1 - -/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you - don't. */ -/* #undef HAVE_DECL_SSIZE_MAX */ - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -/* #undef HAVE_DECL_STRERROR_R */ - -/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT32_MAX 1 - -/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you - don't. */ -#define HAVE_DECL_UINT64_MAX 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRECT_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_DIRENT_H */ - -/* Define to 1 if you have the `dirfd' function. */ -/* #undef HAVE_DIRFD */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if nl_langinfo supports D_MD_ORDER */ -/* #undef HAVE_D_MD_ORDER */ - -/* A possible errno value for invalid file format errors */ -/* #undef HAVE_EFTYPE */ - -/* A possible errno value for invalid file format errors */ -#define HAVE_EILSEQ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXPAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXT2FS_EXT2_FS_H */ - -/* Define to 1 if you have the `extattr_get_file' function. */ -/* #undef HAVE_EXTATTR_GET_FILE */ - -/* Define to 1 if you have the `extattr_list_file' function. */ -/* #undef HAVE_EXTATTR_LIST_FILE */ - -/* Define to 1 if you have the `extattr_set_fd' function. */ -/* #undef HAVE_EXTATTR_SET_FD */ - -/* Define to 1 if you have the `extattr_set_file' function. */ -/* #undef HAVE_EXTATTR_SET_FILE */ - -/* Define to 1 if EXTATTR_NAMESPACE_USER is defined in sys/extattr.h. */ -/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ - -/* Define to 1 if you have the `fchdir' function. */ -/* #undef HAVE_FCHDIR */ - -/* Define to 1 if you have the `fchflags' function. */ -/* #undef HAVE_FCHFLAGS */ - -/* Define to 1 if you have the `fchmod' function. */ -/* #undef HAVE_FCHMOD */ - -/* Define to 1 if you have the `fchown' function. */ -/* #undef HAVE_FCHOWN */ - -/* Define to 1 if you have the `fcntl' function. */ -/* #undef HAVE_FCNTL */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `fdopendir' function. */ -/* #undef HAVE_FDOPENDIR */ - -/* Define to 1 if you have the `fgetea' function. */ -/* #undef HAVE_FGETEA */ - -/* Define to 1 if you have the `fgetxattr' function. */ -/* #undef HAVE_FGETXATTR */ - -/* Define to 1 if you have the `flistea' function. */ -/* #undef HAVE_FLISTEA */ - -/* Define to 1 if you have the `flistxattr' function. */ -/* #undef HAVE_FLISTXATTR */ - -/* Define to 1 if you have the `fork' function. */ -/* #undef HAVE_FORK */ - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -/* #undef HAVE_FSEEKO */ - -/* Define to 1 if you have the `fsetea' function. */ -/* #undef HAVE_FSETEA */ - -/* Define to 1 if you have the `fsetxattr' function. */ -/* #undef HAVE_FSETXATTR */ - -/* Define to 1 if you have the `fstat' function. */ -#define HAVE_FSTAT 1 - -/* Define to 1 if you have the `fstatat' function. */ -/* #undef HAVE_FSTATAT */ - -/* Define to 1 if you have the `fstatfs' function. */ -/* #undef HAVE_FSTATFS */ - -/* Define to 1 if you have the `fstatvfs' function. */ -/* #undef HAVE_FSTATVFS */ - -/* Define to 1 if you have the `ftruncate' function. */ -/* #undef HAVE_FTRUNCATE */ - -/* Define to 1 if you have the `futimens' function. */ -/* #undef HAVE_FUTIMENS */ - -/* Define to 1 if you have the `futimes' function. */ -/* #undef HAVE_FUTIMES */ - -/* Define to 1 if you have the `futimesat' function. */ -/* #undef HAVE_FUTIMESAT */ - -/* Define to 1 if you have the `getea' function. */ -/* #undef HAVE_GETEA */ - -/* Define to 1 if you have the `geteuid' function. */ -/* #undef HAVE_GETEUID */ - -/* Define to 1 if you have the `getgrgid_r' function. */ -/* #undef HAVE_GETGRGID_R */ - -/* Define to 1 if you have the `getgrnam_r' function. */ -/* #undef HAVE_GETGRNAM_R */ - -/* Define to 1 if you have the `getpid' function. */ -#define HAVE_GETPID 1 - -/* Define to 1 if you have the `getpwnam_r' function. */ -/* #undef HAVE_GETPWNAM_R */ - -/* Define to 1 if you have the `getpwuid_r' function. */ -/* #undef HAVE_GETPWUID_R */ - -/* Define to 1 if you have the `getvfsbyname' function. */ -/* #undef HAVE_GETVFSBYNAME */ - -/* Define to 1 if you have the `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the `gmtime_r' function. */ -/* #undef HAVE_GMTIME_R */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_GRP_H */ - -/* Define to 1 if you have the `iconv' function. */ -/* #undef HAVE_ICONV */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ICONV_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LANGINFO_H */ - -/* Define to 1 if you have the `lchflags' function. */ -/* #undef HAVE_LCHFLAGS */ - -/* Define to 1 if you have the `lchmod' function. */ -/* #undef HAVE_LCHMOD */ - -/* Define to 1 if you have the `lchown' function. */ -/* #undef HAVE_LCHOWN */ - -/* Define to 1 if you have the `lgetea' function. */ -/* #undef HAVE_LGETEA */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `acl' library (-lacl). */ -/* #undef HAVE_LIBACL */ - -/* Define to 1 if you have the `attr' library (-lattr). */ -/* #undef HAVE_LIBATTR */ - -/* Define to 1 if you have the `bsdxml' library (-lbsdxml). */ -/* #undef HAVE_LIBBSDXML */ - -/* Define to 1 if you have the `bz2' library (-lbz2). */ -/* #undef HAVE_LIBBZ2 */ - -/* Define to 1 if you have the `expat' library (-lexpat). */ -/* #undef HAVE_LIBEXPAT */ - -/* Define to 1 if you have the `gcc' library (-lgcc). */ -/* #undef HAVE_LIBGCC */ - -/* Define to 1 if you have the `lzma' library (-llzma). */ -/* #undef HAVE_LIBLZMA */ - -/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ -/* #undef HAVE_LIBLZMADEC */ - -/* Define to 1 if you have the `lzo2' library (-llzo2). */ -/* #undef HAVE_LIBLZO2 */ - -/* Define to 1 if you have the `nettle' library (-lnettle). */ -/* #undef HAVE_LIBNETTLE */ - -/* Define to 1 if you have the `pcre' library (-lpcre). */ -/* #undef HAVE_LIBPCRE */ - -/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ -/* #undef HAVE_LIBPCREPOSIX */ - -/* Define to 1 if you have the `xml2' library (-lxml2). */ -/* #undef HAVE_LIBXML2 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLREADER_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBXML_XMLWRITER_H */ - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the `link' function. */ -/* #undef HAVE_LINK */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FIEMAP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_MAGIC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_TYPES_H */ - -/* Define to 1 if you have the `listea' function. */ -/* #undef HAVE_LISTEA */ - -/* Define to 1 if you have the `listxattr' function. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistea' function. */ -/* #undef HAVE_LLISTEA */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LOCALCHARSET_H */ - -/* Define to 1 if you have the `locale_charset' function. */ -/* #undef HAVE_LOCALE_CHARSET */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -/* #undef HAVE_LOCALTIME_R */ - -/* Define to 1 if the system has the type `long long int'. */ -/* #undef HAVE_LONG_LONG_INT */ - -/* Define to 1 if you have the `lsetea' function. */ -/* #undef HAVE_LSETEA */ - -/* Define to 1 if you have the `lsetxattr' function. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if you have the `lstat' function. */ -/* #undef HAVE_LSTAT */ - -/* Define to 1 if `lstat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the `lutimes' function. */ -/* #undef HAVE_LUTIMES */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMADEC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZMA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZO1X_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LZO_LZOCONF_H */ - -/* Define to 1 if you have the `mbrtowc' function. */ -#define HAVE_MBRTOWC 1 - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the `mkfifo' function. */ -/* #undef HAVE_MKFIFO */ - -/* Define to 1 if you have the `mknod' function. */ -/* #undef HAVE_MKNOD */ - -/* Define to 1 if you have the `mkstemp' function. */ -/* #undef HAVE_MKSTEMP */ - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_MD5_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_RIPEMD160_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETTLE_SHA_H */ - -/* Define to 1 if you have the `nl_langinfo' function. */ -/* #undef HAVE_NL_LANGINFO */ - -/* Define to 1 if you have the `openat' function. */ -/* #undef HAVE_OPENAT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PATHS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PCREPOSIX_H */ - -/* Define to 1 if you have the `pipe' function. */ -/* #undef HAVE_PIPE */ - -/* Define to 1 if you have the `poll' function. */ -/* #undef HAVE_POLL */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_POLL_H */ - -/* Define to 1 if you have the `posix_spawnp' function. */ -/* #undef HAVE_POSIX_SPAWNP */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PROCESS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 if you have the `readdir_r' function. */ -/* #undef HAVE_READDIR_R */ - -/* Define to 1 if you have the `readlink' function. */ -/* #undef HAVE_READLINK */ - -/* Define to 1 if you have the `readlinkat' function. */ -/* #undef HAVE_READLINKAT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_REGEX_H */ - -/* Define to 1 if you have the `select' function. */ -/* #undef HAVE_SELECT */ - -/* Define to 1 if you have the `setenv' function. */ -/* #undef HAVE_SETENV */ - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `sigaction' function. */ -/* #undef HAVE_SIGACTION */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SPAWN_H */ - -/* Define to 1 if you have the `statfs' function. */ -/* #undef HAVE_STATFS */ - -/* Define to 1 if you have the `statvfs' function. */ -/* #undef HAVE_STATVFS */ - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -/* #undef HAVE_STRERROR_R */ - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ -/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ - -/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ -/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ - -/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */ - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ - -/* Define to 1 if `st_flags' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ - -/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */ - -/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ - -/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ - -/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ - -/* Define to 1 if `st_umtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ - -/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM_TM_GMTOFF */ - -/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ - -/* Define to 1 if you have the `symlink' function. */ -/* #undef HAVE_SYMLINK */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ACL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_CDEFS_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EXTATTR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MOUNT_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PARAM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SELECT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_STATFS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_STATVFS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTSNAME_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_VFS_H */ - -/* Define to 1 if you have that is POSIX.1 compatible. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the `timegm' function. */ -/* #undef HAVE_TIMEGM */ - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the `tzset' function. */ -#define HAVE_TZSET 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define to 1 if you have the `unsetenv' function. */ -/* #undef HAVE_UNSETENV */ - -/* Define to 1 if the system has the type `unsigned long long'. */ -/* #undef HAVE_UNSIGNED_LONG_LONG */ - -/* Define to 1 if the system has the type `unsigned long long int'. */ -/* #undef HAVE_UNSIGNED_LONG_LONG_INT */ - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimensat' function. */ -/* #undef HAVE_UTIMENSAT */ - -/* Define to 1 if you have the `utimes' function. */ -/* #undef HAVE_UTIMES */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UTIME_H */ - -/* Define to 1 if you have the `vfork' function. */ -/* #undef HAVE_VFORK */ - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if the system has the type `wchar_t'. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the `wcrtomb' function. */ -#define HAVE_WCRTOMB 1 - -/* Define to 1 if you have the `wcscmp' function. */ -#define HAVE_WCSCMP 1 - -/* Define to 1 if you have the `wcscpy' function. */ -#define HAVE_WCSCPY 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define to 1 if you have the `wctomb' function. */ -#define HAVE_WCTOMB 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCTYPE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WINCRYPT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WINIOCTL_H 1 - -/* Define to 1 if you have _CrtSetReportMode in */ -#define HAVE__CrtSetReportMode 1 - -/* Define to 1 if you have the `wmemcmp' function. */ -/* #undef HAVE_WMEMCMP */ - -/* Define to 1 if you have the `wmemcpy' function. */ -/* #undef HAVE_WMEMCPY */ - -/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ -/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Define to 1 if you have the `_ctime64_s' function. */ -#define HAVE__CTIME64_S 1 - -/* Define to 1 if you have the `_fseeki64' function. */ -#define HAVE__FSEEKI64 1 - -/* Define to 1 if you have the `_get_timezone' function. */ -#define HAVE__GET_TIMEZONE 1 - -/* Define to 1 if you have the `_localtime64_s' function. */ -#define HAVE__LOCALTIME64_S 1 - -/* Define to 1 if you have the `_mkgmtime64' function. */ -#define HAVE__MKGMTIME64 1 - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Version number of libarchive as a single integer */ -#define LIBARCHIVE_VERSION_NUMBER "3001002" - -/* Version number of libarchive */ -#define LIBARCHIVE_VERSION_STRING "3.1.2" - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 2 - -/* Define to 1 if strerror_r returns char *. */ -/* #undef STRERROR_R_CHAR_P */ - -/* Define to 1 if you can safely include both and . */ -/* #undef TIME_WITH_SYS_TIME */ - -/* - * Some platform requires a macro to use extension functions. - */ -#define SAFE_TO_DEFINE_EXTENSIONS 1 -#ifdef SAFE_TO_DEFINE_EXTENSIONS -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif -#endif /* SAFE_TO_DEFINE_EXTENSIONS */ - -/* Version number of package */ -#define VERSION "3.1.2" - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define for Windows to use Windows 2000+ APIs. */ -#define _WIN32_WINNT 0x0500 -#define WINVER 0x0500 - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `int' if doesn't define. */ -#define gid_t short - -/* Define to `unsigned long' if does not define. */ -#define id_t short - -/* Define to `int' if does not define. */ -#ifndef __MINGW32__ -# define mode_t unsigned short -#endif - -/* Define to `long long' if does not define. */ -/* #undef off_t */ - -/* Define to `int' if doesn't define. */ -#define pid_t int - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to `int' if does not define. */ -#if defined(_WIN64) -# define ssize_t __int64 -#else -# define ssize_t long -#endif - -/* Define to `int' if doesn't define. */ -#define uid_t short - -/* Define to `int' if does not define. */ -/* #undef intptr_t */ - -/* Define to `unsigned int' if does not define. */ -/* #undef uintptr_t */ diff --git a/3rdparty/libarchive/libarchive.pro b/3rdparty/libarchive/libarchive.pro deleted file mode 100644 index 4ec7eaaa..00000000 --- a/3rdparty/libarchive/libarchive.pro +++ /dev/null @@ -1,126 +0,0 @@ -TEMPLATE = lib -TARGET = qtarchive - -load(am-config) - -CONFIG += \ - static \ - hide_symbols \ - exceptions_off rtti_off warn_off \ - installed - -macos:LIBS += -framework CoreServices -liconv -ios:LIBS += -liconv -win32:LIBS += -lcrypt32 -ladvapi32 -win32:MODULE_DEFINES += LIBARCHIVE_STATIC -MODULE_INCLUDEPATH += $$PWD/libarchive - -load(qt_helper_lib) - -win32-msvc* { - QMAKE_CFLAGS += /wd4146 /wd4133 /D_CRT_SECURE_NO_WARNINGS -} -*-g++* { - QMAKE_CFLAGS += -Wno-unused -Wno-sign-compare -Wno-old-style-declaration -} -*-clang* { - CONFIG *= warn_off - QMAKE_CFLAGS += -Wall -W -Wno-unused -Wno-sign-compare -} - -android:DEFINES += PLATFORM_CONFIG_H=\\\"config-android.h\\\" -else:win32:DEFINES += PLATFORM_CONFIG_H=\\\"config-windows.h\\\" -else:macos:DEFINES += PLATFORM_CONFIG_H=\\\"config-macos.h\\\" -else:ios:DEFINES += PLATFORM_CONFIG_H=\\\"config-ios.h\\\" -else:DEFINES += PLATFORM_CONFIG_H=\\\"config-unix.h\\\" - -OTHER_FILES += \ - config-android.h \ - config-windows.h \ - config-macos.h \ - config-ios.h \ - config-unix.h \ - android_lf.h \ - -INCLUDEPATH *= $$PWD/libarchive - -include(../libz.pri) - -# disabled for now, since we have 2 problems: -# 1) the python/django appstore is based on python 2.7 which does not support it via tarfile -# 2) we get a weird error on macOS when creating XZ'ed packages from libarchive -# include(../liblzma.pri) - -SOURCES += \ - libarchive/archive_acl.c \ - libarchive/archive_check_magic.c \ - libarchive/archive_cmdline.c \ - libarchive/archive_entry.c \ - libarchive/archive_entry_copy_stat.c \ - libarchive/archive_entry_link_resolver.c \ - libarchive/archive_entry_sparse.c \ - libarchive/archive_entry_stat.c \ - libarchive/archive_entry_strmode.c \ - libarchive/archive_entry_xattr.c \ - libarchive/archive_getdate.c \ - libarchive/archive_match.c \ - libarchive/archive_options.c \ - libarchive/archive_pathmatch.c \ - libarchive/archive_ppmd7.c \ - libarchive/archive_random.c \ - libarchive/archive_rb.c \ - libarchive/archive_read_append_filter.c \ - libarchive/archive_read.c \ - libarchive/archive_read_data_into_fd.c \ - libarchive/archive_read_disk_entry_from_file.c \ - libarchive/archive_read_disk_set_standard_lookup.c \ - libarchive/archive_read_extract.c \ - libarchive/archive_read_open_fd.c \ - libarchive/archive_read_open_file.c \ - libarchive/archive_read_open_filename.c \ - libarchive/archive_read_open_memory.c \ - libarchive/archive_read_set_format.c \ - libarchive/archive_read_set_options.c \ - libarchive/archive_read_support_filter_bzip2.c \ - libarchive/archive_read_support_filter_gzip.c \ - libarchive/archive_read_support_filter_none.c \ - libarchive/archive_read_support_filter_program.c \ - libarchive/archive_read_support_filter_xz.c \ - libarchive/archive_read_support_format_by_code.c \ - libarchive/archive_read_support_format_empty.c \ - libarchive/archive_read_support_format_tar.c \ - libarchive/archive_string.c \ - libarchive/archive_string_sprintf.c \ - libarchive/archive_util.c \ - libarchive/archive_virtual.c \ - libarchive/archive_write_add_filter_b64encode.c \ - libarchive/archive_write_add_filter_by_name.c \ - libarchive/archive_write_add_filter_bzip2.c \ - libarchive/archive_write_add_filter.c \ - libarchive/archive_write_add_filter_gzip.c \ - libarchive/archive_write_add_filter_none.c \ - libarchive/archive_write_add_filter_program.c \ - libarchive/archive_write_add_filter_xz.c \ - libarchive/archive_write.c \ - libarchive/archive_write_disk_set_standard_lookup.c \ - libarchive/archive_write_open_fd.c \ - libarchive/archive_write_open_file.c \ - libarchive/archive_write_open_filename.c \ - libarchive/archive_write_open_memory.c \ - libarchive/archive_write_set_format_by_name.c \ - libarchive/archive_write_set_format.c \ - libarchive/archive_write_set_format_gnutar.c \ - libarchive/archive_write_set_format_ustar.c \ - libarchive/archive_write_set_options.c \ - -!win32:SOURCES += \ - libarchive/archive_read_disk_posix.c \ - libarchive/archive_write_disk_posix.c \ - libarchive/filter_fork_posix.c \ - -win32:SOURCES += \ - libarchive/archive_entry_copy_bhfi.c \ - libarchive/archive_read_disk_windows.c \ - libarchive/archive_windows.c \ - libarchive/archive_write_disk_windows.c \ - libarchive/filter_fork_windows.c \ diff --git a/3rdparty/libarchive/libarchive/android_lf.h b/3rdparty/libarchive/libarchive/android_lf.h deleted file mode 100644 index 2a18f514..00000000 --- a/3rdparty/libarchive/libarchive/android_lf.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Macros for file64 functions - * - * Android does not support the macro _FILE_OFFSET_BITS=64 - * As of android-21 it does however support many file64 functions -*/ - -#ifndef ARCHIVE_ANDROID_LF_H_INCLUDED -#define ARCHIVE_ANDROID_LF_H_INCLUDED - -#if __ANDROID_API__ > 20 - -#include -#include -#include -#include -#include -#include -#include - -//dirent.h -#define readdir_r readdir64_r -#define readdir readdir64 -#define dirent dirent64 -//fcntl.h -#define openat openat64 -#define open open64 -#define mkstemp mkstemp64 -//unistd.h -#define lseek lseek64 -#define ftruncate ftruncate64 -//sys/stat.h -#define fstatat fstatat64 -#define fstat fstat64 -#define lstat lstat64 -#define stat stat64 -//sys/statvfs.h -#define fstatvfs fstatvfs64 -#define statvfs statvfs64 -//sys/types.h -#define off_t off64_t -//sys/vfs.h -#define fstatfs fstatfs64 -#define statfs statfs64 -#endif - -#endif /* ARCHIVE_ANDROID_LF_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive.h b/3rdparty/libarchive/libarchive/archive.h deleted file mode 100644 index 316a68a6..00000000 --- a/3rdparty/libarchive/libarchive/archive.h +++ /dev/null @@ -1,1187 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $ - */ - -#ifndef ARCHIVE_H_INCLUDED -#define ARCHIVE_H_INCLUDED - -/* - * The version number is expressed as a single integer that makes it - * easy to compare versions at build time: for version a.b.c, the - * version number is printf("%d%03d%03d",a,b,c). For example, if you - * know your application requires version 2.12.108 or later, you can - * assert that ARCHIVE_VERSION_NUMBER >= 2012108. - */ -/* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3003002 - -#include -#include /* for wchar_t */ -#include /* For FILE * */ -#include /* For time_t */ - -/* - * Note: archive.h is for use outside of libarchive; the configuration - * headers (config.h, archive_platform.h, etc.) are purely internal. - * Do NOT use HAVE_XXX configuration macros to control the behavior of - * this header! If you must conditionalize, use predefined compiler and/or - * platform macros. - */ -#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 -# include -#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__) -# include -#endif - -/* Get appropriate definitions of 64-bit integer */ -#if !defined(__LA_INT64_T_DEFINED) -/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */ -# if ARCHIVE_VERSION_NUMBER < 4000000 -#define __LA_INT64_T la_int64_t -# endif -#define __LA_INT64_T_DEFINED -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) -typedef __int64 la_int64_t; -# else -# include /* ssize_t */ -# if defined(_SCO_DS) || defined(__osf__) -typedef long long la_int64_t; -# else -typedef int64_t la_int64_t; -# endif -# endif -#endif - -/* The la_ssize_t should match the type used in 'struct stat' */ -#if !defined(__LA_SSIZE_T_DEFINED) -/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */ -# if ARCHIVE_VERSION_NUMBER < 4000000 -#define __LA_SSIZE_T la_ssize_t -# endif -#define __LA_SSIZE_T_DEFINED -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) -# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_) -typedef ssize_t la_ssize_t; -# elif defined(_WIN64) -typedef __int64 la_ssize_t; -# else -typedef long la_ssize_t; -# endif -# else -# include /* ssize_t */ -typedef ssize_t la_ssize_t; -# endif -#endif - -/* Large file support for Android */ -#ifdef __ANDROID__ -#include "android_lf.h" -#endif - -/* - * On Windows, define LIBARCHIVE_STATIC if you're building or using a - * .lib. The default here assumes you're building a DLL. Only - * libarchive source should ever define __LIBARCHIVE_BUILD. - */ -#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) -# ifdef __LIBARCHIVE_BUILD -# ifdef __GNUC__ -# define __LA_DECL __attribute__((dllexport)) extern -# else -# define __LA_DECL __declspec(dllexport) -# endif -# else -# ifdef __GNUC__ -# define __LA_DECL -# else -# define __LA_DECL __declspec(dllimport) -# endif -# endif -#else -/* Static libraries or non-Windows needs no special declaration. */ -# define __LA_DECL -#endif - -#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__) -#define __LA_PRINTF(fmtarg, firstvararg) \ - __attribute__((__format__ (__printf__, fmtarg, firstvararg))) -#else -#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */ -#endif - -#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 -# define __LA_DEPRECATED __attribute__((deprecated)) -#else -# define __LA_DEPRECATED -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The version number is provided as both a macro and a function. - * The macro identifies the installed header; the function identifies - * the library version (which may not be the same if you're using a - * dynamically-linked version of the library). Of course, if the - * header and library are very different, you should expect some - * strangeness. Don't do that. - */ -__LA_DECL int archive_version_number(void); - -/* - * Textual name/version of the library, useful for version displays. - */ -#define ARCHIVE_VERSION_ONLY_STRING "3.3.2" -#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING -__LA_DECL const char * archive_version_string(void); - -/* - * Detailed textual name/version of the library and its dependencies. - * This has the form: - * "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..." - * the list of libraries described here will vary depending on how - * libarchive was compiled. - */ -__LA_DECL const char * archive_version_details(void); - -/* - * Returns NULL if libarchive was compiled without the associated library. - * Otherwise, returns the version number that libarchive was compiled - * against. - */ -__LA_DECL const char * archive_zlib_version(void); -__LA_DECL const char * archive_liblzma_version(void); -__LA_DECL const char * archive_bzlib_version(void); -__LA_DECL const char * archive_liblz4_version(void); - -/* Declare our basic types. */ -struct archive; -struct archive_entry; - -/* - * Error codes: Use archive_errno() and archive_error_string() - * to retrieve details. Unless specified otherwise, all functions - * that return 'int' use these codes. - */ -#define ARCHIVE_EOF 1 /* Found end of archive. */ -#define ARCHIVE_OK 0 /* Operation was successful. */ -#define ARCHIVE_RETRY (-10) /* Retry might succeed. */ -#define ARCHIVE_WARN (-20) /* Partial success. */ -/* For example, if write_header "fails", then you can't push data. */ -#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */ -/* But if write_header is "fatal," then this archive is dead and useless. */ -#define ARCHIVE_FATAL (-30) /* No more operations are possible. */ - -/* - * As far as possible, archive_errno returns standard platform errno codes. - * Of course, the details vary by platform, so the actual definitions - * here are stored in "archive_platform.h". The symbols are listed here - * for reference; as a rule, clients should not need to know the exact - * platform-dependent error code. - */ -/* Unrecognized or invalid file format. */ -/* #define ARCHIVE_ERRNO_FILE_FORMAT */ -/* Illegal usage of the library. */ -/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */ -/* Unknown or unclassified error. */ -/* #define ARCHIVE_ERRNO_MISC */ - -/* - * Callbacks are invoked to automatically read/skip/write/open/close the - * archive. You can provide your own for complex tasks (like breaking - * archives across multiple tapes) or use standard ones built into the - * library. - */ - -/* Returns pointer and size of next block of data from archive. */ -typedef la_ssize_t archive_read_callback(struct archive *, - void *_client_data, const void **_buffer); - -/* Skips at most request bytes from archive and returns the skipped amount. - * This may skip fewer bytes than requested; it may even skip zero bytes. - * If you do skip fewer bytes than requested, libarchive will invoke your - * read callback and discard data as necessary to make up the full skip. - */ -typedef la_int64_t archive_skip_callback(struct archive *, - void *_client_data, la_int64_t request); - -/* Seeks to specified location in the file and returns the position. - * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h. - * Return ARCHIVE_FATAL if the seek fails for any reason. - */ -typedef la_int64_t archive_seek_callback(struct archive *, - void *_client_data, la_int64_t offset, int whence); - -/* Returns size actually written, zero on EOF, -1 on error. */ -typedef la_ssize_t archive_write_callback(struct archive *, - void *_client_data, - const void *_buffer, size_t _length); - -typedef int archive_open_callback(struct archive *, void *_client_data); - -typedef int archive_close_callback(struct archive *, void *_client_data); - -/* Switches from one client data object to the next/prev client data object. - * This is useful for reading from different data blocks such as a set of files - * that make up one large file. - */ -typedef int archive_switch_callback(struct archive *, void *_client_data1, - void *_client_data2); - -/* - * Returns a passphrase used for encryption or decryption, NULL on nothing - * to do and give it up. - */ -typedef const char *archive_passphrase_callback(struct archive *, - void *_client_data); - -/* - * Codes to identify various stream filters. - */ -#define ARCHIVE_FILTER_NONE 0 -#define ARCHIVE_FILTER_GZIP 1 -#define ARCHIVE_FILTER_BZIP2 2 -#define ARCHIVE_FILTER_COMPRESS 3 -#define ARCHIVE_FILTER_PROGRAM 4 -#define ARCHIVE_FILTER_LZMA 5 -#define ARCHIVE_FILTER_XZ 6 -#define ARCHIVE_FILTER_UU 7 -#define ARCHIVE_FILTER_RPM 8 -#define ARCHIVE_FILTER_LZIP 9 -#define ARCHIVE_FILTER_LRZIP 10 -#define ARCHIVE_FILTER_LZOP 11 -#define ARCHIVE_FILTER_GRZIP 12 -#define ARCHIVE_FILTER_LZ4 13 - -#if ARCHIVE_VERSION_NUMBER < 4000000 -#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE -#define ARCHIVE_COMPRESSION_GZIP ARCHIVE_FILTER_GZIP -#define ARCHIVE_COMPRESSION_BZIP2 ARCHIVE_FILTER_BZIP2 -#define ARCHIVE_COMPRESSION_COMPRESS ARCHIVE_FILTER_COMPRESS -#define ARCHIVE_COMPRESSION_PROGRAM ARCHIVE_FILTER_PROGRAM -#define ARCHIVE_COMPRESSION_LZMA ARCHIVE_FILTER_LZMA -#define ARCHIVE_COMPRESSION_XZ ARCHIVE_FILTER_XZ -#define ARCHIVE_COMPRESSION_UU ARCHIVE_FILTER_UU -#define ARCHIVE_COMPRESSION_RPM ARCHIVE_FILTER_RPM -#define ARCHIVE_COMPRESSION_LZIP ARCHIVE_FILTER_LZIP -#define ARCHIVE_COMPRESSION_LRZIP ARCHIVE_FILTER_LRZIP -#endif - -/* - * Codes returned by archive_format. - * - * Top 16 bits identifies the format family (e.g., "tar"); lower - * 16 bits indicate the variant. This is updated by read_next_header. - * Note that the lower 16 bits will often vary from entry to entry. - * In some cases, this variation occurs as libarchive learns more about - * the archive (for example, later entries might utilize extensions that - * weren't necessary earlier in the archive; in this case, libarchive - * will change the format code to indicate the extended format that - * was used). In other cases, it's because different tools have - * modified the archive and so different parts of the archive - * actually have slightly different formats. (Both tar and cpio store - * format codes in each entry, so it is quite possible for each - * entry to be in a different format.) - */ -#define ARCHIVE_FORMAT_BASE_MASK 0xff0000 -#define ARCHIVE_FORMAT_CPIO 0x10000 -#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1) -#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2) -#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3) -#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) -#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) -#define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6) -#define ARCHIVE_FORMAT_SHAR 0x20000 -#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) -#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) -#define ARCHIVE_FORMAT_TAR 0x30000 -#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1) -#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2) -#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3) -#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4) -#define ARCHIVE_FORMAT_ISO9660 0x40000 -#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1) -#define ARCHIVE_FORMAT_ZIP 0x50000 -#define ARCHIVE_FORMAT_EMPTY 0x60000 -#define ARCHIVE_FORMAT_AR 0x70000 -#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1) -#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2) -#define ARCHIVE_FORMAT_MTREE 0x80000 -#define ARCHIVE_FORMAT_RAW 0x90000 -#define ARCHIVE_FORMAT_XAR 0xA0000 -#define ARCHIVE_FORMAT_LHA 0xB0000 -#define ARCHIVE_FORMAT_CAB 0xC0000 -#define ARCHIVE_FORMAT_RAR 0xD0000 -#define ARCHIVE_FORMAT_7ZIP 0xE0000 -#define ARCHIVE_FORMAT_WARC 0xF0000 - -/* - * Codes returned by archive_read_format_capabilities(). - * - * This list can be extended with values between 0 and 0xffff. - * The original purpose of this list was to let different archive - * format readers expose their general capabilities in terms of - * encryption. - */ -#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */ -#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */ -#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */ - -/* - * Codes returned by archive_read_has_encrypted_entries(). - * - * In case the archive does not support encryption detection at all - * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader - * for some other reason (e.g. not enough bytes read) cannot say if - * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW - * is returned. - */ -#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2 -#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1 - -/*- - * Basic outline for reading an archive: - * 1) Ask archive_read_new for an archive reader object. - * 2) Update any global properties as appropriate. - * In particular, you'll certainly want to call appropriate - * archive_read_support_XXX functions. - * 3) Call archive_read_open_XXX to open the archive - * 4) Repeatedly call archive_read_next_header to get information about - * successive archive entries. Call archive_read_data to extract - * data for entries of interest. - * 5) Call archive_read_free to end processing. - */ -__LA_DECL struct archive *archive_read_new(void); - -/* - * The archive_read_support_XXX calls enable auto-detect for this - * archive handle. They also link in the necessary support code. - * For example, if you don't want bzlib linked in, don't invoke - * support_compression_bzip2(). The "all" functions provide the - * obvious shorthand. - */ - -#if ARCHIVE_VERSION_NUMBER < 4000000 -__LA_DECL int archive_read_support_compression_all(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_bzip2(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_compress(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_gzip(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_lzip(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_lzma(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_none(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_program(struct archive *, - const char *command) __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_program_signature - (struct archive *, const char *, - const void * /* match */, size_t) __LA_DEPRECATED; - -__LA_DECL int archive_read_support_compression_rpm(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_uu(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_read_support_compression_xz(struct archive *) - __LA_DEPRECATED; -#endif - -__LA_DECL int archive_read_support_filter_all(struct archive *); -__LA_DECL int archive_read_support_filter_bzip2(struct archive *); -__LA_DECL int archive_read_support_filter_compress(struct archive *); -__LA_DECL int archive_read_support_filter_gzip(struct archive *); -__LA_DECL int archive_read_support_filter_grzip(struct archive *); -__LA_DECL int archive_read_support_filter_lrzip(struct archive *); -__LA_DECL int archive_read_support_filter_lz4(struct archive *); -__LA_DECL int archive_read_support_filter_lzip(struct archive *); -__LA_DECL int archive_read_support_filter_lzma(struct archive *); -__LA_DECL int archive_read_support_filter_lzop(struct archive *); -__LA_DECL int archive_read_support_filter_none(struct archive *); -__LA_DECL int archive_read_support_filter_program(struct archive *, - const char *command); -__LA_DECL int archive_read_support_filter_program_signature - (struct archive *, const char * /* cmd */, - const void * /* match */, size_t); -__LA_DECL int archive_read_support_filter_rpm(struct archive *); -__LA_DECL int archive_read_support_filter_uu(struct archive *); -__LA_DECL int archive_read_support_filter_xz(struct archive *); - -__LA_DECL int archive_read_support_format_7zip(struct archive *); -__LA_DECL int archive_read_support_format_all(struct archive *); -__LA_DECL int archive_read_support_format_ar(struct archive *); -__LA_DECL int archive_read_support_format_by_code(struct archive *, int); -__LA_DECL int archive_read_support_format_cab(struct archive *); -__LA_DECL int archive_read_support_format_cpio(struct archive *); -__LA_DECL int archive_read_support_format_empty(struct archive *); -__LA_DECL int archive_read_support_format_gnutar(struct archive *); -__LA_DECL int archive_read_support_format_iso9660(struct archive *); -__LA_DECL int archive_read_support_format_lha(struct archive *); -__LA_DECL int archive_read_support_format_mtree(struct archive *); -__LA_DECL int archive_read_support_format_rar(struct archive *); -__LA_DECL int archive_read_support_format_raw(struct archive *); -__LA_DECL int archive_read_support_format_tar(struct archive *); -__LA_DECL int archive_read_support_format_warc(struct archive *); -__LA_DECL int archive_read_support_format_xar(struct archive *); -/* archive_read_support_format_zip() enables both streamable and seekable - * zip readers. */ -__LA_DECL int archive_read_support_format_zip(struct archive *); -/* Reads Zip archives as stream from beginning to end. Doesn't - * correctly handle SFX ZIP files or ZIP archives that have been modified - * in-place. */ -__LA_DECL int archive_read_support_format_zip_streamable(struct archive *); -/* Reads starting from central directory; requires seekable input. */ -__LA_DECL int archive_read_support_format_zip_seekable(struct archive *); - -/* Functions to manually set the format and filters to be used. This is - * useful to bypass the bidding process when the format and filters to use - * is known in advance. - */ -__LA_DECL int archive_read_set_format(struct archive *, int); -__LA_DECL int archive_read_append_filter(struct archive *, int); -__LA_DECL int archive_read_append_filter_program(struct archive *, - const char *); -__LA_DECL int archive_read_append_filter_program_signature - (struct archive *, const char *, const void * /* match */, size_t); - -/* Set various callbacks. */ -__LA_DECL int archive_read_set_open_callback(struct archive *, - archive_open_callback *); -__LA_DECL int archive_read_set_read_callback(struct archive *, - archive_read_callback *); -__LA_DECL int archive_read_set_seek_callback(struct archive *, - archive_seek_callback *); -__LA_DECL int archive_read_set_skip_callback(struct archive *, - archive_skip_callback *); -__LA_DECL int archive_read_set_close_callback(struct archive *, - archive_close_callback *); -/* Callback used to switch between one data object to the next */ -__LA_DECL int archive_read_set_switch_callback(struct archive *, - archive_switch_callback *); - -/* This sets the first data object. */ -__LA_DECL int archive_read_set_callback_data(struct archive *, void *); -/* This sets data object at specified index */ -__LA_DECL int archive_read_set_callback_data2(struct archive *, void *, - unsigned int); -/* This adds a data object at the specified index. */ -__LA_DECL int archive_read_add_callback_data(struct archive *, void *, - unsigned int); -/* This appends a data object to the end of list */ -__LA_DECL int archive_read_append_callback_data(struct archive *, void *); -/* This prepends a data object to the beginning of list */ -__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *); - -/* Opening freezes the callbacks. */ -__LA_DECL int archive_read_open1(struct archive *); - -/* Convenience wrappers around the above. */ -__LA_DECL int archive_read_open(struct archive *, void *_client_data, - archive_open_callback *, archive_read_callback *, - archive_close_callback *); -__LA_DECL int archive_read_open2(struct archive *, void *_client_data, - archive_open_callback *, archive_read_callback *, - archive_skip_callback *, archive_close_callback *); - -/* - * A variety of shortcuts that invoke archive_read_open() with - * canned callbacks suitable for common situations. The ones that - * accept a block size handle tape blocking correctly. - */ -/* Use this if you know the filename. Note: NULL indicates stdin. */ -__LA_DECL int archive_read_open_filename(struct archive *, - const char *_filename, size_t _block_size); -/* Use this for reading multivolume files by filenames. - * NOTE: Must be NULL terminated. Sorting is NOT done. */ -__LA_DECL int archive_read_open_filenames(struct archive *, - const char **_filenames, size_t _block_size); -__LA_DECL int archive_read_open_filename_w(struct archive *, - const wchar_t *_filename, size_t _block_size); -/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */ -__LA_DECL int archive_read_open_file(struct archive *, - const char *_filename, size_t _block_size) __LA_DEPRECATED; -/* Read an archive that's stored in memory. */ -__LA_DECL int archive_read_open_memory(struct archive *, - const void * buff, size_t size); -/* A more involved version that is only used for internal testing. */ -__LA_DECL int archive_read_open_memory2(struct archive *a, const void *buff, - size_t size, size_t read_size); -/* Read an archive that's already open, using the file descriptor. */ -__LA_DECL int archive_read_open_fd(struct archive *, int _fd, - size_t _block_size); -/* Read an archive that's already open, using a FILE *. */ -/* Note: DO NOT use this with tape drives. */ -__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file); - -/* Parses and returns next entry header. */ -__LA_DECL int archive_read_next_header(struct archive *, - struct archive_entry **); - -/* Parses and returns next entry header using the archive_entry passed in */ -__LA_DECL int archive_read_next_header2(struct archive *, - struct archive_entry *); - -/* - * Retrieve the byte offset in UNCOMPRESSED data where last-read - * header started. - */ -__LA_DECL la_int64_t archive_read_header_position(struct archive *); - -/* - * Returns 1 if the archive contains at least one encrypted entry. - * If the archive format not support encryption at all - * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. - * If for any other reason (e.g. not enough data read so far) - * we cannot say whether there are encrypted entries, then - * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. - * In general, this function will return values below zero when the - * reader is uncertain or totally incapable of encryption support. - * When this function returns 0 you can be sure that the reader - * supports encryption detection but no encrypted entries have - * been found yet. - * - * NOTE: If the metadata/header of an archive is also encrypted, you - * cannot rely on the number of encrypted entries. That is why this - * function does not return the number of encrypted entries but# - * just shows that there are some. - */ -__LA_DECL int archive_read_has_encrypted_entries(struct archive *); - -/* - * Returns a bitmask of capabilities that are supported by the archive format reader. - * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. - */ -__LA_DECL int archive_read_format_capabilities(struct archive *); - -/* Read data from the body of an entry. Similar to read(2). */ -__LA_DECL la_ssize_t archive_read_data(struct archive *, - void *, size_t); - -/* Seek within the body of an entry. Similar to lseek(2). */ -__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int); - -/* - * A zero-copy version of archive_read_data that also exposes the file offset - * of each returned block. Note that the client has no way to specify - * the desired size of the block. The API does guarantee that offsets will - * be strictly increasing and that returned blocks will not overlap. - */ -__LA_DECL int archive_read_data_block(struct archive *a, - const void **buff, size_t *size, la_int64_t *offset); - -/*- - * Some convenience functions that are built on archive_read_data: - * 'skip': skips entire entry - * 'into_buffer': writes data into memory buffer that you provide - * 'into_fd': writes data to specified filedes - */ -__LA_DECL int archive_read_data_skip(struct archive *); -__LA_DECL int archive_read_data_into_fd(struct archive *, int fd); - -/* - * Set read options. - */ -/* Apply option to the format only. */ -__LA_DECL int archive_read_set_format_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option to the filter only. */ -__LA_DECL int archive_read_set_filter_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option to both the format and the filter. */ -__LA_DECL int archive_read_set_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option string to both the format and the filter. */ -__LA_DECL int archive_read_set_options(struct archive *_a, - const char *opts); - -/* - * Add a decryption passphrase. - */ -__LA_DECL int archive_read_add_passphrase(struct archive *, const char *); -__LA_DECL int archive_read_set_passphrase_callback(struct archive *, - void *client_data, archive_passphrase_callback *); - - -/*- - * Convenience function to recreate the current entry (whose header - * has just been read) on disk. - * - * This does quite a bit more than just copy data to disk. It also: - * - Creates intermediate directories as required. - * - Manages directory permissions: non-writable directories will - * be initially created with write permission enabled; when the - * archive is closed, dir permissions are edited to the values specified - * in the archive. - * - Checks hardlinks: hardlinks will not be extracted unless the - * linked-to file was also extracted within the same session. (TODO) - */ - -/* The "flags" argument selects optional behavior, 'OR' the flags you want. */ - -/* Default: Do not try to set owner/group. */ -#define ARCHIVE_EXTRACT_OWNER (0x0001) -/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ -#define ARCHIVE_EXTRACT_PERM (0x0002) -/* Default: Do not restore mtime/atime. */ -#define ARCHIVE_EXTRACT_TIME (0x0004) -/* Default: Replace existing files. */ -#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008) -/* Default: Try create first, unlink only if create fails with EEXIST. */ -#define ARCHIVE_EXTRACT_UNLINK (0x0010) -/* Default: Do not restore ACLs. */ -#define ARCHIVE_EXTRACT_ACL (0x0020) -/* Default: Do not restore fflags. */ -#define ARCHIVE_EXTRACT_FFLAGS (0x0040) -/* Default: Do not restore xattrs. */ -#define ARCHIVE_EXTRACT_XATTR (0x0080) -/* Default: Do not try to guard against extracts redirected by symlinks. */ -/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */ -#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100) -/* Default: Do not reject entries with '..' as path elements. */ -#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200) -/* Default: Create parent directories as needed. */ -#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400) -/* Default: Overwrite files, even if one on disk is newer. */ -#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) -/* Detect blocks of 0 and write holes instead. */ -#define ARCHIVE_EXTRACT_SPARSE (0x1000) -/* Default: Do not restore Mac extended metadata. */ -/* This has no effect except on Mac OS. */ -#define ARCHIVE_EXTRACT_MAC_METADATA (0x2000) -/* Default: Use HFS+ compression if it was compressed. */ -/* This has no effect except on Mac OS v10.6 or later. */ -#define ARCHIVE_EXTRACT_NO_HFS_COMPRESSION (0x4000) -/* Default: Do not use HFS+ compression if it was not compressed. */ -/* This has no effect except on Mac OS v10.6 or later. */ -#define ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED (0x8000) -/* Default: Do not reject entries with absolute paths */ -#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000) -/* Default: Do not clear no-change flags when unlinking object */ -#define ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS (0x20000) - -__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *, - int flags); -__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *, - struct archive * /* dest */); -__LA_DECL void archive_read_extract_set_progress_callback(struct archive *, - void (*_progress_func)(void *), void *_user_data); - -/* Record the dev/ino of a file that will not be written. This is - * generally set to the dev/ino of the archive being read. */ -__LA_DECL void archive_read_extract_set_skip_file(struct archive *, - la_int64_t, la_int64_t); - -/* Close the file and release most resources. */ -__LA_DECL int archive_read_close(struct archive *); -/* Release all resources and destroy the object. */ -/* Note that archive_read_free will call archive_read_close for you. */ -__LA_DECL int archive_read_free(struct archive *); -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Synonym for archive_read_free() for backwards compatibility. */ -__LA_DECL int archive_read_finish(struct archive *) __LA_DEPRECATED; -#endif - -/*- - * To create an archive: - * 1) Ask archive_write_new for an archive writer object. - * 2) Set any global properties. In particular, you should set - * the compression and format to use. - * 3) Call archive_write_open to open the file (most people - * will use archive_write_open_file or archive_write_open_fd, - * which provide convenient canned I/O callbacks for you). - * 4) For each entry: - * - construct an appropriate struct archive_entry structure - * - archive_write_header to write the header - * - archive_write_data to write the entry data - * 5) archive_write_close to close the output - * 6) archive_write_free to cleanup the writer and release resources - */ -__LA_DECL struct archive *archive_write_new(void); -__LA_DECL int archive_write_set_bytes_per_block(struct archive *, - int bytes_per_block); -__LA_DECL int archive_write_get_bytes_per_block(struct archive *); -/* XXX This is badly misnamed; suggestions appreciated. XXX */ -__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *, - int bytes_in_last_block); -__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *); - -/* The dev/ino of a file that won't be archived. This is used - * to avoid recursively adding an archive to itself. */ -__LA_DECL int archive_write_set_skip_file(struct archive *, - la_int64_t, la_int64_t); - -#if ARCHIVE_VERSION_NUMBER < 4000000 -__LA_DECL int archive_write_set_compression_bzip2(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_compress(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_gzip(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_lzip(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_lzma(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_none(struct archive *) - __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_program(struct archive *, - const char *cmd) __LA_DEPRECATED; -__LA_DECL int archive_write_set_compression_xz(struct archive *) - __LA_DEPRECATED; -#endif - -/* A convenience function to set the filter based on the code. */ -__LA_DECL int archive_write_add_filter(struct archive *, int filter_code); -__LA_DECL int archive_write_add_filter_by_name(struct archive *, - const char *name); -__LA_DECL int archive_write_add_filter_b64encode(struct archive *); -__LA_DECL int archive_write_add_filter_bzip2(struct archive *); -__LA_DECL int archive_write_add_filter_compress(struct archive *); -__LA_DECL int archive_write_add_filter_grzip(struct archive *); -__LA_DECL int archive_write_add_filter_gzip(struct archive *); -__LA_DECL int archive_write_add_filter_lrzip(struct archive *); -__LA_DECL int archive_write_add_filter_lz4(struct archive *); -__LA_DECL int archive_write_add_filter_lzip(struct archive *); -__LA_DECL int archive_write_add_filter_lzma(struct archive *); -__LA_DECL int archive_write_add_filter_lzop(struct archive *); -__LA_DECL int archive_write_add_filter_none(struct archive *); -__LA_DECL int archive_write_add_filter_program(struct archive *, - const char *cmd); -__LA_DECL int archive_write_add_filter_uuencode(struct archive *); -__LA_DECL int archive_write_add_filter_xz(struct archive *); - - -/* A convenience function to set the format based on the code or name. */ -__LA_DECL int archive_write_set_format(struct archive *, int format_code); -__LA_DECL int archive_write_set_format_by_name(struct archive *, - const char *name); -/* To minimize link pollution, use one or more of the following. */ -__LA_DECL int archive_write_set_format_7zip(struct archive *); -__LA_DECL int archive_write_set_format_ar_bsd(struct archive *); -__LA_DECL int archive_write_set_format_ar_svr4(struct archive *); -__LA_DECL int archive_write_set_format_cpio(struct archive *); -__LA_DECL int archive_write_set_format_cpio_newc(struct archive *); -__LA_DECL int archive_write_set_format_gnutar(struct archive *); -__LA_DECL int archive_write_set_format_iso9660(struct archive *); -__LA_DECL int archive_write_set_format_mtree(struct archive *); -__LA_DECL int archive_write_set_format_mtree_classic(struct archive *); -/* TODO: int archive_write_set_format_old_tar(struct archive *); */ -__LA_DECL int archive_write_set_format_pax(struct archive *); -__LA_DECL int archive_write_set_format_pax_restricted(struct archive *); -__LA_DECL int archive_write_set_format_raw(struct archive *); -__LA_DECL int archive_write_set_format_shar(struct archive *); -__LA_DECL int archive_write_set_format_shar_dump(struct archive *); -__LA_DECL int archive_write_set_format_ustar(struct archive *); -__LA_DECL int archive_write_set_format_v7tar(struct archive *); -__LA_DECL int archive_write_set_format_warc(struct archive *); -__LA_DECL int archive_write_set_format_xar(struct archive *); -__LA_DECL int archive_write_set_format_zip(struct archive *); -__LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const char *filename); -__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext); -__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *); -__LA_DECL int archive_write_zip_set_compression_store(struct archive *); -__LA_DECL int archive_write_open(struct archive *, void *, - archive_open_callback *, archive_write_callback *, - archive_close_callback *); -__LA_DECL int archive_write_open_fd(struct archive *, int _fd); -__LA_DECL int archive_write_open_filename(struct archive *, const char *_file); -__LA_DECL int archive_write_open_filename_w(struct archive *, - const wchar_t *_file); -/* A deprecated synonym for archive_write_open_filename() */ -__LA_DECL int archive_write_open_file(struct archive *, const char *_file) - __LA_DEPRECATED; -__LA_DECL int archive_write_open_FILE(struct archive *, FILE *); -/* _buffSize is the size of the buffer, _used refers to a variable that - * will be updated after each write into the buffer. */ -__LA_DECL int archive_write_open_memory(struct archive *, - void *_buffer, size_t _buffSize, size_t *_used); - -/* - * Note that the library will truncate writes beyond the size provided - * to archive_write_header or pad if the provided data is short. - */ -__LA_DECL int archive_write_header(struct archive *, - struct archive_entry *); -__LA_DECL la_ssize_t archive_write_data(struct archive *, - const void *, size_t); - -/* This interface is currently only available for archive_write_disk handles. */ -__LA_DECL la_ssize_t archive_write_data_block(struct archive *, - const void *, size_t, la_int64_t); - -__LA_DECL int archive_write_finish_entry(struct archive *); -__LA_DECL int archive_write_close(struct archive *); -/* Marks the archive as FATAL so that a subsequent free() operation - * won't try to close() cleanly. Provides a fast abort capability - * when the client discovers that things have gone wrong. */ -__LA_DECL int archive_write_fail(struct archive *); -/* This can fail if the archive wasn't already closed, in which case - * archive_write_free() will implicitly call archive_write_close(). */ -__LA_DECL int archive_write_free(struct archive *); -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Synonym for archive_write_free() for backwards compatibility. */ -__LA_DECL int archive_write_finish(struct archive *) __LA_DEPRECATED; -#endif - -/* - * Set write options. - */ -/* Apply option to the format only. */ -__LA_DECL int archive_write_set_format_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option to the filter only. */ -__LA_DECL int archive_write_set_filter_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option to both the format and the filter. */ -__LA_DECL int archive_write_set_option(struct archive *_a, - const char *m, const char *o, - const char *v); -/* Apply option string to both the format and the filter. */ -__LA_DECL int archive_write_set_options(struct archive *_a, - const char *opts); - -/* - * Set a encryption passphrase. - */ -__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p); -__LA_DECL int archive_write_set_passphrase_callback(struct archive *, - void *client_data, archive_passphrase_callback *); - -/*- - * ARCHIVE_WRITE_DISK API - * - * To create objects on disk: - * 1) Ask archive_write_disk_new for a new archive_write_disk object. - * 2) Set any global properties. In particular, you probably - * want to set the options. - * 3) For each entry: - * - construct an appropriate struct archive_entry structure - * - archive_write_header to create the file/dir/etc on disk - * - archive_write_data to write the entry data - * 4) archive_write_free to cleanup the writer and release resources - * - * In particular, you can use this in conjunction with archive_read() - * to pull entries out of an archive and create them on disk. - */ -__LA_DECL struct archive *archive_write_disk_new(void); -/* This file will not be overwritten. */ -__LA_DECL int archive_write_disk_set_skip_file(struct archive *, - la_int64_t, la_int64_t); -/* Set flags to control how the next item gets created. - * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */ -__LA_DECL int archive_write_disk_set_options(struct archive *, - int flags); -/* - * The lookup functions are given uname/uid (or gname/gid) pairs and - * return a uid (gid) suitable for this system. These are used for - * restoring ownership and for setting ACLs. The default functions - * are naive, they just return the uid/gid. These are small, so reasonable - * for applications that don't need to preserve ownership; they - * are probably also appropriate for applications that are doing - * same-system backup and restore. - */ -/* - * The "standard" lookup functions use common system calls to lookup - * the uname/gname, falling back to the uid/gid if the names can't be - * found. They cache lookups and are reasonably fast, but can be very - * large, so they are not used unless you ask for them. In - * particular, these match the specifications of POSIX "pax" and old - * POSIX "tar". - */ -__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *); -/* - * If neither the default (naive) nor the standard (big) functions suit - * your needs, you can write your own and register them. Be sure to - * include a cleanup function if you have allocated private data. - */ -__LA_DECL int archive_write_disk_set_group_lookup(struct archive *, - void * /* private_data */, - la_int64_t (*)(void *, const char *, la_int64_t), - void (* /* cleanup */)(void *)); -__LA_DECL int archive_write_disk_set_user_lookup(struct archive *, - void * /* private_data */, - la_int64_t (*)(void *, const char *, la_int64_t), - void (* /* cleanup */)(void *)); -__LA_DECL la_int64_t archive_write_disk_gid(struct archive *, const char *, la_int64_t); -__LA_DECL la_int64_t archive_write_disk_uid(struct archive *, const char *, la_int64_t); - -/* - * ARCHIVE_READ_DISK API - * - * This is still evolving and somewhat experimental. - */ -__LA_DECL struct archive *archive_read_disk_new(void); -/* The names for symlink modes here correspond to an old BSD - * command-line argument convention: -L, -P, -H */ -/* Follow all symlinks. */ -__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *); -/* Follow no symlinks. */ -__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *); -/* Follow symlink initially, then not. */ -__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *); -/* TODO: Handle Linux stat32/stat64 ugliness. */ -__LA_DECL int archive_read_disk_entry_from_file(struct archive *, - struct archive_entry *, int /* fd */, const struct stat *); -/* Look up gname for gid or uname for uid. */ -/* Default implementations are very, very stupid. */ -__LA_DECL const char *archive_read_disk_gname(struct archive *, la_int64_t); -__LA_DECL const char *archive_read_disk_uname(struct archive *, la_int64_t); -/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the - * results for performance. */ -__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *); -/* You can install your own lookups if you like. */ -__LA_DECL int archive_read_disk_set_gname_lookup(struct archive *, - void * /* private_data */, - const char *(* /* lookup_fn */)(void *, la_int64_t), - void (* /* cleanup_fn */)(void *)); -__LA_DECL int archive_read_disk_set_uname_lookup(struct archive *, - void * /* private_data */, - const char *(* /* lookup_fn */)(void *, la_int64_t), - void (* /* cleanup_fn */)(void *)); -/* Start traversal. */ -__LA_DECL int archive_read_disk_open(struct archive *, const char *); -__LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *); -/* - * Request that current entry be visited. If you invoke it on every - * directory, you'll get a physical traversal. This is ignored if the - * current entry isn't a directory or a link to a directory. So, if - * you invoke this on every returned path, you'll get a full logical - * traversal. - */ -__LA_DECL int archive_read_disk_descend(struct archive *); -__LA_DECL int archive_read_disk_can_descend(struct archive *); -__LA_DECL int archive_read_disk_current_filesystem(struct archive *); -__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *); -__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *); -/* Request that the access time of the entry visited by traversal be restored. */ -__LA_DECL int archive_read_disk_set_atime_restored(struct archive *); -/* - * Set behavior. The "flags" argument selects optional behavior. - */ -/* Request that the access time of the entry visited by traversal be restored. - * This is the same as archive_read_disk_set_atime_restored. */ -#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001) -/* Default: Do not skip an entry which has nodump flags. */ -#define ARCHIVE_READDISK_HONOR_NODUMP (0x0002) -/* Default: Skip a mac resource fork file whose prefix is "._" because of - * using copyfile. */ -#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004) -/* Default: Traverse mount points. */ -#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008) -/* Default: Xattrs are read from disk. */ -#define ARCHIVE_READDISK_NO_XATTR (0x0010) -/* Default: ACLs are read from disk. */ -#define ARCHIVE_READDISK_NO_ACL (0x0020) -/* Default: File flags are read from disk. */ -#define ARCHIVE_READDISK_NO_FFLAGS (0x0040) - -__LA_DECL int archive_read_disk_set_behavior(struct archive *, - int flags); - -/* - * Set archive_match object that will be used in archive_read_disk to - * know whether an entry should be skipped. The callback function - * _excluded_func will be invoked when an entry is skipped by the result - * of archive_match. - */ -__LA_DECL int archive_read_disk_set_matching(struct archive *, - struct archive *_matching, void (*_excluded_func) - (struct archive *, void *, struct archive_entry *), - void *_client_data); -__LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *, - int (*_metadata_filter_func)(struct archive *, void *, - struct archive_entry *), void *_client_data); - -/* Simplified cleanup interface; - * This calls archive_read_free() or archive_write_free() as needed. */ -__LA_DECL int archive_free(struct archive *); - -/* - * Accessor functions to read/set various information in - * the struct archive object: - */ - -/* Number of filters in the current filter pipeline. */ -/* Filter #0 is the one closest to the format, -1 is a synonym for the - * last filter, which is always the pseudo-filter that wraps the - * client callbacks. */ -__LA_DECL int archive_filter_count(struct archive *); -__LA_DECL la_int64_t archive_filter_bytes(struct archive *, int); -__LA_DECL int archive_filter_code(struct archive *, int); -__LA_DECL const char * archive_filter_name(struct archive *, int); - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* These don't properly handle multiple filters, so are deprecated and - * will eventually be removed. */ -/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */ -__LA_DECL la_int64_t archive_position_compressed(struct archive *) - __LA_DEPRECATED; -/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */ -__LA_DECL la_int64_t archive_position_uncompressed(struct archive *) - __LA_DEPRECATED; -/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */ -__LA_DECL const char *archive_compression_name(struct archive *) - __LA_DEPRECATED; -/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */ -__LA_DECL int archive_compression(struct archive *) - __LA_DEPRECATED; -#endif - -__LA_DECL int archive_errno(struct archive *); -__LA_DECL const char *archive_error_string(struct archive *); -__LA_DECL const char *archive_format_name(struct archive *); -__LA_DECL int archive_format(struct archive *); -__LA_DECL void archive_clear_error(struct archive *); -__LA_DECL void archive_set_error(struct archive *, int _err, - const char *fmt, ...) __LA_PRINTF(3, 4); -__LA_DECL void archive_copy_error(struct archive *dest, - struct archive *src); -__LA_DECL int archive_file_count(struct archive *); - -/* - * ARCHIVE_MATCH API - */ -__LA_DECL struct archive *archive_match_new(void); -__LA_DECL int archive_match_free(struct archive *); - -/* - * Test if archive_entry is excluded. - * This is a convenience function. This is the same as calling all - * archive_match_path_excluded, archive_match_time_excluded - * and archive_match_owner_excluded. - */ -__LA_DECL int archive_match_excluded(struct archive *, - struct archive_entry *); - -/* - * Test if pathname is excluded. The conditions are set by following functions. - */ -__LA_DECL int archive_match_path_excluded(struct archive *, - struct archive_entry *); -/* Add exclusion pathname pattern. */ -__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *); -__LA_DECL int archive_match_exclude_pattern_w(struct archive *, - const wchar_t *); -/* Add exclusion pathname pattern from file. */ -__LA_DECL int archive_match_exclude_pattern_from_file(struct archive *, - const char *, int _nullSeparator); -__LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *, - const wchar_t *, int _nullSeparator); -/* Add inclusion pathname pattern. */ -__LA_DECL int archive_match_include_pattern(struct archive *, const char *); -__LA_DECL int archive_match_include_pattern_w(struct archive *, - const wchar_t *); -/* Add inclusion pathname pattern from file. */ -__LA_DECL int archive_match_include_pattern_from_file(struct archive *, - const char *, int _nullSeparator); -__LA_DECL int archive_match_include_pattern_from_file_w(struct archive *, - const wchar_t *, int _nullSeparator); -/* - * How to get statistic information for inclusion patterns. - */ -/* Return the amount number of unmatched inclusion patterns. */ -__LA_DECL int archive_match_path_unmatched_inclusions(struct archive *); -/* Return the pattern of unmatched inclusion with ARCHIVE_OK. - * Return ARCHIVE_EOF if there is no inclusion pattern. */ -__LA_DECL int archive_match_path_unmatched_inclusions_next( - struct archive *, const char **); -__LA_DECL int archive_match_path_unmatched_inclusions_next_w( - struct archive *, const wchar_t **); - -/* - * Test if a file is excluded by its time stamp. - * The conditions are set by following functions. - */ -__LA_DECL int archive_match_time_excluded(struct archive *, - struct archive_entry *); - -/* - * Flags to tell a matching type of time stamps. These are used for - * following functions. - */ -/* Time flag: mtime to be tested. */ -#define ARCHIVE_MATCH_MTIME (0x0100) -/* Time flag: ctime to be tested. */ -#define ARCHIVE_MATCH_CTIME (0x0200) -/* Comparison flag: Match the time if it is newer than. */ -#define ARCHIVE_MATCH_NEWER (0x0001) -/* Comparison flag: Match the time if it is older than. */ -#define ARCHIVE_MATCH_OLDER (0x0002) -/* Comparison flag: Match the time if it is equal to. */ -#define ARCHIVE_MATCH_EQUAL (0x0010) -/* Set inclusion time. */ -__LA_DECL int archive_match_include_time(struct archive *, int _flag, - time_t _sec, long _nsec); -/* Set inclusion time by a date string. */ -__LA_DECL int archive_match_include_date(struct archive *, int _flag, - const char *_datestr); -__LA_DECL int archive_match_include_date_w(struct archive *, int _flag, - const wchar_t *_datestr); -/* Set inclusion time by a particular file. */ -__LA_DECL int archive_match_include_file_time(struct archive *, - int _flag, const char *_pathname); -__LA_DECL int archive_match_include_file_time_w(struct archive *, - int _flag, const wchar_t *_pathname); -/* Add exclusion entry. */ -__LA_DECL int archive_match_exclude_entry(struct archive *, - int _flag, struct archive_entry *); - -/* - * Test if a file is excluded by its uid ,gid, uname or gname. - * The conditions are set by following functions. - */ -__LA_DECL int archive_match_owner_excluded(struct archive *, - struct archive_entry *); -/* Add inclusion uid, gid, uname and gname. */ -__LA_DECL int archive_match_include_uid(struct archive *, la_int64_t); -__LA_DECL int archive_match_include_gid(struct archive *, la_int64_t); -__LA_DECL int archive_match_include_uname(struct archive *, const char *); -__LA_DECL int archive_match_include_uname_w(struct archive *, - const wchar_t *); -__LA_DECL int archive_match_include_gname(struct archive *, const char *); -__LA_DECL int archive_match_include_gname_w(struct archive *, - const wchar_t *); - -/* Utility functions */ -/* Convenience function to sort a NULL terminated list of strings */ -__LA_DECL int archive_utility_string_sort(char **); - -#ifdef __cplusplus -} -#endif - -/* These are meaningless outside of this header. */ -#undef __LA_DECL - -#endif /* !ARCHIVE_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_acl.c b/3rdparty/libarchive/libarchive/archive_acl.c deleted file mode 100644 index b8b6b636..00000000 --- a/3rdparty/libarchive/libarchive/archive_acl.c +++ /dev/null @@ -1,2069 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * Copyright (c) 2016 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif - -#include "archive_acl_private.h" -#include "archive_entry.h" -#include "archive_private.h" - -#undef max -#define max(a, b) ((a)>(b)?(a):(b)) - -#ifndef HAVE_WMEMCMP -/* Good enough for simple equality testing, but not for sorting. */ -#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) -#endif - -static int acl_special(struct archive_acl *acl, - int type, int permset, int tag); -static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, - int type, int permset, int tag, int id); -static int archive_acl_add_entry_len_l(struct archive_acl *acl, - int type, int permset, int tag, int id, const char *name, - size_t len, struct archive_string_conv *sc); -static int archive_acl_text_want_type(struct archive_acl *acl, int flags); -static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type, - int flags, int wide, struct archive *a, - struct archive_string_conv *sc); -static int isint_w(const wchar_t *start, const wchar_t *end, int *result); -static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); -static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, - int *result); -static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, - int *result); -static void next_field_w(const wchar_t **wp, const wchar_t **start, - const wchar_t **end, wchar_t *sep); -static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, - int tag, int flags, const wchar_t *wname, int perm, int id); -static void append_id_w(wchar_t **wp, int id); -static int isint(const char *start, const char *end, int *result); -static int ismode(const char *start, const char *end, int *result); -static int is_nfs4_flags(const char *start, const char *end, - int *result); -static int is_nfs4_perms(const char *start, const char *end, - int *result); -static void next_field(const char **p, const char **start, - const char **end, char *sep); -static void append_entry(char **p, const char *prefix, int type, - int tag, int flags, const char *name, int perm, int id); -static void append_id(char **p, int id); - -static const struct { - const int perm; - const char c; - const wchar_t wc; -} nfsv4_acl_perm_map[] = { - { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', - L'r' }, - { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', - L'w' }, - { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, - { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, - 'p', L'p' }, - { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, - { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, - { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, - { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, - { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, - { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, - { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, - { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, - { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, - { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } -}; - -static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / - sizeof(nfsv4_acl_perm_map[0])); - -static const struct { - const int perm; - const char c; - const wchar_t wc; -} nfsv4_acl_flag_map[] = { - { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, - { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, - { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, - { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, - { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, - { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, - { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } -}; - -static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / - sizeof(nfsv4_acl_flag_map[0])); - -void -archive_acl_clear(struct archive_acl *acl) -{ - struct archive_acl_entry *ap; - - while (acl->acl_head != NULL) { - ap = acl->acl_head->next; - archive_mstring_clean(&acl->acl_head->name); - free(acl->acl_head); - acl->acl_head = ap; - } - if (acl->acl_text_w != NULL) { - free(acl->acl_text_w); - acl->acl_text_w = NULL; - } - if (acl->acl_text != NULL) { - free(acl->acl_text); - acl->acl_text = NULL; - } - acl->acl_p = NULL; - acl->acl_types = 0; - acl->acl_state = 0; /* Not counting. */ -} - -void -archive_acl_copy(struct archive_acl *dest, struct archive_acl *src) -{ - struct archive_acl_entry *ap, *ap2; - - archive_acl_clear(dest); - - dest->mode = src->mode; - ap = src->acl_head; - while (ap != NULL) { - ap2 = acl_new_entry(dest, - ap->type, ap->permset, ap->tag, ap->id); - if (ap2 != NULL) - archive_mstring_copy(&ap2->name, &ap->name); - ap = ap->next; - } -} - -int -archive_acl_add_entry(struct archive_acl *acl, - int type, int permset, int tag, int id, const char *name) -{ - struct archive_acl_entry *ap; - - if (acl_special(acl, type, permset, tag) == 0) - return ARCHIVE_OK; - ap = acl_new_entry(acl, type, permset, tag, id); - if (ap == NULL) { - /* XXX Error XXX */ - return ARCHIVE_FAILED; - } - if (name != NULL && *name != '\0') - archive_mstring_copy_mbs(&ap->name, name); - else - archive_mstring_clean(&ap->name); - return ARCHIVE_OK; -} - -int -archive_acl_add_entry_w_len(struct archive_acl *acl, - int type, int permset, int tag, int id, const wchar_t *name, size_t len) -{ - struct archive_acl_entry *ap; - - if (acl_special(acl, type, permset, tag) == 0) - return ARCHIVE_OK; - ap = acl_new_entry(acl, type, permset, tag, id); - if (ap == NULL) { - /* XXX Error XXX */ - return ARCHIVE_FAILED; - } - if (name != NULL && *name != L'\0' && len > 0) - archive_mstring_copy_wcs_len(&ap->name, name, len); - else - archive_mstring_clean(&ap->name); - return ARCHIVE_OK; -} - -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) -{ - struct archive_acl_entry *ap; - int r; - - if (acl_special(acl, type, permset, tag) == 0) - return ARCHIVE_OK; - ap = acl_new_entry(acl, type, permset, tag, id); - if (ap == NULL) { - /* XXX Error XXX */ - return ARCHIVE_FAILED; - } - if (name != NULL && *name != '\0' && len > 0) { - r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); - } else { - r = 0; - archive_mstring_clean(&ap->name); - } - if (r == 0) - return (ARCHIVE_OK); - else if (errno == ENOMEM) - return (ARCHIVE_FATAL); - else - return (ARCHIVE_WARN); -} - -/* - * If this ACL entry is part of the standard POSIX permissions set, - * store the permissions in the stat structure and return zero. - */ -static int -acl_special(struct archive_acl *acl, int type, int permset, int tag) -{ - if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS - && ((permset & ~007) == 0)) { - switch (tag) { - case ARCHIVE_ENTRY_ACL_USER_OBJ: - acl->mode &= ~0700; - acl->mode |= (permset & 7) << 6; - return (0); - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - acl->mode &= ~0070; - acl->mode |= (permset & 7) << 3; - return (0); - case ARCHIVE_ENTRY_ACL_OTHER: - acl->mode &= ~0007; - acl->mode |= permset & 7; - return (0); - } - } - return (1); -} - -/* - * Allocate and populate a new ACL entry with everything but the - * name. - */ -static struct archive_acl_entry * -acl_new_entry(struct archive_acl *acl, - int type, int permset, int tag, int id) -{ - struct archive_acl_entry *ap, *aq; - - /* Type argument must be a valid NFS4 or POSIX.1e type. - * The type must agree with anything already set and - * the permset must be compatible. */ - if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - return (NULL); - } - if (permset & - ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 - | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { - return (NULL); - } - } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { - if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { - return (NULL); - } - if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { - return (NULL); - } - } else { - return (NULL); - } - - /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ - switch (tag) { - case ARCHIVE_ENTRY_ACL_USER: - case ARCHIVE_ENTRY_ACL_USER_OBJ: - case ARCHIVE_ENTRY_ACL_GROUP: - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - /* Tags valid in both NFS4 and POSIX.1e */ - break; - case ARCHIVE_ENTRY_ACL_MASK: - case ARCHIVE_ENTRY_ACL_OTHER: - /* Tags valid only in POSIX.1e. */ - if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { - return (NULL); - } - break; - case ARCHIVE_ENTRY_ACL_EVERYONE: - /* Tags valid only in NFS4. */ - if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - return (NULL); - } - break; - default: - /* No other values are valid. */ - return (NULL); - } - - if (acl->acl_text_w != NULL) { - free(acl->acl_text_w); - acl->acl_text_w = NULL; - } - if (acl->acl_text != NULL) { - free(acl->acl_text); - acl->acl_text = NULL; - } - - /* - * If there's a matching entry already in the list, overwrite it. - * NFSv4 entries may be repeated and are not overwritten. - * - * TODO: compare names of no id is provided (needs more rework) - */ - ap = acl->acl_head; - aq = NULL; - while (ap != NULL) { - if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && - ap->type == type && ap->tag == tag && ap->id == id) { - if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && - tag != ARCHIVE_ENTRY_ACL_GROUP)) { - ap->permset = permset; - return (ap); - } - } - aq = ap; - ap = ap->next; - } - - /* Add a new entry to the end of the list. */ - ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); - if (ap == NULL) - return (NULL); - if (aq == NULL) - acl->acl_head = ap; - else - aq->next = ap; - ap->type = type; - ap->tag = tag; - ap->id = id; - ap->permset = permset; - acl->acl_types |= type; - return (ap); -} - -/* - * Return a count of entries matching "want_type". - */ -int -archive_acl_count(struct archive_acl *acl, int want_type) -{ - int count; - struct archive_acl_entry *ap; - - count = 0; - ap = acl->acl_head; - while (ap != NULL) { - if ((ap->type & want_type) != 0) - count++; - ap = ap->next; - } - - if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) - count += 3; - return (count); -} - -/* - * Return a bitmask of stored ACL types in an ACL list - */ -int -archive_acl_types(struct archive_acl *acl) -{ - return (acl->acl_types); -} - -/* - * Prepare for reading entries from the ACL data. Returns a count - * of entries matching "want_type", or zero if there are no - * non-extended ACL entries of that type. - */ -int -archive_acl_reset(struct archive_acl *acl, int want_type) -{ - int count, cutoff; - - count = archive_acl_count(acl, want_type); - - /* - * If the only entries are the three standard ones, - * then don't return any ACL data. (In this case, - * client can just use chmod(2) to set permissions.) - */ - if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) - cutoff = 3; - else - cutoff = 0; - - if (count > cutoff) - acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; - else - acl->acl_state = 0; - acl->acl_p = acl->acl_head; - return (count); -} - - -/* - * Return the next ACL entry in the list. Fake entries for the - * standard permissions and include them in the returned list. - */ -int -archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, - int *type, int *permset, int *tag, int *id, const char **name) -{ - *name = NULL; - *id = -1; - - /* - * The acl_state is either zero (no entries available), -1 - * (reading from list), or an entry type (retrieve that type - * from ae_stat.aest_mode). - */ - if (acl->acl_state == 0) - return (ARCHIVE_WARN); - - /* The first three access entries are special. */ - if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - switch (acl->acl_state) { - case ARCHIVE_ENTRY_ACL_USER_OBJ: - *permset = (acl->mode >> 6) & 7; - *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - return (ARCHIVE_OK); - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - *permset = (acl->mode >> 3) & 7; - *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; - return (ARCHIVE_OK); - case ARCHIVE_ENTRY_ACL_OTHER: - *permset = acl->mode & 7; - *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - *tag = ARCHIVE_ENTRY_ACL_OTHER; - acl->acl_state = -1; - acl->acl_p = acl->acl_head; - return (ARCHIVE_OK); - default: - break; - } - } - - while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) - acl->acl_p = acl->acl_p->next; - if (acl->acl_p == NULL) { - acl->acl_state = 0; - *type = 0; - *permset = 0; - *tag = 0; - *id = -1; - *name = NULL; - return (ARCHIVE_EOF); /* End of ACL entries. */ - } - *type = acl->acl_p->type; - *permset = acl->acl_p->permset; - *tag = acl->acl_p->tag; - *id = acl->acl_p->id; - if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { - if (errno == ENOMEM) - return (ARCHIVE_FATAL); - *name = NULL; - } - acl->acl_p = acl->acl_p->next; - return (ARCHIVE_OK); -} - -/* - * Determine what type of ACL do we want - */ -static int -archive_acl_text_want_type(struct archive_acl *acl, int flags) -{ - int want_type; - - /* Check if ACL is NFSv4 */ - if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - /* NFSv4 should never mix with POSIX.1e */ - if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) - return (0); - else - return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); - } - - /* Now deal with POSIX.1e ACLs */ - - want_type = 0; - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) - want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) - want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; - - /* By default we want both access and default ACLs */ - if (want_type == 0) - return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); - - return (want_type); -} - -/* - * Calculate ACL text string length - */ -static ssize_t -archive_acl_text_len(struct archive_acl *acl, int want_type, int flags, - int wide, struct archive *a, struct archive_string_conv *sc) { - struct archive_acl_entry *ap; - const char *name; - const wchar_t *wname; - int count, idlen, tmp, r; - ssize_t length; - size_t len; - - count = 0; - length = 0; - for (ap = acl->acl_head; ap != NULL; ap = ap->next) { - if ((ap->type & want_type) == 0) - continue; - /* - * Filemode-mapping ACL entries are stored exclusively in - * ap->mode so they should not be in the list - */ - if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) - && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) - continue; - count++; - if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 - && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) - length += 8; /* "default:" */ - switch (ap->tag) { - case ARCHIVE_ENTRY_ACL_USER_OBJ: - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - length += 6; /* "owner@" */ - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_USER: - case ARCHIVE_ENTRY_ACL_MASK: - length += 4; /* "user", "mask" */ - break; - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - length += 6; /* "group@" */ - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_GROUP: - case ARCHIVE_ENTRY_ACL_OTHER: - length += 5; /* "group", "other" */ - break; - case ARCHIVE_ENTRY_ACL_EVERYONE: - length += 9; /* "everyone@" */ - break; - } - length += 1; /* colon after tag */ - if (ap->tag == ARCHIVE_ENTRY_ACL_USER || - ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { - if (wide) { - r = archive_mstring_get_wcs(a, &ap->name, - &wname); - if (r == 0 && wname != NULL) - length += wcslen(wname); - else if (r < 0 && errno == ENOMEM) - return (0); - else - length += sizeof(uid_t) * 3 + 1; - } else { - r = archive_mstring_get_mbs_l(&ap->name, &name, - &len, sc); - if (r != 0) - return (0); - if (len > 0 && name != NULL) - length += len; - else - length += sizeof(uid_t) * 3 + 1; - } - length += 1; /* colon after user or group name */ - } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) - length += 1; /* 2nd colon empty user,group or other */ - - if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) - && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) - && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER - || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { - /* Solaris has no colon after other: and mask: */ - length = length - 1; - } - - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - /* rwxpdDaARWcCos:fdinSFI:deny */ - length += 27; - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) - length += 1; /* allow, alarm, audit */ - } else - length += 3; /* rwx */ - - if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || - ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && - (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { - length += 1; /* colon */ - /* 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); -} - -/* - * Generate a wide text version of the ACL. The flags parameter controls - * the type and style of the generated ACL. - */ -wchar_t * -archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, - struct archive *a) -{ - int count; - ssize_t length; - size_t len; - const wchar_t *wname; - const wchar_t *prefix; - wchar_t separator; - struct archive_acl_entry *ap; - int id, r, want_type; - wchar_t *wp, *ws; - - want_type = archive_acl_text_want_type(acl, flags); - - /* Both NFSv4 and POSIX.1 types found */ - if (want_type == 0) - return (NULL); - - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) - flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; - - length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); - - if (length == 0) - return (NULL); - - if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) - separator = L','; - else - separator = L'\n'; - - /* Now, allocate the string and actually populate it. */ - wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); - if (wp == NULL) { - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); - } - count = 0; - - if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, - acl->mode & 0700, -1); - *wp++ = separator; - append_entry_w(&wp, 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_ENTRY_ACL_OTHER, flags, NULL, - acl->mode & 0007, -1); - count += 3; - } - - for (ap = acl->acl_head; ap != NULL; ap = ap->next) { - if ((ap->type & want_type) == 0) - continue; - /* - * Filemode-mapping ACL entries are stored exclusively in - * ap->mode so they should not be in the list - */ - if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) - && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) - continue; - if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && - (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) - prefix = L"default:"; - else - prefix = NULL; - r = archive_mstring_get_wcs(a, &ap->name, &wname); - if (r == 0) { - if (count > 0) - *wp++ = separator; - if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) - id = ap->id; - else - id = -1; - append_entry_w(&wp, prefix, ap->type, ap->tag, flags, - wname, ap->permset, id); - count++; - } else if (r < 0 && errno == ENOMEM) - return (NULL); - } - - /* Add terminating character */ - *wp++ = L'\0'; - - len = wcslen(ws); - - if ((ssize_t)len > (length - 1)) - __archive_errx(1, "Buffer overrun"); - - if (text_len != NULL) - *text_len = len; - - return (ws); -} - -static void -append_id_w(wchar_t **wp, int id) -{ - if (id < 0) - id = 0; - if (id > 9) - append_id_w(wp, id / 10); - *(*wp)++ = L"0123456789"[id % 10]; -} - -static void -append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, - int tag, int flags, const wchar_t *wname, int perm, int id) -{ - int i; - - if (prefix != NULL) { - wcscpy(*wp, prefix); - *wp += wcslen(*wp); - } - switch (tag) { - case ARCHIVE_ENTRY_ACL_USER_OBJ: - wname = NULL; - id = -1; - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - wcscpy(*wp, L"owner@"); - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_USER: - wcscpy(*wp, L"user"); - break; - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - wname = NULL; - id = -1; - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - wcscpy(*wp, L"group@"); - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_GROUP: - wcscpy(*wp, L"group"); - break; - case ARCHIVE_ENTRY_ACL_MASK: - wcscpy(*wp, L"mask"); - wname = NULL; - id = -1; - break; - case ARCHIVE_ENTRY_ACL_OTHER: - wcscpy(*wp, L"other"); - wname = NULL; - id = -1; - break; - case ARCHIVE_ENTRY_ACL_EVERYONE: - wcscpy(*wp, L"everyone@"); - wname = NULL; - id = -1; - break; - } - *wp += wcslen(*wp); - *(*wp)++ = 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); - } else if (tag == ARCHIVE_ENTRY_ACL_USER - || tag == ARCHIVE_ENTRY_ACL_GROUP) { - append_id_w(wp, id); - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) - id = -1; - } - /* Solaris style has no second colon after other and mask */ - if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) - || (tag != ARCHIVE_ENTRY_ACL_OTHER - && tag != ARCHIVE_ENTRY_ACL_MASK)) - *(*wp)++ = L':'; - } - if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { - /* POSIX.1e ACL perms */ - *(*wp)++ = (perm & 0444) ? L'r' : L'-'; - *(*wp)++ = (perm & 0222) ? L'w' : L'-'; - *(*wp)++ = (perm & 0111) ? L'x' : L'-'; - } else { - /* NFSv4 ACL perms */ - for (i = 0; i < nfsv4_acl_perm_map_size; i++) { - if (perm & nfsv4_acl_perm_map[i].perm) - *(*wp)++ = nfsv4_acl_perm_map[i].wc; - else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) - *(*wp)++ = L'-'; - } - *(*wp)++ = L':'; - for (i = 0; i < nfsv4_acl_flag_map_size; i++) { - if (perm & nfsv4_acl_flag_map[i].perm) - *(*wp)++ = nfsv4_acl_flag_map[i].wc; - else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) - *(*wp)++ = L'-'; - } - *(*wp)++ = L':'; - switch (type) { - case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - wcscpy(*wp, L"allow"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_DENY: - wcscpy(*wp, L"deny"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: - wcscpy(*wp, L"audit"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_ALARM: - wcscpy(*wp, L"alarm"); - break; - default: - break; - } - *wp += wcslen(*wp); - } - if (id != -1) { - *(*wp)++ = L':'; - append_id_w(wp, id); - } -} - -/* - * Generate a text version of the ACL. The flags parameter controls - * the type and style of the generated ACL. - */ -char * -archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, - struct archive_string_conv *sc) -{ - int count; - ssize_t length; - size_t len; - const char *name; - const char *prefix; - char separator; - struct archive_acl_entry *ap; - int id, r, want_type; - char *p, *s; - - want_type = archive_acl_text_want_type(acl, flags); - - /* Both NFSv4 and POSIX.1 types found */ - if (want_type == 0) - return (NULL); - - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) - flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; - - length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); - - if (length == 0) - return (NULL); - - if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) - separator = ','; - else - separator = '\n'; - - /* Now, allocate the string and actually populate it. */ - p = s = (char *)malloc(length * sizeof(char)); - if (p == NULL) { - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); - } - count = 0; - - if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, - acl->mode & 0700, -1); - *p++ = separator; - append_entry(&p, 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_ENTRY_ACL_OTHER, flags, NULL, - acl->mode & 0007, -1); - count += 3; - } - - for (ap = acl->acl_head; ap != NULL; ap = ap->next) { - if ((ap->type & want_type) == 0) - continue; - /* - * Filemode-mapping ACL entries are stored exclusively in - * ap->mode so they should not be in the list - */ - if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) - && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ - || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) - continue; - if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && - (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) - prefix = "default:"; - else - prefix = NULL; - r = archive_mstring_get_mbs_l( - &ap->name, &name, &len, sc); - if (r != 0) - return (NULL); - if (count > 0) - *p++ = separator; - if (name == NULL || - (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { - id = ap->id; - } else { - id = -1; - } - append_entry(&p, prefix, ap->type, ap->tag, flags, name, - ap->permset, id); - count++; - } - - /* Add terminating character */ - *p++ = '\0'; - - len = strlen(s); - - if ((ssize_t)len > (length - 1)) - __archive_errx(1, "Buffer overrun"); - - if (text_len != NULL) - *text_len = len; - - return (s); -} - -static void -append_id(char **p, int id) -{ - if (id < 0) - id = 0; - if (id > 9) - append_id(p, id / 10); - *(*p)++ = "0123456789"[id % 10]; -} - -static void -append_entry(char **p, const char *prefix, int type, - int tag, int flags, const char *name, int perm, int id) -{ - int i; - - if (prefix != NULL) { - strcpy(*p, prefix); - *p += strlen(*p); - } - switch (tag) { - case ARCHIVE_ENTRY_ACL_USER_OBJ: - name = NULL; - id = -1; - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - strcpy(*p, "owner@"); - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_USER: - strcpy(*p, "user"); - break; - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - name = NULL; - id = -1; - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - strcpy(*p, "group@"); - break; - } - /* FALLTHROUGH */ - case ARCHIVE_ENTRY_ACL_GROUP: - strcpy(*p, "group"); - break; - case ARCHIVE_ENTRY_ACL_MASK: - strcpy(*p, "mask"); - name = NULL; - id = -1; - break; - case ARCHIVE_ENTRY_ACL_OTHER: - strcpy(*p, "other"); - name = NULL; - id = -1; - break; - case ARCHIVE_ENTRY_ACL_EVERYONE: - strcpy(*p, "everyone@"); - name = NULL; - id = -1; - break; - } - *p += strlen(*p); - *(*p)++ = ':'; - if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || - tag == ARCHIVE_ENTRY_ACL_USER || - tag == ARCHIVE_ENTRY_ACL_GROUP) { - if (name != NULL) { - strcpy(*p, name); - *p += strlen(*p); - } else if (tag == ARCHIVE_ENTRY_ACL_USER - || tag == ARCHIVE_ENTRY_ACL_GROUP) { - append_id(p, id); - if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) - id = -1; - } - /* Solaris style has no second colon after other and mask */ - if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) - || (tag != ARCHIVE_ENTRY_ACL_OTHER - && tag != ARCHIVE_ENTRY_ACL_MASK)) - *(*p)++ = ':'; - } - if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { - /* POSIX.1e ACL perms */ - *(*p)++ = (perm & 0444) ? 'r' : '-'; - *(*p)++ = (perm & 0222) ? 'w' : '-'; - *(*p)++ = (perm & 0111) ? 'x' : '-'; - } else { - /* NFSv4 ACL perms */ - for (i = 0; i < nfsv4_acl_perm_map_size; i++) { - if (perm & nfsv4_acl_perm_map[i].perm) - *(*p)++ = nfsv4_acl_perm_map[i].c; - else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) - *(*p)++ = '-'; - } - *(*p)++ = ':'; - for (i = 0; i < nfsv4_acl_flag_map_size; i++) { - if (perm & nfsv4_acl_flag_map[i].perm) - *(*p)++ = nfsv4_acl_flag_map[i].c; - else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) - *(*p)++ = '-'; - } - *(*p)++ = ':'; - switch (type) { - case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - strcpy(*p, "allow"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_DENY: - strcpy(*p, "deny"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: - strcpy(*p, "audit"); - break; - case ARCHIVE_ENTRY_ACL_TYPE_ALARM: - strcpy(*p, "alarm"); - break; - } - *p += strlen(*p); - } - if (id != -1) { - *(*p)++ = ':'; - append_id(p, id); - } -} - -/* - * Parse a wide ACL text string. - * - * The want_type argument may be one of the following: - * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS - * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT - * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL - * - * POSIX.1e ACL entries prefixed with "default:" are treated as - * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 - */ -int -archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, - int want_type) -{ - struct { - const wchar_t *start; - const wchar_t *end; - } field[6], name; - - const wchar_t *s, *st; - - int numfields, fields, n, r, sol, ret; - int type, types, tag, permset, id; - size_t len; - wchar_t sep; - - ret = ARCHIVE_OK; - types = 0; - - switch (want_type) { - case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: - want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - numfields = 5; - break; - case ARCHIVE_ENTRY_ACL_TYPE_NFS4: - numfields = 6; - break; - default: - return (ARCHIVE_FATAL); - } - - while (text != NULL && *text != L'\0') { - /* - * Parse the fields out of the next entry, - * advance 'text' to start of next entry. - */ - fields = 0; - do { - const wchar_t *start, *end; - next_field_w(&text, &start, &end, &sep); - if (fields < numfields) { - field[fields].start = start; - field[fields].end = end; - } - ++fields; - } while (sep == L':'); - - /* Set remaining fields to blank. */ - for (n = fields; n < numfields; ++n) - field[n].start = field[n].end = NULL; - - if (field[0].start != NULL && *(field[0].start) == L'#') { - /* Comment, skip entry */ - continue; - } - - n = 0; - sol = 0; - id = -1; - permset = 0; - name.start = name.end = NULL; - - if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - /* POSIX.1e ACLs */ - /* - * Default keyword "default:user::rwx" - * if found, we have one more field - * - * We also support old Solaris extension: - * "defaultuser::rwx" is the default ACL corresponding - * to "user::rwx", etc. valid only for first field - */ - s = field[0].start; - len = field[0].end - field[0].start; - if (*s == L'd' && (len == 1 || (len >= 7 - && wmemcmp((s + 1), L"efault", 6) == 0))) { - type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; - if (len > 7) - field[0].start += 7; - else - n = 1; - } else - type = want_type; - - /* Check for a numeric ID in field n+1 or n+3. */ - isint_w(field[n + 1].start, field[n + 1].end, &id); - /* Field n+3 is optional. */ - if (id == -1 && fields > n+3) - isint_w(field[n + 3].start, field[n + 3].end, - &id); - - tag = 0; - s = field[n].start; - st = field[n].start + 1; - len = field[n].end - field[n].start; - - switch (*s) { - case L'u': - if (len == 1 || (len == 4 - && wmemcmp(st, L"ser", 3) == 0)) - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - break; - case L'g': - if (len == 1 || (len == 5 - && wmemcmp(st, L"roup", 4) == 0)) - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case L'o': - if (len == 1 || (len == 5 - && wmemcmp(st, L"ther", 4) == 0)) - tag = ARCHIVE_ENTRY_ACL_OTHER; - break; - case L'm': - if (len == 1 || (len == 4 - && wmemcmp(st, L"ask", 3) == 0)) - tag = ARCHIVE_ENTRY_ACL_MASK; - break; - default: - break; - } - - switch (tag) { - case ARCHIVE_ENTRY_ACL_OTHER: - case ARCHIVE_ENTRY_ACL_MASK: - if (fields == (n + 2) - && field[n + 1].start < field[n + 1].end - && ismode_w(field[n + 1].start, - field[n + 1].end, &permset)) { - /* This is Solaris-style "other:rwx" */ - sol = 1; - } else if (fields == (n + 3) && - field[n + 1].start < field[n + 1].end) { - /* Invalid mask or other field */ - ret = ARCHIVE_WARN; - continue; - } - break; - case ARCHIVE_ENTRY_ACL_USER_OBJ: - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - if (id != -1 || - field[n + 1].start < field[n + 1].end) { - name = field[n + 1]; - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - tag = ARCHIVE_ENTRY_ACL_USER; - else - tag = ARCHIVE_ENTRY_ACL_GROUP; - } - break; - default: - /* Invalid tag, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - - /* - * Without "default:" we expect mode in field 2 - * Exception: Solaris other and mask fields - */ - if (permset == 0 && !ismode_w(field[n + 2 - sol].start, - field[n + 2 - sol].end, &permset)) { - /* Invalid mode, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - } else { - /* NFS4 ACLs */ - s = field[0].start; - len = field[0].end - field[0].start; - tag = 0; - - switch (len) { - case 4: - if (wmemcmp(s, L"user", 4) == 0) - tag = ARCHIVE_ENTRY_ACL_USER; - break; - case 5: - if (wmemcmp(s, L"group", 5) == 0) - tag = ARCHIVE_ENTRY_ACL_GROUP; - break; - case 6: - if (wmemcmp(s, L"owner@", 6) == 0) - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - else if (wmemcmp(s, L"group@", len) == 0) - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case 9: - if (wmemcmp(s, L"everyone@", 9) == 0) - tag = ARCHIVE_ENTRY_ACL_EVERYONE; - default: - break; - } - - if (tag == 0) { - /* Invalid tag, skip entry */ - ret = ARCHIVE_WARN; - continue; - } else if (tag == ARCHIVE_ENTRY_ACL_USER || - tag == ARCHIVE_ENTRY_ACL_GROUP) { - n = 1; - name = field[1]; - isint_w(name.start, name.end, &id); - } else - n = 0; - - if (!is_nfs4_perms_w(field[1 + n].start, - field[1 + n].end, &permset)) { - /* Invalid NFSv4 perms, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - if (!is_nfs4_flags_w(field[2 + n].start, - field[2 + n].end, &permset)) { - /* Invalid NFSv4 flags, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - s = field[3 + n].start; - len = field[3 + n].end - field[3 + n].start; - type = 0; - if (len == 4) { - if (wmemcmp(s, L"deny", 4) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_DENY; - } else if (len == 5) { - if (wmemcmp(s, L"allow", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; - else if (wmemcmp(s, L"audit", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; - else if (wmemcmp(s, L"alarm", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; - } - if (type == 0) { - /* Invalid entry type, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - isint_w(field[4 + n].start, field[4 + n].end, &id); - } - - /* Add entry to the internal list. */ - r = archive_acl_add_entry_w_len(acl, type, permset, - tag, id, name.start, name.end - name.start); - if (r < ARCHIVE_WARN) - return (r); - if (r != ARCHIVE_OK) - ret = ARCHIVE_WARN; - types |= type; - } - - /* Reset ACL */ - archive_acl_reset(acl, types); - - return (ret); -} - -/* - * Parse a string to a positive decimal integer. Returns true if - * the string is non-empty and consists only of decimal digits, - * false otherwise. - */ -static int -isint_w(const wchar_t *start, const wchar_t *end, int *result) -{ - int n = 0; - if (start >= end) - return (0); - while (start < end) { - if (*start < '0' || *start > '9') - return (0); - if (n > (INT_MAX / 10) || - (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { - n = INT_MAX; - } else { - n *= 10; - n += *start - '0'; - } - start++; - } - *result = n; - return (1); -} - -/* - * Parse a string as a mode field. Returns true if - * the string is non-empty and consists only of mode characters, - * false otherwise. - */ -static int -ismode_w(const wchar_t *start, const wchar_t *end, int *permset) -{ - const wchar_t *p; - - if (start >= end) - return (0); - p = start; - *permset = 0; - while (p < end) { - switch (*p++) { - case L'r': case L'R': - *permset |= ARCHIVE_ENTRY_ACL_READ; - break; - case L'w': case L'W': - *permset |= ARCHIVE_ENTRY_ACL_WRITE; - break; - case L'x': case L'X': - *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; - break; - case L'-': - break; - default: - return (0); - } - } - return (1); -} - -/* - * Parse a string as a NFS4 ACL permission field. - * Returns true if the string is non-empty and consists only of NFS4 ACL - * permission characters, false otherwise - */ -static int -is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) -{ - const wchar_t *p = start; - - while (p < end) { - switch (*p++) { - case L'r': - *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; - break; - case L'w': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; - break; - case L'x': - *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; - break; - case L'p': - *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; - break; - case L'D': - *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; - break; - case L'd': - *permset |= ARCHIVE_ENTRY_ACL_DELETE; - break; - case L'a': - *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; - break; - case L'A': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; - break; - case L'R': - *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; - break; - case L'W': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; - break; - case L'c': - *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; - break; - case L'C': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; - break; - case L'o': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; - break; - case L's': - *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; - break; - case L'-': - break; - default: - return(0); - } - } - return (1); -} - -/* - * Parse a string as a NFS4 ACL flags field. - * Returns true if the string is non-empty and consists only of NFS4 ACL - * flag characters, false otherwise - */ -static int -is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) -{ - const wchar_t *p = start; - - while (p < end) { - switch(*p++) { - case L'f': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; - break; - case L'd': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; - break; - case L'i': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; - break; - case L'n': - *permset |= - ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; - break; - case L'S': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; - break; - case L'F': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; - break; - case L'I': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; - break; - case L'-': - break; - default: - return (0); - } - } - return (1); -} - -/* - * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated - * to point to just after the separator. *start points to the first - * character of the matched text and *end just after the last - * character of the matched identifier. In particular *end - *start - * is the length of the field body, not including leading or trailing - * whitespace. - */ -static void -next_field_w(const wchar_t **wp, const wchar_t **start, - const wchar_t **end, wchar_t *sep) -{ - /* Skip leading whitespace to find start of field. */ - while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { - (*wp)++; - } - *start = *wp; - - /* Scan for the separator. */ - while (**wp != L'\0' && **wp != L',' && **wp != L':' && - **wp != L'\n') { - (*wp)++; - } - *sep = **wp; - - /* Trim trailing whitespace to locate end of field. */ - *end = *wp - 1; - while (**end == L' ' || **end == L'\t' || **end == L'\n') { - (*end)--; - } - (*end)++; - - /* Adjust scanner location. */ - if (**wp != L'\0') - (*wp)++; -} - -/* - * Parse an ACL text string. - * - * The want_type argument may be one of the following: - * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS - * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT - * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL - * - * POSIX.1e ACL entries prefixed with "default:" are treated as - * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 - */ -int -archive_acl_from_text_l(struct archive_acl *acl, const char *text, - int want_type, struct archive_string_conv *sc) -{ - struct { - const char *start; - const char *end; - } field[6], name; - - const char *s, *st; - int numfields, fields, n, r, sol, ret; - int type, types, tag, permset, id; - size_t len; - char sep; - - switch (want_type) { - case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: - want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - numfields = 5; - break; - case ARCHIVE_ENTRY_ACL_TYPE_NFS4: - numfields = 6; - break; - default: - return (ARCHIVE_FATAL); - } - - ret = ARCHIVE_OK; - types = 0; - - while (text != NULL && *text != '\0') { - /* - * Parse the fields out of the next entry, - * advance 'text' to start of next entry. - */ - fields = 0; - do { - const char *start, *end; - next_field(&text, &start, &end, &sep); - if (fields < numfields) { - field[fields].start = start; - field[fields].end = end; - } - ++fields; - } while (sep == ':'); - - /* Set remaining fields to blank. */ - for (n = fields; n < numfields; ++n) - field[n].start = field[n].end = NULL; - - if (field[0].start != NULL && *(field[0].start) == '#') { - /* Comment, skip entry */ - continue; - } - - n = 0; - sol = 0; - id = -1; - permset = 0; - name.start = name.end = NULL; - - if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - /* POSIX.1e ACLs */ - /* - * Default keyword "default:user::rwx" - * if found, we have one more field - * - * We also support old Solaris extension: - * "defaultuser::rwx" is the default ACL corresponding - * to "user::rwx", etc. valid only for first field - */ - s = field[0].start; - len = field[0].end - field[0].start; - if (*s == 'd' && (len == 1 || (len >= 7 - && memcmp((s + 1), "efault", 6) == 0))) { - type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; - if (len > 7) - field[0].start += 7; - else - n = 1; - } else - type = want_type; - - /* Check for a numeric ID in field n+1 or n+3. */ - isint(field[n + 1].start, field[n + 1].end, &id); - /* Field n+3 is optional. */ - if (id == -1 && fields > (n + 3)) - isint(field[n + 3].start, field[n + 3].end, - &id); - - tag = 0; - s = field[n].start; - st = field[n].start + 1; - len = field[n].end - field[n].start; - - switch (*s) { - case 'u': - if (len == 1 || (len == 4 - && memcmp(st, "ser", 3) == 0)) - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - break; - case 'g': - if (len == 1 || (len == 5 - && memcmp(st, "roup", 4) == 0)) - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case 'o': - if (len == 1 || (len == 5 - && memcmp(st, "ther", 4) == 0)) - tag = ARCHIVE_ENTRY_ACL_OTHER; - break; - case 'm': - if (len == 1 || (len == 4 - && memcmp(st, "ask", 3) == 0)) - tag = ARCHIVE_ENTRY_ACL_MASK; - break; - default: - break; - } - - switch (tag) { - case ARCHIVE_ENTRY_ACL_OTHER: - case ARCHIVE_ENTRY_ACL_MASK: - if (fields == (n + 2) - && field[n + 1].start < field[n + 1].end - && ismode(field[n + 1].start, - field[n + 1].end, &permset)) { - /* This is Solaris-style "other:rwx" */ - sol = 1; - } else if (fields == (n + 3) && - field[n + 1].start < field[n + 1].end) { - /* Invalid mask or other field */ - ret = ARCHIVE_WARN; - continue; - } - break; - case ARCHIVE_ENTRY_ACL_USER_OBJ: - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - if (id != -1 || - field[n + 1].start < field[n + 1].end) { - name = field[n + 1]; - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - tag = ARCHIVE_ENTRY_ACL_USER; - else - tag = ARCHIVE_ENTRY_ACL_GROUP; - } - break; - default: - /* Invalid tag, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - - /* - * Without "default:" we expect mode in field 3 - * Exception: Solaris other and mask fields - */ - if (permset == 0 && !ismode(field[n + 2 - sol].start, - field[n + 2 - sol].end, &permset)) { - /* Invalid mode, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - } else { - /* NFS4 ACLs */ - s = field[0].start; - len = field[0].end - field[0].start; - tag = 0; - - switch (len) { - case 4: - if (memcmp(s, "user", 4) == 0) - tag = ARCHIVE_ENTRY_ACL_USER; - break; - case 5: - if (memcmp(s, "group", 5) == 0) - tag = ARCHIVE_ENTRY_ACL_GROUP; - break; - case 6: - if (memcmp(s, "owner@", 6) == 0) - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - else if (memcmp(s, "group@", 6) == 0) - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case 9: - if (memcmp(s, "everyone@", 9) == 0) - tag = ARCHIVE_ENTRY_ACL_EVERYONE; - break; - default: - break; - } - - if (tag == 0) { - /* Invalid tag, skip entry */ - ret = ARCHIVE_WARN; - continue; - } else if (tag == ARCHIVE_ENTRY_ACL_USER || - tag == ARCHIVE_ENTRY_ACL_GROUP) { - n = 1; - name = field[1]; - isint(name.start, name.end, &id); - } else - n = 0; - - if (!is_nfs4_perms(field[1 + n].start, - field[1 + n].end, &permset)) { - /* Invalid NFSv4 perms, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - if (!is_nfs4_flags(field[2 + n].start, - field[2 + n].end, &permset)) { - /* Invalid NFSv4 flags, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - s = field[3 + n].start; - len = field[3 + n].end - field[3 + n].start; - type = 0; - if (len == 4) { - if (memcmp(s, "deny", 4) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_DENY; - } else if (len == 5) { - if (memcmp(s, "allow", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; - else if (memcmp(s, "audit", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; - else if (memcmp(s, "alarm", 5) == 0) - type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; - } - if (type == 0) { - /* Invalid entry type, skip entry */ - ret = ARCHIVE_WARN; - continue; - } - isint(field[4 + n].start, field[4 + n].end, - &id); - } - - /* Add entry to the internal list. */ - r = archive_acl_add_entry_len_l(acl, type, permset, - tag, id, name.start, name.end - name.start, sc); - if (r < ARCHIVE_WARN) - return (r); - if (r != ARCHIVE_OK) - ret = ARCHIVE_WARN; - types |= type; - } - - /* Reset ACL */ - archive_acl_reset(acl, types); - - return (ret); -} - -/* - * Parse a string to a positive decimal integer. Returns true if - * the string is non-empty and consists only of decimal digits, - * false otherwise. - */ -static int -isint(const char *start, const char *end, int *result) -{ - int n = 0; - if (start >= end) - return (0); - while (start < end) { - if (*start < '0' || *start > '9') - return (0); - if (n > (INT_MAX / 10) || - (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { - n = INT_MAX; - } else { - n *= 10; - n += *start - '0'; - } - start++; - } - *result = n; - return (1); -} - -/* - * Parse a string as a mode field. Returns true if - * the string is non-empty and consists only of mode characters, - * false otherwise. - */ -static int -ismode(const char *start, const char *end, int *permset) -{ - const char *p; - - if (start >= end) - return (0); - p = start; - *permset = 0; - while (p < end) { - switch (*p++) { - case 'r': case 'R': - *permset |= ARCHIVE_ENTRY_ACL_READ; - break; - case 'w': case 'W': - *permset |= ARCHIVE_ENTRY_ACL_WRITE; - break; - case 'x': case 'X': - *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; - break; - case '-': - break; - default: - return (0); - } - } - return (1); -} - -/* - * Parse a string as a NFS4 ACL permission field. - * Returns true if the string is non-empty and consists only of NFS4 ACL - * permission characters, false otherwise - */ -static int -is_nfs4_perms(const char *start, const char *end, int *permset) -{ - const char *p = start; - - while (p < end) { - switch (*p++) { - case 'r': - *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; - break; - case 'w': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; - break; - case 'x': - *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; - break; - case 'p': - *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; - break; - case 'D': - *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; - break; - case 'd': - *permset |= ARCHIVE_ENTRY_ACL_DELETE; - break; - case 'a': - *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; - break; - case 'A': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; - break; - case 'R': - *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; - break; - case 'W': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; - break; - case 'c': - *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; - break; - case 'C': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; - break; - case 'o': - *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; - break; - case 's': - *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; - break; - case '-': - break; - default: - return(0); - } - } - return (1); -} - -/* - * Parse a string as a NFS4 ACL flags field. - * Returns true if the string is non-empty and consists only of NFS4 ACL - * flag characters, false otherwise - */ -static int -is_nfs4_flags(const char *start, const char *end, int *permset) -{ - const char *p = start; - - while (p < end) { - switch(*p++) { - case 'f': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; - break; - case 'd': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; - break; - case 'i': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; - break; - case 'n': - *permset |= - ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; - break; - case 'S': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; - break; - case 'F': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; - break; - case 'I': - *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; - break; - case '-': - break; - default: - return (0); - } - } - return (1); -} - -/* - * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated - * to point to just after the separator. *start points to the first - * character of the matched text and *end just after the last - * character of the matched identifier. In particular *end - *start - * is the length of the field body, not including leading or trailing - * whitespace. - */ -static void -next_field(const char **p, const char **start, - const char **end, char *sep) -{ - /* Skip leading whitespace to find start of field. */ - while (**p == ' ' || **p == '\t' || **p == '\n') { - (*p)++; - } - *start = *p; - - /* Scan for the separator. */ - while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') { - (*p)++; - } - *sep = **p; - - /* Trim trailing whitespace to locate end of field. */ - *end = *p - 1; - while (**end == ' ' || **end == '\t' || **end == '\n') { - (*end)--; - } - (*end)++; - - /* Adjust scanner location. */ - if (**p != '\0') - (*p)++; -} diff --git a/3rdparty/libarchive/libarchive/archive_acl_private.h b/3rdparty/libarchive/libarchive/archive_acl_private.h deleted file mode 100644 index ef0b0234..00000000 --- a/3rdparty/libarchive/libarchive/archive_acl_private.h +++ /dev/null @@ -1,83 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED -#define ARCHIVE_ACL_PRIVATE_H_INCLUDED - -#include "archive_string.h" - -struct archive_acl_entry { - struct archive_acl_entry *next; - int type; /* E.g., access or default */ - int tag; /* E.g., user/group/other/mask */ - int permset; /* r/w/x bits */ - int id; /* uid/gid for user/group */ - struct archive_mstring name; /* uname/gname */ -}; - -struct archive_acl { - mode_t mode; - struct archive_acl_entry *acl_head; - struct archive_acl_entry *acl_p; - int acl_state; /* See acl_next for details. */ - wchar_t *acl_text_w; - char *acl_text; - int acl_types; -}; - -void archive_acl_clear(struct archive_acl *); -void archive_acl_copy(struct archive_acl *, struct archive_acl *); -int archive_acl_count(struct archive_acl *, int); -int archive_acl_types(struct archive_acl *); -int archive_acl_reset(struct archive_acl *, int); -int archive_acl_next(struct archive *, struct archive_acl *, int, - int *, int *, int *, int *, const char **); - -int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *); -int archive_acl_add_entry_w_len(struct archive_acl *, - int, int, int, int, const wchar_t *, size_t); -int archive_acl_add_entry_len(struct archive_acl *, - int, int, int, int, const char *, size_t); - -wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int, - struct archive *); -char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int, - struct archive_string_conv *); - -/* - * ACL text parser. - */ -int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */, - int /* type */); -int archive_acl_from_text_l(struct archive_acl *, const char * /* text */, - int /* type */, struct archive_string_conv *); - -#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_check_magic.c b/3rdparty/libarchive/libarchive/archive_check_magic.c deleted file mode 100644 index 288ce233..00000000 --- a/3rdparty/libarchive/libarchive/archive_check_magic.c +++ /dev/null @@ -1,175 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_check_magic.c 201089 2009-12-28 02:20:23Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#include -#endif - -#include "archive_private.h" - -static void -errmsg(const char *m) -{ - size_t s = strlen(m); - ssize_t written; - - while (s > 0) { - written = write(2, m, strlen(m)); - if (written <= 0) - return; - m += written; - s -= written; - } -} - -static __LA_DEAD void -diediedie(void) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) - /* Cause a breakpoint exception */ - DebugBreak(); -#endif - abort(); /* Terminate the program abnormally. */ -} - -static const char * -state_name(unsigned s) -{ - switch (s) { - case ARCHIVE_STATE_NEW: return ("new"); - case ARCHIVE_STATE_HEADER: return ("header"); - case ARCHIVE_STATE_DATA: return ("data"); - case ARCHIVE_STATE_EOF: return ("eof"); - case ARCHIVE_STATE_CLOSED: return ("closed"); - case ARCHIVE_STATE_FATAL: return ("fatal"); - default: return ("??"); - } -} - -static const char * -archive_handle_type_name(unsigned m) -{ - switch (m) { - case ARCHIVE_WRITE_MAGIC: return ("archive_write"); - case ARCHIVE_READ_MAGIC: return ("archive_read"); - case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk"); - case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk"); - case ARCHIVE_MATCH_MAGIC: return ("archive_match"); - default: return NULL; - } -} - - -static char * -write_all_states(char *buff, unsigned int states) -{ - unsigned int lowbit; - - buff[0] = '\0'; - - /* A trick for computing the lowest set bit. */ - while ((lowbit = states & (1 + ~states)) != 0) { - states &= ~lowbit; /* Clear the low bit. */ - strcat(buff, state_name(lowbit)); - if (states != 0) - strcat(buff, "/"); - } - return buff; -} - -/* - * Check magic value and current state. - * Magic value mismatches are fatal and result in calls to abort(). - * State mismatches return ARCHIVE_FATAL. - * Otherwise, returns ARCHIVE_OK. - * - * This is designed to catch serious programming errors that violate - * the libarchive API. - */ -int -__archive_check_magic(struct archive *a, unsigned int magic, - unsigned int state, const char *function) -{ - char states1[64]; - char states2[64]; - const char *handle_type; - - /* - * If this isn't some form of archive handle, - * then the library user has screwed up so bad that - * we don't even have a reliable way to report an error. - */ - handle_type = archive_handle_type_name(a->magic); - - if (!handle_type) { - errmsg("PROGRAMMER ERROR: Function "); - errmsg(function); - errmsg(" invoked with invalid archive handle.\n"); - diediedie(); - } - - if (a->magic != magic) { - archive_set_error(a, -1, - "PROGRAMMER ERROR: Function '%s' invoked" - " on '%s' archive object, which is not supported.", - function, - handle_type); - a->state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - - if ((a->state & state) == 0) { - /* If we're already FATAL, don't overwrite the error. */ - if (a->state != ARCHIVE_STATE_FATAL) - archive_set_error(a, -1, - "INTERNAL ERROR: Function '%s' invoked with" - " archive structure in state '%s'," - " should be in state '%s'", - function, - write_all_states(states1, a->state), - write_all_states(states2, state)); - a->state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - return ARCHIVE_OK; -} diff --git a/3rdparty/libarchive/libarchive/archive_cmdline.c b/3rdparty/libarchive/libarchive/archive_cmdline.c deleted file mode 100644 index 7d3bac53..00000000 --- a/3rdparty/libarchive/libarchive/archive_cmdline.c +++ /dev/null @@ -1,227 +0,0 @@ -/*- - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif - -#include "archive.h" -#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 -extract_quotation(struct archive_string *as, const char *p) -{ - const char *s; - - for (s = p + 1; *s;) { - if (*s == '\\') { - if (s[1] != '\0') { - archive_strappend_char(as, s[1]); - s += 2; - } else - s++; - } else if (*s == '"') - break; - else { - archive_strappend_char(as, s[0]); - s++; - } - } - if (*s != '"') - return (ARCHIVE_FAILED);/* Invalid sequence. */ - return ((ssize_t)(s + 1 - p)); -} - -static ssize_t -get_argument(struct archive_string *as, const char *p) -{ - const char *s = p; - - archive_string_empty(as); - - /* Skip beginning space characters. */ - while (*s != '\0' && *s == ' ') - s++; - /* Copy non-space characters. */ - while (*s != '\0' && *s != ' ') { - if (*s == '\\') { - if (s[1] != '\0') { - archive_strappend_char(as, s[1]); - s += 2; - } else { - s++;/* Ignore this character.*/ - break; - } - } else if (*s == '"') { - ssize_t q = extract_quotation(as, s); - if (q < 0) - return (ARCHIVE_FAILED);/* Invalid sequence. */ - s += q; - } else { - archive_strappend_char(as, s[0]); - s++; - } - } - return ((ssize_t)(s - p)); -} - -/* - * Set up command line arguments. - * Returns ARChIVE_OK if everything okey. - * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an - * empty command line. - * Returns ARChIVE_FATAL if no memory. - */ -int -__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd) -{ - struct archive_string as; - const char *p; - ssize_t al; - int r; - - archive_string_init(&as); - - /* Get first argument as a command path. */ - al = get_argument(&as, cmd); - if (al < 0) { - r = ARCHIVE_FAILED;/* Invalid sequence. */ - goto exit_function; - } - if (archive_strlen(&as) == 0) { - r = ARCHIVE_FAILED;/* An empty command path. */ - goto exit_function; - } - r = cmdline_set_path(data, as.s); - if (r != ARCHIVE_OK) - goto exit_function; - p = strrchr(as.s, '/'); - if (p == NULL) - p = as.s; - else - p++; - r = cmdline_add_arg(data, p); - if (r != ARCHIVE_OK) - goto exit_function; - cmd += al; - - for (;;) { - al = get_argument(&as, cmd); - if (al < 0) { - r = ARCHIVE_FAILED;/* Invalid sequence. */ - goto exit_function; - } - if (al == 0) - break; - cmd += al; - if (archive_strlen(&as) == 0 && *cmd == '\0') - break; - r = cmdline_add_arg(data, as.s); - if (r != ARCHIVE_OK) - goto exit_function; - } - r = ARCHIVE_OK; -exit_function: - archive_string_free(&as); - return (r); -} - -/* - * 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. - */ -static int -cmdline_add_arg(struct archive_cmdline *data, const char *arg) -{ - char **newargv; - - if (data->path == NULL) - return (ARCHIVE_FAILED); - - newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *)); - if (newargv == NULL) - return (ARCHIVE_FATAL); - data->argv = newargv; - data->argv[data->argc] = strdup(arg); - if (data->argv[data->argc] == NULL) - return (ARCHIVE_FATAL); - /* Set the terminator of argv. */ - data->argv[++data->argc] = NULL; - return (ARCHIVE_OK); -} - -struct archive_cmdline * -__archive_cmdline_allocate(void) -{ - return (struct archive_cmdline *) - calloc(1, sizeof(struct archive_cmdline)); -} - -/* - * Release the resources. - */ -int -__archive_cmdline_free(struct archive_cmdline *data) -{ - - if (data) { - free(data->path); - if (data->argv != NULL) { - int i; - for (i = 0; data->argv[i] != NULL; i++) - free(data->argv[i]); - free(data->argv); - } - free(data); - } - return (ARCHIVE_OK); -} - diff --git a/3rdparty/libarchive/libarchive/archive_cmdline_private.h b/3rdparty/libarchive/libarchive/archive_cmdline_private.h deleted file mode 100644 index 4e409e81..00000000 --- a/3rdparty/libarchive/libarchive/archive_cmdline_private.h +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#ifndef __LIBARCHIVE_TEST -#error This header is only to be used internally to libarchive. -#endif -#endif - -#ifndef ARCHIVE_CMDLINE_PRIVATE_H -#define ARCHIVE_CMDLINE_PRIVATE_H - -struct archive_cmdline { - char *path; - char **argv; - int argc; -}; - -struct archive_cmdline *__archive_cmdline_allocate(void); -int __archive_cmdline_parse(struct archive_cmdline *, const char *); -int __archive_cmdline_free(struct archive_cmdline *); - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_crc32.h b/3rdparty/libarchive/libarchive/archive_crc32.h deleted file mode 100644 index cd633af8..00000000 --- a/3rdparty/libarchive/libarchive/archive_crc32.h +++ /dev/null @@ -1,78 +0,0 @@ -/*- - * Copyright (c) 2009 Joerg Sonnenberger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_crc32.h 201102 2009-12-28 03:11:36Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -/* - * When zlib is unavailable, we should still be able to validate - * uncompressed zip archives. That requires us to be able to compute - * the CRC32 check value. This is a drop-in compatible replacement - * for crc32() from zlib. It's slower than the zlib implementation, - * but still pretty fast: This runs about 300MB/s on my 3GHz P4 - * compared to about 800MB/s for the zlib implementation. - */ -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]; - - 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. */ - for (;len >= 8; len -= 8) { - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - } - while (len--) - crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return (crc ^ 0xffffffffUL); -} diff --git a/3rdparty/libarchive/libarchive/archive_endian.h b/3rdparty/libarchive/libarchive/archive_endian.h deleted file mode 100644 index 1c48563b..00000000 --- a/3rdparty/libarchive/libarchive/archive_endian.h +++ /dev/null @@ -1,196 +0,0 @@ -/*- - * Copyright (c) 2002 Thomas Moestl - * 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. - * - * $FreeBSD: head/lib/libarchive/archive_endian.h 201085 2009-12-28 02:17:15Z kientzle $ - * - * Borrowed from FreeBSD's - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -/* Note: This is a purely internal header! */ -/* Do not use this outside of libarchive internal code! */ - -#ifndef ARCHIVE_ENDIAN_H_INCLUDED -#define ARCHIVE_ENDIAN_H_INCLUDED - - -/* - * 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 - -/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ - -static inline uint16_t -archive_be16dec(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 p1 = p[1]; - unsigned int p0 = p[0]; - - return ((p0 << 8) | p1); -} - -static inline uint32_t -archive_be32dec(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 p3 = p[3]; - unsigned int p2 = p[2]; - unsigned int p1 = p[1]; - unsigned int p0 = p[0]; - - return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3); -} - -static inline uint64_t -archive_be64dec(const void *pp) -{ - unsigned char const *p = (unsigned char const *)pp; - - return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4)); -} - -static inline uint16_t -archive_le16dec(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 p1 = p[1]; - unsigned int p0 = p[0]; - - return ((p1 << 8) | p0); -} - -static inline uint32_t -archive_le32dec(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 p3 = p[3]; - unsigned int p2 = p[2]; - unsigned int p1 = p[1]; - unsigned int p0 = p[0]; - - return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0); -} - -static inline uint64_t -archive_le64dec(const void *pp) -{ - unsigned char const *p = (unsigned char const *)pp; - - return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p)); -} - -static inline void -archive_be16enc(void *pp, uint16_t u) -{ - unsigned char *p = (unsigned char *)pp; - - p[0] = (u >> 8) & 0xff; - p[1] = u & 0xff; -} - -static inline void -archive_be32enc(void *pp, uint32_t u) -{ - unsigned char *p = (unsigned char *)pp; - - p[0] = (u >> 24) & 0xff; - p[1] = (u >> 16) & 0xff; - p[2] = (u >> 8) & 0xff; - p[3] = u & 0xff; -} - -static inline void -archive_be64enc(void *pp, uint64_t u) -{ - unsigned char *p = (unsigned char *)pp; - - archive_be32enc(p, (uint32_t)(u >> 32)); - archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff)); -} - -static inline void -archive_le16enc(void *pp, uint16_t u) -{ - unsigned char *p = (unsigned char *)pp; - - p[0] = u & 0xff; - p[1] = (u >> 8) & 0xff; -} - -static inline void -archive_le32enc(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; - p[3] = (u >> 24) & 0xff; -} - -static inline void -archive_le64enc(void *pp, uint64_t u) -{ - unsigned char *p = (unsigned char *)pp; - - archive_le32enc(p, (uint32_t)(u & 0xffffffff)); - archive_le32enc(p + 4, (uint32_t)(u >> 32)); -} - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_entry.c b/3rdparty/libarchive/libarchive/archive_entry.c deleted file mode 100644 index 30fb4566..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry.c +++ /dev/null @@ -1,2038 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2016 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:27Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#if MAJOR_IN_MKDEV -#include -#define HAVE_MAJOR -#elif MAJOR_IN_SYSMACROS -#include -#define HAVE_MAJOR -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_LINUX_FS_H -#include /* for Linux file flags */ -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include /* for Linux file flags */ -#endif -#include -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif - -#include "archive.h" -#include "archive_acl_private.h" -#include "archive_entry.h" -#include "archive_entry_locale.h" -#include "archive_private.h" -#include "archive_entry_private.h" - -#if !defined(HAVE_MAJOR) && !defined(major) -/* Replacement for major/minor/makedev. */ -#define major(x) ((int)(0x00ff & ((x) >> 8))) -#define minor(x) ((int)(0xffff00ff & (x))) -#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) -#endif - -/* Play games to come up with a suitable makedev() definition. */ -#ifdef __QNXNTO__ -/* QNX. */ -#include -#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) -#elif defined makedev -/* There's a "makedev" macro. */ -#define ae_makedev(maj, min) makedev((maj), (min)) -#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) -/* Windows. */ -#define ae_makedev(maj, min) mkdev((maj), (min)) -#else -/* There's a "makedev" function. */ -#define ae_makedev(maj, min) makedev((maj), (min)) -#endif - -/* - * This adjustment is needed to support the following idiom for adding - * 1000ns to the stored time: - * archive_entry_set_atime(archive_entry_atime(), - * archive_entry_atime_nsec() + 1000) - * The additional if() here compensates for ambiguity in the C standard, - * which permits two possible interpretations of a % b when a is negative. - */ -#define FIX_NS(t,ns) \ - do { \ - t += ns / 1000000000; \ - ns %= 1000000000; \ - if (ns < 0) { --t; ns += 1000000000; } \ - } while (0) - -static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); -static const wchar_t *ae_wcstofflags(const wchar_t *stringp, - unsigned long *setp, unsigned long *clrp); -static const char *ae_strtofflags(const char *stringp, - unsigned long *setp, unsigned long *clrp); - -#ifndef HAVE_WCSCPY -static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2) -{ - wchar_t *dest = s1; - while ((*s1 = *s2) != L'\0') - ++s1, ++s2; - return dest; -} -#endif -#ifndef HAVE_WCSLEN -static size_t wcslen(const wchar_t *s) -{ - const wchar_t *p = s; - while (*p != L'\0') - ++p; - return p - s; -} -#endif -#ifndef HAVE_WMEMCMP -/* Good enough for simple equality testing, but not for sorting. */ -#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) -#endif - -/**************************************************************************** - * - * Public Interface - * - ****************************************************************************/ - -struct archive_entry * -archive_entry_clear(struct archive_entry *entry) -{ - if (entry == NULL) - return (NULL); - archive_mstring_clean(&entry->ae_fflags_text); - archive_mstring_clean(&entry->ae_gname); - archive_mstring_clean(&entry->ae_hardlink); - archive_mstring_clean(&entry->ae_pathname); - archive_mstring_clean(&entry->ae_sourcepath); - archive_mstring_clean(&entry->ae_symlink); - archive_mstring_clean(&entry->ae_uname); - archive_entry_copy_mac_metadata(entry, NULL, 0); - archive_acl_clear(&entry->acl); - archive_entry_xattr_clear(entry); - archive_entry_sparse_clear(entry); - free(entry->stat); - memset(entry, 0, sizeof(*entry)); - return entry; -} - -struct archive_entry * -archive_entry_clone(struct archive_entry *entry) -{ - struct archive_entry *entry2; - struct ae_xattr *xp; - struct ae_sparse *sp; - size_t s; - const void *p; - - /* Allocate new structure and copy over all of the fields. */ - /* TODO: Should we copy the archive over? Or require a new archive - * as an argument? */ - entry2 = archive_entry_new2(entry->archive); - if (entry2 == NULL) - return (NULL); - entry2->ae_stat = entry->ae_stat; - entry2->ae_fflags_set = entry->ae_fflags_set; - entry2->ae_fflags_clear = entry->ae_fflags_clear; - - /* TODO: XXX If clone can have a different archive, what do we do here if - * character sets are different? XXX */ - archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); - archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname); - archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink); - archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname); - archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); - archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink); - entry2->ae_set = entry->ae_set; - archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname); - - /* Copy encryption status */ - entry2->encryption = entry->encryption; - - /* Copy ACL data over. */ - archive_acl_copy(&entry2->acl, &entry->acl); - - /* Copy Mac OS metadata. */ - p = archive_entry_mac_metadata(entry, &s); - archive_entry_copy_mac_metadata(entry2, p, s); - - /* Copy xattr data over. */ - xp = entry->xattr_head; - while (xp != NULL) { - archive_entry_xattr_add_entry(entry2, - xp->name, xp->value, xp->size); - xp = xp->next; - } - - /* Copy sparse data over. */ - sp = entry->sparse_head; - while (sp != NULL) { - archive_entry_sparse_add_entry(entry2, - sp->offset, sp->length); - sp = sp->next; - } - - return (entry2); -} - -void -archive_entry_free(struct archive_entry *entry) -{ - archive_entry_clear(entry); - free(entry); -} - -struct archive_entry * -archive_entry_new(void) -{ - return archive_entry_new2(NULL); -} - -struct archive_entry * -archive_entry_new2(struct archive *a) -{ - struct archive_entry *entry; - - entry = (struct archive_entry *)calloc(1, sizeof(*entry)); - if (entry == NULL) - return (NULL); - entry->archive = a; - return (entry); -} - -/* - * Functions for reading fields from an archive_entry. - */ - -time_t -archive_entry_atime(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_atime); -} - -long -archive_entry_atime_nsec(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_atime_nsec); -} - -int -archive_entry_atime_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_ATIME); -} - -time_t -archive_entry_birthtime(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_birthtime); -} - -long -archive_entry_birthtime_nsec(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_birthtime_nsec); -} - -int -archive_entry_birthtime_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_BIRTHTIME); -} - -time_t -archive_entry_ctime(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_ctime); -} - -int -archive_entry_ctime_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_CTIME); -} - -long -archive_entry_ctime_nsec(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_ctime_nsec); -} - -dev_t -archive_entry_dev(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_dev_is_broken_down) - return ae_makedev(entry->ae_stat.aest_devmajor, - entry->ae_stat.aest_devminor); - else - return (entry->ae_stat.aest_dev); -} - -int -archive_entry_dev_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_DEV); -} - -dev_t -archive_entry_devmajor(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_dev_is_broken_down) - return (entry->ae_stat.aest_devmajor); - else - return major(entry->ae_stat.aest_dev); -} - -dev_t -archive_entry_devminor(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_dev_is_broken_down) - return (entry->ae_stat.aest_devminor); - else - return minor(entry->ae_stat.aest_dev); -} - -mode_t -archive_entry_filetype(struct archive_entry *entry) -{ - return (AE_IFMT & entry->acl.mode); -} - -void -archive_entry_fflags(struct archive_entry *entry, - unsigned long *set, unsigned long *clear) -{ - *set = entry->ae_fflags_set; - *clear = entry->ae_fflags_clear; -} - -/* - * Note: if text was provided, this just returns that text. If you - * really need the text to be rebuilt in a canonical form, set the - * text, ask for the bitmaps, then set the bitmaps. (Setting the - * bitmaps clears any stored text.) This design is deliberate: if - * we're editing archives, we don't want to discard flags just because - * they aren't supported on the current system. The bitmap<->text - * conversions are platform-specific (see below). - */ -const char * -archive_entry_fflags_text(struct archive_entry *entry) -{ - const char *f; - char *p; - - if (archive_mstring_get_mbs(entry->archive, - &entry->ae_fflags_text, &f) == 0) { - if (f != NULL) - return (f); - } else if (errno == ENOMEM) - __archive_errx(1, "No memory"); - - if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) - return (NULL); - - p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); - if (p == NULL) - return (NULL); - - archive_mstring_copy_mbs(&entry->ae_fflags_text, p); - free(p); - if (archive_mstring_get_mbs(entry->archive, - &entry->ae_fflags_text, &f) == 0) - return (f); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -la_int64_t -archive_entry_gid(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_gid); -} - -const char * -archive_entry_gname(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const char * -archive_entry_gname_utf8(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - - -const wchar_t * -archive_entry_gname_w(struct archive_entry *entry) -{ - const wchar_t *p; - if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -int -_archive_entry_gname_l(struct archive_entry *entry, - const char **p, size_t *len, struct archive_string_conv *sc) -{ - return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc)); -} - -const char * -archive_entry_hardlink(struct archive_entry *entry) -{ - const char *p; - if ((entry->ae_set & AE_SET_HARDLINK) == 0) - return (NULL); - if (archive_mstring_get_mbs( - entry->archive, &entry->ae_hardlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const char * -archive_entry_hardlink_utf8(struct archive_entry *entry) -{ - const char *p; - if ((entry->ae_set & AE_SET_HARDLINK) == 0) - return (NULL); - if (archive_mstring_get_utf8( - entry->archive, &entry->ae_hardlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const wchar_t * -archive_entry_hardlink_w(struct archive_entry *entry) -{ - const wchar_t *p; - if ((entry->ae_set & AE_SET_HARDLINK) == 0) - return (NULL); - if (archive_mstring_get_wcs( - entry->archive, &entry->ae_hardlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -int -_archive_entry_hardlink_l(struct archive_entry *entry, - const char **p, size_t *len, struct archive_string_conv *sc) -{ - if ((entry->ae_set & AE_SET_HARDLINK) == 0) { - *p = NULL; - *len = 0; - return (0); - } - return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc)); -} - -la_int64_t -archive_entry_ino(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_ino); -} - -int -archive_entry_ino_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_INO); -} - -la_int64_t -archive_entry_ino64(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_ino); -} - -mode_t -archive_entry_mode(struct archive_entry *entry) -{ - return (entry->acl.mode); -} - -time_t -archive_entry_mtime(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_mtime); -} - -long -archive_entry_mtime_nsec(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_mtime_nsec); -} - -int -archive_entry_mtime_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_MTIME); -} - -unsigned int -archive_entry_nlink(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_nlink); -} - -const char * -archive_entry_pathname(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_mbs( - entry->archive, &entry->ae_pathname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const char * -archive_entry_pathname_utf8(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_utf8( - entry->archive, &entry->ae_pathname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const wchar_t * -archive_entry_pathname_w(struct archive_entry *entry) -{ - const wchar_t *p; - if (archive_mstring_get_wcs( - entry->archive, &entry->ae_pathname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -int -_archive_entry_pathname_l(struct archive_entry *entry, - const char **p, size_t *len, struct archive_string_conv *sc) -{ - return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc)); -} - -mode_t -archive_entry_perm(struct archive_entry *entry) -{ - return (~AE_IFMT & entry->acl.mode); -} - -dev_t -archive_entry_rdev(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_rdev_is_broken_down) - return ae_makedev(entry->ae_stat.aest_rdevmajor, - entry->ae_stat.aest_rdevminor); - else - return (entry->ae_stat.aest_rdev); -} - -dev_t -archive_entry_rdevmajor(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_rdev_is_broken_down) - return (entry->ae_stat.aest_rdevmajor); - else - return major(entry->ae_stat.aest_rdev); -} - -dev_t -archive_entry_rdevminor(struct archive_entry *entry) -{ - if (entry->ae_stat.aest_rdev_is_broken_down) - return (entry->ae_stat.aest_rdevminor); - else - return minor(entry->ae_stat.aest_rdev); -} - -la_int64_t -archive_entry_size(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_size); -} - -int -archive_entry_size_is_set(struct archive_entry *entry) -{ - return (entry->ae_set & AE_SET_SIZE); -} - -const char * -archive_entry_sourcepath(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_mbs( - entry->archive, &entry->ae_sourcepath, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const wchar_t * -archive_entry_sourcepath_w(struct archive_entry *entry) -{ - const wchar_t *p; - if (archive_mstring_get_wcs( - entry->archive, &entry->ae_sourcepath, &p) == 0) - return (p); - return (NULL); -} - -const char * -archive_entry_symlink(struct archive_entry *entry) -{ - const char *p; - if ((entry->ae_set & AE_SET_SYMLINK) == 0) - return (NULL); - if (archive_mstring_get_mbs( - entry->archive, &entry->ae_symlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const char * -archive_entry_symlink_utf8(struct archive_entry *entry) -{ - const char *p; - if ((entry->ae_set & AE_SET_SYMLINK) == 0) - return (NULL); - if (archive_mstring_get_utf8( - entry->archive, &entry->ae_symlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const wchar_t * -archive_entry_symlink_w(struct archive_entry *entry) -{ - const wchar_t *p; - if ((entry->ae_set & AE_SET_SYMLINK) == 0) - return (NULL); - if (archive_mstring_get_wcs( - entry->archive, &entry->ae_symlink, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -int -_archive_entry_symlink_l(struct archive_entry *entry, - const char **p, size_t *len, struct archive_string_conv *sc) -{ - if ((entry->ae_set & AE_SET_SYMLINK) == 0) { - *p = NULL; - *len = 0; - return (0); - } - return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc)); -} - -la_int64_t -archive_entry_uid(struct archive_entry *entry) -{ - return (entry->ae_stat.aest_uid); -} - -const char * -archive_entry_uname(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const char * -archive_entry_uname_utf8(struct archive_entry *entry) -{ - const char *p; - if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -const wchar_t * -archive_entry_uname_w(struct archive_entry *entry) -{ - const wchar_t *p; - if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0) - return (p); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (NULL); -} - -int -_archive_entry_uname_l(struct archive_entry *entry, - const char **p, size_t *len, struct archive_string_conv *sc) -{ - return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc)); -} - -int -archive_entry_is_data_encrypted(struct archive_entry *entry) -{ - return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA); -} - -int -archive_entry_is_metadata_encrypted(struct archive_entry *entry) -{ - return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA); -} - -int -archive_entry_is_encrypted(struct archive_entry *entry) -{ - return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA)); -} - -/* - * Functions to set archive_entry properties. - */ - -void -archive_entry_set_filetype(struct archive_entry *entry, unsigned int type) -{ - entry->stat_valid = 0; - entry->acl.mode &= ~AE_IFMT; - entry->acl.mode |= AE_IFMT & type; -} - -void -archive_entry_set_fflags(struct archive_entry *entry, - unsigned long set, unsigned long clear) -{ - archive_mstring_clean(&entry->ae_fflags_text); - entry->ae_fflags_set = set; - entry->ae_fflags_clear = clear; -} - -const char * -archive_entry_copy_fflags_text(struct archive_entry *entry, - const char *flags) -{ - archive_mstring_copy_mbs(&entry->ae_fflags_text, flags); - return (ae_strtofflags(flags, - &entry->ae_fflags_set, &entry->ae_fflags_clear)); -} - -const wchar_t * -archive_entry_copy_fflags_text_w(struct archive_entry *entry, - const wchar_t *flags) -{ - archive_mstring_copy_wcs(&entry->ae_fflags_text, flags); - return (ae_wcstofflags(flags, - &entry->ae_fflags_set, &entry->ae_fflags_clear)); -} - -void -archive_entry_set_gid(struct archive_entry *entry, la_int64_t g) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_gid = g; -} - -void -archive_entry_set_gname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_gname, name); -} - -void -archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_utf8(&entry->ae_gname, name); -} - -void -archive_entry_copy_gname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_gname, name); -} - -void -archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) -{ - archive_mstring_copy_wcs(&entry->ae_gname, name); -} - -int -archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) -{ - if (archive_mstring_update_utf8(entry->archive, - &entry->ae_gname, name) == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -int -_archive_entry_copy_gname_l(struct archive_entry *entry, - const char *name, size_t len, struct archive_string_conv *sc) -{ - return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc)); -} - -void -archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino) -{ - entry->stat_valid = 0; - entry->ae_set |= AE_SET_INO; - entry->ae_stat.aest_ino = ino; -} - -void -archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino) -{ - entry->stat_valid = 0; - entry->ae_set |= AE_SET_INO; - entry->ae_stat.aest_ino = ino; -} - -void -archive_entry_set_hardlink(struct archive_entry *entry, const char *target) -{ - archive_mstring_copy_mbs(&entry->ae_hardlink, target); - if (target != NULL) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; -} - -void -archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target) -{ - archive_mstring_copy_utf8(&entry->ae_hardlink, target); - if (target != NULL) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; -} - -void -archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) -{ - archive_mstring_copy_mbs(&entry->ae_hardlink, target); - if (target != NULL) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; -} - -void -archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) -{ - archive_mstring_copy_wcs(&entry->ae_hardlink, target); - if (target != NULL) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; -} - -int -archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target) -{ - if (target != NULL) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; - if (archive_mstring_update_utf8(entry->archive, - &entry->ae_hardlink, target) == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -int -_archive_entry_copy_hardlink_l(struct archive_entry *entry, - const char *target, size_t len, struct archive_string_conv *sc) -{ - int r; - - r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, - target, len, sc); - if (target != NULL && r == 0) - entry->ae_set |= AE_SET_HARDLINK; - else - entry->ae_set &= ~AE_SET_HARDLINK; - return (r); -} - -void -archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) -{ - FIX_NS(t, ns); - entry->stat_valid = 0; - entry->ae_set |= AE_SET_ATIME; - entry->ae_stat.aest_atime = t; - entry->ae_stat.aest_atime_nsec = ns; -} - -void -archive_entry_unset_atime(struct archive_entry *entry) -{ - archive_entry_set_atime(entry, 0, 0); - entry->ae_set &= ~AE_SET_ATIME; -} - -void -archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns) -{ - FIX_NS(t, ns); - entry->stat_valid = 0; - entry->ae_set |= AE_SET_BIRTHTIME; - entry->ae_stat.aest_birthtime = t; - entry->ae_stat.aest_birthtime_nsec = ns; -} - -void -archive_entry_unset_birthtime(struct archive_entry *entry) -{ - archive_entry_set_birthtime(entry, 0, 0); - entry->ae_set &= ~AE_SET_BIRTHTIME; -} - -void -archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) -{ - FIX_NS(t, ns); - entry->stat_valid = 0; - entry->ae_set |= AE_SET_CTIME; - entry->ae_stat.aest_ctime = t; - entry->ae_stat.aest_ctime_nsec = ns; -} - -void -archive_entry_unset_ctime(struct archive_entry *entry) -{ - archive_entry_set_ctime(entry, 0, 0); - entry->ae_set &= ~AE_SET_CTIME; -} - -void -archive_entry_set_dev(struct archive_entry *entry, dev_t d) -{ - entry->stat_valid = 0; - entry->ae_set |= AE_SET_DEV; - entry->ae_stat.aest_dev_is_broken_down = 0; - entry->ae_stat.aest_dev = d; -} - -void -archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) -{ - entry->stat_valid = 0; - entry->ae_set |= AE_SET_DEV; - entry->ae_stat.aest_dev_is_broken_down = 1; - entry->ae_stat.aest_devmajor = m; -} - -void -archive_entry_set_devminor(struct archive_entry *entry, dev_t m) -{ - entry->stat_valid = 0; - entry->ae_set |= AE_SET_DEV; - entry->ae_stat.aest_dev_is_broken_down = 1; - entry->ae_stat.aest_devminor = m; -} - -/* Set symlink if symlink is already set, else set hardlink. */ -void -archive_entry_set_link(struct archive_entry *entry, const char *target) -{ - if (entry->ae_set & AE_SET_SYMLINK) - archive_mstring_copy_mbs(&entry->ae_symlink, target); - else - archive_mstring_copy_mbs(&entry->ae_hardlink, target); -} - -void -archive_entry_set_link_utf8(struct archive_entry *entry, const char *target) -{ - if (entry->ae_set & AE_SET_SYMLINK) - archive_mstring_copy_utf8(&entry->ae_symlink, target); - else - archive_mstring_copy_utf8(&entry->ae_hardlink, target); -} - -/* Set symlink if symlink is already set, else set hardlink. */ -void -archive_entry_copy_link(struct archive_entry *entry, const char *target) -{ - if (entry->ae_set & AE_SET_SYMLINK) - archive_mstring_copy_mbs(&entry->ae_symlink, target); - else - archive_mstring_copy_mbs(&entry->ae_hardlink, target); -} - -/* Set symlink if symlink is already set, else set hardlink. */ -void -archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) -{ - if (entry->ae_set & AE_SET_SYMLINK) - archive_mstring_copy_wcs(&entry->ae_symlink, target); - else - archive_mstring_copy_wcs(&entry->ae_hardlink, target); -} - -int -archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) -{ - int r; - if (entry->ae_set & AE_SET_SYMLINK) - r = archive_mstring_update_utf8(entry->archive, - &entry->ae_symlink, target); - else - r = archive_mstring_update_utf8(entry->archive, - &entry->ae_hardlink, target); - if (r == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -int -_archive_entry_copy_link_l(struct archive_entry *entry, - const char *target, size_t len, struct archive_string_conv *sc) -{ - int r; - - if (entry->ae_set & AE_SET_SYMLINK) - r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, - target, len, sc); - else - r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, - target, len, sc); - return (r); -} - -void -archive_entry_set_mode(struct archive_entry *entry, mode_t m) -{ - entry->stat_valid = 0; - entry->acl.mode = m; -} - -void -archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns) -{ - FIX_NS(t, ns); - entry->stat_valid = 0; - entry->ae_set |= AE_SET_MTIME; - entry->ae_stat.aest_mtime = t; - entry->ae_stat.aest_mtime_nsec = ns; -} - -void -archive_entry_unset_mtime(struct archive_entry *entry) -{ - archive_entry_set_mtime(entry, 0, 0); - entry->ae_set &= ~AE_SET_MTIME; -} - -void -archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_nlink = nlink; -} - -void -archive_entry_set_pathname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_pathname, name); -} - -void -archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_utf8(&entry->ae_pathname, name); -} - -void -archive_entry_copy_pathname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_pathname, name); -} - -void -archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) -{ - archive_mstring_copy_wcs(&entry->ae_pathname, name); -} - -int -archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) -{ - if (archive_mstring_update_utf8(entry->archive, - &entry->ae_pathname, name) == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -int -_archive_entry_copy_pathname_l(struct archive_entry *entry, - const char *name, size_t len, struct archive_string_conv *sc) -{ - return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname, - name, len, sc)); -} - -void -archive_entry_set_perm(struct archive_entry *entry, mode_t p) -{ - entry->stat_valid = 0; - entry->acl.mode &= AE_IFMT; - entry->acl.mode |= ~AE_IFMT & p; -} - -void -archive_entry_set_rdev(struct archive_entry *entry, dev_t m) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_rdev = m; - entry->ae_stat.aest_rdev_is_broken_down = 0; -} - -void -archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_rdev_is_broken_down = 1; - entry->ae_stat.aest_rdevmajor = m; -} - -void -archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_rdev_is_broken_down = 1; - entry->ae_stat.aest_rdevminor = m; -} - -void -archive_entry_set_size(struct archive_entry *entry, la_int64_t s) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_size = s; - entry->ae_set |= AE_SET_SIZE; -} - -void -archive_entry_unset_size(struct archive_entry *entry) -{ - archive_entry_set_size(entry, 0); - entry->ae_set &= ~AE_SET_SIZE; -} - -void -archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) -{ - archive_mstring_copy_mbs(&entry->ae_sourcepath, path); -} - -void -archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path) -{ - archive_mstring_copy_wcs(&entry->ae_sourcepath, path); -} - -void -archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) -{ - archive_mstring_copy_mbs(&entry->ae_symlink, linkname); - if (linkname != NULL) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; -} - -void -archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname) -{ - archive_mstring_copy_utf8(&entry->ae_symlink, linkname); - if (linkname != NULL) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; -} - -void -archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) -{ - archive_mstring_copy_mbs(&entry->ae_symlink, linkname); - if (linkname != NULL) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; -} - -void -archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) -{ - archive_mstring_copy_wcs(&entry->ae_symlink, linkname); - if (linkname != NULL) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; -} - -int -archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname) -{ - if (linkname != NULL) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; - if (archive_mstring_update_utf8(entry->archive, - &entry->ae_symlink, linkname) == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -int -_archive_entry_copy_symlink_l(struct archive_entry *entry, - const char *linkname, size_t len, struct archive_string_conv *sc) -{ - int r; - - r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, - linkname, len, sc); - if (linkname != NULL && r == 0) - entry->ae_set |= AE_SET_SYMLINK; - else - entry->ae_set &= ~AE_SET_SYMLINK; - return (r); -} - -void -archive_entry_set_uid(struct archive_entry *entry, la_int64_t u) -{ - entry->stat_valid = 0; - entry->ae_stat.aest_uid = u; -} - -void -archive_entry_set_uname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_uname, name); -} - -void -archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_utf8(&entry->ae_uname, name); -} - -void -archive_entry_copy_uname(struct archive_entry *entry, const char *name) -{ - archive_mstring_copy_mbs(&entry->ae_uname, name); -} - -void -archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) -{ - archive_mstring_copy_wcs(&entry->ae_uname, name); -} - -int -archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) -{ - if (archive_mstring_update_utf8(entry->archive, - &entry->ae_uname, name) == 0) - return (1); - if (errno == ENOMEM) - __archive_errx(1, "No memory"); - return (0); -} - -void -archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted) -{ - if (is_encrypted) { - entry->encryption |= AE_ENCRYPTION_DATA; - } else { - entry->encryption &= ~AE_ENCRYPTION_DATA; - } -} - -void -archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted) -{ - if (is_encrypted) { - entry->encryption |= AE_ENCRYPTION_METADATA; - } else { - entry->encryption &= ~AE_ENCRYPTION_METADATA; - } -} - -int -_archive_entry_copy_uname_l(struct archive_entry *entry, - const char *name, size_t len, struct archive_string_conv *sc) -{ - return (archive_mstring_copy_mbs_len_l(&entry->ae_uname, - name, len, sc)); -} - -const void * -archive_entry_mac_metadata(struct archive_entry *entry, size_t *s) -{ - *s = entry->mac_metadata_size; - return entry->mac_metadata; -} - -void -archive_entry_copy_mac_metadata(struct archive_entry *entry, - const void *p, size_t s) -{ - free(entry->mac_metadata); - if (p == NULL || s == 0) { - entry->mac_metadata = NULL; - entry->mac_metadata_size = 0; - } else { - entry->mac_metadata_size = s; - entry->mac_metadata = malloc(s); - if (entry->mac_metadata == NULL) - abort(); - memcpy(entry->mac_metadata, p, s); - } -} - -/* - * ACL management. The following would, of course, be a lot simpler - * if: 1) the last draft of POSIX.1e were a really thorough and - * complete standard that addressed the needs of ACL archiving and 2) - * everyone followed it faithfully. Alas, neither is true, so the - * following is a lot more complex than might seem necessary to the - * uninitiated. - */ - -struct archive_acl * -archive_entry_acl(struct archive_entry *entry) -{ - return &entry->acl; -} - -void -archive_entry_acl_clear(struct archive_entry *entry) -{ - archive_acl_clear(&entry->acl); -} - -/* - * Add a single ACL entry to the internal list of ACL data. - */ -int -archive_entry_acl_add_entry(struct archive_entry *entry, - int type, int permset, int tag, int id, const char *name) -{ - return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name); -} - -/* - * As above, but with a wide-character name. - */ -int -archive_entry_acl_add_entry_w(struct archive_entry *entry, - int type, int permset, int tag, int id, const wchar_t *name) -{ - return archive_acl_add_entry_w_len(&entry->acl, - type, permset, tag, id, name, wcslen(name)); -} - -/* - * Return a bitmask of ACL types in an archive entry ACL list - */ -int -archive_entry_acl_types(struct archive_entry *entry) -{ - return (archive_acl_types(&entry->acl)); -} - -/* - * Return a count of entries matching "want_type". - */ -int -archive_entry_acl_count(struct archive_entry *entry, int want_type) -{ - return archive_acl_count(&entry->acl, want_type); -} - -/* - * Prepare for reading entries from the ACL data. Returns a count - * of entries matching "want_type", or zero if there are no - * non-extended ACL entries of that type. - */ -int -archive_entry_acl_reset(struct archive_entry *entry, int want_type) -{ - return archive_acl_reset(&entry->acl, want_type); -} - -/* - * Return the next ACL entry in the list. Fake entries for the - * standard permissions and include them in the returned list. - */ -int -archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, - int *permset, int *tag, int *id, const char **name) -{ - int r; - r = archive_acl_next(entry->archive, &entry->acl, want_type, type, - permset, tag, id, name); - if (r == ARCHIVE_FATAL && errno == ENOMEM) - __archive_errx(1, "No memory"); - return (r); -} - -/* - * Generate a text version of the ACL. The flags parameter controls - * the style of the generated ACL. - */ -wchar_t * -archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len, - int flags) -{ - return (archive_acl_to_text_w(&entry->acl, len, flags, - entry->archive)); -} - -char * -archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len, - int flags) -{ - return (archive_acl_to_text_l(&entry->acl, len, flags, NULL)); -} - -char * -_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len, - int flags, struct archive_string_conv *sc) -{ - return (archive_acl_to_text_l(&entry->acl, len, flags, sc)); -} - -/* - * ACL text parser. - */ -int -archive_entry_acl_from_text_w(struct archive_entry *entry, - const wchar_t *wtext, int type) -{ - return (archive_acl_from_text_w(&entry->acl, wtext, type)); -} - -int -archive_entry_acl_from_text(struct archive_entry *entry, - const char *text, int type) -{ - return (archive_acl_from_text_l(&entry->acl, text, type, NULL)); -} - -int -_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text, - int type, struct archive_string_conv *sc) -{ - return (archive_acl_from_text_l(&entry->acl, text, type, sc)); -} - -/* Deprecated */ -static int -archive_entry_acl_text_compat(int *flags) -{ - if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0) - return (1); - - /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */ - if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) - *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID; - - /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */ - if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) - *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; - - *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA; - - return (0); -} - -/* Deprecated */ -const wchar_t * -archive_entry_acl_text_w(struct archive_entry *entry, int flags) -{ - if (entry->acl.acl_text_w != NULL) { - free(entry->acl.acl_text_w); - entry->acl.acl_text_w = NULL; - } - if (archive_entry_acl_text_compat(&flags) == 0) - entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl, - NULL, flags, entry->archive); - return (entry->acl.acl_text_w); -} - -/* Deprecated */ -const char * -archive_entry_acl_text(struct archive_entry *entry, int flags) -{ - if (entry->acl.acl_text != NULL) { - free(entry->acl.acl_text); - entry->acl.acl_text = NULL; - } - if (archive_entry_acl_text_compat(&flags) == 0) - entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL, - flags, NULL); - - return (entry->acl.acl_text); -} - -/* Deprecated */ -int -_archive_entry_acl_text_l(struct archive_entry *entry, int flags, - const char **acl_text, size_t *len, struct archive_string_conv *sc) -{ - if (entry->acl.acl_text != NULL) { - free(entry->acl.acl_text); - entry->acl.acl_text = NULL; - } - - if (archive_entry_acl_text_compat(&flags) == 0) - entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, - (ssize_t *)len, flags, sc); - - *acl_text = entry->acl.acl_text; - - return (0); -} - -/* - * Following code is modified from UC Berkeley sources, and - * is subject to the following copyright notice. - */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -static const struct flag { - const char *name; - const wchar_t *wname; - unsigned long set; - unsigned long clear; -} flags[] = { - /* Preferred (shorter) names per flag first, all prefixed by "no" */ -#ifdef SF_APPEND - { "nosappnd", L"nosappnd", SF_APPEND, 0 }, - { "nosappend", L"nosappend", SF_APPEND, 0 }, -#endif -#if defined(FS_APPEND_FL) /* 'a' */ - { "nosappnd", L"nosappnd", FS_APPEND_FL, 0 }, - { "nosappend", L"nosappend", FS_APPEND_FL, 0 }, -#elif defined(EXT2_APPEND_FL) /* 'a' */ - { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, - { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, -#endif -#ifdef SF_ARCHIVED - { "noarch", L"noarch", SF_ARCHIVED, 0 }, - { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, -#endif -#ifdef SF_IMMUTABLE - { "noschg", L"noschg", SF_IMMUTABLE, 0 }, - { "noschange", L"noschange", SF_IMMUTABLE, 0 }, - { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, -#endif -#if defined(FS_IMMUTABLE_FL) /* 'i' */ - { "noschg", L"noschg", FS_IMMUTABLE_FL, 0 }, - { "noschange", L"noschange", FS_IMMUTABLE_FL, 0 }, - { "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0 }, -#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */ - { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, - { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, - { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, -#endif -#ifdef SF_NOUNLINK - { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, - { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, -#endif -#ifdef SF_SNAPSHOT - { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, -#endif -#ifdef UF_APPEND - { "nouappnd", L"nouappnd", UF_APPEND, 0 }, - { "nouappend", L"nouappend", UF_APPEND, 0 }, -#endif -#ifdef UF_IMMUTABLE - { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, - { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, - { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, -#endif -#ifdef UF_NODUMP - { "nodump", L"nodump", 0, UF_NODUMP}, -#endif -#if defined(FS_NODUMP_FL) /* 'd' */ - { "nodump", L"nodump", 0, FS_NODUMP_FL}, -#elif defined(EXT2_NODUMP_FL) /* 'd' */ - { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, -#endif -#ifdef UF_OPAQUE - { "noopaque", L"noopaque", UF_OPAQUE, 0 }, -#endif -#ifdef UF_NOUNLINK - { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, - { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, -#endif -#ifdef UF_COMPRESSED - { "nocompressed",L"nocompressed", UF_COMPRESSED, 0 }, -#endif -#ifdef UF_HIDDEN - { "nohidden", L"nohidden", UF_HIDDEN, 0 }, -#endif -#if defined(FS_UNRM_FL) - { "nouunlink", L"nouunlink", FS_UNRM_FL, 0}, -#elif defined(EXT2_UNRM_FL) - { "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0}, -#endif - -#if defined(FS_BTREE_FL) - { "nobtree", L"nobtree", FS_BTREE_FL, 0 }, -#elif defined(EXT2_BTREE_FL) - { "nobtree", L"nobtree", EXT2_BTREE_FL, 0 }, -#endif - -#if defined(FS_ECOMPR_FL) - { "nocomperr", L"nocomperr", FS_ECOMPR_FL, 0 }, -#elif defined(EXT2_ECOMPR_FL) - { "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 }, -#endif - -#if defined(FS_COMPR_FL) /* 'c' */ - { "nocompress", L"nocompress", FS_COMPR_FL, 0 }, -#elif defined(EXT2_COMPR_FL) /* 'c' */ - { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, -#endif - -#if defined(FS_NOATIME_FL) /* 'A' */ - { "noatime", L"noatime", 0, FS_NOATIME_FL}, -#elif defined(EXT2_NOATIME_FL) /* 'A' */ - { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, -#endif - -#if defined(FS_DIRTY_FL) - { "nocompdirty",L"nocompdirty", FS_DIRTY_FL, 0}, -#elif defined(EXT2_DIRTY_FL) - { "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0}, -#endif - -#if defined(FS_COMPRBLK_FL) -#if defined(FS_NOCOMPR_FL) - { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, FS_NOCOMPR_FL}, -#else - { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, 0}, -#endif -#elif defined(EXT2_COMPRBLK_FL) -#if defined(EXT2_NOCOMPR_FL) - { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL}, -#else - { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0}, -#endif -#endif -#if defined(FS_DIRSYNC_FL) - { "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0}, -#elif defined(EXT2_DIRSYNC_FL) - { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0}, -#endif -#if defined(FS_INDEX_FL) - { "nohashidx", L"nohashidx", FS_INDEX_FL, 0}, -#elif defined(EXT2_INDEX_FL) - { "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0}, -#endif -#if defined(FS_IMAGIC_FL) - { "noimagic", L"noimagic", FS_IMAGIC_FL, 0}, -#elif defined(EXT2_IMAGIC_FL) - { "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0}, -#endif -#if defined(FS_JOURNAL_DATA_FL) - { "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0}, -#elif defined(EXT3_JOURNAL_DATA_FL) - { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0}, -#endif -#if defined(FS_SECRM_FL) - { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0}, -#elif defined(EXT2_SECRM_FL) - { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0}, -#endif -#if defined(FS_SYNC_FL) - { "nosync", L"nosync", FS_SYNC_FL, 0}, -#elif defined(EXT2_SYNC_FL) - { "nosync", L"nosync", EXT2_SYNC_FL, 0}, -#endif -#if defined(FS_NOTAIL_FL) - { "notail", L"notail", 0, FS_NOTAIL_FL}, -#elif defined(EXT2_NOTAIL_FL) - { "notail", L"notail", 0, EXT2_NOTAIL_FL}, -#endif -#if defined(FS_TOPDIR_FL) - { "notopdir", L"notopdir", FS_TOPDIR_FL, 0}, -#elif defined(EXT2_TOPDIR_FL) - { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0}, -#endif -#ifdef FS_ENCRYPT_FL - { "noencrypt", L"noencrypt", FS_ENCRYPT_FL, 0}, -#endif -#ifdef FS_HUGE_FILE_FL - { "nohugefile", L"nohugefile", FS_HUGE_FILE_FL, 0}, -#endif -#ifdef FS_EXTENT_FL - { "noextent", L"noextent", FS_EXTENT_FL, 0}, -#endif -#ifdef FS_EA_INODE_FL - { "noeainode", L"noeainode", FS_EA_INODE_FL, 0}, -#endif -#ifdef FS_EOFBLOCKS_FL - { "noeofblocks",L"noeofblocks", FS_EOFBLOCKS_FL, 0}, -#endif -#ifdef FS_NOCOW_FL - { "nocow", L"nocow", FS_NOCOW_FL, 0}, -#endif -#ifdef FS_INLINE_DATA_FL - { "noinlinedata",L"noinlinedata", FS_INLINE_DATA_FL, 0}, -#endif -#ifdef FS_PROJINHERIT_FL - { "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0}, -#endif -#if defined(FS_RESERVED_FL) - { "noreserved", L"noreserved", FS_RESERVED_FL, 0}, -#elif defined(EXT2_RESERVED_FL) - { "noreserved", L"noreserved", EXT2_RESERVED_FL, 0}, -#endif - { NULL, NULL, 0, 0 } -}; - -/* - * fflagstostr -- - * Convert file flags to a comma-separated string. If no flags - * are set, return the empty string. - */ -static char * -ae_fflagstostr(unsigned long bitset, unsigned long bitclear) -{ - char *string, *dp; - const char *sp; - unsigned long bits; - const struct flag *flag; - size_t length; - - bits = bitset | bitclear; - length = 0; - for (flag = flags; flag->name != NULL; flag++) - if (bits & (flag->set | flag->clear)) { - length += strlen(flag->name) + 1; - bits &= ~(flag->set | flag->clear); - } - - if (length == 0) - return (NULL); - string = (char *)malloc(length); - if (string == NULL) - return (NULL); - - dp = string; - for (flag = flags; flag->name != NULL; flag++) { - if (bitset & flag->set || bitclear & flag->clear) { - sp = flag->name + 2; - } else if (bitset & flag->clear || bitclear & flag->set) { - sp = flag->name; - } else - continue; - bitset &= ~(flag->set | flag->clear); - bitclear &= ~(flag->set | flag->clear); - if (dp > string) - *dp++ = ','; - while ((*dp++ = *sp++) != '\0') - ; - dp--; - } - - *dp = '\0'; - return (string); -} - -/* - * strtofflags -- - * Take string of arguments and return file flags. This - * version works a little differently than strtofflags(3). - * In particular, it always tests every token, skipping any - * unrecognized tokens. It returns a pointer to the first - * unrecognized token, or NULL if every token was recognized. - * This version is also const-correct and does not modify the - * provided string. - */ -static const char * -ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) -{ - const char *start, *end; - const struct flag *flag; - unsigned long set, clear; - const char *failed; - - set = clear = 0; - start = s; - failed = NULL; - /* Find start of first token. */ - while (*start == '\t' || *start == ' ' || *start == ',') - start++; - while (*start != '\0') { - size_t length; - /* Locate end of token. */ - end = start; - while (*end != '\0' && *end != '\t' && - *end != ' ' && *end != ',') - end++; - length = end - start; - for (flag = flags; flag->name != NULL; flag++) { - size_t flag_length = strlen(flag->name); - if (length == flag_length - && memcmp(start, flag->name, length) == 0) { - /* Matched "noXXXX", so reverse the sense. */ - clear |= flag->set; - set |= flag->clear; - break; - } else if (length == flag_length - 2 - && memcmp(start, flag->name + 2, length) == 0) { - /* Matched "XXXX", so don't reverse. */ - set |= flag->set; - clear |= flag->clear; - break; - } - } - /* Ignore unknown flag names. */ - if (flag->name == NULL && failed == NULL) - failed = start; - - /* Find start of next token. */ - start = end; - while (*start == '\t' || *start == ' ' || *start == ',') - start++; - - } - - if (setp) - *setp = set; - if (clrp) - *clrp = clear; - - /* Return location of first failure. */ - return (failed); -} - -/* - * wcstofflags -- - * Take string of arguments and return file flags. This - * version works a little differently than strtofflags(3). - * In particular, it always tests every token, skipping any - * unrecognized tokens. It returns a pointer to the first - * unrecognized token, or NULL if every token was recognized. - * This version is also const-correct and does not modify the - * provided string. - */ -static const wchar_t * -ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) -{ - const wchar_t *start, *end; - const struct flag *flag; - unsigned long set, clear; - const wchar_t *failed; - - set = clear = 0; - start = s; - failed = NULL; - /* Find start of first token. */ - while (*start == L'\t' || *start == L' ' || *start == L',') - start++; - while (*start != L'\0') { - size_t length; - /* Locate end of token. */ - end = start; - while (*end != L'\0' && *end != L'\t' && - *end != L' ' && *end != L',') - end++; - length = end - start; - for (flag = flags; flag->wname != NULL; flag++) { - size_t flag_length = wcslen(flag->wname); - if (length == flag_length - && wmemcmp(start, flag->wname, length) == 0) { - /* Matched "noXXXX", so reverse the sense. */ - clear |= flag->set; - set |= flag->clear; - break; - } else if (length == flag_length - 2 - && wmemcmp(start, flag->wname + 2, length) == 0) { - /* Matched "XXXX", so don't reverse. */ - set |= flag->set; - clear |= flag->clear; - break; - } - } - /* Ignore unknown flag names. */ - if (flag->wname == NULL && failed == NULL) - failed = start; - - /* Find start of next token. */ - start = end; - while (*start == L'\t' || *start == L' ' || *start == L',') - start++; - - } - - if (setp) - *setp = set; - if (clrp) - *clrp = clear; - - /* Return location of first failure. */ - return (failed); -} - - -#ifdef TEST -#include -int -main(int argc, char **argv) -{ - struct archive_entry *entry = archive_entry_new(); - unsigned long set, clear; - const wchar_t *remainder; - - remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); - archive_entry_fflags(entry, &set, &clear); - - wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); - - wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); - return (0); -} -#endif diff --git a/3rdparty/libarchive/libarchive/archive_entry.h b/3rdparty/libarchive/libarchive/archive_entry.h deleted file mode 100644 index bcc2962b..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry.h +++ /dev/null @@ -1,702 +0,0 @@ -/*- - * Copyright (c) 2003-2008 Tim Kientzle - * Copyright (c) 2016 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $ - */ - -#ifndef ARCHIVE_ENTRY_H_INCLUDED -#define ARCHIVE_ENTRY_H_INCLUDED - -/* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3003002 - -/* - * Note: archive_entry.h is for use outside of libarchive; the - * configuration headers (config.h, archive_platform.h, etc.) are - * purely internal. Do NOT use HAVE_XXX configuration macros to - * control the behavior of this header! If you must conditionalize, - * use predefined compiler and/or platform macros. - */ - -#include -#include /* for wchar_t */ -#include - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#endif - -/* Get a suitable 64-bit integer type. */ -#if !defined(__LA_INT64_T_DEFINED) -# if ARCHIVE_VERSION_NUMBER < 4000000 -#define __LA_INT64_T la_int64_t -# endif -#define __LA_INT64_T_DEFINED -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) -typedef __int64 la_int64_t; -# else -#include -# if defined(_SCO_DS) || defined(__osf__) -typedef long long la_int64_t; -# else -typedef int64_t la_int64_t; -# endif -# endif -#endif - -/* The la_ssize_t should match the type used in 'struct stat' */ -#if !defined(__LA_SSIZE_T_DEFINED) -/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */ -# if ARCHIVE_VERSION_NUMBER < 4000000 -#define __LA_SSIZE_T la_ssize_t -# endif -#define __LA_SSIZE_T_DEFINED -# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) -# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_) -typedef ssize_t la_ssize_t; -# elif defined(_WIN64) -typedef __int64 la_ssize_t; -# else -typedef long la_ssize_t; -# endif -# else -# include /* ssize_t */ -typedef ssize_t la_ssize_t; -# endif -#endif - -/* Get a suitable definition for mode_t */ -#if ARCHIVE_VERSION_NUMBER >= 3999000 -/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */ -# define __LA_MODE_T int -#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__) -# define __LA_MODE_T unsigned short -#else -# define __LA_MODE_T mode_t -#endif - -/* Large file support for Android */ -#ifdef __ANDROID__ -#include "android_lf.h" -#endif - -/* - * On Windows, define LIBARCHIVE_STATIC if you're building or using a - * .lib. The default here assumes you're building a DLL. Only - * libarchive source should ever define __LIBARCHIVE_BUILD. - */ -#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) -# ifdef __LIBARCHIVE_BUILD -# ifdef __GNUC__ -# define __LA_DECL __attribute__((dllexport)) extern -# else -# define __LA_DECL __declspec(dllexport) -# endif -# else -# ifdef __GNUC__ -# define __LA_DECL -# else -# define __LA_DECL __declspec(dllimport) -# endif -# endif -#else -/* Static libraries on all platforms and shared libraries on non-Windows. */ -# define __LA_DECL -#endif - -#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 -# define __LA_DEPRECATED __attribute__((deprecated)) -#else -# define __LA_DEPRECATED -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Description of an archive entry. - * - * You can think of this as "struct stat" with some text fields added in. - * - * TODO: Add "comment", "charset", and possibly other entries that are - * supported by "pax interchange" format. However, GNU, ustar, cpio, - * and other variants don't support these features, so they're not an - * excruciatingly high priority right now. - * - * TODO: "pax interchange" format allows essentially arbitrary - * key/value attributes to be attached to any entry. Supporting - * such extensions may make this library useful for special - * applications (e.g., a package manager could attach special - * package-management attributes to each entry). - */ -struct archive; -struct archive_entry; - -/* - * File-type constants. These are returned from archive_entry_filetype() - * and passed to archive_entry_set_filetype(). - * - * These values match S_XXX defines on every platform I've checked, - * including Windows, AIX, Linux, Solaris, and BSD. They're - * (re)defined here because platforms generally don't define the ones - * they don't support. For example, Windows doesn't define S_IFLNK or - * S_IFBLK. Instead of having a mass of conditional logic and system - * checks to define any S_XXX values that aren't supported locally, - * I've just defined a new set of such constants so that - * libarchive-based applications can manipulate and identify archive - * entries properly even if the hosting platform can't store them on - * disk. - * - * These values are also used directly within some portable formats, - * such as cpio. If you find a platform that varies from these, the - * correct solution is to leave these alone and translate from these - * portable values to platform-native values when entries are read from - * or written to disk. - */ -/* - * In libarchive 4.0, we can drop the casts here. - * They're needed to work around Borland C's broken mode_t. - */ -#define AE_IFMT ((__LA_MODE_T)0170000) -#define AE_IFREG ((__LA_MODE_T)0100000) -#define AE_IFLNK ((__LA_MODE_T)0120000) -#define AE_IFSOCK ((__LA_MODE_T)0140000) -#define AE_IFCHR ((__LA_MODE_T)0020000) -#define AE_IFBLK ((__LA_MODE_T)0060000) -#define AE_IFDIR ((__LA_MODE_T)0040000) -#define AE_IFIFO ((__LA_MODE_T)0010000) - -/* - * Basic object manipulation - */ - -__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *); -/* The 'clone' function does a deep copy; all of the strings are copied too. */ -__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *); -__LA_DECL void archive_entry_free(struct archive_entry *); -__LA_DECL struct archive_entry *archive_entry_new(void); - -/* - * This form of archive_entry_new2() will pull character-set - * conversion information from the specified archive handle. The - * older archive_entry_new(void) form is equivalent to calling - * archive_entry_new2(NULL) and will result in the use of an internal - * default character-set conversion. - */ -__LA_DECL struct archive_entry *archive_entry_new2(struct archive *); - -/* - * Retrieve fields from an archive_entry. - * - * There are a number of implicit conversions among these fields. For - * example, if a regular string field is set and you read the _w wide - * character field, the entry will implicitly convert narrow-to-wide - * using the current locale. Similarly, dev values are automatically - * updated when you write devmajor or devminor and vice versa. - * - * In addition, fields can be "set" or "unset." Unset string fields - * return NULL, non-string fields have _is_set() functions to test - * whether they've been set. You can "unset" a string field by - * assigning NULL; non-string fields have _unset() functions to - * unset them. - * - * Note: There is one ambiguity in the above; string fields will - * also return NULL when implicit character set conversions fail. - * This is usually what you want. - */ -__LA_DECL time_t archive_entry_atime(struct archive_entry *); -__LA_DECL long archive_entry_atime_nsec(struct archive_entry *); -__LA_DECL int archive_entry_atime_is_set(struct archive_entry *); -__LA_DECL time_t archive_entry_birthtime(struct archive_entry *); -__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *); -__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *); -__LA_DECL time_t archive_entry_ctime(struct archive_entry *); -__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); -__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *); -__LA_DECL dev_t archive_entry_dev(struct archive_entry *); -__LA_DECL int archive_entry_dev_is_set(struct archive_entry *); -__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); -__LA_DECL dev_t archive_entry_devminor(struct archive_entry *); -__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); -__LA_DECL void archive_entry_fflags(struct archive_entry *, - unsigned long * /* set */, - unsigned long * /* clear */); -__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_gid(struct archive_entry *); -__LA_DECL const char *archive_entry_gname(struct archive_entry *); -__LA_DECL const char *archive_entry_gname_utf8(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *); -__LA_DECL const char *archive_entry_hardlink(struct archive_entry *); -__LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *); -__LA_DECL int archive_entry_ino_is_set(struct archive_entry *); -__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); -__LA_DECL time_t archive_entry_mtime(struct archive_entry *); -__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *); -__LA_DECL int archive_entry_mtime_is_set(struct archive_entry *); -__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *); -__LA_DECL const char *archive_entry_pathname(struct archive_entry *); -__LA_DECL const char *archive_entry_pathname_utf8(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *); -__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdev(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); -__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_size(struct archive_entry *); -__LA_DECL int archive_entry_size_is_set(struct archive_entry *); -__LA_DECL const char *archive_entry_strmode(struct archive_entry *); -__LA_DECL const char *archive_entry_symlink(struct archive_entry *); -__LA_DECL const char *archive_entry_symlink_utf8(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_uid(struct archive_entry *); -__LA_DECL const char *archive_entry_uname(struct archive_entry *); -__LA_DECL const char *archive_entry_uname_utf8(struct archive_entry *); -__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); -__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *); -__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *); -__LA_DECL int archive_entry_is_encrypted(struct archive_entry *); - -/* - * Set fields in an archive_entry. - * - * Note: Before libarchive 2.4, there were 'set' and 'copy' versions - * of the string setters. 'copy' copied the actual string, 'set' just - * stored the pointer. In libarchive 2.4 and later, strings are - * always copied. - */ - -__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); -__LA_DECL void archive_entry_unset_atime(struct archive_entry *); -#if defined(_WIN32) && !defined(__CYGWIN__) -__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *); -#endif -__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); -__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); -__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long); -__LA_DECL void archive_entry_unset_ctime(struct archive_entry *); -__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int); -__LA_DECL void archive_entry_set_fflags(struct archive_entry *, - unsigned long /* set */, unsigned long /* clear */); -/* Returns pointer to start of first invalid token, or NULL if none. */ -/* Note that all recognized tokens are processed, regardless. */ -__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *, - const char *); -__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, - const wchar_t *); -__LA_DECL void archive_entry_set_gid(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_gname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_set_ino64(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T); -__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long); -__LA_DECL void archive_entry_unset_mtime(struct archive_entry *); -__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int); -__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_pathname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T); -__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_unset_size(struct archive_entry *); -__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *); -__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_symlink_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_uid(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_uname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *); -__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); -__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted); -__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted); -/* - * Routines to bulk copy fields to/from a platform-native "struct - * stat." Libarchive used to just store a struct stat inside of each - * archive_entry object, but this created issues when trying to - * manipulate archives on systems different than the ones they were - * created on. - * - * TODO: On Linux and other LFS systems, provide both stat32 and - * stat64 versions of these functions and all of the macro glue so - * that archive_entry_stat is magically defined to - * archive_entry_stat32 or archive_entry_stat64 as appropriate. - */ -__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); -__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); - -/* - * Storage for Mac OS-specific AppleDouble metadata information. - * Apple-format tar files store a separate binary blob containing - * encoded metadata with ACL, extended attributes, etc. - * This provides a place to store that blob. - */ - -__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *); -__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t); - -/* - * ACL routines. This used to simply store and return text-format ACL - * strings, but that proved insufficient for a number of reasons: - * = clients need control over uname/uid and gname/gid mappings - * = there are many different ACL text formats - * = would like to be able to read/convert archives containing ACLs - * on platforms that lack ACL libraries - * - * This last point, in particular, forces me to implement a reasonably - * complete set of ACL support routines. - */ - -/* - * Permission bits. - */ -#define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001 -#define ARCHIVE_ENTRY_ACL_WRITE 0x00000002 -#define ARCHIVE_ENTRY_ACL_READ 0x00000004 -#define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008 -#define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008 -#define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010 -#define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010 -#define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020 -#define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020 -#define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040 -#define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080 -#define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100 -#define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200 -#define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400 -#define ARCHIVE_ENTRY_ACL_DELETE 0x00000800 -#define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000 -#define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000 -#define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000 -#define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000 - -#define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \ - (ARCHIVE_ENTRY_ACL_EXECUTE \ - | ARCHIVE_ENTRY_ACL_WRITE \ - | ARCHIVE_ENTRY_ACL_READ) - -#define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \ - (ARCHIVE_ENTRY_ACL_EXECUTE \ - | ARCHIVE_ENTRY_ACL_READ_DATA \ - | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \ - | ARCHIVE_ENTRY_ACL_WRITE_DATA \ - | ARCHIVE_ENTRY_ACL_ADD_FILE \ - | ARCHIVE_ENTRY_ACL_APPEND_DATA \ - | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \ - | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \ - | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \ - | ARCHIVE_ENTRY_ACL_DELETE_CHILD \ - | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \ - | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \ - | ARCHIVE_ENTRY_ACL_DELETE \ - | ARCHIVE_ENTRY_ACL_READ_ACL \ - | ARCHIVE_ENTRY_ACL_WRITE_ACL \ - | ARCHIVE_ENTRY_ACL_WRITE_OWNER \ - | ARCHIVE_ENTRY_ACL_SYNCHRONIZE) - -/* - * Inheritance values (NFS4 ACLs only); included in permset. - */ -#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000 -#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000 - -#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \ - (ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \ - | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \ - | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \ - | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \ - | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \ - | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \ - | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) - -/* We need to be able to specify combinations of these. */ -#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */ -#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */ -#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \ - | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) -#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \ - | ARCHIVE_ENTRY_ACL_TYPE_DENY \ - | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \ - | ARCHIVE_ENTRY_ACL_TYPE_ALARM) - -/* Tag values mimic POSIX.1e */ -#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */ -#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */ -#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */ -#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */ -#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */ -#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */ -#define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */ - -/* - * Set the ACL by clearing it and adding entries one at a time. - * Unlike the POSIX.1e ACL routines, you must specify the type - * (access/default) for each entry. Internally, the ACL data is just - * a soup of entries. API calls here allow you to retrieve just the - * entries of interest. This design (which goes against the spirit of - * POSIX.1e) is useful for handling archive formats that combine - * default and access information in a single ACL list. - */ -__LA_DECL void archive_entry_acl_clear(struct archive_entry *); -__LA_DECL int archive_entry_acl_add_entry(struct archive_entry *, - int /* type */, int /* permset */, int /* tag */, - int /* qual */, const char * /* name */); -__LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *, - int /* type */, int /* permset */, int /* tag */, - int /* qual */, const wchar_t * /* name */); - -/* - * To retrieve the ACL, first "reset", then repeatedly ask for the - * "next" entry. The want_type parameter allows you to request only - * certain types of entries. - */ -__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); -__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */, - int * /* type */, int * /* permset */, int * /* tag */, - int * /* qual */, const char ** /* name */); -__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, - int * /* type */, int * /* permset */, int * /* tag */, - int * /* qual */, const wchar_t ** /* name */); - -/* - * Construct a text-format ACL. The flags argument is a bitmask that - * can include any of the following: - * - * Flags only for archive entries with POSIX.1e ACL: - * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries. - * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries. - * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each - * default ACL entry. - * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and - * "mask" entries. - * - * Flags only for archive entries with NFSv4 ACL: - * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for - * unset permissions and flags in NFSv4 ACL permission and flag fields - * - * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL: - * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in - * each ACL entry. - * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma - * instead of newline. - */ -#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001 -#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002 -#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004 -#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008 -#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010 - -__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *, - la_ssize_t * /* len */, int /* flags */); -__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *, - la_ssize_t * /* len */, int /* flags */); -__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *, - const wchar_t * /* wtext */, int /* type */); -__LA_DECL int archive_entry_acl_from_text(struct archive_entry *, - const char * /* text */, int /* type */); - -/* Deprecated constants */ -#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 -#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 - -/* Deprecated functions */ -__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, - int /* flags */) __LA_DEPRECATED; -__LA_DECL const char *archive_entry_acl_text(struct archive_entry *, - int /* flags */) __LA_DEPRECATED; - -/* Return bitmask of ACL types in an archive entry */ -__LA_DECL int archive_entry_acl_types(struct archive_entry *); - -/* Return a count of entries matching 'want_type' */ -__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); - -/* Return an opaque ACL object. */ -/* There's not yet anything clients can actually do with this... */ -struct archive_acl; -__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *); - -/* - * extended attributes - */ - -__LA_DECL void archive_entry_xattr_clear(struct archive_entry *); -__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *, - const char * /* name */, const void * /* value */, - size_t /* size */); - -/* - * To retrieve the xattr list, first "reset", then repeatedly ask for the - * "next" entry. - */ - -__LA_DECL int archive_entry_xattr_count(struct archive_entry *); -__LA_DECL int archive_entry_xattr_reset(struct archive_entry *); -__LA_DECL int archive_entry_xattr_next(struct archive_entry *, - const char ** /* name */, const void ** /* value */, size_t *); - -/* - * sparse - */ - -__LA_DECL void archive_entry_sparse_clear(struct archive_entry *); -__LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *, - la_int64_t /* offset */, la_int64_t /* length */); - -/* - * To retrieve the xattr list, first "reset", then repeatedly ask for the - * "next" entry. - */ - -__LA_DECL int archive_entry_sparse_count(struct archive_entry *); -__LA_DECL int archive_entry_sparse_reset(struct archive_entry *); -__LA_DECL int archive_entry_sparse_next(struct archive_entry *, - la_int64_t * /* offset */, la_int64_t * /* length */); - -/* - * Utility to match up hardlinks. - * - * The 'struct archive_entry_linkresolver' is a cache of archive entries - * for files with multiple links. Here's how to use it: - * 1. Create a lookup object with archive_entry_linkresolver_new() - * 2. Tell it the archive format you're using. - * 3. Hand each archive_entry to archive_entry_linkify(). - * That function will return 0, 1, or 2 entries that should - * be written. - * 4. Call archive_entry_linkify(resolver, NULL) until - * no more entries are returned. - * 5. Call archive_entry_linkresolver_free(resolver) to free resources. - * - * The entries returned have their hardlink and size fields updated - * appropriately. If an entry is passed in that does not refer to - * a file with multiple links, it is returned unchanged. The intention - * is that you should be able to simply filter all entries through - * this machine. - * - * To make things more efficient, be sure that each entry has a valid - * nlinks value. The hardlink cache uses this to track when all links - * have been found. If the nlinks value is zero, it will keep every - * name in the cache indefinitely, which can use a lot of memory. - * - * Note that archive_entry_size() is reset to zero if the file - * body should not be written to the archive. Pay attention! - */ -struct archive_entry_linkresolver; - -/* - * There are three different strategies for marking hardlinks. - * The descriptions below name them after the best-known - * formats that rely on each strategy: - * - * "Old cpio" is the simplest, it always returns any entry unmodified. - * As far as I know, only cpio formats use this. Old cpio archives - * store every link with the full body; the onus is on the dearchiver - * to detect and properly link the files as they are restored. - * "tar" is also pretty simple; it caches a copy the first time it sees - * any link. Subsequent appearances are modified to be hardlink - * references to the first one without any body. Used by all tar - * formats, although the newest tar formats permit the "old cpio" strategy - * as well. This strategy is very simple for the dearchiver, - * and reasonably straightforward for the archiver. - * "new cpio" is trickier. It stores the body only with the last - * occurrence. The complication is that we might not - * see every link to a particular file in a single session, so - * there's no easy way to know when we've seen the last occurrence. - * The solution here is to queue one link until we see the next. - * At the end of the session, you can enumerate any remaining - * entries by calling archive_entry_linkify(NULL) and store those - * bodies. If you have a file with three links l1, l2, and l3, - * you'll get the following behavior if you see all three links: - * linkify(l1) => NULL (the resolver stores l1 internally) - * linkify(l2) => l1 (resolver stores l2, you write l1) - * linkify(l3) => l2, l3 (all links seen, you can write both). - * If you only see l1 and l2, you'll get this behavior: - * linkify(l1) => NULL - * linkify(l2) => l1 - * linkify(NULL) => l2 (at end, you retrieve remaining links) - * As the name suggests, this strategy is used by newer cpio variants. - * It's noticeably more complex for the archiver, slightly more complex - * for the dearchiver than the tar strategy, but makes it straightforward - * to restore a file using any link by simply continuing to scan until - * you see a link that is stored with a body. In contrast, the tar - * strategy requires you to rescan the archive from the beginning to - * correctly extract an arbitrary link. - */ - -__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); -__LA_DECL void archive_entry_linkresolver_set_strategy( - struct archive_entry_linkresolver *, int /* format_code */); -__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); -__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *, - struct archive_entry **, struct archive_entry **); -__LA_DECL struct archive_entry *archive_entry_partial_links( - struct archive_entry_linkresolver *res, unsigned int *links); - -#ifdef __cplusplus -} -#endif - -/* This is meaningless outside of this header. */ -#undef __LA_DECL - -#endif /* !ARCHIVE_ENTRY_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c b/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c deleted file mode 100644 index 77bf38e4..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive_private.h" -#include "archive_entry.h" - -#if defined(_WIN32) && !defined(__CYGWIN__) - -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) - -__inline static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ - } else { - *t = 0; - *ns = 0; - } -} - -void -archive_entry_copy_bhfi(struct archive_entry *entry, - BY_HANDLE_FILE_INFORMATION *bhfi) -{ - time_t secs; - long nsecs; - - fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); - archive_entry_set_atime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); - archive_entry_set_mtime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); - archive_entry_set_birthtime(entry, secs, nsecs); - archive_entry_set_ctime(entry, secs, nsecs); - archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber); - archive_entry_set_ino64(entry, (((int64_t)bhfi->nFileIndexHigh) << 32) - + bhfi->nFileIndexLow); - archive_entry_set_nlink(entry, bhfi->nNumberOfLinks); - archive_entry_set_size(entry, (((int64_t)bhfi->nFileSizeHigh) << 32) - + bhfi->nFileSizeLow); - /* archive_entry_set_mode(entry, st->st_mode); */ -} -#endif diff --git a/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c b/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c deleted file mode 100644 index ac83868e..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c +++ /dev/null @@ -1,83 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_copy_stat.c 189466 2009-03-07 00:52:02Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" - -void -archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st) -{ -#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC - archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec); - archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec); - archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec); -#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec); - archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec); - archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec); -#elif HAVE_STRUCT_STAT_ST_MTIME_NSEC - archive_entry_set_atime(entry, st->st_atime, st->st_atime_nsec); - archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_nsec); - archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_nsec); -#elif HAVE_STRUCT_STAT_ST_MTIME_N - archive_entry_set_atime(entry, st->st_atime, st->st_atime_n); - archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n); - archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n); -#elif HAVE_STRUCT_STAT_ST_UMTIME - archive_entry_set_atime(entry, st->st_atime, st->st_uatime * 1000); - archive_entry_set_ctime(entry, st->st_ctime, st->st_uctime * 1000); - archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime * 1000); -#elif HAVE_STRUCT_STAT_ST_MTIME_USEC - archive_entry_set_atime(entry, st->st_atime, st->st_atime_usec * 1000); - archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_usec * 1000); - archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec * 1000); -#else - archive_entry_set_atime(entry, st->st_atime, 0); - archive_entry_set_ctime(entry, st->st_ctime, 0); - archive_entry_set_mtime(entry, st->st_mtime, 0); -#endif -#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC - archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec); -#elif HAVE_STRUCT_STAT_ST_BIRTHTIME - archive_entry_set_birthtime(entry, st->st_birthtime, 0); -#else - archive_entry_unset_birthtime(entry); -#endif - archive_entry_set_dev(entry, st->st_dev); - archive_entry_set_gid(entry, st->st_gid); - archive_entry_set_uid(entry, st->st_uid); - archive_entry_set_ino(entry, st->st_ino); - archive_entry_set_nlink(entry, st->st_nlink); - archive_entry_set_rdev(entry, st->st_rdev); - archive_entry_set_size(entry, st->st_size); - archive_entry_set_mode(entry, st->st_mode); -} diff --git a/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c b/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c deleted file mode 100644 index c7d59497..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c +++ /dev/null @@ -1,447 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_link_resolver.c 201100 2009-12-28 03:05:31Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" - -/* - * This is mostly a pretty straightforward hash table implementation. - * The only interesting bit is the different strategies used to - * match up links. These strategies match those used by various - * archiving formats: - * tar - content stored with first link, remainder refer back to it. - * This requires us to match each subsequent link up with the - * first appearance. - * cpio - Old cpio just stored body with each link, match-ups were - * implicit. This is trivial. - * new cpio - New cpio only stores body with last link, match-ups - * are implicit. This is actually quite tricky; see the notes - * below. - */ - -/* Users pass us a format code, we translate that into a strategy here. */ -#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE 1 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 2 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 3 - -/* Initial size of link cache. */ -#define links_cache_initial_size 1024 - -struct links_entry { - struct links_entry *next; - struct links_entry *previous; - struct archive_entry *canonical; - struct archive_entry *entry; - size_t hash; - unsigned int links; /* # links not yet seen */ -}; - -struct archive_entry_linkresolver { - struct links_entry **buckets; - struct links_entry *spare; - unsigned long number_entries; - size_t number_buckets; - int strategy; -}; - -#define NEXT_ENTRY_DEFERRED 1 -#define NEXT_ENTRY_PARTIAL 2 -#define NEXT_ENTRY_ALL (NEXT_ENTRY_DEFERRED | NEXT_ENTRY_PARTIAL) - -static struct links_entry *find_entry(struct archive_entry_linkresolver *, - struct archive_entry *); -static void grow_hash(struct archive_entry_linkresolver *); -static struct links_entry *insert_entry(struct archive_entry_linkresolver *, - struct archive_entry *); -static struct links_entry *next_entry(struct archive_entry_linkresolver *, - int); - -struct archive_entry_linkresolver * -archive_entry_linkresolver_new(void) -{ - struct archive_entry_linkresolver *res; - - /* Check for positive power-of-two */ - if (links_cache_initial_size == 0 || - (links_cache_initial_size & (links_cache_initial_size - 1)) != 0) - return (NULL); - - res = calloc(1, sizeof(struct archive_entry_linkresolver)); - if (res == NULL) - return (NULL); - res->number_buckets = links_cache_initial_size; - res->buckets = calloc(res->number_buckets, sizeof(res->buckets[0])); - if (res->buckets == NULL) { - free(res); - return (NULL); - } - return (res); -} - -void -archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res, - int fmt) -{ - int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK; - - switch (fmtbase) { - case ARCHIVE_FORMAT_7ZIP: - case ARCHIVE_FORMAT_AR: - case ARCHIVE_FORMAT_ZIP: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; - break; - case ARCHIVE_FORMAT_CPIO: - switch (fmt) { - case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC: - case ARCHIVE_FORMAT_CPIO_SVR4_CRC: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO; - break; - default: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; - break; - } - break; - case ARCHIVE_FORMAT_MTREE: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE; - break; - case ARCHIVE_FORMAT_ISO9660: - case ARCHIVE_FORMAT_SHAR: - case ARCHIVE_FORMAT_TAR: - case ARCHIVE_FORMAT_XAR: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; - break; - default: - res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; - break; - } -} - -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); - free(res->buckets); - free(res); -} - -void -archive_entry_linkify(struct archive_entry_linkresolver *res, - struct archive_entry **e, struct archive_entry **f) -{ - struct links_entry *le; - struct archive_entry *t; - - *f = NULL; /* Default: Don't return a second entry. */ - - if (*e == NULL) { - le = next_entry(res, NEXT_ENTRY_DEFERRED); - if (le != NULL) { - *e = le->entry; - le->entry = NULL; - } - return; - } - - /* If it has only one link, then we're done. */ - if (archive_entry_nlink(*e) == 1) - return; - /* Directories, devices never have hardlinks. */ - if (archive_entry_filetype(*e) == AE_IFDIR - || archive_entry_filetype(*e) == AE_IFBLK - || archive_entry_filetype(*e) == AE_IFCHR) - return; - - switch (res->strategy) { - case ARCHIVE_ENTRY_LINKIFY_LIKE_TAR: - le = find_entry(res, *e); - if (le != NULL) { - archive_entry_unset_size(*e); - archive_entry_copy_hardlink(*e, - archive_entry_pathname(le->canonical)); - } else - insert_entry(res, *e); - return; - case ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE: - le = find_entry(res, *e); - if (le != NULL) { - archive_entry_copy_hardlink(*e, - archive_entry_pathname(le->canonical)); - } else - insert_entry(res, *e); - return; - case ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO: - /* This one is trivial. */ - return; - case ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO: - le = find_entry(res, *e); - if (le != NULL) { - /* - * Put the new entry in le, return the - * old entry from le. - */ - t = *e; - *e = le->entry; - le->entry = t; - /* Make the old entry into a hardlink. */ - archive_entry_unset_size(*e); - archive_entry_copy_hardlink(*e, - archive_entry_pathname(le->canonical)); - /* If we ran out of links, return the - * final entry as well. */ - if (le->links == 0) { - *f = le->entry; - le->entry = NULL; - } - } else { - /* - * If we haven't seen it, tuck it away - * for future use. - */ - le = insert_entry(res, *e); - if (le == NULL) - /* XXX We should return an error code XXX */ - return; - le->entry = *e; - *e = NULL; - } - return; - default: - break; - } - return; -} - -static struct links_entry * -find_entry(struct archive_entry_linkresolver *res, - struct archive_entry *entry) -{ - struct links_entry *le; - size_t hash, bucket; - dev_t dev; - int64_t ino; - - /* Free a held entry. */ - if (res->spare != NULL) { - archive_entry_free(res->spare->canonical); - archive_entry_free(res->spare->entry); - free(res->spare); - res->spare = NULL; - } - - dev = archive_entry_dev(entry); - ino = archive_entry_ino64(entry); - hash = (size_t)(dev ^ ino); - - /* Try to locate this entry in the links cache. */ - bucket = hash & (res->number_buckets - 1); - for (le = res->buckets[bucket]; le != NULL; le = le->next) { - if (le->hash == hash - && dev == archive_entry_dev(le->canonical) - && ino == archive_entry_ino64(le->canonical)) { - /* - * Decrement link count each time and release - * the entry if it hits zero. This saves - * memory and is necessary for detecting - * missed links. - */ - --le->links; - if (le->links > 0) - return (le); - /* Remove it from this hash bucket. */ - if (le->previous != NULL) - le->previous->next = le->next; - if (le->next != NULL) - le->next->previous = le->previous; - if (res->buckets[bucket] == le) - res->buckets[bucket] = le->next; - res->number_entries--; - /* Defer freeing this entry. */ - res->spare = le; - return (le); - } - } - return (NULL); -} - -static struct links_entry * -next_entry(struct archive_entry_linkresolver *res, int mode) -{ - struct links_entry *le; - size_t bucket; - - /* Free a held entry. */ - if (res->spare != NULL) { - archive_entry_free(res->spare->canonical); - archive_entry_free(res->spare->entry); - free(res->spare); - res->spare = NULL; - } - - /* Look for next non-empty bucket in the links cache. */ - for (bucket = 0; bucket < res->number_buckets; bucket++) { - for (le = res->buckets[bucket]; le != NULL; le = le->next) { - if (le->entry != NULL && - (mode & NEXT_ENTRY_DEFERRED) == 0) - continue; - if (le->entry == NULL && - (mode & NEXT_ENTRY_PARTIAL) == 0) - continue; - /* Remove it from this hash bucket. */ - if (le->next != NULL) - le->next->previous = le->previous; - if (le->previous != NULL) - le->previous->next = le->next; - else - res->buckets[bucket] = le->next; - res->number_entries--; - /* Defer freeing this entry. */ - res->spare = le; - return (le); - } - } - return (NULL); -} - -static struct links_entry * -insert_entry(struct archive_entry_linkresolver *res, - struct archive_entry *entry) -{ - struct links_entry *le; - size_t hash, bucket; - - /* Add this entry to the links cache. */ - le = calloc(1, sizeof(struct links_entry)); - if (le == NULL) - return (NULL); - le->canonical = archive_entry_clone(entry); - - /* If the links cache is getting too full, enlarge the hash table. */ - if (res->number_entries > res->number_buckets * 2) - grow_hash(res); - - hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry)); - bucket = hash & (res->number_buckets - 1); - - /* If we could allocate the entry, record it. */ - if (res->buckets[bucket] != NULL) - res->buckets[bucket]->previous = le; - res->number_entries++; - le->next = res->buckets[bucket]; - le->previous = NULL; - res->buckets[bucket] = le; - le->hash = hash; - le->links = archive_entry_nlink(entry) - 1; - return (le); -} - -static void -grow_hash(struct archive_entry_linkresolver *res) -{ - struct links_entry *le, **new_buckets; - size_t new_size; - size_t i, bucket; - - /* Try to enlarge the bucket list. */ - new_size = res->number_buckets * 2; - if (new_size < res->number_buckets) - return; - new_buckets = calloc(new_size, sizeof(struct links_entry *)); - - if (new_buckets == NULL) - return; - - for (i = 0; i < res->number_buckets; i++) { - while (res->buckets[i] != NULL) { - /* Remove entry from old bucket. */ - le = res->buckets[i]; - res->buckets[i] = le->next; - - /* Add entry to new bucket. */ - bucket = le->hash & (new_size - 1); - - if (new_buckets[bucket] != NULL) - new_buckets[bucket]->previous = le; - le->next = new_buckets[bucket]; - le->previous = NULL; - new_buckets[bucket] = le; - } - } - free(res->buckets); - res->buckets = new_buckets; - res->number_buckets = new_size; -} - -struct archive_entry * -archive_entry_partial_links(struct archive_entry_linkresolver *res, - unsigned int *links) -{ - struct archive_entry *e; - struct links_entry *le; - - /* Free a held entry. */ - if (res->spare != NULL) { - archive_entry_free(res->spare->canonical); - archive_entry_free(res->spare->entry); - free(res->spare); - res->spare = NULL; - } - - le = next_entry(res, NEXT_ENTRY_PARTIAL); - if (le != NULL) { - e = le->canonical; - if (links != NULL) - *links = le->links; - le->canonical = NULL; - } else { - e = NULL; - if (links != NULL) - *links = 0; - } - return (e); -} diff --git a/3rdparty/libarchive/libarchive/archive_entry_locale.h b/3rdparty/libarchive/libarchive/archive_entry_locale.h deleted file mode 100644 index 44550c51..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_locale.h +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * Copyright (c) 2011 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED -#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED - -struct archive_entry; -struct archive_string_conv; - -/* - * Utility functions to set and get entry attributes by translating - * character-set. These are designed for use in format readers and writers. - * - * The return code and interface of these are quite different from other - * functions for archive_entry defined in archive_entry.h. - * Common return code are: - * Return 0 if the string conversion succeeded. - * Return -1 if the string conversion failed. - */ - -#define archive_entry_gname_l _archive_entry_gname_l -int _archive_entry_gname_l(struct archive_entry *, - const char **, size_t *, struct archive_string_conv *); -#define archive_entry_hardlink_l _archive_entry_hardlink_l -int _archive_entry_hardlink_l(struct archive_entry *, - const char **, size_t *, struct archive_string_conv *); -#define archive_entry_pathname_l _archive_entry_pathname_l -int _archive_entry_pathname_l(struct archive_entry *, - const char **, size_t *, struct archive_string_conv *); -#define archive_entry_symlink_l _archive_entry_symlink_l -int _archive_entry_symlink_l(struct archive_entry *, - const char **, size_t *, struct archive_string_conv *); -#define archive_entry_uname_l _archive_entry_uname_l -int _archive_entry_uname_l(struct archive_entry *, - const char **, size_t *, struct archive_string_conv *); -#define archive_entry_acl_text_l _archive_entry_acl_text_l -int _archive_entry_acl_text_l(struct archive_entry *, int, -const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED; -#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l -char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int, - struct archive_string_conv *); -#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l -int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text, - int type, struct archive_string_conv *); -#define archive_entry_copy_gname_l _archive_entry_copy_gname_l -int _archive_entry_copy_gname_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); -#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l -int _archive_entry_copy_hardlink_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); -#define archive_entry_copy_link_l _archive_entry_copy_link_l -int _archive_entry_copy_link_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); -#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l -int _archive_entry_copy_pathname_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); -#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l -int _archive_entry_copy_symlink_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); -#define archive_entry_copy_uname_l _archive_entry_copy_uname_l -int _archive_entry_copy_uname_l(struct archive_entry *, - const char *, size_t, struct archive_string_conv *); - -#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_entry_private.h b/3rdparty/libarchive/libarchive/archive_entry_private.h deleted file mode 100644 index c69233e6..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_private.h +++ /dev/null @@ -1,181 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_entry_private.h 201096 2009-12-28 02:41:27Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED -#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED - -#include "archive_acl_private.h" -#include "archive_string.h" - -struct ae_xattr { - struct ae_xattr *next; - - char *name; - void *value; - size_t size; -}; - -struct ae_sparse { - struct ae_sparse *next; - - int64_t offset; - int64_t length; -}; - -/* - * Description of an archive entry. - * - * Basically, this is a "struct stat" with a few text fields added in. - * - * TODO: Add "comment", "charset", and possibly other entries - * that are supported by "pax interchange" format. However, GNU, ustar, - * cpio, and other variants don't support these features, so they're not an - * excruciatingly high priority right now. - * - * TODO: "pax interchange" format allows essentially arbitrary - * key/value attributes to be attached to any entry. Supporting - * such extensions may make this library useful for special - * applications (e.g., a package manager could attach special - * package-management attributes to each entry). There are tricky - * API issues involved, so this is not going to happen until - * there's a real demand for it. - * - * TODO: Design a good API for handling sparse files. - */ -struct archive_entry { - struct archive *archive; - - /* - * Note that ae_stat.st_mode & AE_IFMT can be 0! - * - * This occurs when the actual file type of the object is not - * in the archive. For example, 'tar' archives store - * hardlinks without marking the type of the underlying - * object. - */ - - /* - * We have a "struct aest" for holding file metadata rather than just - * a "struct stat" because on some platforms the "struct stat" has - * fields which are too narrow to hold the range of possible values; - * we don't want to lose information if we read an archive and write - * out another (e.g., in "tar -cf new.tar @old.tar"). - * - * The "stat" pointer points to some form of platform-specific struct - * stat; it is declared as a void * rather than a struct stat * as - * some platforms have multiple varieties of stat structures. - */ - void *stat; - int stat_valid; /* Set to 0 whenever a field in aest changes. */ - - struct aest { - int64_t aest_atime; - uint32_t aest_atime_nsec; - int64_t aest_ctime; - uint32_t aest_ctime_nsec; - int64_t aest_mtime; - uint32_t aest_mtime_nsec; - int64_t aest_birthtime; - uint32_t aest_birthtime_nsec; - int64_t aest_gid; - int64_t aest_ino; - uint32_t aest_nlink; - uint64_t aest_size; - int64_t aest_uid; - /* - * Because converting between device codes and - * major/minor values is platform-specific and - * inherently a bit risky, we only do that conversion - * lazily. That way, we will do a better job of - * preserving information in those cases where no - * conversion is actually required. - */ - int aest_dev_is_broken_down; - dev_t aest_dev; - dev_t aest_devmajor; - dev_t aest_devminor; - int aest_rdev_is_broken_down; - dev_t aest_rdev; - dev_t aest_rdevmajor; - dev_t aest_rdevminor; - } ae_stat; - - int ae_set; /* bitmap of fields that are currently set */ -#define AE_SET_HARDLINK 1 -#define AE_SET_SYMLINK 2 -#define AE_SET_ATIME 4 -#define AE_SET_CTIME 8 -#define AE_SET_MTIME 16 -#define AE_SET_BIRTHTIME 32 -#define AE_SET_SIZE 64 -#define AE_SET_INO 128 -#define AE_SET_DEV 256 - - /* - * Use aes here so that we get transparent mbs<->wcs conversions. - */ - struct archive_mstring ae_fflags_text; /* Text fflags per fflagstostr(3) */ - unsigned long ae_fflags_set; /* Bitmap fflags */ - unsigned long ae_fflags_clear; - struct archive_mstring ae_gname; /* Name of owning group */ - struct archive_mstring ae_hardlink; /* Name of target for hardlink */ - struct archive_mstring ae_pathname; /* Name of entry */ - struct archive_mstring ae_symlink; /* symlink contents */ - struct archive_mstring ae_uname; /* Name of owner */ - - /* Not used within libarchive; useful for some clients. */ - struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */ - -#define AE_ENCRYPTION_NONE 0 -#define AE_ENCRYPTION_DATA 1 -#define AE_ENCRYPTION_METADATA 2 - char encryption; - - void *mac_metadata; - size_t mac_metadata_size; - - /* ACL support. */ - struct archive_acl acl; - - /* extattr support. */ - struct ae_xattr *xattr_head; - struct ae_xattr *xattr_p; - - /* sparse support. */ - struct ae_sparse *sparse_head; - struct ae_sparse *sparse_tail; - struct ae_sparse *sparse_p; - - /* Miscellaneous. */ - char strmode[12]; -}; - -#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_entry_sparse.c b/3rdparty/libarchive/libarchive/archive_entry_sparse.c deleted file mode 100644 index 74917b37..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_sparse.c +++ /dev/null @@ -1,156 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2010-2011 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_entry_private.h" - -/* - * sparse handling - */ - -void -archive_entry_sparse_clear(struct archive_entry *entry) -{ - struct ae_sparse *sp; - - while (entry->sparse_head != NULL) { - sp = entry->sparse_head->next; - free(entry->sparse_head); - entry->sparse_head = sp; - } - entry->sparse_tail = NULL; -} - -void -archive_entry_sparse_add_entry(struct archive_entry *entry, - la_int64_t offset, la_int64_t length) -{ - struct ae_sparse *sp; - - if (offset < 0 || length < 0) - /* Invalid value */ - return; - if (offset > INT64_MAX - length || - offset + length > archive_entry_size(entry)) - /* A value of "length" parameter is too large. */ - return; - if ((sp = entry->sparse_tail) != NULL) { - if (sp->offset + sp->length > offset) - /* Invalid value. */ - return; - if (sp->offset + sp->length == offset) { - if (sp->offset + sp->length + length < 0) - /* A value of "length" parameter is - * too large. */ - return; - /* Expand existing sparse block size. */ - sp->length += length; - return; - } - } - - if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL) - /* XXX Error XXX */ - return; - - sp->offset = offset; - sp->length = length; - sp->next = NULL; - - if (entry->sparse_head == NULL) - entry->sparse_head = entry->sparse_tail = sp; - else { - /* Add a new sparse block to the tail of list. */ - if (entry->sparse_tail != NULL) - entry->sparse_tail->next = sp; - entry->sparse_tail = sp; - } -} - - -/* - * returns number of the sparse entries - */ -int -archive_entry_sparse_count(struct archive_entry *entry) -{ - struct ae_sparse *sp; - int count = 0; - - for (sp = entry->sparse_head; sp != NULL; sp = sp->next) - count++; - - /* - * Sanity check if this entry is exactly sparse. - * If amount of sparse blocks is just one and it indicates the whole - * file data, we should remove it and return zero. - */ - if (count == 1) { - sp = entry->sparse_head; - if (sp->offset == 0 && - sp->length >= archive_entry_size(entry)) { - count = 0; - archive_entry_sparse_clear(entry); - } - } - - return (count); -} - -int -archive_entry_sparse_reset(struct archive_entry * entry) -{ - entry->sparse_p = entry->sparse_head; - - return archive_entry_sparse_count(entry); -} - -int -archive_entry_sparse_next(struct archive_entry * entry, - la_int64_t *offset, la_int64_t *length) -{ - if (entry->sparse_p) { - *offset = entry->sparse_p->offset; - *length = entry->sparse_p->length; - - entry->sparse_p = entry->sparse_p->next; - - return (ARCHIVE_OK); - } else { - *offset = 0; - *length = 0; - return (ARCHIVE_WARN); - } -} - -/* - * end of sparse handling - */ diff --git a/3rdparty/libarchive/libarchive/archive_entry_stat.c b/3rdparty/libarchive/libarchive/archive_entry_stat.c deleted file mode 100644 index 71a407b1..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_stat.c +++ /dev/null @@ -1,118 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_stat.c 201100 2009-12-28 03:05:31Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif - -#include "archive_entry.h" -#include "archive_entry_private.h" - -const struct stat * -archive_entry_stat(struct archive_entry *entry) -{ - struct stat *st; - if (entry->stat == NULL) { - entry->stat = calloc(1, sizeof(*st)); - if (entry->stat == NULL) - return (NULL); - entry->stat_valid = 0; - } - - /* - * If none of the underlying fields have been changed, we - * don't need to regenerate. In theory, we could use a bitmap - * here to flag only those items that have changed, but the - * extra complexity probably isn't worth it. It will be very - * rare for anyone to change just one field then request a new - * stat structure. - */ - if (entry->stat_valid) - return (entry->stat); - - st = entry->stat; - /* - * Use the public interfaces to extract items, so that - * the appropriate conversions get invoked. - */ - st->st_atime = archive_entry_atime(entry); -#if HAVE_STRUCT_STAT_ST_BIRTHTIME - st->st_birthtime = archive_entry_birthtime(entry); -#endif - st->st_ctime = archive_entry_ctime(entry); - st->st_mtime = archive_entry_mtime(entry); - st->st_dev = archive_entry_dev(entry); - st->st_gid = (gid_t)archive_entry_gid(entry); - st->st_uid = (uid_t)archive_entry_uid(entry); - st->st_ino = (ino_t)archive_entry_ino64(entry); - st->st_nlink = archive_entry_nlink(entry); - st->st_rdev = archive_entry_rdev(entry); - st->st_size = (off_t)archive_entry_size(entry); - st->st_mode = archive_entry_mode(entry); - - /* - * On systems that support high-res timestamps, copy that - * information into struct stat. - */ -#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC - st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry); - st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry); - st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry); -#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - st->st_atim.tv_nsec = archive_entry_atime_nsec(entry); - st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry); - st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry); -#elif HAVE_STRUCT_STAT_ST_MTIME_N - st->st_atime_n = archive_entry_atime_nsec(entry); - st->st_ctime_n = archive_entry_ctime_nsec(entry); - st->st_mtime_n = archive_entry_mtime_nsec(entry); -#elif HAVE_STRUCT_STAT_ST_UMTIME - st->st_uatime = archive_entry_atime_nsec(entry) / 1000; - st->st_uctime = archive_entry_ctime_nsec(entry) / 1000; - st->st_umtime = archive_entry_mtime_nsec(entry) / 1000; -#elif HAVE_STRUCT_STAT_ST_MTIME_USEC - st->st_atime_usec = archive_entry_atime_nsec(entry) / 1000; - st->st_ctime_usec = archive_entry_ctime_nsec(entry) / 1000; - st->st_mtime_usec = archive_entry_mtime_nsec(entry) / 1000; -#endif -#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC - st->st_birthtimespec.tv_nsec = archive_entry_birthtime_nsec(entry); -#endif - - /* - * TODO: On Linux, store 32 or 64 here depending on whether - * the cached stat structure is a stat32 or a stat64. This - * will allow us to support both variants interchangeably. - */ - entry->stat_valid = 1; - - return (st); -} diff --git a/3rdparty/libarchive/libarchive/archive_entry_strmode.c b/3rdparty/libarchive/libarchive/archive_entry_strmode.c deleted file mode 100644 index af2517a3..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_strmode.c +++ /dev/null @@ -1,87 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.4 2008/06/15 05:14:01 kientzle Exp $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive_entry.h" -#include "archive_entry_private.h" - -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; - 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; - case AE_IFCHR: bp[0] = 'c'; break; - case AE_IFDIR: bp[0] = 'd'; break; - case AE_IFLNK: bp[0] = 'l'; break; - 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; - } - } - - for (i = 0; i < 9; i++) - if (!(mode & permbits[i])) - bp[i+1] = '-'; - - 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] = '+'; - - return (bp); -} diff --git a/3rdparty/libarchive/libarchive/archive_entry_xattr.c b/3rdparty/libarchive/libarchive/archive_entry_xattr.c deleted file mode 100644 index 5fe726b9..00000000 --- a/3rdparty/libarchive/libarchive/archive_entry_xattr.c +++ /dev/null @@ -1,156 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_xattr.c 201096 2009-12-28 02:41:27Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_LINUX_FS_H -#include /* for Linux file flags */ -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include /* for Linux file flags */ -#endif -#include -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_entry_private.h" - -/* - * extended attribute handling - */ - -void -archive_entry_xattr_clear(struct archive_entry *entry) -{ - struct ae_xattr *xp; - - while (entry->xattr_head != NULL) { - xp = entry->xattr_head->next; - free(entry->xattr_head->name); - free(entry->xattr_head->value); - free(entry->xattr_head); - entry->xattr_head = xp; - } - - entry->xattr_head = NULL; -} - -void -archive_entry_xattr_add_entry(struct archive_entry *entry, - const char *name, const void *value, size_t size) -{ - struct ae_xattr *xp; - - if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL) - __archive_errx(1, "Out of memory"); - - 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; - - xp->next = entry->xattr_head; - entry->xattr_head = xp; -} - - -/* - * returns number of the extended attribute entries - */ -int -archive_entry_xattr_count(struct archive_entry *entry) -{ - struct ae_xattr *xp; - int count = 0; - - for (xp = entry->xattr_head; xp != NULL; xp = xp->next) - count++; - - return count; -} - -int -archive_entry_xattr_reset(struct archive_entry * entry) -{ - entry->xattr_p = entry->xattr_head; - - return archive_entry_xattr_count(entry); -} - -int -archive_entry_xattr_next(struct archive_entry * entry, - const char **name, const void **value, size_t *size) -{ - if (entry->xattr_p) { - *name = entry->xattr_p->name; - *value = entry->xattr_p->value; - *size = entry->xattr_p->size; - - entry->xattr_p = entry->xattr_p->next; - - return (ARCHIVE_OK); - } else { - *name = NULL; - *value = NULL; - *size = (size_t)0; - return (ARCHIVE_WARN); - } -} - -/* - * end of xattr handling - */ diff --git a/3rdparty/libarchive/libarchive/archive_getdate.c b/3rdparty/libarchive/libarchive/archive_getdate.c deleted file mode 100644 index 030c083c..00000000 --- a/3rdparty/libarchive/libarchive/archive_getdate.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * This code is in the public domain and has no copyright. - * - * This is a plain C recursive-descent translation of an old - * public-domain YACC grammar that has been used for parsing dates in - * very many open-source projects. - * - * Since the original authors were generous enough to donate their - * work to the public domain, I feel compelled to match their - * generosity. - * - * Tim Kientzle, February 2009. - */ - -/* - * Header comment from original getdate.y: - */ - -/* -** Originally written by Steven M. Bellovin while -** at the University of North Carolina at Chapel Hill. Later tweaked by -** a couple of people on Usenet. Completely overhauled by Rich $alz -** and Jim Berets in August, 1990; -** -** This grammar has 10 shift/reduce conflicts. -** -** This code is in the public domain and has no copyright. -*/ - -#ifdef __FreeBSD__ -#include -__FBSDID("$FreeBSD$"); -#endif - -#include -#include -#include -#include -#include - -#define __LIBARCHIVE_BUILD 1 -#include "archive_getdate.h" - -/* Basic time units. */ -#define EPOCH 1970 -#define MINUTE (60L) -#define HOUR (60L * MINUTE) -#define DAY (24L * HOUR) - -/* Daylight-savings mode: on, off, or not yet known. */ -enum DSTMODE { DSTon, DSToff, DSTmaybe }; -/* Meridian: am or pm. */ -enum { tAM, tPM }; -/* Token types returned by nexttoken() */ -enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT, - tUNUMBER, tZONE, tDST }; -struct token { int token; time_t value; }; - -/* - * Parser state. - */ -struct gdstate { - struct token *tokenp; /* Pointer to next token. */ - /* HaveXxxx counts how many of this kind of phrase we've seen; - * it's a fatal error to have more than one time, zone, day, - * or date phrase. */ - int HaveYear; - int HaveMonth; - int HaveDay; - int HaveWeekDay; /* Day of week */ - int HaveTime; /* Hour/minute/second */ - int HaveZone; /* timezone and/or DST info */ - int HaveRel; /* time offset; we can have more than one */ - /* Absolute time values. */ - time_t Timezone; /* Seconds offset from GMT */ - time_t Day; - time_t Hour; - time_t Minutes; - time_t Month; - time_t Seconds; - time_t Year; - /* DST selection */ - enum DSTMODE DSTmode; - /* Day of week accounting, e.g., "3rd Tuesday" */ - time_t DayOrdinal; /* "3" in "3rd Tuesday" */ - time_t DayNumber; /* "Tuesday" in "3rd Tuesday" */ - /* Relative time values: hour/day/week offsets are measured in - * seconds, month/year are counted in months. */ - time_t RelMonth; - time_t RelSeconds; -}; - -/* - * A series of functions that recognize certain common time phrases. - * Each function returns 1 if it managed to make sense of some of the - * tokens, zero otherwise. - */ - -/* - * hour:minute or hour:minute:second with optional AM, PM, or numeric - * timezone offset - */ -static int -timephrase(struct gdstate *gds) -{ - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == ':' - && gds->tokenp[2].token == tUNUMBER - && gds->tokenp[3].token == ':' - && gds->tokenp[4].token == tUNUMBER) { - /* "12:14:18" or "22:08:07" */ - ++gds->HaveTime; - gds->Hour = gds->tokenp[0].value; - gds->Minutes = gds->tokenp[2].value; - gds->Seconds = gds->tokenp[4].value; - gds->tokenp += 5; - } - else if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == ':' - && gds->tokenp[2].token == tUNUMBER) { - /* "12:14" or "22:08" */ - ++gds->HaveTime; - gds->Hour = gds->tokenp[0].value; - gds->Minutes = gds->tokenp[2].value; - gds->Seconds = 0; - gds->tokenp += 3; - } - else if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tAMPM) { - /* "7" is a time if it's followed by "am" or "pm" */ - ++gds->HaveTime; - gds->Hour = gds->tokenp[0].value; - gds->Minutes = gds->Seconds = 0; - /* We'll handle the AM/PM below. */ - gds->tokenp += 1; - } else { - /* We can't handle this. */ - return 0; - } - - if (gds->tokenp[0].token == tAMPM) { - /* "7:12pm", "12:20:13am" */ - if (gds->Hour == 12) - gds->Hour = 0; - if (gds->tokenp[0].value == tPM) - gds->Hour += 12; - gds->tokenp += 1; - } - if (gds->tokenp[0].token == '+' - && gds->tokenp[1].token == tUNUMBER) { - /* "7:14+0700" */ - gds->HaveZone++; - gds->DSTmode = DSToff; - gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR - + (gds->tokenp[1].value % 100) * MINUTE); - gds->tokenp += 2; - } - if (gds->tokenp[0].token == '-' - && gds->tokenp[1].token == tUNUMBER) { - /* "19:14:12-0530" */ - gds->HaveZone++; - gds->DSTmode = DSToff; - gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR - + (gds->tokenp[1].value % 100) * MINUTE); - gds->tokenp += 2; - } - return 1; -} - -/* - * Timezone name, possibly including DST. - */ -static int -zonephrase(struct gdstate *gds) -{ - if (gds->tokenp[0].token == tZONE - && gds->tokenp[1].token == tDST) { - gds->HaveZone++; - gds->Timezone = gds->tokenp[0].value; - gds->DSTmode = DSTon; - gds->tokenp += 1; - return 1; - } - - if (gds->tokenp[0].token == tZONE) { - gds->HaveZone++; - gds->Timezone = gds->tokenp[0].value; - gds->DSTmode = DSToff; - gds->tokenp += 1; - return 1; - } - - if (gds->tokenp[0].token == tDAYZONE) { - gds->HaveZone++; - gds->Timezone = gds->tokenp[0].value; - gds->DSTmode = DSTon; - gds->tokenp += 1; - return 1; - } - return 0; -} - -/* - * Year/month/day in various combinations. - */ -static int -datephrase(struct gdstate *gds) -{ - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == '/' - && gds->tokenp[2].token == tUNUMBER - && gds->tokenp[3].token == '/' - && gds->tokenp[4].token == tUNUMBER) { - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - if (gds->tokenp[0].value >= 13) { - /* First number is big: 2004/01/29, 99/02/17 */ - gds->Year = gds->tokenp[0].value; - gds->Month = gds->tokenp[2].value; - gds->Day = gds->tokenp[4].value; - } else if ((gds->tokenp[4].value >= 13) - || (gds->tokenp[2].value >= 13)) { - /* Last number is big: 01/07/98 */ - /* Middle number is big: 01/29/04 */ - gds->Month = gds->tokenp[0].value; - gds->Day = gds->tokenp[2].value; - gds->Year = gds->tokenp[4].value; - } else { - /* No significant clues: 02/03/04 */ - gds->Month = gds->tokenp[0].value; - gds->Day = gds->tokenp[2].value; - gds->Year = gds->tokenp[4].value; - } - gds->tokenp += 5; - return 1; - } - - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == '/' - && gds->tokenp[2].token == tUNUMBER) { - /* "1/15" */ - gds->HaveMonth++; - gds->HaveDay++; - gds->Month = gds->tokenp[0].value; - gds->Day = gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == '-' - && gds->tokenp[2].token == tUNUMBER - && gds->tokenp[3].token == '-' - && gds->tokenp[4].token == tUNUMBER) { - /* ISO 8601 format. yyyy-mm-dd. */ - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - gds->Year = gds->tokenp[0].value; - gds->Month = gds->tokenp[2].value; - gds->Day = gds->tokenp[4].value; - gds->tokenp += 5; - return 1; - } - - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == '-' - && gds->tokenp[2].token == tMONTH - && gds->tokenp[3].token == '-' - && gds->tokenp[4].token == tUNUMBER) { - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - if (gds->tokenp[0].value > 31) { - /* e.g. 1992-Jun-17 */ - gds->Year = gds->tokenp[0].value; - gds->Month = gds->tokenp[2].value; - gds->Day = gds->tokenp[4].value; - } else { - /* e.g. 17-JUN-1992. */ - gds->Day = gds->tokenp[0].value; - gds->Month = gds->tokenp[2].value; - gds->Year = gds->tokenp[4].value; - } - gds->tokenp += 5; - return 1; - } - - if (gds->tokenp[0].token == tMONTH - && gds->tokenp[1].token == tUNUMBER - && gds->tokenp[2].token == ',' - && gds->tokenp[3].token == tUNUMBER) { - /* "June 17, 2001" */ - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - gds->Month = gds->tokenp[0].value; - gds->Day = gds->tokenp[1].value; - gds->Year = gds->tokenp[3].value; - gds->tokenp += 4; - return 1; - } - - if (gds->tokenp[0].token == tMONTH - && gds->tokenp[1].token == tUNUMBER) { - /* "May 3" */ - gds->HaveMonth++; - gds->HaveDay++; - gds->Month = gds->tokenp[0].value; - gds->Day = gds->tokenp[1].value; - gds->tokenp += 2; - return 1; - } - - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tMONTH - && gds->tokenp[2].token == tUNUMBER) { - /* "12 Sept 1997" */ - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - gds->Day = gds->tokenp[0].value; - gds->Month = gds->tokenp[1].value; - gds->Year = gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tMONTH) { - /* "12 Sept" */ - gds->HaveMonth++; - gds->HaveDay++; - gds->Day = gds->tokenp[0].value; - gds->Month = gds->tokenp[1].value; - gds->tokenp += 2; - return 1; - } - - return 0; -} - -/* - * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc. - */ -static int -relunitphrase(struct gdstate *gds) -{ - if (gds->tokenp[0].token == '-' - && gds->tokenp[1].token == tUNUMBER - && gds->tokenp[2].token == tSEC_UNIT) { - /* "-3 hours" */ - gds->HaveRel++; - gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - if (gds->tokenp[0].token == '+' - && gds->tokenp[1].token == tUNUMBER - && gds->tokenp[2].token == tSEC_UNIT) { - /* "+1 minute" */ - gds->HaveRel++; - gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tSEC_UNIT) { - /* "1 day" */ - gds->HaveRel++; - gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value; - gds->tokenp += 2; - return 1; - } - if (gds->tokenp[0].token == '-' - && gds->tokenp[1].token == tUNUMBER - && gds->tokenp[2].token == tMONTH_UNIT) { - /* "-3 months" */ - gds->HaveRel++; - gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - if (gds->tokenp[0].token == '+' - && gds->tokenp[1].token == tUNUMBER - && gds->tokenp[2].token == tMONTH_UNIT) { - /* "+5 years" */ - gds->HaveRel++; - gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value; - gds->tokenp += 3; - return 1; - } - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tMONTH_UNIT) { - /* "2 years" */ - gds->HaveRel++; - gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value; - gds->tokenp += 2; - return 1; - } - if (gds->tokenp[0].token == tSEC_UNIT) { - /* "now", "tomorrow" */ - gds->HaveRel++; - gds->RelSeconds += gds->tokenp[0].value; - gds->tokenp += 1; - return 1; - } - if (gds->tokenp[0].token == tMONTH_UNIT) { - /* "month" */ - gds->HaveRel++; - gds->RelMonth += gds->tokenp[0].value; - gds->tokenp += 1; - return 1; - } - return 0; -} - -/* - * Day of the week specification. - */ -static int -dayphrase(struct gdstate *gds) -{ - if (gds->tokenp[0].token == tDAY) { - /* "tues", "wednesday," */ - gds->HaveWeekDay++; - gds->DayOrdinal = 1; - gds->DayNumber = gds->tokenp[0].value; - gds->tokenp += 1; - if (gds->tokenp[0].token == ',') - gds->tokenp += 1; - return 1; - } - if (gds->tokenp[0].token == tUNUMBER - && gds->tokenp[1].token == tDAY) { - /* "second tues" "3 wed" */ - gds->HaveWeekDay++; - gds->DayOrdinal = gds->tokenp[0].value; - gds->DayNumber = gds->tokenp[1].value; - gds->tokenp += 2; - return 1; - } - return 0; -} - -/* - * Try to match a phrase using one of the above functions. - * This layer also deals with a couple of generic issues. - */ -static int -phrase(struct gdstate *gds) -{ - if (timephrase(gds)) - return 1; - if (zonephrase(gds)) - return 1; - if (datephrase(gds)) - return 1; - if (dayphrase(gds)) - return 1; - if (relunitphrase(gds)) { - if (gds->tokenp[0].token == tAGO) { - gds->RelSeconds = -gds->RelSeconds; - gds->RelMonth = -gds->RelMonth; - gds->tokenp += 1; - } - return 1; - } - - /* Bare numbers sometimes have meaning. */ - if (gds->tokenp[0].token == tUNUMBER) { - if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) { - gds->HaveYear++; - gds->Year = gds->tokenp[0].value; - gds->tokenp += 1; - return 1; - } - - if(gds->tokenp[0].value > 10000) { - /* "20040301" */ - gds->HaveYear++; - gds->HaveMonth++; - gds->HaveDay++; - gds->Day= (gds->tokenp[0].value)%100; - gds->Month= (gds->tokenp[0].value/100)%100; - gds->Year = gds->tokenp[0].value/10000; - gds->tokenp += 1; - return 1; - } - - if (gds->tokenp[0].value < 24) { - gds->HaveTime++; - gds->Hour = gds->tokenp[0].value; - gds->Minutes = 0; - gds->Seconds = 0; - gds->tokenp += 1; - return 1; - } - - if ((gds->tokenp[0].value / 100 < 24) - && (gds->tokenp[0].value % 100 < 60)) { - /* "513" is same as "5:13" */ - gds->Hour = gds->tokenp[0].value / 100; - gds->Minutes = gds->tokenp[0].value % 100; - gds->Seconds = 0; - gds->tokenp += 1; - return 1; - } - } - - return 0; -} - -/* - * A dictionary of time words. - */ -static struct LEXICON { - size_t abbrev; - const char *name; - int type; - time_t value; -} const TimeWords[] = { - /* am/pm */ - { 0, "am", tAMPM, tAM }, - { 0, "pm", tAMPM, tPM }, - - /* Month names. */ - { 3, "january", tMONTH, 1 }, - { 3, "february", tMONTH, 2 }, - { 3, "march", tMONTH, 3 }, - { 3, "april", tMONTH, 4 }, - { 3, "may", tMONTH, 5 }, - { 3, "june", tMONTH, 6 }, - { 3, "july", tMONTH, 7 }, - { 3, "august", tMONTH, 8 }, - { 3, "september", tMONTH, 9 }, - { 3, "october", tMONTH, 10 }, - { 3, "november", tMONTH, 11 }, - { 3, "december", tMONTH, 12 }, - - /* Days of the week. */ - { 2, "sunday", tDAY, 0 }, - { 3, "monday", tDAY, 1 }, - { 2, "tuesday", tDAY, 2 }, - { 3, "wednesday", tDAY, 3 }, - { 2, "thursday", tDAY, 4 }, - { 2, "friday", tDAY, 5 }, - { 2, "saturday", tDAY, 6 }, - - /* Timezones: Offsets are in seconds. */ - { 0, "gmt", tZONE, 0*HOUR }, /* Greenwich Mean */ - { 0, "ut", tZONE, 0*HOUR }, /* Universal (Coordinated) */ - { 0, "utc", tZONE, 0*HOUR }, - { 0, "wet", tZONE, 0*HOUR }, /* Western European */ - { 0, "bst", tDAYZONE, 0*HOUR }, /* British Summer */ - { 0, "wat", tZONE, 1*HOUR }, /* West Africa */ - { 0, "at", tZONE, 2*HOUR }, /* Azores */ - /* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */ - /* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/ - { 0, "nft", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland */ - { 0, "nst", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Standard */ - { 0, "ndt", tDAYZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Daylight */ - { 0, "ast", tZONE, 4*HOUR }, /* Atlantic Standard */ - { 0, "adt", tDAYZONE, 4*HOUR }, /* Atlantic Daylight */ - { 0, "est", tZONE, 5*HOUR }, /* Eastern Standard */ - { 0, "edt", tDAYZONE, 5*HOUR }, /* Eastern Daylight */ - { 0, "cst", tZONE, 6*HOUR }, /* Central Standard */ - { 0, "cdt", tDAYZONE, 6*HOUR }, /* Central Daylight */ - { 0, "mst", tZONE, 7*HOUR }, /* Mountain Standard */ - { 0, "mdt", tDAYZONE, 7*HOUR }, /* Mountain Daylight */ - { 0, "pst", tZONE, 8*HOUR }, /* Pacific Standard */ - { 0, "pdt", tDAYZONE, 8*HOUR }, /* Pacific Daylight */ - { 0, "yst", tZONE, 9*HOUR }, /* Yukon Standard */ - { 0, "ydt", tDAYZONE, 9*HOUR }, /* Yukon Daylight */ - { 0, "hst", tZONE, 10*HOUR }, /* Hawaii Standard */ - { 0, "hdt", tDAYZONE, 10*HOUR }, /* Hawaii Daylight */ - { 0, "cat", tZONE, 10*HOUR }, /* Central Alaska */ - { 0, "ahst", tZONE, 10*HOUR }, /* Alaska-Hawaii Standard */ - { 0, "nt", tZONE, 11*HOUR }, /* Nome */ - { 0, "idlw", tZONE, 12*HOUR }, /* Intl Date Line West */ - { 0, "cet", tZONE, -1*HOUR }, /* Central European */ - { 0, "met", tZONE, -1*HOUR }, /* Middle European */ - { 0, "mewt", tZONE, -1*HOUR }, /* Middle European Winter */ - { 0, "mest", tDAYZONE, -1*HOUR }, /* Middle European Summer */ - { 0, "swt", tZONE, -1*HOUR }, /* Swedish Winter */ - { 0, "sst", tDAYZONE, -1*HOUR }, /* Swedish Summer */ - { 0, "fwt", tZONE, -1*HOUR }, /* French Winter */ - { 0, "fst", tDAYZONE, -1*HOUR }, /* French Summer */ - { 0, "eet", tZONE, -2*HOUR }, /* Eastern Eur, USSR Zone 1 */ - { 0, "bt", tZONE, -3*HOUR }, /* Baghdad, USSR Zone 2 */ - { 0, "it", tZONE, -3*HOUR-30*MINUTE },/* Iran */ - { 0, "zp4", tZONE, -4*HOUR }, /* USSR Zone 3 */ - { 0, "zp5", tZONE, -5*HOUR }, /* USSR Zone 4 */ - { 0, "ist", tZONE, -5*HOUR-30*MINUTE },/* Indian Standard */ - { 0, "zp6", tZONE, -6*HOUR }, /* USSR Zone 5 */ - /* { 0, "nst", tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */ - /* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */ - { 0, "wast", tZONE, -7*HOUR }, /* West Australian Standard */ - { 0, "wadt", tDAYZONE, -7*HOUR }, /* West Australian Daylight */ - { 0, "jt", tZONE, -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/ - { 0, "cct", tZONE, -8*HOUR }, /* China Coast, USSR Zone 7 */ - { 0, "jst", tZONE, -9*HOUR }, /* Japan Std, USSR Zone 8 */ - { 0, "cast", tZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Std */ - { 0, "cadt", tDAYZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */ - { 0, "east", tZONE, -10*HOUR }, /* Eastern Australian Std */ - { 0, "eadt", tDAYZONE, -10*HOUR }, /* Eastern Australian Daylt */ - { 0, "gst", tZONE, -10*HOUR }, /* Guam Std, USSR Zone 9 */ - { 0, "nzt", tZONE, -12*HOUR }, /* New Zealand */ - { 0, "nzst", tZONE, -12*HOUR }, /* New Zealand Standard */ - { 0, "nzdt", tDAYZONE, -12*HOUR }, /* New Zealand Daylight */ - { 0, "idle", tZONE, -12*HOUR }, /* Intl Date Line East */ - - { 0, "dst", tDST, 0 }, - - /* Time units. */ - { 4, "years", tMONTH_UNIT, 12 }, - { 5, "months", tMONTH_UNIT, 1 }, - { 9, "fortnights", tSEC_UNIT, 14 * DAY }, - { 4, "weeks", tSEC_UNIT, 7 * DAY }, - { 3, "days", tSEC_UNIT, DAY }, - { 4, "hours", tSEC_UNIT, HOUR }, - { 3, "minutes", tSEC_UNIT, MINUTE }, - { 3, "seconds", tSEC_UNIT, 1 }, - - /* Relative-time words. */ - { 0, "tomorrow", tSEC_UNIT, DAY }, - { 0, "yesterday", tSEC_UNIT, -DAY }, - { 0, "today", tSEC_UNIT, 0 }, - { 0, "now", tSEC_UNIT, 0 }, - { 0, "last", tUNUMBER, -1 }, - { 0, "this", tSEC_UNIT, 0 }, - { 0, "next", tUNUMBER, 2 }, - { 0, "first", tUNUMBER, 1 }, - { 0, "1st", tUNUMBER, 1 }, -/* { 0, "second", tUNUMBER, 2 }, */ - { 0, "2nd", tUNUMBER, 2 }, - { 0, "third", tUNUMBER, 3 }, - { 0, "3rd", tUNUMBER, 3 }, - { 0, "fourth", tUNUMBER, 4 }, - { 0, "4th", tUNUMBER, 4 }, - { 0, "fifth", tUNUMBER, 5 }, - { 0, "5th", tUNUMBER, 5 }, - { 0, "sixth", tUNUMBER, 6 }, - { 0, "seventh", tUNUMBER, 7 }, - { 0, "eighth", tUNUMBER, 8 }, - { 0, "ninth", tUNUMBER, 9 }, - { 0, "tenth", tUNUMBER, 10 }, - { 0, "eleventh", tUNUMBER, 11 }, - { 0, "twelfth", tUNUMBER, 12 }, - { 0, "ago", tAGO, 1 }, - - /* Military timezones. */ - { 0, "a", tZONE, 1*HOUR }, - { 0, "b", tZONE, 2*HOUR }, - { 0, "c", tZONE, 3*HOUR }, - { 0, "d", tZONE, 4*HOUR }, - { 0, "e", tZONE, 5*HOUR }, - { 0, "f", tZONE, 6*HOUR }, - { 0, "g", tZONE, 7*HOUR }, - { 0, "h", tZONE, 8*HOUR }, - { 0, "i", tZONE, 9*HOUR }, - { 0, "k", tZONE, 10*HOUR }, - { 0, "l", tZONE, 11*HOUR }, - { 0, "m", tZONE, 12*HOUR }, - { 0, "n", tZONE, -1*HOUR }, - { 0, "o", tZONE, -2*HOUR }, - { 0, "p", tZONE, -3*HOUR }, - { 0, "q", tZONE, -4*HOUR }, - { 0, "r", tZONE, -5*HOUR }, - { 0, "s", tZONE, -6*HOUR }, - { 0, "t", tZONE, -7*HOUR }, - { 0, "u", tZONE, -8*HOUR }, - { 0, "v", tZONE, -9*HOUR }, - { 0, "w", tZONE, -10*HOUR }, - { 0, "x", tZONE, -11*HOUR }, - { 0, "y", tZONE, -12*HOUR }, - { 0, "z", tZONE, 0*HOUR }, - - /* End of table. */ - { 0, NULL, 0, 0 } -}; - -/* - * Year is either: - * = A number from 0 to 99, which means a year from 1970 to 2069, or - * = The actual year (>=100). - */ -static time_t -Convert(time_t Month, time_t Day, time_t Year, - time_t Hours, time_t Minutes, time_t Seconds, - time_t Timezone, enum DSTMODE DSTmode) -{ - signed char DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t Julian; - int i; - - if (Year < 69) - Year += 2000; - else if (Year < 100) - Year += 1900; - DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) - ? 29 : 28; - /* Checking for 2038 bogusly assumes that time_t is 32 bits. But - I'm too lazy to try to check for time_t overflow in another way. */ - if (Year < EPOCH || Year > 2038 - || Month < 1 || Month > 12 - /* Lint fluff: "conversion from long may lose accuracy" */ - || Day < 1 || Day > DaysInMonth[(int)--Month] - || Hours < 0 || Hours > 23 - || Minutes < 0 || Minutes > 59 - || Seconds < 0 || Seconds > 59) - return -1; - - Julian = Day - 1; - for (i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - for (i = EPOCH; i < Year; i++) - Julian += 365 + (i % 4 == 0); - Julian *= DAY; - Julian += Timezone; - Julian += Hours * HOUR + Minutes * MINUTE + Seconds; - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) - Julian -= HOUR; - return Julian; -} - - -static time_t -DSTcorrect(time_t Start, time_t Future) -{ - time_t StartDay; - time_t FutureDay; - - StartDay = (localtime(&Start)->tm_hour + 1) % 24; - FutureDay = (localtime(&Future)->tm_hour + 1) % 24; - return (Future - Start) + (StartDay - FutureDay) * HOUR; -} - - -static time_t -RelativeDate(time_t Start, time_t zone, int dstmode, - time_t DayOrdinal, time_t DayNumber) -{ - struct tm *tm; - time_t t, now; - - t = Start - zone; - tm = gmtime(&t); - now = Start; - now += DAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - if (dstmode == DSTmaybe) - return DSTcorrect(Start, now); - return now - Start; -} - - -static time_t -RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth) -{ - struct tm *tm; - time_t Month; - time_t Year; - - if (RelMonth == 0) - return 0; - tm = localtime(&Start); - Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; - Year = Month / 12; - Month = Month % 12 + 1; - return DSTcorrect(Start, - Convert(Month, (time_t)tm->tm_mday, Year, - (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, - Timezone, DSTmaybe)); -} - -/* - * Tokenizer. - */ -static int -nexttoken(const char **in, time_t *value) -{ - char c; - char buff[64]; - - for ( ; ; ) { - while (isspace((unsigned char)**in)) - ++*in; - - /* Skip parenthesized comments. */ - if (**in == '(') { - int Count = 0; - do { - c = *(*in)++; - if (c == '\0') - return c; - if (c == '(') - Count++; - else if (c == ')') - Count--; - } while (Count > 0); - continue; - } - - /* Try the next token in the word table first. */ - /* This allows us to match "2nd", for example. */ - { - const char *src = *in; - const struct LEXICON *tp; - unsigned i = 0; - - /* Force to lowercase and strip '.' characters. */ - while (*src != '\0' - && (isalnum((unsigned char)*src) || *src == '.') - && i < sizeof(buff)-1) { - if (*src != '.') { - if (isupper((unsigned char)*src)) - buff[i++] = tolower((unsigned char)*src); - else - buff[i++] = *src; - } - src++; - } - buff[i] = '\0'; - - /* - * Find the first match. If the word can be - * abbreviated, make sure we match at least - * the minimum abbreviation. - */ - for (tp = TimeWords; tp->name; tp++) { - size_t abbrev = tp->abbrev; - if (abbrev == 0) - abbrev = strlen(tp->name); - if (strlen(buff) >= abbrev - && strncmp(tp->name, buff, strlen(buff)) - == 0) { - /* Skip over token. */ - *in = src; - /* Return the match. */ - *value = tp->value; - return tp->type; - } - } - } - - /* - * 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. - */ - if (isdigit((unsigned char)(c = **in))) { - for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); ) - *value = 10 * *value + c - '0'; - (*in)--; - return (tUNUMBER); - } - - return *(*in)++; - } -} - -#define TM_YEAR_ORIGIN 1900 - -/* Yield A - B, measured in seconds. */ -static long -difftm (struct tm *a, struct tm *b) -{ - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int days = ( - /* difference in day of year */ - a->tm_yday - b->tm_yday - /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - /* + difference in years * 365 */ - + (long)(ay-by) * 365 - ); - return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR - + (a->tm_min - b->tm_min) * MINUTE - + (a->tm_sec - b->tm_sec)); -} - -/* - * - * The public function. - * - * TODO: tokens[] array should be dynamically sized. - */ -time_t -__archive_get_date(time_t now, const char *p) -{ - struct token tokens[256]; - struct gdstate _gds; - struct token *lasttoken; - struct gdstate *gds; - struct tm local, *tm; - struct tm gmt, *gmt_ptr; - time_t Start; - time_t tod; - long tzone; - - /* Clear out the parsed token array. */ - memset(tokens, 0, sizeof(tokens)); - /* Initialize the parser state. */ - memset(&_gds, 0, sizeof(_gds)); - gds = &_gds; - - /* Look up the current time. */ - memset(&local, 0, sizeof(local)); - tm = localtime (&now); - if (tm == NULL) - return -1; - local = *tm; - - /* Look up UTC if we can and use that to determine the current - * timezone offset. */ - memset(&gmt, 0, sizeof(gmt)); - gmt_ptr = gmtime (&now); - if (gmt_ptr != NULL) { - /* Copy, in case localtime and gmtime use the same buffer. */ - gmt = *gmt_ptr; - } - if (gmt_ptr != NULL) - tzone = difftm (&gmt, &local); - else - /* This system doesn't understand timezones; fake it. */ - tzone = 0; - if(local.tm_isdst) - tzone += HOUR; - - /* Tokenize the input string. */ - lasttoken = tokens; - while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) { - ++lasttoken; - if (lasttoken > tokens + 255) - return -1; - } - gds->tokenp = tokens; - - /* Match phrases until we run out of input tokens. */ - while (gds->tokenp < lasttoken) { - if (!phrase(gds)) - return -1; - } - - /* Use current local timezone if none was specified. */ - if (!gds->HaveZone) { - gds->Timezone = tzone; - gds->DSTmode = DSTmaybe; - } - - /* If a timezone was specified, use that for generating the default - * time components instead of the local timezone. */ - if (gds->HaveZone && gmt_ptr != NULL) { - now -= gds->Timezone; - gmt_ptr = gmtime (&now); - if (gmt_ptr != NULL) - local = *gmt_ptr; - now += gds->Timezone; - } - - if (!gds->HaveYear) - gds->Year = local.tm_year + 1900; - if (!gds->HaveMonth) - gds->Month = local.tm_mon + 1; - if (!gds->HaveDay) - gds->Day = local.tm_mday; - /* Note: No default for hour/min/sec; a specifier that just - * gives date always refers to 00:00 on that date. */ - - /* If we saw more than one time, timezone, weekday, year, month, - * or day, then give up. */ - if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1 - || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1) - return -1; - - /* Compute an absolute time based on whatever absolute information - * we collected. */ - if (gds->HaveYear || gds->HaveMonth || gds->HaveDay - || gds->HaveTime || gds->HaveWeekDay) { - Start = Convert(gds->Month, gds->Day, gds->Year, - gds->Hour, gds->Minutes, gds->Seconds, - gds->Timezone, gds->DSTmode); - if (Start < 0) - return -1; - } else { - Start = now; - if (!gds->HaveRel) - Start -= local.tm_hour * HOUR + local.tm_min * MINUTE - + local.tm_sec; - } - - /* Add the relative offset. */ - Start += gds->RelSeconds; - Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth); - - /* Adjust for day-of-week offsets. */ - if (gds->HaveWeekDay - && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) { - tod = RelativeDate(Start, gds->Timezone, - gds->DSTmode, gds->DayOrdinal, gds->DayNumber); - Start += tod; - } - - /* -1 is an error indicator, so return 0 instead of -1 if - * that's the actual time. */ - return Start == -1 ? 0 : Start; -} - - -#if defined(TEST) - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - time_t d; - time_t now = time(NULL); - - while (*++argv != NULL) { - (void)printf("Input: %s\n", *argv); - d = get_date(now, *argv); - if (d == -1) - (void)printf("Bad format - couldn't convert.\n"); - else - (void)printf("Output: %s\n", ctime(&d)); - } - exit(0); - /* NOTREACHED */ -} -#endif /* defined(TEST) */ diff --git a/3rdparty/libarchive/libarchive/archive_getdate.h b/3rdparty/libarchive/libarchive/archive_getdate.h deleted file mode 100644 index 666ff5ff..00000000 --- a/3rdparty/libarchive/libarchive/archive_getdate.h +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * Copyright (c) 2003-2015 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_GETDATE_H_INCLUDED -#define ARCHIVE_GETDATE_H_INCLUDED - -#include - -time_t __archive_get_date(time_t now, const char *); - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_match.c b/3rdparty/libarchive/libarchive/archive_match.c deleted file mode 100644 index be72066e..00000000 --- a/3rdparty/libarchive/libarchive/archive_match.c +++ /dev/null @@ -1,1846 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_entry.h" -#include "archive_getdate.h" -#include "archive_pathmatch.h" -#include "archive_rb.h" -#include "archive_string.h" - -struct match { - struct match *next; - int matches; - struct archive_mstring pattern; -}; - -struct match_list { - struct match *first; - struct match **last; - int count; - int unmatched_count; - struct match *unmatched_next; - int unmatched_eof; -}; - -struct match_file { - struct archive_rb_node node; - struct match_file *next; - struct archive_mstring pathname; - int flag; - time_t mtime_sec; - long mtime_nsec; - time_t ctime_sec; - long ctime_nsec; -}; - -struct entry_list { - struct match_file *first; - struct match_file **last; - int count; -}; - -struct id_array { - size_t size;/* Allocated size */ - size_t count; - int64_t *ids; -}; - -#define PATTERN_IS_SET 1 -#define TIME_IS_SET 2 -#define ID_IS_SET 4 - -struct archive_match { - struct archive archive; - - /* exclusion/inclusion set flag. */ - int setflag; - - /* - * Matching filename patterns. - */ - struct match_list exclusions; - struct match_list inclusions; - - /* - * Matching time stamps. - */ - time_t now; - int newer_mtime_filter; - time_t newer_mtime_sec; - long newer_mtime_nsec; - int newer_ctime_filter; - time_t newer_ctime_sec; - long newer_ctime_nsec; - int older_mtime_filter; - time_t older_mtime_sec; - long older_mtime_nsec; - int older_ctime_filter; - time_t older_ctime_sec; - long older_ctime_nsec; - /* - * Matching time stamps with its filename. - */ - struct archive_rb_tree exclusion_tree; - struct entry_list exclusion_entry_list; - - /* - * Matching file owners. - */ - struct id_array inclusion_uids; - struct id_array inclusion_gids; - struct match_list inclusion_unames; - struct match_list inclusion_gnames; -}; - -static int add_pattern_from_file(struct archive_match *, - struct match_list *, int, const void *, int); -static int add_entry(struct archive_match *, int, - struct archive_entry *); -static int add_owner_id(struct archive_match *, struct id_array *, - int64_t); -static int add_owner_name(struct archive_match *, struct match_list *, - int, const void *); -static int add_pattern_mbs(struct archive_match *, struct match_list *, - const char *); -static int add_pattern_wcs(struct archive_match *, struct match_list *, - const wchar_t *); -static int cmp_key_mbs(const struct archive_rb_node *, const void *); -static int cmp_key_wcs(const struct archive_rb_node *, const void *); -static int cmp_node_mbs(const struct archive_rb_node *, - const struct archive_rb_node *); -static int cmp_node_wcs(const struct archive_rb_node *, - const struct archive_rb_node *); -static void entry_list_add(struct entry_list *, struct match_file *); -static void entry_list_free(struct entry_list *); -static void entry_list_init(struct entry_list *); -static int error_nomem(struct archive_match *); -static void match_list_add(struct match_list *, struct match *); -static void match_list_free(struct match_list *); -static void match_list_init(struct match_list *); -static int match_list_unmatched_inclusions_next(struct archive_match *, - struct match_list *, int, const void **); -static int match_owner_id(struct id_array *, int64_t); -#if !defined(_WIN32) || defined(__CYGWIN__) -static int match_owner_name_mbs(struct archive_match *, - struct match_list *, const char *); -#else -static int match_owner_name_wcs(struct archive_match *, - struct match_list *, const wchar_t *); -#endif -static int match_path_exclusion(struct archive_match *, - struct match *, int, const void *); -static int match_path_inclusion(struct archive_match *, - struct match *, int, const void *); -static int owner_excluded(struct archive_match *, - struct archive_entry *); -static int path_excluded(struct archive_match *, int, const void *); -static int set_timefilter(struct archive_match *, int, time_t, long, - time_t, long); -static int set_timefilter_pathname_mbs(struct archive_match *, - int, const char *); -static int set_timefilter_pathname_wcs(struct archive_match *, - int, const wchar_t *); -static int set_timefilter_date(struct archive_match *, int, const char *); -static int set_timefilter_date_w(struct archive_match *, int, - const wchar_t *); -static int time_excluded(struct archive_match *, - struct archive_entry *); -static int validate_time_flag(struct archive *, int, const char *); - -#define get_date __archive_get_date - -static const struct archive_rb_tree_ops rb_ops_mbs = { - cmp_node_mbs, cmp_key_mbs -}; - -static const struct archive_rb_tree_ops rb_ops_wcs = { - cmp_node_wcs, cmp_key_wcs -}; - -/* - * The matching logic here needs to be re-thought. I started out to - * try to mimic gtar's matching logic, but it's not entirely - * consistent. In particular 'tar -t' and 'tar -x' interpret patterns - * on the command line as anchored, but --exclude doesn't. - */ - -static int -error_nomem(struct archive_match *a) -{ - archive_set_error(&(a->archive), ENOMEM, "No memory"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); -} - -/* - * Create an ARCHIVE_MATCH object. - */ -struct archive * -archive_match_new(void) -{ - struct archive_match *a; - - a = (struct archive_match *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_MATCH_MAGIC; - a->archive.state = ARCHIVE_STATE_NEW; - match_list_init(&(a->inclusions)); - match_list_init(&(a->exclusions)); - __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); - entry_list_init(&(a->exclusion_entry_list)); - match_list_init(&(a->inclusion_unames)); - match_list_init(&(a->inclusion_gnames)); - time(&a->now); - return (&(a->archive)); -} - -/* - * Free an ARCHIVE_MATCH object. - */ -int -archive_match_free(struct archive *_a) -{ - struct archive_match *a; - - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); - a = (struct archive_match *)_a; - match_list_free(&(a->inclusions)); - match_list_free(&(a->exclusions)); - entry_list_free(&(a->exclusion_entry_list)); - free(a->inclusion_uids.ids); - free(a->inclusion_gids.ids); - match_list_free(&(a->inclusion_unames)); - match_list_free(&(a->inclusion_gnames)); - free(a); - return (ARCHIVE_OK); -} - -/* - * Convenience function to perform all exclusion tests. - * - * Returns 1 if archive entry is excluded. - * Returns 0 if archive entry is not excluded. - * Returns <0 if something error happened. - */ -int -archive_match_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_excluded_ae"); - - a = (struct archive_match *)_a; - if (entry == NULL) { - archive_set_error(&(a->archive), EINVAL, "entry is NULL"); - return (ARCHIVE_FAILED); - } - - r = 0; - if (a->setflag & PATTERN_IS_SET) { -#if defined(_WIN32) && !defined(__CYGWIN__) - r = path_excluded(a, 0, archive_entry_pathname_w(entry)); -#else - r = path_excluded(a, 1, archive_entry_pathname(entry)); -#endif - if (r != 0) - return (r); - } - - if (a->setflag & TIME_IS_SET) { - r = time_excluded(a, entry); - if (r != 0) - return (r); - } - - if (a->setflag & ID_IS_SET) - r = owner_excluded(a, entry); - return (r); -} - -/* - * Utility functions to manage exclusion/inclusion patterns - */ - -int -archive_match_exclude_pattern(struct archive *_a, const char *pattern) -{ - struct archive_match *a; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); - a = (struct archive_match *)_a; - - if (pattern == NULL || *pattern == '\0') { - archive_set_error(&(a->archive), EINVAL, "pattern is empty"); - return (ARCHIVE_FAILED); - } - if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) - return (r); - return (ARCHIVE_OK); -} - -int -archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) -{ - struct archive_match *a; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); - a = (struct archive_match *)_a; - - if (pattern == NULL || *pattern == L'\0') { - archive_set_error(&(a->archive), EINVAL, "pattern is empty"); - return (ARCHIVE_FAILED); - } - if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) - return (r); - return (ARCHIVE_OK); -} - -int -archive_match_exclude_pattern_from_file(struct archive *_a, - const char *pathname, int nullSeparator) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); - a = (struct archive_match *)_a; - - return add_pattern_from_file(a, &(a->exclusions), 1, pathname, - nullSeparator); -} - -int -archive_match_exclude_pattern_from_file_w(struct archive *_a, - const wchar_t *pathname, int nullSeparator) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); - a = (struct archive_match *)_a; - - return add_pattern_from_file(a, &(a->exclusions), 0, pathname, - nullSeparator); -} - -int -archive_match_include_pattern(struct archive *_a, const char *pattern) -{ - struct archive_match *a; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_pattern"); - a = (struct archive_match *)_a; - - if (pattern == NULL || *pattern == '\0') { - archive_set_error(&(a->archive), EINVAL, "pattern is empty"); - return (ARCHIVE_FAILED); - } - if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) - return (r); - return (ARCHIVE_OK); -} - -int -archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) -{ - struct archive_match *a; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); - a = (struct archive_match *)_a; - - if (pattern == NULL || *pattern == L'\0') { - archive_set_error(&(a->archive), EINVAL, "pattern is empty"); - return (ARCHIVE_FAILED); - } - if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) - return (r); - return (ARCHIVE_OK); -} - -int -archive_match_include_pattern_from_file(struct archive *_a, - const char *pathname, int nullSeparator) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); - a = (struct archive_match *)_a; - - return add_pattern_from_file(a, &(a->inclusions), 1, pathname, - nullSeparator); -} - -int -archive_match_include_pattern_from_file_w(struct archive *_a, - const wchar_t *pathname, int nullSeparator) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); - a = (struct archive_match *)_a; - - return add_pattern_from_file(a, &(a->inclusions), 0, pathname, - nullSeparator); -} - -/* - * Test functions for pathname patterns. - * - * Returns 1 if archive entry is excluded. - * Returns 0 if archive entry is not excluded. - * Returns <0 if something error happened. - */ -int -archive_match_path_excluded(struct archive *_a, - struct archive_entry *entry) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_path_excluded"); - - a = (struct archive_match *)_a; - if (entry == NULL) { - archive_set_error(&(a->archive), EINVAL, "entry is NULL"); - return (ARCHIVE_FAILED); - } - - /* If we don't have exclusion/inclusion pattern set at all, - * the entry is always not excluded. */ - if ((a->setflag & PATTERN_IS_SET) == 0) - return (0); -#if defined(_WIN32) && !defined(__CYGWIN__) - return (path_excluded(a, 0, archive_entry_pathname_w(entry))); -#else - return (path_excluded(a, 1, archive_entry_pathname(entry))); -#endif -} - -/* - * Utility functions to get statistic information for inclusion patterns. - */ -int -archive_match_path_unmatched_inclusions(struct archive *_a) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); - a = (struct archive_match *)_a; - - return (a->inclusions.unmatched_count); -} - -int -archive_match_path_unmatched_inclusions_next(struct archive *_a, - const char **_p) -{ - struct archive_match *a; - const void *v; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); - a = (struct archive_match *)_a; - - r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); - *_p = (const char *)v; - return (r); -} - -int -archive_match_path_unmatched_inclusions_next_w(struct archive *_a, - const wchar_t **_p) -{ - struct archive_match *a; - const void *v; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); - a = (struct archive_match *)_a; - - r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); - *_p = (const wchar_t *)v; - return (r); -} - -/* - * Add inclusion/exclusion patterns. - */ -static int -add_pattern_mbs(struct archive_match *a, struct match_list *list, - const char *pattern) -{ - struct match *match; - size_t len; - - match = calloc(1, sizeof(*match)); - if (match == NULL) - return (error_nomem(a)); - /* Both "foo/" and "foo" should match "foo/bar". */ - len = strlen(pattern); - if (len && pattern[len - 1] == '/') - --len; - archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); - match_list_add(list, match); - a->setflag |= PATTERN_IS_SET; - return (ARCHIVE_OK); -} - -static int -add_pattern_wcs(struct archive_match *a, struct match_list *list, - const wchar_t *pattern) -{ - struct match *match; - size_t len; - - match = calloc(1, sizeof(*match)); - if (match == NULL) - return (error_nomem(a)); - /* Both "foo/" and "foo" should match "foo/bar". */ - len = wcslen(pattern); - if (len && pattern[len - 1] == L'/') - --len; - archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); - match_list_add(list, match); - a->setflag |= PATTERN_IS_SET; - return (ARCHIVE_OK); -} - -static int -add_pattern_from_file(struct archive_match *a, struct match_list *mlist, - int mbs, const void *pathname, int nullSeparator) -{ - struct archive *ar; - struct archive_entry *ae; - struct archive_string as; - const void *buff; - size_t size; - int64_t offset; - int r; - - ar = archive_read_new(); - if (ar == NULL) { - archive_set_error(&(a->archive), ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - r = archive_read_support_format_raw(ar); - r = archive_read_support_format_empty(ar); - if (r != ARCHIVE_OK) { - archive_copy_error(&(a->archive), ar); - archive_read_free(ar); - return (r); - } - if (mbs) - r = archive_read_open_filename(ar, pathname, 512*20); - else - r = archive_read_open_filename_w(ar, pathname, 512*20); - if (r != ARCHIVE_OK) { - archive_copy_error(&(a->archive), ar); - archive_read_free(ar); - return (r); - } - r = archive_read_next_header(ar, &ae); - if (r != ARCHIVE_OK) { - archive_read_free(ar); - if (r == ARCHIVE_EOF) { - return (ARCHIVE_OK); - } else { - archive_copy_error(&(a->archive), ar); - return (r); - } - } - - archive_string_init(&as); - - while ((r = archive_read_data_block(ar, &buff, &size, &offset)) - == ARCHIVE_OK) { - const char *b = (const char *)buff; - - while (size) { - const char *s = (const char *)b; - size_t length = 0; - int found_separator = 0; - - while (length < size) { - if (nullSeparator) { - if (*b == '\0') { - found_separator = 1; - break; - } - } else { - if (*b == 0x0d || *b == 0x0a) { - found_separator = 1; - break; - } - } - b++; - length++; - } - if (!found_separator) { - archive_strncat(&as, s, length); - /* Read next data block. */ - break; - } - b++; - size -= length + 1; - archive_strncat(&as, s, length); - - /* If the line is not empty, add the pattern. */ - if (archive_strlen(&as) > 0) { - /* Add pattern. */ - r = add_pattern_mbs(a, mlist, as.s); - if (r != ARCHIVE_OK) { - archive_read_free(ar); - archive_string_free(&as); - return (r); - } - archive_string_empty(&as); - } - } - } - - /* If an error occurred, report it immediately. */ - if (r < ARCHIVE_OK) { - archive_copy_error(&(a->archive), ar); - archive_read_free(ar); - archive_string_free(&as); - return (r); - } - - /* If the line is not empty, add the pattern. */ - if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { - /* Add pattern. */ - r = add_pattern_mbs(a, mlist, as.s); - if (r != ARCHIVE_OK) { - archive_read_free(ar); - archive_string_free(&as); - return (r); - } - } - archive_read_free(ar); - archive_string_free(&as); - return (ARCHIVE_OK); -} - -/* - * Test if pathname is excluded by inclusion/exclusion patterns. - */ -static int -path_excluded(struct archive_match *a, int mbs, const void *pathname) -{ - struct match *match; - struct match *matched; - int r; - - if (a == NULL) - return (0); - - /* Mark off any unmatched inclusions. */ - /* In particular, if a filename does appear in the archive and - * is explicitly included and excluded, then we don't report - * it as missing even though we don't extract it. - */ - matched = NULL; - for (match = a->inclusions.first; match != NULL; - match = match->next){ - if (match->matches == 0 && - (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { - if (r < 0) - return (r); - a->inclusions.unmatched_count--; - match->matches++; - matched = match; - } - } - - /* Exclusions take priority */ - for (match = a->exclusions.first; match != NULL; - match = match->next){ - r = match_path_exclusion(a, match, mbs, pathname); - if (r) - return (r); - } - - /* It's not excluded and we found an inclusion above, so it's - * included. */ - if (matched != NULL) - return (0); - - - /* We didn't find an unmatched inclusion, check the remaining ones. */ - for (match = a->inclusions.first; match != NULL; - match = match->next){ - /* We looked at previously-unmatched inclusions already. */ - if (match->matches > 0 && - (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { - if (r < 0) - return (r); - match->matches++; - return (0); - } - } - - /* If there were inclusions, default is to exclude. */ - if (a->inclusions.first != NULL) - return (1); - - /* No explicit inclusions, default is to match. */ - return (0); -} - -/* - * This is a little odd, but it matches the default behavior of - * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' - * - */ -static int -match_path_exclusion(struct archive_match *a, struct match *m, - int mbs, const void *pn) -{ - int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; - int r; - - if (mbs) { - const char *p; - r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); - if (r == 0) - return (archive_pathmatch(p, (const char *)pn, flag)); - } else { - const wchar_t *p; - r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); - if (r == 0) - return (archive_pathmatch_w(p, (const wchar_t *)pn, - flag)); - } - if (errno == ENOMEM) - return (error_nomem(a)); - return (0); -} - -/* - * Again, mimic gtar: inclusions are always anchored (have to match - * the beginning of the path) even though exclusions are not anchored. - */ -static int -match_path_inclusion(struct archive_match *a, struct match *m, - int mbs, const void *pn) -{ - int flag = PATHMATCH_NO_ANCHOR_END; - int r; - - if (mbs) { - const char *p; - r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); - if (r == 0) - return (archive_pathmatch(p, (const char *)pn, flag)); - } else { - const wchar_t *p; - r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); - if (r == 0) - return (archive_pathmatch_w(p, (const wchar_t *)pn, - flag)); - } - if (errno == ENOMEM) - return (error_nomem(a)); - return (0); -} - -static void -match_list_init(struct match_list *list) -{ - list->first = NULL; - list->last = &(list->first); - list->count = 0; -} - -static void -match_list_free(struct match_list *list) -{ - struct match *p, *q; - - for (p = list->first; p != NULL; ) { - q = p; - p = p->next; - archive_mstring_clean(&(q->pattern)); - free(q); - } -} - -static void -match_list_add(struct match_list *list, struct match *m) -{ - *list->last = m; - list->last = &(m->next); - list->count++; - list->unmatched_count++; -} - -static int -match_list_unmatched_inclusions_next(struct archive_match *a, - struct match_list *list, int mbs, const void **vp) -{ - struct match *m; - - *vp = NULL; - if (list->unmatched_eof) { - list->unmatched_eof = 0; - return (ARCHIVE_EOF); - } - if (list->unmatched_next == NULL) { - if (list->unmatched_count == 0) - return (ARCHIVE_EOF); - list->unmatched_next = list->first; - } - - for (m = list->unmatched_next; m != NULL; m = m->next) { - int r; - - if (m->matches) - continue; - if (mbs) { - const char *p; - r = archive_mstring_get_mbs(&(a->archive), - &(m->pattern), &p); - if (r < 0 && errno == ENOMEM) - return (error_nomem(a)); - if (p == NULL) - p = ""; - *vp = p; - } else { - const wchar_t *p; - r = archive_mstring_get_wcs(&(a->archive), - &(m->pattern), &p); - if (r < 0 && errno == ENOMEM) - return (error_nomem(a)); - if (p == NULL) - p = L""; - *vp = p; - } - list->unmatched_next = m->next; - if (list->unmatched_next == NULL) - /* To return EOF next time. */ - list->unmatched_eof = 1; - return (ARCHIVE_OK); - } - list->unmatched_next = NULL; - return (ARCHIVE_EOF); -} - -/* - * Utility functions to manage inclusion timestamps. - */ -int -archive_match_include_time(struct archive *_a, int flag, time_t sec, - long nsec) -{ - int r; - - r = validate_time_flag(_a, flag, "archive_match_include_time"); - if (r != ARCHIVE_OK) - return (r); - return set_timefilter((struct archive_match *)_a, flag, - sec, nsec, sec, nsec); -} - -int -archive_match_include_date(struct archive *_a, int flag, - const char *datestr) -{ - int r; - - r = validate_time_flag(_a, flag, "archive_match_include_date"); - if (r != ARCHIVE_OK) - return (r); - return set_timefilter_date((struct archive_match *)_a, flag, datestr); -} - -int -archive_match_include_date_w(struct archive *_a, int flag, - const wchar_t *datestr) -{ - int r; - - r = validate_time_flag(_a, flag, "archive_match_include_date_w"); - if (r != ARCHIVE_OK) - return (r); - - return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); -} - -int -archive_match_include_file_time(struct archive *_a, int flag, - const char *pathname) -{ - int r; - - r = validate_time_flag(_a, flag, "archive_match_include_file_time"); - if (r != ARCHIVE_OK) - return (r); - return set_timefilter_pathname_mbs((struct archive_match *)_a, - flag, pathname); -} - -int -archive_match_include_file_time_w(struct archive *_a, int flag, - const wchar_t *pathname) -{ - int r; - - r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); - if (r != ARCHIVE_OK) - return (r); - return set_timefilter_pathname_wcs((struct archive_match *)_a, - flag, pathname); -} - -int -archive_match_exclude_entry(struct archive *_a, int flag, - struct archive_entry *entry) -{ - struct archive_match *a; - int r; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); - a = (struct archive_match *)_a; - - if (entry == NULL) { - archive_set_error(&(a->archive), EINVAL, "entry is NULL"); - return (ARCHIVE_FAILED); - } - r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); - if (r != ARCHIVE_OK) - return (r); - return (add_entry(a, flag, entry)); -} - -/* - * Test function for time stamps. - * - * Returns 1 if archive entry is excluded. - * Returns 0 if archive entry is not excluded. - * Returns <0 if something error happened. - */ -int -archive_match_time_excluded(struct archive *_a, - struct archive_entry *entry) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); - - a = (struct archive_match *)_a; - if (entry == NULL) { - archive_set_error(&(a->archive), EINVAL, "entry is NULL"); - return (ARCHIVE_FAILED); - } - - /* If we don't have inclusion time set at all, the entry is always - * not excluded. */ - if ((a->setflag & TIME_IS_SET) == 0) - return (0); - return (time_excluded(a, entry)); -} - -static int -validate_time_flag(struct archive *_a, int flag, const char *_fn) -{ - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, _fn); - - /* Check a type of time. */ - if (flag & - ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { - archive_set_error(_a, EINVAL, "Invalid time flag"); - return (ARCHIVE_FAILED); - } - if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { - archive_set_error(_a, EINVAL, "No time flag"); - return (ARCHIVE_FAILED); - } - - /* Check a type of comparison. */ - if (flag & - ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER - | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { - archive_set_error(_a, EINVAL, "Invalid comparison flag"); - return (ARCHIVE_FAILED); - } - if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER - | ARCHIVE_MATCH_EQUAL)) == 0) { - archive_set_error(_a, EINVAL, "No comparison flag"); - return (ARCHIVE_FAILED); - } - - return (ARCHIVE_OK); -} - -#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ - ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) -static int -set_timefilter(struct archive_match *a, int timetype, - time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) -{ - if (timetype & ARCHIVE_MATCH_MTIME) { - if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { - a->newer_mtime_filter = timetype; - a->newer_mtime_sec = mtime_sec; - a->newer_mtime_nsec = mtime_nsec; - a->setflag |= TIME_IS_SET; - } - if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { - a->older_mtime_filter = timetype; - a->older_mtime_sec = mtime_sec; - a->older_mtime_nsec = mtime_nsec; - a->setflag |= TIME_IS_SET; - } - } - if (timetype & ARCHIVE_MATCH_CTIME) { - if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { - a->newer_ctime_filter = timetype; - a->newer_ctime_sec = ctime_sec; - a->newer_ctime_nsec = ctime_nsec; - a->setflag |= TIME_IS_SET; - } - if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { - a->older_ctime_filter = timetype; - a->older_ctime_sec = ctime_sec; - a->older_ctime_nsec = ctime_nsec; - a->setflag |= TIME_IS_SET; - } - } - return (ARCHIVE_OK); -} - -static int -set_timefilter_date(struct archive_match *a, int timetype, const char *datestr) -{ - time_t t; - - if (datestr == NULL || *datestr == '\0') { - archive_set_error(&(a->archive), EINVAL, "date is empty"); - return (ARCHIVE_FAILED); - } - t = get_date(a->now, datestr); - if (t == (time_t)-1) { - archive_set_error(&(a->archive), EINVAL, "invalid date string"); - return (ARCHIVE_FAILED); - } - return set_timefilter(a, timetype, t, 0, t, 0); -} - -static int -set_timefilter_date_w(struct archive_match *a, int timetype, - const wchar_t *datestr) -{ - struct archive_string as; - time_t t; - - if (datestr == NULL || *datestr == L'\0') { - archive_set_error(&(a->archive), EINVAL, "date is empty"); - return (ARCHIVE_FAILED); - } - - archive_string_init(&as); - if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { - archive_string_free(&as); - if (errno == ENOMEM) - return (error_nomem(a)); - archive_set_error(&(a->archive), -1, - "Failed to convert WCS to MBS"); - return (ARCHIVE_FAILED); - } - t = get_date(a->now, as.s); - archive_string_free(&as); - if (t == (time_t)-1) { - archive_set_error(&(a->archive), EINVAL, "invalid date string"); - return (ARCHIVE_FAILED); - } - return set_timefilter(a, timetype, t, 0, t, 0); -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -static int -set_timefilter_find_data(struct archive_match *a, int timetype, - DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, - DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) -{ - ULARGE_INTEGER utc; - time_t ctime_sec, mtime_sec; - long ctime_ns, mtime_ns; - - utc.HighPart = ftCreationTime_dwHighDateTime; - utc.LowPart = ftCreationTime_dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - ctime_sec = (time_t)(utc.QuadPart / 10000000); - ctime_ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - ctime_sec = 0; - ctime_ns = 0; - } - utc.HighPart = ftLastWriteTime_dwHighDateTime; - utc.LowPart = ftLastWriteTime_dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - mtime_sec = (time_t)(utc.QuadPart / 10000000); - mtime_ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - mtime_sec = 0; - mtime_ns = 0; - } - return set_timefilter(a, timetype, - mtime_sec, mtime_ns, ctime_sec, ctime_ns); -} - -static int -set_timefilter_pathname_mbs(struct archive_match *a, int timetype, - const char *path) -{ - /* NOTE: stat() on Windows cannot handle nano seconds. */ - HANDLE h; - WIN32_FIND_DATAA d; - - if (path == NULL || *path == '\0') { - archive_set_error(&(a->archive), EINVAL, "pathname is empty"); - return (ARCHIVE_FAILED); - } - h = FindFirstFileA(path, &d); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - archive_set_error(&(a->archive), errno, - "Failed to FindFirstFileA"); - return (ARCHIVE_FAILED); - } - FindClose(h); - return set_timefilter_find_data(a, timetype, - d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, - d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); -} - -static int -set_timefilter_pathname_wcs(struct archive_match *a, int timetype, - const wchar_t *path) -{ - HANDLE h; - WIN32_FIND_DATAW d; - - if (path == NULL || *path == L'\0') { - archive_set_error(&(a->archive), EINVAL, "pathname is empty"); - return (ARCHIVE_FAILED); - } - h = FindFirstFileW(path, &d); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - archive_set_error(&(a->archive), errno, - "Failed to FindFirstFile"); - return (ARCHIVE_FAILED); - } - FindClose(h); - return set_timefilter_find_data(a, timetype, - d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, - d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); -} - -#else /* _WIN32 && !__CYGWIN__ */ - -static int -set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) -{ - struct archive_entry *ae; - time_t ctime_sec, mtime_sec; - long ctime_ns, mtime_ns; - - ae = archive_entry_new(); - if (ae == NULL) - return (error_nomem(a)); - archive_entry_copy_stat(ae, st); - ctime_sec = archive_entry_ctime(ae); - ctime_ns = archive_entry_ctime_nsec(ae); - mtime_sec = archive_entry_mtime(ae); - mtime_ns = archive_entry_mtime_nsec(ae); - archive_entry_free(ae); - return set_timefilter(a, timetype, mtime_sec, mtime_ns, - ctime_sec, ctime_ns); -} - -static int -set_timefilter_pathname_mbs(struct archive_match *a, int timetype, - const char *path) -{ - struct stat st; - - if (path == NULL || *path == '\0') { - archive_set_error(&(a->archive), EINVAL, "pathname is empty"); - return (ARCHIVE_FAILED); - } - if (stat(path, &st) != 0) { - archive_set_error(&(a->archive), errno, "Failed to stat()"); - return (ARCHIVE_FAILED); - } - return (set_timefilter_stat(a, timetype, &st)); -} - -static int -set_timefilter_pathname_wcs(struct archive_match *a, int timetype, - const wchar_t *path) -{ - struct archive_string as; - int r; - - if (path == NULL || *path == L'\0') { - archive_set_error(&(a->archive), EINVAL, "pathname is empty"); - return (ARCHIVE_FAILED); - } - - /* Convert WCS filename to MBS filename. */ - archive_string_init(&as); - if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { - archive_string_free(&as); - if (errno == ENOMEM) - return (error_nomem(a)); - archive_set_error(&(a->archive), -1, - "Failed to convert WCS to MBS"); - return (ARCHIVE_FAILED); - } - - r = set_timefilter_pathname_mbs(a, timetype, as.s); - archive_string_free(&as); - - return (r); -} -#endif /* _WIN32 && !__CYGWIN__ */ - -/* - * Call back functions for archive_rb. - */ -static int -cmp_node_mbs(const struct archive_rb_node *n1, - const struct archive_rb_node *n2) -{ - struct match_file *f1 = (struct match_file *)(uintptr_t)n1; - struct match_file *f2 = (struct match_file *)(uintptr_t)n2; - const char *p1, *p2; - - archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); - archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); - if (p1 == NULL) - return (1); - if (p2 == NULL) - return (-1); - return (strcmp(p1, p2)); -} - -static int -cmp_key_mbs(const struct archive_rb_node *n, const void *key) -{ - struct match_file *f = (struct match_file *)(uintptr_t)n; - const char *p; - - archive_mstring_get_mbs(NULL, &(f->pathname), &p); - if (p == NULL) - return (-1); - return (strcmp(p, (const char *)key)); -} - -static int -cmp_node_wcs(const struct archive_rb_node *n1, - const struct archive_rb_node *n2) -{ - struct match_file *f1 = (struct match_file *)(uintptr_t)n1; - struct match_file *f2 = (struct match_file *)(uintptr_t)n2; - const wchar_t *p1, *p2; - - archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); - archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); - if (p1 == NULL) - return (1); - if (p2 == NULL) - return (-1); - return (wcscmp(p1, p2)); -} - -static int -cmp_key_wcs(const struct archive_rb_node *n, const void *key) -{ - struct match_file *f = (struct match_file *)(uintptr_t)n; - const wchar_t *p; - - archive_mstring_get_wcs(NULL, &(f->pathname), &p); - if (p == NULL) - return (-1); - return (wcscmp(p, (const wchar_t *)key)); -} - -static void -entry_list_init(struct entry_list *list) -{ - list->first = NULL; - list->last = &(list->first); - list->count = 0; -} - -static void -entry_list_free(struct entry_list *list) -{ - struct match_file *p, *q; - - for (p = list->first; p != NULL; ) { - q = p; - p = p->next; - archive_mstring_clean(&(q->pathname)); - free(q); - } -} - -static void -entry_list_add(struct entry_list *list, struct match_file *file) -{ - *list->last = file; - list->last = &(file->next); - list->count++; -} - -static int -add_entry(struct archive_match *a, int flag, - struct archive_entry *entry) -{ - struct match_file *f; - const void *pathname; - int r; - - f = calloc(1, sizeof(*f)); - if (f == NULL) - return (error_nomem(a)); - -#if defined(_WIN32) && !defined(__CYGWIN__) - pathname = archive_entry_pathname_w(entry); - if (pathname == NULL) { - free(f); - archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); - return (ARCHIVE_FAILED); - } - archive_mstring_copy_wcs(&(f->pathname), pathname); - a->exclusion_tree.rbt_ops = &rb_ops_wcs; -#else - (void)rb_ops_wcs; - pathname = archive_entry_pathname(entry); - if (pathname == NULL) { - free(f); - archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); - return (ARCHIVE_FAILED); - } - archive_mstring_copy_mbs(&(f->pathname), pathname); - a->exclusion_tree.rbt_ops = &rb_ops_mbs; -#endif - f->flag = flag; - f->mtime_sec = archive_entry_mtime(entry); - f->mtime_nsec = archive_entry_mtime_nsec(entry); - f->ctime_sec = archive_entry_ctime(entry); - f->ctime_nsec = archive_entry_ctime_nsec(entry); - r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); - if (!r) { - struct match_file *f2; - - /* Get the duplicated file. */ - f2 = (struct match_file *)__archive_rb_tree_find_node( - &(a->exclusion_tree), pathname); - - /* - * We always overwrite comparison condition. - * If you do not want to overwrite it, you should not - * call archive_match_exclude_entry(). We cannot know - * what behavior you really expect since overwriting - * condition might be different with the flag. - */ - if (f2 != NULL) { - f2->flag = f->flag; - f2->mtime_sec = f->mtime_sec; - f2->mtime_nsec = f->mtime_nsec; - f2->ctime_sec = f->ctime_sec; - f2->ctime_nsec = f->ctime_nsec; - } - /* Release the duplicated file. */ - archive_mstring_clean(&(f->pathname)); - free(f); - return (ARCHIVE_OK); - } - entry_list_add(&(a->exclusion_entry_list), f); - a->setflag |= TIME_IS_SET; - return (ARCHIVE_OK); -} - -/* - * Test if entry is excluded by its timestamp. - */ -static int -time_excluded(struct archive_match *a, struct archive_entry *entry) -{ - struct match_file *f; - const void *pathname; - time_t sec; - long nsec; - - /* - * If this file/dir is excluded by a time comparison, skip it. - */ - if (a->newer_ctime_filter) { - /* If ctime is not set, use mtime instead. */ - if (archive_entry_ctime_is_set(entry)) - sec = archive_entry_ctime(entry); - else - sec = archive_entry_mtime(entry); - if (sec < a->newer_ctime_sec) - return (1); /* Too old, skip it. */ - if (sec == a->newer_ctime_sec) { - if (archive_entry_ctime_is_set(entry)) - nsec = archive_entry_ctime_nsec(entry); - else - nsec = archive_entry_mtime_nsec(entry); - if (nsec < a->newer_ctime_nsec) - return (1); /* Too old, skip it. */ - if (nsec == a->newer_ctime_nsec && - (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) - == 0) - return (1); /* Equal, skip it. */ - } - } - if (a->older_ctime_filter) { - /* If ctime is not set, use mtime instead. */ - if (archive_entry_ctime_is_set(entry)) - sec = archive_entry_ctime(entry); - else - sec = archive_entry_mtime(entry); - if (sec > a->older_ctime_sec) - return (1); /* Too new, skip it. */ - if (sec == a->older_ctime_sec) { - if (archive_entry_ctime_is_set(entry)) - nsec = archive_entry_ctime_nsec(entry); - else - nsec = archive_entry_mtime_nsec(entry); - if (nsec > a->older_ctime_nsec) - return (1); /* Too new, skip it. */ - if (nsec == a->older_ctime_nsec && - (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) - == 0) - return (1); /* Equal, skip it. */ - } - } - if (a->newer_mtime_filter) { - sec = archive_entry_mtime(entry); - if (sec < a->newer_mtime_sec) - return (1); /* Too old, skip it. */ - if (sec == a->newer_mtime_sec) { - nsec = archive_entry_mtime_nsec(entry); - if (nsec < a->newer_mtime_nsec) - return (1); /* Too old, skip it. */ - if (nsec == a->newer_mtime_nsec && - (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) - == 0) - return (1); /* Equal, skip it. */ - } - } - if (a->older_mtime_filter) { - sec = archive_entry_mtime(entry); - if (sec > a->older_mtime_sec) - return (1); /* Too new, skip it. */ - nsec = archive_entry_mtime_nsec(entry); - if (sec == a->older_mtime_sec) { - if (nsec > a->older_mtime_nsec) - return (1); /* Too new, skip it. */ - if (nsec == a->older_mtime_nsec && - (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) - == 0) - return (1); /* Equal, skip it. */ - } - } - - /* If there is no exclusion list, include the file. */ - if (a->exclusion_entry_list.count == 0) - return (0); - -#if defined(_WIN32) && !defined(__CYGWIN__) - pathname = archive_entry_pathname_w(entry); - a->exclusion_tree.rbt_ops = &rb_ops_wcs; -#else - (void)rb_ops_wcs; - pathname = archive_entry_pathname(entry); - a->exclusion_tree.rbt_ops = &rb_ops_mbs; -#endif - if (pathname == NULL) - return (0); - - f = (struct match_file *)__archive_rb_tree_find_node( - &(a->exclusion_tree), pathname); - /* If the file wasn't rejected, include it. */ - if (f == NULL) - return (0); - - if (f->flag & ARCHIVE_MATCH_CTIME) { - sec = archive_entry_ctime(entry); - if (f->ctime_sec > sec) { - if (f->flag & ARCHIVE_MATCH_OLDER) - return (1); - } else if (f->ctime_sec < sec) { - if (f->flag & ARCHIVE_MATCH_NEWER) - return (1); - } else { - nsec = archive_entry_ctime_nsec(entry); - if (f->ctime_nsec > nsec) { - if (f->flag & ARCHIVE_MATCH_OLDER) - return (1); - } else if (f->ctime_nsec < nsec) { - if (f->flag & ARCHIVE_MATCH_NEWER) - return (1); - } else if (f->flag & ARCHIVE_MATCH_EQUAL) - return (1); - } - } - if (f->flag & ARCHIVE_MATCH_MTIME) { - sec = archive_entry_mtime(entry); - if (f->mtime_sec > sec) { - if (f->flag & ARCHIVE_MATCH_OLDER) - return (1); - } else if (f->mtime_sec < sec) { - if (f->flag & ARCHIVE_MATCH_NEWER) - return (1); - } else { - nsec = archive_entry_mtime_nsec(entry); - if (f->mtime_nsec > nsec) { - if (f->flag & ARCHIVE_MATCH_OLDER) - return (1); - } else if (f->mtime_nsec < nsec) { - if (f->flag & ARCHIVE_MATCH_NEWER) - return (1); - } else if (f->flag & ARCHIVE_MATCH_EQUAL) - return (1); - } - } - return (0); -} - -/* - * Utility functions to manage inclusion owners - */ - -int -archive_match_include_uid(struct archive *_a, int64_t uid) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_uid"); - a = (struct archive_match *)_a; - return (add_owner_id(a, &(a->inclusion_uids), uid)); -} - -int -archive_match_include_gid(struct archive *_a, int64_t gid) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_gid"); - a = (struct archive_match *)_a; - return (add_owner_id(a, &(a->inclusion_gids), gid)); -} - -int -archive_match_include_uname(struct archive *_a, const char *uname) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_uname"); - a = (struct archive_match *)_a; - return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); -} - -int -archive_match_include_uname_w(struct archive *_a, const wchar_t *uname) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); - a = (struct archive_match *)_a; - return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); -} - -int -archive_match_include_gname(struct archive *_a, const char *gname) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_gname"); - a = (struct archive_match *)_a; - return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); -} - -int -archive_match_include_gname_w(struct archive *_a, const wchar_t *gname) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); - a = (struct archive_match *)_a; - return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); -} - -/* - * Test function for owner(uid, gid, uname, gname). - * - * Returns 1 if archive entry is excluded. - * Returns 0 if archive entry is not excluded. - * Returns <0 if something error happened. - */ -int -archive_match_owner_excluded(struct archive *_a, - struct archive_entry *entry) -{ - struct archive_match *a; - - archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, - ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); - - a = (struct archive_match *)_a; - if (entry == NULL) { - archive_set_error(&(a->archive), EINVAL, "entry is NULL"); - return (ARCHIVE_FAILED); - } - - /* If we don't have inclusion id set at all, the entry is always - * not excluded. */ - if ((a->setflag & ID_IS_SET) == 0) - return (0); - return (owner_excluded(a, entry)); -} - -static int -add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) -{ - unsigned i; - - if (ids->count + 1 >= ids->size) { - void *p; - - if (ids->size == 0) - ids->size = 8; - else - ids->size *= 2; - p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); - if (p == NULL) - return (error_nomem(a)); - ids->ids = (int64_t *)p; - } - - /* Find an insert point. */ - for (i = 0; i < ids->count; i++) { - if (ids->ids[i] >= id) - break; - } - - /* Add owner id. */ - if (i == ids->count) - ids->ids[ids->count++] = id; - else if (ids->ids[i] != id) { - memmove(&(ids->ids[i+1]), &(ids->ids[i]), - (ids->count - i) * sizeof(ids->ids[0])); - ids->ids[i] = id; - ids->count++; - } - a->setflag |= ID_IS_SET; - return (ARCHIVE_OK); -} - -static int -match_owner_id(struct id_array *ids, int64_t id) -{ - unsigned b, m, t; - - t = 0; - b = (unsigned)ids->count; - while (t < b) { - m = (t + b)>>1; - if (ids->ids[m] == id) - return (1); - if (ids->ids[m] < id) - t = m + 1; - else - b = m; - } - return (0); -} - -static int -add_owner_name(struct archive_match *a, struct match_list *list, - int mbs, const void *name) -{ - struct match *match; - - match = calloc(1, sizeof(*match)); - if (match == NULL) - return (error_nomem(a)); - if (mbs) - archive_mstring_copy_mbs(&(match->pattern), name); - else - archive_mstring_copy_wcs(&(match->pattern), name); - match_list_add(list, match); - a->setflag |= ID_IS_SET; - return (ARCHIVE_OK); -} - -#if !defined(_WIN32) || defined(__CYGWIN__) -static int -match_owner_name_mbs(struct archive_match *a, struct match_list *list, - const char *name) -{ - struct match *m; - const char *p; - - if (name == NULL || *name == '\0') - return (0); - for (m = list->first; m; m = m->next) { - if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) - < 0 && errno == ENOMEM) - return (error_nomem(a)); - if (p != NULL && strcmp(p, name) == 0) { - m->matches++; - return (1); - } - } - return (0); -} -#else -static int -match_owner_name_wcs(struct archive_match *a, struct match_list *list, - const wchar_t *name) -{ - struct match *m; - const wchar_t *p; - - if (name == NULL || *name == L'\0') - return (0); - for (m = list->first; m; m = m->next) { - if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) - < 0 && errno == ENOMEM) - return (error_nomem(a)); - if (p != NULL && wcscmp(p, name) == 0) { - m->matches++; - return (1); - } - } - return (0); -} -#endif - -/* - * Test if entry is excluded by uid, gid, uname or gname. - */ -static int -owner_excluded(struct archive_match *a, struct archive_entry *entry) -{ - int r; - - if (a->inclusion_uids.count) { - if (!match_owner_id(&(a->inclusion_uids), - archive_entry_uid(entry))) - return (1); - } - - if (a->inclusion_gids.count) { - if (!match_owner_id(&(a->inclusion_gids), - archive_entry_gid(entry))) - return (1); - } - - if (a->inclusion_unames.count) { -#if defined(_WIN32) && !defined(__CYGWIN__) - r = match_owner_name_wcs(a, &(a->inclusion_unames), - archive_entry_uname_w(entry)); -#else - r = match_owner_name_mbs(a, &(a->inclusion_unames), - archive_entry_uname(entry)); -#endif - if (!r) - return (1); - else if (r < 0) - return (r); - } - - if (a->inclusion_gnames.count) { -#if defined(_WIN32) && !defined(__CYGWIN__) - r = match_owner_name_wcs(a, &(a->inclusion_gnames), - archive_entry_gname_w(entry)); -#else - r = match_owner_name_mbs(a, &(a->inclusion_gnames), - archive_entry_gname(entry)); -#endif - if (!r) - return (1); - else if (r < 0) - return (r); - } - return (0); -} - diff --git a/3rdparty/libarchive/libarchive/archive_options.c b/3rdparty/libarchive/libarchive/archive_options.c deleted file mode 100644 index 6496025a..00000000 --- a/3rdparty/libarchive/libarchive/archive_options.c +++ /dev/null @@ -1,218 +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 "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive_options_private.h" - -static const char * -parse_option(const char **str, - const char **mod, const char **opt, const char **val); - -int -_archive_set_option(struct archive *a, - const char *m, const char *o, const char *v, - int magic, const char *fn, option_handler use_option) -{ - const char *mp, *op, *vp; - int r; - - archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); - - mp = (m != NULL && m[0] != '\0') ? m : NULL; - op = (o != NULL && o[0] != '\0') ? o : NULL; - vp = (v != NULL && v[0] != '\0') ? v : NULL; - - if (op == NULL && vp == NULL) - return (ARCHIVE_OK); - if (op == NULL) { - archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option"); - return (ARCHIVE_FAILED); - } - - r = use_option(a, mp, op, vp); - if (r == ARCHIVE_WARN - 1) { - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unknown module name: `%s'", mp); - return (ARCHIVE_FAILED); - } - if (r == ARCHIVE_WARN) { - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Undefined option: `%s%s%s%s%s%s'", - vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:""); - return (ARCHIVE_FAILED); - } - return (r); -} - -int -_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v, - option_handler use_format_option, option_handler use_filter_option) -{ - int r1, r2; - - if (o == NULL && v == NULL) - return (ARCHIVE_OK); - if (o == NULL) - return (ARCHIVE_FAILED); - - r1 = use_format_option(a, m, o, v); - if (r1 == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - r2 = use_filter_option(a, m, o, v); - if (r2 == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - if (r2 == ARCHIVE_WARN - 1) - return r1; - return r1 > r2 ? r1 : r2; -} - -int -_archive_set_options(struct archive *a, const char *options, - 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; - - archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); - - if (options == NULL || options[0] == '\0') - return ARCHIVE_OK; - - if ((data = strdup(options)) == NULL) { - archive_set_error(a, - ENOMEM, "Out of memory adding file to list"); - return (ARCHIVE_FATAL); - } - s = (const char *)data; - - do { - mod = opt = val = NULL; - - parse_option(&s, &mod, &opt, &val); - if (mod == NULL && opt != NULL && - strcmp("__ignore_wrong_module_name__", opt) == 0) { - /* Ignore module name error */ - if (val != NULL) { - ignore_mod_err = 1; - anyok = 1; - } - continue; - } - - r = use_option(a, mod, opt, val); - if (r == ARCHIVE_FATAL) { - free(data); - return (ARCHIVE_FATAL); - } - if (r == ARCHIVE_FAILED && mod != NULL) { - free(data); - return (ARCHIVE_FAILED); - } - if (r == ARCHIVE_WARN - 1) { - if (ignore_mod_err) - continue; - /* The module name is wrong. */ - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unknown module name: `%s'", mod); - free(data); - return (ARCHIVE_FAILED); - } - if (r == ARCHIVE_WARN) { - /* The option name is wrong. No-one used this. */ - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Undefined option: `%s%s%s'", - mod?mod:"", mod?":":"", opt); - free(data); - return (ARCHIVE_FAILED); - } - if (r == ARCHIVE_OK) - anyok = 1; - else - allok = 0; - } while (s != NULL); - - free(data); - 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) -{ - const char *end, *mod, *opt, *val; - char *p; - - end = NULL; - mod = NULL; - opt = *s; - val = "1"; - - p = strchr(opt, ','); - - if (p != NULL) { - *p = '\0'; - end = ((const char *)p) + 1; - } - - if (0 == strlen(opt)) { - *s = end; - *m = NULL; - *o = NULL; - *v = NULL; - return end; - } - - p = strchr(opt, ':'); - if (p != NULL) { - *p = '\0'; - mod = opt; - opt = ++p; - } - - p = strchr(opt, '='); - if (p != NULL) { - *p = '\0'; - val = ++p; - } else if (opt[0] == '!') { - ++opt; - val = NULL; - } - - *s = end; - *m = mod; - *o = opt; - *v = val; - - return end; -} - diff --git a/3rdparty/libarchive/libarchive/archive_options_private.h b/3rdparty/libarchive/libarchive/archive_options_private.h deleted file mode 100644 index 6ef0165a..00000000 --- a/3rdparty/libarchive/libarchive/archive_options_private.h +++ /dev/null @@ -1,47 +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 "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive_private.h" - -typedef int (*option_handler)(struct archive *a, - const char *mod, const char *opt, const char *val); - -int -_archive_set_option(struct archive *a, - const char *mod, const char *opt, const char *val, - int magic, const char *fn, option_handler use_option); - -int -_archive_set_options(struct archive *a, const char *options, - int magic, const char *fn, option_handler use_option); - -int -_archive_set_either_option(struct archive *a, - const char *m, const char *o, const char *v, - option_handler use_format_option, option_handler use_filter_option); - diff --git a/3rdparty/libarchive/libarchive/archive_pack_dev.h b/3rdparty/libarchive/libarchive/archive_pack_dev.h deleted file mode 100644 index 749fd3d2..00000000 --- a/3rdparty/libarchive/libarchive/archive_pack_dev.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */ - -/*- - * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Charles M. Hannum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Originally from NetBSD's mknod(8) source. */ - -#ifndef _PACK_DEV_H -#define _PACK_DEV_H - -typedef dev_t pack_t(int, unsigned long [], const char **); - -pack_t *pack_find(const char *); -pack_t pack_native; - -#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) -#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ - (((x) & 0x000000ff) >> 0))) -#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ - (((y) << 12) & 0xfff00000) | \ - (((y) << 0) & 0x000000ff))) - -#endif /* _PACK_DEV_H */ diff --git a/3rdparty/libarchive/libarchive/archive_pathmatch.c b/3rdparty/libarchive/libarchive/archive_pathmatch.c deleted file mode 100644 index 619e2b62..00000000 --- a/3rdparty/libarchive/libarchive/archive_pathmatch.c +++ /dev/null @@ -1,459 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif - -#include "archive_pathmatch.h" - -/* - * Check whether a character 'c' is matched by a list specification [...]: - * * Leading '!' or '^' negates the class. - * * - is a range of characters - * * \ removes any special meaning for - * - * Some interesting boundary cases: - * a-d-e is one range (a-d) followed by two single characters - and e. - * \a-\d is same as a-d - * a\-d is three single characters: a, d, - - * Trailing - is not special (so [a-] is two characters a and -). - * Initial - is not special ([a-] is same as [-a] is same as [\\-a]) - * This function never sees a trailing \. - * [] always fails - * [!] always succeeds - */ -static int -pm_list(const char *start, const char *end, const char c, int flags) -{ - const char *p = start; - char rangeStart = '\0', nextRangeStart; - int match = 1, nomatch = 0; - - /* This will be used soon... */ - (void)flags; /* UNUSED */ - - /* If this is a negated class, return success for nomatch. */ - if ((*p == '!' || *p == '^') && p < end) { - match = 0; - nomatch = 1; - ++p; - } - - while (p < end) { - nextRangeStart = '\0'; - switch (*p) { - case '-': - /* Trailing or initial '-' is not special. */ - if ((rangeStart == '\0') || (p == end - 1)) { - if (*p == c) - return (match); - } else { - char rangeEnd = *++p; - if (rangeEnd == '\\') - rangeEnd = *++p; - if ((rangeStart <= c) && (c <= rangeEnd)) - return (match); - } - break; - case '\\': - ++p; - /* Fall through */ - default: - if (*p == c) - return (match); - nextRangeStart = *p; /* Possible start of range. */ - } - rangeStart = nextRangeStart; - ++p; - } - return (nomatch); -} - -static int -pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags) -{ - const wchar_t *p = start; - wchar_t rangeStart = L'\0', nextRangeStart; - int match = 1, nomatch = 0; - - /* This will be used soon... */ - (void)flags; /* UNUSED */ - - /* If this is a negated class, return success for nomatch. */ - if ((*p == L'!' || *p == L'^') && p < end) { - match = 0; - nomatch = 1; - ++p; - } - - while (p < end) { - nextRangeStart = L'\0'; - switch (*p) { - case L'-': - /* Trailing or initial '-' is not special. */ - if ((rangeStart == L'\0') || (p == end - 1)) { - if (*p == c) - return (match); - } else { - wchar_t rangeEnd = *++p; - if (rangeEnd == L'\\') - rangeEnd = *++p; - if ((rangeStart <= c) && (c <= rangeEnd)) - return (match); - } - break; - case L'\\': - ++p; - /* Fall through */ - default: - if (*p == c) - return (match); - nextRangeStart = *p; /* Possible start of range. */ - } - rangeStart = nextRangeStart; - ++p; - } - return (nomatch); -} - -/* - * If s is pointing to "./", ".//", "./././" or the like, skip it. - */ -static const char * -pm_slashskip(const char *s) { - while ((*s == '/') - || (s[0] == '.' && s[1] == '/') - || (s[0] == '.' && s[1] == '\0')) - ++s; - return (s); -} - -static const wchar_t * -pm_slashskip_w(const wchar_t *s) { - while ((*s == L'/') - || (s[0] == L'.' && s[1] == L'/') - || (s[0] == L'.' && s[1] == L'\0')) - ++s; - return (s); -} - -static int -pm(const char *p, const char *s, int flags) -{ - const char *end; - - /* - * Ignore leading './', './/', '././', etc. - */ - if (s[0] == '.' && s[1] == '/') - s = pm_slashskip(s + 1); - if (p[0] == '.' && p[1] == '/') - p = pm_slashskip(p + 1); - - for (;;) { - switch (*p) { - case '\0': - if (s[0] == '/') { - if (flags & PATHMATCH_NO_ANCHOR_END) - return (1); - /* "dir" == "dir/" == "dir/." */ - s = pm_slashskip(s); - } - return (*s == '\0'); - case '?': - /* ? always succeeds, unless we hit end of 's' */ - if (*s == '\0') - return (0); - break; - case '*': - /* "*" == "**" == "***" ... */ - while (*p == '*') - ++p; - /* Trailing '*' always succeeds. */ - if (*p == '\0') - return (1); - while (*s) { - if (archive_pathmatch(p, s, flags)) - return (1); - ++s; - } - return (0); - case '[': - /* - * Find the end of the [...] character class, - * ignoring \] that might occur within the class. - */ - end = p + 1; - while (*end != '\0' && *end != ']') { - if (*end == '\\' && end[1] != '\0') - ++end; - ++end; - } - if (*end == ']') { - /* We found [...], try to match it. */ - if (!pm_list(p + 1, end, *s, flags)) - return (0); - p = end; /* Jump to trailing ']' char. */ - break; - } else - /* No final ']', so just match '['. */ - if (*p != *s) - return (0); - break; - case '\\': - /* Trailing '\\' matches itself. */ - if (p[1] == '\0') { - if (*s != '\\') - return (0); - } else { - ++p; - if (*p != *s) - return (0); - } - break; - case '/': - if (*s != '/' && *s != '\0') - return (0); - /* Note: pattern "/\./" won't match "/"; - * pm_slashskip() correctly stops at backslash. */ - p = pm_slashskip(p); - s = pm_slashskip(s); - if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)) - return (1); - --p; /* Counteract the increment below. */ - --s; - break; - case '$': - /* '$' is special only at end of pattern and only - * if PATHMATCH_NO_ANCHOR_END is specified. */ - if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ - /* "dir" == "dir/" == "dir/." */ - return (*pm_slashskip(s) == '\0'); - } - /* Otherwise, '$' is not special. */ - /* FALL THROUGH */ - default: - if (*p != *s) - return (0); - break; - } - ++p; - ++s; - } -} - -static int -pm_w(const wchar_t *p, const wchar_t *s, int flags) -{ - const wchar_t *end; - - /* - * Ignore leading './', './/', '././', etc. - */ - if (s[0] == L'.' && s[1] == L'/') - s = pm_slashskip_w(s + 1); - if (p[0] == L'.' && p[1] == L'/') - p = pm_slashskip_w(p + 1); - - for (;;) { - switch (*p) { - case L'\0': - if (s[0] == L'/') { - if (flags & PATHMATCH_NO_ANCHOR_END) - return (1); - /* "dir" == "dir/" == "dir/." */ - s = pm_slashskip_w(s); - } - return (*s == L'\0'); - case L'?': - /* ? always succeeds, unless we hit end of 's' */ - if (*s == L'\0') - return (0); - break; - case L'*': - /* "*" == "**" == "***" ... */ - while (*p == L'*') - ++p; - /* Trailing '*' always succeeds. */ - if (*p == L'\0') - return (1); - while (*s) { - if (archive_pathmatch_w(p, s, flags)) - return (1); - ++s; - } - return (0); - case L'[': - /* - * Find the end of the [...] character class, - * ignoring \] that might occur within the class. - */ - end = p + 1; - while (*end != L'\0' && *end != L']') { - if (*end == L'\\' && end[1] != L'\0') - ++end; - ++end; - } - if (*end == L']') { - /* We found [...], try to match it. */ - if (!pm_list_w(p + 1, end, *s, flags)) - return (0); - p = end; /* Jump to trailing ']' char. */ - break; - } else - /* No final ']', so just match '['. */ - if (*p != *s) - return (0); - break; - case L'\\': - /* Trailing '\\' matches itself. */ - if (p[1] == L'\0') { - if (*s != L'\\') - return (0); - } else { - ++p; - if (*p != *s) - return (0); - } - break; - case L'/': - if (*s != L'/' && *s != L'\0') - return (0); - /* Note: pattern "/\./" won't match "/"; - * pm_slashskip() correctly stops at backslash. */ - p = pm_slashskip_w(p); - s = pm_slashskip_w(s); - if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)) - return (1); - --p; /* Counteract the increment below. */ - --s; - break; - case L'$': - /* '$' is special only at end of pattern and only - * if PATHMATCH_NO_ANCHOR_END is specified. */ - if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ - /* "dir" == "dir/" == "dir/." */ - return (*pm_slashskip_w(s) == L'\0'); - } - /* Otherwise, '$' is not special. */ - /* FALL THROUGH */ - default: - if (*p != *s) - return (0); - break; - } - ++p; - ++s; - } -} - -/* Main entry point. */ -int -__archive_pathmatch(const char *p, const char *s, int flags) -{ - /* Empty pattern only matches the empty string. */ - if (p == NULL || *p == '\0') - return (s == NULL || *s == '\0'); - - /* Leading '^' anchors the start of the pattern. */ - if (*p == '^') { - ++p; - flags &= ~PATHMATCH_NO_ANCHOR_START; - } - - if (*p == '/' && *s != '/') - return (0); - - /* Certain patterns anchor implicitly. */ - if (*p == '*' || *p == '/') { - while (*p == '/') - ++p; - while (*s == '/') - ++s; - return (pm(p, s, flags)); - } - - /* If start is unanchored, try to match start of each path element. */ - if (flags & PATHMATCH_NO_ANCHOR_START) { - for ( ; s != NULL; s = strchr(s, '/')) { - if (*s == '/') - s++; - if (pm(p, s, flags)) - return (1); - } - return (0); - } - - /* Default: Match from beginning. */ - return (pm(p, s, flags)); -} - -int -__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags) -{ - /* Empty pattern only matches the empty string. */ - if (p == NULL || *p == L'\0') - return (s == NULL || *s == L'\0'); - - /* Leading '^' anchors the start of the pattern. */ - if (*p == L'^') { - ++p; - flags &= ~PATHMATCH_NO_ANCHOR_START; - } - - if (*p == L'/' && *s != L'/') - return (0); - - /* Certain patterns anchor implicitly. */ - if (*p == L'*' || *p == L'/') { - while (*p == L'/') - ++p; - while (*s == L'/') - ++s; - return (pm_w(p, s, flags)); - } - - /* 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'/')) { - if (*s == L'/') - s++; - if (pm_w(p, s, flags)) - return (1); - } - return (0); - } - - /* Default: Match from beginning. */ - return (pm_w(p, s, flags)); -} diff --git a/3rdparty/libarchive/libarchive/archive_pathmatch.h b/3rdparty/libarchive/libarchive/archive_pathmatch.h deleted file mode 100644 index e6901774..00000000 --- a/3rdparty/libarchive/libarchive/archive_pathmatch.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#ifndef __LIBARCHIVE_TEST -#error This header is only to be used internally to libarchive. -#endif -#endif - -#ifndef ARCHIVE_PATHMATCH_H -#define ARCHIVE_PATHMATCH_H - -/* Don't anchor at beginning unless the pattern starts with "^" */ -#define PATHMATCH_NO_ANCHOR_START 1 -/* Don't anchor at end unless the pattern ends with "$" */ -#define PATHMATCH_NO_ANCHOR_END 2 - -/* Note that "^" and "$" are not special unless you set the corresponding - * flag above. */ - -int __archive_pathmatch(const char *p, const char *s, int flags); -int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags); - -#define archive_pathmatch(p, s, f) __archive_pathmatch(p, s, f) -#define archive_pathmatch_w(p, s, f) __archive_pathmatch_w(p, s, f) - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_platform.h b/3rdparty/libarchive/libarchive/archive_platform.h deleted file mode 100644 index 34be8eda..00000000 --- a/3rdparty/libarchive/libarchive/archive_platform.h +++ /dev/null @@ -1,183 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_platform.h 201090 2009-12-28 02:22:04Z kientzle $ - */ - -/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ - -/* - * This header is the first thing included in any of the libarchive - * source files. As far as possible, platform-specific issues should - * be dealt with here and not within individual source files. I'm - * actively trying to minimize #if blocks within the main source, - * since they obfuscate the code. - */ - -#ifndef ARCHIVE_PLATFORM_H_INCLUDED -#define ARCHIVE_PLATFORM_H_INCLUDED - -/* archive.h and archive_entry.h require this. */ -#define __LIBARCHIVE_BUILD 1 - -#if defined(PLATFORM_CONFIG_H) -/* Use hand-built config.h in environments that need it. */ -#include PLATFORM_CONFIG_H -#elif defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in archive_platform.h. -#endif - -/* It should be possible to get rid of this by extending the feature-test - * macros to cover Windows API functions, probably along with non-trivial - * refactoring of code to find structures that sit more cleanly on top of - * either Windows or Posix APIs. */ -#if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__) -#include "archive_windows.h" -#endif - -/* - * The config files define a lot of feature macros. The following - * uses those macros to select/define replacements and include key - * headers as required. - */ - -/* Get a real definition for __FBSDID or __RCSID if we can */ -#if HAVE_SYS_CDEFS_H -#include -#endif - -/* If not, define them so as to avoid dangling semicolons. */ -#ifndef __FBSDID -#define __FBSDID(a) struct _undefined_hack -#endif -#ifndef __RCSID -#define __RCSID(a) struct _undefined_hack -#endif - -/* Try to get standard C99-style integer type definitions. */ -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif - -/* Borland warns about its own constants! */ -#if defined(__BORLANDC__) -# if HAVE_DECL_UINT64_MAX -# undef UINT64_MAX -# undef HAVE_DECL_UINT64_MAX -# endif -# if HAVE_DECL_UINT64_MIN -# undef UINT64_MIN -# undef HAVE_DECL_UINT64_MIN -# endif -# if HAVE_DECL_INT64_MAX -# undef INT64_MAX -# undef HAVE_DECL_INT64_MAX -# endif -# if HAVE_DECL_INT64_MIN -# undef INT64_MIN -# undef HAVE_DECL_INT64_MIN -# endif -#endif - -/* Some platforms lack the standard *_MAX definitions. */ -#if !HAVE_DECL_SIZE_MAX -#define SIZE_MAX (~(size_t)0) -#endif -#if !HAVE_DECL_SSIZE_MAX -#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1)) -#endif -#if !HAVE_DECL_UINT32_MAX -#define UINT32_MAX (~(uint32_t)0) -#endif -#if !HAVE_DECL_INT32_MAX -#define INT32_MAX ((int32_t)(UINT32_MAX >> 1)) -#endif -#if !HAVE_DECL_INT32_MIN -#define INT32_MIN ((int32_t)(~INT32_MAX)) -#endif -#if !HAVE_DECL_UINT64_MAX -#define UINT64_MAX (~(uint64_t)0) -#endif -#if !HAVE_DECL_INT64_MAX -#define INT64_MAX ((int64_t)(UINT64_MAX >> 1)) -#endif -#if !HAVE_DECL_INT64_MIN -#define INT64_MIN ((int64_t)(~INT64_MAX)) -#endif -#if !HAVE_DECL_UINTMAX_MAX -#define UINTMAX_MAX (~(uintmax_t)0) -#endif -#if !HAVE_DECL_INTMAX_MAX -#define INTMAX_MAX ((intmax_t)(UINTMAX_MAX >> 1)) -#endif -#if !HAVE_DECL_INTMAX_MIN -#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX)) -#endif - -/* - * If we can't restore metadata using a file descriptor, then - * for compatibility's sake, close files before trying to restore metadata. - */ -#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN) -#define CAN_RESTORE_METADATA_FD -#endif - -/* - * glibc 2.24 deprecates readdir_r - */ -#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) -#define USE_READDIR_R 1 -#else -#undef USE_READDIR_R -#endif - -/* Set up defaults for internal error codes. */ -#ifndef ARCHIVE_ERRNO_FILE_FORMAT -#if HAVE_EFTYPE -#define ARCHIVE_ERRNO_FILE_FORMAT EFTYPE -#else -#if HAVE_EILSEQ -#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ -#else -#define ARCHIVE_ERRNO_FILE_FORMAT EINVAL -#endif -#endif -#endif - -#ifndef ARCHIVE_ERRNO_PROGRAMMER -#define ARCHIVE_ERRNO_PROGRAMMER EINVAL -#endif - -#ifndef ARCHIVE_ERRNO_MISC -#define ARCHIVE_ERRNO_MISC (-1) -#endif - -#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_platform_acl.h b/3rdparty/libarchive/libarchive/archive_platform_acl.h deleted file mode 100644 index 3498f78b..00000000 --- a/3rdparty/libarchive/libarchive/archive_platform_acl.h +++ /dev/null @@ -1,49 +0,0 @@ -/*- - * Copyright (c) 2017 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ - -#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED -#define ARCHIVE_PLATFORM_ACL_H_INCLUDED - -/* - * Determine what ACL types are supported - */ -#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL -#define ARCHIVE_ACL_POSIX1E 1 -#endif - -#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \ - ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL -#define ARCHIVE_ACL_NFS4 1 -#endif - -#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4 -#define ARCHIVE_ACL_SUPPORT 1 -#endif - -#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_ppmd7.c b/3rdparty/libarchive/libarchive/archive_ppmd7.c deleted file mode 100644 index 1aed922d..00000000 --- a/3rdparty/libarchive/libarchive/archive_ppmd7.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* Ppmd7.c -- PPMdH codec -2010-03-12 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -#include "archive_platform.h" - -#include - -#include "archive_ppmd7_private.h" - -#ifdef PPMD_32BIT - #define Ppmd7_GetPtr(p, ptr) (ptr) - #define Ppmd7_GetContext(p, ptr) (ptr) - #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) -#else - #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) - #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) - #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) -#endif - -#define Ppmd7_GetBinSumm(p) \ - &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ - p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ - (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ - 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ - ((p->RunLength >> 26) & 0x20)] - -#define kTopValue (1 << 24) -#define MAX_FREQ 124 -#define UNIT_SIZE 12 - -#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -#define U2I(nu) (p->Units2Indx[(nu) - 1]) -#define I2U(indx) (p->Indx2Units[indx]) - -#ifdef PPMD_32BIT - #define REF(ptr) (ptr) -#else - #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) -#endif - -#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) - -#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -#define STATS(ctx) Ppmd7_GetStats(p, ctx) -#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) -#define SUFFIX(ctx) CTX((ctx)->Suffix) - -static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; -static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; - -typedef CPpmd7_Context * CTX_PTR; - -struct CPpmd7_Node_; - -typedef - #ifdef PPMD_32BIT - struct CPpmd7_Node_ * - #else - UInt32 - #endif - CPpmd7_Node_Ref; - -typedef struct CPpmd7_Node_ -{ - UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ - UInt16 NU; - CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ - CPpmd7_Node_Ref Prev; -} CPpmd7_Node; - -#ifdef PPMD_32BIT - #define NODE(ptr) (ptr) -#else - #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) -#endif - -static void Ppmd7_Update1(CPpmd7 *p); -static void Ppmd7_Update1_0(CPpmd7 *p); -static void Ppmd7_Update2(CPpmd7 *p); -static void Ppmd7_UpdateBin(CPpmd7 *p); -static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, - UInt32 *scale); - -/* ----------- Base ----------- */ - -static void Ppmd7_Construct(CPpmd7 *p) -{ - unsigned i, k, m; - - p->Base = 0; - - for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) - { - unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while(--step); - p->Indx2Units[i] = (Byte)k; - } - - p->NS2BSIndx[0] = (0 << 1); - p->NS2BSIndx[1] = (1 << 1); - memset(p->NS2BSIndx + 2, (2 << 1), 9); - memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); - - for (i = 0; i < 3; i++) - p->NS2Indx[i] = (Byte)i; - for (m = i, k = 1; i < 256; i++) - { - p->NS2Indx[i] = (Byte)m; - if (--k == 0) - k = (++m) - 2; - } - - memset(p->HB2Flag, 0, 0x40); - memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); -} - -static void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) -{ - alloc->Free(alloc, p->Base); - p->Size = 0; - p->Base = 0; -} - -static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) -{ - if (p->Base == 0 || p->Size != size) - { - /* RestartModel() below assumes that p->Size >= UNIT_SIZE - (see the calculation of m->MinContext). */ - if (size < UNIT_SIZE) { - return False; - } - Ppmd7_Free(p, alloc); - p->AlignOffset = - #ifdef PPMD_32BIT - (4 - size) & 3; - #else - 4 - (size & 3); - #endif - if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size - #ifndef PPMD_32BIT - + UNIT_SIZE - #endif - )) == 0) - return False; - p->Size = size; - } - return True; -} - -static void InsertNode(CPpmd7 *p, void *node, unsigned indx) -{ - *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; - p->FreeList[indx] = REF(node); -} - -static void *RemoveNode(CPpmd7 *p, unsigned indx) -{ - CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); - p->FreeList[indx] = *node; - return node; -} - -static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -{ - unsigned i, nu = I2U(oldIndx) - I2U(newIndx); - ptr = (Byte *)ptr + U2B(I2U(newIndx)); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); - } - InsertNode(p, ptr, i); -} - -static void GlueFreeBlocks(CPpmd7 *p) -{ - #ifdef PPMD_32BIT - CPpmd7_Node headItem; - CPpmd7_Node_Ref head = &headItem; - #else - CPpmd7_Node_Ref head = p->AlignOffset + p->Size; - #endif - - CPpmd7_Node_Ref n = head; - unsigned i; - - p->GlueCount = 255; - - /* create doubly-linked list of free blocks */ - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - UInt16 nu = I2U(i); - CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) - { - CPpmd7_Node *node = NODE(next); - node->Next = n; - n = NODE(n)->Prev = next; - next = *(const CPpmd7_Node_Ref *)node; - node->Stamp = 0; - node->NU = (UInt16)nu; - } - } - NODE(head)->Stamp = 1; - NODE(head)->Next = n; - NODE(n)->Prev = head; - if (p->LoUnit != p->HiUnit) - ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; - - /* Glue free blocks */ - while (n != head) - { - CPpmd7_Node *node = NODE(n); - UInt32 nu = (UInt32)node->NU; - for (;;) - { - CPpmd7_Node *node2 = NODE(n) + nu; - nu += node2->NU; - if (node2->Stamp != 0 || nu >= 0x10000) - break; - NODE(node2->Prev)->Next = node2->Next; - NODE(node2->Next)->Prev = node2->Prev; - node->NU = (UInt16)nu; - } - n = node->Next; - } - - /* Fill lists of free blocks */ - for (n = NODE(head)->Next; n != head;) - { - CPpmd7_Node *node = NODE(n); - unsigned nu; - CPpmd7_Node_Ref next = node->Next; - for (nu = node->NU; nu > 128; nu -= 128, node += 128) - InsertNode(p, node, PPMD_NUM_INDEXES - 1); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, node + k, nu - k - 1); - } - InsertNode(p, node, i); - n = next; - } -} - -static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) -{ - unsigned i; - void *retVal; - if (p->GlueCount == 0) - { - GlueFreeBlocks(p); - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - } - i = indx; - do - { - if (++i == PPMD_NUM_INDEXES) - { - UInt32 numBytes = U2B(I2U(indx)); - p->GlueCount--; - return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); - } - } - while (p->FreeList[i] == 0); - retVal = RemoveNode(p, i); - SplitBlock(p, retVal, i, indx); - return retVal; -} - -static void *AllocUnits(CPpmd7 *p, unsigned indx) -{ - UInt32 numBytes; - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - numBytes = U2B(I2U(indx)); - if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) - { - void *retVal = p->LoUnit; - p->LoUnit += numBytes; - return retVal; - } - return AllocUnitsRare(p, indx); -} - -#define MyMem12Cpy(dest, src, num) \ - { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ - do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } - -static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) -{ - unsigned i0 = U2I(oldNU); - unsigned i1 = U2I(newNU); - if (i0 == i1) - return oldPtr; - if (p->FreeList[i1] != 0) - { - void *ptr = RemoveNode(p, i1); - MyMem12Cpy(ptr, oldPtr, newNU); - InsertNode(p, oldPtr, i0); - return ptr; - } - SplitBlock(p, oldPtr, i0, i1); - return oldPtr; -} - -#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) - -static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -{ - (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); - (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); -} - -static void RestartModel(CPpmd7 *p) -{ - unsigned i, k, m; - - memset(p->FreeList, 0, sizeof(p->FreeList)); - p->Text = p->Base + p->AlignOffset; - p->HiUnit = p->Text + p->Size; - p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; - p->GlueCount = 0; - - p->OrderFall = p->MaxOrder; - p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; - p->PrevSuccess = 0; - - p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - p->MinContext->Suffix = 0; - p->MinContext->NumStats = 256; - p->MinContext->SummFreq = 256 + 1; - p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - p->LoUnit += U2B(256 / 2); - p->MinContext->Stats = REF(p->FoundState); - for (i = 0; i < 256; i++) - { - CPpmd_State *s = &p->FoundState[i]; - s->Symbol = (Byte)i; - s->Freq = 1; - SetSuccessor(s, 0); - } - - for (i = 0; i < 128; i++) - for (k = 0; k < 8; k++) - { - UInt16 *dest = p->BinSumm[i] + k; - UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); - for (m = 0; m < 64; m += 8) - dest[m] = val; - } - - for (i = 0; i < 25; i++) - for (k = 0; k < 16; k++) - { - CPpmd_See *s = &p->See[i][k]; - s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); - s->Count = 4; - } -} - -static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) -{ - p->MaxOrder = maxOrder; - RestartModel(p); - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Count = 64; /* unused */ -} - -static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) -{ - CPpmd_State upState; - CTX_PTR c = p->MinContext; - CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - CPpmd_State *ps[PPMD7_MAX_ORDER]; - unsigned numPs = 0; - - if (!skip) - ps[numPs++] = p->FoundState; - - while (c->Suffix) - { - CPpmd_Void_Ref successor; - CPpmd_State *s; - c = SUFFIX(c); - if (c->NumStats != 1) - { - for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); - } - else - s = ONE_STATE(c); - successor = SUCCESSOR(s); - if (successor != upBranch) - { - c = CTX(successor); - if (numPs == 0) - return c; - break; - } - ps[numPs++] = s; - } - - upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); - SetSuccessor(&upState, upBranch + 1); - - if (c->NumStats == 1) - upState.Freq = ONE_STATE(c)->Freq; - else - { - UInt32 cf, s0; - CPpmd_State *s; - for (s = STATS(c); s->Symbol != upState.Symbol; s++); - cf = s->Freq - 1; - s0 = c->SummFreq - c->NumStats - cf; - upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); - } - - while (numPs != 0) - { - /* Create Child */ - CTX_PTR c1; /* = AllocContext(p); */ - if (p->HiUnit != p->LoUnit) - c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); - else if (p->FreeList[0] != 0) - c1 = (CTX_PTR)RemoveNode(p, 0); - else - { - c1 = (CTX_PTR)AllocUnitsRare(p, 0); - if (!c1) - return NULL; - } - c1->NumStats = 1; - *ONE_STATE(c1) = upState; - c1->Suffix = REF(c); - SetSuccessor(ps[--numPs], REF(c1)); - c = c1; - } - - return c; -} - -static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) -{ - CPpmd_State tmp = *t1; - *t1 = *t2; - *t2 = tmp; -} - -static void UpdateModel(CPpmd7 *p) -{ - CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); - CTX_PTR c; - unsigned s0, ns; - - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) - { - c = SUFFIX(p->MinContext); - - if (c->NumStats == 1) - { - CPpmd_State *s = ONE_STATE(c); - if (s->Freq < 32) - s->Freq++; - } - else - { - CPpmd_State *s = STATS(c); - if (s->Symbol != p->FoundState->Symbol) - { - do { s++; } while (s->Symbol != p->FoundState->Symbol); - if (s[0].Freq >= s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - s--; - } - } - if (s->Freq < MAX_FREQ - 9) - { - s->Freq += 2; - c->SummFreq += 2; - } - } - } - - if (p->OrderFall == 0) - { - p->MinContext = p->MaxContext = CreateSuccessors(p, True); - if (p->MinContext == 0) - { - RestartModel(p); - return; - } - SetSuccessor(p->FoundState, REF(p->MinContext)); - return; - } - - *p->Text++ = p->FoundState->Symbol; - successor = REF(p->Text); - if (p->Text >= p->UnitsStart) - { - RestartModel(p); - return; - } - - if (fSuccessor) - { - if (fSuccessor <= successor) - { - CTX_PTR cs = CreateSuccessors(p, False); - if (cs == NULL) - { - RestartModel(p); - return; - } - fSuccessor = REF(cs); - } - if (--p->OrderFall == 0) - { - successor = fSuccessor; - p->Text -= (p->MaxContext != p->MinContext); - } - } - else - { - SetSuccessor(p->FoundState, successor); - fSuccessor = REF(p->MinContext); - } - - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); - - for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) - { - unsigned ns1; - UInt32 cf, sf; - if ((ns1 = c->NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - /* Expand for one UNIT */ - unsigned oldNU = ns1 >> 1; - unsigned i = U2I(oldNU); - if (i != U2I(oldNU + 1)) - { - void *ptr = AllocUnits(p, i + 1); - void *oldPtr; - if (!ptr) - { - RestartModel(p); - return; - } - oldPtr = STATS(c); - MyMem12Cpy(ptr, oldPtr, oldNU); - InsertNode(p, oldPtr, i); - c->Stats = STATS_REF(ptr); - } - } - c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); - } - else - { - CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); - if (!s) - { - RestartModel(p); - return; - } - *s = *ONE_STATE(c); - c->Stats = REF(s); - if (s->Freq < MAX_FREQ / 4 - 1) - s->Freq <<= 1; - else - s->Freq = MAX_FREQ - 4; - c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); - } - cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); - sf = (UInt32)s0 + c->SummFreq; - if (cf < 6 * sf) - { - cf = 1 + (cf > sf) + (cf >= 4 * sf); - c->SummFreq += 3; - } - else - { - cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); - c->SummFreq = (UInt16)(c->SummFreq + cf); - } - { - CPpmd_State *s = STATS(c) + ns1; - SetSuccessor(s, successor); - s->Symbol = p->FoundState->Symbol; - s->Freq = (Byte)cf; - c->NumStats = (UInt16)(ns1 + 1); - } - } - p->MaxContext = p->MinContext = CTX(fSuccessor); -} - -static void Rescale(CPpmd7 *p) -{ - unsigned i, adder, sumFreq, escFreq; - CPpmd_State *stats = STATS(p->MinContext); - CPpmd_State *s = p->FoundState; - { - CPpmd_State tmp = *s; - for (; s != stats; s--) - s[0] = s[-1]; - *s = tmp; - } - escFreq = p->MinContext->SummFreq - s->Freq; - s->Freq += 4; - adder = (p->OrderFall != 0); - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq = s->Freq; - - i = p->MinContext->NumStats - 1; - do - { - escFreq -= (++s)->Freq; - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq += s->Freq; - if (s[0].Freq > s[-1].Freq) - { - CPpmd_State *s1 = s; - CPpmd_State tmp = *s1; - do - s1[0] = s1[-1]; - while (--s1 != stats && tmp.Freq > s1[-1].Freq); - *s1 = tmp; - } - } - while (--i); - - if (s->Freq == 0) - { - unsigned numStats = p->MinContext->NumStats; - unsigned n0, n1; - do { i++; } while ((--s)->Freq == 0); - escFreq += i; - p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); - if (p->MinContext->NumStats == 1) - { - CPpmd_State tmp = *stats; - do - { - tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); - escFreq >>= 1; - } - while (escFreq > 1); - InsertNode(p, stats, U2I(((numStats + 1) >> 1))); - *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; - return; - } - n0 = (numStats + 1) >> 1; - n1 = (p->MinContext->NumStats + 1) >> 1; - if (n0 != n1) - p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); - } - p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - p->FoundState = STATS(p->MinContext); -} - -static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) -{ - CPpmd_See *see; - unsigned nonMasked = p->MinContext->NumStats - numMasked; - if (p->MinContext->NumStats != 256) - { - see = p->See[p->NS2Indx[nonMasked - 1]] + - (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + - 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + - 4 * (numMasked > nonMasked) + - p->HiBitsFlag; - { - unsigned r = (see->Summ >> see->Shift); - see->Summ = (UInt16)(see->Summ - r); - *escFreq = r + (r == 0); - } - } - else - { - see = &p->DummySee; - *escFreq = 1; - } - return see; -} - -static void NextContext(CPpmd7 *p) -{ - CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (Byte *)c > p->Text) - p->MinContext = p->MaxContext = c; - else - UpdateModel(p); -} - -static void Ppmd7_Update1(CPpmd7 *p) -{ - CPpmd_State *s = p->FoundState; - s->Freq += 4; - p->MinContext->SummFreq += 4; - if (s[0].Freq > s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - p->FoundState = --s; - if (s->Freq > MAX_FREQ) - Rescale(p); - } - NextContext(p); -} - -static void Ppmd7_Update1_0(CPpmd7 *p) -{ - p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); - p->RunLength += p->PrevSuccess; - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - NextContext(p); -} - -static void Ppmd7_UpdateBin(CPpmd7 *p) -{ - p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); - p->PrevSuccess = 1; - p->RunLength++; - NextContext(p); -} - -static void Ppmd7_Update2(CPpmd7 *p) -{ - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - p->RunLength = p->InitRL; - UpdateModel(p); -} - -/* ---------- Decode ---------- */ - -static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p) -{ - unsigned i; - p->Low = p->Bottom = 0; - p->Range = 0xFFFFFFFF; - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); - return (p->Code < 0xFFFFFFFF); -} - -static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) -{ - if (p->Stream->Read((void *)p->Stream) != 0) - return False; - return Ppmd_RangeDec_Init(p); -} - -static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p) -{ - if (!Ppmd_RangeDec_Init(p)) - return False; - p->Bottom = 0x8000; - return True; -} - -static UInt32 Range_GetThreshold(void *pp, UInt32 total) -{ - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - return (p->Code - p->Low) / (p->Range /= total); -} - -static void Range_Normalize(CPpmd7z_RangeDec *p) -{ - while (1) - { - if((p->Low ^ (p->Low + p->Range)) >= kTopValue) - { - if(p->Range >= p->Bottom) - break; - else - p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1); - } - p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); - p->Range <<= 8; - p->Low <<= 8; - } -} - -static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size) -{ - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - p->Code -= start * p->Range; - p->Range *= size; - Range_Normalize(p); -} - -static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size) -{ - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - p->Low += start * p->Range; - p->Range *= size; - Range_Normalize(p); -} - -static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0) -{ - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - UInt32 newBound = (p->Range >> 14) * size0; - UInt32 symbol; - if (p->Code < newBound) - { - symbol = 0; - p->Range = newBound; - } - else - { - symbol = 1; - p->Code -= newBound; - p->Range -= newBound; - } - Range_Normalize(p); - return symbol; -} - -static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0) -{ - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE); - if(value < size0) - { - bit = 0; - p->p.Decode(p, 0, size0); - } - else - { - bit = 1; - p->p.Decode(p, size0, PPMD_BIN_SCALE - size0); - } - return bit; -} - -static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) -{ - p->p.GetThreshold = Range_GetThreshold; - p->p.Decode = Range_Decode_7z; - p->p.DecodeBit = Range_DecodeBit_7z; -} - -static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) -{ - p->p.GetThreshold = Range_GetThreshold; - p->p.Decode = Range_Decode_RAR; - p->p.DecodeBit = Range_DecodeBit_RAR; -} - -#define MASK(sym) ((signed char *)charMask)[sym] - -static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) -{ - size_t charMask[256 / sizeof(size_t)]; - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) - { - Byte symbol; - rc->Decode(rc, 0, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update1_0(p); - return symbol; - } - p->PrevSuccess = 0; - i = p->MinContext->NumStats - 1; - do - { - if ((hiCnt += (++s)->Freq) > count) - { - Byte symbol; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update1(p); - return symbol; - } - } - while (--i); - if (count >= p->MinContext->SummFreq) - return -2; - p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; - rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats - 1; - do { MASK((--s)->Symbol) = 0; } while (--i); - } - else - { - UInt16 *prob = Ppmd7_GetBinSumm(p); - if (rc->DecodeBit(rc, *prob) == 0) - { - Byte symbol; - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; - Ppmd7_UpdateBin(p); - return symbol; - } - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - for (;;) - { - CPpmd_State *ps[256], *s; - UInt32 freqSum, count, hiCnt; - CPpmd_See *see; - unsigned i, num, numMasked = p->MinContext->NumStats; - do - { - p->OrderFall++; - if (!p->MinContext->Suffix) - return -1; - p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); - } - while (p->MinContext->NumStats == numMasked); - hiCnt = 0; - s = Ppmd7_GetStats(p, p->MinContext); - i = 0; - num = p->MinContext->NumStats - numMasked; - do - { - int k = (int)(MASK(s->Symbol)); - hiCnt += (s->Freq & k); - ps[i] = s++; - i -= k; - } - while (i != num); - - see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - count = rc->GetThreshold(rc, freqSum); - - if (count < hiCnt) - { - Byte symbol; - CPpmd_State **pps = ps; - for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); - s = *pps; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); - Ppmd_See_Update(see); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update2(p); - return symbol; - } - if (count >= freqSum) - return -2; - rc->Decode(rc, hiCnt, freqSum - hiCnt); - see->Summ = (UInt16)(see->Summ + freqSum); - do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); - } -} - -/* ---------- Encode ---------- Ppmd7Enc.c */ - -#define kTopValue (1 << 24) - -static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) -{ - p->Low = 0; - p->Range = 0xFFFFFFFF; - p->Cache = 0; - p->CacheSize = 1; -} - -static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) -{ - if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) - { - Byte temp = p->Cache; - do - { - p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); - temp = 0xFF; - } - while(--p->CacheSize != 0); - p->Cache = (Byte)((UInt32)p->Low >> 24); - } - p->CacheSize++; - p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF; -} - -static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) -{ - p->Low += start * (p->Range /= total); - p->Range *= size; - while (p->Range < kTopValue) - { - p->Range <<= 8; - RangeEnc_ShiftLow(p); - } -} - -static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) -{ - p->Range = (p->Range >> 14) * size0; - while (p->Range < kTopValue) - { - p->Range <<= 8; - RangeEnc_ShiftLow(p); - } -} - -static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) -{ - UInt32 newBound = (p->Range >> 14) * size0; - p->Low += newBound; - p->Range -= newBound; - while (p->Range < kTopValue) - { - p->Range <<= 8; - RangeEnc_ShiftLow(p); - } -} - -static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) -{ - unsigned i; - for (i = 0; i < 5; i++) - RangeEnc_ShiftLow(p); -} - - -#define MASK(sym) ((signed char *)charMask)[sym] - -static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) -{ - size_t charMask[256 / sizeof(size_t)]; - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - UInt32 sum; - unsigned i; - if (s->Symbol == symbol) - { - RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); - p->FoundState = s; - Ppmd7_Update1_0(p); - return; - } - p->PrevSuccess = 0; - sum = s->Freq; - i = p->MinContext->NumStats - 1; - do - { - if ((++s)->Symbol == symbol) - { - RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); - p->FoundState = s; - Ppmd7_Update1(p); - return; - } - sum += s->Freq; - } - while (--i); - - p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats - 1; - do { MASK((--s)->Symbol) = 0; } while (--i); - RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); - } - else - { - UInt16 *prob = Ppmd7_GetBinSumm(p); - CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); - if (s->Symbol == symbol) - { - RangeEnc_EncodeBit_0(rc, *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - p->FoundState = s; - Ppmd7_UpdateBin(p); - return; - } - else - { - RangeEnc_EncodeBit_1(rc, *prob); - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - p->PrevSuccess = 0; - } - } - for (;;) - { - UInt32 escFreq; - CPpmd_See *see; - CPpmd_State *s; - UInt32 sum; - unsigned i, numMasked = p->MinContext->NumStats; - do - { - p->OrderFall++; - if (!p->MinContext->Suffix) - return; /* EndMarker (symbol = -1) */ - p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); - } - while (p->MinContext->NumStats == numMasked); - - see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); - s = Ppmd7_GetStats(p, p->MinContext); - sum = 0; - i = p->MinContext->NumStats; - do - { - int cur = s->Symbol; - if (cur == symbol) - { - UInt32 low = sum; - CPpmd_State *s1 = s; - do - { - sum += (s->Freq & (int)(MASK(s->Symbol))); - s++; - } - while (--i); - RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); - Ppmd_See_Update(see); - p->FoundState = s1; - Ppmd7_Update2(p); - return; - } - sum += (s->Freq & (int)(MASK(cur))); - MASK(cur) = 0; - s++; - } - while (--i); - - RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); - see->Summ = (UInt16)(see->Summ + sum + escFreq); - } -} - -const IPpmd7 __archive_ppmd7_functions = -{ - &Ppmd7_Construct, - &Ppmd7_Alloc, - &Ppmd7_Free, - &Ppmd7_Init, - &Ppmd7z_RangeDec_CreateVTable, - &PpmdRAR_RangeDec_CreateVTable, - &Ppmd7z_RangeDec_Init, - &PpmdRAR_RangeDec_Init, - &Ppmd7_DecodeSymbol, - &Ppmd7z_RangeEnc_Init, - &Ppmd7z_RangeEnc_FlushData, - &Ppmd7_EncodeSymbol -}; diff --git a/3rdparty/libarchive/libarchive/archive_ppmd7_private.h b/3rdparty/libarchive/libarchive/archive_ppmd7_private.h deleted file mode 100644 index 06c99e82..00000000 --- a/3rdparty/libarchive/libarchive/archive_ppmd7_private.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Ppmd7.h -- PPMdH compression codec -2010-03-12 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -/* This code supports virtual RangeDecoder and includes the implementation -of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. -If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED -#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED - -#include "archive_ppmd_private.h" - -#define PPMD7_MIN_ORDER 2 -#define PPMD7_MAX_ORDER 64 - -#define PPMD7_MIN_MEM_SIZE (1 << 11) -#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3) - -struct CPpmd7_Context_; - -typedef - #ifdef PPMD_32BIT - struct CPpmd7_Context_ * - #else - UInt32 - #endif - CPpmd7_Context_Ref; - -typedef struct CPpmd7_Context_ -{ - UInt16 NumStats; - UInt16 SummFreq; - CPpmd_State_Ref Stats; - CPpmd7_Context_Ref Suffix; -} CPpmd7_Context; - -#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) - -typedef struct -{ - CPpmd7_Context *MinContext, *MaxContext; - CPpmd_State *FoundState; - unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; - Int32 RunLength, InitRL; /* must be 32-bit at least */ - - UInt32 Size; - UInt32 GlueCount; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - UInt32 AlignOffset; - - Byte Indx2Units[PPMD_NUM_INDEXES]; - Byte Units2Indx[128]; - CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; - CPpmd_See DummySee, See[25][16]; - UInt16 BinSumm[128][64]; -} CPpmd7; - -/* ---------- Decode ---------- */ - -typedef struct -{ - UInt32 (*GetThreshold)(void *p, UInt32 total); - void (*Decode)(void *p, UInt32 start, UInt32 size); - UInt32 (*DecodeBit)(void *p, UInt32 size0); -} IPpmd7_RangeDec; - -typedef struct -{ - IPpmd7_RangeDec p; - UInt32 Range; - UInt32 Code; - UInt32 Low; - UInt32 Bottom; - IByteIn *Stream; -} CPpmd7z_RangeDec; - -/* ---------- Encode ---------- */ - -typedef struct -{ - UInt64 Low; - UInt32 Range; - Byte Cache; - UInt64 CacheSize; - IByteOut *Stream; -} CPpmd7z_RangeEnc; - -typedef struct -{ - /* Base Functions */ - void (*Ppmd7_Construct)(CPpmd7 *p); - Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); - void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc); - void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder); - #define Ppmd7_WasAllocated(p) ((p)->Base != NULL) - - /* Decode Functions */ - void (*Ppmd7z_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p); - void (*PpmdRAR_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p); - Bool (*Ppmd7z_RangeDec_Init)(CPpmd7z_RangeDec *p); - Bool (*PpmdRAR_RangeDec_Init)(CPpmd7z_RangeDec *p); - #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) - int (*Ppmd7_DecodeSymbol)(CPpmd7 *p, IPpmd7_RangeDec *rc); - - /* Encode Functions */ - void (*Ppmd7z_RangeEnc_Init)(CPpmd7z_RangeEnc *p); - void (*Ppmd7z_RangeEnc_FlushData)(CPpmd7z_RangeEnc *p); - - void (*Ppmd7_EncodeSymbol)(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); -} IPpmd7; - -extern const IPpmd7 __archive_ppmd7_functions; -#endif diff --git a/3rdparty/libarchive/libarchive/archive_ppmd_private.h b/3rdparty/libarchive/libarchive/archive_ppmd_private.h deleted file mode 100644 index e78bde59..00000000 --- a/3rdparty/libarchive/libarchive/archive_ppmd_private.h +++ /dev/null @@ -1,158 +0,0 @@ -/* Ppmd.h -- PPMD codec common code -2010-03-12 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED -#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED - -#include - -#include "archive_read_private.h" - -/*** Begin defined in Types.h ***/ - -#if !defined(ZCONF_H) -typedef unsigned char Byte; -#endif -typedef short Int16; -typedef unsigned short UInt16; - -#ifdef _LZMA_UINT32_IS_ULONG -typedef long Int32; -typedef unsigned long UInt32; -#else -typedef int Int32; -typedef unsigned int UInt32; -#endif - -#ifdef _SZ_NO_INT_64 - -/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. - NOTES: Some code will work incorrectly in that case! */ - -typedef long Int64; -typedef unsigned long UInt64; - -#else - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#define UINT64_CONST(n) n -#else -typedef long long int Int64; -typedef unsigned long long int UInt64; -#define UINT64_CONST(n) n ## ULL -#endif - -#endif - -typedef int Bool; -#define True 1 -#define False 0 - -/* The following interfaces use first parameter as pointer to structure */ - -typedef struct -{ - struct archive_read *a; - Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ -} IByteIn; - -typedef struct -{ - struct archive_write *a; - void (*Write)(void *p, Byte b); -} IByteOut; - - -typedef struct -{ - void *(*Alloc)(void *p, size_t size); - void (*Free)(void *p, void *address); /* address can be 0 */ -} ISzAlloc; - -/*** End defined in Types.h ***/ -/*** Begin defined in CpuArch.h ***/ - -#if defined(_M_IX86) || defined(__i386__) -#define MY_CPU_X86 -#endif - -#if defined(MY_CPU_X86) || defined(_M_ARM) -#define MY_CPU_32BIT -#endif - -#ifdef MY_CPU_32BIT -#define PPMD_32BIT -#endif - -/*** End defined in CpuArch.h ***/ - -#define PPMD_INT_BITS 7 -#define PPMD_PERIOD_BITS 7 -#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) - -#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) -#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) -#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) -#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) - -#define PPMD_N1 4 -#define PPMD_N2 4 -#define PPMD_N3 4 -#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) -#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) - -/* SEE-contexts for PPM-contexts with masked symbols */ -typedef struct -{ - UInt16 Summ; /* Freq */ - Byte Shift; /* Speed of Freq change; low Shift is for fast change */ - Byte Count; /* Count to next change of Shift */ -} CPpmd_See; - -#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ - { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } - -typedef struct -{ - Byte Symbol; - Byte Freq; - UInt16 SuccessorLow; - UInt16 SuccessorHigh; -} CPpmd_State; - -typedef - #ifdef PPMD_32BIT - CPpmd_State * - #else - UInt32 - #endif - CPpmd_State_Ref; - -typedef - #ifdef PPMD_32BIT - void * - #else - UInt32 - #endif - CPpmd_Void_Ref; - -typedef - #ifdef PPMD_32BIT - Byte * - #else - UInt32 - #endif - CPpmd_Byte_Ref; - -#define PPMD_SetAllBitsIn256Bytes(p) \ - { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \ - p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }} - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_private.h b/3rdparty/libarchive/libarchive/archive_private.h deleted file mode 100644 index 4b4be979..00000000 --- a/3rdparty/libarchive/libarchive/archive_private.h +++ /dev/null @@ -1,171 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_private.h 201098 2009-12-28 02:58:14Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_PRIVATE_H_INCLUDED -#define ARCHIVE_PRIVATE_H_INCLUDED - -#if HAVE_ICONV_H -#include -#endif - -#include "archive.h" -#include "archive_string.h" - -#if defined(__GNUC__) && (__GNUC__ > 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) -#define __LA_DEAD __attribute__((__noreturn__)) -#else -#define __LA_DEAD -#endif - -#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU) -#define ARCHIVE_READ_MAGIC (0xdeb0c5U) -#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U) -#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) -#define ARCHIVE_MATCH_MAGIC (0xcad11c9U) - -#define ARCHIVE_STATE_NEW 1U -#define ARCHIVE_STATE_HEADER 2U -#define ARCHIVE_STATE_DATA 4U -#define ARCHIVE_STATE_EOF 0x10U -#define ARCHIVE_STATE_CLOSED 0x20U -#define ARCHIVE_STATE_FATAL 0x8000U -#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL) - -struct archive_vtable { - int (*archive_close)(struct archive *); - int (*archive_free)(struct archive *); - int (*archive_write_header)(struct archive *, - struct archive_entry *); - int (*archive_write_finish_entry)(struct archive *); - ssize_t (*archive_write_data)(struct archive *, - const void *, size_t); - ssize_t (*archive_write_data_block)(struct archive *, - const void *, size_t, int64_t); - - int (*archive_read_next_header)(struct archive *, - struct archive_entry **); - int (*archive_read_next_header2)(struct archive *, - struct archive_entry *); - int (*archive_read_data_block)(struct archive *, - const void **, size_t *, int64_t *); - - int (*archive_filter_count)(struct archive *); - int64_t (*archive_filter_bytes)(struct archive *, int); - int (*archive_filter_code)(struct archive *, int); - const char * (*archive_filter_name)(struct archive *, int); -}; - -struct archive_string_conv; - -struct archive { - /* - * The magic/state values are used to sanity-check the - * client's usage. If an API function is called at a - * ridiculous time, or the client passes us an invalid - * pointer, these values allow me to catch that. - */ - unsigned int magic; - unsigned int state; - - /* - * Some public API functions depend on the "real" type of the - * archive object. - */ - struct archive_vtable *vtable; - - int archive_format; - const char *archive_format_name; - - int compression_code; /* Currently active compression. */ - const char *compression_name; - - /* Number of file entries processed. */ - int file_count; - - int archive_error_number; - const char *error; - struct archive_string error_string; - - char *current_code; - unsigned current_codepage; /* Current ACP(ANSI CodePage). */ - unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */ - struct archive_string_conv *sconv; - - /* - * Used by archive_read_data() to track blocks and copy - * data to client buffers, filling gaps with zero bytes. - */ - const char *read_data_block; - int64_t read_data_offset; - int64_t read_data_output_offset; - size_t read_data_remaining; - - /* - * Used by formats/filters to determine the amount of data - * requested from a call to archive_read_data(). This is only - * useful when the format/filter has seek support. - */ - char read_data_is_posix_read; - size_t read_data_requested; -}; - -/* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */ -int __archive_check_magic(struct archive *, unsigned int magic, - unsigned int state, const char *func); -#define archive_check_magic(a, expected_magic, allowed_states, function_name) \ - do { \ - int magic_test = __archive_check_magic((a), (expected_magic), \ - (allowed_states), (function_name)); \ - if (magic_test == ARCHIVE_FATAL) \ - return ARCHIVE_FATAL; \ - } while (0) - -void __archive_errx(int retvalue, const char *msg) __LA_DEAD; - -void __archive_ensure_cloexec_flag(int fd); -int __archive_mktemp(const char *tmpdir); - -int __archive_clean(struct archive *); - -void __archive_reset_read_data(struct archive *); - -#define err_combine(a,b) ((a) < (b) ? (a) : (b)) - -#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300) -# define ARCHIVE_LITERAL_LL(x) x##i64 -# define ARCHIVE_LITERAL_ULL(x) x##ui64 -#else -# define ARCHIVE_LITERAL_LL(x) x##ll -# define ARCHIVE_LITERAL_ULL(x) x##ull -#endif - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_random.c b/3rdparty/libarchive/libarchive/archive_random.c deleted file mode 100644 index 65ea6915..00000000 --- a/3rdparty/libarchive/libarchive/archive_random.c +++ /dev/null @@ -1,272 +0,0 @@ -/*- - * Copyright (c) 2014 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_STDLIB_H -#include -#endif - -#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) - -#ifdef HAVE_FCNTL -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_PTHREAD_H -#include -#endif - -static void arc4random_buf(void *, size_t); - -#endif /* HAVE_ARC4RANDOM_BUF */ - -#include "archive.h" -#include "archive_random_private.h" - -#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) -#include -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -/* - * Random number generator function. - * This simply calls arc4random_buf function if the platform provides it. - */ - -int -archive_random(void *buf, size_t nbytes) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - HCRYPTPROV hProv; - BOOL success; - - success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT); - if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) { - success = CryptAcquireContext(&hProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_NEWKEYSET); - } - if (success) { - success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf); - CryptReleaseContext(hProv, 0); - if (success) - return ARCHIVE_OK; - } - /* TODO: Does this case really happen? */ - return ARCHIVE_FAILED; -#else - arc4random_buf(buf, nbytes); - return ARCHIVE_OK; -#endif -} - -#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) - -/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ -/* - * Copyright (c) 1996, David Mazieres - * Copyright (c) 2008, Damien Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * Arc4 random number generator for OpenBSD. - * - * This code is derived from section 17.1 of Applied Cryptography, - * second edition, which describes a stream cipher allegedly - * compatible with RSA Labs "RC4" cipher (the actual description of - * which is a trade secret). The same algorithm is used as a stream - * cipher called "arcfour" in Tatu Ylonen's ssh package. - * - * RC4 is a registered trademark of RSA Laboratories. - */ - -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ - -struct arc4_stream { - uint8_t i; - uint8_t j; - uint8_t s[256]; -}; - -#define RANDOMDEV "/dev/urandom" -#define KEYSIZE 128 -#ifdef HAVE_PTHREAD_H -static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; -#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx); -#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx); -#else -#define _ARC4_LOCK() -#define _ARC4_UNLOCK() -#endif - -static int rs_initialized; -static struct arc4_stream rs; -static pid_t arc4_stir_pid; -static int arc4_count; - -static inline uint8_t arc4_getbyte(void); -static void arc4_stir(void); - -static inline void -arc4_init(void) -{ - int n; - - for (n = 0; n < 256; n++) - rs.s[n] = n; - rs.i = 0; - rs.j = 0; -} - -static inline void -arc4_addrandom(u_char *dat, int datlen) -{ - int n; - uint8_t si; - - rs.i--; - for (n = 0; n < 256; n++) { - rs.i = (rs.i + 1); - si = rs.s[rs.i]; - rs.j = (rs.j + si + dat[n % datlen]); - rs.s[rs.i] = rs.s[rs.j]; - rs.s[rs.j] = si; - } - rs.j = rs.i; -} - -static void -arc4_stir(void) -{ - int done, fd, i; - struct { - struct timeval tv; - pid_t pid; - u_char rnd[KEYSIZE]; - } rdat; - - if (!rs_initialized) { - arc4_init(); - rs_initialized = 1; - } - done = 0; - fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); - if (fd >= 0) { - if (read(fd, &rdat, KEYSIZE) == KEYSIZE) - done = 1; - (void)close(fd); - } - if (!done) { - (void)gettimeofday(&rdat.tv, NULL); - rdat.pid = getpid(); - /* We'll just take whatever was on the stack too... */ - } - - arc4_addrandom((u_char *)&rdat, KEYSIZE); - - /* - * Discard early keystream, as per recommendations in: - * "(Not So) Random Shuffles of RC4" by Ilya Mironov. - * As per the Network Operations Division, cryptographic requirements - * published on wikileaks on March 2017. - */ - - for (i = 0; i < 3072; i++) - (void)arc4_getbyte(); - arc4_count = 1600000; -} - -static void -arc4_stir_if_needed(void) -{ - pid_t pid = getpid(); - - if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { - arc4_stir_pid = pid; - arc4_stir(); - } -} - -static inline uint8_t -arc4_getbyte(void) -{ - uint8_t si, sj; - - rs.i = (rs.i + 1); - si = rs.s[rs.i]; - rs.j = (rs.j + si); - sj = rs.s[rs.j]; - rs.s[rs.i] = sj; - rs.s[rs.j] = si; - return (rs.s[(si + sj) & 0xff]); -} - -static void -arc4random_buf(void *_buf, size_t n) -{ - u_char *buf = (u_char *)_buf; - _ARC4_LOCK(); - arc4_stir_if_needed(); - while (n--) { - if (--arc4_count <= 0) - arc4_stir(); - buf[n] = arc4_getbyte(); - } - _ARC4_UNLOCK(); -} - -#endif /* !HAVE_ARC4RANDOM_BUF */ diff --git a/3rdparty/libarchive/libarchive/archive_random_private.h b/3rdparty/libarchive/libarchive/archive_random_private.h deleted file mode 100644 index c414779f..00000000 --- a/3rdparty/libarchive/libarchive/archive_random_private.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 2014 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_RANDOM_PRIVATE_H_INCLUDED -#define ARCHIVE_RANDOM_PRIVATE_H_INCLUDED - -/* Random number generator. */ -int archive_random(void *buf, size_t nbytes); - -#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_rb.c b/3rdparty/libarchive/libarchive/archive_rb.c deleted file mode 100644 index cf58ac33..00000000 --- a/3rdparty/libarchive/libarchive/archive_rb.c +++ /dev/null @@ -1,709 +0,0 @@ -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matt Thomas . - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Based on: NetBSD: rb.c,v 1.6 2010/04/30 13:58:09 joerg Exp - */ - -#include "archive_platform.h" - -#include - -#include "archive_rb.h" - -/* Keep in sync with archive_rb.h */ -#define RB_DIR_LEFT 0 -#define RB_DIR_RIGHT 1 -#define RB_DIR_OTHER 1 -#define rb_left rb_nodes[RB_DIR_LEFT] -#define rb_right rb_nodes[RB_DIR_RIGHT] - -#define RB_FLAG_POSITION 0x2 -#define RB_FLAG_RED 0x1 -#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED) -#define RB_FATHER(rb) \ - ((struct archive_rb_node *)((rb)->rb_info & ~RB_FLAG_MASK)) -#define RB_SET_FATHER(rb, father) \ - ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK))) - -#define RB_SENTINEL_P(rb) ((rb) == NULL) -#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left) -#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right) -#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb))) -#define RB_CHILDLESS_P(rb) \ - (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb))) -#define RB_TWOCHILDREN_P(rb) \ - (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb)) - -#define RB_POSITION(rb) \ - (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT) -#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT) -#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT) -#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0) -#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0) -#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED)) -#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED)) -#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED)) -#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb)) -#define RB_SET_POSITION(rb, position) \ - ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \ - ((rb)->rb_info &= ~RB_FLAG_POSITION))) -#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK)) -#define RB_COPY_PROPERTIES(dst, src) \ - ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK)) -#define RB_SWAP_PROPERTIES(a, b) do { \ - uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \ - (a)->rb_info ^= xorinfo; \ - (b)->rb_info ^= xorinfo; \ - } while (/*CONSTCOND*/ 0) - -static void __archive_rb_tree_insert_rebalance(struct archive_rb_tree *, - struct archive_rb_node *); -static void __archive_rb_tree_removal_rebalance(struct archive_rb_tree *, - struct archive_rb_node *, unsigned int); - -#define RB_SENTINEL_NODE NULL - -#define T 1 -#define F 0 - -void -__archive_rb_tree_init(struct archive_rb_tree *rbt, - const struct archive_rb_tree_ops *ops) -{ - rbt->rbt_ops = ops; - *((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE; -} - -struct archive_rb_node * -__archive_rb_tree_find_node(struct archive_rb_tree *rbt, const void *key) -{ - archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; - struct archive_rb_node *parent = rbt->rbt_root; - - while (!RB_SENTINEL_P(parent)) { - const signed int diff = (*compare_key)(parent, key); - if (diff == 0) - return parent; - parent = parent->rb_nodes[diff > 0]; - } - - return NULL; -} - -struct archive_rb_node * -__archive_rb_tree_find_node_geq(struct archive_rb_tree *rbt, const void *key) -{ - archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; - struct archive_rb_node *parent = rbt->rbt_root; - struct archive_rb_node *last = NULL; - - while (!RB_SENTINEL_P(parent)) { - const signed int diff = (*compare_key)(parent, key); - if (diff == 0) - return parent; - if (diff < 0) - last = parent; - parent = parent->rb_nodes[diff > 0]; - } - - return last; -} - -struct archive_rb_node * -__archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key) -{ - archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; - struct archive_rb_node *parent = rbt->rbt_root; - struct archive_rb_node *last = NULL; - - while (!RB_SENTINEL_P(parent)) { - const signed int diff = (*compare_key)(parent, key); - if (diff == 0) - return parent; - if (diff > 0) - last = parent; - parent = parent->rb_nodes[diff > 0]; - } - - return last; -} - -int -__archive_rb_tree_insert_node(struct archive_rb_tree *rbt, - struct archive_rb_node *self) -{ - archive_rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes; - struct archive_rb_node *parent, *tmp; - unsigned int position; - int rebalance; - - tmp = rbt->rbt_root; - /* - * This is a hack. Because rbt->rbt_root is just a - * struct archive_rb_node *, just like rb_node->rb_nodes[RB_DIR_LEFT], - * we can use this fact to avoid a lot of tests for root and know - * that even at root, updating - * RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will - * update rbt->rbt_root. - */ - parent = (struct archive_rb_node *)(void *)&rbt->rbt_root; - position = RB_DIR_LEFT; - - /* - * Find out where to place this new leaf. - */ - while (!RB_SENTINEL_P(tmp)) { - const signed int diff = (*compare_nodes)(tmp, self); - if (diff == 0) { - /* - * Node already exists; don't insert. - */ - return F; - } - parent = tmp; - position = (diff > 0); - tmp = parent->rb_nodes[position]; - } - - /* - * Initialize the node and insert as a leaf into the tree. - */ - RB_SET_FATHER(self, parent); - RB_SET_POSITION(self, position); - if (parent == (struct archive_rb_node *)(void *)&rbt->rbt_root) { - RB_MARK_BLACK(self); /* root is always black */ - rebalance = F; - } else { - /* - * All new nodes are colored red. We only need to rebalance - * if our parent is also red. - */ - RB_MARK_RED(self); - rebalance = RB_RED_P(parent); - } - self->rb_left = parent->rb_nodes[position]; - self->rb_right = parent->rb_nodes[position]; - parent->rb_nodes[position] = self; - - /* - * Rebalance tree after insertion - */ - if (rebalance) - __archive_rb_tree_insert_rebalance(rbt, self); - - return T; -} - -/* - * Swap the location and colors of 'self' and its child @ which. The child - * can not be a sentinel node. This is our rotation function. However, - * since it preserves coloring, it great simplifies both insertion and - * removal since rotation almost always involves the exchanging of colors - * as a separate step. - */ -/*ARGSUSED*/ -static void -__archive_rb_tree_reparent_nodes( - struct archive_rb_node *old_father, const unsigned int which) -{ - const unsigned int other = which ^ RB_DIR_OTHER; - struct archive_rb_node * const grandpa = RB_FATHER(old_father); - struct archive_rb_node * const old_child = old_father->rb_nodes[which]; - struct archive_rb_node * const new_father = old_child; - struct archive_rb_node * const new_child = old_father; - - if (new_father == NULL) - return; - /* - * Exchange descendant linkages. - */ - grandpa->rb_nodes[RB_POSITION(old_father)] = new_father; - new_child->rb_nodes[which] = old_child->rb_nodes[other]; - new_father->rb_nodes[other] = new_child; - - /* - * Update ancestor linkages - */ - RB_SET_FATHER(new_father, grandpa); - RB_SET_FATHER(new_child, new_father); - - /* - * Exchange properties between new_father and new_child. The only - * change is that new_child's position is now on the other side. - */ - RB_SWAP_PROPERTIES(new_father, new_child); - RB_SET_POSITION(new_child, other); - - /* - * Make sure to reparent the new child to ourself. - */ - if (!RB_SENTINEL_P(new_child->rb_nodes[which])) { - RB_SET_FATHER(new_child->rb_nodes[which], new_child); - RB_SET_POSITION(new_child->rb_nodes[which], which); - } - -} - -static void -__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt, - struct archive_rb_node *self) -{ - struct archive_rb_node * father = RB_FATHER(self); - struct archive_rb_node * grandpa; - struct archive_rb_node * uncle; - unsigned int which; - unsigned int other; - - for (;;) { - /* - * We are red and our parent is red, therefore we must have a - * grandfather and he must be black. - */ - grandpa = RB_FATHER(father); - which = (father == grandpa->rb_right); - other = which ^ RB_DIR_OTHER; - uncle = grandpa->rb_nodes[other]; - - if (RB_BLACK_P(uncle)) - break; - - /* - * Case 1: our uncle is red - * Simply invert the colors of our parent and - * uncle and make our grandparent red. And - * then solve the problem up at his level. - */ - RB_MARK_BLACK(uncle); - RB_MARK_BLACK(father); - if (RB_ROOT_P(rbt, grandpa)) { - /* - * If our grandpa is root, don't bother - * setting him to red, just return. - */ - return; - } - RB_MARK_RED(grandpa); - self = grandpa; - father = RB_FATHER(self); - if (RB_BLACK_P(father)) { - /* - * If our great-grandpa is black, we're done. - */ - return; - } - } - - /* - * Case 2&3: our uncle is black. - */ - if (self == father->rb_nodes[other]) { - /* - * Case 2: we are on the same side as our uncle - * Swap ourselves with our parent so this case - * becomes case 3. Basically our parent becomes our - * child. - */ - __archive_rb_tree_reparent_nodes(father, other); - } - /* - * Case 3: we are opposite a child of a black uncle. - * Swap our parent and grandparent. Since our grandfather - * is black, our father will become black and our new sibling - * (former grandparent) will become red. - */ - __archive_rb_tree_reparent_nodes(grandpa, which); - - /* - * Final step: Set the root to black. - */ - RB_MARK_BLACK(rbt->rbt_root); -} - -static void -__archive_rb_tree_prune_node(struct archive_rb_tree *rbt, - struct archive_rb_node *self, int rebalance) -{ - const unsigned int which = RB_POSITION(self); - struct archive_rb_node *father = RB_FATHER(self); - - /* - * Since we are childless, we know that self->rb_left is pointing - * to the sentinel node. - */ - father->rb_nodes[which] = self->rb_left; - - /* - * Rebalance if requested. - */ - if (rebalance) - __archive_rb_tree_removal_rebalance(rbt, father, which); -} - -/* - * When deleting an interior node - */ -static void -__archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt, - struct archive_rb_node *self, struct archive_rb_node *standin) -{ - const unsigned int standin_which = RB_POSITION(standin); - unsigned int standin_other = standin_which ^ RB_DIR_OTHER; - struct archive_rb_node *standin_son; - struct archive_rb_node *standin_father = RB_FATHER(standin); - int rebalance = RB_BLACK_P(standin); - - if (standin_father == self) { - /* - * As a child of self, any children would be opposite of - * our parent. - */ - standin_son = standin->rb_nodes[standin_which]; - } else { - /* - * Since we aren't a child of self, any children would be - * on the same side as our parent. - */ - standin_son = standin->rb_nodes[standin_other]; - } - - if (RB_RED_P(standin_son)) { - /* - * We know we have a red child so if we flip it to black - * we don't have to rebalance. - */ - RB_MARK_BLACK(standin_son); - rebalance = F; - - if (standin_father != self) { - /* - * Change the son's parentage to point to his grandpa. - */ - RB_SET_FATHER(standin_son, standin_father); - RB_SET_POSITION(standin_son, standin_which); - } - } - - if (standin_father == self) { - /* - * If we are about to delete the standin's father, then when - * we call rebalance, we need to use ourselves as our father. - * Otherwise remember our original father. Also, since we are - * our standin's father we only need to reparent the standin's - * brother. - * - * | R --> S | - * | Q S --> Q T | - * | t --> | - * - * Have our son/standin adopt his brother as his new son. - */ - standin_father = standin; - } else { - /* - * | R --> S . | - * | / \ | T --> / \ | / | - * | ..... | S --> ..... | T | - * - * Sever standin's connection to his father. - */ - standin_father->rb_nodes[standin_which] = standin_son; - /* - * Adopt the far son. - */ - standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; - RB_SET_FATHER(standin->rb_nodes[standin_other], standin); - /* - * Use standin_other because we need to preserve standin_which - * for the removal_rebalance. - */ - standin_other = standin_which; - } - - /* - * Move the only remaining son to our standin. If our standin is our - * son, this will be the only son needed to be moved. - */ - standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; - RB_SET_FATHER(standin->rb_nodes[standin_other], standin); - - /* - * Now copy the result of self to standin and then replace - * self with standin in the tree. - */ - RB_COPY_PROPERTIES(standin, self); - RB_SET_FATHER(standin, RB_FATHER(self)); - RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin; - - if (rebalance) - __archive_rb_tree_removal_rebalance(rbt, standin_father, standin_which); -} - -/* - * We could do this by doing - * __archive_rb_tree_node_swap(rbt, self, which); - * __archive_rb_tree_prune_node(rbt, self, F); - * - * But it's more efficient to just evaluate and recolor the child. - */ -static void -__archive_rb_tree_prune_blackred_branch( - struct archive_rb_node *self, unsigned int which) -{ - struct archive_rb_node *father = RB_FATHER(self); - struct archive_rb_node *son = self->rb_nodes[which]; - - /* - * Remove ourselves from the tree and give our former child our - * properties (position, color, root). - */ - RB_COPY_PROPERTIES(son, self); - father->rb_nodes[RB_POSITION(son)] = son; - RB_SET_FATHER(son, father); -} -/* - * - */ -void -__archive_rb_tree_remove_node(struct archive_rb_tree *rbt, - struct archive_rb_node *self) -{ - struct archive_rb_node *standin; - unsigned int which; - - /* - * In the following diagrams, we (the node to be removed) are S. Red - * nodes are lowercase. T could be either red or black. - * - * Remember the major axiom of the red-black tree: the number of - * black nodes from the root to each leaf is constant across all - * leaves, only the number of red nodes varies. - * - * Thus removing a red leaf doesn't require any other changes to a - * red-black tree. So if we must remove a node, attempt to rearrange - * the tree so we can remove a red node. - * - * The simplest case is a childless red node or a childless root node: - * - * | T --> T | or | R --> * | - * | s --> * | - */ - if (RB_CHILDLESS_P(self)) { - const int rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self); - __archive_rb_tree_prune_node(rbt, self, rebalance); - return; - } - if (!RB_TWOCHILDREN_P(self)) { - /* - * The next simplest case is the node we are deleting is - * black and has one red child. - * - * | T --> T --> T | - * | S --> R --> R | - * | r --> s --> * | - */ - which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT; - __archive_rb_tree_prune_blackred_branch(self, which); - return; - } - - /* - * We invert these because we prefer to remove from the inside of - * the tree. - */ - which = RB_POSITION(self) ^ RB_DIR_OTHER; - - /* - * Let's find the node closes to us opposite of our parent - * Now swap it with ourself, "prune" it, and rebalance, if needed. - */ - standin = __archive_rb_tree_iterate(rbt, self, which); - __archive_rb_tree_swap_prune_and_rebalance(rbt, self, standin); -} - -static void -__archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt, - struct archive_rb_node *parent, unsigned int which) -{ - - while (RB_BLACK_P(parent->rb_nodes[which])) { - unsigned int other = which ^ RB_DIR_OTHER; - struct archive_rb_node *brother = parent->rb_nodes[other]; - - if (brother == NULL) - return;/* The tree may be broken. */ - /* - * For cases 1, 2a, and 2b, our brother's children must - * be black and our father must be black - */ - if (RB_BLACK_P(parent) - && RB_BLACK_P(brother->rb_left) - && RB_BLACK_P(brother->rb_right)) { - if (RB_RED_P(brother)) { - /* - * Case 1: Our brother is red, swap its - * position (and colors) with our parent. - * This should now be case 2b (unless C or E - * has a red child which is case 3; thus no - * explicit branch to case 2b). - * - * B -> D - * A d -> b E - * C E -> A C - */ - __archive_rb_tree_reparent_nodes(parent, other); - brother = parent->rb_nodes[other]; - if (brother == NULL) - return;/* The tree may be broken. */ - } else { - /* - * Both our parent and brother are black. - * Change our brother to red, advance up rank - * and go through the loop again. - * - * B -> *B - * *A D -> A d - * C E -> C E - */ - RB_MARK_RED(brother); - if (RB_ROOT_P(rbt, parent)) - return; /* root == parent == black */ - which = RB_POSITION(parent); - parent = RB_FATHER(parent); - continue; - } - } - /* - * Avoid an else here so that case 2a above can hit either - * case 2b, 3, or 4. - */ - if (RB_RED_P(parent) - && RB_BLACK_P(brother) - && RB_BLACK_P(brother->rb_left) - && RB_BLACK_P(brother->rb_right)) { - /* - * We are black, our father is red, our brother and - * both nephews are black. Simply invert/exchange the - * colors of our father and brother (to black and red - * respectively). - * - * | f --> F | - * | * B --> * b | - * | N N --> N N | - */ - RB_MARK_BLACK(parent); - RB_MARK_RED(brother); - break; /* We're done! */ - } else { - /* - * Our brother must be black and have at least one - * red child (it may have two). - */ - if (RB_BLACK_P(brother->rb_nodes[other])) { - /* - * Case 3: our brother is black, our near - * nephew is red, and our far nephew is black. - * Swap our brother with our near nephew. - * This result in a tree that matches case 4. - * (Our father could be red or black). - * - * | F --> F | - * | x B --> x B | - * | n --> n | - */ - __archive_rb_tree_reparent_nodes(brother, which); - brother = parent->rb_nodes[other]; - } - /* - * Case 4: our brother is black and our far nephew - * is red. Swap our father and brother locations and - * change our far nephew to black. (these can be - * done in either order so we change the color first). - * The result is a valid red-black tree and is a - * terminal case. (again we don't care about the - * father's color) - * - * If the father is red, we will get a red-black-black - * tree: - * | f -> f --> b | - * | B -> B --> F N | - * | n -> N --> | - * - * If the father is black, we will get an all black - * tree: - * | F -> F --> B | - * | B -> B --> F N | - * | n -> N --> | - * - * If we had two red nephews, then after the swap, - * our former father would have a red grandson. - */ - if (brother->rb_nodes[other] == NULL) - return;/* The tree may be broken. */ - RB_MARK_BLACK(brother->rb_nodes[other]); - __archive_rb_tree_reparent_nodes(parent, other); - break; /* We're done! */ - } - } -} - -struct archive_rb_node * -__archive_rb_tree_iterate(struct archive_rb_tree *rbt, - struct archive_rb_node *self, const unsigned int direction) -{ - const unsigned int other = direction ^ RB_DIR_OTHER; - - if (self == NULL) { - self = rbt->rbt_root; - if (RB_SENTINEL_P(self)) - return NULL; - while (!RB_SENTINEL_P(self->rb_nodes[direction])) - self = self->rb_nodes[direction]; - return self; - } - /* - * We can't go any further in this direction. We proceed up in the - * opposite direction until our parent is in direction we want to go. - */ - if (RB_SENTINEL_P(self->rb_nodes[direction])) { - while (!RB_ROOT_P(rbt, self)) { - if (other == (unsigned int)RB_POSITION(self)) - return RB_FATHER(self); - self = RB_FATHER(self); - } - return NULL; - } - - /* - * Advance down one in current direction and go down as far as possible - * in the opposite direction. - */ - self = self->rb_nodes[direction]; - while (!RB_SENTINEL_P(self->rb_nodes[other])) - self = self->rb_nodes[other]; - return self; -} diff --git a/3rdparty/libarchive/libarchive/archive_rb.h b/3rdparty/libarchive/libarchive/archive_rb.h deleted file mode 100644 index 4562e9eb..00000000 --- a/3rdparty/libarchive/libarchive/archive_rb.h +++ /dev/null @@ -1,100 +0,0 @@ -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matt Thomas . - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Based on NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp - */ -#ifndef ARCHIVE_RB_H_ -#define ARCHIVE_RB_H_ - -struct archive_rb_node { - struct archive_rb_node *rb_nodes[2]; - /* - * rb_info contains the two flags and the parent back pointer. - * We put the two flags in the low two bits since we know that - * rb_node will have an alignment of 4 or 8 bytes. - */ - uintptr_t rb_info; -}; - -#define ARCHIVE_RB_DIR_LEFT 0 -#define ARCHIVE_RB_DIR_RIGHT 1 - -#define ARCHIVE_RB_TREE_MIN(T) \ - __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_LEFT) -#define ARCHIVE_RB_TREE_MAX(T) \ - __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_RIGHT) -#define ARCHIVE_RB_TREE_FOREACH(N, T) \ - for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \ - (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT)) -#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \ - for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \ - (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT)) - -/* - * archive_rbto_compare_nodes_fn: - * return a positive value if the first node < the second node. - * return a negative value if the first node > the second node. - * return 0 if they are considered same. - * - * archive_rbto_compare_key_fn: - * return a positive value if the node < the key. - * return a negative value if the node > the key. - * return 0 if they are considered same. - */ - -typedef signed int (*const archive_rbto_compare_nodes_fn)(const struct archive_rb_node *, - const struct archive_rb_node *); -typedef signed int (*const archive_rbto_compare_key_fn)(const struct archive_rb_node *, - const void *); - -struct archive_rb_tree_ops { - archive_rbto_compare_nodes_fn rbto_compare_nodes; - archive_rbto_compare_key_fn rbto_compare_key; -}; - -struct archive_rb_tree { - struct archive_rb_node *rbt_root; - const struct archive_rb_tree_ops *rbt_ops; -}; - -void __archive_rb_tree_init(struct archive_rb_tree *, - const struct archive_rb_tree_ops *); -int __archive_rb_tree_insert_node(struct archive_rb_tree *, - struct archive_rb_node *); -struct archive_rb_node * - __archive_rb_tree_find_node(struct archive_rb_tree *, const void *); -struct archive_rb_node * - __archive_rb_tree_find_node_geq(struct archive_rb_tree *, const void *); -struct archive_rb_node * - __archive_rb_tree_find_node_leq(struct archive_rb_tree *, const void *); -void __archive_rb_tree_remove_node(struct archive_rb_tree *, struct archive_rb_node *); -struct archive_rb_node * - __archive_rb_tree_iterate(struct archive_rb_tree *, - struct archive_rb_node *, const unsigned int); - -#endif /* ARCHIVE_RB_H_*/ diff --git a/3rdparty/libarchive/libarchive/archive_read.c b/3rdparty/libarchive/libarchive/archive_read.c deleted file mode 100644 index a642a336..00000000 --- a/3rdparty/libarchive/libarchive/archive_read.c +++ /dev/null @@ -1,1739 +0,0 @@ -/*- - * Copyright (c) 2003-2011 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file contains the "essential" portions of the read API, that - * is, stuff that will probably always be used by any client that - * actually needs to read an archive. Optional pieces have been, as - * far as possible, separated out into separate files to avoid - * needlessly bloating statically-linked clients. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:23Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#define minimum(a, b) (a < b ? a : b) - -static int choose_filters(struct archive_read *); -static int choose_format(struct archive_read *); -static int close_filters(struct archive_read *); -static struct archive_vtable *archive_read_vtable(void); -static int64_t _archive_filter_bytes(struct archive *, int); -static int _archive_filter_code(struct archive *, int); -static const char *_archive_filter_name(struct archive *, int); -static int _archive_filter_count(struct archive *); -static int _archive_read_close(struct archive *); -static int _archive_read_data_block(struct archive *, - const void **, size_t *, int64_t *); -static int _archive_read_free(struct archive *); -static int _archive_read_next_header(struct archive *, - struct archive_entry **); -static int _archive_read_next_header2(struct archive *, - struct archive_entry *); -static int64_t advance_file_pointer(struct archive_read_filter *, int64_t); - -static struct archive_vtable * -archive_read_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_filter_bytes = _archive_filter_bytes; - av.archive_filter_code = _archive_filter_code; - av.archive_filter_name = _archive_filter_name; - av.archive_filter_count = _archive_filter_count; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - inited = 1; - } - return (&av); -} - -/* - * Allocate, initialize and return a struct archive object. - */ -struct archive * -archive_read_new(void) -{ - struct archive_read *a; - - a = (struct archive_read *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_READ_MAGIC; - - a->archive.state = ARCHIVE_STATE_NEW; - a->entry = archive_entry_new2(&a->archive); - a->archive.vtable = archive_read_vtable(); - - a->passphrases.last = &a->passphrases.first; - - return (&a->archive); -} - -/* - * Record the do-not-extract-to file. This belongs in archive_read_extract.c. - */ -void -archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i) -{ - struct archive_read *a = (struct archive_read *)_a; - - if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file")) - return; - a->skip_file_set = 1; - a->skip_file_dev = d; - a->skip_file_ino = i; -} - -/* - * Open the archive - */ -int -archive_read_open(struct archive *a, void *client_data, - archive_open_callback *client_opener, archive_read_callback *client_reader, - archive_close_callback *client_closer) -{ - /* 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); - return archive_read_open1(a); -} - - -int -archive_read_open2(struct archive *a, void *client_data, - archive_open_callback *client_opener, - archive_read_callback *client_reader, - archive_skip_callback *client_skipper, - archive_close_callback *client_closer) -{ - /* Old archive_read_open2() is just a thin shell around - * archive_read_open1. */ - archive_read_set_callback_data(a, client_data); - archive_read_set_open_callback(a, client_opener); - archive_read_set_read_callback(a, client_reader); - archive_read_set_skip_callback(a, client_skipper); - archive_read_set_close_callback(a, client_closer); - return archive_read_open1(a); -} - -static ssize_t -client_read_proxy(struct archive_read_filter *self, const void **buff) -{ - ssize_t r; - r = (self->archive->client.reader)(&self->archive->archive, - self->data, buff); - return (r); -} - -static int64_t -client_skip_proxy(struct archive_read_filter *self, int64_t request) -{ - if (request < 0) - __archive_errx(1, "Negative skip requested."); - if (request == 0) - return 0; - - if (self->archive->client.skipper != NULL) { - /* Seek requests over 1GiB are broken down into - * multiple seeks. This avoids overflows when the - * requests get passed through 32-bit arguments. */ - int64_t skip_limit = (int64_t)1 << 30; - int64_t total = 0; - for (;;) { - int64_t get, ask = request; - if (ask > skip_limit) - ask = skip_limit; - get = (self->archive->client.skipper) - (&self->archive->archive, self->data, ask); - total += get; - if (get == 0 || get == request) - return (total); - if (get > request) - return ARCHIVE_FATAL; - request -= get; - } - } else if (self->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. - * - * Note: This isn't always a good idea. The client - * skipper is allowed to skip by less than requested - * if it needs to maintain block alignment. The - * seeker is not allowed to play such games, so using - * the seeker here may be a performance loss compared - * 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); - if (after != before + request) - return ARCHIVE_FATAL; - return after - before; - } - return 0; -} - -static int64_t -client_seek_proxy(struct archive_read_filter *self, 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, - "Current client reader does not support seeking a device"); - return (ARCHIVE_FAILED); - } - return (self->archive->client.seeker)(&self->archive->archive, - self->data, offset, whence); -} - -static int -client_close_proxy(struct archive_read_filter *self) -{ - int r = ARCHIVE_OK, r2; - unsigned int i; - - if (self->archive->client.closer == NULL) - return (r); - for (i = 0; i < self->archive->client.nodes; i++) - { - r2 = (self->archive->client.closer) - ((struct archive *)self->archive, - self->archive->client.dataset[i].data); - if (r > r2) - r = r2; - } - return (r); -} - -static int -client_open_proxy(struct archive_read_filter *self) -{ - int r = ARCHIVE_OK; - if (self->archive->client.opener != NULL) - r = (self->archive->client.opener)( - (struct archive *)self->archive, self->data); - return (r); -} - -static int -client_switch_proxy(struct archive_read_filter *self, unsigned int iindex) -{ - int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; - void *data2 = NULL; - - /* Don't do anything if already in the specified data node */ - if (self->archive->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) - { - r1 = r2 = (self->archive->client.switcher) - ((struct archive *)self->archive, self->data, data2); - self->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; - if (self->archive->client.opener != NULL) - r2 = (self->archive->client.opener) - ((struct archive *)self->archive, self->data); - } - return (r1 < r2) ? r1 : r2; -} - -int -archive_read_set_open_callback(struct archive *_a, - archive_open_callback *client_opener) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_open_callback"); - a->client.opener = client_opener; - return ARCHIVE_OK; -} - -int -archive_read_set_read_callback(struct archive *_a, - archive_read_callback *client_reader) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_read_callback"); - a->client.reader = client_reader; - return ARCHIVE_OK; -} - -int -archive_read_set_skip_callback(struct archive *_a, - archive_skip_callback *client_skipper) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_skip_callback"); - a->client.skipper = client_skipper; - return ARCHIVE_OK; -} - -int -archive_read_set_seek_callback(struct archive *_a, - archive_seek_callback *client_seeker) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_seek_callback"); - a->client.seeker = client_seeker; - return ARCHIVE_OK; -} - -int -archive_read_set_close_callback(struct archive *_a, - archive_close_callback *client_closer) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_close_callback"); - a->client.closer = client_closer; - return ARCHIVE_OK; -} - -int -archive_read_set_switch_callback(struct archive *_a, - archive_switch_callback *client_switcher) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_switch_callback"); - a->client.switcher = client_switcher; - return ARCHIVE_OK; -} - -int -archive_read_set_callback_data(struct archive *_a, void *client_data) -{ - return archive_read_set_callback_data2(_a, client_data, 0); -} - -int -archive_read_set_callback_data2(struct archive *_a, void *client_data, - unsigned int iindex) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_set_callback_data2"); - - if (a->client.nodes == 0) - { - a->client.dataset = (struct archive_read_data_node *) - calloc(1, sizeof(*a->client.dataset)); - if (a->client.dataset == NULL) - { - archive_set_error(&a->archive, ENOMEM, - "No memory."); - return ARCHIVE_FATAL; - } - a->client.nodes = 1; - } - - if (iindex > a->client.nodes - 1) - { - archive_set_error(&a->archive, EINVAL, - "Invalid index specified."); - return ARCHIVE_FATAL; - } - a->client.dataset[iindex].data = client_data; - a->client.dataset[iindex].begin_position = -1; - a->client.dataset[iindex].total_size = -1; - return ARCHIVE_OK; -} - -int -archive_read_add_callback_data(struct archive *_a, void *client_data, - unsigned int iindex) -{ - struct archive_read *a = (struct archive_read *)_a; - void *p; - unsigned int i; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_add_callback_data"); - if (iindex > a->client.nodes) { - archive_set_error(&a->archive, EINVAL, - "Invalid index specified."); - return ARCHIVE_FATAL; - } - p = realloc(a->client.dataset, sizeof(*a->client.dataset) - * (++(a->client.nodes))); - if (p == NULL) { - archive_set_error(&a->archive, ENOMEM, - "No memory."); - return ARCHIVE_FATAL; - } - a->client.dataset = (struct archive_read_data_node *)p; - for (i = a->client.nodes - 1; i > iindex && i > 0; i--) { - a->client.dataset[i].data = a->client.dataset[i-1].data; - a->client.dataset[i].begin_position = -1; - a->client.dataset[i].total_size = -1; - } - a->client.dataset[iindex].data = client_data; - a->client.dataset[iindex].begin_position = -1; - a->client.dataset[iindex].total_size = -1; - return ARCHIVE_OK; -} - -int -archive_read_append_callback_data(struct archive *_a, void *client_data) -{ - struct archive_read *a = (struct archive_read *)_a; - return archive_read_add_callback_data(_a, client_data, a->client.nodes); -} - -int -archive_read_prepend_callback_data(struct archive *_a, void *client_data) -{ - return archive_read_add_callback_data(_a, client_data, 0); -} - -int -archive_read_open1(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *filter, *tmp; - int slot, e = ARCHIVE_OK; - unsigned int i; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "archive_read_open"); - archive_clear_error(&a->archive); - - if (a->client.reader == NULL) { - archive_set_error(&a->archive, EINVAL, - "No reader function provided to archive_read_open"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - - /* Open data source. */ - if (a->client.opener != NULL) { - e = (a->client.opener)(&a->archive, a->client.dataset[0].data); - if (e != 0) { - /* If the open failed, call the closer to clean up. */ - if (a->client.closer) { - for (i = 0; i < a->client.nodes; i++) - (a->client.closer)(&a->archive, - a->client.dataset[i].data); - } - return (e); - } - } - - filter = calloc(1, sizeof(*filter)); - if (filter == NULL) - return (ARCHIVE_FATAL); - filter->bidder = NULL; - filter->upstream = NULL; - filter->archive = a; - filter->data = a->client.dataset[0].data; - filter->open = client_open_proxy; - filter->read = client_read_proxy; - filter->skip = client_skip_proxy; - filter->seek = client_seek_proxy; - filter->close = client_close_proxy; - filter->sswitch = client_switch_proxy; - filter->name = "none"; - filter->code = ARCHIVE_FILTER_NONE; - - a->client.dataset[0].begin_position = 0; - if (!a->filter || !a->bypass_filter_bidding) - { - a->filter = filter; - /* Build out the input pipeline. */ - e = choose_filters(a); - if (e < ARCHIVE_WARN) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } - else - { - /* Need to add "NONE" type filter at the end of the filter chain */ - tmp = a->filter; - while (tmp->upstream) - tmp = tmp->upstream; - tmp->upstream = filter; - } - - if (!a->format) - { - slot = choose_format(a); - if (slot < 0) { - close_filters(a); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - a->format = &(a->formats[slot]); - } - - a->archive.state = ARCHIVE_STATE_HEADER; - - /* Ensure libarchive starts from the first node in a multivolume set */ - client_switch_proxy(a->filter, 0); - return (e); -} - -/* - * Allow each registered stream transform to bid on whether - * it wants to handle this stream. Repeat until we've finished - * building the pipeline. - */ - -/* We won't build a filter pipeline with more stages than this. */ -#define MAX_NUMBER_FILTERS 25 - -static int -choose_filters(struct archive_read *a) -{ - int number_bidders, i, bid, best_bid, number_filters; - struct archive_read_filter_bidder *bidder, *best_bidder; - struct archive_read_filter *filter; - ssize_t avail; - int r; - - for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) { - number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - - best_bid = 0; - best_bidder = NULL; - - bidder = a->bidders; - for (i = 0; i < number_bidders; i++, bidder++) { - if (bidder->bid != NULL) { - bid = (bidder->bid)(bidder, a->filter); - if (bid > best_bid) { - best_bid = bid; - best_bidder = bidder; - } - } - } - - /* If no bidder, we're done. */ - if (best_bidder == NULL) { - /* Verify the filter by asking it for some data. */ - __archive_read_filter_ahead(a->filter, 1, &avail); - if (avail < 0) { - __archive_read_free_filters(a); - return (ARCHIVE_FATAL); - } - a->archive.compression_name = a->filter->name; - a->archive.compression_code = a->filter->code; - return (ARCHIVE_OK); - } - - filter - = (struct archive_read_filter *)calloc(1, sizeof(*filter)); - if (filter == NULL) - return (ARCHIVE_FATAL); - filter->bidder = best_bidder; - filter->archive = a; - filter->upstream = a->filter; - a->filter = filter; - r = (best_bidder->init)(a->filter); - if (r != ARCHIVE_OK) { - __archive_read_free_filters(a); - return (ARCHIVE_FATAL); - } - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Input requires too many filters for decoding"); - return (ARCHIVE_FATAL); -} - -/* - * Read header of next entry. - */ -static int -_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) -{ - struct archive_read *a = (struct archive_read *)_a; - int r1 = ARCHIVE_OK, r2; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_next_header"); - - archive_entry_clear(entry); - archive_clear_error(&a->archive); - - /* - * If client didn't consume entire data, skip any remainder - * (This is especially important for GNU incremental directories.) - */ - if (a->archive.state == ARCHIVE_STATE_DATA) { - r1 = archive_read_data_skip(&a->archive); - if (r1 == ARCHIVE_EOF) - archive_set_error(&a->archive, EIO, - "Premature end-of-file."); - if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } - - /* Record start-of-header offset in uncompressed stream. */ - a->header_position = a->filter->position; - - ++_a->file_count; - r2 = (a->format->read_header)(a, entry); - - /* - * EOF and FATAL are persistent at this layer. By - * modifying the state, we guarantee that future calls to - * read a header or read data will fail. - */ - switch (r2) { - case ARCHIVE_EOF: - a->archive.state = ARCHIVE_STATE_EOF; - --_a->file_count;/* Revert a file counter. */ - break; - case ARCHIVE_OK: - a->archive.state = ARCHIVE_STATE_DATA; - break; - case ARCHIVE_WARN: - a->archive.state = ARCHIVE_STATE_DATA; - break; - case ARCHIVE_RETRY: - break; - case ARCHIVE_FATAL: - a->archive.state = ARCHIVE_STATE_FATAL; - break; - } - - __archive_reset_read_data(&a->archive); - - a->data_start_node = a->client.cursor; - /* EOF always wins; otherwise return the worst error. */ - return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1; -} - -static int -_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) -{ - int ret; - struct archive_read *a = (struct archive_read *)_a; - *entryp = NULL; - ret = _archive_read_next_header2(_a, a->entry); - *entryp = a->entry; - return ret; -} - -/* - * Allow each registered format to bid on whether it wants to handle - * the next entry. Return index of winning bidder. - */ -static int -choose_format(struct archive_read *a) -{ - int slots; - int i; - int bid, best_bid; - int best_bid_slot; - - slots = sizeof(a->formats) / sizeof(a->formats[0]); - best_bid = -1; - best_bid_slot = -1; - - /* Set up a->format for convenience of bidders. */ - a->format = &(a->formats[0]); - for (i = 0; i < slots; i++, a->format++) { - if (a->format->bid) { - bid = (a->format->bid)(a, best_bid); - if (bid == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - if (a->filter->position != 0) - __archive_read_seek(a, 0, SEEK_SET); - if ((bid > best_bid) || (best_bid_slot < 0)) { - best_bid = bid; - best_bid_slot = i; - } - } - } - - /* - * There were no bidders; this is a serious programmer error - * and demands a quick and definitive abort. - */ - if (best_bid_slot < 0) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "No formats registered"); - return (ARCHIVE_FATAL); - } - - /* - * There were bidders, but no non-zero bids; this means we - * can't support this stream. - */ - if (best_bid < 1) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Unrecognized archive format"); - return (ARCHIVE_FATAL); - } - - return (best_bid_slot); -} - -/* - * Return the file offset (within the uncompressed data stream) where - * the last header started. - */ -int64_t -archive_read_header_position(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_header_position"); - return (a->header_position); -} - -/* - * Returns 1 if the archive contains at least one encrypted entry. - * If the archive format not support encryption at all - * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. - * If for any other reason (e.g. not enough data read so far) - * we cannot say whether there are encrypted entries, then - * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. - * In general, this function will return values below zero when the - * reader is uncertain or totally incapable of encryption support. - * When this function returns 0 you can be sure that the reader - * supports encryption detection but no encrypted entries have - * been found yet. - * - * NOTE: If the metadata/header of an archive is also encrypted, you - * cannot rely on the number of encrypted entries. That is why this - * function does not return the number of encrypted entries but# - * just shows that there are some. - */ -int -archive_read_has_encrypted_entries(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - int format_supports_encryption = archive_read_format_capabilities(_a) - & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); - - if (!_a || !format_supports_encryption) { - /* Format in general doesn't support encryption */ - return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED; - } - - /* A reader potentially has read enough data now. */ - if (a->format && a->format->has_encrypted_entries) { - return (a->format->has_encrypted_entries)(a); - } - - /* For any other reason we cannot say how many entries are there. */ - return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; -} - -/* - * Returns a bitmask of capabilities that are supported by the archive format reader. - * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. - */ -int -archive_read_format_capabilities(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - if (a && a->format && a->format->format_capabilties) { - return (a->format->format_capabilties)(a); - } - return ARCHIVE_READ_FORMAT_CAPS_NONE; -} - -/* - * Read data from an archive entry, using a read(2)-style interface. - * This is a convenience routine that just calls - * archive_read_data_block and copies the results into the client - * buffer, filling any gaps with zero bytes. Clients using this - * API can be completely ignorant of sparse-file issues; sparse files - * will simply be padded with nulls. - * - * DO NOT intermingle calls to this function and archive_read_data_block - * to read a single entry body. - */ -ssize_t -archive_read_data(struct archive *_a, void *buff, size_t s) -{ - struct archive *a = (struct archive *)_a; - char *dest; - const void *read_buf; - size_t bytes_read; - size_t len; - int r; - - bytes_read = 0; - dest = (char *)buff; - - while (s > 0) { - if (a->read_data_remaining == 0) { - read_buf = a->read_data_block; - a->read_data_is_posix_read = 1; - a->read_data_requested = s; - r = archive_read_data_block(a, &read_buf, - &a->read_data_remaining, &a->read_data_offset); - a->read_data_block = read_buf; - if (r == ARCHIVE_EOF) - return (bytes_read); - /* - * Error codes are all negative, so the status - * return here cannot be confused with a valid - * byte count. (ARCHIVE_OK is zero.) - */ - if (r < ARCHIVE_OK) - return (r); - } - - if (a->read_data_offset < a->read_data_output_offset) { - archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, - "Encountered out-of-order sparse blocks"); - return (ARCHIVE_RETRY); - } - - /* Compute the amount of zero padding needed. */ - if (a->read_data_output_offset + (int64_t)s < - a->read_data_offset) { - len = s; - } else if (a->read_data_output_offset < - a->read_data_offset) { - len = (size_t)(a->read_data_offset - - a->read_data_output_offset); - } else - len = 0; - - /* Add zeroes. */ - memset(dest, 0, len); - s -= len; - a->read_data_output_offset += len; - dest += len; - bytes_read += len; - - /* Copy data if there is any space left. */ - if (s > 0) { - len = a->read_data_remaining; - if (len > s) - len = s; - if (len) - memcpy(dest, a->read_data_block, len); - s -= len; - a->read_data_block += len; - a->read_data_remaining -= len; - a->read_data_output_offset += len; - a->read_data_offset += len; - dest += len; - bytes_read += len; - } - } - a->read_data_is_posix_read = 0; - a->read_data_requested = 0; - return (bytes_read); -} - -/* - * Reset the read_data_* variables, used for starting a new entry. - */ -void __archive_reset_read_data(struct archive * a) -{ - a->read_data_output_offset = 0; - a->read_data_remaining = 0; - a->read_data_is_posix_read = 0; - a->read_data_requested = 0; - - /* extra resets, from rar.c */ - a->read_data_block = NULL; - a->read_data_offset = 0; -} - -/* - * Skip over all remaining data in this entry. - */ -int -archive_read_data_skip(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - int r; - const void *buff; - size_t size; - int64_t offset; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_data_skip"); - - if (a->format->read_data_skip != NULL) - r = (a->format->read_data_skip)(a); - else { - while ((r = archive_read_data_block(&a->archive, - &buff, &size, &offset)) - == ARCHIVE_OK) - ; - } - - if (r == ARCHIVE_EOF) - r = ARCHIVE_OK; - - a->archive.state = ARCHIVE_STATE_HEADER; - return (r); -} - -int64_t -archive_seek_data(struct archive *_a, int64_t offset, int whence) -{ - struct archive_read *a = (struct archive_read *)_a; - 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); - } - - return (a->format->seek_data)(a, offset, whence); -} - -/* - * Read the next block of entry data from the archive. - * This is a zero-copy interface; the client receives a pointer, - * size, and file offset of the next available block of data. - * - * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if - * the end of entry is encountered. - */ -static int -_archive_read_data_block(struct archive *_a, - const void **buff, size_t *size, int64_t *offset) -{ - struct archive_read *a = (struct archive_read *)_a; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_data_block"); - - if (a->format->read_data == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: " - "No format->read_data function registered"); - return (ARCHIVE_FATAL); - } - - return (a->format->read_data)(a, buff, size, offset); -} - -static int -close_filters(struct archive_read *a) -{ - struct archive_read_filter *f = a->filter; - int r = ARCHIVE_OK; - /* Close each filter in the pipeline. */ - while (f != NULL) { - struct archive_read_filter *t = f->upstream; - if (!f->closed && f->close != NULL) { - int r1 = (f->close)(f); - f->closed = 1; - if (r1 < r) - r = r1; - } - free(f->buffer); - f->buffer = NULL; - f = t; - } - return r; -} - -void -__archive_read_free_filters(struct archive_read *a) -{ - /* Make sure filters are closed and their buffers are freed */ - close_filters(a); - - while (a->filter != NULL) { - struct archive_read_filter *t = a->filter->upstream; - free(a->filter); - a->filter = t; - } -} - -/* - * return the count of # of filters in use - */ -static int -_archive_filter_count(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *p = a->filter; - int count = 0; - while(p) { - count++; - p = p->upstream; - } - return count; -} - -/* - * Close the file and all I/O. - */ -static int -_archive_read_close(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - int r = ARCHIVE_OK, r1 = ARCHIVE_OK; - - archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); - if (a->archive.state == ARCHIVE_STATE_CLOSED) - return (ARCHIVE_OK); - archive_clear_error(&a->archive); - a->archive.state = ARCHIVE_STATE_CLOSED; - - /* TODO: Clean up the formatters. */ - - /* Release the filter objects. */ - r1 = close_filters(a); - if (r1 < r) - r = r1; - - return (r); -} - -/* - * Release memory and other resources. - */ -static int -_archive_read_free(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_passphrase *p; - int i, n; - int slots; - int r = ARCHIVE_OK; - - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); - if (a->archive.state != ARCHIVE_STATE_CLOSED - && a->archive.state != ARCHIVE_STATE_FATAL) - r = archive_read_close(&a->archive); - - /* Call cleanup functions registered by optional components. */ - if (a->cleanup_archive_extract != NULL) - r = (a->cleanup_archive_extract)(a); - - /* Cleanup format-specific data. */ - slots = sizeof(a->formats) / sizeof(a->formats[0]); - for (i = 0; i < slots; i++) { - a->format = &(a->formats[i]); - if (a->formats[i].cleanup) - (a->formats[i].cleanup)(a); - } - - /* Free the filters */ - __archive_read_free_filters(a); - - /* Release the bidder objects. */ - n = sizeof(a->bidders)/sizeof(a->bidders[0]); - for (i = 0; i < n; i++) { - if (a->bidders[i].free != NULL) { - int r1 = (a->bidders[i].free)(&a->bidders[i]); - if (r1 < r) - r = r1; - } - } - - /* Release passphrase list. */ - p = a->passphrases.first; - while (p != NULL) { - struct archive_read_passphrase *np = p->next; - - /* A passphrase should be cleaned. */ - memset(p->passphrase, 0, strlen(p->passphrase)); - free(p->passphrase); - free(p); - p = np; - } - - archive_string_free(&a->archive.error_string); - archive_entry_free(a->entry); - a->archive.magic = 0; - __archive_clean(&a->archive); - free(a->client.dataset); - free(a); - return (r); -} - -static struct archive_read_filter * -get_filter(struct archive *_a, int n) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *f = a->filter; - /* We use n == -1 for 'the last filter', which is always the - * client proxy. */ - if (n == -1 && f != NULL) { - struct archive_read_filter *last = f; - f = f->upstream; - while (f != NULL) { - last = f; - f = f->upstream; - } - return (last); - } - if (n < 0) - return NULL; - while (n > 0 && f != NULL) { - f = f->upstream; - --n; - } - return (f); -} - -static int -_archive_filter_code(struct archive *_a, int n) -{ - struct archive_read_filter *f = get_filter(_a, n); - return f == NULL ? -1 : f->code; -} - -static const char * -_archive_filter_name(struct archive *_a, int n) -{ - struct archive_read_filter *f = get_filter(_a, n); - return f != NULL ? f->name : NULL; -} - -static int64_t -_archive_filter_bytes(struct archive *_a, int n) -{ - struct archive_read_filter *f = get_filter(_a, n); - return f == NULL ? -1 : f->position; -} - -/* - * Used internally by read format handlers to register their bid and - * initialization functions. - */ -int -__archive_read_register_format(struct archive_read *a, - void *format_data, - const char *name, - int (*bid)(struct archive_read *, int), - int (*options)(struct archive_read *, const char *, const char *), - int (*read_header)(struct archive_read *, struct archive_entry *), - int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), - int (*read_data_skip)(struct archive_read *), - int64_t (*seek_data)(struct archive_read *, int64_t, int), - int (*cleanup)(struct archive_read *), - int (*format_capabilities)(struct archive_read *), - int (*has_encrypted_entries)(struct archive_read *)) -{ - int i, number_slots; - - archive_check_magic(&a->archive, - ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, - "__archive_read_register_format"); - - number_slots = sizeof(a->formats) / sizeof(a->formats[0]); - - for (i = 0; i < number_slots; i++) { - if (a->formats[i].bid == bid) - return (ARCHIVE_WARN); /* We've already installed */ - if (a->formats[i].bid == NULL) { - a->formats[i].bid = bid; - a->formats[i].options = options; - a->formats[i].read_header = read_header; - a->formats[i].read_data = read_data; - a->formats[i].read_data_skip = read_data_skip; - a->formats[i].seek_data = seek_data; - a->formats[i].cleanup = cleanup; - a->formats[i].data = format_data; - a->formats[i].name = name; - a->formats[i].format_capabilties = format_capabilities; - a->formats[i].has_encrypted_entries = has_encrypted_entries; - return (ARCHIVE_OK); - } - } - - archive_set_error(&a->archive, ENOMEM, - "Not enough slots for format registration"); - return (ARCHIVE_FATAL); -} - -/* - * Used internally by decompression routines to register their bid and - * initialization functions. - */ -int -__archive_read_get_bidder(struct archive_read *a, - struct archive_read_filter_bidder **bidder) -{ - int i, number_slots; - - number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]); - - for (i = 0; i < number_slots; i++) { - if (a->bidders[i].bid == NULL) { - memset(a->bidders + i, 0, sizeof(a->bidders[0])); - *bidder = (a->bidders + i); - return (ARCHIVE_OK); - } - } - - archive_set_error(&a->archive, ENOMEM, - "Not enough slots for filter registration"); - return (ARCHIVE_FATAL); -} - -/* - * The next section implements the peek/consume internal I/O - * system used by archive readers. This system allows simple - * read-ahead for consumers while preserving zero-copy operation - * most of the time. - * - * The two key operations: - * * The read-ahead function returns a pointer to a block of data - * that satisfies a minimum request. - * * The consume function advances the file pointer. - * - * In the ideal case, filters generate blocks of data - * and __archive_read_ahead() just returns pointers directly into - * those blocks. Then __archive_read_consume() just bumps those - * pointers. Only if your request would span blocks does the I/O - * layer use a copy buffer to provide you with a contiguous block of - * data. - * - * A couple of useful idioms: - * * "I just want some data." Ask for 1 byte and pay attention to - * the "number of bytes available" from __archive_read_ahead(). - * Consume whatever you actually use. - * * "I want to output a large block of data." As above, ask for 1 byte, - * emit all that's available (up to whatever limit you have), consume - * it all, then repeat until you're done. This effectively means that - * you're passing along the blocks that came from your provider. - * * "I want to peek ahead by a large amount." Ask for 4k or so, then - * double and repeat until you get an error or have enough. Note - * that the I/O layer will likely end up expanding its copy buffer - * to fit your request, so use this technique cautiously. This - * technique is used, for example, by some of the format tasting - * code that has uncertain look-ahead needs. - */ - -/* - * Looks ahead in the input stream: - * * If 'avail' pointer is provided, that returns number of bytes available - * in the current buffer, which may be much larger than requested. - * * If end-of-file, *avail gets set to zero. - * * If error, *avail gets error code. - * * If request can be met, returns pointer to data. - * * If minimum request cannot be met, returns NULL. - * - * Note: If you just want "some data", ask for 1 byte and pay attention - * to *avail, which will have the actual amount available. If you - * know exactly how many bytes you need, just ask for that and treat - * a NULL return as an error. - * - * Important: This does NOT move the file pointer. See - * __archive_read_consume() below. - */ -const void * -__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) -{ - return (__archive_read_filter_ahead(a->filter, min, avail)); -} - -const void * -__archive_read_filter_ahead(struct archive_read_filter *filter, - size_t min, ssize_t *avail) -{ - ssize_t bytes_read; - size_t tocopy; - - if (filter->fatal) { - if (avail) - *avail = ARCHIVE_FATAL; - return (NULL); - } - - /* - * Keep pulling more data until we can satisfy the request. - */ - for (;;) { - - /* - * If we can satisfy from the copy buffer (and the - * copy buffer isn't empty), we're done. In particular, - * note that min == 0 is a perfectly well-defined - * request. - */ - if (filter->avail >= min && filter->avail > 0) { - if (avail != NULL) - *avail = filter->avail; - return (filter->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) { - /* "Roll back" to client buffer. */ - filter->client_avail += filter->avail; - filter->client_next -= filter->avail; - /* Copy buffer is now empty. */ - filter->avail = 0; - filter->next = filter->buffer; - /* Return data from client buffer. */ - if (avail != NULL) - *avail = filter->client_avail; - return (filter->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 we've used up the client data, get more. */ - if (filter->client_avail <= 0) { - if (filter->end_of_file) { - if (avail != NULL) - *avail = 0; - return (NULL); - } - bytes_read = (filter->read)(filter, - &filter->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; - 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) - == 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; - /* Return whatever we do have. */ - if (avail != NULL) - *avail = filter->avail; - return (NULL); - } - filter->client_total = bytes_read; - filter->client_avail = filter->client_total; - filter->client_next = filter->client_buff; - } else { - /* - * We can't satisfy the request from the copy - * buffer or the existing client data, so we - * need to copy more client data over to the - * copy buffer. - */ - - /* Ensure the buffer is big enough. */ - if (min > filter->buffer_size) { - size_t s, t; - char *p; - - /* Double the buffer; watch for overflow. */ - s = t = filter->buffer_size; - if (s == 0) - s = min; - while (s < min) { - t *= 2; - if (t <= s) { /* Integer overflow! */ - archive_set_error( - &filter->archive->archive, - ENOMEM, - "Unable to allocate copy" - " buffer"); - filter->fatal = 1; - if (avail != NULL) - *avail = ARCHIVE_FATAL; - return (NULL); - } - s = t; - } - /* Now s >= min, so allocate a new buffer. */ - p = (char *)malloc(s); - if (p == NULL) { - archive_set_error( - &filter->archive->archive, - ENOMEM, - "Unable to allocate copy buffer"); - filter->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; - } - - /* 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); - /* Don't waste time buffering more than we need to. */ - if (tocopy + filter->avail > min) - tocopy = min - filter->avail; - /* Don't copy more than is available. */ - if (tocopy > filter->client_avail) - tocopy = filter->client_avail; - - memcpy(filter->next + filter->avail, - filter->client_next, tocopy); - /* Remove this data from client buffer. */ - filter->client_next += tocopy; - filter->client_avail -= tocopy; - /* add it to copy buffer. */ - filter->avail += tocopy; - } - } -} - -/* - * Move the file pointer forward. - */ -int64_t -__archive_read_consume(struct archive_read *a, int64_t request) -{ - return (__archive_read_filter_consume(a->filter, request)); -} - -int64_t -__archive_read_filter_consume(struct archive_read_filter * filter, - int64_t request) -{ - int64_t skipped; - - if (request < 0) - return ARCHIVE_FATAL; - if (request == 0) - return 0; - - skipped = advance_file_pointer(filter, 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_ERRNO_MISC, - "Truncated input file (needed %jd bytes, only %jd available)", - (intmax_t)request, (intmax_t)skipped); - return (ARCHIVE_FATAL); -} - -/* - * Advance the file pointer by the amount requested. - * Returns the amount actually advanced, which may be less than the - * request if EOF is encountered first. - * 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) -{ - int64_t bytes_skipped, total_bytes_skipped = 0; - ssize_t bytes_read; - size_t min; - - if (filter->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; - request -= min; - filter->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; - request -= min; - filter->position += min; - total_bytes_skipped += min; - } - if (request == 0) - return (total_bytes_skipped); - - /* If there's an optimized skip function, use it. */ - if (filter->skip != NULL) { - bytes_skipped = (filter->skip)(filter, request); - if (bytes_skipped < 0) { /* error */ - filter->fatal = 1; - return (bytes_skipped); - } - filter->position += bytes_skipped; - total_bytes_skipped += bytes_skipped; - request -= bytes_skipped; - if (request == 0) - return (total_bytes_skipped); - } - - /* Use ordinary reads as necessary to complete the request. */ - for (;;) { - bytes_read = (filter->read)(filter, &filter->client_buff); - if (bytes_read < 0) { - filter->client_buff = NULL; - filter->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) - == ARCHIVE_OK) - continue; - } - filter->client_buff = NULL; - filter->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; - total_bytes_skipped += request; - filter->position += request; - return (total_bytes_skipped); - } - - filter->position += bytes_read; - total_bytes_skipped += bytes_read; - request -= bytes_read; - } -} - -/** - * Returns ARCHIVE_FAILED if seeking isn't supported. - */ -int64_t -__archive_read_seek(struct archive_read *a, int64_t offset, int whence) -{ - return __archive_read_filter_seek(a->filter, offset, whence); -} - -int64_t -__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, - int whence) -{ - struct archive_read_client *client; - int64_t r; - unsigned int cursor; - - if (filter->closed || filter->fatal) - return (ARCHIVE_FATAL); - if (filter->seek == NULL) - return (ARCHIVE_FAILED); - - client = &(filter->archive->client); - switch (whence) { - case SEEK_CUR: - /* Adjust the offset and use SEEK_SET instead */ - offset += filter->position; - case SEEK_SET: - cursor = 0; - while (1) - { - if (client->dataset[cursor].begin_position < 0 || - client->dataset[cursor].total_size < 0 || - client->dataset[cursor].begin_position + - client->dataset[cursor].total_size - 1 > offset || - cursor + 1 >= client->nodes) - break; - r = client->dataset[cursor].begin_position + - client->dataset[cursor].total_size; - client->dataset[++cursor].begin_position = r; - } - while (1) { - r = client_switch_proxy(filter, cursor); - if (r != ARCHIVE_OK) - return r; - if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) - return r; - client->dataset[cursor].total_size = r; - if (client->dataset[cursor].begin_position + - client->dataset[cursor].total_size - 1 > offset || - cursor + 1 >= client->nodes) - break; - r = client->dataset[cursor].begin_position + - client->dataset[cursor].total_size; - client->dataset[++cursor].begin_position = r; - } - offset -= client->dataset[cursor].begin_position; - if (offset < 0 - || offset > client->dataset[cursor].total_size) - return ARCHIVE_FATAL; - if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0) - return r; - break; - - case SEEK_END: - cursor = 0; - while (1) { - if (client->dataset[cursor].begin_position < 0 || - client->dataset[cursor].total_size < 0 || - cursor + 1 >= client->nodes) - break; - r = client->dataset[cursor].begin_position + - client->dataset[cursor].total_size; - client->dataset[++cursor].begin_position = r; - } - while (1) { - r = client_switch_proxy(filter, cursor); - if (r != ARCHIVE_OK) - return r; - if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) - return r; - client->dataset[cursor].total_size = r; - r = client->dataset[cursor].begin_position + - client->dataset[cursor].total_size; - if (cursor + 1 >= client->nodes) - break; - client->dataset[++cursor].begin_position = r; - } - while (1) { - if (r + offset >= - client->dataset[cursor].begin_position) - break; - offset += client->dataset[cursor].total_size; - if (cursor == 0) - break; - cursor--; - r = client->dataset[cursor].begin_position + - client->dataset[cursor].total_size; - } - offset = (r + offset) - client->dataset[cursor].begin_position; - if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK) - return r; - r = client_seek_proxy(filter, offset, SEEK_SET); - if (r < ARCHIVE_OK) - return r; - break; - - default: - return (ARCHIVE_FATAL); - } - r += client->dataset[cursor].begin_position; - - if (r >= 0) { - /* - * Ouch. Clearing the buffer like this hurts, especially - * at bid time. A lot of our efficiency at bid time comes - * from having bidders reuse the data we've already read. - * - * TODO: If the seek request is in data we already - * have, then don't call the seek callback. - * - * TODO: Zip seeks to end-of-file at bid time. If - * other formats also start doing this, we may need to - * find a way for clients to fudge the seek offset to - * a block boundary. - * - * Hmmm... If whence was SEEK_END, we know the file - * 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; - } - return r; -} diff --git a/3rdparty/libarchive/libarchive/archive_read_append_filter.c b/3rdparty/libarchive/libarchive/archive_read_append_filter.c deleted file mode 100644 index 5e4d1630..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_append_filter.c +++ /dev/null @@ -1,200 +0,0 @@ -/*- - * Copyright (c) 2003-2012 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" - -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; - struct archive_read *a = (struct archive_read *)_a; - - r2 = (ARCHIVE_OK); - switch (code) - { - case ARCHIVE_FILTER_NONE: - /* No filter to add, so do nothing. - * NOTE: An initial "NONE" type filter is always set at the end of the - * filter chain. - */ - r1 = (ARCHIVE_OK); - break; - case ARCHIVE_FILTER_GZIP: - strcpy(str, "gzip"); - r1 = archive_read_support_filter_gzip(_a); - break; - case ARCHIVE_FILTER_BZIP2: - strcpy(str, "bzip2"); - r1 = archive_read_support_filter_bzip2(_a); - break; - case ARCHIVE_FILTER_COMPRESS: - strcpy(str, "compress (.Z)"); - r1 = archive_read_support_filter_compress(_a); - break; - case ARCHIVE_FILTER_PROGRAM: - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Cannot append program filter using archive_read_append_filter"); - return (ARCHIVE_FATAL); - case ARCHIVE_FILTER_LZMA: - strcpy(str, "lzma"); - r1 = archive_read_support_filter_lzma(_a); - break; - case ARCHIVE_FILTER_XZ: - strcpy(str, "xz"); - r1 = archive_read_support_filter_xz(_a); - break; - case ARCHIVE_FILTER_UU: - strcpy(str, "uu"); - r1 = archive_read_support_filter_uu(_a); - break; - case ARCHIVE_FILTER_RPM: - strcpy(str, "rpm"); - r1 = archive_read_support_filter_rpm(_a); - break; - case ARCHIVE_FILTER_LZ4: - strcpy(str, "lz4"); - r1 = archive_read_support_filter_lz4(_a); - break; - case ARCHIVE_FILTER_LZIP: - strcpy(str, "lzip"); - r1 = archive_read_support_filter_lzip(_a); - break; - case ARCHIVE_FILTER_LRZIP: - strcpy(str, "lrzip"); - r1 = archive_read_support_filter_lrzip(_a); - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Invalid filter code specified"); - return (ARCHIVE_FATAL); - } - - if (code != ARCHIVE_FILTER_NONE) - { - number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - - bidder = a->bidders; - for (i = 0; i < number_bidders; i++, bidder++) - { - if (!bidder->name || !strcmp(bidder->name, str)) - break; - } - if (!bidder->name || strcmp(bidder->name, str)) - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: Unable to append filter"); - return (ARCHIVE_FATAL); - } - - filter - = (struct archive_read_filter *)calloc(1, sizeof(*filter)); - if (filter == 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->init)(a->filter); - if (r2 != ARCHIVE_OK) { - __archive_read_free_filters(a); - return (ARCHIVE_FATAL); - } - } - - a->bypass_filter_bidding = 1; - return (r1 < r2) ? r1 : r2; -} - -int -archive_read_append_filter_program(struct archive *_a, const char *cmd) -{ - return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0)); -} - -int -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 *a = (struct archive_read *)_a; - - if (archive_read_support_filter_program_signature(_a, cmd, signature, - signature_len) != (ARCHIVE_OK)) - return (ARCHIVE_FATAL); - - number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - - bidder = a->bidders; - for (i = 0; i < number_bidders; i++, bidder++) - { - /* Program bidder name set to filter name after initialization */ - if (bidder->data && !bidder->name) - break; - } - if (!bidder->data) - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: Unable to append program filter"); - return (ARCHIVE_FATAL); - } - - filter - = (struct archive_read_filter *)calloc(1, sizeof(*filter)); - if (filter == 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->init)(a->filter); - if (r != ARCHIVE_OK) { - __archive_read_free_filters(a); - return (ARCHIVE_FATAL); - } - bidder->name = a->filter->name; - - a->bypass_filter_bidding = 1; - return r; -} diff --git a/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c b/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c deleted file mode 100644 index b4398f1e..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c +++ /dev/null @@ -1,139 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/05/23 05:01:29 cperciva Exp $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" - -/* Maximum amount of data to write at one time. */ -#define MAX_WRITE (1024 * 1024) - -/* - * This implementation minimizes copying of data and is sparse-file aware. - */ -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) -{ - size_t to_write; - ssize_t bytes_written; - - if (can_lseek) { - actual_offset = lseek(fd, - target_offset - actual_offset, SEEK_CUR); - if (actual_offset != target_offset) { - archive_set_error(a, errno, "Seek error"); - return (ARCHIVE_FATAL); - } - return (ARCHIVE_OK); - } - 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); - if (bytes_written < 0) { - archive_set_error(a, errno, "Write error"); - return (ARCHIVE_FATAL); - } - actual_offset += bytes_written; - } - return (ARCHIVE_OK); -} - - -int -archive_read_data_into_fd(struct archive *a, int fd) -{ - struct stat st; - int r, r2; - const void *buff; - size_t size, bytes_to_write; - ssize_t bytes_written; - int64_t target_offset; - int64_t actual_offset = 0; - 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"); - - can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode); - if (!can_lseek) - nulls = calloc(1, nulls_size); - - while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) == - ARCHIVE_OK) { - const char *p = buff; - if (target_offset > actual_offset) { - r = pad_to(a, fd, can_lseek, nulls_size, nulls, - target_offset, actual_offset); - if (r != ARCHIVE_OK) - break; - actual_offset = target_offset; - } - while (size > 0) { - bytes_to_write = size; - if (bytes_to_write > MAX_WRITE) - bytes_to_write = MAX_WRITE; - bytes_written = write(fd, p, bytes_to_write); - if (bytes_written < 0) { - archive_set_error(a, errno, "Write error"); - r = ARCHIVE_FATAL; - goto cleanup; - } - actual_offset += bytes_written; - p += bytes_written; - size -= bytes_written; - } - } - - 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; - } - -cleanup: - free(nulls); - if (r != ARCHIVE_EOF) - return (r); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c b/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c deleted file mode 100644 index 548ba89e..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c +++ /dev/null @@ -1,1041 +0,0 @@ -/*- - * Copyright (c) 2003-2009 Tim Kientzle - * Copyright (c) 2010-2012 Michihiro NAKAJIMA - * Copyright (c) 2016 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD"); - -/* This is the tree-walking code for POSIX systems. */ -#if !defined(_WIN32) || defined(__CYGWIN__) - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_EXTATTR_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#if defined(HAVE_SYS_XATTR_H) -#include -#elif defined(HAVE_ATTR_XATTR_H) -#include -#endif -#ifdef HAVE_SYS_EA_H -#include -#endif -#ifdef HAVE_COPYFILE_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_LINUX_TYPES_H -#include -#endif -#ifdef HAVE_LINUX_FIEMAP_H -#include -#endif -#ifdef HAVE_LINUX_FS_H -#include -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include /* Linux file flags, broken on Cygwin */ -#endif -#ifdef HAVE_PATHS_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_disk_private.h" - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -static int setup_mac_metadata(struct archive_read_disk *, - struct archive_entry *, int *fd); -static int setup_xattrs(struct archive_read_disk *, - struct archive_entry *, int *fd); -static int setup_sparse(struct archive_read_disk *, - struct archive_entry *, int *fd); -#if defined(HAVE_LINUX_FIEMAP_H) -static int setup_sparse_fiemap(struct archive_read_disk *, - struct archive_entry *, int *fd); -#endif - -#if !ARCHIVE_ACL_SUPPORT -int -archive_read_disk_entry_setup_acls(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - (void)fd; /* UNUSED */ - return (ARCHIVE_OK); -} -#endif - -/* - * Enter working directory and return working pathname of archive_entry. - * If a pointer to an integer is provided and its value is below zero - * open a file descriptor on this pahtname. - */ -const char * -archive_read_disk_entry_setup_path(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - const char *path; - - path = archive_entry_sourcepath(entry); - - if (path == NULL || (a->tree != NULL && - a->tree_enter_working_dir(a->tree) != 0)) - path = archive_entry_pathname(entry); - if (path == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Couldn't determine path"); - } else if (fd != NULL && *fd < 0 && a->tree != NULL && - (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) { - *fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK); - } - return (path); -} - -int -archive_read_disk_entry_from_file(struct archive *_a, - struct archive_entry *entry, - int fd, - const struct stat *st) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - const char *path, *name; - struct stat s; - int initial_fd = fd; - int r, r1; - - archive_clear_error(_a); - path = archive_entry_sourcepath(entry); - if (path == NULL) - path = archive_entry_pathname(entry); - - if (a->tree == NULL) { - if (st == NULL) { -#if HAVE_FSTAT - if (fd >= 0) { - if (fstat(fd, &s) != 0) { - archive_set_error(&a->archive, errno, - "Can't fstat"); - return (ARCHIVE_FAILED); - } - } else -#endif -#if HAVE_LSTAT - if (!a->follow_symlinks) { - if (lstat(path, &s) != 0) { - archive_set_error(&a->archive, errno, - "Can't lstat %s", path); - return (ARCHIVE_FAILED); - } - } else -#endif - if (stat(path, &s) != 0) { - archive_set_error(&a->archive, errno, - "Can't stat %s", path); - return (ARCHIVE_FAILED); - } - st = &s; - } - archive_entry_copy_stat(entry, st); - } - - /* Lookup uname/gname */ - name = archive_read_disk_uname(_a, archive_entry_uid(entry)); - if (name != NULL) - archive_entry_copy_uname(entry, name); - name = archive_read_disk_gname(_a, archive_entry_gid(entry)); - if (name != NULL) - archive_entry_copy_gname(entry, name); - -#ifdef HAVE_STRUCT_STAT_ST_FLAGS - /* On FreeBSD, we get flags for free with the stat. */ - /* TODO: Does this belong in copy_stat()? */ - if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0) - archive_entry_set_fflags(entry, st->st_flags, 0); -#endif - -#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ - (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) - /* Linux requires an extra ioctl to pull the flags. Although - * this is an extra step, it has a nice side-effect: We get an - * open file descriptor which we can use in the subsequent lookups. */ - if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && - (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) { - if (fd < 0) { - if (a->tree != NULL) - fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK | O_CLOEXEC); - else - fd = open(path, O_RDONLY | O_NONBLOCK | - O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - } - if (fd >= 0) { - int stflags; - r = ioctl(fd, -#if defined(FS_IOC_GETFLAGS) - FS_IOC_GETFLAGS, -#else - EXT2_IOC_GETFLAGS, -#endif - &stflags); - if (r == 0 && stflags != 0) - archive_entry_set_fflags(entry, stflags, 0); - } - } -#endif - -#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT) - if (S_ISLNK(st->st_mode)) { - size_t linkbuffer_len = st->st_size + 1; - char *linkbuffer; - int lnklen; - - linkbuffer = malloc(linkbuffer_len); - if (linkbuffer == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Couldn't read link data"); - return (ARCHIVE_FAILED); - } - if (a->tree != NULL) { -#ifdef HAVE_READLINKAT - lnklen = readlinkat(a->tree_current_dir_fd(a->tree), - path, linkbuffer, linkbuffer_len); -#else - if (a->tree_enter_working_dir(a->tree) != 0) { - archive_set_error(&a->archive, errno, - "Couldn't read link data"); - free(linkbuffer); - return (ARCHIVE_FAILED); - } - lnklen = readlink(path, linkbuffer, linkbuffer_len); -#endif /* HAVE_READLINKAT */ - } else - lnklen = readlink(path, linkbuffer, linkbuffer_len); - if (lnklen < 0) { - archive_set_error(&a->archive, errno, - "Couldn't read link data"); - free(linkbuffer); - return (ARCHIVE_FAILED); - } - linkbuffer[lnklen] = 0; - archive_entry_set_symlink(entry, linkbuffer); - free(linkbuffer); - } -#endif /* HAVE_READLINK || HAVE_READLINKAT */ - - r = 0; - if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0) - r = archive_read_disk_entry_setup_acls(a, entry, &fd); - if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) { - r1 = setup_xattrs(a, entry, &fd); - if (r1 < r) - r = r1; - } - if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { - r1 = setup_mac_metadata(a, entry, &fd); - if (r1 < r) - r = r1; - } - r1 = setup_sparse(a, entry, &fd); - if (r1 < r) - r = r1; - - /* If we opened the file earlier in this function, close it. */ - if (initial_fd != fd) - close(fd); - return (r); -} - -#if defined(__APPLE__) && defined(HAVE_COPYFILE_H) -/* - * The Mac OS "copyfile()" API copies the extended metadata for a - * file into a separate file in AppleDouble format (see RFC 1740). - * - * Mac OS tar and cpio implementations store this extended - * metadata as a separate entry just before the regular entry - * with a "._" prefix added to the filename. - * - * Note that this is currently done unconditionally; the tar program has - * an option to discard this information before the archive is written. - * - * TODO: If there's a failure, report it and return ARCHIVE_WARN. - */ -static int -setup_mac_metadata(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - int tempfd = -1; - int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR; - struct stat copyfile_stat; - int ret = ARCHIVE_OK; - void *buff = NULL; - int have_attrs; - const char *name, *tempdir; - struct archive_string tempfile; - - (void)fd; /* UNUSED */ - - name = archive_read_disk_entry_setup_path(a, entry, NULL); - if (name == NULL) - return (ARCHIVE_WARN); - - /* Short-circuit if there's nothing to do. */ - have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); - if (have_attrs == -1) { - archive_set_error(&a->archive, errno, - "Could not check extended attributes"); - return (ARCHIVE_WARN); - } - if (have_attrs == 0) - return (ARCHIVE_OK); - - tempdir = NULL; - if (issetugid() == 0) - tempdir = getenv("TMPDIR"); - if (tempdir == NULL) - tempdir = _PATH_TMP; - archive_string_init(&tempfile); - archive_strcpy(&tempfile, tempdir); - archive_strcat(&tempfile, "tar.md.XXXXXX"); - tempfd = mkstemp(tempfile.s); - if (tempfd < 0) { - archive_set_error(&a->archive, errno, - "Could not open extended attribute file"); - ret = ARCHIVE_WARN; - goto cleanup; - } - __archive_ensure_cloexec_flag(tempfd); - - /* XXX I wish copyfile() could pack directly to a memory - * buffer; that would avoid the temp file here. For that - * matter, it would be nice if fcopyfile() actually worked, - * that would reduce the many open/close races here. */ - if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) { - archive_set_error(&a->archive, errno, - "Could not pack extended attributes"); - ret = ARCHIVE_WARN; - goto cleanup; - } - if (fstat(tempfd, ©file_stat)) { - archive_set_error(&a->archive, errno, - "Could not check size of extended attributes"); - ret = ARCHIVE_WARN; - goto cleanup; - } - buff = malloc(copyfile_stat.st_size); - if (buff == NULL) { - archive_set_error(&a->archive, errno, - "Could not allocate memory for extended attributes"); - ret = ARCHIVE_WARN; - goto cleanup; - } - if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) { - archive_set_error(&a->archive, errno, - "Could not read extended attributes into memory"); - ret = ARCHIVE_WARN; - goto cleanup; - } - archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size); - -cleanup: - if (tempfd >= 0) { - close(tempfd); - unlink(tempfile.s); - } - archive_string_free(&tempfile); - free(buff); - return (ret); -} - -#else - -/* - * Stub implementation for non-Mac systems. - */ -static int -setup_mac_metadata(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - (void)fd; /* UNUSED */ - return (ARCHIVE_OK); -} -#endif - -#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX - -/* - * Linux, Darwin and AIX extended attribute support. - * - * TODO: By using a stack-allocated buffer for the first - * call to getxattr(), we might be able to avoid the second - * call entirely. We only need the second call if the - * stack-allocated buffer is too small. But a modest buffer - * of 1024 bytes or so will often be big enough. Same applies - * to listxattr(). - */ - - -static int -setup_xattr(struct archive_read_disk *a, - struct archive_entry *entry, const char *name, int fd, const char *accpath) -{ - ssize_t size; - void *value = NULL; - - - if (fd >= 0) { -#if ARCHIVE_XATTR_LINUX - size = fgetxattr(fd, name, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - size = fgetxattr(fd, name, NULL, 0, 0, 0); -#elif ARCHIVE_XATTR_AIX - size = fgetea(fd, name, NULL, 0); -#endif - } else if (!a->follow_symlinks) { -#if ARCHIVE_XATTR_LINUX - size = lgetxattr(accpath, name, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW); -#elif ARCHIVE_XATTR_AIX - size = lgetea(accpath, name, NULL, 0); -#endif - } else { -#if ARCHIVE_XATTR_LINUX - size = getxattr(accpath, name, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - size = getxattr(accpath, name, NULL, 0, 0, 0); -#elif ARCHIVE_XATTR_AIX - size = getea(accpath, name, NULL, 0); -#endif - } - - if (size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't query extended attribute"); - return (ARCHIVE_WARN); - } - - if (size > 0 && (value = malloc(size)) == NULL) { - archive_set_error(&a->archive, errno, "Out of memory"); - return (ARCHIVE_FATAL); - } - - - if (fd >= 0) { -#if ARCHIVE_XATTR_LINUX - size = fgetxattr(fd, name, value, size); -#elif ARCHIVE_XATTR_DARWIN - size = fgetxattr(fd, name, value, size, 0, 0); -#elif ARCHIVE_XATTR_AIX - size = fgetea(fd, name, value, size); -#endif - } else if (!a->follow_symlinks) { -#if ARCHIVE_XATTR_LINUX - size = lgetxattr(accpath, name, value, size); -#elif ARCHIVE_XATTR_DARWIN - size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW); -#elif ARCHIVE_XATTR_AIX - size = lgetea(accpath, name, value, size); -#endif - } else { -#if ARCHIVE_XATTR_LINUX - size = getxattr(accpath, name, value, size); -#elif ARCHIVE_XATTR_DARWIN - size = getxattr(accpath, name, value, size, 0, 0); -#elif ARCHIVE_XATTR_AIX - size = getea(accpath, name, value, size); -#endif - } - - if (size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't read extended attribute"); - return (ARCHIVE_WARN); - } - - archive_entry_xattr_add_entry(entry, name, value, size); - - free(value); - return (ARCHIVE_OK); -} - -static int -setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - char *list, *p; - const char *path; - ssize_t list_size; - - path = NULL; - - if (*fd < 0) { - path = archive_read_disk_entry_setup_path(a, entry, fd); - if (path == NULL) - return (ARCHIVE_WARN); - } - - if (*fd >= 0) { -#if ARCHIVE_XATTR_LINUX - list_size = flistxattr(*fd, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - list_size = flistxattr(*fd, NULL, 0, 0); -#elif ARCHIVE_XATTR_AIX - list_size = flistea(*fd, NULL, 0); -#endif - } else if (!a->follow_symlinks) { -#if ARCHIVE_XATTR_LINUX - list_size = llistxattr(path, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW); -#elif ARCHIVE_XATTR_AIX - list_size = llistea(path, NULL, 0); -#endif - } else { -#if ARCHIVE_XATTR_LINUX - list_size = listxattr(path, NULL, 0); -#elif ARCHIVE_XATTR_DARWIN - list_size = listxattr(path, NULL, 0, 0); -#elif ARCHIVE_XATTR_AIX - list_size = listea(path, NULL, 0); -#endif - } - - if (list_size == -1) { - if (errno == ENOTSUP || errno == ENOSYS) - return (ARCHIVE_OK); - archive_set_error(&a->archive, errno, - "Couldn't list extended attributes"); - return (ARCHIVE_WARN); - } - - if (list_size == 0) - return (ARCHIVE_OK); - - if ((list = malloc(list_size)) == NULL) { - archive_set_error(&a->archive, errno, "Out of memory"); - return (ARCHIVE_FATAL); - } - - if (*fd >= 0) { -#if ARCHIVE_XATTR_LINUX - list_size = flistxattr(*fd, list, list_size); -#elif ARCHIVE_XATTR_DARWIN - list_size = flistxattr(*fd, list, list_size, 0); -#elif ARCHIVE_XATTR_AIX - list_size = flistea(*fd, list, list_size); -#endif - } else if (!a->follow_symlinks) { -#if ARCHIVE_XATTR_LINUX - list_size = llistxattr(path, list, list_size); -#elif ARCHIVE_XATTR_DARWIN - list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW); -#elif ARCHIVE_XATTR_AIX - list_size = llistea(path, list, list_size); -#endif - } else { -#if ARCHIVE_XATTR_LINUX - list_size = listxattr(path, list, list_size); -#elif ARCHIVE_XATTR_DARWIN - list_size = listxattr(path, list, list_size, 0); -#elif ARCHIVE_XATTR_AIX - list_size = listea(path, list, list_size); -#endif - } - - if (list_size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't retrieve extended attributes"); - free(list); - return (ARCHIVE_WARN); - } - - for (p = list; (p - list) < list_size; p += strlen(p) + 1) { -#if ARCHIVE_XATTR_LINUX - /* Linux: skip POSIX.1e ACL extended attributes */ - if (strncmp(p, "system.", 7) == 0 && - (strcmp(p + 7, "posix_acl_access") == 0 || - strcmp(p + 7, "posix_acl_default") == 0)) - continue; - if (strncmp(p, "trusted.SGI_", 12) == 0 && - (strcmp(p + 12, "ACL_DEFAULT") == 0 || - strcmp(p + 12, "ACL_FILE") == 0)) - continue; - - /* Linux: xfsroot namespace is obsolete and unsupported */ - if (strncmp(p, "xfsroot.", 8) == 0) - continue; -#endif - setup_xattr(a, entry, p, *fd, path); - } - - free(list); - return (ARCHIVE_OK); -} - -#elif ARCHIVE_XATTR_FREEBSD - -/* - * FreeBSD extattr interface. - */ - -/* TODO: Implement this. Follow the Linux model above, but - * with FreeBSD-specific system calls, of course. Be careful - * to not include the system extattrs that hold ACLs; we handle - * those separately. - */ -static int -setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, - int namespace, const char *name, const char *fullname, int fd, - const char *path); - -static int -setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, - int namespace, const char *name, const char *fullname, int fd, - const char *accpath) -{ - ssize_t size; - void *value = NULL; - - if (fd >= 0) - size = extattr_get_fd(fd, namespace, name, NULL, 0); - else if (!a->follow_symlinks) - size = extattr_get_link(accpath, namespace, name, NULL, 0); - else - size = extattr_get_file(accpath, namespace, name, NULL, 0); - - if (size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't query extended attribute"); - return (ARCHIVE_WARN); - } - - if (size > 0 && (value = malloc(size)) == NULL) { - archive_set_error(&a->archive, errno, "Out of memory"); - return (ARCHIVE_FATAL); - } - - if (fd >= 0) - size = extattr_get_fd(fd, namespace, name, value, size); - else if (!a->follow_symlinks) - size = extattr_get_link(accpath, namespace, name, value, size); - else - size = extattr_get_file(accpath, namespace, name, value, size); - - if (size == -1) { - free(value); - archive_set_error(&a->archive, errno, - "Couldn't read extended attribute"); - return (ARCHIVE_WARN); - } - - archive_entry_xattr_add_entry(entry, fullname, value, size); - - free(value); - return (ARCHIVE_OK); -} - -static int -setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - char buff[512]; - char *list, *p; - ssize_t list_size; - const char *path; - int namespace = EXTATTR_NAMESPACE_USER; - - path = NULL; - - if (*fd < 0) { - path = archive_read_disk_entry_setup_path(a, entry, fd); - if (path == NULL) - return (ARCHIVE_WARN); - } - - if (*fd >= 0) - list_size = extattr_list_fd(*fd, namespace, NULL, 0); - else if (!a->follow_symlinks) - list_size = extattr_list_link(path, namespace, NULL, 0); - else - list_size = extattr_list_file(path, namespace, NULL, 0); - - if (list_size == -1 && errno == EOPNOTSUPP) - return (ARCHIVE_OK); - if (list_size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't list extended attributes"); - return (ARCHIVE_WARN); - } - - if (list_size == 0) - return (ARCHIVE_OK); - - if ((list = malloc(list_size)) == NULL) { - archive_set_error(&a->archive, errno, "Out of memory"); - return (ARCHIVE_FATAL); - } - - if (*fd >= 0) - list_size = extattr_list_fd(*fd, namespace, list, list_size); - else if (!a->follow_symlinks) - list_size = extattr_list_link(path, namespace, list, list_size); - else - list_size = extattr_list_file(path, namespace, list, list_size); - - if (list_size == -1) { - archive_set_error(&a->archive, errno, - "Couldn't retrieve extended attributes"); - free(list); - return (ARCHIVE_WARN); - } - - p = list; - while ((p - list) < list_size) { - size_t len = 255 & (int)*p; - char *name; - - strcpy(buff, "user."); - name = buff + strlen(buff); - memcpy(name, p + 1, len); - name[len] = '\0'; - setup_xattr(a, entry, namespace, name, buff, *fd, path); - p += 1 + len; - } - - free(list); - return (ARCHIVE_OK); -} - -#else - -/* - * Generic (stub) extended attribute support. - */ -static int -setup_xattrs(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - (void)fd; /* UNUSED */ - return (ARCHIVE_OK); -} - -#endif - -#if defined(HAVE_LINUX_FIEMAP_H) - -/* - * Linux FIEMAP sparse interface. - * - * The FIEMAP ioctl returns an "extent" for each physical allocation - * on disk. We need to process those to generate a more compact list - * of logical file blocks. We also need to be very careful to use - * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes - * does not report allocations for newly-written data that hasn't - * been synced to disk. - * - * It's important to return a minimal sparse file list because we want - * to not trigger sparse file extensions if we don't have to, since - * not all readers support them. - */ - -static int -setup_sparse_fiemap(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - char buff[4096]; - struct fiemap *fm; - struct fiemap_extent *fe; - int64_t size; - int count, do_fiemap, iters; - int exit_sts = ARCHIVE_OK; - const char *path; - - if (archive_entry_filetype(entry) != AE_IFREG - || archive_entry_size(entry) <= 0 - || archive_entry_hardlink(entry) != NULL) - return (ARCHIVE_OK); - - if (*fd < 0) { - path = archive_read_disk_entry_setup_path(a, entry, NULL); - if (path == NULL) - return (ARCHIVE_FAILED); - - if (a->tree != NULL) - *fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK | O_CLOEXEC); - else - *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (*fd < 0) { - archive_set_error(&a->archive, errno, - "Can't open `%s'", path); - return (ARCHIVE_FAILED); - } - __archive_ensure_cloexec_flag(*fd); - } - - /* Initialize buffer to avoid the error valgrind complains about. */ - memset(buff, 0, sizeof(buff)); - count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe); - fm = (struct fiemap *)buff; - fm->fm_start = 0; - fm->fm_length = ~0ULL;; - fm->fm_flags = FIEMAP_FLAG_SYNC; - fm->fm_extent_count = count; - do_fiemap = 1; - size = archive_entry_size(entry); - for (iters = 0; ; ++iters) { - int i, r; - - r = ioctl(*fd, FS_IOC_FIEMAP, fm); - if (r < 0) { - /* When something error happens, it is better we - * should return ARCHIVE_OK because an earlier - * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */ - goto exit_setup_sparse_fiemap; - } - if (fm->fm_mapped_extents == 0) { - if (iters == 0) { - /* Fully sparse file; insert a zero-length "data" entry */ - archive_entry_sparse_add_entry(entry, 0, 0); - } - break; - } - fe = fm->fm_extents; - for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) { - if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) { - /* The fe_length of the last block does not - * adjust itself to its size files. */ - int64_t length = fe->fe_length; - if (fe->fe_logical + length > (uint64_t)size) - length -= fe->fe_logical + length - size; - if (fe->fe_logical == 0 && length == size) { - /* This is not sparse. */ - do_fiemap = 0; - break; - } - if (length > 0) - archive_entry_sparse_add_entry(entry, - fe->fe_logical, length); - } - if (fe->fe_flags & FIEMAP_EXTENT_LAST) - do_fiemap = 0; - } - if (do_fiemap) { - fe = fm->fm_extents + fm->fm_mapped_extents -1; - fm->fm_start = fe->fe_logical + fe->fe_length; - } else - break; - } -exit_setup_sparse_fiemap: - return (exit_sts); -} - -#if !defined(SEEK_HOLE) || !defined(SEEK_DATA) -static int -setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - return setup_sparse_fiemap(a, entry, fd); -} -#endif -#endif /* defined(HAVE_LINUX_FIEMAP_H) */ - -#if defined(SEEK_HOLE) && defined(SEEK_DATA) - -/* - * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris) - */ - -static int -setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - int64_t size; - off_t initial_off; - off_t off_s, off_e; - int exit_sts = ARCHIVE_OK; - int check_fully_sparse = 0; - const char *path; - - if (archive_entry_filetype(entry) != AE_IFREG - || archive_entry_size(entry) <= 0 - || archive_entry_hardlink(entry) != NULL) - return (ARCHIVE_OK); - - /* Does filesystem support the reporting of hole ? */ - if (*fd < 0) - path = archive_read_disk_entry_setup_path(a, entry, fd); - else - path = NULL; - - if (*fd >= 0) { -#ifdef _PC_MIN_HOLE_SIZE - if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0) - return (ARCHIVE_OK); -#endif - initial_off = lseek(*fd, 0, SEEK_CUR); - if (initial_off != 0) - lseek(*fd, 0, SEEK_SET); - } else { - if (path == NULL) - return (ARCHIVE_FAILED); -#ifdef _PC_MIN_HOLE_SIZE - if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) - return (ARCHIVE_OK); -#endif - *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (*fd < 0) { - archive_set_error(&a->archive, errno, - "Can't open `%s'", path); - return (ARCHIVE_FAILED); - } - __archive_ensure_cloexec_flag(*fd); - initial_off = 0; - } - -#ifndef _PC_MIN_HOLE_SIZE - /* Check if the underlying filesystem supports seek hole */ - off_s = lseek(*fd, 0, SEEK_HOLE); - if (off_s < 0) -#if defined(HAVE_LINUX_FIEMAP_H) - return setup_sparse_fiemap(a, entry, fd); -#else - goto exit_setup_sparse; -#endif - else if (off_s > 0) - lseek(*fd, 0, SEEK_SET); -#endif - - off_s = 0; - size = archive_entry_size(entry); - while (off_s < size) { - off_s = lseek(*fd, off_s, SEEK_DATA); - if (off_s == (off_t)-1) { - if (errno == ENXIO) { - /* no more hole */ - if (archive_entry_sparse_count(entry) == 0) { - /* Potentially a fully-sparse file. */ - check_fully_sparse = 1; - } - break; - } - archive_set_error(&a->archive, errno, - "lseek(SEEK_HOLE) failed"); - exit_sts = ARCHIVE_FAILED; - goto exit_setup_sparse; - } - off_e = lseek(*fd, off_s, SEEK_HOLE); - if (off_e == (off_t)-1) { - if (errno == ENXIO) { - off_e = lseek(*fd, 0, SEEK_END); - if (off_e != (off_t)-1) - break;/* no more data */ - } - archive_set_error(&a->archive, errno, - "lseek(SEEK_DATA) failed"); - exit_sts = ARCHIVE_FAILED; - goto exit_setup_sparse; - } - if (off_s == 0 && off_e == size) - break;/* This is not sparse. */ - archive_entry_sparse_add_entry(entry, off_s, - off_e - off_s); - off_s = off_e; - } - - if (check_fully_sparse) { - if (lseek(*fd, 0, SEEK_HOLE) == 0 && - lseek(*fd, 0, SEEK_END) == size) { - /* Fully sparse file; insert a zero-length "data" entry */ - archive_entry_sparse_add_entry(entry, 0, 0); - } - } -exit_setup_sparse: - lseek(*fd, initial_off, SEEK_SET); - return (exit_sts); -} - -#elif !defined(HAVE_LINUX_FIEMAP_H) - -/* - * Generic (stub) sparse support. - */ -static int -setup_sparse(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - (void)fd; /* UNUSED */ - return (ARCHIVE_OK); -} - -#endif - -#endif /* !defined(_WIN32) || defined(__CYGWIN__) */ - diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_posix.c b/3rdparty/libarchive/libarchive/archive_read_disk_posix.c deleted file mode 100644 index 6961ae6a..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_disk_posix.c +++ /dev/null @@ -1,2661 +0,0 @@ -/*- - * Copyright (c) 2003-2009 Tim Kientzle - * Copyright (c) 2010-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This is the tree-walking code for POSIX systems. */ -#if !defined(_WIN32) || defined(__CYGWIN__) - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_MOUNT_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_STATFS_H -#include -#endif -#ifdef HAVE_SYS_STATVFS_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_LINUX_MAGIC_H -#include -#endif -#ifdef HAVE_LINUX_FS_H -#include -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include /* Linux file flags, broken on Cygwin */ -#endif -#ifdef HAVE_DIRECT_H -#include -#endif -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#include "archive.h" -#include "archive_string.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_disk_private.h" - -#ifndef HAVE_FCHDIR -#error fchdir function required. -#endif -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -/*- - * This is a new directory-walking system that addresses a number - * of problems I've had with fts(3). In particular, it has no - * pathname-length limits (other than the size of 'int'), handles - * deep logical traversals, uses considerably less memory, and has - * an opaque interface (easier to modify in the future). - * - * Internally, it keeps a single list of "tree_entry" items that - * represent filesystem objects that require further attention. - * Non-directories are not kept in memory: they are pulled from - * readdir(), returned to the client, then freed as soon as possible. - * Any directory entry to be traversed gets pushed onto the stack. - * - * There is surprisingly little information that needs to be kept for - * each item on the stack. Just the name, depth (represented here as the - * string length of the parent directory's pathname), and some markers - * indicating how to get back to the parent (via chdir("..") for a - * regular dir or via fchdir(2) for a symlink). - */ -/* - * TODO: - * 1) Loop checking. - * 3) Arbitrary logical traversals by closing/reopening intermediate fds. - */ - -struct restore_time { - const char *name; - time_t mtime; - long mtime_nsec; - time_t atime; - long atime_nsec; - mode_t filetype; - int noatime; -}; - -struct tree_entry { - int depth; - struct tree_entry *next; - struct tree_entry *parent; - struct archive_string name; - size_t dirname_length; - int64_t dev; - int64_t ino; - int flags; - int filesystem_id; - /* How to return back to the parent of a symlink. */ - int symlink_parent_fd; - /* How to restore time of a directory. */ - struct restore_time restore_time; -}; - -struct filesystem { - int64_t dev; - int synthetic; - int remote; - int noatime; -#if defined(USE_READDIR_R) - size_t name_max; -#endif - long incr_xfer_size; - long max_xfer_size; - long min_xfer_size; - long xfer_align; - - /* - * Buffer used for reading file contents. - */ - /* Exactly allocated memory pointer. */ - unsigned char *allocation_ptr; - /* Pointer adjusted to the filesystem alignment . */ - unsigned char *buff; - size_t buff_size; -}; - -/* Definitions for tree_entry.flags bitmap. */ -#define isDir 1 /* This entry is a regular directory. */ -#define isDirLink 2 /* This entry is a symbolic link to a directory. */ -#define needsFirstVisit 4 /* This is an initial entry. */ -#define needsDescent 8 /* This entry needs to be previsited. */ -#define needsOpen 16 /* This is a directory that needs to be opened. */ -#define needsAscent 32 /* This entry needs to be postvisited. */ - -/* - * Local data for this package. - */ -struct tree { - struct tree_entry *stack; - struct tree_entry *current; - DIR *d; -#define INVALID_DIR_HANDLE NULL - struct dirent *de; -#if defined(USE_READDIR_R) - struct dirent *dirent; - size_t dirent_allocated; -#endif - int flags; - int visit_type; - /* Error code from last failed operation. */ - int tree_errno; - - /* Dynamically-sized buffer for holding path */ - struct archive_string path; - - /* Last path element */ - const char *basename; - /* Leading dir length */ - size_t dirname_length; - - int depth; - int openCount; - int maxOpenCount; - int initial_dir_fd; - int working_dir_fd; - - struct stat lst; - struct stat st; - int descend; - int nlink; - /* How to restore time of a file. */ - struct restore_time restore_time; - - struct entry_sparse { - int64_t length; - int64_t offset; - } *sparse_list, *current_sparse; - int sparse_count; - int sparse_list_size; - - char initial_symlink_mode; - char symlink_mode; - struct filesystem *current_filesystem; - struct filesystem *filesystem_table; - int initial_filesystem_id; - int current_filesystem_id; - int max_filesystem_id; - int allocated_filesystem; - - int entry_fd; - int entry_eof; - int64_t entry_remaining_bytes; - int64_t entry_total; - unsigned char *entry_buff; - size_t entry_buff_size; -}; - -/* Definitions for tree.flags bitmap. */ -#define hasStat 16 /* The st entry is valid. */ -#define hasLstat 32 /* The lst entry is valid. */ -#define onWorkingDir 64 /* We are on the working dir where we are - * reading directory entry at this time. */ -#define needsRestoreTimes 128 -#define onInitialDir 256 /* We are on the initial dir. */ - -static int -tree_dir_next_posix(struct tree *t); - -#ifdef HAVE_DIRENT_D_NAMLEN -/* BSD extension; avoids need for a strlen() call. */ -#define D_NAMELEN(dp) (dp)->d_namlen -#else -#define D_NAMELEN(dp) (strlen((dp)->d_name)) -#endif - -/* Initiate/terminate a tree traversal. */ -static struct tree *tree_open(const char *, int, int); -static struct tree *tree_reopen(struct tree *, const char *, int); -static void tree_close(struct tree *); -static void tree_free(struct tree *); -static void tree_push(struct tree *, const char *, int, int64_t, int64_t, - struct restore_time *); -static int tree_enter_initial_dir(struct tree *); -static int tree_enter_working_dir(struct tree *); -static int tree_current_dir_fd(struct tree *); - -/* - * tree_next() returns Zero if there is no next entry, non-zero if - * there is. Note that directories are visited three times. - * Directories are always visited first as part of enumerating their - * parent; that is a "regular" visit. If tree_descend() is invoked at - * that time, the directory is added to a work list and will - * subsequently be visited two more times: once just after descending - * into the directory ("postdescent") and again just after ascending - * back to the parent ("postascent"). - * - * TREE_ERROR_DIR is returned if the descent failed (because the - * directory couldn't be opened, for instance). This is returned - * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a - * fatal error, but it does imply that the relevant subtree won't be - * visited. TREE_ERROR_FATAL is returned for an error that left the - * traversal completely hosed. Right now, this is only returned for - * chdir() failures during ascent. - */ -#define TREE_REGULAR 1 -#define TREE_POSTDESCENT 2 -#define TREE_POSTASCENT 3 -#define TREE_ERROR_DIR -1 -#define TREE_ERROR_FATAL -2 - -static int tree_next(struct tree *); - -/* - * Return information about the current entry. - */ - -/* - * The current full pathname, length of the full pathname, and a name - * that can be used to access the file. Because tree does use chdir - * extensively, the access path is almost never the same as the full - * current path. - * - * TODO: On platforms that support it, use openat()-style operations - * to eliminate the chdir() operations entirely while still supporting - * arbitrarily deep traversals. This makes access_path troublesome to - * support, of course, which means we'll need a rich enough interface - * that clients can function without it. (In particular, we'll need - * tree_current_open() that returns an open file descriptor.) - * - */ -static const char *tree_current_path(struct tree *); -static const char *tree_current_access_path(struct tree *); - -/* - * Request the lstat() or stat() data for the current path. Since the - * tree package needs to do some of this anyway, and caches the - * results, you should take advantage of it here if you need it rather - * than make a redundant stat() or lstat() call of your own. - */ -static const struct stat *tree_current_stat(struct tree *); -static const struct stat *tree_current_lstat(struct tree *); -static int tree_current_is_symblic_link_target(struct tree *); - -/* The following functions use tricks to avoid a certain number of - * stat()/lstat() calls. */ -/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ -static int tree_current_is_physical_dir(struct tree *); -/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ -static int tree_current_is_dir(struct tree *); -static int update_current_filesystem(struct archive_read_disk *a, - int64_t dev); -static int setup_current_filesystem(struct archive_read_disk *); -static int tree_target_is_same_as_parent(struct tree *, const struct stat *); - -static int _archive_read_disk_open(struct archive *, const char *); -static int _archive_read_free(struct archive *); -static int _archive_read_close(struct archive *); -static int _archive_read_data_block(struct archive *, - const void **, size_t *, int64_t *); -static int _archive_read_next_header(struct archive *, - struct archive_entry **); -static int _archive_read_next_header2(struct archive *, - struct archive_entry *); -static const char *trivial_lookup_gname(void *, int64_t gid); -static const char *trivial_lookup_uname(void *, int64_t uid); -static int setup_sparse(struct archive_read_disk *, struct archive_entry *); -static int close_and_restore_time(int fd, struct tree *, - struct restore_time *); -static int open_on_current_dir(struct tree *, const char *, int); -static int tree_dup(int); - - -static struct archive_vtable * -archive_read_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - inited = 1; - } - return (&av); -} - -const char * -archive_read_disk_gname(struct archive *_a, int64_t gid) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_gname")) - return (NULL); - if (a->lookup_gname == NULL) - return (NULL); - return ((*a->lookup_gname)(a->lookup_gname_data, gid)); -} - -const char * -archive_read_disk_uname(struct archive *_a, int64_t uid) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_uname")) - return (NULL); - if (a->lookup_uname == NULL) - return (NULL); - return ((*a->lookup_uname)(a->lookup_uname_data, uid)); -} - -int -archive_read_disk_set_gname_lookup(struct archive *_a, - void *private_data, - const char * (*lookup_gname)(void *private, int64_t gid), - void (*cleanup_gname)(void *private)) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); - - if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) - (a->cleanup_gname)(a->lookup_gname_data); - - a->lookup_gname = lookup_gname; - a->cleanup_gname = cleanup_gname; - a->lookup_gname_data = private_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_uname_lookup(struct archive *_a, - void *private_data, - const char * (*lookup_uname)(void *private, int64_t uid), - void (*cleanup_uname)(void *private)) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); - - if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) - (a->cleanup_uname)(a->lookup_uname_data); - - a->lookup_uname = lookup_uname; - a->cleanup_uname = cleanup_uname; - a->lookup_uname_data = private_data; - return (ARCHIVE_OK); -} - -/* - * Create a new archive_read_disk object and initialize it with global state. - */ -struct archive * -archive_read_disk_new(void) -{ - struct archive_read_disk *a; - - a = (struct archive_read_disk *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_READ_DISK_MAGIC; - a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_read_disk_vtable(); - a->entry = archive_entry_new2(&a->archive); - a->lookup_uname = trivial_lookup_uname; - a->lookup_gname = trivial_lookup_gname; - a->flags = ARCHIVE_READDISK_MAC_COPYFILE; - a->open_on_current_dir = open_on_current_dir; - a->tree_current_dir_fd = tree_current_dir_fd; - a->tree_enter_working_dir = tree_enter_working_dir; - return (&a->archive); -} - -static int -_archive_read_free(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - int r; - - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); - - if (a->archive.state != ARCHIVE_STATE_CLOSED) - r = _archive_read_close(&a->archive); - else - r = ARCHIVE_OK; - - tree_free(a->tree); - if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) - (a->cleanup_gname)(a->lookup_gname_data); - if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) - (a->cleanup_uname)(a->lookup_uname_data); - archive_string_free(&a->archive.error_string); - archive_entry_free(a->entry); - a->archive.magic = 0; - __archive_clean(&a->archive); - free(a); - return (r); -} - -static int -_archive_read_close(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); - - if (a->archive.state != ARCHIVE_STATE_FATAL) - a->archive.state = ARCHIVE_STATE_CLOSED; - - tree_close(a->tree); - - return (ARCHIVE_OK); -} - -static void -setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, - int follow_symlinks) -{ - a->symlink_mode = symlink_mode; - a->follow_symlinks = follow_symlinks; - if (a->tree != NULL) { - a->tree->initial_symlink_mode = a->symlink_mode; - a->tree->symlink_mode = a->symlink_mode; - } -} - -int -archive_read_disk_set_symlink_logical(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); - setup_symlink_mode(a, 'L', 1); - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_symlink_physical(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); - setup_symlink_mode(a, 'P', 0); - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_symlink_hybrid(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); - setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_atime_restored(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); -#ifdef HAVE_UTIMES - a->flags |= ARCHIVE_READDISK_RESTORE_ATIME; - if (a->tree != NULL) - a->tree->flags |= needsRestoreTimes; - return (ARCHIVE_OK); -#else - /* Display warning and unset flag */ - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Cannot restore access time on this system"); - a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME; - return (ARCHIVE_WARN); -#endif -} - -int -archive_read_disk_set_behavior(struct archive *_a, int flags) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - int r = ARCHIVE_OK; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); - - a->flags = flags; - - if (flags & ARCHIVE_READDISK_RESTORE_ATIME) - r = archive_read_disk_set_atime_restored(_a); - else { - if (a->tree != NULL) - a->tree->flags &= ~needsRestoreTimes; - } - return (r); -} - -/* - * Trivial implementations of gname/uname lookup functions. - * These are normally overridden by the client, but these stub - * versions ensure that we always have something that works. - */ -static const char * -trivial_lookup_gname(void *private_data, int64_t gid) -{ - (void)private_data; /* UNUSED */ - (void)gid; /* UNUSED */ - return (NULL); -} - -static const char * -trivial_lookup_uname(void *private_data, int64_t uid) -{ - (void)private_data; /* UNUSED */ - (void)uid; /* UNUSED */ - return (NULL); -} - -/* - * Allocate memory for the reading buffer adjusted to the filesystem - * alignment. - */ -static int -setup_suitable_read_buffer(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - struct filesystem *cf = t->current_filesystem; - size_t asize; - size_t s; - - if (cf->allocation_ptr == NULL) { - /* If we couldn't get a filesystem alignment, - * we use 4096 as default value but we won't use - * O_DIRECT to open() and openat() operations. */ - long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align; - - if (cf->max_xfer_size != -1) - asize = cf->max_xfer_size + xfer_align; - else { - long incr = cf->incr_xfer_size; - /* Some platform does not set a proper value to - * incr_xfer_size.*/ - if (incr < 0) - incr = cf->min_xfer_size; - if (cf->min_xfer_size < 0) { - incr = xfer_align; - asize = xfer_align; - } else - asize = cf->min_xfer_size; - - /* Increase a buffer size up to 64K bytes in - * a proper increment size. */ - while (asize < 1024*64) - asize += incr; - /* Take a margin to adjust to the filesystem - * alignment. */ - asize += xfer_align; - } - cf->allocation_ptr = malloc(asize); - if (cf->allocation_ptr == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Couldn't allocate memory"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - - /* - * Calculate proper address for the filesystem. - */ - s = (uintptr_t)cf->allocation_ptr; - s %= xfer_align; - if (s > 0) - s = xfer_align - s; - - /* - * Set a read buffer pointer in the proper alignment of - * the current filesystem. - */ - cf->buff = cf->allocation_ptr + s; - cf->buff_size = asize - xfer_align; - } - return (ARCHIVE_OK); -} - -static int -_archive_read_data_block(struct archive *_a, const void **buff, - size_t *size, int64_t *offset) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - int r; - ssize_t bytes; - size_t buffbytes; - int empty_sparse_region = 0; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_data_block"); - - if (t->entry_eof || t->entry_remaining_bytes <= 0) { - r = ARCHIVE_EOF; - goto abort_read_data; - } - - /* - * Open the current file. - */ - if (t->entry_fd < 0) { - int flags = O_RDONLY | O_BINARY | O_CLOEXEC; - - /* - * Eliminate or reduce cache effects if we can. - * - * Carefully consider this to be enabled. - */ -#if defined(O_DIRECT) && 0/* Disabled for now */ - if (t->current_filesystem->xfer_align != -1 && - t->nlink == 1) - flags |= O_DIRECT; -#endif -#if defined(O_NOATIME) - /* - * Linux has O_NOATIME flag; use it if we need. - */ - if ((t->flags & needsRestoreTimes) != 0 && - t->restore_time.noatime == 0) - flags |= O_NOATIME; - do { -#endif - t->entry_fd = open_on_current_dir(t, - tree_current_access_path(t), flags); - __archive_ensure_cloexec_flag(t->entry_fd); -#if defined(O_NOATIME) - /* - * When we did open the file with O_NOATIME flag, - * if successful, set 1 to t->restore_time.noatime - * not to restore an atime of the file later. - * if failed by EPERM, retry it without O_NOATIME flag. - */ - if (flags & O_NOATIME) { - if (t->entry_fd >= 0) - t->restore_time.noatime = 1; - else if (errno == EPERM) { - flags &= ~O_NOATIME; - continue; - } - } - } while (0); -#endif - if (t->entry_fd < 0) { - archive_set_error(&a->archive, errno, - "Couldn't open %s", tree_current_path(t)); - r = ARCHIVE_FAILED; - tree_enter_initial_dir(t); - goto abort_read_data; - } - tree_enter_initial_dir(t); - } - - /* - * Allocate read buffer if not allocated. - */ - if (t->current_filesystem->allocation_ptr == NULL) { - r = setup_suitable_read_buffer(a); - if (r != ARCHIVE_OK) { - a->archive.state = ARCHIVE_STATE_FATAL; - goto abort_read_data; - } - } - t->entry_buff = t->current_filesystem->buff; - t->entry_buff_size = t->current_filesystem->buff_size; - - buffbytes = t->entry_buff_size; - if ((int64_t)buffbytes > t->current_sparse->length) - buffbytes = t->current_sparse->length; - - if (t->current_sparse->length == 0) - empty_sparse_region = 1; - - /* - * Skip hole. - * TODO: Should we consider t->current_filesystem->xfer_align? - */ - if (t->current_sparse->offset > t->entry_total) { - if (lseek(t->entry_fd, - (off_t)t->current_sparse->offset, SEEK_SET) < 0) { - archive_set_error(&a->archive, errno, "Seek error"); - r = ARCHIVE_FATAL; - a->archive.state = ARCHIVE_STATE_FATAL; - goto abort_read_data; - } - bytes = t->current_sparse->offset - t->entry_total; - t->entry_remaining_bytes -= bytes; - t->entry_total += bytes; - } - - /* - * Read file contents. - */ - if (buffbytes > 0) { - bytes = read(t->entry_fd, t->entry_buff, buffbytes); - if (bytes < 0) { - archive_set_error(&a->archive, errno, "Read error"); - r = ARCHIVE_FATAL; - a->archive.state = ARCHIVE_STATE_FATAL; - goto abort_read_data; - } - } else - bytes = 0; - /* - * Return an EOF unless we've read a leading empty sparse region, which - * is used to represent fully-sparse files. - */ - if (bytes == 0 && !empty_sparse_region) { - /* Get EOF */ - t->entry_eof = 1; - r = ARCHIVE_EOF; - goto abort_read_data; - } - *buff = t->entry_buff; - *size = bytes; - *offset = t->entry_total; - t->entry_total += bytes; - t->entry_remaining_bytes -= bytes; - if (t->entry_remaining_bytes == 0) { - /* Close the current file descriptor */ - close_and_restore_time(t->entry_fd, t, &t->restore_time); - t->entry_fd = -1; - t->entry_eof = 1; - } - t->current_sparse->offset += bytes; - t->current_sparse->length -= bytes; - if (t->current_sparse->length == 0 && !t->entry_eof) - t->current_sparse++; - return (ARCHIVE_OK); - -abort_read_data: - *buff = NULL; - *size = 0; - *offset = t->entry_total; - if (t->entry_fd >= 0) { - /* Close the current file descriptor */ - close_and_restore_time(t->entry_fd, t, &t->restore_time); - t->entry_fd = -1; - } - return (r); -} - -static int -next_entry(struct archive_read_disk *a, struct tree *t, - struct archive_entry *entry) -{ - const struct stat *st; /* info to use for this entry */ - const struct stat *lst;/* lstat() information */ - const char *name; - int descend, r; - - st = NULL; - lst = NULL; - t->descend = 0; - do { - switch (tree_next(t)) { - case TREE_ERROR_FATAL: - archive_set_error(&a->archive, t->tree_errno, - "%s: Unable to continue traversing directory tree", - tree_current_path(t)); - a->archive.state = ARCHIVE_STATE_FATAL; - tree_enter_initial_dir(t); - return (ARCHIVE_FATAL); - case TREE_ERROR_DIR: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "%s: Couldn't visit directory", - tree_current_path(t)); - tree_enter_initial_dir(t); - return (ARCHIVE_FAILED); - case 0: - tree_enter_initial_dir(t); - return (ARCHIVE_EOF); - case TREE_POSTDESCENT: - case TREE_POSTASCENT: - break; - case TREE_REGULAR: - lst = tree_current_lstat(t); - if (lst == NULL) { - archive_set_error(&a->archive, errno, - "%s: Cannot stat", - tree_current_path(t)); - tree_enter_initial_dir(t); - return (ARCHIVE_FAILED); - } - break; - } - } while (lst == NULL); - -#ifdef __APPLE__ - if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { - /* If we're using copyfile(), ignore "._XXX" files. */ - const char *bname = strrchr(tree_current_path(t), '/'); - if (bname == NULL) - bname = tree_current_path(t); - else - ++bname; - if (bname[0] == '.' && bname[1] == '_') - return (ARCHIVE_RETRY); - } -#endif - - archive_entry_copy_pathname(entry, tree_current_path(t)); - /* - * Perform path matching. - */ - if (a->matching) { - r = archive_match_path_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* - * Distinguish 'L'/'P'/'H' symlink following. - */ - switch(t->symlink_mode) { - case 'H': - /* 'H': After the first item, rest like 'P'. */ - t->symlink_mode = 'P'; - /* 'H': First item (from command line) like 'L'. */ - /* FALLTHROUGH */ - case 'L': - /* 'L': Do descend through a symlink to dir. */ - descend = tree_current_is_dir(t); - /* 'L': Follow symlinks to files. */ - a->symlink_mode = 'L'; - a->follow_symlinks = 1; - /* 'L': Archive symlinks as targets, if we can. */ - st = tree_current_stat(t); - if (st != NULL && !tree_target_is_same_as_parent(t, st)) - break; - /* If stat fails, we have a broken symlink; - * in that case, don't follow the link. */ - /* FALLTHROUGH */ - default: - /* 'P': Don't descend through a symlink to dir. */ - descend = tree_current_is_physical_dir(t); - /* 'P': Don't follow symlinks to files. */ - a->symlink_mode = 'P'; - a->follow_symlinks = 0; - /* 'P': Archive symlinks as symlinks. */ - st = lst; - break; - } - - if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) { - a->archive.state = ARCHIVE_STATE_FATAL; - tree_enter_initial_dir(t); - return (ARCHIVE_FATAL); - } - if (t->initial_filesystem_id == -1) - t->initial_filesystem_id = t->current_filesystem_id; - if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) { - if (t->initial_filesystem_id != t->current_filesystem_id) - descend = 0; - } - t->descend = descend; - - /* - * Honor nodump flag. - * If the file is marked with nodump flag, do not return this entry. - */ - if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) { -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - if (st->st_flags & UF_NODUMP) - return (ARCHIVE_RETRY); -#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \ - defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ - (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \ - defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) - if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { - int stflags; - - t->entry_fd = open_on_current_dir(t, - tree_current_access_path(t), - O_RDONLY | O_NONBLOCK | O_CLOEXEC); - __archive_ensure_cloexec_flag(t->entry_fd); - if (t->entry_fd >= 0) { - r = ioctl(t->entry_fd, -#ifdef FS_IOC_GETFLAGS - FS_IOC_GETFLAGS, -#else - EXT2_IOC_GETFLAGS, -#endif - &stflags); -#ifdef FS_NODUMP_FL - if (r == 0 && (stflags & FS_NODUMP_FL) != 0) -#else - if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) -#endif - return (ARCHIVE_RETRY); - } - } -#endif - } - - archive_entry_copy_stat(entry, st); - - /* Save the times to be restored. This must be in before - * calling archive_read_disk_descend() or any chance of it, - * especially, invoking a callback. */ - t->restore_time.mtime = archive_entry_mtime(entry); - t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); - t->restore_time.atime = archive_entry_atime(entry); - t->restore_time.atime_nsec = archive_entry_atime_nsec(entry); - t->restore_time.filetype = archive_entry_filetype(entry); - t->restore_time.noatime = t->current_filesystem->noatime; - - /* - * Perform time matching. - */ - if (a->matching) { - r = archive_match_time_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* Lookup uname/gname */ - name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); - if (name != NULL) - archive_entry_copy_uname(entry, name); - name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); - if (name != NULL) - archive_entry_copy_gname(entry, name); - - /* - * Perform owner matching. - */ - if (a->matching) { - r = archive_match_owner_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* - * Invoke a meta data filter callback. - */ - if (a->metadata_filter_func) { - if (!a->metadata_filter_func(&(a->archive), - a->metadata_filter_data, entry)) - return (ARCHIVE_RETRY); - } - - /* - * Populate the archive_entry with metadata from the disk. - */ - archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); - r = archive_read_disk_entry_from_file(&(a->archive), entry, - t->entry_fd, st); - - return (r); -} - -static int -_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) -{ - int ret; - struct archive_read_disk *a = (struct archive_read_disk *)_a; - *entryp = NULL; - ret = _archive_read_next_header2(_a, a->entry); - *entryp = a->entry; - return ret; -} - -static int -_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t; - int r; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_next_header2"); - - t = a->tree; - if (t->entry_fd >= 0) { - close_and_restore_time(t->entry_fd, t, &t->restore_time); - t->entry_fd = -1; - } - - for (;;) { - r = next_entry(a, t, entry); - if (t->entry_fd >= 0) { - close(t->entry_fd); - t->entry_fd = -1; - } - - if (r == ARCHIVE_RETRY) { - archive_entry_clear(entry); - continue; - } - break; - } - - /* Return to the initial directory. */ - tree_enter_initial_dir(t); - - /* - * EOF and FATAL are persistent at this layer. By - * modifying the state, we guarantee that future calls to - * read a header or read data will fail. - */ - switch (r) { - case ARCHIVE_EOF: - a->archive.state = ARCHIVE_STATE_EOF; - break; - case ARCHIVE_OK: - case ARCHIVE_WARN: - /* Overwrite the sourcepath based on the initial directory. */ - archive_entry_copy_sourcepath(entry, tree_current_path(t)); - t->entry_total = 0; - if (archive_entry_filetype(entry) == AE_IFREG) { - t->nlink = archive_entry_nlink(entry); - t->entry_remaining_bytes = archive_entry_size(entry); - t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; - if (!t->entry_eof && - setup_sparse(a, entry) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } else { - t->entry_remaining_bytes = 0; - t->entry_eof = 1; - } - a->archive.state = ARCHIVE_STATE_DATA; - break; - case ARCHIVE_RETRY: - break; - case ARCHIVE_FATAL: - a->archive.state = ARCHIVE_STATE_FATAL; - break; - } - - __archive_reset_read_data(&a->archive); - return (r); -} - -static int -setup_sparse(struct archive_read_disk *a, struct archive_entry *entry) -{ - struct tree *t = a->tree; - int64_t length, offset; - int i; - - t->sparse_count = archive_entry_sparse_reset(entry); - if (t->sparse_count+1 > t->sparse_list_size) { - free(t->sparse_list); - t->sparse_list_size = t->sparse_count + 1; - t->sparse_list = malloc(sizeof(t->sparse_list[0]) * - t->sparse_list_size); - if (t->sparse_list == NULL) { - t->sparse_list_size = 0; - archive_set_error(&a->archive, ENOMEM, - "Can't allocate data"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } - for (i = 0; i < t->sparse_count; i++) { - archive_entry_sparse_next(entry, &offset, &length); - t->sparse_list[i].offset = offset; - t->sparse_list[i].length = length; - } - if (i == 0) { - t->sparse_list[i].offset = 0; - t->sparse_list[i].length = archive_entry_size(entry); - } else { - t->sparse_list[i].offset = archive_entry_size(entry); - t->sparse_list[i].length = 0; - } - t->current_sparse = t->sparse_list; - - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_matching(struct archive *_a, struct archive *_ma, - void (*_excluded_func)(struct archive *, void *, struct archive_entry *), - void *_client_data) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); - a->matching = _ma; - a->excluded_cb_func = _excluded_func; - a->excluded_cb_data = _client_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_metadata_filter_callback(struct archive *_a, - int (*_metadata_filter_func)(struct archive *, void *, - struct archive_entry *), void *_client_data) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, - "archive_read_disk_set_metadata_filter_callback"); - - a->metadata_filter_func = _metadata_filter_func; - a->metadata_filter_data = _client_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_can_descend(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_disk_can_descend"); - - return (t->visit_type == TREE_REGULAR && t->descend); -} - -/* - * Called by the client to mark the directory just returned from - * tree_next() as needing to be visited. - */ -int -archive_read_disk_descend(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_disk_descend"); - - if (t->visit_type != TREE_REGULAR || !t->descend) - return (ARCHIVE_OK); - - if (tree_current_is_physical_dir(t)) { - tree_push(t, t->basename, t->current_filesystem_id, - t->lst.st_dev, t->lst.st_ino, &t->restore_time); - t->stack->flags |= isDir; - } else if (tree_current_is_dir(t)) { - tree_push(t, t->basename, t->current_filesystem_id, - t->st.st_dev, t->st.st_ino, &t->restore_time); - t->stack->flags |= isDirLink; - } - t->descend = 0; - return (ARCHIVE_OK); -} - -int -archive_read_disk_open(struct archive *_a, const char *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, - "archive_read_disk_open"); - archive_clear_error(&a->archive); - - return (_archive_read_disk_open(_a, pathname)); -} - -int -archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct archive_string path; - int ret; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, - "archive_read_disk_open_w"); - archive_clear_error(&a->archive); - - /* Make a char string from a wchar_t string. */ - archive_string_init(&path); - if (archive_string_append_from_wcs(&path, pathname, - wcslen(pathname)) != 0) { - if (errno == ENOMEM) - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory"); - else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Can't convert a path to a char string"); - a->archive.state = ARCHIVE_STATE_FATAL; - ret = ARCHIVE_FATAL; - } else - ret = _archive_read_disk_open(_a, path.s); - - archive_string_free(&path); - return (ret); -} - -static int -_archive_read_disk_open(struct archive *_a, const char *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - if (a->tree != NULL) - a->tree = tree_reopen(a->tree, pathname, - a->flags & ARCHIVE_READDISK_RESTORE_ATIME); - else - a->tree = tree_open(pathname, a->symlink_mode, - a->flags & ARCHIVE_READDISK_RESTORE_ATIME); - if (a->tree == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate tar data"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - a->archive.state = ARCHIVE_STATE_HEADER; - - return (ARCHIVE_OK); -} - -/* - * Return a current filesystem ID which is index of the filesystem entry - * you've visited through archive_read_disk. - */ -int -archive_read_disk_current_filesystem(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem_id); -} - -static int -update_current_filesystem(struct archive_read_disk *a, int64_t dev) -{ - struct tree *t = a->tree; - int i, fid; - - if (t->current_filesystem != NULL && - t->current_filesystem->dev == dev) - return (ARCHIVE_OK); - - for (i = 0; i < t->max_filesystem_id; i++) { - if (t->filesystem_table[i].dev == dev) { - /* There is the filesystem ID we've already generated. */ - t->current_filesystem_id = i; - t->current_filesystem = &(t->filesystem_table[i]); - return (ARCHIVE_OK); - } - } - - /* - * This is the new filesystem which we have to generate a new ID for. - */ - fid = t->max_filesystem_id++; - if (t->max_filesystem_id > t->allocated_filesystem) { - size_t s; - void *p; - - s = t->max_filesystem_id * 2; - p = realloc(t->filesystem_table, - s * sizeof(*t->filesystem_table)); - if (p == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate tar data"); - return (ARCHIVE_FATAL); - } - t->filesystem_table = (struct filesystem *)p; - t->allocated_filesystem = s; - } - t->current_filesystem_id = fid; - t->current_filesystem = &(t->filesystem_table[fid]); - t->current_filesystem->dev = dev; - t->current_filesystem->allocation_ptr = NULL; - t->current_filesystem->buff = NULL; - - /* Setup the current filesystem properties which depend on - * platform specific. */ - return (setup_current_filesystem(a)); -} - -/* - * Returns 1 if current filesystem is generated filesystem, 0 if it is not - * or -1 if it is unknown. - */ -int -archive_read_disk_current_filesystem_is_synthetic(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem->synthetic); -} - -/* - * Returns 1 if current filesystem is remote filesystem, 0 if it is not - * or -1 if it is unknown. - */ -int -archive_read_disk_current_filesystem_is_remote(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem->remote); -} - -#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\ - defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN) -static int -get_xfer_size(struct tree *t, int fd, const char *path) -{ - t->current_filesystem->xfer_align = -1; - errno = 0; - if (fd >= 0) { - t->current_filesystem->incr_xfer_size = - fpathconf(fd, _PC_REC_INCR_XFER_SIZE); - t->current_filesystem->max_xfer_size = - fpathconf(fd, _PC_REC_MAX_XFER_SIZE); - t->current_filesystem->min_xfer_size = - fpathconf(fd, _PC_REC_MIN_XFER_SIZE); - t->current_filesystem->xfer_align = - fpathconf(fd, _PC_REC_XFER_ALIGN); - } else if (path != NULL) { - t->current_filesystem->incr_xfer_size = - pathconf(path, _PC_REC_INCR_XFER_SIZE); - t->current_filesystem->max_xfer_size = - pathconf(path, _PC_REC_MAX_XFER_SIZE); - t->current_filesystem->min_xfer_size = - pathconf(path, _PC_REC_MIN_XFER_SIZE); - t->current_filesystem->xfer_align = - pathconf(path, _PC_REC_XFER_ALIGN); - } - /* At least we need an alignment size. */ - if (t->current_filesystem->xfer_align == -1) - return ((errno == EINVAL)?1:-1); - else - return (0); -} -#else -static int -get_xfer_size(struct tree *t, int fd, const char *path) -{ - (void)t; /* UNUSED */ - (void)fd; /* UNUSED */ - (void)path; /* UNUSED */ - return (1);/* Not supported */ -} -#endif - -#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \ - && !defined(ST_LOCAL) - -/* - * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X. - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - struct statfs sfs; -#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) -/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make - * this accurate; some platforms have both and we need the one that's - * used by getvfsbyname() - * - * Then the following would become: - * #if defined(GETVFSBYNAME_ARG_TYPE) - * GETVFSBYNAME_ARG_TYPE vfc; - * #endif - */ -# if defined(HAVE_STRUCT_XVFSCONF) - struct xvfsconf vfc; -# else - struct vfsconf vfc; -# endif -#endif - int r, xr = 0; -#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) - long nm; -#endif - - t->current_filesystem->synthetic = -1; - t->current_filesystem->remote = -1; - if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) - /* - * Get file system statistics on any directory - * where current is. - */ - int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY | O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - if (fd < 0) { - archive_set_error(&a->archive, errno, - "openat failed"); - return (ARCHIVE_FAILED); - } - r = fstatfs(fd, &sfs); - if (r == 0) - xr = get_xfer_size(t, fd, NULL); - close(fd); -#else - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - r = statfs(tree_current_access_path(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, tree_current_access_path(t)); -#endif - } else { - r = fstatfs(tree_current_dir_fd(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); - } - if (r == -1 || xr == -1) { - archive_set_error(&a->archive, errno, "statfs failed"); - return (ARCHIVE_FAILED); - } else if (xr == 1) { - /* pathconf(_PC_REX_*) operations are not supported. */ - t->current_filesystem->xfer_align = sfs.f_bsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = sfs.f_iosize; - t->current_filesystem->incr_xfer_size = sfs.f_iosize; - } - if (sfs.f_flags & MNT_LOCAL) - t->current_filesystem->remote = 0; - else - t->current_filesystem->remote = 1; - -#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) - r = getvfsbyname(sfs.f_fstypename, &vfc); - if (r == -1) { - archive_set_error(&a->archive, errno, "getvfsbyname failed"); - return (ARCHIVE_FAILED); - } - if (vfc.vfc_flags & VFCF_SYNTHETIC) - t->current_filesystem->synthetic = 1; - else - t->current_filesystem->synthetic = 0; -#endif - -#if defined(MNT_NOATIME) - if (sfs.f_flags & MNT_NOATIME) - t->current_filesystem->noatime = 1; - else -#endif - t->current_filesystem->noatime = 0; - -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ -#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) - t->current_filesystem->name_max = sfs.f_namemax; -#else -# if defined(_PC_NAME_MAX) - /* Mac OS X does not have f_namemax in struct statfs. */ - if (tree_current_is_symblic_link_target(t)) { - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - } else - nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); -# else - nm = -1; -# endif - if (nm == -1) - t->current_filesystem->name_max = NAME_MAX; - else - t->current_filesystem->name_max = nm; -#endif -#endif /* USE_READDIR_R */ - return (ARCHIVE_OK); -} - -#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL) - -/* - * Gather current filesystem properties on NetBSD - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - struct statvfs sfs; - int r, xr = 0; - - t->current_filesystem->synthetic = -1; - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - if (tree_current_is_symblic_link_target(t)) { - r = statvfs(tree_current_access_path(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, tree_current_access_path(t)); - } else { -#ifdef HAVE_FSTATVFS - r = fstatvfs(tree_current_dir_fd(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); -#else - r = statvfs(".", &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, "."); -#endif - } - if (r == -1 || xr == -1) { - t->current_filesystem->remote = -1; - archive_set_error(&a->archive, errno, "statvfs failed"); - return (ARCHIVE_FAILED); - } else if (xr == 1) { - /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN - * for pathconf() function. */ - t->current_filesystem->xfer_align = sfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; -#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) - t->current_filesystem->min_xfer_size = sfs.f_iosize; - t->current_filesystem->incr_xfer_size = sfs.f_iosize; -#else - t->current_filesystem->min_xfer_size = sfs.f_bsize; - t->current_filesystem->incr_xfer_size = sfs.f_bsize; -#endif - } - if (sfs.f_flag & ST_LOCAL) - t->current_filesystem->remote = 0; - else - t->current_filesystem->remote = 1; - -#if defined(ST_NOATIME) - if (sfs.f_flag & ST_NOATIME) - t->current_filesystem->noatime = 1; - else -#endif - t->current_filesystem->noatime = 0; - - /* Set maximum filename length. */ - t->current_filesystem->name_max = sfs.f_namemax; - return (ARCHIVE_OK); -} - -#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\ - defined(HAVE_STATFS) && defined(HAVE_FSTATFS) -/* - * Note: statfs is deprecated since LSB 3.2 - */ - -#ifndef CIFS_SUPER_MAGIC -#define CIFS_SUPER_MAGIC 0xFF534D42 -#endif -#ifndef DEVFS_SUPER_MAGIC -#define DEVFS_SUPER_MAGIC 0x1373 -#endif - -/* - * Gather current filesystem properties on Linux - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - struct statfs sfs; -#if defined(HAVE_STATVFS) - struct statvfs svfs; -#endif - int r, vr = 0, xr = 0; - - if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) - /* - * Get file system statistics on any directory - * where current is. - */ - int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY | O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - if (fd < 0) { - archive_set_error(&a->archive, errno, - "openat failed"); - return (ARCHIVE_FAILED); - } -#if defined(HAVE_FSTATVFS) - vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */ -#endif - r = fstatfs(fd, &sfs); - if (r == 0) - xr = get_xfer_size(t, fd, NULL); - close(fd); -#else - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } -#if defined(HAVE_STATVFS) - vr = statvfs(tree_current_access_path(t), &svfs); -#endif - r = statfs(tree_current_access_path(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, tree_current_access_path(t)); -#endif - } else { -#ifdef HAVE_FSTATFS -#if defined(HAVE_FSTATVFS) - vr = fstatvfs(tree_current_dir_fd(t), &svfs); -#endif - r = fstatfs(tree_current_dir_fd(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); -#else - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } -#if defined(HAVE_STATVFS) - vr = statvfs(".", &svfs); -#endif - r = statfs(".", &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, "."); -#endif - } - if (r == -1 || xr == -1 || vr == -1) { - t->current_filesystem->synthetic = -1; - t->current_filesystem->remote = -1; - archive_set_error(&a->archive, errno, "statfs failed"); - return (ARCHIVE_FAILED); - } else if (xr == 1) { - /* pathconf(_PC_REX_*) operations are not supported. */ -#if defined(HAVE_STATVFS) - t->current_filesystem->xfer_align = svfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = svfs.f_bsize; - t->current_filesystem->incr_xfer_size = svfs.f_bsize; -#else - t->current_filesystem->xfer_align = sfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = sfs.f_bsize; - t->current_filesystem->incr_xfer_size = sfs.f_bsize; -#endif - } - switch (sfs.f_type) { - case AFS_SUPER_MAGIC: - case CIFS_SUPER_MAGIC: - case CODA_SUPER_MAGIC: - case NCP_SUPER_MAGIC:/* NetWare */ - case NFS_SUPER_MAGIC: - case SMB_SUPER_MAGIC: - t->current_filesystem->remote = 1; - t->current_filesystem->synthetic = 0; - break; - case DEVFS_SUPER_MAGIC: - case PROC_SUPER_MAGIC: - case USBDEVICE_SUPER_MAGIC: - t->current_filesystem->remote = 0; - t->current_filesystem->synthetic = 1; - break; - default: - t->current_filesystem->remote = 0; - t->current_filesystem->synthetic = 0; - break; - } - -#if defined(ST_NOATIME) -#if defined(HAVE_STATVFS) - if (svfs.f_flag & ST_NOATIME) -#else - if (sfs.f_flag & ST_NOATIME) -#endif - t->current_filesystem->noatime = 1; - else -#endif - t->current_filesystem->noatime = 0; - -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ - t->current_filesystem->name_max = sfs.f_namelen; -#endif - return (ARCHIVE_OK); -} - -#elif defined(HAVE_SYS_STATVFS_H) &&\ - (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) - -/* - * Gather current filesystem properties on other posix platform. - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - struct statvfs sfs; - int r, xr = 0; - - t->current_filesystem->synthetic = -1;/* Not supported */ - t->current_filesystem->remote = -1;/* Not supported */ - if (tree_current_is_symblic_link_target(t)) { -#if defined(HAVE_OPENAT) - /* - * Get file system statistics on any directory - * where current is. - */ - int fd = openat(tree_current_dir_fd(t), - tree_current_access_path(t), O_RDONLY | O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - if (fd < 0) { - archive_set_error(&a->archive, errno, - "openat failed"); - return (ARCHIVE_FAILED); - } - r = fstatvfs(fd, &sfs); - if (r == 0) - xr = get_xfer_size(t, fd, NULL); - close(fd); -#else - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - r = statvfs(tree_current_access_path(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, tree_current_access_path(t)); -#endif - } else { -#ifdef HAVE_FSTATVFS - r = fstatvfs(tree_current_dir_fd(t), &sfs); - if (r == 0) - xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); -#else - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - r = statvfs(".", &sfs); - if (r == 0) - xr = get_xfer_size(t, -1, "."); -#endif - } - if (r == -1 || xr == -1) { - t->current_filesystem->synthetic = -1; - t->current_filesystem->remote = -1; - archive_set_error(&a->archive, errno, "statvfs failed"); - return (ARCHIVE_FAILED); - } else if (xr == 1) { - /* pathconf(_PC_REX_*) operations are not supported. */ - t->current_filesystem->xfer_align = sfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = sfs.f_bsize; - t->current_filesystem->incr_xfer_size = sfs.f_bsize; - } - -#if defined(ST_NOATIME) - if (sfs.f_flag & ST_NOATIME) - t->current_filesystem->noatime = 1; - else -#endif - t->current_filesystem->noatime = 0; - -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ - t->current_filesystem->name_max = sfs.f_namemax; -#endif - return (ARCHIVE_OK); -} - -#else - -/* - * Generic: Gather current filesystem properties. - * TODO: Is this generic function really needed? - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; -#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R) - long nm; -#endif - t->current_filesystem->synthetic = -1;/* Not supported */ - t->current_filesystem->remote = -1;/* Not supported */ - t->current_filesystem->noatime = 0; - (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */ - t->current_filesystem->xfer_align = -1;/* Unknown */ - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = -1; - t->current_filesystem->incr_xfer_size = -1; - -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ -# if defined(_PC_NAME_MAX) - if (tree_current_is_symblic_link_target(t)) { - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - } else - nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); - if (nm == -1) -# endif /* _PC_NAME_MAX */ - /* - * Some systems (HP-UX or others?) incorrectly defined - * NAME_MAX macro to be a smaller value. - */ -# if defined(NAME_MAX) && NAME_MAX >= 255 - t->current_filesystem->name_max = NAME_MAX; -# else - /* No way to get a trusted value of maximum filename - * length. */ - t->current_filesystem->name_max = PATH_MAX; -# endif /* NAME_MAX */ -# if defined(_PC_NAME_MAX) - else - t->current_filesystem->name_max = nm; -# endif /* _PC_NAME_MAX */ -#endif /* USE_READDIR_R */ - return (ARCHIVE_OK); -} - -#endif - -static int -close_and_restore_time(int fd, struct tree *t, struct restore_time *rt) -{ -#ifndef HAVE_UTIMES - (void)t; /* UNUSED */ - (void)rt; /* UNUSED */ - return (close(fd)); -#else -#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) - struct timespec timespecs[2]; -#endif - struct timeval times[2]; - - if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) { - if (fd >= 0) - return (close(fd)); - else - return (0); - } - -#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) - timespecs[1].tv_sec = rt->mtime; - timespecs[1].tv_nsec = rt->mtime_nsec; - - timespecs[0].tv_sec = rt->atime; - timespecs[0].tv_nsec = rt->atime_nsec; - /* futimens() is defined in POSIX.1-2008. */ - if (futimens(fd, timespecs) == 0) - return (close(fd)); -#endif - - times[1].tv_sec = rt->mtime; - times[1].tv_usec = rt->mtime_nsec / 1000; - - times[0].tv_sec = rt->atime; - times[0].tv_usec = rt->atime_nsec / 1000; - -#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__) - if (futimes(fd, times) == 0) - return (close(fd)); -#endif - close(fd); -#if defined(HAVE_FUTIMESAT) - if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0) - return (0); -#endif -#ifdef HAVE_LUTIMES - if (lutimes(rt->name, times) != 0) -#else - if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0) -#endif - return (-1); -#endif - return (0); -} - -static int -open_on_current_dir(struct tree *t, const char *path, int flags) -{ -#ifdef HAVE_OPENAT - return (openat(tree_current_dir_fd(t), path, flags)); -#else - if (tree_enter_working_dir(t) != 0) - return (-1); - return (open(path, flags)); -#endif -} - -static int -tree_dup(int fd) -{ - int new_fd; -#ifdef F_DUPFD_CLOEXEC - static volatile int can_dupfd_cloexec = 1; - - if (can_dupfd_cloexec) { - new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); - if (new_fd != -1) - return (new_fd); - /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, - * but it cannot be used. So we have to try dup(). */ - /* We won't try F_DUPFD_CLOEXEC. */ - can_dupfd_cloexec = 0; - } -#endif /* F_DUPFD_CLOEXEC */ - new_fd = dup(fd); - __archive_ensure_cloexec_flag(new_fd); - return (new_fd); -} - -/* - * Add a directory path to the current stack. - */ -static void -tree_push(struct tree *t, const char *path, int filesystem_id, - int64_t dev, int64_t ino, struct restore_time *rt) -{ - struct tree_entry *te; - - te = calloc(1, sizeof(*te)); - te->next = t->stack; - te->parent = t->current; - if (te->parent) - te->depth = te->parent->depth + 1; - t->stack = te; - archive_string_init(&te->name); - te->symlink_parent_fd = -1; - archive_strcpy(&te->name, path); - te->flags = needsDescent | needsOpen | needsAscent; - te->filesystem_id = filesystem_id; - te->dev = dev; - te->ino = ino; - te->dirname_length = t->dirname_length; - te->restore_time.name = te->name.s; - if (rt != NULL) { - te->restore_time.mtime = rt->mtime; - te->restore_time.mtime_nsec = rt->mtime_nsec; - te->restore_time.atime = rt->atime; - te->restore_time.atime_nsec = rt->atime_nsec; - te->restore_time.filetype = rt->filetype; - te->restore_time.noatime = rt->noatime; - } -} - -/* - * Append a name to the current dir path. - */ -static void -tree_append(struct tree *t, const char *name, size_t name_length) -{ - size_t size_needed; - - t->path.s[t->dirname_length] = '\0'; - t->path.length = t->dirname_length; - /* Strip trailing '/' from name, unless entire name is "/". */ - while (name_length > 1 && name[name_length - 1] == '/') - name_length--; - - /* Resize pathname buffer as needed. */ - size_needed = name_length + t->dirname_length + 2; - archive_string_ensure(&t->path, size_needed); - /* Add a separating '/' if it's needed. */ - if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/') - archive_strappend_char(&t->path, '/'); - t->basename = t->path.s + archive_strlen(&t->path); - archive_strncat(&t->path, name, name_length); - t->restore_time.name = t->basename; -} - -/* - * Open a directory tree for traversal. - */ -static struct tree * -tree_open(const char *path, int symlink_mode, int restore_time) -{ - struct tree *t; - - if ((t = calloc(1, sizeof(*t))) == NULL) - return (NULL); - archive_string_init(&t->path); - archive_string_ensure(&t->path, 31); - t->initial_symlink_mode = symlink_mode; - return (tree_reopen(t, path, restore_time)); -} - -static struct tree * -tree_reopen(struct tree *t, const char *path, int restore_time) -{ - t->flags = (restore_time != 0)?needsRestoreTimes:0; - t->flags |= onInitialDir; - t->visit_type = 0; - t->tree_errno = 0; - t->dirname_length = 0; - t->depth = 0; - t->descend = 0; - t->current = NULL; - t->d = INVALID_DIR_HANDLE; - t->symlink_mode = t->initial_symlink_mode; - archive_string_empty(&t->path); - t->entry_fd = -1; - t->entry_eof = 0; - t->entry_remaining_bytes = 0; - t->initial_filesystem_id = -1; - - /* First item is set up a lot like a symlink traversal. */ - tree_push(t, path, 0, 0, 0, NULL); - t->stack->flags = needsFirstVisit; - t->maxOpenCount = t->openCount = 1; - t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC); - __archive_ensure_cloexec_flag(t->initial_dir_fd); - t->working_dir_fd = tree_dup(t->initial_dir_fd); - return (t); -} - -static int -tree_descent(struct tree *t) -{ - int flag, new_fd, r = 0; - - t->dirname_length = archive_strlen(&t->path); - flag = O_RDONLY | O_CLOEXEC; -#if defined(O_DIRECTORY) - flag |= O_DIRECTORY; -#endif - new_fd = open_on_current_dir(t, t->stack->name.s, flag); - __archive_ensure_cloexec_flag(new_fd); - if (new_fd < 0) { - t->tree_errno = errno; - r = TREE_ERROR_DIR; - } else { - t->depth++; - /* If it is a link, set up fd for the ascent. */ - if (t->stack->flags & isDirLink) { - t->stack->symlink_parent_fd = t->working_dir_fd; - t->openCount++; - if (t->openCount > t->maxOpenCount) - t->maxOpenCount = t->openCount; - } else - close(t->working_dir_fd); - /* Renew the current working directory. */ - t->working_dir_fd = new_fd; - t->flags &= ~onWorkingDir; - } - return (r); -} - -/* - * We've finished a directory; ascend back to the parent. - */ -static int -tree_ascend(struct tree *t) -{ - struct tree_entry *te; - int new_fd, r = 0, prev_dir_fd; - - te = t->stack; - prev_dir_fd = t->working_dir_fd; - if (te->flags & isDirLink) - new_fd = te->symlink_parent_fd; - else { - new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC); - __archive_ensure_cloexec_flag(new_fd); - } - if (new_fd < 0) { - t->tree_errno = errno; - r = TREE_ERROR_FATAL; - } else { - /* Renew the current working directory. */ - t->working_dir_fd = new_fd; - t->flags &= ~onWorkingDir; - /* Current directory has been changed, we should - * close an fd of previous working directory. */ - close_and_restore_time(prev_dir_fd, t, &te->restore_time); - if (te->flags & isDirLink) { - t->openCount--; - te->symlink_parent_fd = -1; - } - t->depth--; - } - return (r); -} - -/* - * Return to the initial directory where tree_open() was performed. - */ -static int -tree_enter_initial_dir(struct tree *t) -{ - int r = 0; - - if ((t->flags & onInitialDir) == 0) { - r = fchdir(t->initial_dir_fd); - if (r == 0) { - t->flags &= ~onWorkingDir; - t->flags |= onInitialDir; - } - } - return (r); -} - -/* - * Restore working directory of directory traversals. - */ -static int -tree_enter_working_dir(struct tree *t) -{ - int r = 0; - - /* - * Change the current directory if really needed. - * Sometimes this is unneeded when we did not do - * descent. - */ - if (t->depth > 0 && (t->flags & onWorkingDir) == 0) { - r = fchdir(t->working_dir_fd); - if (r == 0) { - t->flags &= ~onInitialDir; - t->flags |= onWorkingDir; - } - } - return (r); -} - -static int -tree_current_dir_fd(struct tree *t) -{ - return (t->working_dir_fd); -} - -/* - * Pop the working stack. - */ -static void -tree_pop(struct tree *t) -{ - struct tree_entry *te; - - t->path.s[t->dirname_length] = '\0'; - t->path.length = t->dirname_length; - if (t->stack == t->current && t->current != NULL) - t->current = t->current->parent; - te = t->stack; - t->stack = te->next; - t->dirname_length = te->dirname_length; - t->basename = t->path.s + t->dirname_length; - while (t->basename[0] == '/') - t->basename++; - archive_string_free(&te->name); - free(te); -} - -/* - * Get the next item in the tree traversal. - */ -static int -tree_next(struct tree *t) -{ - int r; - - while (t->stack != NULL) { - /* If there's an open dir, get the next entry from there. */ - if (t->d != INVALID_DIR_HANDLE) { - r = tree_dir_next_posix(t); - if (r == 0) - continue; - return (r); - } - - if (t->stack->flags & needsFirstVisit) { - /* Top stack item needs a regular visit. */ - t->current = t->stack; - tree_append(t, t->stack->name.s, - archive_strlen(&(t->stack->name))); - /* t->dirname_length = t->path_length; */ - /* tree_pop(t); */ - t->stack->flags &= ~needsFirstVisit; - return (t->visit_type = TREE_REGULAR); - } else if (t->stack->flags & needsDescent) { - /* Top stack item is dir to descend into. */ - t->current = t->stack; - tree_append(t, t->stack->name.s, - archive_strlen(&(t->stack->name))); - t->stack->flags &= ~needsDescent; - r = tree_descent(t); - if (r != 0) { - tree_pop(t); - t->visit_type = r; - } else - t->visit_type = TREE_POSTDESCENT; - return (t->visit_type); - } else if (t->stack->flags & needsOpen) { - t->stack->flags &= ~needsOpen; - r = tree_dir_next_posix(t); - if (r == 0) - continue; - return (r); - } else if (t->stack->flags & needsAscent) { - /* Top stack item is dir and we're done with it. */ - r = tree_ascend(t); - tree_pop(t); - t->visit_type = r != 0 ? r : TREE_POSTASCENT; - return (t->visit_type); - } else { - /* Top item on stack is dead. */ - tree_pop(t); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - } - } - return (t->visit_type = 0); -} - -static int -tree_dir_next_posix(struct tree *t) -{ - int r; - const char *name; - size_t namelen; - - if (t->d == NULL) { -#if defined(USE_READDIR_R) - size_t dirent_size; -#endif - -#if defined(HAVE_FDOPENDIR) - t->d = fdopendir(tree_dup(t->working_dir_fd)); -#else /* HAVE_FDOPENDIR */ - if (tree_enter_working_dir(t) == 0) { - t->d = opendir("."); -#if HAVE_DIRFD || defined(dirfd) - __archive_ensure_cloexec_flag(dirfd(t->d)); -#endif - } -#endif /* HAVE_FDOPENDIR */ - if (t->d == NULL) { - r = tree_ascend(t); /* Undo "chdir" */ - tree_pop(t); - t->tree_errno = errno; - t->visit_type = r != 0 ? r : TREE_ERROR_DIR; - return (t->visit_type); - } -#if defined(USE_READDIR_R) - dirent_size = offsetof(struct dirent, d_name) + - t->filesystem_table[t->current->filesystem_id].name_max + 1; - if (t->dirent == NULL || t->dirent_allocated < dirent_size) { - free(t->dirent); - t->dirent = malloc(dirent_size); - if (t->dirent == NULL) { - closedir(t->d); - t->d = INVALID_DIR_HANDLE; - (void)tree_ascend(t); - tree_pop(t); - t->tree_errno = ENOMEM; - t->visit_type = TREE_ERROR_DIR; - return (t->visit_type); - } - t->dirent_allocated = dirent_size; - } -#endif /* USE_READDIR_R */ - } - for (;;) { - errno = 0; -#if defined(USE_READDIR_R) - r = readdir_r(t->d, t->dirent, &t->de); -#ifdef _AIX - /* Note: According to the man page, return value 9 indicates - * that the readdir_r was not successful and the error code - * is set to the global errno variable. And then if the end - * of directory entries was reached, the return value is 9 - * and the third parameter is set to NULL and errno is - * unchanged. */ - if (r == 9) - r = errno; -#endif /* _AIX */ - if (r != 0 || t->de == NULL) { -#else - t->de = readdir(t->d); - if (t->de == NULL) { - r = errno; -#endif - closedir(t->d); - t->d = INVALID_DIR_HANDLE; - if (r != 0) { - t->tree_errno = r; - t->visit_type = TREE_ERROR_DIR; - return (t->visit_type); - } else - return (0); - } - name = t->de->d_name; - namelen = D_NAMELEN(t->de); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - if (name[0] == '.' && name[1] == '\0') - continue; - if (name[0] == '.' && name[1] == '.' && name[2] == '\0') - continue; - tree_append(t, name, namelen); - return (t->visit_type = TREE_REGULAR); - } -} - - -/* - * Get the stat() data for the entry just returned from tree_next(). - */ -static const struct stat * -tree_current_stat(struct tree *t) -{ - if (!(t->flags & hasStat)) { -#ifdef HAVE_FSTATAT - if (fstatat(tree_current_dir_fd(t), - tree_current_access_path(t), &t->st, 0) != 0) -#else - if (tree_enter_working_dir(t) != 0) - return NULL; - if (stat(tree_current_access_path(t), &t->st) != 0) -#endif - return NULL; - t->flags |= hasStat; - } - return (&t->st); -} - -/* - * Get the lstat() data for the entry just returned from tree_next(). - */ -static const struct stat * -tree_current_lstat(struct tree *t) -{ - if (!(t->flags & hasLstat)) { -#ifdef HAVE_FSTATAT - if (fstatat(tree_current_dir_fd(t), - tree_current_access_path(t), &t->lst, - AT_SYMLINK_NOFOLLOW) != 0) -#else - if (tree_enter_working_dir(t) != 0) - return NULL; - if (lstat(tree_current_access_path(t), &t->lst) != 0) -#endif - return NULL; - t->flags |= hasLstat; - } - return (&t->lst); -} - -/* - * Test whether current entry is a dir or link to a dir. - */ -static int -tree_current_is_dir(struct tree *t) -{ - const struct stat *st; - /* - * If we already have lstat() info, then try some - * cheap tests to determine if this is a dir. - */ - if (t->flags & hasLstat) { - /* If lstat() says it's a dir, it must be a dir. */ - st = tree_current_lstat(t); - if (st == NULL) - return 0; - if (S_ISDIR(st->st_mode)) - return 1; - /* Not a dir; might be a link to a dir. */ - /* If it's not a link, then it's not a link to a dir. */ - if (!S_ISLNK(st->st_mode)) - return 0; - /* - * It's a link, but we don't know what it's a link to, - * so we'll have to use stat(). - */ - } - - st = tree_current_stat(t); - /* If we can't stat it, it's not a dir. */ - if (st == NULL) - return 0; - /* Use the definitive test. Hopefully this is cached. */ - return (S_ISDIR(st->st_mode)); -} - -/* - * Test whether current entry is a physical directory. Usually, we - * already have at least one of stat() or lstat() in memory, so we - * use tricks to try to avoid an extra trip to the disk. - */ -static int -tree_current_is_physical_dir(struct tree *t) -{ - const struct stat *st; - - /* - * If stat() says it isn't a dir, then it's not a dir. - * If stat() data is cached, this check is free, so do it first. - */ - if (t->flags & hasStat) { - st = tree_current_stat(t); - if (st == NULL) - return (0); - if (!S_ISDIR(st->st_mode)) - return (0); - } - - /* - * Either stat() said it was a dir (in which case, we have - * to determine whether it's really a link to a dir) or - * stat() info wasn't available. So we use lstat(), which - * hopefully is already cached. - */ - - st = tree_current_lstat(t); - /* If we can't stat it, it's not a dir. */ - if (st == NULL) - return 0; - /* Use the definitive test. Hopefully this is cached. */ - return (S_ISDIR(st->st_mode)); -} - -/* - * Test whether the same file has been in the tree as its parent. - */ -static int -tree_target_is_same_as_parent(struct tree *t, const struct stat *st) -{ - struct tree_entry *te; - - for (te = t->current->parent; te != NULL; te = te->parent) { - if (te->dev == (int64_t)st->st_dev && - te->ino == (int64_t)st->st_ino) - return (1); - } - return (0); -} - -/* - * Test whether the current file is symbolic link target and - * on the other filesystem. - */ -static int -tree_current_is_symblic_link_target(struct tree *t) -{ - static const struct stat *lst, *st; - - lst = tree_current_lstat(t); - st = tree_current_stat(t); - return (st != NULL && lst != NULL && - (int64_t)st->st_dev == t->current_filesystem->dev && - st->st_dev != lst->st_dev); -} - -/* - * Return the access path for the entry just returned from tree_next(). - */ -static const char * -tree_current_access_path(struct tree *t) -{ - return (t->basename); -} - -/* - * Return the full path for the entry just returned from tree_next(). - */ -static const char * -tree_current_path(struct tree *t) -{ - return (t->path.s); -} - -/* - * Terminate the traversal. - */ -static void -tree_close(struct tree *t) -{ - - if (t == NULL) - return; - if (t->entry_fd >= 0) { - close_and_restore_time(t->entry_fd, t, &t->restore_time); - t->entry_fd = -1; - } - /* Close the handle of readdir(). */ - if (t->d != INVALID_DIR_HANDLE) { - closedir(t->d); - t->d = INVALID_DIR_HANDLE; - } - /* Release anything remaining in the stack. */ - while (t->stack != NULL) { - if (t->stack->flags & isDirLink) - close(t->stack->symlink_parent_fd); - tree_pop(t); - } - if (t->working_dir_fd >= 0) { - close(t->working_dir_fd); - t->working_dir_fd = -1; - } - if (t->initial_dir_fd >= 0) { - close(t->initial_dir_fd); - t->initial_dir_fd = -1; - } -} - -/* - * Release any resources. - */ -static void -tree_free(struct tree *t) -{ - int i; - - if (t == NULL) - return; - archive_string_free(&t->path); -#if defined(USE_READDIR_R) - free(t->dirent); -#endif - free(t->sparse_list); - for (i = 0; i < t->max_filesystem_id; i++) - free(t->filesystem_table[i].allocation_ptr); - free(t->filesystem_table); - free(t); -} - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_private.h b/3rdparty/libarchive/libarchive/archive_read_disk_private.h deleted file mode 100644 index f03a0a9c..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_disk_private.h +++ /dev/null @@ -1,98 +0,0 @@ -/*- - * Copyright (c) 2003-2009 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_read_disk_private.h 201105 2009-12-28 03:20:54Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED -#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED - -#include "archive_platform_acl.h" - -struct tree; -struct archive_entry; - -struct archive_read_disk { - struct archive archive; - - /* Reused by archive_read_next_header() */ - struct archive_entry *entry; - - /* - * Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid, - * following an old BSD convention. 'L' follows all symlinks, - * 'P' follows none, 'H' follows symlinks only for the first - * item. - */ - char symlink_mode; - - /* - * Since symlink interaction changes, we need to track whether - * we're following symlinks for the current item. 'L' mode above - * sets this true, 'P' sets it false, 'H' changes it as we traverse. - */ - char follow_symlinks; /* Either 'L' or 'P'. */ - - /* Directory traversals. */ - struct tree *tree; - int (*open_on_current_dir)(struct tree*, const char *, int); - int (*tree_current_dir_fd)(struct tree*); - int (*tree_enter_working_dir)(struct tree*); - - /* Bitfield with ARCHIVE_READDISK_* tunables */ - int flags; - - const char * (*lookup_gname)(void *private, int64_t gid); - void (*cleanup_gname)(void *private); - void *lookup_gname_data; - const char * (*lookup_uname)(void *private, int64_t uid); - void (*cleanup_uname)(void *private); - void *lookup_uname_data; - - int (*metadata_filter_func)(struct archive *, void *, - struct archive_entry *); - void *metadata_filter_data; - - /* ARCHIVE_MATCH object. */ - struct archive *matching; - /* Callback function, this will be invoked when ARCHIVE_MATCH - * archive_match_*_excluded_ae return true. */ - void (*excluded_cb_func)(struct archive *, void *, - struct archive_entry *); - void *excluded_cb_data; -}; - -const char * -archive_read_disk_entry_setup_path(struct archive_read_disk *, - struct archive_entry *, int *); - -int -archive_read_disk_entry_setup_acls(struct archive_read_disk *, - struct archive_entry *, int *); -#endif diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c b/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c deleted file mode 100644 index c7fd2471..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c +++ /dev/null @@ -1,313 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_set_standard_lookup.c 201109 2009-12-28 03:30:31Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" - -#if defined(_WIN32) && !defined(__CYGWIN__) -int -archive_read_disk_set_standard_lookup(struct archive *a) -{ - archive_set_error(a, -1, "Standard lookups not available on Windows"); - return (ARCHIVE_FATAL); -} -#else /* ! (_WIN32 && !__CYGWIN__) */ -#define name_cache_size 127 - -static const char * const NO_NAME = "(noname)"; - -struct name_cache { - struct archive *archive; - char *buff; - size_t buff_size; - int probes; - int hits; - size_t size; - struct { - id_t id; - const char *name; - } cache[name_cache_size]; -}; - -static const char * lookup_gname(void *, int64_t); -static const char * lookup_uname(void *, int64_t); -static void cleanup(void *); -static const char * lookup_gname_helper(struct name_cache *, id_t gid); -static const char * lookup_uname_helper(struct name_cache *, id_t uid); - -/* - * Installs functions that use getpwuid()/getgrgid()---along with - * a simple cache to accelerate such lookups---into the archive_read_disk - * object. This is in a separate file because getpwuid()/getgrgid() - * can pull in a LOT of library code (including NIS/LDAP functions, which - * pull in DNS resolvers, etc). This can easily top 500kB, which makes - * it inappropriate for some space-constrained applications. - * - * Applications that are size-sensitive may want to just use the - * real default functions (defined in archive_read_disk.c) that just - * use the uid/gid without the lookup. Or define your own custom functions - * if you prefer. - */ -int -archive_read_disk_set_standard_lookup(struct archive *a) -{ - struct name_cache *ucache = malloc(sizeof(struct name_cache)); - struct name_cache *gcache = malloc(sizeof(struct name_cache)); - - if (ucache == NULL || gcache == NULL) { - archive_set_error(a, ENOMEM, - "Can't allocate uname/gname lookup cache"); - free(ucache); - free(gcache); - return (ARCHIVE_FATAL); - } - - memset(ucache, 0, sizeof(*ucache)); - ucache->archive = a; - ucache->size = name_cache_size; - memset(gcache, 0, sizeof(*gcache)); - gcache->archive = a; - gcache->size = name_cache_size; - - archive_read_disk_set_gname_lookup(a, gcache, lookup_gname, cleanup); - archive_read_disk_set_uname_lookup(a, ucache, lookup_uname, cleanup); - - return (ARCHIVE_OK); -} - -static void -cleanup(void *data) -{ - struct name_cache *cache = (struct name_cache *)data; - size_t i; - - if (cache != NULL) { - for (i = 0; i < cache->size; i++) { - if (cache->cache[i].name != NULL && - cache->cache[i].name != NO_NAME) - free((void *)(uintptr_t)cache->cache[i].name); - } - free(cache->buff); - free(cache); - } -} - -/* - * Lookup uid/gid from uname/gname, return NULL if no match. - */ -static const char * -lookup_name(struct name_cache *cache, - const char * (*lookup_fn)(struct name_cache *, id_t), id_t id) -{ - const char *name; - int slot; - - - cache->probes++; - - slot = id % cache->size; - if (cache->cache[slot].name != NULL) { - if (cache->cache[slot].id == id) { - cache->hits++; - if (cache->cache[slot].name == NO_NAME) - return (NULL); - return (cache->cache[slot].name); - } - if (cache->cache[slot].name != NO_NAME) - free((void *)(uintptr_t)cache->cache[slot].name); - cache->cache[slot].name = NULL; - } - - name = (lookup_fn)(cache, id); - if (name == NULL) { - /* Cache and return the negative response. */ - cache->cache[slot].name = NO_NAME; - cache->cache[slot].id = id; - return (NULL); - } - - cache->cache[slot].name = name; - cache->cache[slot].id = id; - return (cache->cache[slot].name); -} - -static const char * -lookup_uname(void *data, int64_t uid) -{ - struct name_cache *uname_cache = (struct name_cache *)data; - return (lookup_name(uname_cache, - &lookup_uname_helper, (id_t)uid)); -} - -#if HAVE_GETPWUID_R -static const char * -lookup_uname_helper(struct name_cache *cache, id_t id) -{ - struct passwd pwent, *result; - char * nbuff; - size_t nbuff_size; - int r; - - if (cache->buff_size == 0) { - cache->buff_size = 256; - cache->buff = malloc(cache->buff_size); - } - if (cache->buff == NULL) - return (NULL); - for (;;) { - result = &pwent; /* Old getpwuid_r ignores last arg. */ - r = getpwuid_r((uid_t)id, &pwent, - cache->buff, cache->buff_size, &result); - if (r == 0) - break; - if (r != ERANGE) - break; - /* 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. 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; - nbuff = realloc(cache->buff, nbuff_size); - if (nbuff == NULL) - break; - cache->buff = nbuff; - cache->buff_size = nbuff_size; - } - if (r != 0) { - archive_set_error(cache->archive, errno, - "Can't lookup user for id %d", (int)id); - return (NULL); - } - if (result == NULL) - return (NULL); - - return strdup(result->pw_name); -} -#else -static const char * -lookup_uname_helper(struct name_cache *cache, id_t id) -{ - struct passwd *result; - (void)cache; /* UNUSED */ - - result = getpwuid((uid_t)id); - - if (result == NULL) - return (NULL); - - return strdup(result->pw_name); -} -#endif - -static const char * -lookup_gname(void *data, int64_t gid) -{ - struct name_cache *gname_cache = (struct name_cache *)data; - return (lookup_name(gname_cache, - &lookup_gname_helper, (id_t)gid)); -} - -#if HAVE_GETGRGID_R -static const char * -lookup_gname_helper(struct name_cache *cache, id_t id) -{ - struct group grent, *result; - char * nbuff; - size_t nbuff_size; - int r; - - if (cache->buff_size == 0) { - cache->buff_size = 256; - cache->buff = malloc(cache->buff_size); - } - if (cache->buff == NULL) - return (NULL); - for (;;) { - result = &grent; /* Old getgrgid_r ignores last arg. */ - r = getgrgid_r((gid_t)id, &grent, - cache->buff, cache->buff_size, &result); - if (r == 0) - break; - if (r != ERANGE) - break; - /* 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; - nbuff = realloc(cache->buff, nbuff_size); - if (nbuff == NULL) - break; - cache->buff = nbuff; - cache->buff_size = nbuff_size; - } - if (r != 0) { - archive_set_error(cache->archive, errno, - "Can't lookup group for id %d", (int)id); - return (NULL); - } - if (result == NULL) - return (NULL); - - return strdup(result->gr_name); -} -#else -static const char * -lookup_gname_helper(struct name_cache *cache, id_t id) -{ - struct group *result; - (void)cache; /* UNUSED */ - - result = getgrgid((gid_t)id); - - if (result == NULL) - return (NULL); - - return strdup(result->gr_name); -} -#endif - -#endif /* ! (_WIN32 && !__CYGWIN__) */ diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_windows.c b/3rdparty/libarchive/libarchive/archive_read_disk_windows.c deleted file mode 100644 index 3b903304..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_disk_windows.c +++ /dev/null @@ -1,2298 +0,0 @@ -/*- - * Copyright (c) 2003-2009 Tim Kientzle - * Copyright (c) 2010-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#if defined(_WIN32) && !defined(__CYGWIN__) - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#include - -#include "archive.h" -#include "archive_string.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_disk_private.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef IO_REPARSE_TAG_SYMLINK -/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ -#define IO_REPARSE_TAG_SYMLINK 0xA000000CL -#endif - -/*- - * This is a new directory-walking system that addresses a number - * of problems I've had with fts(3). In particular, it has no - * pathname-length limits (other than the size of 'int'), handles - * deep logical traversals, uses considerably less memory, and has - * an opaque interface (easier to modify in the future). - * - * Internally, it keeps a single list of "tree_entry" items that - * represent filesystem objects that require further attention. - * Non-directories are not kept in memory: they are pulled from - * readdir(), returned to the client, then freed as soon as possible. - * Any directory entry to be traversed gets pushed onto the stack. - * - * There is surprisingly little information that needs to be kept for - * each item on the stack. Just the name, depth (represented here as the - * string length of the parent directory's pathname), and some markers - * indicating how to get back to the parent (via chdir("..") for a - * regular dir or via fchdir(2) for a symlink). - */ - -struct restore_time { - const wchar_t *full_path; - FILETIME lastWriteTime; - FILETIME lastAccessTime; - mode_t filetype; -}; - -struct tree_entry { - int depth; - struct tree_entry *next; - struct tree_entry *parent; - size_t full_path_dir_length; - struct archive_wstring name; - struct archive_wstring full_path; - size_t dirname_length; - int64_t dev; - int64_t ino; - int flags; - int filesystem_id; - /* How to restore time of a directory. */ - struct restore_time restore_time; -}; - -struct filesystem { - int64_t dev; - int synthetic; - int remote; - DWORD bytesPerSector; -}; - -/* Definitions for tree_entry.flags bitmap. */ -#define isDir 1 /* This entry is a regular directory. */ -#define isDirLink 2 /* This entry is a symbolic link to a directory. */ -#define needsFirstVisit 4 /* This is an initial entry. */ -#define needsDescent 8 /* This entry needs to be previsited. */ -#define needsOpen 16 /* This is a directory that needs to be opened. */ -#define needsAscent 32 /* This entry needs to be postvisited. */ - -/* - * On Windows, "first visit" is handled as a pattern to be handed to - * _findfirst(). This is consistent with Windows conventions that - * file patterns are handled within the application. On Posix, - * "first visit" is just returned to the client. - */ - -#define MAX_OVERLAPPED 8 -#define BUFFER_SIZE (1024 * 8) -#define DIRECT_IO 0/* Disabled */ -#define ASYNC_IO 1/* Enabled */ - -/* - * Local data for this package. - */ -struct tree { - struct tree_entry *stack; - struct tree_entry *current; - HANDLE d; - WIN32_FIND_DATAW _findData; - WIN32_FIND_DATAW *findData; - int flags; - int visit_type; - /* Error code from last failed operation. */ - int tree_errno; - - /* A full path with "\\?\" prefix. */ - struct archive_wstring full_path; - size_t full_path_dir_length; - /* Dynamically-sized buffer for holding path */ - struct archive_wstring path; - - /* Last path element */ - const wchar_t *basename; - /* Leading dir length */ - size_t dirname_length; - - int depth; - - BY_HANDLE_FILE_INFORMATION lst; - BY_HANDLE_FILE_INFORMATION st; - int descend; - /* How to restore time of a file. */ - struct restore_time restore_time; - - struct entry_sparse { - int64_t length; - int64_t offset; - } *sparse_list, *current_sparse; - int sparse_count; - int sparse_list_size; - - char initial_symlink_mode; - char symlink_mode; - struct filesystem *current_filesystem; - struct filesystem *filesystem_table; - int initial_filesystem_id; - int current_filesystem_id; - int max_filesystem_id; - int allocated_filesystem; - - HANDLE entry_fh; - int entry_eof; - int64_t entry_remaining_bytes; - int64_t entry_total; - - int ol_idx_doing; - int ol_idx_done; - int ol_num_doing; - int ol_num_done; - int64_t ol_remaining_bytes; - int64_t ol_total; - struct la_overlapped { - OVERLAPPED ol; - struct archive * _a; - unsigned char *buff; - size_t buff_size; - int64_t offset; - size_t bytes_expected; - size_t bytes_transferred; - } ol[MAX_OVERLAPPED]; - int direct_io; - int async_io; -}; - -#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber) -/* Treat FileIndex as i-node. We should remove a sequence number - * which is high-16-bits of nFileIndexHigh. */ -#define bhfi_ino(bhfi) \ - ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \ - + (bhfi)->nFileIndexLow) - -/* Definitions for tree.flags bitmap. */ -#define hasStat 16 /* The st entry is valid. */ -#define hasLstat 32 /* The lst entry is valid. */ -#define needsRestoreTimes 128 - -static int -tree_dir_next_windows(struct tree *t, const wchar_t *pattern); - -/* Initiate/terminate a tree traversal. */ -static struct tree *tree_open(const wchar_t *, int, int); -static struct tree *tree_reopen(struct tree *, const wchar_t *, int); -static void tree_close(struct tree *); -static void tree_free(struct tree *); -static void tree_push(struct tree *, const wchar_t *, const wchar_t *, - int, int64_t, int64_t, struct restore_time *); - -/* - * tree_next() returns Zero if there is no next entry, non-zero if - * there is. Note that directories are visited three times. - * Directories are always visited first as part of enumerating their - * parent; that is a "regular" visit. If tree_descend() is invoked at - * that time, the directory is added to a work list and will - * subsequently be visited two more times: once just after descending - * into the directory ("postdescent") and again just after ascending - * back to the parent ("postascent"). - * - * TREE_ERROR_DIR is returned if the descent failed (because the - * directory couldn't be opened, for instance). This is returned - * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a - * fatal error, but it does imply that the relevant subtree won't be - * visited. TREE_ERROR_FATAL is returned for an error that left the - * traversal completely hosed. Right now, this is only returned for - * chdir() failures during ascent. - */ -#define TREE_REGULAR 1 -#define TREE_POSTDESCENT 2 -#define TREE_POSTASCENT 3 -#define TREE_ERROR_DIR -1 -#define TREE_ERROR_FATAL -2 - -static int tree_next(struct tree *); - -/* - * Return information about the current entry. - */ - -/* - * The current full pathname, length of the full pathname, and a name - * that can be used to access the file. Because tree does use chdir - * extensively, the access path is almost never the same as the full - * current path. - * - */ -static const wchar_t *tree_current_path(struct tree *); -static const wchar_t *tree_current_access_path(struct tree *); - -/* - * Request the lstat() or stat() data for the current path. Since the - * tree package needs to do some of this anyway, and caches the - * results, you should take advantage of it here if you need it rather - * than make a redundant stat() or lstat() call of your own. - */ -static const BY_HANDLE_FILE_INFORMATION *tree_current_stat(struct tree *); -static const BY_HANDLE_FILE_INFORMATION *tree_current_lstat(struct tree *); - -/* The following functions use tricks to avoid a certain number of - * stat()/lstat() calls. */ -/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ -static int tree_current_is_physical_dir(struct tree *); -/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */ -static int tree_current_is_physical_link(struct tree *); -/* Instead of archive_entry_copy_stat for BY_HANDLE_FILE_INFORMATION */ -static void tree_archive_entry_copy_bhfi(struct archive_entry *, - struct tree *, const BY_HANDLE_FILE_INFORMATION *); -/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ -static int tree_current_is_dir(struct tree *); -static int update_current_filesystem(struct archive_read_disk *a, - int64_t dev); -static int setup_current_filesystem(struct archive_read_disk *); -static int tree_target_is_same_as_parent(struct tree *, - const BY_HANDLE_FILE_INFORMATION *); - -static int _archive_read_disk_open_w(struct archive *, const wchar_t *); -static int _archive_read_free(struct archive *); -static int _archive_read_close(struct archive *); -static int _archive_read_data_block(struct archive *, - const void **, size_t *, int64_t *); -static int _archive_read_next_header(struct archive *, - struct archive_entry **); -static int _archive_read_next_header2(struct archive *, - struct archive_entry *); -static const char *trivial_lookup_gname(void *, int64_t gid); -static const char *trivial_lookup_uname(void *, int64_t uid); -static int setup_sparse(struct archive_read_disk *, struct archive_entry *); -static int close_and_restore_time(HANDLE, struct tree *, - struct restore_time *); -static int setup_sparse_from_disk(struct archive_read_disk *, - struct archive_entry *, HANDLE); - - - -static struct archive_vtable * -archive_read_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - inited = 1; - } - return (&av); -} - -const char * -archive_read_disk_gname(struct archive *_a, int64_t gid) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_gname")) - return (NULL); - if (a->lookup_gname == NULL) - return (NULL); - return ((*a->lookup_gname)(a->lookup_gname_data, gid)); -} - -const char * -archive_read_disk_uname(struct archive *_a, int64_t uid) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_uname")) - return (NULL); - if (a->lookup_uname == NULL) - return (NULL); - return ((*a->lookup_uname)(a->lookup_uname_data, uid)); -} - -int -archive_read_disk_set_gname_lookup(struct archive *_a, - void *private_data, - const char * (*lookup_gname)(void *private, int64_t gid), - void (*cleanup_gname)(void *private)) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); - - if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) - (a->cleanup_gname)(a->lookup_gname_data); - - a->lookup_gname = lookup_gname; - a->cleanup_gname = cleanup_gname; - a->lookup_gname_data = private_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_uname_lookup(struct archive *_a, - void *private_data, - const char * (*lookup_uname)(void *private, int64_t uid), - void (*cleanup_uname)(void *private)) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); - - if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) - (a->cleanup_uname)(a->lookup_uname_data); - - a->lookup_uname = lookup_uname; - a->cleanup_uname = cleanup_uname; - a->lookup_uname_data = private_data; - return (ARCHIVE_OK); -} - -/* - * Create a new archive_read_disk object and initialize it with global state. - */ -struct archive * -archive_read_disk_new(void) -{ - struct archive_read_disk *a; - - a = (struct archive_read_disk *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_READ_DISK_MAGIC; - a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_read_disk_vtable(); - a->entry = archive_entry_new2(&a->archive); - a->lookup_uname = trivial_lookup_uname; - a->lookup_gname = trivial_lookup_gname; - a->flags = ARCHIVE_READDISK_MAC_COPYFILE; - return (&a->archive); -} - -static int -_archive_read_free(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - int r; - - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); - - if (a->archive.state != ARCHIVE_STATE_CLOSED) - r = _archive_read_close(&a->archive); - else - r = ARCHIVE_OK; - - tree_free(a->tree); - if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) - (a->cleanup_gname)(a->lookup_gname_data); - if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) - (a->cleanup_uname)(a->lookup_uname_data); - archive_string_free(&a->archive.error_string); - archive_entry_free(a->entry); - a->archive.magic = 0; - free(a); - return (r); -} - -static int -_archive_read_close(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); - - if (a->archive.state != ARCHIVE_STATE_FATAL) - a->archive.state = ARCHIVE_STATE_CLOSED; - - tree_close(a->tree); - - return (ARCHIVE_OK); -} - -static void -setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, - int follow_symlinks) -{ - a->symlink_mode = symlink_mode; - a->follow_symlinks = follow_symlinks; - if (a->tree != NULL) { - a->tree->initial_symlink_mode = a->symlink_mode; - a->tree->symlink_mode = a->symlink_mode; - } -} - -int -archive_read_disk_set_symlink_logical(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); - setup_symlink_mode(a, 'L', 1); - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_symlink_physical(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); - setup_symlink_mode(a, 'P', 0); - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_symlink_hybrid(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); - setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_atime_restored(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); - a->flags |= ARCHIVE_READDISK_RESTORE_ATIME; - if (a->tree != NULL) - a->tree->flags |= needsRestoreTimes; - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_behavior(struct archive *_a, int flags) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - int r = ARCHIVE_OK; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); - - a->flags = flags; - - if (flags & ARCHIVE_READDISK_RESTORE_ATIME) - r = archive_read_disk_set_atime_restored(_a); - else { - if (a->tree != NULL) - a->tree->flags &= ~needsRestoreTimes; - } - return (r); -} - -/* - * Trivial implementations of gname/uname lookup functions. - * These are normally overridden by the client, but these stub - * versions ensure that we always have something that works. - */ -static const char * -trivial_lookup_gname(void *private_data, int64_t gid) -{ - (void)private_data; /* UNUSED */ - (void)gid; /* UNUSED */ - return (NULL); -} - -static const char * -trivial_lookup_uname(void *private_data, int64_t uid) -{ - (void)private_data; /* UNUSED */ - (void)uid; /* UNUSED */ - return (NULL); -} - -static int64_t -align_num_per_sector(struct tree *t, int64_t size) -{ - int64_t surplus; - - size += t->current_filesystem->bytesPerSector -1; - surplus = size % t->current_filesystem->bytesPerSector; - size -= surplus; - return (size); -} - -static int -start_next_async_read(struct archive_read_disk *a, struct tree *t) -{ - struct la_overlapped *olp; - DWORD buffbytes, rbytes; - - if (t->ol_remaining_bytes == 0) - return (ARCHIVE_EOF); - - olp = &(t->ol[t->ol_idx_doing]); - t->ol_idx_doing = (t->ol_idx_doing + 1) % MAX_OVERLAPPED; - - /* Allocate read buffer. */ - if (olp->buff == NULL) { - void *p; - size_t s = (size_t)align_num_per_sector(t, BUFFER_SIZE); - p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE); - if (p == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Couldn't allocate memory"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - olp->buff = p; - olp->buff_size = s; - olp->_a = &a->archive; - olp->ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - if (olp->ol.hEvent == NULL) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "CreateEvent failed"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } else - ResetEvent(olp->ol.hEvent); - - buffbytes = (DWORD)olp->buff_size; - if (buffbytes > t->current_sparse->length) - buffbytes = (DWORD)t->current_sparse->length; - - /* Skip hole. */ - if (t->current_sparse->offset > t->ol_total) { - t->ol_remaining_bytes -= - t->current_sparse->offset - t->ol_total; - } - - olp->offset = t->current_sparse->offset; - olp->ol.Offset = (DWORD)(olp->offset & 0xffffffff); - olp->ol.OffsetHigh = (DWORD)(olp->offset >> 32); - - if (t->ol_remaining_bytes > buffbytes) { - olp->bytes_expected = buffbytes; - t->ol_remaining_bytes -= buffbytes; - } else { - olp->bytes_expected = (size_t)t->ol_remaining_bytes; - t->ol_remaining_bytes = 0; - } - olp->bytes_transferred = 0; - t->current_sparse->offset += buffbytes; - t->current_sparse->length -= buffbytes; - t->ol_total = t->current_sparse->offset; - if (t->current_sparse->length == 0 && t->ol_remaining_bytes > 0) - t->current_sparse++; - - if (!ReadFile(t->entry_fh, olp->buff, buffbytes, &rbytes, &(olp->ol))) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == ERROR_HANDLE_EOF) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Reading file truncated"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } else if (lasterr != ERROR_IO_PENDING) { - if (lasterr == ERROR_NO_DATA) - errno = EAGAIN; - else if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - archive_set_error(&a->archive, errno, "Read error"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } else - olp->bytes_transferred = rbytes; - t->ol_num_doing++; - - return (t->ol_remaining_bytes == 0)? ARCHIVE_EOF: ARCHIVE_OK; -} - -static void -cancel_async(struct tree *t) -{ - if (t->ol_num_doing != t->ol_num_done) { - CancelIo(t->entry_fh); - t->ol_num_doing = t->ol_num_done = 0; - } -} - -static int -_archive_read_data_block(struct archive *_a, const void **buff, - size_t *size, int64_t *offset) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - struct la_overlapped *olp; - DWORD bytes_transferred; - int r = ARCHIVE_FATAL; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_data_block"); - - if (t->entry_eof || t->entry_remaining_bytes <= 0) { - r = ARCHIVE_EOF; - goto abort_read_data; - } - - /* - * Make a request to read the file in asynchronous. - */ - if (t->ol_num_doing == 0) { - do { - r = start_next_async_read(a, t); - if (r == ARCHIVE_FATAL) - goto abort_read_data; - if (!t->async_io) - break; - } while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED); - } else { - if (start_next_async_read(a, t) == ARCHIVE_FATAL) - goto abort_read_data; - } - - olp = &(t->ol[t->ol_idx_done]); - t->ol_idx_done = (t->ol_idx_done + 1) % MAX_OVERLAPPED; - if (olp->bytes_transferred) - bytes_transferred = (DWORD)olp->bytes_transferred; - else if (!GetOverlappedResult(t->entry_fh, &(olp->ol), - &bytes_transferred, TRUE)) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "GetOverlappedResult failed"); - a->archive.state = ARCHIVE_STATE_FATAL; - r = ARCHIVE_FATAL; - goto abort_read_data; - } - t->ol_num_done++; - - if (bytes_transferred == 0 || - olp->bytes_expected != bytes_transferred) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Reading file truncated"); - a->archive.state = ARCHIVE_STATE_FATAL; - r = ARCHIVE_FATAL; - goto abort_read_data; - } - - *buff = olp->buff; - *size = bytes_transferred; - *offset = olp->offset; - if (olp->offset > t->entry_total) - t->entry_remaining_bytes -= olp->offset - t->entry_total; - t->entry_total = olp->offset + *size; - t->entry_remaining_bytes -= *size; - if (t->entry_remaining_bytes == 0) { - /* Close the current file descriptor */ - close_and_restore_time(t->entry_fh, t, &t->restore_time); - t->entry_fh = INVALID_HANDLE_VALUE; - t->entry_eof = 1; - } - return (ARCHIVE_OK); - -abort_read_data: - *buff = NULL; - *size = 0; - *offset = t->entry_total; - if (t->entry_fh != INVALID_HANDLE_VALUE) { - cancel_async(t); - /* Close the current file descriptor */ - close_and_restore_time(t->entry_fh, t, &t->restore_time); - t->entry_fh = INVALID_HANDLE_VALUE; - } - return (r); -} - -static int -next_entry(struct archive_read_disk *a, struct tree *t, - struct archive_entry *entry) -{ - const BY_HANDLE_FILE_INFORMATION *st; - const BY_HANDLE_FILE_INFORMATION *lst; - const char*name; - int descend, r; - - st = NULL; - lst = NULL; - t->descend = 0; - do { - switch (tree_next(t)) { - case TREE_ERROR_FATAL: - archive_set_error(&a->archive, t->tree_errno, - "%ls: Unable to continue traversing directory tree", - tree_current_path(t)); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - case TREE_ERROR_DIR: - archive_set_error(&a->archive, t->tree_errno, - "%ls: Couldn't visit directory", - tree_current_path(t)); - return (ARCHIVE_FAILED); - case 0: - return (ARCHIVE_EOF); - case TREE_POSTDESCENT: - case TREE_POSTASCENT: - break; - case TREE_REGULAR: - lst = tree_current_lstat(t); - if (lst == NULL) { - archive_set_error(&a->archive, t->tree_errno, - "%ls: Cannot stat", - tree_current_path(t)); - return (ARCHIVE_FAILED); - } - break; - } - } while (lst == NULL); - - archive_entry_copy_pathname_w(entry, tree_current_path(t)); - - /* - * Perform path matching. - */ - if (a->matching) { - r = archive_match_path_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* - * Distinguish 'L'/'P'/'H' symlink following. - */ - switch(t->symlink_mode) { - case 'H': - /* 'H': After the first item, rest like 'P'. */ - t->symlink_mode = 'P'; - /* 'H': First item (from command line) like 'L'. */ - /* FALLTHROUGH */ - case 'L': - /* 'L': Do descend through a symlink to dir. */ - descend = tree_current_is_dir(t); - /* 'L': Follow symlinks to files. */ - a->symlink_mode = 'L'; - a->follow_symlinks = 1; - /* 'L': Archive symlinks as targets, if we can. */ - st = tree_current_stat(t); - if (st != NULL && !tree_target_is_same_as_parent(t, st)) - break; - /* If stat fails, we have a broken symlink; - * in that case, don't follow the link. */ - /* FALLTHROUGH */ - default: - /* 'P': Don't descend through a symlink to dir. */ - descend = tree_current_is_physical_dir(t); - /* 'P': Don't follow symlinks to files. */ - a->symlink_mode = 'P'; - a->follow_symlinks = 0; - /* 'P': Archive symlinks as symlinks. */ - st = lst; - break; - } - - if (update_current_filesystem(a, bhfi_dev(st)) != ARCHIVE_OK) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - if (t->initial_filesystem_id == -1) - t->initial_filesystem_id = t->current_filesystem_id; - if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) { - if (t->initial_filesystem_id != t->current_filesystem_id) - return (ARCHIVE_RETRY); - } - t->descend = descend; - - tree_archive_entry_copy_bhfi(entry, t, st); - - /* Save the times to be restored. This must be in before - * calling archive_read_disk_descend() or any chance of it, - * especially, invoking a callback. */ - t->restore_time.lastWriteTime = st->ftLastWriteTime; - t->restore_time.lastAccessTime = st->ftLastAccessTime; - t->restore_time.filetype = archive_entry_filetype(entry); - - /* - * Perform time matching. - */ - if (a->matching) { - r = archive_match_time_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* Lookup uname/gname */ - name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); - if (name != NULL) - archive_entry_copy_uname(entry, name); - name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); - if (name != NULL) - archive_entry_copy_gname(entry, name); - - /* - * Perform owner matching. - */ - if (a->matching) { - r = archive_match_owner_excluded(a->matching, entry); - if (r < 0) { - archive_set_error(&(a->archive), errno, - "Failed : %s", archive_error_string(a->matching)); - return (r); - } - if (r) { - if (a->excluded_cb_func) - a->excluded_cb_func(&(a->archive), - a->excluded_cb_data, entry); - return (ARCHIVE_RETRY); - } - } - - /* - * Invoke a meta data filter callback. - */ - if (a->metadata_filter_func) { - if (!a->metadata_filter_func(&(a->archive), - a->metadata_filter_data, entry)) - return (ARCHIVE_RETRY); - } - - archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t)); - - r = ARCHIVE_OK; - if (archive_entry_filetype(entry) == AE_IFREG && - archive_entry_size(entry) > 0) { - DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; - if (t->async_io) - flags |= FILE_FLAG_OVERLAPPED; - if (t->direct_io) - flags |= FILE_FLAG_NO_BUFFERING; - else - flags |= FILE_FLAG_SEQUENTIAL_SCAN; - t->entry_fh = CreateFileW(tree_current_access_path(t), - GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL); - if (t->entry_fh == INVALID_HANDLE_VALUE) { - archive_set_error(&a->archive, errno, - "Couldn't open %ls", tree_current_path(a->tree)); - return (ARCHIVE_FAILED); - } - - /* Find sparse data from the disk. */ - if (archive_entry_hardlink(entry) == NULL && - (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0) - r = setup_sparse_from_disk(a, entry, t->entry_fh); - } - return (r); -} - -static int -_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) -{ - int ret; - struct archive_read_disk *a = (struct archive_read_disk *)_a; - *entryp = NULL; - ret = _archive_read_next_header2(_a, a->entry); - *entryp = a->entry; - return ret; -} - -static int -_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t; - int r; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_next_header2"); - - t = a->tree; - if (t->entry_fh != INVALID_HANDLE_VALUE) { - cancel_async(t); - close_and_restore_time(t->entry_fh, t, &t->restore_time); - t->entry_fh = INVALID_HANDLE_VALUE; - } - - while ((r = next_entry(a, t, entry)) == ARCHIVE_RETRY) - archive_entry_clear(entry); - - /* - * EOF and FATAL are persistent at this layer. By - * modifying the state, we guarantee that future calls to - * read a header or read data will fail. - */ - switch (r) { - case ARCHIVE_EOF: - a->archive.state = ARCHIVE_STATE_EOF; - break; - case ARCHIVE_OK: - case ARCHIVE_WARN: - t->entry_total = 0; - if (archive_entry_filetype(entry) == AE_IFREG) { - t->entry_remaining_bytes = archive_entry_size(entry); - t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; - if (!t->entry_eof && - setup_sparse(a, entry) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } else { - t->entry_remaining_bytes = 0; - t->entry_eof = 1; - } - t->ol_idx_doing = t->ol_idx_done = 0; - t->ol_num_doing = t->ol_num_done = 0; - t->ol_remaining_bytes = t->entry_remaining_bytes; - t->ol_total = 0; - a->archive.state = ARCHIVE_STATE_DATA; - break; - case ARCHIVE_RETRY: - break; - case ARCHIVE_FATAL: - a->archive.state = ARCHIVE_STATE_FATAL; - break; - } - - __archive_reset_read_data(&a->archive); - return (r); -} - -static int -setup_sparse(struct archive_read_disk *a, struct archive_entry *entry) -{ - struct tree *t = a->tree; - int64_t aligned, length, offset; - int i; - - t->sparse_count = archive_entry_sparse_reset(entry); - if (t->sparse_count+1 > t->sparse_list_size) { - free(t->sparse_list); - t->sparse_list_size = t->sparse_count + 1; - t->sparse_list = malloc(sizeof(t->sparse_list[0]) * - t->sparse_list_size); - if (t->sparse_list == NULL) { - t->sparse_list_size = 0; - archive_set_error(&a->archive, ENOMEM, - "Can't allocate data"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - } - /* - * Get sparse list and make sure those offsets and lengths are - * aligned by a sector size. - */ - for (i = 0; i < t->sparse_count; i++) { - archive_entry_sparse_next(entry, &offset, &length); - aligned = align_num_per_sector(t, offset); - if (aligned != offset) { - aligned -= t->current_filesystem->bytesPerSector; - length += offset - aligned; - } - t->sparse_list[i].offset = aligned; - aligned = align_num_per_sector(t, length); - t->sparse_list[i].length = aligned; - } - - aligned = align_num_per_sector(t, archive_entry_size(entry)); - if (i == 0) { - t->sparse_list[i].offset = 0; - t->sparse_list[i].length = aligned; - } else { - int j, last = i; - - t->sparse_list[i].offset = aligned; - t->sparse_list[i].length = 0; - for (i = 0; i < last; i++) { - if ((t->sparse_list[i].offset + - t->sparse_list[i].length) <= - t->sparse_list[i+1].offset) - continue; - /* - * Now sparse_list[i+1] is overlapped by sparse_list[i]. - * Merge those two. - */ - length = t->sparse_list[i+1].offset - - t->sparse_list[i].offset; - t->sparse_list[i+1].offset = t->sparse_list[i].offset; - t->sparse_list[i+1].length += length; - /* Remove sparse_list[i]. */ - for (j = i; j < last; j++) { - t->sparse_list[j].offset = - t->sparse_list[j+1].offset; - t->sparse_list[j].length = - t->sparse_list[j+1].length; - } - last--; - } - } - t->current_sparse = t->sparse_list; - - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_matching(struct archive *_a, struct archive *_ma, - void (*_excluded_func)(struct archive *, void *, struct archive_entry *), - void *_client_data) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); - a->matching = _ma; - a->excluded_cb_func = _excluded_func; - a->excluded_cb_data = _client_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_set_metadata_filter_callback(struct archive *_a, - int (*_metadata_filter_func)(struct archive *, void *, - struct archive_entry *), void *_client_data) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, - "archive_read_disk_set_metadata_filter_callback"); - - a->metadata_filter_func = _metadata_filter_func; - a->metadata_filter_data = _client_data; - return (ARCHIVE_OK); -} - -int -archive_read_disk_can_descend(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_disk_can_descend"); - - return (t->visit_type == TREE_REGULAR && t->descend); -} - -/* - * Called by the client to mark the directory just returned from - * tree_next() as needing to be visited. - */ -int -archive_read_disk_descend(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct tree *t = a->tree; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_read_disk_descend"); - - if (t->visit_type != TREE_REGULAR || !t->descend) - return (ARCHIVE_OK); - - if (tree_current_is_physical_dir(t)) { - tree_push(t, t->basename, t->full_path.s, - t->current_filesystem_id, - bhfi_dev(&(t->lst)), bhfi_ino(&(t->lst)), - &t->restore_time); - t->stack->flags |= isDir; - } else if (tree_current_is_dir(t)) { - tree_push(t, t->basename, t->full_path.s, - t->current_filesystem_id, - bhfi_dev(&(t->st)), bhfi_ino(&(t->st)), - &t->restore_time); - t->stack->flags |= isDirLink; - } - t->descend = 0; - return (ARCHIVE_OK); -} - -int -archive_read_disk_open(struct archive *_a, const char *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - struct archive_wstring wpath; - int ret; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, - "archive_read_disk_open"); - archive_clear_error(&a->archive); - - /* Make a wchar_t string from a char string. */ - archive_string_init(&wpath); - if (archive_wstring_append_from_mbs(&wpath, pathname, - strlen(pathname)) != 0) { - if (errno == ENOMEM) - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory"); - else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Can't convert a path to a wchar_t string"); - a->archive.state = ARCHIVE_STATE_FATAL; - ret = ARCHIVE_FATAL; - } else - ret = _archive_read_disk_open_w(_a, wpath.s); - - archive_wstring_free(&wpath); - return (ret); -} - -int -archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, - "archive_read_disk_open_w"); - archive_clear_error(&a->archive); - - return (_archive_read_disk_open_w(_a, pathname)); -} - -static int -_archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - if (a->tree != NULL) - a->tree = tree_reopen(a->tree, pathname, - a->flags & ARCHIVE_READDISK_RESTORE_ATIME); - else - a->tree = tree_open(pathname, a->symlink_mode, - a->flags & ARCHIVE_READDISK_RESTORE_ATIME); - if (a->tree == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate directory traversal data"); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - a->archive.state = ARCHIVE_STATE_HEADER; - - return (ARCHIVE_OK); -} - -/* - * Return a current filesystem ID which is index of the filesystem entry - * you've visited through archive_read_disk. - */ -int -archive_read_disk_current_filesystem(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem_id); -} - -static int -update_current_filesystem(struct archive_read_disk *a, int64_t dev) -{ - struct tree *t = a->tree; - int i, fid; - - if (t->current_filesystem != NULL && - t->current_filesystem->dev == dev) - return (ARCHIVE_OK); - - for (i = 0; i < t->max_filesystem_id; i++) { - if (t->filesystem_table[i].dev == dev) { - /* There is the filesystem ID we've already generated. */ - t->current_filesystem_id = i; - t->current_filesystem = &(t->filesystem_table[i]); - return (ARCHIVE_OK); - } - } - - /* - * There is a new filesystem, we generate a new ID for. - */ - fid = t->max_filesystem_id++; - if (t->max_filesystem_id > t->allocated_filesystem) { - size_t s; - void *p; - - s = t->max_filesystem_id * 2; - p = realloc(t->filesystem_table, - s * sizeof(*t->filesystem_table)); - if (p == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate tar data"); - return (ARCHIVE_FATAL); - } - t->filesystem_table = (struct filesystem *)p; - t->allocated_filesystem = (int)s; - } - t->current_filesystem_id = fid; - t->current_filesystem = &(t->filesystem_table[fid]); - t->current_filesystem->dev = dev; - - return (setup_current_filesystem(a)); -} - -/* - * Returns 1 if current filesystem is generated filesystem, 0 if it is not - * or -1 if it is unknown. - */ -int -archive_read_disk_current_filesystem_is_synthetic(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem->synthetic); -} - -/* - * Returns 1 if current filesystem is remote filesystem, 0 if it is not - * or -1 if it is unknown. - */ -int -archive_read_disk_current_filesystem_is_remote(struct archive *_a) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - - archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, - "archive_read_disk_current_filesystem"); - - return (a->tree->current_filesystem->remote); -} - -/* - * If symlink is broken, statfs or statvfs will fail. - * Use its directory path instead. - */ -static wchar_t * -safe_path_for_statfs(struct tree *t) -{ - const wchar_t *path; - wchar_t *cp, *p = NULL; - - path = tree_current_access_path(t); - if (tree_current_stat(t) == NULL) { - p = _wcsdup(path); - cp = wcsrchr(p, '/'); - if (cp != NULL && wcslen(cp) >= 2) { - cp[1] = '.'; - cp[2] = '\0'; - path = p; - } - } else - p = _wcsdup(path); - return (p); -} - -/* - * Get conditions of synthetic and remote on Windows - */ -static int -setup_current_filesystem(struct archive_read_disk *a) -{ - struct tree *t = a->tree; - wchar_t vol[256]; - wchar_t *path; - - t->current_filesystem->synthetic = -1;/* Not supported */ - path = safe_path_for_statfs(t); - if (!GetVolumePathNameW(path, vol, sizeof(vol)/sizeof(vol[0]))) { - free(path); - t->current_filesystem->remote = -1; - t->current_filesystem->bytesPerSector = 0; - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "GetVolumePathName failed: %d", (int)GetLastError()); - return (ARCHIVE_FAILED); - } - free(path); - switch (GetDriveTypeW(vol)) { - case DRIVE_UNKNOWN: - case DRIVE_NO_ROOT_DIR: - t->current_filesystem->remote = -1; - break; - case DRIVE_REMOTE: - t->current_filesystem->remote = 1; - break; - default: - t->current_filesystem->remote = 0; - break; - } - - if (!GetDiskFreeSpaceW(vol, NULL, - &(t->current_filesystem->bytesPerSector), NULL, NULL)) { - t->current_filesystem->bytesPerSector = 0; - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "GetDiskFreeSpace failed: %d", (int)GetLastError()); - return (ARCHIVE_FAILED); - } - - return (ARCHIVE_OK); -} - -static int -close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt) -{ - HANDLE handle; - int r = 0; - - if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype) - return (0); - - /* Close a file descriptor. - * It will not be used for SetFileTime() because it has been opened - * by a read only mode. - */ - if (h != INVALID_HANDLE_VALUE) - CloseHandle(h); - if ((t->flags & needsRestoreTimes) == 0) - return (r); - - handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES, - 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (handle == INVALID_HANDLE_VALUE) { - errno = EINVAL; - return (-1); - } - - if (SetFileTime(handle, NULL, &rt->lastAccessTime, - &rt->lastWriteTime) == 0) { - errno = EINVAL; - r = -1; - } else - r = 0; - CloseHandle(handle); - return (r); -} - -/* - * Add a directory path to the current stack. - */ -static void -tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path, - int filesystem_id, int64_t dev, int64_t ino, struct restore_time *rt) -{ - struct tree_entry *te; - - te = calloc(1, sizeof(*te)); - te->next = t->stack; - te->parent = t->current; - if (te->parent) - te->depth = te->parent->depth + 1; - t->stack = te; - archive_string_init(&te->name); - archive_wstrcpy(&te->name, path); - archive_string_init(&te->full_path); - archive_wstrcpy(&te->full_path, full_path); - te->flags = needsDescent | needsOpen | needsAscent; - te->filesystem_id = filesystem_id; - te->dev = dev; - te->ino = ino; - te->dirname_length = t->dirname_length; - te->full_path_dir_length = t->full_path_dir_length; - te->restore_time.full_path = te->full_path.s; - if (rt != NULL) { - te->restore_time.lastWriteTime = rt->lastWriteTime; - te->restore_time.lastAccessTime = rt->lastAccessTime; - te->restore_time.filetype = rt->filetype; - } -} - -/* - * Append a name to the current dir path. - */ -static void -tree_append(struct tree *t, const wchar_t *name, size_t name_length) -{ - size_t size_needed; - - t->path.s[t->dirname_length] = L'\0'; - t->path.length = t->dirname_length; - /* Strip trailing '/' from name, unless entire name is "/". */ - while (name_length > 1 && name[name_length - 1] == L'/') - name_length--; - - /* Resize pathname buffer as needed. */ - size_needed = name_length + t->dirname_length + 2; - archive_wstring_ensure(&t->path, size_needed); - /* Add a separating '/' if it's needed. */ - if (t->dirname_length > 0 && - t->path.s[archive_strlen(&t->path)-1] != L'/') - archive_wstrappend_wchar(&t->path, L'/'); - t->basename = t->path.s + archive_strlen(&t->path); - archive_wstrncat(&t->path, name, name_length); - t->restore_time.full_path = t->basename; - if (t->full_path_dir_length > 0) { - t->full_path.s[t->full_path_dir_length] = L'\0'; - t->full_path.length = t->full_path_dir_length; - size_needed = name_length + t->full_path_dir_length + 2; - archive_wstring_ensure(&t->full_path, size_needed); - /* Add a separating '\' if it's needed. */ - if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\') - archive_wstrappend_wchar(&t->full_path, L'\\'); - archive_wstrncat(&t->full_path, name, name_length); - t->restore_time.full_path = t->full_path.s; - } -} - -/* - * Open a directory tree for traversal. - */ -static struct tree * -tree_open(const wchar_t *path, int symlink_mode, int restore_time) -{ - struct tree *t; - - t = calloc(1, sizeof(*t)); - archive_string_init(&(t->full_path)); - archive_string_init(&t->path); - archive_wstring_ensure(&t->path, 15); - t->initial_symlink_mode = symlink_mode; - return (tree_reopen(t, path, restore_time)); -} - -static struct tree * -tree_reopen(struct tree *t, const wchar_t *path, int restore_time) -{ - struct archive_wstring ws; - wchar_t *pathname, *p, *base; - - t->flags = (restore_time != 0)?needsRestoreTimes:0; - t->visit_type = 0; - t->tree_errno = 0; - t->full_path_dir_length = 0; - t->dirname_length = 0; - t->depth = 0; - t->descend = 0; - t->current = NULL; - t->d = INVALID_HANDLE_VALUE; - t->symlink_mode = t->initial_symlink_mode; - archive_string_empty(&(t->full_path)); - archive_string_empty(&t->path); - t->entry_fh = INVALID_HANDLE_VALUE; - t->entry_eof = 0; - t->entry_remaining_bytes = 0; - t->initial_filesystem_id = -1; - - /* Get wchar_t strings from char strings. */ - archive_string_init(&ws); - archive_wstrcpy(&ws, path); - pathname = ws.s; - /* Get a full-path-name. */ - p = __la_win_permissive_name_w(pathname); - if (p == NULL) - goto failed; - archive_wstrcpy(&(t->full_path), p); - free(p); - - /* Convert path separators from '\' to '/' */ - for (p = pathname; *p != L'\0'; ++p) { - if (*p == L'\\') - *p = L'/'; - } - base = pathname; - - /* First item is set up a lot like a symlink traversal. */ - /* printf("Looking for wildcard in %s\n", path); */ - if ((base[0] == L'/' && base[1] == L'/' && - base[2] == L'?' && base[3] == L'/' && - (wcschr(base+4, L'*') || wcschr(base+4, L'?'))) || - (!(base[0] == L'/' && base[1] == L'/' && - base[2] == L'?' && base[3] == L'/') && - (wcschr(base, L'*') || wcschr(base, L'?')))) { - // It has a wildcard in it... - // Separate the last element. - p = wcsrchr(base, L'/'); - if (p != NULL) { - *p = L'\0'; - tree_append(t, base, p - base); - t->dirname_length = archive_strlen(&t->path); - base = p + 1; - } - p = wcsrchr(t->full_path.s, L'\\'); - if (p != NULL) { - *p = L'\0'; - t->full_path.length = wcslen(t->full_path.s); - t->full_path_dir_length = archive_strlen(&t->full_path); - } - } - tree_push(t, base, t->full_path.s, 0, 0, 0, NULL); - archive_wstring_free(&ws); - t->stack->flags = needsFirstVisit; - /* - * Debug flag for Direct IO(No buffering) or Async IO. - * Those dependent on environment variable switches - * will be removed until next release. - */ - { - const char *e; - if ((e = getenv("LIBARCHIVE_DIRECT_IO")) != NULL) { - if (e[0] == '0') - t->direct_io = 0; - else - t->direct_io = 1; - fprintf(stderr, "LIBARCHIVE_DIRECT_IO=%s\n", - (t->direct_io)?"Enabled":"Disabled"); - } else - t->direct_io = DIRECT_IO; - if ((e = getenv("LIBARCHIVE_ASYNC_IO")) != NULL) { - if (e[0] == '0') - t->async_io = 0; - else - t->async_io = 1; - fprintf(stderr, "LIBARCHIVE_ASYNC_IO=%s\n", - (t->async_io)?"Enabled":"Disabled"); - } else - t->async_io = ASYNC_IO; - } - return (t); -failed: - archive_wstring_free(&ws); - tree_free(t); - return (NULL); -} - -static int -tree_descent(struct tree *t) -{ - t->dirname_length = archive_strlen(&t->path); - t->full_path_dir_length = archive_strlen(&t->full_path); - t->depth++; - return (0); -} - -/* - * We've finished a directory; ascend back to the parent. - */ -static int -tree_ascend(struct tree *t) -{ - struct tree_entry *te; - - te = t->stack; - t->depth--; - close_and_restore_time(INVALID_HANDLE_VALUE, t, &te->restore_time); - return (0); -} - -/* - * Pop the working stack. - */ -static void -tree_pop(struct tree *t) -{ - struct tree_entry *te; - - t->full_path.s[t->full_path_dir_length] = L'\0'; - t->full_path.length = t->full_path_dir_length; - t->path.s[t->dirname_length] = L'\0'; - t->path.length = t->dirname_length; - if (t->stack == t->current && t->current != NULL) - t->current = t->current->parent; - te = t->stack; - t->stack = te->next; - t->dirname_length = te->dirname_length; - t->basename = t->path.s + t->dirname_length; - t->full_path_dir_length = te->full_path_dir_length; - while (t->basename[0] == L'/') - t->basename++; - archive_wstring_free(&te->name); - archive_wstring_free(&te->full_path); - free(te); -} - -/* - * Get the next item in the tree traversal. - */ -static int -tree_next(struct tree *t) -{ - int r; - - while (t->stack != NULL) { - /* If there's an open dir, get the next entry from there. */ - if (t->d != INVALID_HANDLE_VALUE) { - r = tree_dir_next_windows(t, NULL); - if (r == 0) - continue; - return (r); - } - - if (t->stack->flags & needsFirstVisit) { - wchar_t *d = t->stack->name.s; - t->stack->flags &= ~needsFirstVisit; - if (!(d[0] == L'/' && d[1] == L'/' && - d[2] == L'?' && d[3] == L'/') && - (wcschr(d, L'*') || wcschr(d, L'?'))) { - r = tree_dir_next_windows(t, d); - if (r == 0) - continue; - return (r); - } else { - HANDLE h = FindFirstFileW(d, &t->_findData); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - t->tree_errno = errno; - t->visit_type = TREE_ERROR_DIR; - return (t->visit_type); - } - t->findData = &t->_findData; - FindClose(h); - } - /* Top stack item needs a regular visit. */ - t->current = t->stack; - tree_append(t, t->stack->name.s, - archive_strlen(&(t->stack->name))); - //t->dirname_length = t->path_length; - //tree_pop(t); - t->stack->flags &= ~needsFirstVisit; - return (t->visit_type = TREE_REGULAR); - } else if (t->stack->flags & needsDescent) { - /* Top stack item is dir to descend into. */ - t->current = t->stack; - tree_append(t, t->stack->name.s, - archive_strlen(&(t->stack->name))); - t->stack->flags &= ~needsDescent; - r = tree_descent(t); - if (r != 0) { - tree_pop(t); - t->visit_type = r; - } else - t->visit_type = TREE_POSTDESCENT; - return (t->visit_type); - } else if (t->stack->flags & needsOpen) { - t->stack->flags &= ~needsOpen; - r = tree_dir_next_windows(t, L"*"); - if (r == 0) - continue; - return (r); - } else if (t->stack->flags & needsAscent) { - /* Top stack item is dir and we're done with it. */ - r = tree_ascend(t); - tree_pop(t); - t->visit_type = r != 0 ? r : TREE_POSTASCENT; - return (t->visit_type); - } else { - /* Top item on stack is dead. */ - tree_pop(t); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - } - } - return (t->visit_type = 0); -} - -static int -tree_dir_next_windows(struct tree *t, const wchar_t *pattern) -{ - const wchar_t *name; - size_t namelen; - int r; - - for (;;) { - if (pattern != NULL) { - struct archive_wstring pt; - - archive_string_init(&pt); - archive_wstring_ensure(&pt, - archive_strlen(&(t->full_path)) - + 2 + wcslen(pattern)); - archive_wstring_copy(&pt, &(t->full_path)); - archive_wstrappend_wchar(&pt, L'\\'); - archive_wstrcat(&pt, pattern); - t->d = FindFirstFileW(pt.s, &t->_findData); - archive_wstring_free(&pt); - if (t->d == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - t->tree_errno = errno; - r = tree_ascend(t); /* Undo "chdir" */ - tree_pop(t); - t->visit_type = r != 0 ? r : TREE_ERROR_DIR; - return (t->visit_type); - } - t->findData = &t->_findData; - pattern = NULL; - } else if (!FindNextFileW(t->d, &t->_findData)) { - FindClose(t->d); - t->d = INVALID_HANDLE_VALUE; - t->findData = NULL; - return (0); - } - name = t->findData->cFileName; - namelen = wcslen(name); - t->flags &= ~hasLstat; - t->flags &= ~hasStat; - if (name[0] == L'.' && name[1] == L'\0') - continue; - if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0') - continue; - tree_append(t, name, namelen); - return (t->visit_type = TREE_REGULAR); - } -} - -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - /* milli seconds base */ - *t = (time_t)(utc.QuadPart / 10000000); - /* nano seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - *t = 0; - *ns = 0; - } -} - -static void -entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path, - const WIN32_FIND_DATAW *findData, - const BY_HANDLE_FILE_INFORMATION *bhfi) -{ - time_t secs; - long nsecs; - mode_t mode; - - fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); - archive_entry_set_atime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); - archive_entry_set_mtime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); - archive_entry_set_birthtime(entry, secs, nsecs); - archive_entry_set_ctime(entry, secs, nsecs); - archive_entry_set_dev(entry, bhfi_dev(bhfi)); - archive_entry_set_ino64(entry, bhfi_ino(bhfi)); - if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - archive_entry_set_nlink(entry, bhfi->nNumberOfLinks + 1); - else - archive_entry_set_nlink(entry, bhfi->nNumberOfLinks); - archive_entry_set_size(entry, - (((int64_t)bhfi->nFileSizeHigh) << 32) - + bhfi->nFileSizeLow); - archive_entry_set_uid(entry, 0); - archive_entry_set_gid(entry, 0); - archive_entry_set_rdev(entry, 0); - - mode = S_IRUSR | S_IRGRP | S_IROTH; - if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && - findData != NULL && - findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK) - mode |= S_IFLNK; - else if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; - else { - const wchar_t *p; - - mode |= S_IFREG; - p = wcsrchr(path, L'.'); - if (p != NULL && wcslen(p) == 4) { - switch (p[1]) { - case L'B': case L'b': - if ((p[2] == L'A' || p[2] == L'a' ) && - (p[3] == L'T' || p[3] == L't' )) - mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - case L'C': case L'c': - if (((p[2] == L'M' || p[2] == L'm' ) && - (p[3] == L'D' || p[3] == L'd' ))) - mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - case L'E': case L'e': - if ((p[2] == L'X' || p[2] == L'x' ) && - (p[3] == L'E' || p[3] == L'e' )) - mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - default: - break; - } - } - } - archive_entry_set_mode(entry, mode); -} - -static void -tree_archive_entry_copy_bhfi(struct archive_entry *entry, struct tree *t, - const BY_HANDLE_FILE_INFORMATION *bhfi) -{ - entry_copy_bhfi(entry, tree_current_path(t), t->findData, bhfi); -} - -static int -tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st, - int sim_lstat) -{ - HANDLE h; - int r; - DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; - - if (sim_lstat && tree_current_is_physical_link(t)) - flag |= FILE_FLAG_OPEN_REPARSE_POINT; - h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL, - OPEN_EXISTING, flag, NULL); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - t->tree_errno = errno; - return (0); - } - r = GetFileInformationByHandle(h, st); - CloseHandle(h); - return (r); -} - -/* - * Get the stat() data for the entry just returned from tree_next(). - */ -static const BY_HANDLE_FILE_INFORMATION * -tree_current_stat(struct tree *t) -{ - if (!(t->flags & hasStat)) { - if (!tree_current_file_information(t, &t->st, 0)) - return NULL; - t->flags |= hasStat; - } - return (&t->st); -} - -/* - * Get the lstat() data for the entry just returned from tree_next(). - */ -static const BY_HANDLE_FILE_INFORMATION * -tree_current_lstat(struct tree *t) -{ - if (!(t->flags & hasLstat)) { - if (!tree_current_file_information(t, &t->lst, 1)) - return NULL; - t->flags |= hasLstat; - } - return (&t->lst); -} - -/* - * Test whether current entry is a dir or link to a dir. - */ -static int -tree_current_is_dir(struct tree *t) -{ - if (t->findData) - return (t->findData->dwFileAttributes - & FILE_ATTRIBUTE_DIRECTORY); - return (0); -} - -/* - * Test whether current entry is a physical directory. Usually, we - * already have at least one of stat() or lstat() in memory, so we - * use tricks to try to avoid an extra trip to the disk. - */ -static int -tree_current_is_physical_dir(struct tree *t) -{ - if (tree_current_is_physical_link(t)) - return (0); - return (tree_current_is_dir(t)); -} - -/* - * Test whether current entry is a symbolic link. - */ -static int -tree_current_is_physical_link(struct tree *t) -{ - if (t->findData) - return ((t->findData->dwFileAttributes - & FILE_ATTRIBUTE_REPARSE_POINT) && - (t->findData->dwReserved0 - == IO_REPARSE_TAG_SYMLINK)); - return (0); -} - -/* - * Test whether the same file has been in the tree as its parent. - */ -static int -tree_target_is_same_as_parent(struct tree *t, - const BY_HANDLE_FILE_INFORMATION *st) -{ - struct tree_entry *te; - int64_t dev = bhfi_dev(st); - int64_t ino = bhfi_ino(st); - - for (te = t->current->parent; te != NULL; te = te->parent) { - if (te->dev == dev && te->ino == ino) - return (1); - } - return (0); -} - -/* - * Return the access path for the entry just returned from tree_next(). - */ -static const wchar_t * -tree_current_access_path(struct tree *t) -{ - return (t->full_path.s); -} - -/* - * Return the full path for the entry just returned from tree_next(). - */ -static const wchar_t * -tree_current_path(struct tree *t) -{ - return (t->path.s); -} - -/* - * Terminate the traversal. - */ -static void -tree_close(struct tree *t) -{ - - if (t == NULL) - return; - if (t->entry_fh != INVALID_HANDLE_VALUE) { - cancel_async(t); - close_and_restore_time(t->entry_fh, t, &t->restore_time); - t->entry_fh = INVALID_HANDLE_VALUE; - } - /* Close the handle of FindFirstFileW */ - if (t->d != INVALID_HANDLE_VALUE) { - FindClose(t->d); - t->d = INVALID_HANDLE_VALUE; - t->findData = NULL; - } - /* Release anything remaining in the stack. */ - while (t->stack != NULL) - tree_pop(t); -} - -/* - * Release any resources. - */ -static void -tree_free(struct tree *t) -{ - int i; - - if (t == NULL) - return; - archive_wstring_free(&t->path); - archive_wstring_free(&t->full_path); - free(t->sparse_list); - free(t->filesystem_table); - for (i = 0; i < MAX_OVERLAPPED; i++) { - if (t->ol[i].buff) - VirtualFree(t->ol[i].buff, 0, MEM_RELEASE); - CloseHandle(t->ol[i].ol.hEvent); - } - free(t); -} - - -/* - * Populate the archive_entry with metadata from the disk. - */ -int -archive_read_disk_entry_from_file(struct archive *_a, - struct archive_entry *entry, int fd, const struct stat *st) -{ - struct archive_read_disk *a = (struct archive_read_disk *)_a; - const wchar_t *path; - const wchar_t *wname; - const char *name; - HANDLE h; - BY_HANDLE_FILE_INFORMATION bhfi; - DWORD fileAttributes = 0; - int r; - - archive_clear_error(_a); - wname = archive_entry_sourcepath_w(entry); - if (wname == NULL) - wname = archive_entry_pathname_w(entry); - if (wname == NULL) { - archive_set_error(&a->archive, EINVAL, - "Can't get a wide character version of the path"); - return (ARCHIVE_FAILED); - } - path = __la_win_permissive_name_w(wname); - - if (st == NULL) { - /* - * Get metadata through GetFileInformationByHandle(). - */ - if (fd >= 0) { - h = (HANDLE)_get_osfhandle(fd); - r = GetFileInformationByHandle(h, &bhfi); - if (r == 0) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't GetFileInformationByHandle"); - return (ARCHIVE_FAILED); - } - entry_copy_bhfi(entry, path, NULL, &bhfi); - } else { - WIN32_FIND_DATAW findData; - DWORD flag, desiredAccess; - - h = FindFirstFileW(path, &findData); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't FindFirstFileW"); - return (ARCHIVE_FAILED); - } - FindClose(h); - - flag = FILE_FLAG_BACKUP_SEMANTICS; - if (!a->follow_symlinks && - (findData.dwFileAttributes - & FILE_ATTRIBUTE_REPARSE_POINT) && - (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { - flag |= FILE_FLAG_OPEN_REPARSE_POINT; - desiredAccess = 0; - } else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - desiredAccess = 0; - } else - desiredAccess = GENERIC_READ; - - h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL, - OPEN_EXISTING, flag, NULL); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't CreateFileW"); - return (ARCHIVE_FAILED); - } - r = GetFileInformationByHandle(h, &bhfi); - if (r == 0) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't GetFileInformationByHandle"); - CloseHandle(h); - return (ARCHIVE_FAILED); - } - entry_copy_bhfi(entry, path, &findData, &bhfi); - } - fileAttributes = bhfi.dwFileAttributes; - } else { - archive_entry_copy_stat(entry, st); - h = INVALID_HANDLE_VALUE; - } - - /* Lookup uname/gname */ - name = archive_read_disk_uname(_a, archive_entry_uid(entry)); - if (name != NULL) - archive_entry_copy_uname(entry, name); - name = archive_read_disk_gname(_a, archive_entry_gid(entry)); - if (name != NULL) - archive_entry_copy_gname(entry, name); - - /* - * Can this file be sparse file ? - */ - if (archive_entry_filetype(entry) != AE_IFREG - || archive_entry_size(entry) <= 0 - || archive_entry_hardlink(entry) != NULL) { - if (h != INVALID_HANDLE_VALUE && fd < 0) - CloseHandle(h); - return (ARCHIVE_OK); - } - - if (h == INVALID_HANDLE_VALUE) { - if (fd >= 0) { - h = (HANDLE)_get_osfhandle(fd); - } else { - h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't CreateFileW"); - return (ARCHIVE_FAILED); - } - } - r = GetFileInformationByHandle(h, &bhfi); - if (r == 0) { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "Can't GetFileInformationByHandle"); - if (h != INVALID_HANDLE_VALUE && fd < 0) - CloseHandle(h); - return (ARCHIVE_FAILED); - } - fileAttributes = bhfi.dwFileAttributes; - } - - /* Sparse file must be set a mark, FILE_ATTRIBUTE_SPARSE_FILE */ - if ((fileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { - if (fd < 0) - CloseHandle(h); - return (ARCHIVE_OK); - } - - r = setup_sparse_from_disk(a, entry, h); - if (fd < 0) - CloseHandle(h); - - return (r); -} - -/* - * Windows sparse interface. - */ -#if defined(__MINGW32__) && !defined(FSCTL_QUERY_ALLOCATED_RANGES) -#define FSCTL_QUERY_ALLOCATED_RANGES 0x940CF -typedef struct { - LARGE_INTEGER FileOffset; - LARGE_INTEGER Length; -} FILE_ALLOCATED_RANGE_BUFFER; -#endif - -static int -setup_sparse_from_disk(struct archive_read_disk *a, - struct archive_entry *entry, HANDLE handle) -{ - FILE_ALLOCATED_RANGE_BUFFER range, *outranges = NULL; - size_t outranges_size; - int64_t entry_size = archive_entry_size(entry); - int exit_sts = ARCHIVE_OK; - - range.FileOffset.QuadPart = 0; - range.Length.QuadPart = entry_size; - outranges_size = 2048; - outranges = (FILE_ALLOCATED_RANGE_BUFFER *)malloc(outranges_size); - if (outranges == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Couldn't allocate memory"); - exit_sts = ARCHIVE_FATAL; - goto exit_setup_sparse; - } - - for (;;) { - DWORD retbytes; - BOOL ret; - - for (;;) { - ret = DeviceIoControl(handle, - FSCTL_QUERY_ALLOCATED_RANGES, - &range, sizeof(range), outranges, - (DWORD)outranges_size, &retbytes, NULL); - if (ret == 0 && GetLastError() == ERROR_MORE_DATA) { - free(outranges); - outranges_size *= 2; - outranges = (FILE_ALLOCATED_RANGE_BUFFER *) - malloc(outranges_size); - if (outranges == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Couldn't allocate memory"); - exit_sts = ARCHIVE_FATAL; - goto exit_setup_sparse; - } - continue; - } else - break; - } - if (ret != 0) { - if (retbytes > 0) { - DWORD i, n; - - n = retbytes / sizeof(outranges[0]); - if (n == 1 && - outranges[0].FileOffset.QuadPart == 0 && - outranges[0].Length.QuadPart == entry_size) - break;/* This is not sparse. */ - for (i = 0; i < n; i++) - archive_entry_sparse_add_entry(entry, - outranges[i].FileOffset.QuadPart, - outranges[i].Length.QuadPart); - range.FileOffset.QuadPart = - outranges[n-1].FileOffset.QuadPart - + outranges[n-1].Length.QuadPart; - range.Length.QuadPart = - entry_size - range.FileOffset.QuadPart; - if (range.Length.QuadPart > 0) - continue; - } else { - /* The remaining data is hole. */ - archive_entry_sparse_add_entry(entry, - range.FileOffset.QuadPart, - range.Length.QuadPart); - } - break; - } else { - la_dosmaperr(GetLastError()); - archive_set_error(&a->archive, errno, - "DeviceIoControl Failed: %lu", GetLastError()); - exit_sts = ARCHIVE_FAILED; - goto exit_setup_sparse; - } - } -exit_setup_sparse: - free(outranges); - - return (exit_sts); -} - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_read_extract.c b/3rdparty/libarchive/libarchive/archive_read_extract.c deleted file mode 100644 index b7973fa8..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_extract.c +++ /dev/null @@ -1,60 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $"); - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_private.h" - -int -archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags) -{ - struct archive_read_extract *extract; - struct archive_read * a = (struct archive_read *)_a; - - extract = __archive_read_get_extract(a); - if (extract == NULL) - return (ARCHIVE_FATAL); - - /* If we haven't initialized the archive_write_disk object, do it now. */ - if (extract->ad == NULL) { - extract->ad = archive_write_disk_new(); - if (extract->ad == NULL) { - archive_set_error(&a->archive, ENOMEM, "Can't extract"); - return (ARCHIVE_FATAL); - } - archive_write_disk_set_standard_lookup(extract->ad); - } - - archive_write_disk_set_options(extract->ad, flags); - return (archive_read_extract2(&a->archive, entry, extract->ad)); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_open_fd.c b/3rdparty/libarchive/libarchive/archive_read_open_fd.c deleted file mode 100644 index f59cd07f..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_open_fd.c +++ /dev/null @@ -1,211 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_fd.c 201103 2009-12-28 03:13:49Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_IO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" - -struct read_fd_data { - int fd; - size_t block_size; - char use_lseek; - void *buffer; -}; - -static int file_close(struct archive *, void *); -static ssize_t file_read(struct archive *, void *, const void **buff); -static int64_t file_seek(struct archive *, void *, int64_t request, int); -static int64_t file_skip(struct archive *, void *, int64_t request); - -int -archive_read_open_fd(struct archive *a, int fd, size_t block_size) -{ - struct stat st; - struct read_fd_data *mine; - void *b; - - archive_clear_error(a); - if (fstat(fd, &st) != 0) { - archive_set_error(a, errno, "Can't stat fd %d", fd); - return (ARCHIVE_FATAL); - } - - mine = (struct read_fd_data *)calloc(1, sizeof(*mine)); - b = malloc(block_size); - if (mine == NULL || b == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - free(mine); - free(b); - return (ARCHIVE_FATAL); - } - mine->block_size = block_size; - mine->buffer = b; - mine->fd = fd; - /* - * Skip support is a performance optimization for anything - * that supports lseek(). On FreeBSD, only regular files and - * raw disk devices support lseek() and there's no portable - * way to determine if a device is a raw disk device, so we - * only enable this optimization for regular files. - */ - if (S_ISREG(st.st_mode)) { - archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); - mine->use_lseek = 1; - } -#if defined(__CYGWIN__) || defined(_WIN32) - setmode(mine->fd, O_BINARY); -#endif - - archive_read_set_read_callback(a, file_read); - archive_read_set_skip_callback(a, file_skip); - archive_read_set_seek_callback(a, file_seek); - archive_read_set_close_callback(a, file_close); - archive_read_set_callback_data(a, mine); - return (archive_read_open1(a)); -} - -static ssize_t -file_read(struct archive *a, void *client_data, const void **buff) -{ - struct read_fd_data *mine = (struct read_fd_data *)client_data; - ssize_t bytes_read; - - *buff = mine->buffer; - for (;;) { - bytes_read = read(mine->fd, mine->buffer, mine->block_size); - if (bytes_read < 0) { - if (errno == EINTR) - continue; - archive_set_error(a, errno, "Error reading fd %d", - mine->fd); - } - return (bytes_read); - } -} - -static int64_t -file_skip(struct archive *a, void *client_data, int64_t request) -{ - struct read_fd_data *mine = (struct read_fd_data *)client_data; - int64_t skip = request; - int64_t old_offset, new_offset; - int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ - - if (!mine->use_lseek) - return (0); - - /* Reduce a request that would overflow the 'skip' variable. */ - if (sizeof(request) > sizeof(skip)) { - int64_t max_skip = - (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; - if (request > max_skip) - skip = max_skip; - } - - /* Reduce request to the next smallest multiple of block_size */ - request = (request / mine->block_size) * mine->block_size; - if (request == 0) - return (0); - - if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && - ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)) - return (new_offset - old_offset); - - /* If seek failed once, it will probably fail again. */ - mine->use_lseek = 0; - - /* Let libarchive recover with read+discard. */ - if (errno == ESPIPE) - return (0); - - /* - * There's been an error other than ESPIPE. This is most - * likely caused by a programmer error (too large request) - * or a corrupted archive file. - */ - archive_set_error(a, errno, "Error seeking"); - return (-1); -} - -/* - * TODO: Store the offset and use it in the read callback. - */ -static int64_t -file_seek(struct archive *a, void *client_data, int64_t request, int whence) -{ - struct read_fd_data *mine = (struct read_fd_data *)client_data; - int64_t r; - - /* We use off_t here because lseek() is declared that way. */ - /* See above for notes about when off_t is less than 64 bits. */ - r = lseek(mine->fd, request, whence); - if (r >= 0) - return r; - - if (errno == ESPIPE) { - archive_set_error(a, errno, - "A file descriptor(%d) is not seekable(PIPE)", mine->fd); - return (ARCHIVE_FAILED); - } else { - /* If the input is corrupted or truncated, fail. */ - archive_set_error(a, errno, - "Error seeking in a file descriptor(%d)", mine->fd); - return (ARCHIVE_FATAL); - } -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct read_fd_data *mine = (struct read_fd_data *)client_data; - - (void)a; /* UNUSED */ - free(mine->buffer); - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_open_file.c b/3rdparty/libarchive/libarchive/archive_read_open_file.c deleted file mode 100644 index bfe933bf..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_open_file.c +++ /dev/null @@ -1,181 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_file.c 201093 2009-12-28 02:28:44Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_IO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" - -struct read_FILE_data { - FILE *f; - size_t block_size; - void *buffer; - char can_skip; -}; - -static int file_close(struct archive *, void *); -static ssize_t file_read(struct archive *, void *, const void **buff); -static int64_t file_skip(struct archive *, void *, int64_t request); - -int -archive_read_open_FILE(struct archive *a, FILE *f) -{ - struct stat st; - struct read_FILE_data *mine; - size_t block_size = 128 * 1024; - void *b; - - archive_clear_error(a); - mine = (struct read_FILE_data *)malloc(sizeof(*mine)); - b = malloc(block_size); - if (mine == NULL || b == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - free(mine); - free(b); - return (ARCHIVE_FATAL); - } - mine->block_size = block_size; - mine->buffer = b; - mine->f = f; - /* - * If we can't fstat() the file, it may just be that it's not - * a file. (On some platforms, FILE * objects can wrap I/O - * streams that don't support fileno()). As a result, fileno() - * should be used cautiously.) - */ - if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { - archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); - /* Enable the seek optimization only for regular files. */ - mine->can_skip = 1; - } else - mine->can_skip = 0; - -#if defined(__CYGWIN__) || defined(_WIN32) - setmode(fileno(mine->f), O_BINARY); -#endif - - archive_read_set_read_callback(a, file_read); - archive_read_set_skip_callback(a, file_skip); - archive_read_set_close_callback(a, file_close); - archive_read_set_callback_data(a, mine); - return (archive_read_open1(a)); -} - -static ssize_t -file_read(struct archive *a, void *client_data, const void **buff) -{ - struct read_FILE_data *mine = (struct read_FILE_data *)client_data; - size_t bytes_read; - - *buff = mine->buffer; - bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f); - if (bytes_read < mine->block_size && ferror(mine->f)) { - archive_set_error(a, errno, "Error reading file"); - } - return (bytes_read); -} - -static int64_t -file_skip(struct archive *a, void *client_data, int64_t request) -{ - struct read_FILE_data *mine = (struct read_FILE_data *)client_data; -#if HAVE_FSEEKO - off_t skip = (off_t)request; -#elif HAVE__FSEEKI64 - int64_t skip = request; -#else - long skip = (long)request; -#endif - int skip_bits = sizeof(skip) * 8 - 1; - - (void)a; /* UNUSED */ - - /* - * If we can't skip, return 0 as the amount we did step and - * the caller will work around by reading and discarding. - */ - if (!mine->can_skip) - return (0); - if (request == 0) - return (0); - - /* If request is too big for a long or an off_t, reduce it. */ - if (sizeof(request) > sizeof(skip)) { - int64_t max_skip = - (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; - if (request > max_skip) - skip = max_skip; - } - -#ifdef __ANDROID__ - /* fileno() isn't safe on all platforms ... see above. */ - if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0) -#elif HAVE_FSEEKO - if (fseeko(mine->f, skip, SEEK_CUR) != 0) -#elif HAVE__FSEEKI64 - if (_fseeki64(mine->f, skip, SEEK_CUR) != 0) -#else - if (fseek(mine->f, skip, SEEK_CUR) != 0) -#endif - { - mine->can_skip = 0; - return (0); - } - return (request); -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct read_FILE_data *mine = (struct read_FILE_data *)client_data; - - (void)a; /* UNUSED */ - if (mine->buffer != NULL) - free(mine->buffer); - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_open_filename.c b/3rdparty/libarchive/libarchive/archive_read_open_filename.c deleted file mode 100644 index 86635e21..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_open_filename.c +++ /dev/null @@ -1,582 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_filename.c 201093 2009-12-28 02:28:44Z kientzle $"); - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_IO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include -#elif defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -#elif defined(__DragonFly__) -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -struct read_file_data { - int fd; - size_t block_size; - void *buffer; - mode_t st_mode; /* Mode bits for opened file. */ - char use_lseek; - enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type; - union { - char m[1];/* MBS filename. */ - wchar_t w[1];/* WCS filename. */ - } filename; /* Must be last! */ -}; - -static int file_open(struct archive *, void *); -static int file_close(struct archive *, void *); -static int file_close2(struct archive *, void *); -static int file_switch(struct archive *, void *, void *); -static ssize_t file_read(struct archive *, void *, const void **buff); -static int64_t file_seek(struct archive *, void *, int64_t request, int); -static int64_t file_skip(struct archive *, void *, int64_t request); -static int64_t file_skip_lseek(struct archive *, void *, int64_t request); - -int -archive_read_open_file(struct archive *a, const char *filename, - size_t block_size) -{ - return (archive_read_open_filename(a, filename, block_size)); -} - -int -archive_read_open_filename(struct archive *a, const char *filename, - size_t block_size) -{ - const char *filenames[2]; - filenames[0] = filename; - filenames[1] = NULL; - return archive_read_open_filenames(a, filenames, block_size); -} - -int -archive_read_open_filenames(struct archive *a, const char **filenames, - size_t block_size) -{ - struct read_file_data *mine; - const char *filename = NULL; - if (filenames) - filename = *(filenames++); - - archive_clear_error(a); - do - { - if (filename == NULL) - filename = ""; - mine = (struct read_file_data *)calloc(1, - sizeof(*mine) + strlen(filename)); - if (mine == NULL) - goto no_memory; - strcpy(mine->filename.m, filename); - mine->block_size = block_size; - mine->fd = -1; - mine->buffer = NULL; - mine->st_mode = mine->use_lseek = 0; - if (filename == NULL || filename[0] == '\0') { - mine->filename_type = FNT_STDIN; - } else - mine->filename_type = FNT_MBS; - if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) - return (ARCHIVE_FATAL); - if (filenames == NULL) - break; - filename = *(filenames++); - } while (filename != NULL && filename[0] != '\0'); - archive_read_set_open_callback(a, file_open); - archive_read_set_read_callback(a, file_read); - archive_read_set_skip_callback(a, file_skip); - archive_read_set_close_callback(a, file_close); - archive_read_set_switch_callback(a, file_switch); - archive_read_set_seek_callback(a, file_seek); - - return (archive_read_open1(a)); -no_memory: - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); -} - -int -archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, - size_t block_size) -{ - struct read_file_data *mine = (struct read_file_data *)calloc(1, - sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t)); - if (!mine) - { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - mine->fd = -1; - mine->block_size = block_size; - - if (wfilename == NULL || wfilename[0] == L'\0') { - mine->filename_type = FNT_STDIN; - } else { -#if defined(_WIN32) && !defined(__CYGWIN__) - mine->filename_type = FNT_WCS; - wcscpy(mine->filename.w, wfilename); -#else - /* - * POSIX system does not support a wchar_t interface for - * open() system call, so we have to translate a wchar_t - * filename to multi-byte one and use it. - */ - struct archive_string fn; - - archive_string_init(&fn); - if (archive_string_append_from_wcs(&fn, wfilename, - wcslen(wfilename)) != 0) { - if (errno == ENOMEM) - archive_set_error(a, errno, - "Can't allocate memory"); - else - archive_set_error(a, EINVAL, - "Failed to convert a wide-character" - " filename to a multi-byte filename"); - archive_string_free(&fn); - free(mine); - return (ARCHIVE_FATAL); - } - mine->filename_type = FNT_MBS; - strcpy(mine->filename.m, fn.s); - archive_string_free(&fn); -#endif - } - if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) - return (ARCHIVE_FATAL); - archive_read_set_open_callback(a, file_open); - archive_read_set_read_callback(a, file_read); - archive_read_set_skip_callback(a, file_skip); - archive_read_set_close_callback(a, file_close); - archive_read_set_switch_callback(a, file_switch); - archive_read_set_seek_callback(a, file_seek); - - return (archive_read_open1(a)); -} - -static int -file_open(struct archive *a, void *client_data) -{ - struct stat st; - struct read_file_data *mine = (struct read_file_data *)client_data; - void *buffer; - const char *filename = NULL; - const wchar_t *wfilename = NULL; - int fd = -1; - int is_disk_like = 0; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */ -#elif defined(__NetBSD__) || defined(__OpenBSD__) - struct disklabel dl; -#elif defined(__DragonFly__) - struct partinfo pi; -#endif - - archive_clear_error(a); - if (mine->filename_type == FNT_STDIN) { - /* We used to delegate stdin support by - * directly calling archive_read_open_fd(a,0,block_size) - * here, but that doesn't (and shouldn't) handle the - * end-of-file flush when reading stdout from a pipe. - * Basically, read_open_fd() is intended for folks who - * are willing to handle such details themselves. This - * API is intended to be a little smarter for folks who - * want easy handling of the common case. - */ - fd = 0; -#if defined(__CYGWIN__) || defined(_WIN32) - setmode(0, O_BINARY); -#endif - filename = ""; - } else if (mine->filename_type == FNT_MBS) { - filename = mine->filename.m; - fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - if (fd < 0) { - archive_set_error(a, errno, - "Failed to open '%s'", filename); - return (ARCHIVE_FATAL); - } - } else { -#if defined(_WIN32) && !defined(__CYGWIN__) - wfilename = mine->filename.w; - fd = _wopen(wfilename, O_RDONLY | O_BINARY); - if (fd < 0 && errno == ENOENT) { - wchar_t *fullpath; - fullpath = __la_win_permissive_name_w(wfilename); - if (fullpath != NULL) { - fd = _wopen(fullpath, O_RDONLY | O_BINARY); - free(fullpath); - } - } - if (fd < 0) { - archive_set_error(a, errno, - "Failed to open '%S'", wfilename); - return (ARCHIVE_FATAL); - } -#else - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unexpedted operation in archive_read_open_filename"); - goto fail; -#endif - } - if (fstat(fd, &st) != 0) { - if (mine->filename_type == FNT_WCS) - archive_set_error(a, errno, "Can't stat '%S'", - wfilename); - else - archive_set_error(a, errno, "Can't stat '%s'", - filename); - goto fail; - } - - /* - * Determine whether the input looks like a disk device or a - * tape device. The results are used below to select an I/O - * strategy: - * = "disk-like" devices support arbitrary lseek() and will - * support I/O requests of any size. So we get easy skipping - * and can cheat on block sizes to get better performance. - * = "tape-like" devices require strict blocking and use - * specialized ioctls for seeking. - * = "socket-like" devices cannot seek at all but can improve - * performance by using nonblocking I/O to read "whatever is - * available right now". - * - * Right now, we only specially recognize disk-like devices, - * but it should be straightforward to add probes and strategy - * here for tape-like and socket-like devices. - */ - if (S_ISREG(st.st_mode)) { - /* Safety: Tell the extractor not to overwrite the input. */ - archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); - /* Regular files act like disks. */ - is_disk_like = 1; - } -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - /* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */ - else if (S_ISCHR(st.st_mode) && - ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 && - mediasize > 0) { - is_disk_like = 1; - } -#elif defined(__NetBSD__) || defined(__OpenBSD__) - /* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */ - else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) && - ioctl(fd, DIOCGDINFO, &dl) == 0 && - dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) { - is_disk_like = 1; - } -#elif defined(__DragonFly__) - /* DragonFly BSD: if it supports DIOCGPART ioctl, it's disk-like. */ - else if (S_ISCHR(st.st_mode) && - ioctl(fd, DIOCGPART, &pi) == 0 && - pi.media_size > 0) { - is_disk_like = 1; - } -#elif defined(__linux__) - /* Linux: All block devices are disk-like. */ - else if (S_ISBLK(st.st_mode) && - lseek(fd, 0, SEEK_CUR) == 0 && - lseek(fd, 0, SEEK_SET) == 0 && - lseek(fd, 0, SEEK_END) > 0 && - lseek(fd, 0, SEEK_SET) == 0) { - is_disk_like = 1; - } -#endif - /* TODO: Add an "is_tape_like" variable and appropriate tests. */ - - /* Disk-like devices prefer power-of-two block sizes. */ - /* Use provided block_size as a guide so users have some control. */ - if (is_disk_like) { - size_t new_block_size = 64 * 1024; - while (new_block_size < mine->block_size - && new_block_size < 64 * 1024 * 1024) - new_block_size *= 2; - mine->block_size = new_block_size; - } - buffer = malloc(mine->block_size); - if (buffer == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - goto fail; - } - mine->buffer = buffer; - mine->fd = fd; - /* Remember mode so close can decide whether to flush. */ - mine->st_mode = st.st_mode; - - /* Disk-like inputs can use lseek(). */ - if (is_disk_like) - mine->use_lseek = 1; - - return (ARCHIVE_OK); -fail: - /* - * Don't close file descriptors not opened or ones pointing referring - * to `FNT_STDIN`. - */ - if (fd != -1 && fd != 0) - close(fd); - return (ARCHIVE_FATAL); -} - -static ssize_t -file_read(struct archive *a, void *client_data, const void **buff) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; - ssize_t bytes_read; - - /* TODO: If a recent lseek() operation has left us - * mis-aligned, read and return a short block to try to get - * us back in alignment. */ - - /* TODO: Someday, try mmap() here; if that succeeds, give - * the entire file to libarchive as a single block. That - * could be a lot faster than block-by-block manual I/O. */ - - /* TODO: We might be able to improve performance on pipes and - * sockets by setting non-blocking I/O and just accepting - * whatever we get here instead of waiting for a full block - * worth of data. */ - - *buff = mine->buffer; - for (;;) { - bytes_read = read(mine->fd, mine->buffer, mine->block_size); - if (bytes_read < 0) { - if (errno == EINTR) - continue; - else if (mine->filename_type == FNT_STDIN) - archive_set_error(a, errno, - "Error reading stdin"); - else if (mine->filename_type == FNT_MBS) - archive_set_error(a, errno, - "Error reading '%s'", mine->filename.m); - else - archive_set_error(a, errno, - "Error reading '%S'", mine->filename.w); - } - return (bytes_read); - } -} - -/* - * Regular files and disk-like block devices can use simple lseek - * without needing to round the request to the block size. - * - * TODO: This can leave future reads mis-aligned. Since we know the - * offset here, we should store it and use it in file_read() above - * to determine whether we should perform a short read to get back - * into alignment. Long series of mis-aligned reads can negatively - * impact disk throughput. (Of course, the performance impact should - * be carefully tested; extra code complexity is only worthwhile if - * it does provide measurable improvement.) - * - * TODO: Be lazy about the actual seek. There are a few pathological - * cases where libarchive makes a bunch of seek requests in a row - * without any intervening reads. This isn't a huge performance - * problem, since the kernel handles seeks lazily already, but - * it would be very slightly faster if we simply remembered the - * seek request here and then actually performed the seek at the - * top of the read callback above. - */ -static int64_t -file_skip_lseek(struct archive *a, void *client_data, int64_t request) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; -#if defined(_WIN32) && !defined(__CYGWIN__) - /* We use _lseeki64() on Windows. */ - int64_t old_offset, new_offset; -#else - off_t old_offset, new_offset; -#endif - - /* We use off_t here because lseek() is declared that way. */ - - /* TODO: Deal with case where off_t isn't 64 bits. - * This shouldn't be a problem on Linux or other POSIX - * systems, since the configuration logic for libarchive - * tries to obtain a 64-bit off_t. - */ - if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && - (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0) - return (new_offset - old_offset); - - /* If lseek() fails, don't bother trying again. */ - mine->use_lseek = 0; - - /* Let libarchive recover with read+discard */ - if (errno == ESPIPE) - return (0); - - /* If the input is corrupted or truncated, fail. */ - if (mine->filename_type == FNT_STDIN) - archive_set_error(a, errno, "Error seeking in stdin"); - else if (mine->filename_type == FNT_MBS) - archive_set_error(a, errno, "Error seeking in '%s'", - mine->filename.m); - else - archive_set_error(a, errno, "Error seeking in '%S'", - mine->filename.w); - return (-1); -} - - -/* - * TODO: Implement another file_skip_XXXX that uses MTIO ioctls to - * accelerate operation on tape drives. - */ - -static int64_t -file_skip(struct archive *a, void *client_data, int64_t request) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; - - /* Delegate skip requests. */ - if (mine->use_lseek) - return (file_skip_lseek(a, client_data, request)); - - /* If we can't skip, return 0; libarchive will read+discard instead. */ - return (0); -} - -/* - * TODO: Store the offset and use it in the read callback. - */ -static int64_t -file_seek(struct archive *a, void *client_data, int64_t request, int whence) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; - int64_t r; - - /* We use off_t here because lseek() is declared that way. */ - /* See above for notes about when off_t is less than 64 bits. */ - r = lseek(mine->fd, request, whence); - if (r >= 0) - return r; - - /* If the input is corrupted or truncated, fail. */ - if (mine->filename_type == FNT_STDIN) - archive_set_error(a, errno, "Error seeking in stdin"); - else if (mine->filename_type == FNT_MBS) - archive_set_error(a, errno, "Error seeking in '%s'", - mine->filename.m); - else - archive_set_error(a, errno, "Error seeking in '%S'", - mine->filename.w); - return (ARCHIVE_FATAL); -} - -static int -file_close2(struct archive *a, void *client_data) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; - - (void)a; /* UNUSED */ - - /* Only flush and close if open succeeded. */ - if (mine->fd >= 0) { - /* - * Sometimes, we should flush the input before closing. - * Regular files: faster to just close without flush. - * Disk-like devices: Ditto. - * Tapes: must not flush (user might need to - * read the "next" item on a non-rewind device). - * Pipes and sockets: must flush (otherwise, the - * program feeding the pipe or socket may complain). - * Here, I flush everything except for regular files and - * device nodes. - */ - if (!S_ISREG(mine->st_mode) - && !S_ISCHR(mine->st_mode) - && !S_ISBLK(mine->st_mode)) { - ssize_t bytesRead; - do { - bytesRead = read(mine->fd, mine->buffer, - mine->block_size); - } while (bytesRead > 0); - } - /* If a named file was opened, then it needs to be closed. */ - if (mine->filename_type != FNT_STDIN) - close(mine->fd); - } - free(mine->buffer); - mine->buffer = NULL; - mine->fd = -1; - return (ARCHIVE_OK); -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct read_file_data *mine = (struct read_file_data *)client_data; - file_close2(a, client_data); - free(mine); - return (ARCHIVE_OK); -} - -static int -file_switch(struct archive *a, void *client_data1, void *client_data2) -{ - file_close2(a, client_data1); - return file_open(a, client_data2); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_open_memory.c b/3rdparty/libarchive/libarchive/archive_read_open_memory.c deleted file mode 100644 index 311be470..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_open_memory.c +++ /dev/null @@ -1,186 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/06 15:51:59 kientzle Exp $"); - -#include -#include -#include - -#include "archive.h" - -/* - * Glue to read an archive from a block of memory. - * - * This is mostly a huge help in building test harnesses; - * test programs can build archives in memory and read them - * back again without having to mess with files on disk. - */ - -struct read_memory_data { - const unsigned char *start; - const unsigned char *p; - const unsigned char *end; - ssize_t read_size; -}; - -static int memory_read_close(struct archive *, void *); -static int memory_read_open(struct archive *, void *); -static int64_t memory_read_seek(struct archive *, void *, int64_t offset, int whence); -static int64_t memory_read_skip(struct archive *, void *, int64_t request); -static ssize_t memory_read(struct archive *, void *, const void **buff); - -int -archive_read_open_memory(struct archive *a, const void *buff, size_t size) -{ - return archive_read_open_memory2(a, buff, size, size); -} - -/* - * Don't use _open_memory2() in production code; the archive_read_open_memory() - * version is the one you really want. This is just here so that - * test harnesses can exercise block operations inside the library. - */ -int -archive_read_open_memory2(struct archive *a, const void *buff, - size_t size, size_t read_size) -{ - struct read_memory_data *mine; - - mine = (struct read_memory_data *)calloc(1, sizeof(*mine)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - mine->start = mine->p = (const unsigned char *)buff; - mine->end = mine->start + size; - mine->read_size = read_size; - archive_read_set_open_callback(a, memory_read_open); - archive_read_set_read_callback(a, memory_read); - 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); - return (archive_read_open1(a)); -} - -/* - * There's nothing to open. - */ -static int -memory_read_open(struct archive *a, void *client_data) -{ - (void)a; /* UNUSED */ - (void)client_data; /* UNUSED */ - return (ARCHIVE_OK); -} - -/* - * This is scary simple: Just advance a pointer. Limiting - * to read_size is not technically necessary, but it exercises - * more of the internal logic when used with a small block size - * in a test harness. Production use should not specify a block - * size; then this is much faster. - */ -static ssize_t -memory_read(struct archive *a, void *client_data, const void **buff) -{ - struct read_memory_data *mine = (struct read_memory_data *)client_data; - ssize_t size; - - (void)a; /* UNUSED */ - *buff = mine->p; - size = mine->end - mine->p; - if (size > mine->read_size) - size = mine->read_size; - mine->p += size; - return (size); -} - -/* - * Advancing is just as simple. Again, this is doing more than - * necessary in order to better exercise internal code when used - * as a test harness. - */ -static int64_t -memory_read_skip(struct archive *a, void *client_data, int64_t skip) -{ - struct read_memory_data *mine = (struct read_memory_data *)client_data; - - (void)a; /* UNUSED */ - if ((int64_t)skip > (int64_t)(mine->end - mine->p)) - skip = mine->end - mine->p; - /* Round down to block size. */ - skip /= mine->read_size; - skip *= mine->read_size; - mine->p += skip; - return (skip); -} - -/* - * Seeking. - */ -static int64_t -memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence) -{ - struct read_memory_data *mine = (struct read_memory_data *)client_data; - - (void)a; /* UNUSED */ - switch (whence) { - case SEEK_SET: - mine->p = mine->start + offset; - break; - case SEEK_CUR: - mine->p += offset; - break; - case SEEK_END: - mine->p = mine->end + offset; - break; - default: - return ARCHIVE_FATAL; - } - if (mine->p < mine->start) { - mine->p = mine->start; - return ARCHIVE_FAILED; - } - if (mine->p > mine->end) { - mine->p = mine->end; - return ARCHIVE_FAILED; - } - return (mine->p - mine->start); -} - -/* - * Close is just cleaning up our one small bit of data. - */ -static int -memory_read_close(struct archive *a, void *client_data) -{ - struct read_memory_data *mine = (struct read_memory_data *)client_data; - (void)a; /* UNUSED */ - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_private.h b/3rdparty/libarchive/libarchive/archive_read_private.h deleted file mode 100644 index 78546dca..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_private.h +++ /dev/null @@ -1,263 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_read_private.h 201088 2009-12-28 02:18:55Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#ifndef __LIBARCHIVE_TEST -#error This header is only to be used internally to libarchive. -#endif -#endif - -#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED -#define ARCHIVE_READ_PRIVATE_H_INCLUDED - -#include "archive.h" -#include "archive_string.h" -#include "archive_private.h" - -struct archive_read; -struct archive_read_filter_bidder; -struct archive_read_filter; - -/* - * How bidding works for filters: - * * The bid manager initializes the client-provided reader as the - * first filter. - * * It invokes the bidder for each registered filter with the - * current head filter. - * * The bidders can use archive_read_filter_ahead() to peek ahead - * at the incoming data to compose their bids. - * * The bid manager creates a new filter structure for the winning - * bidder and gives the winning bidder a chance to initialize it. - * * The new filter becomes the new top filter and we repeat the - * process. - * This ends only when no bidder provides a non-zero bid. Then - * we perform a similar dance with the registered format handlers. - */ -struct archive_read_filter_bidder { - /* Configuration data for the bidder. */ - void *data; - /* Name of the filter */ - const char *name; - /* Taste the upstream filter to see if we handle this. */ - int (*bid)(struct archive_read_filter_bidder *, - struct archive_read_filter *); - /* Initialize a newly-created filter. */ - int (*init)(struct archive_read_filter *); - /* Set an option for the filter bidder. */ - int (*options)(struct archive_read_filter_bidder *, - const char *key, const char *value); - /* Release the bidder's configuration data. */ - int (*free)(struct archive_read_filter_bidder *); -}; - -/* - * This structure is allocated within the archive_read core - * and initialized by archive_read and the init() method of the - * corresponding bidder above. - */ -struct archive_read_filter { - int64_t position; - /* Essentially all filters will need these values, so - * just declare them here. */ - struct archive_read_filter_bidder *bidder; /* My bidder. */ - struct archive_read_filter *upstream; /* Who I read from. */ - struct archive_read *archive; /* Associated archive. */ - /* Open a block for reading */ - int (*open)(struct archive_read_filter *self); - /* Return next block. */ - ssize_t (*read)(struct archive_read_filter *, const void **); - /* Skip forward this many bytes. */ - int64_t (*skip)(struct archive_read_filter *self, int64_t request); - /* Seek to an absolute location. */ - int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence); - /* Close (just this filter) and free(self). */ - int (*close)(struct archive_read_filter *self); - /* Function that handles switching from reading one block to the next/prev */ - int (*sswitch)(struct archive_read_filter *self, unsigned int iindex); - /* My private data. */ - void *data; - - const char *name; - int code; - - /* Used by reblocking logic. */ - char *buffer; - size_t buffer_size; - char *next; /* Current read location. */ - size_t avail; /* Bytes in my buffer. */ - const void *client_buff; /* Client buffer information. */ - size_t client_total; - const char *client_next; - size_t client_avail; - char end_of_file; - char closed; - char fatal; -}; - -/* - * The client looks a lot like a filter, so we just wrap it here. - * - * TODO: Make archive_read_filter and archive_read_client identical so - * that users of the library can easily register their own - * transformation filters. This will probably break the API/ABI and - * so should be deferred at least until libarchive 3.0. - */ -struct archive_read_data_node { - int64_t begin_position; - int64_t total_size; - void *data; -}; -struct archive_read_client { - archive_open_callback *opener; - archive_read_callback *reader; - archive_skip_callback *skipper; - archive_seek_callback *seeker; - archive_close_callback *closer; - archive_switch_callback *switcher; - unsigned int nodes; - unsigned int cursor; - int64_t position; - struct archive_read_data_node *dataset; -}; -struct archive_read_passphrase { - char *passphrase; - struct archive_read_passphrase *next; -}; - -struct archive_read_extract { - struct archive *ad; /* archive_write_disk object */ - - /* Progress function invoked during extract. */ - void (*extract_progress)(void *); - void *extract_progress_user_data; -}; - -struct archive_read { - struct archive archive; - - struct archive_entry *entry; - - /* Dev/ino of the archive being read/written. */ - int skip_file_set; - int64_t skip_file_dev; - int64_t skip_file_ino; - - /* Callbacks to open/read/write/close client archive streams. */ - struct archive_read_client client; - - /* Registered filter bidders. */ - struct archive_read_filter_bidder bidders[16]; - - /* Last filter in chain */ - struct archive_read_filter *filter; - - /* Whether to bypass filter bidding process */ - int bypass_filter_bidding; - - /* File offset of beginning of most recently-read header. */ - int64_t header_position; - - /* Nodes and offsets of compressed data block */ - unsigned int data_start_node; - unsigned int data_end_node; - - /* - * Format detection is mostly the same as compression - * detection, with one significant difference: The bidders - * use the read_ahead calls above to examine the stream rather - * than having the supervisor hand them a block of data to - * examine. - */ - - struct archive_format_descriptor { - void *data; - const char *name; - int (*bid)(struct archive_read *, int best_bid); - int (*options)(struct archive_read *, const char *key, - const char *value); - int (*read_header)(struct archive_read *, struct archive_entry *); - int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *); - int (*read_data_skip)(struct archive_read *); - int64_t (*seek_data)(struct archive_read *, int64_t, int); - int (*cleanup)(struct archive_read *); - int (*format_capabilties)(struct archive_read *); - int (*has_encrypted_entries)(struct archive_read *); - } formats[16]; - struct archive_format_descriptor *format; /* Active format. */ - - /* - * Various information needed by archive_extract. - */ - struct archive_read_extract *extract; - int (*cleanup_archive_extract)(struct archive_read *); - - /* - * Decryption passphrase. - */ - struct { - struct archive_read_passphrase *first; - struct archive_read_passphrase **last; - int candidate; - archive_passphrase_callback *callback; - void *client_data; - } passphrases; -}; - -int __archive_read_register_format(struct archive_read *a, - void *format_data, - const char *name, - int (*bid)(struct archive_read *, int), - int (*options)(struct archive_read *, const char *, const char *), - int (*read_header)(struct archive_read *, struct archive_entry *), - int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), - int (*read_data_skip)(struct archive_read *), - int64_t (*seek_data)(struct archive_read *, int64_t, int), - int (*cleanup)(struct archive_read *), - int (*format_capabilities)(struct archive_read *), - int (*has_encrypted_entries)(struct archive_read *)); - -int __archive_read_get_bidder(struct archive_read *a, - struct archive_read_filter_bidder **bidder); - -const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *); -const void *__archive_read_filter_ahead(struct archive_read_filter *, - size_t, ssize_t *); -int64_t __archive_read_seek(struct archive_read*, int64_t, int); -int64_t __archive_read_filter_seek(struct archive_read_filter *, int64_t, int); -int64_t __archive_read_consume(struct archive_read *, int64_t); -int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t); -int __archive_read_program(struct archive_read_filter *, const char *); -void __archive_read_free_filters(struct archive_read *); -struct archive_read_extract *__archive_read_get_extract(struct archive_read *); - - -/* - * Get a decryption passphrase. - */ -void __archive_read_reset_passphrase(struct archive_read *a); -const char * __archive_read_next_passphrase(struct archive_read *a); -#endif diff --git a/3rdparty/libarchive/libarchive/archive_read_set_format.c b/3rdparty/libarchive/libarchive/archive_read_set_format.c deleted file mode 100644 index 190f4369..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_set_format.c +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * Copyright (c) 2003-2012 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" - -int -archive_read_set_format(struct archive *_a, int code) -{ - int r1, r2, slots, i; - char str[10]; - struct archive_read *a = (struct archive_read *)_a; - - if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK)) - return r1; - - r1 = r2 = (ARCHIVE_OK); - if (a->format) - r2 = (ARCHIVE_WARN); - switch (code & ARCHIVE_FORMAT_BASE_MASK) - { - case ARCHIVE_FORMAT_7ZIP: - strcpy(str, "7zip"); - break; - case ARCHIVE_FORMAT_AR: - strcpy(str, "ar"); - break; - case ARCHIVE_FORMAT_CAB: - strcpy(str, "cab"); - break; - case ARCHIVE_FORMAT_CPIO: - strcpy(str, "cpio"); - break; - case ARCHIVE_FORMAT_ISO9660: - strcpy(str, "iso9660"); - break; - case ARCHIVE_FORMAT_LHA: - strcpy(str, "lha"); - break; - case ARCHIVE_FORMAT_MTREE: - strcpy(str, "mtree"); - break; - case ARCHIVE_FORMAT_RAR: - strcpy(str, "rar"); - break; - case ARCHIVE_FORMAT_TAR: - strcpy(str, "tar"); - break; - case ARCHIVE_FORMAT_XAR: - strcpy(str, "xar"); - break; - case ARCHIVE_FORMAT_ZIP: - strcpy(str, "zip"); - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Invalid format code specified"); - return (ARCHIVE_FATAL); - } - - slots = sizeof(a->formats) / sizeof(a->formats[0]); - a->format = &(a->formats[0]); - for (i = 0; i < slots; i++, a->format++) { - if (!a->format->name || !strcmp(a->format->name, str)) - break; - } - if (!a->format->name || strcmp(a->format->name, str)) - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: Unable to set format"); - r1 = (ARCHIVE_FATAL); - } - - return (r1 < r2) ? r1 : r2; -} diff --git a/3rdparty/libarchive/libarchive/archive_read_set_options.c b/3rdparty/libarchive/libarchive/archive_read_set_options.c deleted file mode 100644 index 2e2eea69..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_set_options.c +++ /dev/null @@ -1,155 +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 "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive_read_private.h" -#include "archive_options_private.h" - -static int archive_set_format_option(struct archive *a, - const char *m, const char *o, const char *v); -static int archive_set_filter_option(struct archive *a, - const char *m, const char *o, const char *v); -static int archive_set_option(struct archive *a, - const char *m, const char *o, const char *v); - -int -archive_read_set_format_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_READ_MAGIC, "archive_read_set_format_option", - archive_set_format_option); -} - -int -archive_read_set_filter_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_READ_MAGIC, "archive_read_set_filter_option", - archive_set_filter_option); -} - -int -archive_read_set_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_READ_MAGIC, "archive_read_set_option", - archive_set_option); -} - -int -archive_read_set_options(struct archive *a, const char *options) -{ - return _archive_set_options(a, options, - ARCHIVE_READ_MAGIC, "archive_read_set_options", - archive_set_option); -} - -static int -archive_set_format_option(struct archive *_a, const char *m, const char *o, - const char *v) -{ - struct archive_read *a = (struct archive_read *)_a; - size_t i; - int r, rv = ARCHIVE_WARN, matched_modules = 0; - - for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) { - struct archive_format_descriptor *format = &a->formats[i]; - - if (format->options == NULL || format->name == NULL) - /* This format does not support option. */ - continue; - if (m != NULL) { - if (strcmp(format->name, m) != 0) - continue; - ++matched_modules; - } - - a->format = format; - r = format->options(a, o, v); - a->format = NULL; - - if (r == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - if (r == ARCHIVE_OK) - rv = ARCHIVE_OK; - } - /* If the format name didn't match, return a special code for - * _archive_set_option[s]. */ - if (m != NULL && matched_modules == 0) - return ARCHIVE_WARN - 1; - return (rv); -} - -static int -archive_set_filter_option(struct archive *_a, const char *m, const char *o, - const char *v) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *filter; - struct archive_read_filter_bidder *bidder; - int r, rv = ARCHIVE_WARN, matched_modules = 0; - - for (filter = a->filter; filter != NULL; filter = filter->upstream) { - bidder = filter->bidder; - if (bidder == NULL) - continue; - if (bidder->options == NULL) - /* This bidder does not support option */ - continue; - if (m != NULL) { - if (strcmp(filter->name, m) != 0) - continue; - ++matched_modules; - } - - r = bidder->options(bidder, o, v); - - if (r == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - if (r == ARCHIVE_OK) - rv = ARCHIVE_OK; - } - /* If the filter name didn't match, return a special code for - * _archive_set_option[s]. */ - if (m != NULL && matched_modules == 0) - return ARCHIVE_WARN - 1; - return (rv); -} - -static int -archive_set_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_either_option(a, m, o, v, - archive_set_format_option, - archive_set_filter_option); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c deleted file mode 100644 index 3885a7cf..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c +++ /dev/null @@ -1,371 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_BZLIB_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) -struct private_data { - bz_stream stream; - char *out_block; - size_t out_block_size; - char valid; /* True = decompressor is initialized */ - char eof; /* True = found end of compressed data. */ -}; - -/* Bzip2 filter */ -static ssize_t bzip2_filter_read(struct archive_read_filter *, const void **); -static int bzip2_filter_close(struct archive_read_filter *); -#endif - -/* - * 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. - */ -static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); -static int bzip2_reader_init(struct archive_read_filter *); -static int bzip2_reader_free(struct archive_read_filter_bidder *); - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Deprecated; remove in libarchive 4.0 */ -int -archive_read_support_compression_bzip2(struct archive *a) -{ - return archive_read_support_filter_bzip2(a); -} -#endif - -int -archive_read_support_filter_bzip2(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2"); - - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - reader->data = NULL; - reader->name = "bzip2"; - reader->bid = bzip2_reader_bid; - reader->init = bzip2_reader_init; - reader->options = NULL; - reader->free = bzip2_reader_free; -#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) - return (ARCHIVE_OK); -#else - archive_set_error(_a, ARCHIVE_ERRNO_MISC, - "Using external bzip2 program"); - return (ARCHIVE_WARN); -#endif -} - -static int -bzip2_reader_free(struct archive_read_filter_bidder *self){ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} - -/* - * Test whether we can handle this data. - * - * This logic returns zero if any part of the signature fails. It - * also tries to Do The Right Thing if a very short buffer prevents us - * from verifying as much as we would like. - */ -static int -bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter) -{ - const unsigned char *buffer; - ssize_t avail; - int bits_checked; - - (void)self; /* UNUSED */ - - /* Minimal bzip2 archive is 14 bytes. */ - buffer = __archive_read_filter_ahead(filter, 14, &avail); - if (buffer == NULL) - return (0); - - /* First three bytes must be "BZh" */ - bits_checked = 0; - if (memcmp(buffer, "BZh", 3) != 0) - return (0); - bits_checked += 24; - - /* Next follows a compression flag which must be an ASCII digit. */ - if (buffer[3] < '1' || buffer[3] > '9') - return (0); - bits_checked += 5; - - /* After BZh[1-9], there must be either a data block - * which begins with 0x314159265359 or an end-of-data - * marker of 0x177245385090. */ - if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0) - bits_checked += 48; - else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0) - bits_checked += 48; - else - return (0); - - return (bits_checked); -} - -#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. - */ -static int -bzip2_reader_init(struct archive_read_filter *self) -{ - int r; - - r = __archive_read_program(self, "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"; - return (r); -} - - -#else - -/* - * Setup the callbacks. - */ -static int -bzip2_reader_init(struct archive_read_filter *self) -{ - static const size_t out_block_size = 64 * 1024; - void *out_block; - struct private_data *state; - - self->code = ARCHIVE_FILTER_BZIP2; - self->name = "bzip2"; - - state = (struct private_data *)calloc(sizeof(*state), 1); - out_block = (unsigned char *)malloc(out_block_size); - if (state == NULL || out_block == NULL) { - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate data for bzip2 decompression"); - free(out_block); - free(state); - return (ARCHIVE_FATAL); - } - - self->data = state; - state->out_block_size = out_block_size; - state->out_block = out_block; - self->read = bzip2_filter_read; - self->skip = NULL; /* not supported */ - self->close = bzip2_filter_close; - - return (ARCHIVE_OK); -} - -/* - * Return the next block of decompressed data. - */ -static ssize_t -bzip2_filter_read(struct archive_read_filter *self, const void **p) -{ - struct private_data *state; - size_t decompressed; - const char *read_buf; - ssize_t ret; - - state = (struct private_data *)self->data; - - if (state->eof) { - *p = NULL; - return (0); - } - - /* Empty our output buffer. */ - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Try to fill the output buffer. */ - 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; - return (decompressed); - } - /* Initialize compression library. */ - ret = BZ2_bzDecompressInit(&(state->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), - 0 /* library verbosity */, - 1 /* do use low-mem algo */); - - if (ret != BZ_OK) { - const char *detail = NULL; - int err = ARCHIVE_ERRNO_MISC; - switch (ret) { - case BZ_PARAM_ERROR: - detail = "invalid setup parameter"; - break; - case BZ_MEM_ERROR: - err = ENOMEM; - detail = "out of memory"; - break; - case BZ_CONFIG_ERROR: - detail = "mis-compiled library"; - break; - } - archive_set_error(&self->archive->archive, err, - "Internal error initializing decompressor%s%s", - detail == NULL ? "" : ": ", - detail); - return (ARCHIVE_FATAL); - } - state->valid = 1; - } - - /* stream.next_in is really const, but bzlib - * doesn't declare it so. */ - read_buf = - __archive_read_filter_ahead(self->upstream, 1, &ret); - if (read_buf == NULL) { - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "truncated bzip2 input"); - return (ARCHIVE_FATAL); - } - state->stream.next_in = (char *)(uintptr_t)read_buf; - state->stream.avail_in = 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); - } - - /* 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); - - switch (ret) { - case BZ_STREAM_END: /* Found end of stream. */ - switch (BZ2_bzDecompressEnd(&(state->stream))) { - case BZ_OK: - break; - default: - archive_set_error(&(self->archive->archive), - ARCHIVE_ERRNO_MISC, - "Failed to clean up decompressor"); - return (ARCHIVE_FATAL); - } - state->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; - return (decompressed); - } - break; - default: /* Return an error. */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, "bzip decompression failed"); - return (ARCHIVE_FATAL); - } - } -} - -/* - * Clean up the decompressor. - */ -static int -bzip2_filter_close(struct archive_read_filter *self) -{ - struct private_data *state; - int ret = ARCHIVE_OK; - - state = (struct private_data *)self->data; - - if (state->valid) { - switch (BZ2_bzDecompressEnd(&state->stream)) { - case BZ_OK: - break; - default: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Failed to clean up decompressor"); - ret = ARCHIVE_FATAL; - } - state->valid = 0; - } - - free(state->out_block); - free(state); - return (ret); -} - -#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */ diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c deleted file mode 100644 index fa8c675d..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c +++ /dev/null @@ -1,477 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_ZLIB_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#ifdef HAVE_ZLIB_H -struct private_data { - z_stream stream; - char in_stream; - unsigned char *out_block; - size_t out_block_size; - int64_t total_out; - unsigned long crc; - char eof; /* True = found end of compressed data. */ -}; - -/* Gzip Filter. */ -static ssize_t gzip_filter_read(struct archive_read_filter *, const void **); -static int gzip_filter_close(struct archive_read_filter *); -#endif - -/* - * 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. - */ -static int gzip_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *); -static int gzip_bidder_init(struct archive_read_filter *); - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Deprecated; remove in libarchive 4.0 */ -int -archive_read_support_compression_gzip(struct archive *a) -{ - return archive_read_support_filter_gzip(a); -} -#endif - -int -archive_read_support_filter_gzip(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - bidder->data = NULL; - bidder->name = "gzip"; - bidder->bid = gzip_bidder_bid; - bidder->init = gzip_bidder_init; - bidder->options = NULL; - bidder->free = NULL; /* No data, so no cleanup necessary. */ - /* Signal the extent of gzip support with the return value here. */ -#if HAVE_ZLIB_H - return (ARCHIVE_OK); -#else - archive_set_error(_a, ARCHIVE_ERRNO_MISC, - "Using external gzip program"); - return (ARCHIVE_WARN); -#endif -} - -/* - * Read and verify the header. - * - * Returns zero if the header couldn't be validated, else returns - * number of bytes in header. If pbits is non-NULL, it receives a - * count of bits verified, suitable for use by bidder. - */ -static ssize_t -peek_at_header(struct archive_read_filter *filter, int *pbits) -{ - const unsigned char *p; - ssize_t avail, len; - int bits = 0; - int header_flags; - - /* 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) - return (0); - /* We only support deflation- third byte must be 0x08. */ - if (memcmp(p, "\x1F\x8B\x08", 3) != 0) - return (0); - bits += 24; - if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */ - return (0); - bits += 3; - header_flags = p[3]; - /* Bytes 4-7 are mod time. */ - /* Byte 8 is deflate flags. */ - /* XXXX TODO: return deflate flags back to consume_header for use - in initializing the decompressor. */ - /* Byte 9 is OS. */ - - /* Optional extra data: 2 byte length plus variable body. */ - if (header_flags & 4) { - p = __archive_read_filter_ahead(filter, len + 2, &avail); - if (p == NULL) - return (0); - len += ((int)p[len + 1] << 8) | (int)p[len]; - len += 2; - } - - /* Null-terminated optional filename. */ - if (header_flags & 8) { - do { - ++len; - if (avail < len) - p = __archive_read_filter_ahead(filter, - len, &avail); - if (p == NULL) - return (0); - } while (p[len - 1] != 0); - } - - /* Null-terminated optional comment. */ - if (header_flags & 16) { - do { - ++len; - if (avail < len) - p = __archive_read_filter_ahead(filter, - len, &avail); - if (p == NULL) - return (0); - } while (p[len - 1] != 0); - } - - /* Optional header CRC */ - if ((header_flags & 2)) { - p = __archive_read_filter_ahead(filter, len + 2, &avail); - if (p == NULL) - return (0); -#if 0 - int hcrc = ((int)p[len + 1] << 8) | (int)p[len]; - int crc = /* XXX TODO: Compute header CRC. */; - if (crc != hcrc) - return (0); - bits += 16; -#endif - len += 2; - } - - if (pbits != NULL) - *pbits = bits; - return (len); -} - -/* - * 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) -{ - int bits_checked; - - (void)self; /* UNUSED */ - - if (peek_at_header(filter, &bits_checked)) - return (bits_checked); - return (0); -} - - -#ifndef HAVE_ZLIB_H - -/* - * If we don't have the library on this system, we can't do the - * decompression directly. We can, however, try to run "gzip -d" - * in case that's available. - */ -static int -gzip_bidder_init(struct archive_read_filter *self) -{ - int r; - - r = __archive_read_program(self, "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"; - return (r); -} - -#else - -/* - * Initialize the filter object. - */ -static int -gzip_bidder_init(struct archive_read_filter *self) -{ - struct private_data *state; - static const size_t out_block_size = 64 * 1024; - void *out_block; - - self->code = ARCHIVE_FILTER_GZIP; - self->name = "gzip"; - - state = (struct private_data *)calloc(sizeof(*state), 1); - out_block = (unsigned char *)malloc(out_block_size); - if (state == NULL || out_block == NULL) { - free(out_block); - free(state); - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate data for gzip decompression"); - return (ARCHIVE_FATAL); - } - - self->data = state; - state->out_block_size = out_block_size; - state->out_block = out_block; - self->read = gzip_filter_read; - self->skip = NULL; /* not supported */ - self->close = gzip_filter_close; - - state->in_stream = 0; /* We're not actually within a stream yet. */ - - return (ARCHIVE_OK); -} - -static int -consume_header(struct archive_read_filter *self) -{ - struct private_data *state; - ssize_t avail; - 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); - if (len == 0) - return (ARCHIVE_EOF); - __archive_read_filter_consume(self->upstream, len); - - /* Initialize CRC accumulator. */ - state->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), - -15 /* Don't check for zlib header */); - - /* Decipher the error code. */ - switch (ret) { - case Z_OK: - state->in_stream = 1; - return (ARCHIVE_OK); - case Z_STREAM_ERROR: - archive_set_error(&self->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, - "Internal error initializing compression library: " - "out of memory"); - break; - case Z_VERSION_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "invalid library version"); - break; - default: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - " Zlib error %d", ret); - break; - } - return (ARCHIVE_FATAL); -} - -static int -consume_trailer(struct archive_read_filter *self) -{ - struct private_data *state; - const unsigned char *p; - ssize_t avail; - - state = (struct private_data *)self->data; - - state->in_stream = 0; - switch (inflateEnd(&(state->stream))) { - case Z_OK: - break; - default: - archive_set_error(&self->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) - 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); - - return (ARCHIVE_OK); -} - -static ssize_t -gzip_filter_read(struct archive_read_filter *self, const void **p) -{ - struct private_data *state; - size_t decompressed; - ssize_t avail_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; - - /* Try to fill the output buffer. */ - while (state->stream.avail_out > 0 && !state->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 (ret == ARCHIVE_EOF) { - state->eof = 1; - break; - } - if (ret < ARCHIVE_OK) - return (ret); - } - - /* 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, - ARCHIVE_ERRNO_MISC, - "truncated gzip input"); - return (ARCHIVE_FATAL); - } - state->stream.avail_in = (uInt)avail_in; - - /* Decompress and consume some of that data. */ - ret = inflate(&(state->stream), 0); - switch (ret) { - case Z_OK: /* Decompressor made some progress. */ - __archive_read_filter_consume(self->upstream, - avail_in - state->stream.avail_in); - break; - case Z_STREAM_END: /* Found end of stream. */ - __archive_read_filter_consume(self->upstream, - avail_in - state->stream.avail_in); - /* Consume the stream trailer; release the - * decompression library. */ - ret = consume_trailer(self); - if (ret < ARCHIVE_OK) - return (ret); - break; - default: - /* Return an error. */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "gzip decompression failed"); - return (ARCHIVE_FATAL); - } - } - - /* We've read as much as we can. */ - decompressed = state->stream.next_out - state->out_block; - state->total_out += decompressed; - if (decompressed == 0) - *p = NULL; - else - *p = state->out_block; - return (decompressed); -} - -/* - * Clean up the decompressor. - */ -static int -gzip_filter_close(struct archive_read_filter *self) -{ - struct private_data *state; - int ret; - - state = (struct private_data *)self->data; - ret = ARCHIVE_OK; - - if (state->in_stream) { - switch (inflateEnd(&(state->stream))) { - case Z_OK: - break; - default: - archive_set_error(&(self->archive->archive), - ARCHIVE_ERRNO_MISC, - "Failed to clean up gzip compressor"); - ret = ARCHIVE_FATAL; - } - } - - free(state->out_block); - free(state); - return (ret); -} - -#endif /* HAVE_ZLIB_H */ diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c deleted file mode 100644 index 95e5cfdb..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive.h" -#include "archive_private.h" - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Deprecated; remove in libarchive 4.0 */ -int -archive_read_support_compression_none(struct archive *a) -{ - return archive_read_support_filter_none(a); -} -#endif - -/* - * Uncompressed streams are handled implicitly by the read core, - * so this is now a no-op. - */ -int -archive_read_support_filter_none(struct archive *a) -{ - archive_check_magic(a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_none"); - - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c deleted file mode 100644 index b8bf1288..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c +++ /dev/null @@ -1,518 +0,0 @@ -/*- - * Copyright (c) 2007 Joerg Sonnenberger - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_SYS_WAIT_H -# include -#endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -#ifdef HAVE_LIMITS_H -# include -#endif -#ifdef HAVE_SIGNAL_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" -#include "archive_read_private.h" -#include "filter_fork.h" - - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Deprecated; remove in libarchive 4.0 */ -int -archive_read_support_compression_program(struct archive *a, const char *cmd) -{ - return archive_read_support_filter_program(a, cmd); -} - -int -archive_read_support_compression_program_signature(struct archive *a, - const char *cmd, const void *signature, size_t signature_len) -{ - return archive_read_support_filter_program_signature(a, - cmd, signature, signature_len); -} -#endif - -int -archive_read_support_filter_program(struct archive *a, const char *cmd) -{ - return (archive_read_support_filter_program_signature(a, cmd, NULL, 0)); -} - -/* - * The bidder object stores the command and the signature to watch for. - * The 'inhibit' entry here is used to ensure that unchecked filters never - * bid twice in the same pipeline. - */ -struct program_bidder { - char *description; - char *cmd; - void *signature; - size_t signature_len; - int inhibit; -}; - -static int program_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *upstream); -static int program_bidder_init(struct archive_read_filter *); -static int program_bidder_free(struct archive_read_filter_bidder *); - -/* - * The actual filter needs to track input and output data. - */ -struct program_filter { - struct archive_string description; -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE child; -#else - pid_t child; -#endif - int exit_status; - int waitpid_return; - int child_stdin, child_stdout; - - char *out_buf; - size_t out_buf_len; -}; - -static ssize_t program_filter_read(struct archive_read_filter *, - const void **); -static int program_filter_close(struct archive_read_filter *); -static void free_state(struct program_bidder *); - -static int -set_bidder_signature(struct archive_read_filter_bidder *bidder, - struct program_bidder *state, const void *signature, size_t signature_len) -{ - - if (signature != NULL && signature_len > 0) { - state->signature_len = signature_len; - state->signature = malloc(signature_len); - memcpy(state->signature, signature, signature_len); - } - - /* - * Fill in the bidder object. - */ - bidder->data = state; - bidder->bid = program_bidder_bid; - bidder->init = program_bidder_init; - bidder->options = NULL; - bidder->free = program_bidder_free; - return (ARCHIVE_OK); -} - -int -archive_read_support_filter_program_signature(struct archive *_a, - const char *cmd, const void *signature, size_t signature_len) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - struct program_bidder *state; - - /* - * Get a bidder object from the read core. - */ - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - /* - * Allocate our private state. - */ - state = (struct program_bidder *)calloc(1, sizeof (*state)); - if (state == NULL) - goto memerr; - state->cmd = strdup(cmd); - if (state->cmd == NULL) - goto memerr; - - return set_bidder_signature(bidder, state, signature, signature_len); -memerr: - free_state(state); - archive_set_error(_a, ENOMEM, "Can't allocate memory"); - return (ARCHIVE_FATAL); -} - -static int -program_bidder_free(struct archive_read_filter_bidder *self) -{ - struct program_bidder *state = (struct program_bidder *)self->data; - - free_state(state); - return (ARCHIVE_OK); -} - -static void -free_state(struct program_bidder *state) -{ - - if (state) { - free(state->cmd); - free(state->signature); - free(state); - } -} - -/* - * If we do have a signature, bid only if that matches. - * - * If there's no signature, we bid INT_MAX the first time - * we're called, then never bid again. - */ -static int -program_bidder_bid(struct archive_read_filter_bidder *self, - struct archive_read_filter *upstream) -{ - struct program_bidder *state = self->data; - const char *p; - - /* If we have a signature, use that to match. */ - if (state->signature_len > 0) { - p = __archive_read_filter_ahead(upstream, - state->signature_len, NULL); - if (p == NULL) - return (0); - /* No match, so don't bid. */ - if (memcmp(p, state->signature, state->signature_len) != 0) - return (0); - return ((int)state->signature_len * 8); - } - - /* Otherwise, bid once and then never bid again. */ - if (state->inhibit) - return (0); - state->inhibit = 1; - return (INT_MAX); -} - -/* - * Shut down the child, return ARCHIVE_OK if it exited normally. - * - * Note that the return value is sticky; if we're called again, - * we won't reap the child again, but we will return the same status - * (including error message if the child came to a bad end). - */ -static int -child_stop(struct archive_read_filter *self, struct program_filter *state) -{ - /* Close our side of the I/O with the child. */ - if (state->child_stdin != -1) { - close(state->child_stdin); - state->child_stdin = -1; - } - if (state->child_stdout != -1) { - close(state->child_stdout); - state->child_stdout = -1; - } - - if (state->child != 0) { - /* Reap the child. */ - do { - state->waitpid_return - = waitpid(state->child, &state->exit_status, 0); - } while (state->waitpid_return == -1 && errno == EINTR); -#if defined(_WIN32) && !defined(__CYGWIN__) - CloseHandle(state->child); -#endif - state->child = 0; - } - - if (state->waitpid_return < 0) { - /* waitpid() failed? This is ugly. */ - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Child process exited badly"); - return (ARCHIVE_WARN); - } - -#if !defined(_WIN32) || defined(__CYGWIN__) - if (WIFSIGNALED(state->exit_status)) { -#ifdef SIGPIPE - /* If the child died because we stopped reading before - * it was done, that's okay. Some archive formats - * have padding at the end that we routinely ignore. */ - /* 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) - return (ARCHIVE_OK); -#endif - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Child process exited with signal %d", - WTERMSIG(state->exit_status)); - return (ARCHIVE_WARN); - } -#endif /* !_WIN32 || __CYGWIN__ */ - - if (WIFEXITED(state->exit_status)) { - if (WEXITSTATUS(state->exit_status) == 0) - return (ARCHIVE_OK); - - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Child process exited with status %d", - WEXITSTATUS(state->exit_status)); - return (ARCHIVE_WARN); - } - - return (ARCHIVE_WARN); -} - -/* - * 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) -{ - struct program_filter *state = self->data; - ssize_t ret, requested, avail; - const char *p; -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout); -#endif - - requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; - - for (;;) { - do { -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Avoid infinity wait. - * Note: If there is no data in the pipe, ReadFile() - * called in read() never returns and so we won't - * write remaining encoded data to the pipe. - * Note: This way may cause performance problem. - * we are looking forward to great code to resolve - * this. */ - DWORD pipe_avail = -1; - int cnt = 2; - - while (PeekNamedPipe(handle, NULL, 0, NULL, - &pipe_avail, NULL) != 0 && pipe_avail == 0 && - cnt--) - Sleep(5); - if (pipe_avail == 0) { - ret = -1; - errno = EAGAIN; - break; - } -#endif - ret = read(state->child_stdout, buf, requested); - } while (ret == -1 && errno == EINTR); - - if (ret > 0) - return (ret); - if (ret == 0 || (ret == -1 && errno == EPIPE)) - /* Child has closed its output; reap the child - * and return the status. */ - return (child_stop(self, state)); - if (ret == -1 && errno != EAGAIN) - return (-1); - - if (state->child_stdin == -1) { - /* Block until child has some I/O ready. */ - __archive_check_child(state->child_stdin, - state->child_stdout); - continue; - } - - /* Get some more data from upstream. */ - p = __archive_read_filter_ahead(self->upstream, 1, &avail); - if (p == NULL) { - close(state->child_stdin); - state->child_stdin = -1; - fcntl(state->child_stdout, F_SETFL, 0); - if (avail < 0) - return (avail); - continue; - } - - do { - ret = write(state->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); - } else if (ret == -1 && errno == EAGAIN) { - /* Block until child has some I/O ready. */ - __archive_check_child(state->child_stdin, - state->child_stdout); - } else { - /* Write failed. */ - close(state->child_stdin); - state->child_stdin = -1; - fcntl(state->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. */ - if (ret == -1 && errno != EPIPE) - return (-1); - } - } -} - -int -__archive_read_program(struct archive_read_filter *self, const char *cmd) -{ - struct program_filter *state; - static const size_t out_buf_len = 65536; - char *out_buf; - const char *prefix = "Program: "; - pid_t child; - size_t l; - - l = strlen(prefix) + strlen(cmd) + 1; - state = (struct program_filter *)calloc(1, sizeof(*state)); - out_buf = (char *)malloc(out_buf_len); - if (state == NULL || out_buf == NULL || - archive_string_ensure(&state->description, l) == NULL) { - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate input data"); - if (state != NULL) { - archive_string_free(&state->description); - free(state); - } - free(out_buf); - return (ARCHIVE_FATAL); - } - archive_strcpy(&state->description, prefix); - archive_strcat(&state->description, cmd); - - self->code = ARCHIVE_FILTER_PROGRAM; - self->name = state->description.s; - - state->out_buf = out_buf; - state->out_buf_len = out_buf_len; - - child = __archive_create_child(cmd, &state->child_stdin, - &state->child_stdout); - if (child == -1) { - free(state->out_buf); - archive_string_free(&state->description); - free(state); - archive_set_error(&self->archive->archive, EINVAL, - "Can't initialize filter; unable to run program \"%s\"", - cmd); - return (ARCHIVE_FATAL); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child); - if (state->child == NULL) { - child_stop(self, state); - free(state->out_buf); - archive_string_free(&state->description); - free(state); - archive_set_error(&self->archive->archive, EINVAL, - "Can't initialize filter; unable to run program \"%s\"", - cmd); - return (ARCHIVE_FATAL); - } -#else - state->child = child; -#endif - - self->data = state; - self->read = program_filter_read; - self->skip = NULL; - self->close = program_filter_close; - - /* XXX Check that we can read at least one byte? */ - return (ARCHIVE_OK); -} - -static int -program_bidder_init(struct archive_read_filter *self) -{ - struct program_bidder *bidder_state; - - bidder_state = (struct program_bidder *)self->bidder->data; - return (__archive_read_program(self, bidder_state->cmd)); -} - -static ssize_t -program_filter_read(struct archive_read_filter *self, const void **buff) -{ - struct program_filter *state; - 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); - if (bytes < 0) - /* No recovery is possible if we can no longer - * read from the child. */ - return (ARCHIVE_FATAL); - if (bytes == 0) - /* We got EOF from the child. */ - break; - total += bytes; - p += bytes; - } - - *buff = state->out_buf; - return (total); -} - -static int -program_filter_close(struct archive_read_filter *self) -{ - struct program_filter *state; - int e; - - state = (struct program_filter *)self->data; - e = child_stop(self, state); - - /* Release our private data. */ - free(state->out_buf); - archive_string_free(&state->description); - free(state); - - return (e); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c deleted file mode 100644 index 11807cf6..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c +++ /dev/null @@ -1,796 +0,0 @@ -/*- - * Copyright (c) 2009-2011 Michihiro NAKAJIMA - * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#if HAVE_LZMA_H -#include -#endif - -#include "archive.h" -#include "archive_endian.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#if HAVE_LZMA_H && HAVE_LIBLZMA - -struct private_data { - 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; - - /* Following variables are used for lzip only. */ - char lzip_ver; - uint32_t crc32; - int64_t member_in; - int64_t member_out; -}; - -#if LZMA_VERSION_MAJOR >= 5 -/* Effectively disable the limiter. */ -#define LZMA_MEMLIMIT UINT64_MAX -#else -/* NOTE: This needs to check memory size which running system has. */ -#define LZMA_MEMLIMIT (1U << 30) -#endif - -/* Combined lzip/lzma/xz filter */ -static ssize_t xz_filter_read(struct archive_read_filter *, const void **); -static int xz_filter_close(struct archive_read_filter *); -static int xz_lzma_bidder_init(struct archive_read_filter *); - -#endif - -/* - * 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. - */ -static int xz_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *); -static int xz_bidder_init(struct archive_read_filter *); -static int lzma_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *); -static int lzma_bidder_init(struct archive_read_filter *); -static int lzip_has_member(struct archive_read_filter *); -static int lzip_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *); -static int lzip_bidder_init(struct archive_read_filter *); - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* Deprecated; remove in libarchive 4.0 */ -int -archive_read_support_compression_xz(struct archive *a) -{ - return archive_read_support_filter_xz(a); -} -#endif - -int -archive_read_support_filter_xz(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_xz"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - bidder->data = NULL; - bidder->name = "xz"; - bidder->bid = xz_bidder_bid; - bidder->init = xz_bidder_init; - bidder->options = NULL; - bidder->free = NULL; -#if HAVE_LZMA_H && HAVE_LIBLZMA - return (ARCHIVE_OK); -#else - archive_set_error(_a, ARCHIVE_ERRNO_MISC, - "Using external xz program for xz decompression"); - return (ARCHIVE_WARN); -#endif -} - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_read_support_compression_lzma(struct archive *a) -{ - return archive_read_support_filter_lzma(a); -} -#endif - -int -archive_read_support_filter_lzma(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - bidder->data = NULL; - bidder->name = "lzma"; - bidder->bid = lzma_bidder_bid; - bidder->init = lzma_bidder_init; - bidder->options = NULL; - bidder->free = NULL; -#if HAVE_LZMA_H && HAVE_LIBLZMA - return (ARCHIVE_OK); -#else - archive_set_error(_a, ARCHIVE_ERRNO_MISC, - "Using external lzma program for lzma decompression"); - return (ARCHIVE_WARN); -#endif -} - - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_read_support_compression_lzip(struct archive *a) -{ - return archive_read_support_filter_lzip(a); -} -#endif - -int -archive_read_support_filter_lzip(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - bidder->data = NULL; - bidder->name = "lzip"; - bidder->bid = lzip_bidder_bid; - bidder->init = lzip_bidder_init; - bidder->options = NULL; - bidder->free = NULL; -#if HAVE_LZMA_H && HAVE_LIBLZMA - return (ARCHIVE_OK); -#else - archive_set_error(_a, ARCHIVE_ERRNO_MISC, - "Using external lzip program for lzip decompression"); - return (ARCHIVE_WARN); -#endif -} - -/* - * Test whether we can handle this data. - */ -static int -xz_bidder_bid(struct archive_read_filter_bidder *self, - struct archive_read_filter *filter) -{ - const unsigned char *buffer; - ssize_t avail; - - (void)self; /* UNUSED */ - - buffer = __archive_read_filter_ahead(filter, 6, &avail); - if (buffer == NULL) - return (0); - - /* - * Verify Header Magic Bytes : FD 37 7A 58 5A 00 - */ - if (memcmp(buffer, "\xFD\x37\x7A\x58\x5A\x00", 6) != 0) - return (0); - - return (48); -} - -/* - * Test whether we can handle this data. - * - * LZMA has a rather poor file signature. Zeros do not - * make good signature bytes as a rule, and the only non-zero byte - * here is an ASCII character. For example, an uncompressed tar - * archive whose first file is ']' would satisfy this check. It may - * be necessary to exclude LZMA from compression_all() because of - * this. Clients of libarchive would then have to explicitly enable - * LZMA checking instead of (or in addition to) compression_all() when - * 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) -{ - const unsigned char *buffer; - ssize_t avail; - uint32_t dicsize; - uint64_t uncompressed_size; - int bits_checked; - - (void)self; /* UNUSED */ - - buffer = __archive_read_filter_ahead(filter, 14, &avail); - if (buffer == NULL) - return (0); - - /* First byte of raw LZMA stream is commonly 0x5d. - * The first byte is a special number, which consists of - * three parameters of LZMA compression, a number of literal - * context bits(which is from 0 to 8, default is 3), a number - * of literal pos bits(which is from 0 to 4, default is 0), - * a number of pos bits(which is from 0 to 4, default is 2). - * The first byte is made by - * (pos bits * 5 + literal pos bit) * 9 + * literal contest bit, - * and so the default value in this field is - * (2 * 5 + 0) * 9 + 3 = 0x5d. - * lzma of LZMA SDK has options to change those parameters. - * It means a range of this field is from 0 to 224. And lzma of - * XZ Utils with option -e records 0x5e in this field. */ - /* NOTE: If this checking of the first byte increases false - * recognition, we should allow only 0x5d and 0x5e for the first - * byte of LZMA stream. */ - bits_checked = 0; - if (buffer[0] > (4 * 5 + 4) * 9 + 8) - return (0); - /* Most likely value in the first byte of LZMA stream. */ - if (buffer[0] == 0x5d || buffer[0] == 0x5e) - bits_checked += 8; - - /* Sixth through fourteenth bytes are uncompressed size, - * stored in little-endian order. `-1' means uncompressed - * size is unknown and lzma of XZ Utils always records `-1' - * in this field. */ - uncompressed_size = archive_le64dec(buffer+5); - if (uncompressed_size == (uint64_t)ARCHIVE_LITERAL_LL(-1)) - bits_checked += 64; - - /* Second through fifth bytes are dictionary size, stored in - * little-endian order. The minimum dictionary size is - * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option - * -d12 and the maximum dictionary size is 1 << 27(128MiB) - * which the one uses with option -d27. - * NOTE: A comment of LZMA SDK source code says this dictionary - * range is from 1 << 12 to 1 << 30. */ - dicsize = archive_le32dec(buffer+1); - switch (dicsize) { - case 0x00001000:/* lzma of LZMA SDK option -d12. */ - case 0x00002000:/* lzma of LZMA SDK option -d13. */ - case 0x00004000:/* lzma of LZMA SDK option -d14. */ - case 0x00008000:/* lzma of LZMA SDK option -d15. */ - case 0x00010000:/* lzma of XZ Utils option -0 and -1. - * lzma of LZMA SDK option -d16. */ - case 0x00020000:/* lzma of LZMA SDK option -d17. */ - case 0x00040000:/* lzma of LZMA SDK option -d18. */ - case 0x00080000:/* lzma of XZ Utils option -2. - * lzma of LZMA SDK option -d19. */ - case 0x00100000:/* lzma of XZ Utils option -3. - * lzma of LZMA SDK option -d20. */ - case 0x00200000:/* lzma of XZ Utils option -4. - * lzma of LZMA SDK option -d21. */ - case 0x00400000:/* lzma of XZ Utils option -5. - * lzma of LZMA SDK option -d22. */ - case 0x00800000:/* lzma of XZ Utils option -6. - * lzma of LZMA SDK option -d23. */ - case 0x01000000:/* lzma of XZ Utils option -7. - * lzma of LZMA SDK option -d24. */ - case 0x02000000:/* lzma of XZ Utils option -8. - * lzma of LZMA SDK option -d25. */ - case 0x04000000:/* lzma of XZ Utils option -9. - * lzma of LZMA SDK option -d26. */ - case 0x08000000:/* lzma of LZMA SDK option -d27. */ - bits_checked += 32; - break; - default: - /* If a memory usage for encoding was not enough on - * the platform where LZMA stream was made, lzma of - * XZ Utils automatically decreased the dictionary - * size to enough memory for encoding by 1Mi bytes - * (1 << 20).*/ - if (dicsize <= 0x03F00000 && dicsize >= 0x00300000 && - (dicsize & ((1 << 20)-1)) == 0 && - bits_checked == 8 + 64) { - bits_checked += 32; - break; - } - /* Otherwise dictionary size is unlikely. But it is - * possible that someone makes lzma stream with - * liblzma/LZMA SDK in one's dictionary size. */ - return (0); - } - - /* TODO: The above test is still very weak. It would be - * good to do better. */ - - return (bits_checked); -} - -static int -lzip_has_member(struct archive_read_filter *filter) -{ - const unsigned char *buffer; - ssize_t avail; - int bits_checked; - int log2dic; - - buffer = __archive_read_filter_ahead(filter, 6, &avail); - if (buffer == NULL) - return (0); - - /* - * Verify Header Magic Bytes : 4C 5A 49 50 (`LZIP') - */ - bits_checked = 0; - if (memcmp(buffer, "LZIP", 4) != 0) - return (0); - bits_checked += 32; - - /* A version number must be 0 or 1 */ - if (buffer[4] != 0 && buffer[4] != 1) - return (0); - bits_checked += 8; - - /* Dictionary size. */ - log2dic = buffer[5] & 0x1f; - if (log2dic < 12 || log2dic > 27) - return (0); - bits_checked += 8; - - return (bits_checked); -} - -static int -lzip_bidder_bid(struct archive_read_filter_bidder *self, - struct archive_read_filter *filter) -{ - - (void)self; /* UNUSED */ - return (lzip_has_member(filter)); -} - -#if HAVE_LZMA_H && HAVE_LIBLZMA - -/* - * liblzma 4.999.7 and later support both lzma and xz streams. - */ -static int -xz_bidder_init(struct archive_read_filter *self) -{ - self->code = ARCHIVE_FILTER_XZ; - self->name = "xz"; - return (xz_lzma_bidder_init(self)); -} - -static int -lzma_bidder_init(struct archive_read_filter *self) -{ - self->code = ARCHIVE_FILTER_LZMA; - self->name = "lzma"; - return (xz_lzma_bidder_init(self)); -} - -static int -lzip_bidder_init(struct archive_read_filter *self) -{ - self->code = ARCHIVE_FILTER_LZIP; - self->name = "lzip"; - return (xz_lzma_bidder_init(self)); -} - -/* - * Set an error code and choose an error message - */ -static void -set_error(struct archive_read_filter *self, int ret) -{ - - switch (ret) { - case LZMA_STREAM_END: /* Found end of stream. */ - case LZMA_OK: /* Decompressor made some progress. */ - break; - case LZMA_MEM_ERROR: - archive_set_error(&self->archive->archive, ENOMEM, - "Lzma library error: Cannot allocate memory"); - break; - case LZMA_MEMLIMIT_ERROR: - archive_set_error(&self->archive->archive, ENOMEM, - "Lzma library error: Out of memory"); - break; - case LZMA_FORMAT_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma library error: format not recognized"); - break; - case LZMA_OPTIONS_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma library error: Invalid options"); - break; - case LZMA_DATA_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma library error: Corrupted input data"); - break; - case LZMA_BUF_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma library error: No progress is possible"); - break; - default: - /* Return an error. */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma decompression failed: Unknown error"); - break; - } -} - -/* - * Setup the callbacks. - */ -static int -xz_lzma_bidder_init(struct archive_read_filter *self) -{ - static const size_t out_block_size = 64 * 1024; - void *out_block; - struct private_data *state; - int ret; - - state = (struct private_data *)calloc(sizeof(*state), 1); - out_block = (unsigned char *)malloc(out_block_size); - if (state == NULL || out_block == NULL) { - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate data for xz decompression"); - free(out_block); - free(state); - return (ARCHIVE_FATAL); - } - - self->data = state; - state->out_block_size = out_block_size; - state->out_block = out_block; - self->read = xz_filter_read; - self->skip = NULL; /* not supported */ - self->close = xz_filter_close; - - state->stream.avail_in = 0; - - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - state->crc32 = 0; - if (self->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; - return (ARCHIVE_OK); - } else - state->in_stream = 1; - - /* Initialize compression library. */ - if (self->code == ARCHIVE_FILTER_XZ) - ret = lzma_stream_decoder(&(state->stream), - LZMA_MEMLIMIT,/* memlimit */ - LZMA_CONCATENATED); - else - ret = lzma_alone_decoder(&(state->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); - - free(state->out_block); - free(state); - self->data = NULL; - return (ARCHIVE_FATAL); -} - -static int -lzip_init(struct archive_read_filter *self) -{ - struct private_data *state; - 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); - if (h == NULL) - return (ARCHIVE_FATAL); - - /* Get a version number. */ - state->lzip_ver = h[4]; - - /* - * Setup lzma property. - */ - props[0] = 0x5d; - - /* Get dictionary size. */ - log2dic = h[5] & 0x1f; - if (log2dic < 12 || log2dic > 27) - return (ARCHIVE_FATAL); - dicsize = 1U << log2dic; - if (log2dic > 12) - dicsize -= (dicsize / 16) * (h[5] >> 5); - archive_le32enc(props+1, dicsize); - - /* Consume lzip header. */ - __archive_read_filter_consume(self->upstream, 6); - state->member_in = 6; - - filters[0].id = LZMA_FILTER_LZMA1; - filters[0].options = NULL; - filters[1].id = LZMA_VLI_UNKNOWN; - filters[1].options = NULL; - - ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props)); - if (ret != LZMA_OK) { - set_error(self, ret); - return (ARCHIVE_FATAL); - } - ret = lzma_raw_decoder(&(state->stream), filters); - free(filters[0].options); - if (ret != LZMA_OK) { - set_error(self, ret); - return (ARCHIVE_FATAL); - } - return (ARCHIVE_OK); -} - -static int -lzip_tail(struct archive_read_filter *self) -{ - struct private_data *state; - const unsigned char *f; - ssize_t avail_in; - int tail; - - state = (struct private_data *)self->data; - if (state->lzip_ver == 0) - tail = 12; - else - tail = 20; - f = __archive_read_filter_ahead(self->upstream, tail, &avail_in); - if (f == NULL && avail_in < 0) - return (ARCHIVE_FATAL); - if (f == NULL || avail_in < tail) { - archive_set_error(&self->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)) { - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Lzip: CRC32 error"); - return (ARCHIVE_FAILED); - } - - /* 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, - "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, - "Lzip: Member size error"); - return (ARCHIVE_FAILED); - } - __archive_read_filter_consume(self->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; - } - return (ARCHIVE_OK); -} - -/* - * Return the next block of decompressed data. - */ -static ssize_t -xz_filter_read(struct archive_read_filter *self, const void **p) -{ - struct private_data *state; - size_t decompressed; - ssize_t avail_in; - int ret; - - state = (struct private_data *)self->data; - - /* Empty our output buffer. */ - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Try to fill the output buffer. */ - while (state->stream.avail_out > 0 && !state->eof) { - if (!state->in_stream) { - /* - * Initialize liblzma for lzip - */ - ret = lzip_init(self); - if (ret != ARCHIVE_OK) - return (ret); - state->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, - ARCHIVE_ERRNO_MISC, - "truncated input"); - return (ARCHIVE_FATAL); - } - state->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); - switch (ret) { - case LZMA_STREAM_END: /* Found end of stream. */ - state->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; - break; - default: - set_error(self, ret); - return (ARCHIVE_FATAL); - } - } - - decompressed = state->stream.next_out - state->out_block; - state->total_out += decompressed; - state->member_out += decompressed; - if (decompressed == 0) - *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); - if (ret != ARCHIVE_OK) - return (ret); - } - } - } - return (decompressed); -} - -/* - * Clean up the decompressor. - */ -static int -xz_filter_close(struct archive_read_filter *self) -{ - struct private_data *state; - - state = (struct private_data *)self->data; - lzma_end(&(state->stream)); - free(state->out_block); - free(state); - return (ARCHIVE_OK); -} - -#else - -/* - * - * If we have no suitable library on this system, we can't actually do - * the decompression. We can, however, still detect compressed - * archives and emit a useful message. - * - */ -static int -lzma_bidder_init(struct archive_read_filter *self) -{ - int r; - - r = __archive_read_program(self, "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"; - return (r); -} - -static int -xz_bidder_init(struct archive_read_filter *self) -{ - int r; - - r = __archive_read_program(self, "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"; - return (r); -} - -static int -lzip_bidder_init(struct archive_read_filter *self) -{ - int r; - - r = __archive_read_program(self, "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"; - return (r); -} - -#endif /* HAVE_LZMA_H */ diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c b/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c deleted file mode 100644 index 084563f4..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * Copyright (c) 2003-2011 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive.h" -#include "archive_private.h" - -int -archive_read_support_format_by_code(struct archive *a, int format_code) -{ - archive_check_magic(a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_by_code"); - - switch (format_code & ARCHIVE_FORMAT_BASE_MASK) { - case ARCHIVE_FORMAT_7ZIP: - return archive_read_support_format_7zip(a); - break; - case ARCHIVE_FORMAT_AR: - return archive_read_support_format_ar(a); - break; - case ARCHIVE_FORMAT_CAB: - return archive_read_support_format_cab(a); - break; - case ARCHIVE_FORMAT_CPIO: - return archive_read_support_format_cpio(a); - break; - case ARCHIVE_FORMAT_ISO9660: - return archive_read_support_format_iso9660(a); - break; - case ARCHIVE_FORMAT_LHA: - return archive_read_support_format_lha(a); - break; - case ARCHIVE_FORMAT_MTREE: - return archive_read_support_format_mtree(a); - break; - case ARCHIVE_FORMAT_RAR: - return archive_read_support_format_rar(a); - break; - case ARCHIVE_FORMAT_TAR: - return archive_read_support_format_tar(a); - break; - case ARCHIVE_FORMAT_XAR: - return archive_read_support_format_xar(a); - break; - case ARCHIVE_FORMAT_ZIP: - return archive_read_support_format_zip(a); - break; - } - return (ARCHIVE_FATAL); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c b/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c deleted file mode 100644 index c641eb9b..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c +++ /dev/null @@ -1,96 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_empty.c 191524 2009-04-26 18:24:14Z kientzle $"); - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_read_private.h" - -static int archive_read_format_empty_bid(struct archive_read *, int); -static int archive_read_format_empty_read_data(struct archive_read *, - const void **, size_t *, int64_t *); -static int archive_read_format_empty_read_header(struct archive_read *, - struct archive_entry *); -int -archive_read_support_format_empty(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - int r; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_empty"); - - r = __archive_read_register_format(a, - NULL, - NULL, - archive_read_format_empty_bid, - NULL, - archive_read_format_empty_read_header, - archive_read_format_empty_read_data, - NULL, - NULL, - NULL, - NULL, - NULL); - - return (r); -} - - -static int -archive_read_format_empty_bid(struct archive_read *a, int best_bid) -{ - if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) == NULL) - return (1); - return (-1); -} - -static int -archive_read_format_empty_read_header(struct archive_read *a, - struct archive_entry *entry) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - - a->archive.archive_format = ARCHIVE_FORMAT_EMPTY; - a->archive.archive_format_name = "Empty file"; - - return (ARCHIVE_EOF); -} - -static int -archive_read_format_empty_read_data(struct archive_read *a, - const void **buff, size_t *size, int64_t *offset) -{ - (void)a; /* UNUSED */ - (void)buff; /* UNUSED */ - (void)size; /* UNUSED */ - (void)offset; /* UNUSED */ - - return (ARCHIVE_EOF); -} diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c b/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c deleted file mode 100644 index 30d5bc83..00000000 --- a/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c +++ /dev/null @@ -1,2883 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * Copyright (c) 2016 Martin Matuska - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_tar.c 201161 2009-12-29 05:44:39Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_acl_private.h" /* For ACL parsing routines. */ -#include "archive_entry.h" -#include "archive_entry_locale.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#define tar_min(a,b) ((a) < (b) ? (a) : (b)) - -/* - * Layout of POSIX 'ustar' tar header. - */ -struct archive_entry_header_ustar { - char name[100]; - char mode[8]; - char uid[8]; - char gid[8]; - char size[12]; - char mtime[12]; - char checksum[8]; - char typeflag[1]; - char linkname[100]; /* "old format" header ends here */ - char magic[6]; /* For POSIX: "ustar\0" */ - char version[2]; /* For POSIX: "00" */ - char uname[32]; - char gname[32]; - char rdevmajor[8]; - char rdevminor[8]; - char prefix[155]; -}; - -/* - * Structure of GNU tar header - */ -struct gnu_sparse { - char offset[12]; - char numbytes[12]; -}; - -struct archive_entry_header_gnutar { - char name[100]; - char mode[8]; - char uid[8]; - char gid[8]; - char size[12]; - char mtime[12]; - char checksum[8]; - char typeflag[1]; - char linkname[100]; - char magic[8]; /* "ustar \0" (note blank/blank/null at end) */ - char uname[32]; - char gname[32]; - char rdevmajor[8]; - char rdevminor[8]; - char atime[12]; - char ctime[12]; - char offset[12]; - char longnames[4]; - char unused[1]; - struct gnu_sparse sparse[4]; - char isextended[1]; - char realsize[12]; - /* - * Old GNU format doesn't use POSIX 'prefix' field; they use - * the 'L' (longname) entry instead. - */ -}; - -/* - * Data specific to this format. - */ -struct sparse_block { - struct sparse_block *next; - int64_t offset; - int64_t remaining; - int hole; -}; - -struct tar { - struct archive_string acl_text; - struct archive_string entry_pathname; - /* For "GNU.sparse.name" and other similar path extensions. */ - struct archive_string entry_pathname_override; - struct archive_string entry_linkpath; - struct archive_string entry_uname; - struct archive_string entry_gname; - struct archive_string longlink; - struct archive_string longname; - struct archive_string pax_header; - struct archive_string pax_global; - struct archive_string line; - int pax_hdrcharset_binary; - int header_recursion_depth; - int64_t entry_bytes_remaining; - int64_t entry_offset; - int64_t entry_padding; - int64_t entry_bytes_unconsumed; - int64_t realsize; - int sparse_allowed; - struct sparse_block *sparse_list; - struct sparse_block *sparse_last; - int64_t sparse_offset; - int64_t sparse_numbytes; - int sparse_gnu_major; - int sparse_gnu_minor; - char sparse_gnu_pending; - - struct archive_string localname; - struct archive_string_conv *opt_sconv; - struct archive_string_conv *sconv; - struct archive_string_conv *sconv_acl; - struct archive_string_conv *sconv_default; - int init_default_conversion; - int compat_2x; - int process_mac_extensions; - int read_concatenated_archives; - int realsize_override; -}; - -static int archive_block_is_null(const char *p); -static char *base64_decode(const char *, size_t, size_t *); -static int gnu_add_sparse_entry(struct archive_read *, struct tar *, - int64_t offset, int64_t remaining); - -static void gnu_clear_sparse_list(struct tar *); -static int gnu_sparse_old_read(struct archive_read *, struct tar *, - const struct archive_entry_header_gnutar *header, size_t *); -static int gnu_sparse_old_parse(struct archive_read *, struct tar *, - const struct gnu_sparse *sparse, int length); -static int gnu_sparse_01_parse(struct archive_read *, struct tar *, - const char *); -static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *, - size_t *); -static int header_Solaris_ACL(struct archive_read *, struct tar *, - struct archive_entry *, const void *, size_t *); -static int header_common(struct archive_read *, struct tar *, - struct archive_entry *, const void *); -static int header_old_tar(struct archive_read *, struct tar *, - struct archive_entry *, const void *); -static int header_pax_extensions(struct archive_read *, struct tar *, - struct archive_entry *, const void *, size_t *); -static int header_pax_global(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int header_longlink(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int header_longname(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int read_mac_metadata_blob(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int header_volume(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int header_ustar(struct archive_read *, struct tar *, - struct archive_entry *, const void *h); -static int header_gnutar(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); -static int archive_read_format_tar_bid(struct archive_read *, int); -static int archive_read_format_tar_options(struct archive_read *, - const char *, const char *); -static int archive_read_format_tar_cleanup(struct archive_read *); -static int archive_read_format_tar_read_data(struct archive_read *a, - const void **buff, size_t *size, int64_t *offset); -static int archive_read_format_tar_skip(struct archive_read *a); -static int archive_read_format_tar_read_header(struct archive_read *, - struct archive_entry *); -static int checksum(struct archive_read *, const void *); -static int pax_attribute(struct archive_read *, struct tar *, - struct archive_entry *, const char *key, const char *value, - size_t value_length); -static int pax_attribute_acl(struct archive_read *, struct tar *, - struct archive_entry *, const char *, int); -static int pax_attribute_xattr(struct archive_entry *, const char *, - const char *); -static int pax_header(struct archive_read *, struct tar *, - struct archive_entry *, struct archive_string *); -static void pax_time(const char *, int64_t *sec, long *nanos); -static ssize_t readline(struct archive_read *, struct tar *, const char **, - ssize_t limit, size_t *); -static int read_body_to_string(struct archive_read *, struct tar *, - struct archive_string *, const void *h, size_t *); -static int solaris_sparse_parse(struct archive_read *, struct tar *, - struct archive_entry *, const char *); -static int64_t tar_atol(const char *, size_t); -static int64_t tar_atol10(const char *, size_t); -static int64_t tar_atol256(const char *, size_t); -static int64_t tar_atol8(const char *, size_t); -static int tar_read_header(struct archive_read *, struct tar *, - struct archive_entry *, size_t *); -static int tohex(int c); -static char *url_decode(const char *); -static void tar_flush_unconsumed(struct archive_read *, size_t *); - - -int -archive_read_support_format_gnutar(struct archive *a) -{ - archive_check_magic(a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_gnutar"); - return (archive_read_support_format_tar(a)); -} - - -int -archive_read_support_format_tar(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct tar *tar; - int r; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_tar"); - - tar = (struct tar *)calloc(1, sizeof(*tar)); -#ifdef HAVE_COPYFILE_H - /* Set this by default on Mac OS. */ - tar->process_mac_extensions = 1; -#endif - if (tar == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate tar data"); - return (ARCHIVE_FATAL); - } - - r = __archive_read_register_format(a, tar, "tar", - archive_read_format_tar_bid, - archive_read_format_tar_options, - archive_read_format_tar_read_header, - archive_read_format_tar_read_data, - archive_read_format_tar_skip, - NULL, - archive_read_format_tar_cleanup, - NULL, - NULL); - - if (r != ARCHIVE_OK) - free(tar); - return (ARCHIVE_OK); -} - -static int -archive_read_format_tar_cleanup(struct archive_read *a) -{ - struct tar *tar; - - tar = (struct tar *)(a->format->data); - gnu_clear_sparse_list(tar); - archive_string_free(&tar->acl_text); - archive_string_free(&tar->entry_pathname); - archive_string_free(&tar->entry_pathname_override); - archive_string_free(&tar->entry_linkpath); - archive_string_free(&tar->entry_uname); - archive_string_free(&tar->entry_gname); - archive_string_free(&tar->line); - archive_string_free(&tar->pax_global); - archive_string_free(&tar->pax_header); - archive_string_free(&tar->longname); - archive_string_free(&tar->longlink); - archive_string_free(&tar->localname); - free(tar); - (a->format->data) = NULL; - return (ARCHIVE_OK); -} - -/* - * Validate number field - * - * This has to be pretty lenient in order to accommodate the enormous - * variety of tar writers in the world: - * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading - * zeros and allows fields to be terminated with space or null characters - * = Many writers use different termination (in particular, libarchive - * omits terminator bytes to squeeze one or two more digits) - * = Many writers pad with space and omit leading zeros - * = GNU tar and star write base-256 values if numbers are too - * big to be represented in octal - * - * Examples of specific tar headers that we should support: - * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two - * null bytes, pads size with spaces and other numeric fields with zeroes - * = plexus-archiver prior to 2.6.3 (before switching to commons-compress) - * may have uid and gid fields filled with spaces without any octal digits - * at all and pads all numeric fields with spaces - * - * This should tolerate all variants in use. It will reject a field - * where the writer just left garbage after a trailing NUL. - */ -static int -validate_number_field(const char* p_field, size_t i_size) -{ - unsigned char marker = (unsigned char)p_field[0]; - if (marker == 128 || marker == 255 || marker == 0) { - /* Base-256 marker, there's nothing we can check. */ - return 1; - } else { - /* Must be octal */ - size_t i = 0; - /* Skip any leading spaces */ - while (i < i_size && p_field[i] == ' ') { - ++i; - } - /* Skip octal digits. */ - while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') { - ++i; - } - /* Any remaining characters must be space or NUL padding. */ - while (i < i_size) { - if (p_field[i] != ' ' && p_field[i] != 0) { - return 0; - } - ++i; - } - return 1; - } -} - -static int -archive_read_format_tar_bid(struct archive_read *a, int best_bid) -{ - int bid; - const char *h; - const struct archive_entry_header_ustar *header; - - (void)best_bid; /* UNUSED */ - - bid = 0; - - /* Now let's look at the actual header and see if it matches. */ - h = __archive_read_ahead(a, 512, NULL); - if (h == NULL) - return (-1); - - /* If it's an end-of-archive mark, we can handle it. */ - if (h[0] == 0 && archive_block_is_null(h)) { - /* - * Usually, I bid the number of bits verified, but - * in this case, 4096 seems excessive so I picked 10 as - * an arbitrary but reasonable-seeming value. - */ - return (10); - } - - /* If it's not an end-of-archive mark, it must have a valid checksum.*/ - if (!checksum(a, h)) - return (0); - bid += 48; /* Checksum is usually 6 octal digits. */ - - header = (const struct archive_entry_header_ustar *)h; - - /* Recognize POSIX formats. */ - if ((memcmp(header->magic, "ustar\0", 6) == 0) - && (memcmp(header->version, "00", 2) == 0)) - bid += 56; - - /* Recognize GNU tar format. */ - if ((memcmp(header->magic, "ustar ", 6) == 0) - && (memcmp(header->version, " \0", 2) == 0)) - bid += 56; - - /* Type flag must be null, digit or A-Z, a-z. */ - if (header->typeflag[0] != 0 && - !( header->typeflag[0] >= '0' && header->typeflag[0] <= '9') && - !( header->typeflag[0] >= 'A' && header->typeflag[0] <= 'Z') && - !( header->typeflag[0] >= 'a' && header->typeflag[0] <= 'z') ) - return (0); - bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */ - - /* - * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields. - */ - if (bid > 0 && ( - validate_number_field(header->mode, sizeof(header->mode)) == 0 - || validate_number_field(header->uid, sizeof(header->uid)) == 0 - || validate_number_field(header->gid, sizeof(header->gid)) == 0 - || validate_number_field(header->mtime, sizeof(header->mtime)) == 0 - || validate_number_field(header->size, sizeof(header->size)) == 0 - || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 - || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) { - bid = 0; - } - - return (bid); -} - -static int -archive_read_format_tar_options(struct archive_read *a, - const char *key, const char *val) -{ - struct tar *tar; - 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); - tar->init_default_conversion = tar->compat_2x; - return (ARCHIVE_OK); - } else if (strcmp(key, "hdrcharset") == 0) { - if (val == NULL || val[0] == 0) - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "tar: hdrcharset option needs a character-set name"); - else { - tar->opt_sconv = - archive_string_conversion_from_charset( - &a->archive, val, 0); - if (tar->opt_sconv != NULL) - ret = ARCHIVE_OK; - else - ret = ARCHIVE_FATAL; - } - return (ret); - } else if (strcmp(key, "mac-ext") == 0) { - tar->process_mac_extensions = (val != NULL && val[0] != 0); - return (ARCHIVE_OK); - } else if (strcmp(key, "read_concatenated_archives") == 0) { - tar->read_concatenated_archives = (val != NULL && val[0] != 0); - return (ARCHIVE_OK); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -/* utility function- this exists to centralize the logic of tracking - * how much unconsumed data we have floating around, and to consume - * anything outstanding since we're going to do read_aheads - */ -static void -tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed) -{ - if (*unconsumed) { -/* - void *data = (void *)__archive_read_ahead(a, *unconsumed, NULL); - * this block of code is to poison claimed unconsumed space, ensuring - * things break if it is in use still. - * currently it WILL break things, so enable it only for debugging this issue - if (data) { - memset(data, 0xff, *unconsumed); - } -*/ - __archive_read_consume(a, *unconsumed); - *unconsumed = 0; - } -} - -/* - * The function invoked by archive_read_next_header(). This - * just sets up a few things and then calls the internal - * tar_read_header() function below. - */ -static int -archive_read_format_tar_read_header(struct archive_read *a, - struct archive_entry *entry) -{ - /* - * When converting tar archives to cpio archives, it is - * essential that each distinct file have a distinct inode - * number. To simplify this, we keep a static count here to - * assign fake dev/inode numbers to each tar entry. Note that - * pax format archives may overwrite this with something more - * useful. - * - * Ideally, we would track every file read from the archive so - * that we could assign the same dev/ino pair to hardlinks, - * but the memory required to store a complete lookup table is - * probably not worthwhile just to support the relatively - * obscure tar->cpio conversion case. - */ - static int default_inode; - static int default_dev; - struct tar *tar; - const char *p; - const wchar_t *wp; - int r; - size_t l, 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. */ - /* Limit generated st_ino number to 16 bits. */ - if (default_inode >= 0xffff) { - ++default_dev; - default_inode = 0; - } - - tar = (struct tar *)(a->format->data); - tar->entry_offset = 0; - gnu_clear_sparse_list(tar); - tar->realsize = -1; /* Mark this as "unset" */ - tar->realsize_override = 0; - - /* Setup default string conversion. */ - tar->sconv = tar->opt_sconv; - if (tar->sconv == NULL) { - if (!tar->init_default_conversion) { - tar->sconv_default = - archive_string_default_conversion_for_read(&(a->archive)); - tar->init_default_conversion = 1; - } - tar->sconv = tar->sconv_default; - } - - r = tar_read_header(a, tar, entry, &unconsumed); - - tar_flush_unconsumed(a, &unconsumed); - - /* - * "non-sparse" files are really just sparse files with - * a single block. - */ - if (tar->sparse_list == NULL) { - if (gnu_add_sparse_entry(a, tar, 0, tar->entry_bytes_remaining) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } else { - struct sparse_block *sb; - - for (sb = tar->sparse_list; sb != NULL; sb = sb->next) { - if (!sb->hole) - archive_entry_sparse_add_entry(entry, - sb->offset, sb->remaining); - } - } - - if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) { - /* - * "Regular" entry with trailing '/' is really - * directory: This is needed for certain old tar - * variants and even for some broken newer ones. - */ - 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); - } - } else if ((p = archive_entry_pathname(entry)) != NULL) { - l = strlen(p); - if (l > 0 && p[l - 1] == '/') { - archive_entry_set_filetype(entry, AE_IFDIR); - } - } - } - return (r); -} - -static int -archive_read_format_tar_read_data(struct archive_read *a, - const void **buff, size_t *size, int64_t *offset) -{ - 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 && - tar->sparse_list->remaining == 0) { - p = tar->sparse_list; - tar->sparse_list = p->next; - free(p); - } - - if (tar->entry_bytes_unconsumed) { - __archive_read_consume(a, tar->entry_bytes_unconsumed); - tar->entry_bytes_unconsumed = 0; - } - - /* If we're at end of file, return EOF. */ - if (tar->sparse_list == NULL || - tar->entry_bytes_remaining == 0) { - if (__archive_read_consume(a, tar->entry_padding) < 0) - return (ARCHIVE_FATAL); - tar->entry_padding = 0; - *buff = NULL; - *size = 0; - *offset = tar->realsize; - return (ARCHIVE_EOF); - } - - *buff = __archive_read_ahead(a, 1, &bytes_read); - if (bytes_read < 0) - return (ARCHIVE_FATAL); - if (*buff == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated tar archive"); - return (ARCHIVE_FATAL); - } - if (bytes_read > tar->entry_bytes_remaining) - bytes_read = (ssize_t)tar->entry_bytes_remaining; - /* Don't read more than is available in the - * current sparse block. */ - if (tar->sparse_list->remaining < bytes_read) - bytes_read = (ssize_t)tar->sparse_list->remaining; - *size = bytes_read; - *offset = tar->sparse_list->offset; - tar->sparse_list->remaining -= bytes_read; - tar->sparse_list->offset += bytes_read; - tar->entry_bytes_remaining -= bytes_read; - tar->entry_bytes_unconsumed = bytes_read; - - if (!tar->sparse_list->hole) - return (ARCHIVE_OK); - /* Current is hole data and skip this. */ - } -} - -static int -archive_read_format_tar_skip(struct archive_read *a) -{ - int64_t bytes_skipped; - int64_t request; - struct sparse_block *p; - struct tar* tar; - - tar = (struct tar *)(a->format->data); - - /* Do not consume the hole of a sparse file. */ - request = 0; - for (p = tar->sparse_list; p != NULL; p = p->next) { - if (!p->hole) { - if (p->remaining >= INT64_MAX - request) { - return ARCHIVE_FATAL; - } - request += p->remaining; - } - } - if (request > tar->entry_bytes_remaining) - request = tar->entry_bytes_remaining; - request += tar->entry_padding + tar->entry_bytes_unconsumed; - - bytes_skipped = __archive_read_consume(a, request); - if (bytes_skipped < 0) - return (ARCHIVE_FATAL); - - tar->entry_bytes_remaining = 0; - tar->entry_bytes_unconsumed = 0; - tar->entry_padding = 0; - - /* Free the sparse list. */ - gnu_clear_sparse_list(tar); - - return (ARCHIVE_OK); -} - -/* - * This function recursively interprets all of the headers associated - * with a single entry. - */ -static int -tar_read_header(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, size_t *unconsumed) -{ - ssize_t bytes; - int err; - const char *h; - const struct archive_entry_header_ustar *header; - const struct archive_entry_header_gnutar *gnuheader; - - /* Loop until we find a workable header record. */ - for (;;) { - tar_flush_unconsumed(a, unconsumed); - - /* Read 512-byte header record */ - h = __archive_read_ahead(a, 512, &bytes); - if (bytes < 0) - return ((int)bytes); - if (bytes == 0) { /* EOF at a block boundary. */ - /* Some writers do omit the block of nulls. */ - return (ARCHIVE_EOF); - } - if (bytes < 512) { /* Short block at EOF; this is bad. */ - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated tar archive"); - return (ARCHIVE_FATAL); - } - *unconsumed = 512; - - /* Header is workable if it's not an end-of-archive mark. */ - if (h[0] != 0 || !archive_block_is_null(h)) - break; - - /* Ensure format is set for archives with only null blocks. */ - if (a->archive.archive_format_name == NULL) { - a->archive.archive_format = ARCHIVE_FORMAT_TAR; - a->archive.archive_format_name = "tar"; - } - - if (!tar->read_concatenated_archives) { - /* Try to consume a second all-null record, as well. */ - tar_flush_unconsumed(a, unconsumed); - h = __archive_read_ahead(a, 512, NULL); - if (h != NULL && h[0] == 0 && archive_block_is_null(h)) - __archive_read_consume(a, 512); - archive_clear_error(&a->archive); - return (ARCHIVE_EOF); - } - - /* - * We're reading concatenated archives, ignore this block and - * loop to get the next. - */ - } - - /* - * Note: If the checksum fails and we return ARCHIVE_RETRY, - * then the client is likely to just retry. This is a very - * crude way to search for the next valid header! - * - * TODO: Improve this by implementing a real header scan. - */ - if (!checksum(a, h)) { - tar_flush_unconsumed(a, unconsumed); - archive_set_error(&a->archive, EINVAL, "Damaged tar archive"); - return (ARCHIVE_RETRY); /* Retryable: Invalid header */ - } - - if (++tar->header_recursion_depth > 32) { - tar_flush_unconsumed(a, unconsumed); - archive_set_error(&a->archive, EINVAL, "Too many special headers"); - return (ARCHIVE_WARN); - } - - /* Determine the format variant. */ - header = (const struct archive_entry_header_ustar *)h; - - switch(header->typeflag[0]) { - case 'A': /* Solaris tar ACL */ - a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; - a->archive.archive_format_name = "Solaris tar"; - err = header_Solaris_ACL(a, tar, entry, h, unconsumed); - break; - case 'g': /* POSIX-standard 'g' header. */ - a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; - a->archive.archive_format_name = "POSIX pax interchange format"; - err = header_pax_global(a, tar, entry, h, unconsumed); - if (err == ARCHIVE_EOF) - return (err); - break; - case 'K': /* Long link name (GNU tar, others) */ - err = header_longlink(a, tar, entry, h, unconsumed); - break; - case 'L': /* Long filename (GNU tar, others) */ - err = header_longname(a, tar, entry, h, unconsumed); - break; - case 'V': /* GNU volume header */ - err = header_volume(a, tar, entry, h, unconsumed); - break; - case 'X': /* Used by SUN tar; same as 'x'. */ - a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; - a->archive.archive_format_name = - "POSIX pax interchange format (Sun variant)"; - err = header_pax_extensions(a, tar, entry, h, unconsumed); - break; - case 'x': /* POSIX-standard 'x' header. */ - a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; - a->archive.archive_format_name = "POSIX pax interchange format"; - err = header_pax_extensions(a, tar, entry, h, unconsumed); - break; - default: - gnuheader = (const struct archive_entry_header_gnutar *)h; - if (memcmp(gnuheader->magic, "ustar \0", 8) == 0) { - a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; - a->archive.archive_format_name = "GNU tar format"; - err = header_gnutar(a, tar, entry, h, unconsumed); - } else if (memcmp(header->magic, "ustar", 5) == 0) { - if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) { - a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; - a->archive.archive_format_name = "POSIX ustar format"; - } - err = header_ustar(a, tar, entry, h); - } else { - a->archive.archive_format = ARCHIVE_FORMAT_TAR; - a->archive.archive_format_name = "tar (non-POSIX)"; - err = header_old_tar(a, tar, entry, h); - } - } - if (err == ARCHIVE_FATAL) - return (err); - - tar_flush_unconsumed(a, unconsumed); - - h = NULL; - header = NULL; - - --tar->header_recursion_depth; - /* Yuck. Apple's design here ends up storing long pathname - * extensions for both the AppleDouble extension entry and the - * regular entry. - */ - if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) && - tar->header_recursion_depth == 0 && - tar->process_mac_extensions) { - int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed); - if (err2 < err) - err = err2; - } - - /* We return warnings or success as-is. Anything else is fatal. */ - if (err == ARCHIVE_WARN || err == ARCHIVE_OK) { - if (tar->sparse_gnu_pending) { - if (tar->sparse_gnu_major == 1 && - tar->sparse_gnu_minor == 0) { - ssize_t bytes_read; - - tar->sparse_gnu_pending = 0; - /* Read initial sparse map. */ - bytes_read = gnu_sparse_10_read(a, tar, unconsumed); - if (bytes_read < 0) - return ((int)bytes_read); - tar->entry_bytes_remaining -= bytes_read; - } else { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Unrecognized GNU sparse file format"); - return (ARCHIVE_WARN); - } - tar->sparse_gnu_pending = 0; - } - return (err); - } - if (err == ARCHIVE_EOF) - /* EOF when recursively reading a header is bad. */ - archive_set_error(&a->archive, EINVAL, "Damaged tar archive"); - return (ARCHIVE_FATAL); -} - -/* - * Return true if block checksum is correct. - */ -static int -checksum(struct archive_read *a, const void *h) -{ - const unsigned char *bytes; - const struct archive_entry_header_ustar *header; - int check, sum; - size_t i; - - (void)a; /* UNUSED */ - bytes = (const unsigned char *)h; - header = (const struct archive_entry_header_ustar *)h; - - /* Checksum field must hold an octal number */ - for (i = 0; i < sizeof(header->checksum); ++i) { - char c = header->checksum[i]; - if (c != ' ' && c != '\0' && (c < '0' || c > '7')) - return 0; - } - - /* - * Test the checksum. Note that POSIX specifies _unsigned_ - * bytes for this calculation. - */ - sum = (int)tar_atol(header->checksum, sizeof(header->checksum)); - check = 0; - for (i = 0; i < 148; i++) - check += (unsigned char)bytes[i]; - for (; i < 156; i++) - check += 32; - for (; i < 512; i++) - check += (unsigned char)bytes[i]; - if (sum == check) - return (1); - - /* - * Repeat test with _signed_ bytes, just in case this archive - * was created by an old BSD, Solaris, or HP-UX tar with a - * broken checksum calculation. - */ - check = 0; - for (i = 0; i < 148; i++) - check += (signed char)bytes[i]; - for (; i < 156; i++) - check += 32; - for (; i < 512; i++) - check += (signed char)bytes[i]; - if (sum == check) - return (1); - - return (0); -} - -/* - * Return true if this block contains only nulls. - */ -static int -archive_block_is_null(const char *p) -{ - unsigned i; - - for (i = 0; i < 512; i++) - if (*p++) - return (0); - return (1); -} - -/* - * Interpret 'A' Solaris ACL header - */ -static int -header_Solaris_ACL(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - const struct archive_entry_header_ustar *header; - size_t size; - int err, acl_type; - int64_t type; - char *acl, *p; - - /* - * read_body_to_string adds a NUL terminator, but we need a little - * more to make sure that we don't overrun acl_text later. - */ - header = (const struct archive_entry_header_ustar *)h; - size = (size_t)tar_atol(header->size, sizeof(header->size)); - err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed); - if (err != ARCHIVE_OK) - return (err); - - /* Recursively read next header */ - err = tar_read_header(a, tar, entry, unconsumed); - if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) - return (err); - - /* TODO: Examine the first characters to see if this - * is an AIX ACL descriptor. We'll likely never support - * them, but it would be polite to recognize and warn when - * we do see them. */ - - /* Leading octal number indicates ACL type and number of entries. */ - p = acl = tar->acl_text.s; - type = 0; - while (*p != '\0' && p < acl + size) { - if (*p < '0' || *p > '7') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (invalid digit)"); - return(ARCHIVE_WARN); - } - type <<= 3; - type += *p - '0'; - if (type > 077777777) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (count too large)"); - return (ARCHIVE_WARN); - } - p++; - } - switch ((int)type & ~0777777) { - case 01000000: - /* POSIX.1e ACL */ - acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - break; - case 03000000: - /* NFSv4 ACL */ - acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4; - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (unsupported type %o)", - (int)type); - return (ARCHIVE_WARN); - } - p++; - - if (p >= acl + size) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (body overflow)"); - return(ARCHIVE_WARN); - } - - /* ACL text is null-terminated; find the end. */ - size -= (p - acl); - acl = p; - - while (*p != '\0' && p < acl + size) - p++; - - if (tar->sconv_acl == NULL) { - tar->sconv_acl = archive_string_conversion_from_charset( - &(a->archive), "UTF-8", 1); - if (tar->sconv_acl == NULL) - return (ARCHIVE_FATAL); - } - archive_strncpy(&(tar->localname), acl, p - acl); - err = archive_acl_from_text_l(archive_entry_acl(entry), - tar->localname.s, acl_type, tar->sconv_acl); - if (err != ARCHIVE_OK) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for ACL"); - } else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (unparsable)"); - } - return (err); -} - -/* - * Interpret 'K' long linkname header. - */ -static int -header_longlink(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - int err; - - err = read_body_to_string(a, tar, &(tar->longlink), h, unconsumed); - if (err != ARCHIVE_OK) - return (err); - err = tar_read_header(a, tar, entry, unconsumed); - if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) - return (err); - /* Set symlink if symlink already set, else hardlink. */ - archive_entry_copy_link(entry, tar->longlink.s); - return (ARCHIVE_OK); -} - -static int -set_conversion_failed_error(struct archive_read *a, - struct archive_string_conv *sconv, const char *name) -{ - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for %s", name); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "%s can't be converted from %s to current locale.", - name, archive_string_conversion_charset_name(sconv)); - return (ARCHIVE_WARN); -} - -/* - * Interpret 'L' long filename header. - */ -static int -header_longname(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - int err; - - err = read_body_to_string(a, tar, &(tar->longname), h, unconsumed); - if (err != ARCHIVE_OK) - return (err); - /* Read and parse "real" header, then override name. */ - err = tar_read_header(a, tar, entry, unconsumed); - if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) - return (err); - if (archive_entry_copy_pathname_l(entry, tar->longname.s, - archive_strlen(&(tar->longname)), tar->sconv) != 0) - err = set_conversion_failed_error(a, tar->sconv, "Pathname"); - return (err); -} - - -/* - * Interpret 'V' GNU tar volume header. - */ -static int -header_volume(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - (void)h; - - /* Just skip this and read the next header. */ - return (tar_read_header(a, tar, entry, unconsumed)); -} - -/* - * Read body of an archive entry into an archive_string object. - */ -static int -read_body_to_string(struct archive_read *a, struct tar *tar, - struct archive_string *as, const void *h, size_t *unconsumed) -{ - int64_t size; - const struct archive_entry_header_ustar *header; - const void *src; - - (void)tar; /* UNUSED */ - header = (const struct archive_entry_header_ustar *)h; - size = tar_atol(header->size, sizeof(header->size)); - if ((size > 1048576) || (size < 0)) { - archive_set_error(&a->archive, EINVAL, - "Special header too large"); - return (ARCHIVE_FATAL); - } - - /* Fail if we can't make our buffer big enough. */ - if (archive_string_ensure(as, (size_t)size+1) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "No memory"); - return (ARCHIVE_FATAL); - } - - tar_flush_unconsumed(a, unconsumed); - - /* Read the body into the string. */ - *unconsumed = (size_t)((size + 511) & ~ 511); - src = __archive_read_ahead(a, *unconsumed, NULL); - if (src == NULL) { - *unconsumed = 0; - return (ARCHIVE_FATAL); - } - memcpy(as->s, src, (size_t)size); - as->s[size] = '\0'; - as->length = (size_t)size; - return (ARCHIVE_OK); -} - -/* - * Parse out common header elements. - * - * This would be the same as header_old_tar, except that the - * filename is handled slightly differently for old and POSIX - * entries (POSIX entries support a 'prefix'). This factoring - * allows header_old_tar and header_ustar - * to handle filenames differently, while still putting most of the - * common parsing into one place. - */ -static int -header_common(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h) -{ - const struct archive_entry_header_ustar *header; - char tartype; - int err = ARCHIVE_OK; - - header = (const struct archive_entry_header_ustar *)h; - if (header->linkname[0]) - archive_strncpy(&(tar->entry_linkpath), - header->linkname, sizeof(header->linkname)); - else - archive_string_empty(&(tar->entry_linkpath)); - - /* Parse out the numeric fields (all are octal) */ - archive_entry_set_mode(entry, - (mode_t)tar_atol(header->mode, sizeof(header->mode))); - archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid))); - archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid))); - tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size)); - if (tar->entry_bytes_remaining < 0) { - tar->entry_bytes_remaining = 0; - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Tar entry has negative size"); - return (ARCHIVE_FATAL); - } - if (tar->entry_bytes_remaining == INT64_MAX) { - /* Note: tar_atol returns INT64_MAX on overflow */ - tar->entry_bytes_remaining = 0; - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Tar entry size overflow"); - return (ARCHIVE_FATAL); - } - tar->realsize = tar->entry_bytes_remaining; - archive_entry_set_size(entry, tar->entry_bytes_remaining); - archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0); - - /* Handle the tar type flag appropriately. */ - tartype = header->typeflag[0]; - - switch (tartype) { - case '1': /* Hard link */ - if (archive_entry_copy_hardlink_l(entry, tar->entry_linkpath.s, - archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, - "Linkname"); - if (err == ARCHIVE_FATAL) - return (err); - } - /* - * The following may seem odd, but: Technically, tar - * does not store the file type for a "hard link" - * entry, only the fact that it is a hard link. So, I - * leave the type zero normally. But, pax interchange - * format allows hard links to have data, which - * implies that the underlying entry is a regular - * file. - */ - if (archive_entry_size(entry) > 0) - archive_entry_set_filetype(entry, AE_IFREG); - - /* - * A tricky point: Traditionally, tar readers have - * ignored the size field when reading hardlink - * entries, and some writers put non-zero sizes even - * though the body is empty. POSIX blessed this - * convention in the 1988 standard, but broke with - * this tradition in 2001 by permitting hardlink - * entries to store valid bodies in pax interchange - * format, but not in ustar format. Since there is no - * hard and fast way to distinguish pax interchange - * from earlier archives (the 'x' and 'g' entries are - * optional, after all), we need a heuristic. - */ - if (archive_entry_size(entry) == 0) { - /* If the size is already zero, we're done. */ - } else if (a->archive.archive_format - == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) { - /* Definitely pax extended; must obey hardlink size. */ - } else if (a->archive.archive_format == ARCHIVE_FORMAT_TAR - || a->archive.archive_format == ARCHIVE_FORMAT_TAR_GNUTAR) - { - /* Old-style or GNU tar: we must ignore the size. */ - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - } else if (archive_read_format_tar_bid(a, 50) > 50) { - /* - * We don't know if it's pax: If the bid - * function sees a valid ustar header - * immediately following, then let's ignore - * the hardlink size. - */ - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - } - /* - * TODO: There are still two cases I'd like to handle: - * = a ustar non-pax archive with a hardlink entry at - * end-of-archive. (Look for block of nulls following?) - * = a pax archive that has not seen any pax headers - * and has an entry which is a hardlink entry storing - * a body containing an uncompressed tar archive. - * The first is worth addressing; I don't see any reliable - * way to deal with the second possibility. - */ - break; - case '2': /* Symlink */ - archive_entry_set_filetype(entry, AE_IFLNK); - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - if (archive_entry_copy_symlink_l(entry, tar->entry_linkpath.s, - archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, - "Linkname"); - if (err == ARCHIVE_FATAL) - return (err); - } - break; - case '3': /* Character device */ - archive_entry_set_filetype(entry, AE_IFCHR); - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - break; - case '4': /* Block device */ - archive_entry_set_filetype(entry, AE_IFBLK); - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - break; - case '5': /* Dir */ - archive_entry_set_filetype(entry, AE_IFDIR); - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - break; - case '6': /* FIFO device */ - archive_entry_set_filetype(entry, AE_IFIFO); - archive_entry_set_size(entry, 0); - tar->entry_bytes_remaining = 0; - break; - case 'D': /* GNU incremental directory type */ - /* - * No special handling is actually required here. - * It might be nice someday to preprocess the file list and - * provide it to the client, though. - */ - archive_entry_set_filetype(entry, AE_IFDIR); - break; - case 'M': /* GNU "Multi-volume" (remainder of file from last archive)*/ - /* - * As far as I can tell, this is just like a regular file - * entry, except that the contents should be _appended_ to - * the indicated file at the indicated offset. This may - * require some API work to fully support. - */ - break; - case 'N': /* Old GNU "long filename" entry. */ - /* The body of this entry is a script for renaming - * previously-extracted entries. Ugh. It will never - * be supported by libarchive. */ - archive_entry_set_filetype(entry, AE_IFREG); - break; - case 'S': /* GNU sparse files */ - /* - * Sparse files are really just regular files with - * sparse information in the extended area. - */ - /* FALLTHROUGH */ - case '0': - /* - * Enable sparse file "read" support only for regular - * files and explicit GNU sparse files. However, we - * don't allow non-standard file types to be sparse. - */ - tar->sparse_allowed = 1; - /* FALLTHROUGH */ - default: /* Regular file and non-standard types */ - /* - * Per POSIX: non-recognized types should always be - * treated as regular files. - */ - archive_entry_set_filetype(entry, AE_IFREG); - break; - } - return (err); -} - -/* - * Parse out header elements for "old-style" tar archives. - */ -static int -header_old_tar(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h) -{ - const struct archive_entry_header_ustar *header; - int err = ARCHIVE_OK, err2; - - /* Copy filename over (to ensure null termination). */ - header = (const struct archive_entry_header_ustar *)h; - if (archive_entry_copy_pathname_l(entry, - header->name, sizeof(header->name), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Pathname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - /* Grab rest of common fields */ - err2 = header_common(a, tar, entry, h); - if (err > err2) - err = err2; - - tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); - return (err); -} - -/* - * Read a Mac AppleDouble-encoded blob of file metadata, - * if there is one. - */ -static int -read_mac_metadata_blob(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - int64_t size; - const void *data; - const char *p, *name; - const wchar_t *wp, *wname; - - (void)h; /* UNUSED */ - - wname = wp = archive_entry_pathname_w(entry); - if (wp != NULL) { - /* Find the last path element. */ - for (; *wp != L'\0'; ++wp) { - if (wp[0] == '/' && wp[1] != L'\0') - wname = wp + 1; - } - /* - * If last path element starts with "._", then - * this is a Mac extension. - */ - if (wname[0] != L'.' || wname[1] != L'_' || wname[2] == L'\0') - return ARCHIVE_OK; - } 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; - } - /* - * If last path element starts with "._", then - * this is a Mac extension. - */ - if (name[0] != '.' || name[1] != '_' || name[2] == '\0') - return ARCHIVE_OK; - } - - /* Read the body as a Mac OS metadata blob. */ - size = archive_entry_size(entry); - - /* - * TODO: Look beyond the body here to peek at the next header. - * If it's a regular header (not an extension header) - * that has the wrong name, just return the current - * entry as-is, without consuming the body here. - * That would reduce the risk of us mis-identifying - * an ordinary file that just happened to have - * a name starting with "._". - * - * Q: Is the above idea really possible? Even - * when there are GNU or pax extension entries? - */ - data = __archive_read_ahead(a, (size_t)size, NULL); - if (data == NULL) { - *unconsumed = 0; - return (ARCHIVE_FATAL); - } - archive_entry_copy_mac_metadata(entry, data, (size_t)size); - *unconsumed = (size_t)((size + 511) & ~ 511); - tar_flush_unconsumed(a, unconsumed); - return (tar_read_header(a, tar, entry, unconsumed)); -} - -/* - * Parse a file header for a pax extended archive entry. - */ -static int -header_pax_global(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - int err; - - err = read_body_to_string(a, tar, &(tar->pax_global), h, unconsumed); - if (err != ARCHIVE_OK) - return (err); - err = tar_read_header(a, tar, entry, unconsumed); - return (err); -} - -static int -header_pax_extensions(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - int err, err2; - - err = read_body_to_string(a, tar, &(tar->pax_header), h, unconsumed); - if (err != ARCHIVE_OK) - return (err); - - /* Parse the next header. */ - err = tar_read_header(a, tar, entry, unconsumed); - if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) - return (err); - - /* - * TODO: Parse global/default options into 'entry' struct here - * before handling file-specific options. - * - * This design (parse standard header, then overwrite with pax - * extended attribute data) usually works well, but isn't ideal; - * it would be better to parse the pax extended attributes first - * and then skip any fields in the standard header that were - * defined in the pax header. - */ - err2 = pax_header(a, tar, entry, &tar->pax_header); - err = err_combine(err, err2); - tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); - return (err); -} - - -/* - * Parse a file header for a Posix "ustar" archive entry. This also - * handles "pax" or "extended ustar" entries. - */ -static int -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. */ - as = &(tar->entry_pathname); - 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)); - } else { - archive_strncpy(as, header->name, sizeof(header->name)); - } - if (archive_entry_copy_pathname_l(entry, as->s, archive_strlen(as), - tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Pathname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - /* Handle rest of common fields. */ - r = header_common(a, tar, entry, h); - if (r == ARCHIVE_FATAL) - return (r); - if (r < err) - err = r; - - /* Handle POSIX ustar fields. */ - if (archive_entry_copy_uname_l(entry, - header->uname, sizeof(header->uname), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Uname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - if (archive_entry_copy_gname_l(entry, - header->gname, sizeof(header->gname), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Gname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - /* Parse out device numbers only for char and block specials. */ - if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { - archive_entry_set_rdevmajor(entry, (dev_t) - tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); - archive_entry_set_rdevminor(entry, (dev_t) - tar_atol(header->rdevminor, sizeof(header->rdevminor))); - } - - tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); - - return (err); -} - - -/* - * Parse the pax extended attributes record. - * - * Returns non-zero if there's an error in the data. - */ -static int -pax_header(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, struct archive_string *in_as) -{ - size_t attr_length, l, line_length, value_length; - char *p; - char *key, *value; - struct archive_string *as; - struct archive_string_conv *sconv; - int err, err2; - char *attr = in_as->s; - - attr_length = in_as->length; - tar->pax_hdrcharset_binary = 0; - archive_string_empty(&(tar->entry_gname)); - archive_string_empty(&(tar->entry_linkpath)); - archive_string_empty(&(tar->entry_pathname)); - archive_string_empty(&(tar->entry_pathname_override)); - archive_string_empty(&(tar->entry_uname)); - err = ARCHIVE_OK; - while (attr_length > 0) { - /* Parse decimal length field at start of line. */ - line_length = 0; - l = attr_length; - p = attr; /* Record start of line. */ - while (l>0) { - if (*p == ' ') { - p++; - l--; - break; - } - if (*p < '0' || *p > '9') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Ignoring malformed pax extended attributes"); - return (ARCHIVE_WARN); - } - line_length *= 10; - line_length += *p - '0'; - if (line_length > 999999) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Rejecting pax extended attribute > 1MB"); - return (ARCHIVE_WARN); - } - p++; - l--; - } - - /* - * Parsed length must be no bigger than available data, - * at least 1, and the last character of the line must - * be '\n'. - */ - if (line_length > attr_length - || line_length < 1 - || attr[line_length - 1] != '\n') - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Ignoring malformed pax extended attribute"); - return (ARCHIVE_WARN); - } - - /* Null-terminate the line. */ - attr[line_length - 1] = '\0'; - - /* Find end of key and null terminate it. */ - key = p; - if (key[0] == '=') - return (-1); - while (*p && *p != '=') - ++p; - if (*p == '\0') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid pax extended attributes"); - return (ARCHIVE_WARN); - } - *p = '\0'; - - value = p + 1; - - /* Some values may be binary data */ - value_length = attr + line_length - 1 - value; - - /* Identify this attribute and set it in the entry. */ - err2 = pax_attribute(a, tar, entry, key, value, value_length); - if (err2 == ARCHIVE_FATAL) - return (err2); - err = err_combine(err, err2); - - /* Skip to next line */ - attr += line_length; - attr_length -= line_length; - } - - /* - * PAX format uses UTF-8 as default charset for its metadata - * unless hdrcharset=BINARY is present in its header. - * We apply the charset specified by the hdrcharset option only - * when the hdrcharset attribute(in PAX header) is BINARY because - * we respect the charset described in PAX header and BINARY also - * means that metadata(filename,uname and gname) character-set - * is unknown. - */ - if (tar->pax_hdrcharset_binary) - sconv = tar->opt_sconv; - else { - sconv = archive_string_conversion_from_charset( - &(a->archive), "UTF-8", 1); - if (sconv == NULL) - return (ARCHIVE_FATAL); - if (tar->compat_2x) - archive_string_conversion_set_opt(sconv, - SCONV_SET_OPT_UTF8_LIBARCHIVE2X); - } - - if (archive_strlen(&(tar->entry_gname)) > 0) { - if (archive_entry_copy_gname_l(entry, tar->entry_gname.s, - archive_strlen(&(tar->entry_gname)), sconv) != 0) { - err = set_conversion_failed_error(a, sconv, "Gname"); - if (err == ARCHIVE_FATAL) - return (err); - /* Use a converted an original name. */ - archive_entry_copy_gname(entry, tar->entry_gname.s); - } - } - if (archive_strlen(&(tar->entry_linkpath)) > 0) { - if (archive_entry_copy_link_l(entry, tar->entry_linkpath.s, - archive_strlen(&(tar->entry_linkpath)), sconv) != 0) { - err = set_conversion_failed_error(a, sconv, "Linkname"); - if (err == ARCHIVE_FATAL) - return (err); - /* Use a converted an original name. */ - archive_entry_copy_link(entry, tar->entry_linkpath.s); - } - } - /* - * Some extensions (such as the GNU sparse file extensions) - * deliberately store a synthetic name under the regular 'path' - * attribute and the real file name under a different attribute. - * Since we're supposed to not care about the order, we - * have no choice but to store all of the various filenames - * we find and figure it all out afterwards. This is the - * figuring out part. - */ - as = NULL; - if (archive_strlen(&(tar->entry_pathname_override)) > 0) - as = &(tar->entry_pathname_override); - else if (archive_strlen(&(tar->entry_pathname)) > 0) - as = &(tar->entry_pathname); - if (as != NULL) { - if (archive_entry_copy_pathname_l(entry, as->s, - archive_strlen(as), sconv) != 0) { - err = set_conversion_failed_error(a, sconv, "Pathname"); - if (err == ARCHIVE_FATAL) - return (err); - /* Use a converted an original name. */ - archive_entry_copy_pathname(entry, as->s); - } - } - if (archive_strlen(&(tar->entry_uname)) > 0) { - if (archive_entry_copy_uname_l(entry, tar->entry_uname.s, - archive_strlen(&(tar->entry_uname)), sconv) != 0) { - err = set_conversion_failed_error(a, sconv, "Uname"); - if (err == ARCHIVE_FATAL) - return (err); - /* Use a converted an original name. */ - archive_entry_copy_uname(entry, tar->entry_uname.s); - } - } - return (err); -} - -static int -pax_attribute_xattr(struct archive_entry *entry, - const char *name, const char *value) -{ - char *name_decoded; - void *value_decoded; - size_t value_len; - - if (strlen(name) < 18 || (memcmp(name, "LIBARCHIVE.xattr.", 17)) != 0) - return 3; - - name += 17; - - /* URL-decode name */ - name_decoded = url_decode(name); - if (name_decoded == NULL) - return 2; - - /* Base-64 decode value */ - value_decoded = base64_decode(value, strlen(value), &value_len); - if (value_decoded == NULL) { - free(name_decoded); - return 1; - } - - archive_entry_xattr_add_entry(entry, name_decoded, - value_decoded, value_len); - - free(name_decoded); - free(value_decoded); - return 0; -} - -static int -pax_attribute_schily_xattr(struct archive_entry *entry, - const char *name, const char *value, size_t value_length) -{ - if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0) - return 1; - - name += 13; - - archive_entry_xattr_add_entry(entry, name, value, value_length); - - return 0; -} - -static int -pax_attribute_acl(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const char *value, int type) -{ - int r; - const char* errstr; - - switch (type) { - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - errstr = "SCHILY.acl.access"; - break; - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - errstr = "SCHILY.acl.default"; - break; - case ARCHIVE_ENTRY_ACL_TYPE_NFS4: - errstr = "SCHILY.acl.ace"; - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unknown ACL type: %d", type); - return(ARCHIVE_FATAL); - } - - if (tar->sconv_acl == NULL) { - tar->sconv_acl = - archive_string_conversion_from_charset( - &(a->archive), "UTF-8", 1); - if (tar->sconv_acl == NULL) - return (ARCHIVE_FATAL); - } - - r = archive_acl_from_text_l(archive_entry_acl(entry), value, type, - tar->sconv_acl); - if (r != ARCHIVE_OK) { - if (r == ARCHIVE_FATAL) { - archive_set_error(&a->archive, ENOMEM, - "%s %s", "Can't allocate memory for ", - errstr); - return (r); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr); - } - return (r); -} - -/* - * Parse a single key=value attribute. key/value pointers are - * assumed to point into reasonably long-lived storage. - * - * Note that POSIX reserves all-lowercase keywords. Vendor-specific - * extensions should always have keywords of the form "VENDOR.attribute" - * In particular, it's quite feasible to support many different - * vendor extensions here. I'm using "LIBARCHIVE" for extensions - * unique to this library. - * - * Investigate other vendor-specific extensions and see if - * any of them look useful. - */ -static int -pax_attribute(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const char *key, const char *value, size_t value_length) -{ - int64_t s; - long n; - int err = ARCHIVE_OK, r; - - if (value == NULL) - value = ""; /* Disable compiler warning; do not pass - * NULL pointer to strlen(). */ - switch (key[0]) { - case 'G': - /* Reject GNU.sparse.* headers on non-regular files. */ - if (strncmp(key, "GNU.sparse", 10) == 0 && - !tar->sparse_allowed) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Non-regular file cannot be sparse"); - return (ARCHIVE_FATAL); - } - - /* GNU "0.0" sparse pax format. */ - if (strcmp(key, "GNU.sparse.numblocks") == 0) { - tar->sparse_offset = -1; - tar->sparse_numbytes = -1; - tar->sparse_gnu_major = 0; - tar->sparse_gnu_minor = 0; - } - if (strcmp(key, "GNU.sparse.offset") == 0) { - tar->sparse_offset = tar_atol10(value, strlen(value)); - if (tar->sparse_numbytes != -1) { - if (gnu_add_sparse_entry(a, tar, - tar->sparse_offset, tar->sparse_numbytes) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - tar->sparse_offset = -1; - tar->sparse_numbytes = -1; - } - } - if (strcmp(key, "GNU.sparse.numbytes") == 0) { - tar->sparse_numbytes = tar_atol10(value, strlen(value)); - if (tar->sparse_numbytes != -1) { - if (gnu_add_sparse_entry(a, tar, - tar->sparse_offset, tar->sparse_numbytes) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - tar->sparse_offset = -1; - tar->sparse_numbytes = -1; - } - } - if (strcmp(key, "GNU.sparse.size") == 0) { - tar->realsize = tar_atol10(value, strlen(value)); - archive_entry_set_size(entry, tar->realsize); - tar->realsize_override = 1; - } - - /* GNU "0.1" sparse pax format. */ - if (strcmp(key, "GNU.sparse.map") == 0) { - tar->sparse_gnu_major = 0; - tar->sparse_gnu_minor = 1; - if (gnu_sparse_01_parse(a, tar, value) != ARCHIVE_OK) - return (ARCHIVE_WARN); - } - - /* GNU "1.0" sparse pax format */ - if (strcmp(key, "GNU.sparse.major") == 0) { - tar->sparse_gnu_major = (int)tar_atol10(value, strlen(value)); - tar->sparse_gnu_pending = 1; - } - if (strcmp(key, "GNU.sparse.minor") == 0) { - tar->sparse_gnu_minor = (int)tar_atol10(value, strlen(value)); - tar->sparse_gnu_pending = 1; - } - if (strcmp(key, "GNU.sparse.name") == 0) { - /* - * The real filename; when storing sparse - * files, GNU tar puts a synthesized name into - * the regular 'path' attribute in an attempt - * to limit confusion. ;-) - */ - archive_strcpy(&(tar->entry_pathname_override), value); - } - if (strcmp(key, "GNU.sparse.realsize") == 0) { - tar->realsize = tar_atol10(value, strlen(value)); - archive_entry_set_size(entry, tar->realsize); - tar->realsize_override = 1; - } - break; - case 'L': - /* Our extensions */ -/* TODO: Handle arbitrary extended attributes... */ -/* - if (strcmp(key, "LIBARCHIVE.xxxxxxx") == 0) - archive_entry_set_xxxxxx(entry, value); -*/ - if (strcmp(key, "LIBARCHIVE.creationtime") == 0) { - pax_time(value, &s, &n); - archive_entry_set_birthtime(entry, s, n); - } - if (memcmp(key, "LIBARCHIVE.xattr.", 17) == 0) - pax_attribute_xattr(entry, key, value); - break; - case 'S': - /* We support some keys used by the "star" archiver */ - if (strcmp(key, "SCHILY.acl.access") == 0) { - r = pax_attribute_acl(a, tar, entry, value, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - if (r == ARCHIVE_FATAL) - return (r); - } else if (strcmp(key, "SCHILY.acl.default") == 0) { - r = pax_attribute_acl(a, tar, entry, value, - ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); - if (r == ARCHIVE_FATAL) - return (r); - } else if (strcmp(key, "SCHILY.acl.ace") == 0) { - r = pax_attribute_acl(a, tar, entry, value, - ARCHIVE_ENTRY_ACL_TYPE_NFS4); - if (r == ARCHIVE_FATAL) - return (r); - } else if (strcmp(key, "SCHILY.devmajor") == 0) { - archive_entry_set_rdevmajor(entry, - (dev_t)tar_atol10(value, strlen(value))); - } else if (strcmp(key, "SCHILY.devminor") == 0) { - archive_entry_set_rdevminor(entry, - (dev_t)tar_atol10(value, strlen(value))); - } else if (strcmp(key, "SCHILY.fflags") == 0) { - archive_entry_copy_fflags_text(entry, value); - } else if (strcmp(key, "SCHILY.dev") == 0) { - archive_entry_set_dev(entry, - (dev_t)tar_atol10(value, strlen(value))); - } else if (strcmp(key, "SCHILY.ino") == 0) { - archive_entry_set_ino(entry, - tar_atol10(value, strlen(value))); - } else if (strcmp(key, "SCHILY.nlink") == 0) { - archive_entry_set_nlink(entry, (unsigned) - tar_atol10(value, strlen(value))); - } else if (strcmp(key, "SCHILY.realsize") == 0) { - tar->realsize = tar_atol10(value, strlen(value)); - tar->realsize_override = 1; - archive_entry_set_size(entry, tar->realsize); - } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) { - pax_attribute_schily_xattr(entry, key, value, - value_length); - } else if (strcmp(key, "SUN.holesdata") == 0) { - /* A Solaris extension for sparse. */ - r = solaris_sparse_parse(a, tar, entry, value); - if (r < err) { - if (r == ARCHIVE_FATAL) - return (r); - err = r; - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Parse error: SUN.holesdata"); - } - } - break; - case 'a': - if (strcmp(key, "atime") == 0) { - pax_time(value, &s, &n); - archive_entry_set_atime(entry, s, n); - } - break; - case 'c': - if (strcmp(key, "ctime") == 0) { - pax_time(value, &s, &n); - archive_entry_set_ctime(entry, s, n); - } else if (strcmp(key, "charset") == 0) { - /* TODO: Publish charset information in entry. */ - } else if (strcmp(key, "comment") == 0) { - /* TODO: Publish comment in entry. */ - } - break; - case 'g': - if (strcmp(key, "gid") == 0) { - archive_entry_set_gid(entry, - tar_atol10(value, strlen(value))); - } else if (strcmp(key, "gname") == 0) { - archive_strcpy(&(tar->entry_gname), value); - } - break; - case 'h': - if (strcmp(key, "hdrcharset") == 0) { - if (strcmp(value, "BINARY") == 0) - /* Binary mode. */ - tar->pax_hdrcharset_binary = 1; - else if (strcmp(value, "ISO-IR 10646 2000 UTF-8") == 0) - tar->pax_hdrcharset_binary = 0; - } - break; - case 'l': - /* pax interchange doesn't distinguish hardlink vs. symlink. */ - if (strcmp(key, "linkpath") == 0) { - archive_strcpy(&(tar->entry_linkpath), value); - } - break; - case 'm': - if (strcmp(key, "mtime") == 0) { - pax_time(value, &s, &n); - archive_entry_set_mtime(entry, s, n); - } - break; - case 'p': - if (strcmp(key, "path") == 0) { - archive_strcpy(&(tar->entry_pathname), value); - } - break; - case 'r': - /* POSIX has reserved 'realtime.*' */ - break; - case 's': - /* POSIX has reserved 'security.*' */ - /* Someday: if (strcmp(key, "security.acl") == 0) { ... } */ - if (strcmp(key, "size") == 0) { - /* "size" is the size of the data in the entry. */ - tar->entry_bytes_remaining - = tar_atol10(value, strlen(value)); - /* - * The "size" pax header keyword always overrides the - * "size" field in the tar header. - * GNU.sparse.realsize, GNU.sparse.size and - * SCHILY.realsize override this value. - */ - if (!tar->realsize_override) { - archive_entry_set_size(entry, - tar->entry_bytes_remaining); - tar->realsize - = tar->entry_bytes_remaining; - } - } - break; - case 'u': - if (strcmp(key, "uid") == 0) { - archive_entry_set_uid(entry, - tar_atol10(value, strlen(value))); - } else if (strcmp(key, "uname") == 0) { - archive_strcpy(&(tar->entry_uname), value); - } - break; - } - return (err); -} - - - -/* - * parse a decimal time value, which may include a fractional portion - */ -static void -pax_time(const char *p, int64_t *ps, long *pn) -{ - char digit; - int64_t s; - unsigned long l; - int sign; - int64_t limit, last_digit_limit; - - limit = INT64_MAX / 10; - last_digit_limit = INT64_MAX % 10; - - s = 0; - sign = 1; - if (*p == '-') { - sign = -1; - p++; - } - while (*p >= '0' && *p <= '9') { - digit = *p - '0'; - if (s > limit || - (s == limit && digit > last_digit_limit)) { - s = INT64_MAX; - break; - } - s = (s * 10) + digit; - ++p; - } - - *ps = s * sign; - - /* Calculate nanoseconds. */ - *pn = 0; - - if (*p != '.') - return; - - l = 100000000UL; - do { - ++p; - if (*p >= '0' && *p <= '9') - *pn += (*p - '0') * l; - else - break; - } while (l /= 10); -} - -/* - * Parse GNU tar header - */ -static int -header_gnutar(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) -{ - const struct archive_entry_header_gnutar *header; - int64_t t; - int err = ARCHIVE_OK; - - /* - * GNU header is like POSIX ustar, except 'prefix' is - * replaced with some other fields. This also means the - * filename is stored as in old-style archives. - */ - - /* Grab fields common to all tar variants. */ - err = header_common(a, tar, entry, h); - if (err == ARCHIVE_FATAL) - return (err); - - /* Copy filename over (to ensure null termination). */ - header = (const struct archive_entry_header_gnutar *)h; - if (archive_entry_copy_pathname_l(entry, - header->name, sizeof(header->name), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Pathname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - /* Fields common to ustar and GNU */ - /* XXX Can the following be factored out since it's common - * to ustar and gnu tar? Is it okay to move it down into - * header_common, perhaps? */ - if (archive_entry_copy_uname_l(entry, - header->uname, sizeof(header->uname), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Uname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - if (archive_entry_copy_gname_l(entry, - header->gname, sizeof(header->gname), tar->sconv) != 0) { - err = set_conversion_failed_error(a, tar->sconv, "Gname"); - if (err == ARCHIVE_FATAL) - return (err); - } - - /* Parse out device numbers only for char and block specials */ - if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { - archive_entry_set_rdevmajor(entry, (dev_t) - tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); - archive_entry_set_rdevminor(entry, (dev_t) - tar_atol(header->rdevminor, sizeof(header->rdevminor))); - } else - archive_entry_set_rdev(entry, 0); - - tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); - - /* Grab GNU-specific fields. */ - t = tar_atol(header->atime, sizeof(header->atime)); - if (t > 0) - archive_entry_set_atime(entry, t, 0); - t = tar_atol(header->ctime, sizeof(header->ctime)); - if (t > 0) - archive_entry_set_ctime(entry, t, 0); - - if (header->realsize[0] != 0) { - tar->realsize - = tar_atol(header->realsize, sizeof(header->realsize)); - archive_entry_set_size(entry, tar->realsize); - tar->realsize_override = 1; - } - - if (header->sparse[0].offset[0] != 0) { - if (gnu_sparse_old_read(a, tar, header, unconsumed) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } else { - if (header->isextended[0] != 0) { - /* XXX WTF? XXX */ - } - } - - return (err); -} - -static int -gnu_add_sparse_entry(struct archive_read *a, struct tar *tar, - int64_t offset, int64_t remaining) -{ - struct sparse_block *p; - - p = (struct sparse_block *)calloc(1, sizeof(*p)); - if (p == NULL) { - archive_set_error(&a->archive, ENOMEM, "Out of memory"); - return (ARCHIVE_FATAL); - } - if (tar->sparse_last != NULL) - tar->sparse_last->next = p; - else - tar->sparse_list = p; - tar->sparse_last = p; - if (remaining < 0 || offset < 0) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data"); - return (ARCHIVE_FATAL); - } - p->offset = offset; - p->remaining = remaining; - return (ARCHIVE_OK); -} - -static void -gnu_clear_sparse_list(struct tar *tar) -{ - struct sparse_block *p; - - while (tar->sparse_list != NULL) { - p = tar->sparse_list; - tar->sparse_list = p->next; - free(p); - } - tar->sparse_last = NULL; -} - -/* - * GNU tar old-format sparse data. - * - * GNU old-format sparse data is stored in a fixed-field - * format. Offset/size values are 11-byte octal fields (same - * format as 'size' field in ustart header). These are - * stored in the header, allocating subsequent header blocks - * as needed. Extending the header in this way is a pretty - * severe POSIX violation; this design has earned GNU tar a - * lot of criticism. - */ - -static int -gnu_sparse_old_read(struct archive_read *a, struct tar *tar, - const struct archive_entry_header_gnutar *header, size_t *unconsumed) -{ - ssize_t bytes_read; - const void *data; - struct extended { - struct gnu_sparse sparse[21]; - char isextended[1]; - char padding[7]; - }; - const struct extended *ext; - - if (gnu_sparse_old_parse(a, tar, header->sparse, 4) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - if (header->isextended[0] == 0) - return (ARCHIVE_OK); - - do { - tar_flush_unconsumed(a, unconsumed); - data = __archive_read_ahead(a, 512, &bytes_read); - if (bytes_read < 0) - return (ARCHIVE_FATAL); - if (bytes_read < 512) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated tar archive " - "detected while reading sparse file data"); - return (ARCHIVE_FATAL); - } - *unconsumed = 512; - ext = (const struct extended *)data; - if (gnu_sparse_old_parse(a, tar, ext->sparse, 21) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } while (ext->isextended[0] != 0); - if (tar->sparse_list != NULL) - tar->entry_offset = tar->sparse_list->offset; - return (ARCHIVE_OK); -} - -static int -gnu_sparse_old_parse(struct archive_read *a, struct tar *tar, - const struct gnu_sparse *sparse, int length) -{ - while (length > 0 && sparse->offset[0] != 0) { - if (gnu_add_sparse_entry(a, tar, - tar_atol(sparse->offset, sizeof(sparse->offset)), - tar_atol(sparse->numbytes, sizeof(sparse->numbytes))) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - sparse++; - length--; - } - return (ARCHIVE_OK); -} - -/* - * GNU tar sparse format 0.0 - * - * Beginning with GNU tar 1.15, sparse files are stored using - * information in the pax extended header. The GNU tar maintainers - * have gone through a number of variations in the process of working - * out this scheme; fortunately, they're all numbered. - * - * Sparse format 0.0 uses attribute GNU.sparse.numblocks to store the - * number of blocks, and GNU.sparse.offset/GNU.sparse.numbytes to - * store offset/size for each block. The repeated instances of these - * latter fields violate the pax specification (which frowns on - * duplicate keys), so this format was quickly replaced. - */ - -/* - * GNU tar sparse format 0.1 - * - * This version replaced the offset/numbytes attributes with - * a single "map" attribute that stored a list of integers. This - * format had two problems: First, the "map" attribute could be very - * long, which caused problems for some implementations. More - * importantly, the sparse data was lost when extracted by archivers - * that didn't recognize this extension. - */ - -static int -gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p) -{ - const char *e; - int64_t offset = -1, size = -1; - - for (;;) { - e = p; - while (*e != '\0' && *e != ',') { - if (*e < '0' || *e > '9') - return (ARCHIVE_WARN); - e++; - } - if (offset < 0) { - offset = tar_atol10(p, e - p); - if (offset < 0) - return (ARCHIVE_WARN); - } else { - size = tar_atol10(p, e - p); - if (size < 0) - return (ARCHIVE_WARN); - if (gnu_add_sparse_entry(a, tar, offset, size) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - offset = -1; - } - if (*e == '\0') - return (ARCHIVE_OK); - p = e + 1; - } -} - -/* - * GNU tar sparse format 1.0 - * - * The idea: The offset/size data is stored as a series of base-10 - * ASCII numbers prepended to the file data, so that dearchivers that - * don't support this format will extract the block map along with the - * data and a separate post-process can restore the sparseness. - * - * Unfortunately, GNU tar 1.16 had a bug that added unnecessary - * padding to the body of the file when using this format. GNU tar - * 1.17 corrected this bug without bumping the version number, so - * it's not possible to support both variants. This code supports - * the later variant at the expense of not supporting the former. - * - * This variant also replaced GNU.sparse.size with GNU.sparse.realsize - * and introduced the GNU.sparse.major/GNU.sparse.minor attributes. - */ - -/* - * Read the next line from the input, and parse it as a decimal - * integer followed by '\n'. Returns positive integer value or - * negative on error. - */ -static int64_t -gnu_sparse_10_atol(struct archive_read *a, struct tar *tar, - int64_t *remaining, size_t *unconsumed) -{ - int64_t l, limit, last_digit_limit; - 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 - * don't require this, but they should. - */ - do { - bytes_read = readline(a, tar, &p, - (ssize_t)tar_min(*remaining, 100), unconsumed); - if (bytes_read <= 0) - return (ARCHIVE_FATAL); - *remaining -= bytes_read; - } while (p[0] == '#'); - - l = 0; - while (bytes_read > 0) { - if (*p == '\n') - return (l); - if (*p < '0' || *p >= '0' + base) - return (ARCHIVE_WARN); - digit = *p - '0'; - if (l > limit || (l == limit && digit > last_digit_limit)) - l = INT64_MAX; /* Truncate on overflow. */ - else - l = (l * base) + digit; - p++; - bytes_read--; - } - /* TODO: Error message. */ - return (ARCHIVE_WARN); -} - -/* - * Returns length (in bytes) of the sparse data description - * that was read. - */ -static ssize_t -gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) -{ - ssize_t bytes_read; - int entries; - int64_t offset, size, to_skip, remaining; - - /* Clear out the existing sparse list. */ - gnu_clear_sparse_list(tar); - - remaining = tar->entry_bytes_remaining; - - /* Parse entries. */ - entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed); - if (entries < 0) - return (ARCHIVE_FATAL); - /* Parse the individual entries. */ - while (entries-- > 0) { - /* Parse offset/size */ - offset = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); - if (offset < 0) - return (ARCHIVE_FATAL); - size = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); - if (size < 0) - return (ARCHIVE_FATAL); - /* Add a new sparse entry. */ - if (gnu_add_sparse_entry(a, tar, offset, size) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - } - /* Skip rest of block... */ - tar_flush_unconsumed(a, unconsumed); - bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining); - to_skip = 0x1ff & -bytes_read; - /* Fail if tar->entry_bytes_remaing would get negative */ - if (to_skip > remaining) - return (ARCHIVE_FATAL); - if (to_skip != __archive_read_consume(a, to_skip)) - return (ARCHIVE_FATAL); - return ((ssize_t)(bytes_read + to_skip)); -} - -/* - * Solaris pax extension for a sparse file. This is recorded with the - * data and hole pairs. The way recording sparse information by Solaris' - * pax simply indicates where data and sparse are, so the stored contents - * consist of both data and hole. - */ -static int -solaris_sparse_parse(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const char *p) -{ - const char *e; - int64_t start, end; - int hole = 1; - - (void)entry; /* UNUSED */ - - end = 0; - if (*p == ' ') - p++; - else - return (ARCHIVE_WARN); - for (;;) { - e = p; - while (*e != '\0' && *e != ' ') { - if (*e < '0' || *e > '9') - return (ARCHIVE_WARN); - e++; - } - start = end; - end = tar_atol10(p, e - p); - if (end < 0) - return (ARCHIVE_WARN); - if (start < end) { - if (gnu_add_sparse_entry(a, tar, start, - end - start) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - tar->sparse_last->hole = hole; - } - if (*e == '\0') - return (ARCHIVE_OK); - p = e + 1; - hole = hole == 0; - } -} - -/*- - * Convert text->integer. - * - * Traditional tar formats (including POSIX) specify base-8 for - * all of the standard numeric fields. This is a significant limitation - * in practice: - * = file size is limited to 8GB - * = rdevmajor and rdevminor are limited to 21 bits - * = uid/gid are limited to 21 bits - * - * There are two workarounds for this: - * = pax extended headers, which use variable-length string fields - * = GNU tar and STAR both allow either base-8 or base-256 in - * most fields. The high bit is set to indicate base-256. - * - * On read, this implementation supports both extensions. - */ -static int64_t -tar_atol(const char *p, size_t char_cnt) -{ - /* - * Technically, GNU tar considers a field to be in base-256 - * only if the first byte is 0xff or 0x80. - */ - if (*p & 0x80) - return (tar_atol256(p, char_cnt)); - return (tar_atol8(p, char_cnt)); -} - -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - */ -static int64_t -tar_atol_base_n(const char *p, size_t char_cnt, int base) -{ - int64_t l, maxval, limit, last_digit_limit; - int digit, sign; - - maxval = INT64_MAX; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - - /* the pointer will not be dereferenced if char_cnt is zero - * due to the way the && operator is evaluated. - */ - while (char_cnt != 0 && (*p == ' ' || *p == '\t')) { - p++; - char_cnt--; - } - - sign = 1; - if (char_cnt != 0 && *p == '-') { - sign = -1; - p++; - char_cnt--; - - maxval = INT64_MIN; - limit = -(INT64_MIN / base); - last_digit_limit = INT64_MIN % base; - } - - l = 0; - if (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--; - } - } - return (sign < 0) ? -l : l; -} - -static int64_t -tar_atol8(const char *p, size_t char_cnt) -{ - return tar_atol_base_n(p, char_cnt, 8); -} - -static int64_t -tar_atol10(const char *p, size_t char_cnt) -{ - return tar_atol_base_n(p, char_cnt, 10); -} - -/* - * Parse a base-256 integer. This is just a variable-length - * twos-complement signed binary value in big-endian order, except - * that the high-order bit is ignored. The values here can be up to - * 12 bytes, so we need to be careful about overflowing 64-bit - * (8-byte) integers. - * - * This code unashamedly assumes that the local machine uses 8-bit - * bytes and twos-complement arithmetic. - */ -static int64_t -tar_atol256(const char *_p, size_t char_cnt) -{ - uint64_t l; - const unsigned char *p = (const unsigned char *)_p; - unsigned char c, neg; - - /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */ - c = *p; - if (c & 0x40) { - neg = 0xff; - c |= 0x80; - l = ~ARCHIVE_LITERAL_ULL(0); - } else { - neg = 0; - c &= 0x7f; - l = 0; - } - - /* If more than 8 bytes, check that we can ignore - * high-order bits without overflow. */ - while (char_cnt > sizeof(int64_t)) { - --char_cnt; - if (c != neg) - return neg ? INT64_MIN : INT64_MAX; - c = *++p; - } - - /* c is first byte that fits; if sign mismatch, return overflow */ - if ((c ^ neg) & 0x80) { - return neg ? INT64_MIN : INT64_MAX; - } - - /* Accumulate remaining bytes. */ - while (--char_cnt > 0) { - l = (l << 8) | c; - c = *++p; - } - l = (l << 8) | c; - /* Return signed twos-complement value. */ - return (int64_t)(l); -} - -/* - * Returns length of line (including trailing newline) - * or negative on error. 'start' argument is updated to - * point to first character of line. This avoids copying - * when possible. - */ -static ssize_t -readline(struct archive_read *a, struct tar *tar, const char **start, - ssize_t limit, size_t *unconsumed) -{ - ssize_t bytes_read; - ssize_t total_size = 0; - const void *t; - const char *s; - void *p; - - tar_flush_unconsumed(a, unconsumed); - - t = __archive_read_ahead(a, 1, &bytes_read); - if (bytes_read <= 0) - return (ARCHIVE_FATAL); - s = t; /* Start of line? */ - p = memchr(t, '\n', bytes_read); - /* If we found '\n' in the read buffer, return pointer to that. */ - if (p != NULL) { - bytes_read = 1 + ((const char *)p) - s; - if (bytes_read > limit) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Line too long"); - return (ARCHIVE_FATAL); - } - *unconsumed = bytes_read; - *start = s; - return (bytes_read); - } - *unconsumed = bytes_read; - /* Otherwise, we need to accumulate in a line buffer. */ - for (;;) { - if (total_size + bytes_read > limit) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Line too long"); - return (ARCHIVE_FATAL); - } - if (archive_string_ensure(&tar->line, total_size + bytes_read) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate working buffer"); - return (ARCHIVE_FATAL); - } - memcpy(tar->line.s + total_size, t, bytes_read); - tar_flush_unconsumed(a, unconsumed); - total_size += bytes_read; - /* If we found '\n', clean up and return. */ - if (p != NULL) { - *start = tar->line.s; - return (total_size); - } - /* Read some more. */ - t = __archive_read_ahead(a, 1, &bytes_read); - if (bytes_read <= 0) - return (ARCHIVE_FATAL); - s = t; /* Start of line? */ - p = memchr(t, '\n', bytes_read); - /* If we found '\n', trim the read. */ - if (p != NULL) { - bytes_read = 1 + ((const char *)p) - s; - } - *unconsumed = bytes_read; - } -} - -/* - * base64_decode - Base64 decode - * - * This accepts most variations of base-64 encoding, including: - * * with or without line breaks - * * with or without the final group padded with '=' or '_' characters - * (The most economical Base-64 variant does not pad the last group and - * omits line breaks; RFC1341 used for MIME requires both.) - */ -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]; - 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 = (char *)malloc(len - len / 4 + 1); - if (out == NULL) { - *out_len = 0; - return (NULL); - } - d = out; - - while (len > 0) { - /* Collect the next group of (up to) four characters. */ - int v = 0; - int group_size = 0; - while (group_size < 4 && len > 0) { - /* '=' or '_' padding indicates final group. */ - if (*src == '=' || *src == '_') { - len = 0; - break; - } - /* Skip illegal characters (including line breaks) */ - if (*src > 127 || *src < 32 - || decode_table[*src] == 0xff) { - len--; - src++; - continue; - } - v <<= 6; - v |= decode_table[*src++]; - len --; - group_size++; - } - /* Align a short group properly. */ - v <<= 6 * (4 - group_size); - /* Unpack the group we just collected. */ - switch (group_size) { - case 4: d[2] = v & 0xff; - /* FALLTHROUGH */ - case 3: d[1] = (v >> 8) & 0xff; - /* FALLTHROUGH */ - case 2: d[0] = (v >> 16) & 0xff; - break; - case 1: /* this is invalid! */ - break; - } - d += group_size * 3 / 4; - } - - *out_len = d - out; - return (out); -} - -static char * -url_decode(const char *in) -{ - char *out, *d; - const char *s; - - out = (char *)malloc(strlen(in) + 1); - if (out == NULL) - return (NULL); - for (s = in, d = out; *s != '\0'; ) { - if (s[0] == '%' && s[1] != '\0' && s[2] != '\0') { - /* Try to convert % escape */ - int digit1 = tohex(s[1]); - int digit2 = tohex(s[2]); - if (digit1 >= 0 && digit2 >= 0) { - /* Looks good, consume three chars */ - s += 3; - /* Convert output */ - *d++ = ((digit1 << 4) | digit2); - continue; - } - /* Else fall through and treat '%' as normal char */ - } - *d++ = *s++; - } - *d = '\0'; - return (out); -} - -static int -tohex(int c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - else if (c >= 'A' && c <= 'F') - return (c - 'A' + 10); - else if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - else - return (-1); -} diff --git a/3rdparty/libarchive/libarchive/archive_string.c b/3rdparty/libarchive/libarchive/archive_string.c deleted file mode 100644 index 5ae09b62..00000000 --- a/3rdparty/libarchive/libarchive/archive_string.c +++ /dev/null @@ -1,4207 +0,0 @@ -/*- - * Copyright (c) 2003-2011 Tim Kientzle - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33:22Z kientzle $"); - -/* - * Basic resizable string support, to simplify manipulating arbitrary-sized - * strings while minimizing heap activity. - * - * In particular, the buffer used by a string object is only grown, it - * never shrinks, so you can clear and reuse the same string object - * without incurring additional memory allocations. - */ - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_ICONV_H -#include -#endif -#ifdef HAVE_LANGINFO_H -#include -#endif -#ifdef HAVE_LOCALCHARSET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#include -#endif - -#include "archive_endian.h" -#include "archive_private.h" -#include "archive_string.h" -#include "archive_string_composition.h" - -#if !defined(HAVE_WMEMCPY) && !defined(wmemcpy) -#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) -#endif - -#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove) -#define wmemmove(a,b,i) (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t)) -#endif - -struct archive_string_conv { - struct archive_string_conv *next; - char *from_charset; - char *to_charset; - unsigned from_cp; - unsigned to_cp; - /* Set 1 if from_charset and to_charset are the same. */ - int same; - int flag; -#define SCONV_TO_CHARSET 1 /* MBS is being converted to specified - * charset. */ -#define SCONV_FROM_CHARSET (1<<1) /* MBS is being converted from - * specified charset. */ -#define SCONV_BEST_EFFORT (1<<2) /* Copy at least ASCII code. */ -#define SCONV_WIN_CP (1<<3) /* Use Windows API for converting - * MBS. */ -#define SCONV_UTF8_LIBARCHIVE_2 (1<<4) /* Incorrect UTF-8 made by libarchive - * 2.x in the wrong assumption. */ -#define SCONV_NORMALIZATION_C (1<<6) /* Need normalization to be Form C. - * Before UTF-8 characters are actually - * processed. */ -#define SCONV_NORMALIZATION_D (1<<7) /* Need normalization to be Form D. - * Before UTF-8 characters are actually - * processed. - * Currently this only for MAC OS X. */ -#define SCONV_TO_UTF8 (1<<8) /* "to charset" side is UTF-8. */ -#define SCONV_FROM_UTF8 (1<<9) /* "from charset" side is UTF-8. */ -#define SCONV_TO_UTF16BE (1<<10) /* "to charset" side is UTF-16BE. */ -#define SCONV_FROM_UTF16BE (1<<11) /* "from charset" side is UTF-16BE. */ -#define SCONV_TO_UTF16LE (1<<12) /* "to charset" side is UTF-16LE. */ -#define SCONV_FROM_UTF16LE (1<<13) /* "from charset" side is UTF-16LE. */ -#define SCONV_TO_UTF16 (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE) -#define SCONV_FROM_UTF16 (SCONV_FROM_UTF16BE | SCONV_FROM_UTF16LE) - -#if HAVE_ICONV - iconv_t cd; - iconv_t cd_w;/* Use at archive_mstring on - * Windows. */ -#endif - /* A temporary buffer for normalization. */ - struct archive_string utftmp; - int (*converter[2])(struct archive_string *, const void *, size_t, - struct archive_string_conv *); - int nconverter; -}; - -#define CP_C_LOCALE 0 /* "C" locale only for this file. */ -#define CP_UTF16LE 1200 -#define CP_UTF16BE 1201 - -#define IS_HIGH_SURROGATE_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDBFF) -#define IS_LOW_SURROGATE_LA(uc) ((uc) >= 0xDC00 && (uc) <= 0xDFFF) -#define IS_SURROGATE_PAIR_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDFFF) -#define UNICODE_MAX 0x10FFFF -#define UNICODE_R_CHAR 0xFFFD /* Replacement character. */ -/* Set U+FFFD(Replacement character) in UTF-8. */ -static const char utf8_replacement_char[] = {0xef, 0xbf, 0xbd}; - -static struct archive_string_conv *find_sconv_object(struct archive *, - const char *, const char *); -static void add_sconv_object(struct archive *, struct archive_string_conv *); -static struct archive_string_conv *create_sconv_object(const char *, - const char *, unsigned, int); -static void free_sconv_object(struct archive_string_conv *); -static struct archive_string_conv *get_sconv_object(struct archive *, - const char *, const char *, int); -static unsigned make_codepage_from_charset(const char *); -static unsigned get_current_codepage(void); -static unsigned get_current_oemcp(void); -static size_t mbsnbytes(const void *, size_t); -static size_t utf16nbytes(const void *, size_t); -#if defined(_WIN32) && !defined(__CYGWIN__) -static int archive_wstring_append_from_mbs_in_codepage( - struct archive_wstring *, const char *, size_t, - struct archive_string_conv *); -static int archive_string_append_from_wcs_in_codepage(struct archive_string *, - const wchar_t *, size_t, struct archive_string_conv *); -static int is_big_endian(void); -static int strncat_in_codepage(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int win_strncat_from_utf16be(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int win_strncat_from_utf16le(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int win_strncat_to_utf16be(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int win_strncat_to_utf16le(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -#endif -static int best_effort_strncat_from_utf16be(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_from_utf16le(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_to_utf16be(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -static int best_effort_strncat_to_utf16le(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -#if defined(HAVE_ICONV) -static int iconv_strncat_in_locale(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -#endif -static int best_effort_strncat_in_locale(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -static int _utf8_to_unicode(uint32_t *, const char *, size_t); -static int utf8_to_unicode(uint32_t *, const char *, size_t); -static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t); -static int cesu8_to_unicode(uint32_t *, const char *, size_t); -static size_t unicode_to_utf8(char *, size_t, uint32_t); -static int utf16_to_unicode(uint32_t *, const char *, size_t, int); -static size_t unicode_to_utf16be(char *, size_t, uint32_t); -static size_t unicode_to_utf16le(char *, size_t, uint32_t); -static int strncat_from_utf8_libarchive2(struct archive_string *, - const void *, size_t, struct archive_string_conv *); -static int strncat_from_utf8_to_utf8(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int archive_string_normalize_C(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int archive_string_normalize_D(struct archive_string *, const void *, - size_t, struct archive_string_conv *); -static int archive_string_append_unicode(struct archive_string *, - const void *, size_t, struct archive_string_conv *); - -static struct archive_string * -archive_string_append(struct archive_string *as, const char *p, size_t s) -{ - if (archive_string_ensure(as, as->length + s + 1) == NULL) - return (NULL); - if (s) - memmove(as->s + as->length, p, s); - as->length += s; - as->s[as->length] = 0; - return (as); -} - -static struct archive_wstring * -archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s) -{ - if (archive_wstring_ensure(as, as->length + s + 1) == NULL) - return (NULL); - wmemmove(as->s + as->length, p, s); - as->length += s; - as->s[as->length] = 0; - return (as); -} - -struct archive_string * -archive_array_append(struct archive_string *as, const char *p, size_t s) -{ - return archive_string_append(as, p, s); -} - -void -archive_string_concat(struct archive_string *dest, struct archive_string *src) -{ - if (archive_string_append(dest, src->s, src->length) == NULL) - __archive_errx(1, "Out of memory"); -} - -void -archive_wstring_concat(struct archive_wstring *dest, - struct archive_wstring *src) -{ - if (archive_wstring_append(dest, src->s, src->length) == NULL) - __archive_errx(1, "Out of memory"); -} - -void -archive_string_free(struct archive_string *as) -{ - as->length = 0; - as->buffer_length = 0; - free(as->s); - as->s = NULL; -} - -void -archive_wstring_free(struct archive_wstring *as) -{ - as->length = 0; - as->buffer_length = 0; - free(as->s); - as->s = NULL; -} - -struct archive_wstring * -archive_wstring_ensure(struct archive_wstring *as, size_t s) -{ - return (struct archive_wstring *) - archive_string_ensure((struct archive_string *)as, - s * sizeof(wchar_t)); -} - -/* Returns NULL on any allocation failure. */ -struct archive_string * -archive_string_ensure(struct archive_string *as, size_t s) -{ - char *p; - size_t new_length; - - /* If buffer is already big enough, don't reallocate. */ - if (as->s && (s <= as->buffer_length)) - return (as); - - /* - * Growing the buffer at least exponentially ensures that - * append operations are always linear in the number of - * characters appended. Using a smaller growth rate for - * larger buffers reduces memory waste somewhat at the cost of - * a larger constant factor. - */ - if (as->buffer_length < 32) - /* Start with a minimum 32-character buffer. */ - new_length = 32; - else if (as->buffer_length < 8192) - /* Buffers under 8k are doubled for speed. */ - new_length = as->buffer_length + as->buffer_length; - else { - /* Buffers 8k and over grow by at least 25% each time. */ - new_length = as->buffer_length + as->buffer_length / 4; - /* Be safe: If size wraps, fail. */ - if (new_length < as->buffer_length) { - /* On failure, wipe the string and return NULL. */ - archive_string_free(as); - errno = ENOMEM;/* Make sure errno has ENOMEM. */ - return (NULL); - } - } - /* - * The computation above is a lower limit to how much we'll - * grow the buffer. In any case, we have to grow it enough to - * hold the request. - */ - if (new_length < s) - new_length = s; - /* Now we can reallocate the buffer. */ - p = (char *)realloc(as->s, new_length); - if (p == NULL) { - /* On failure, wipe the string and return NULL. */ - archive_string_free(as); - errno = ENOMEM;/* Make sure errno has ENOMEM. */ - return (NULL); - } - - as->s = p; - as->buffer_length = new_length; - return (as); -} - -/* - * TODO: See if there's a way to avoid scanning - * the source string twice. Then test to see - * if it actually helps (remember that we're almost - * always called with pretty short arguments, so - * such an optimization might not help). - */ -struct archive_string * -archive_strncat(struct archive_string *as, const void *_p, size_t n) -{ - size_t s; - const char *p, *pp; - - p = (const char *)_p; - - /* Like strlen(p), except won't examine positions beyond p[n]. */ - s = 0; - pp = p; - while (s < n && *pp) { - pp++; - s++; - } - if ((as = archive_string_append(as, p, s)) == NULL) - __archive_errx(1, "Out of memory"); - return (as); -} - -struct archive_wstring * -archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n) -{ - size_t s; - const wchar_t *pp; - - /* Like strlen(p), except won't examine positions beyond p[n]. */ - s = 0; - pp = p; - while (s < n && *pp) { - pp++; - s++; - } - if ((as = archive_wstring_append(as, p, s)) == NULL) - __archive_errx(1, "Out of memory"); - return (as); -} - -struct archive_string * -archive_strcat(struct archive_string *as, const void *p) -{ - /* strcat is just strncat without an effective limit. - * Assert that we'll never get called with a source - * string over 16MB. - * TODO: Review all uses of strcat in the source - * and try to replace them with strncat(). - */ - return archive_strncat(as, p, 0x1000000); -} - -struct archive_wstring * -archive_wstrcat(struct archive_wstring *as, const wchar_t *p) -{ - /* Ditto. */ - return archive_wstrncat(as, p, 0x1000000); -} - -struct archive_string * -archive_strappend_char(struct archive_string *as, char c) -{ - if ((as = archive_string_append(as, &c, 1)) == NULL) - __archive_errx(1, "Out of memory"); - return (as); -} - -struct archive_wstring * -archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c) -{ - if ((as = archive_wstring_append(as, &c, 1)) == NULL) - __archive_errx(1, "Out of memory"); - return (as); -} - -/* - * Get the "current character set" name to use with iconv. - * On FreeBSD, the empty character set name "" chooses - * the correct character encoding for the current locale, - * so this isn't necessary. - * But iconv on Mac OS 10.6 doesn't seem to handle this correctly; - * on that system, we have to explicitly call nl_langinfo() - * to get the right name. Not sure about other platforms. - * - * NOTE: GNU libiconv does not recognize the character-set name - * which some platform nl_langinfo(CODESET) returns, so we should - * use locale_charset() instead of nl_langinfo(CODESET) for GNU libiconv. - */ -static const char * -default_iconv_charset(const char *charset) { - if (charset != NULL && charset[0] != '\0') - return charset; -#if HAVE_LOCALE_CHARSET && !defined(__APPLE__) - /* locale_charset() is broken on Mac OS */ - return locale_charset(); -#elif HAVE_NL_LANGINFO - return nl_langinfo(CODESET); -#else - return ""; -#endif -} - -#if defined(_WIN32) && !defined(__CYGWIN__) - -/* - * Convert MBS to WCS. - * Note: returns -1 if conversion fails. - */ -int -archive_wstring_append_from_mbs(struct archive_wstring *dest, - const char *p, size_t len) -{ - return archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL); -} - -static int -archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, - const char *s, size_t length, struct archive_string_conv *sc) -{ - int count, ret = 0; - UINT from_cp; - - if (sc != NULL) - from_cp = sc->from_cp; - else - from_cp = get_current_codepage(); - - if (from_cp == CP_C_LOCALE) { - /* - * "C" locale special process. - */ - wchar_t *ws; - const unsigned char *mp; - - if (NULL == archive_wstring_ensure(dest, - dest->length + length + 1)) - return (-1); - - ws = dest->s + dest->length; - mp = (const unsigned char *)s; - count = 0; - while (count < (int)length && *mp) { - *ws++ = (wchar_t)*mp++; - count++; - } - } else if (sc != NULL && - (sc->flag & (SCONV_NORMALIZATION_C | SCONV_NORMALIZATION_D))) { - /* - * Normalize UTF-8 and UTF-16BE and convert it directly - * to UTF-16 as wchar_t. - */ - struct archive_string u16; - int saved_flag = sc->flag;/* save current flag. */ - - if (is_big_endian()) - sc->flag |= SCONV_TO_UTF16BE; - else - sc->flag |= SCONV_TO_UTF16LE; - - if (sc->flag & SCONV_FROM_UTF16) { - /* - * UTF-16BE/LE NFD ===> UTF-16 NFC - * UTF-16BE/LE NFC ===> UTF-16 NFD - */ - count = (int)utf16nbytes(s, length); - } else { - /* - * UTF-8 NFD ===> UTF-16 NFC - * UTF-8 NFC ===> UTF-16 NFD - */ - count = (int)mbsnbytes(s, length); - } - u16.s = (char *)dest->s; - u16.length = dest->length << 1;; - u16.buffer_length = dest->buffer_length; - if (sc->flag & SCONV_NORMALIZATION_C) - ret = archive_string_normalize_C(&u16, s, count, sc); - else - ret = archive_string_normalize_D(&u16, s, count, sc); - dest->s = (wchar_t *)u16.s; - dest->length = u16.length >> 1; - dest->buffer_length = u16.buffer_length; - sc->flag = saved_flag;/* restore the saved flag. */ - return (ret); - } else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) { - count = (int)utf16nbytes(s, length); - count >>= 1; /* to be WCS length */ - /* Allocate memory for WCS. */ - if (NULL == archive_wstring_ensure(dest, - dest->length + count + 1)) - return (-1); - wmemcpy(dest->s + dest->length, (const wchar_t *)s, count); - if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) { - uint16_t *u16 = (uint16_t *)(dest->s + dest->length); - int b; - for (b = 0; b < count; b++) { - uint16_t val = archive_le16dec(u16+b); - archive_be16enc(u16+b, val); - } - } else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) { - uint16_t *u16 = (uint16_t *)(dest->s + dest->length); - int b; - for (b = 0; b < count; b++) { - uint16_t val = archive_be16dec(u16+b); - archive_le16enc(u16+b, val); - } - } - } else { - DWORD mbflag; - size_t buffsize; - - if (sc == NULL) - mbflag = 0; - else if (sc->flag & SCONV_FROM_CHARSET) { - /* Do not trust the length which comes from - * an archive file. */ - length = mbsnbytes(s, length); - mbflag = 0; - } else - mbflag = MB_PRECOMPOSED; - - buffsize = dest->length + length + 1; - do { - /* Allocate memory for WCS. */ - if (NULL == archive_wstring_ensure(dest, buffsize)) - return (-1); - /* Convert MBS to WCS. */ - count = MultiByteToWideChar(from_cp, - mbflag, s, (int)length, dest->s + dest->length, - (int)(dest->buffer_length >> 1) -1); - if (count == 0 && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - /* Expand the WCS buffer. */ - buffsize = dest->buffer_length << 1; - continue; - } - if (count == 0 && length != 0) - ret = -1; - break; - } while (1); - } - dest->length += count; - dest->s[dest->length] = L'\0'; - return (ret); -} - -#else - -/* - * Convert MBS to WCS. - * Note: returns -1 if conversion fails. - */ -int -archive_wstring_append_from_mbs(struct archive_wstring *dest, - const char *p, size_t len) -{ - size_t r; - int ret_val = 0; - /* - * No single byte will be more than one wide character, - * so this length estimate will always be big enough. - */ - size_t wcs_length = len; - size_t mbs_length = len; - const char *mbs = p; - wchar_t *wcs; -#if HAVE_MBRTOWC - mbstate_t shift_state; - - memset(&shift_state, 0, sizeof(shift_state)); -#endif - if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1)) - return (-1); - wcs = dest->s + dest->length; - /* - * We cannot use mbsrtowcs/mbstowcs here because those may convert - * extra MBS when strlen(p) > len and one wide character consists of - * multi bytes. - */ - while (*mbs && mbs_length > 0) { - if (wcs_length == 0) { - dest->length = wcs - dest->s; - dest->s[dest->length] = L'\0'; - wcs_length = mbs_length; - if (NULL == archive_wstring_ensure(dest, - dest->length + wcs_length + 1)) - return (-1); - wcs = dest->s + dest->length; - } -#if HAVE_MBRTOWC - r = mbrtowc(wcs, mbs, wcs_length, &shift_state); -#else - r = mbtowc(wcs, mbs, wcs_length); -#endif - if (r == (size_t)-1 || r == (size_t)-2) { - ret_val = -1; - if (errno == EILSEQ) { - ++mbs; - --mbs_length; - continue; - } else - break; - } - if (r == 0 || r > mbs_length) - break; - wcs++; - wcs_length--; - mbs += r; - mbs_length -= r; - } - dest->length = wcs - dest->s; - dest->s[dest->length] = L'\0'; - return (ret_val); -} - -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) - -/* - * WCS ==> MBS. - * Note: returns -1 if conversion fails. - * - * Win32 builds use WideCharToMultiByte from the Windows API. - * (Maybe Cygwin should too? WideCharToMultiByte will know a - * lot more about local character encodings than the wcrtomb() - * wrapper is going to know.) - */ -int -archive_string_append_from_wcs(struct archive_string *as, - const wchar_t *w, size_t len) -{ - return archive_string_append_from_wcs_in_codepage(as, w, len, NULL); -} - -static int -archive_string_append_from_wcs_in_codepage(struct archive_string *as, - const wchar_t *ws, size_t len, struct archive_string_conv *sc) -{ - BOOL defchar_used, *dp; - int count, ret = 0; - UINT to_cp; - int wslen = (int)len; - - if (sc != NULL) - to_cp = sc->to_cp; - else - to_cp = get_current_codepage(); - - if (to_cp == CP_C_LOCALE) { - /* - * "C" locale special process. - */ - const wchar_t *wp = ws; - char *p; - - if (NULL == archive_string_ensure(as, - as->length + wslen +1)) - return (-1); - p = as->s + as->length; - count = 0; - defchar_used = 0; - while (count < wslen && *wp) { - if (*wp > 255) { - *p++ = '?'; - wp++; - defchar_used = 1; - } else - *p++ = (char)*wp++; - count++; - } - } else if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) { - uint16_t *u16; - - if (NULL == - archive_string_ensure(as, as->length + len * 2 + 2)) - return (-1); - u16 = (uint16_t *)(as->s + as->length); - count = 0; - defchar_used = 0; - if (sc->flag & SCONV_TO_UTF16BE) { - while (count < (int)len && *ws) { - archive_be16enc(u16+count, *ws); - ws++; - count++; - } - } else { - while (count < (int)len && *ws) { - archive_le16enc(u16+count, *ws); - ws++; - count++; - } - } - count <<= 1; /* to be byte size */ - } else { - /* Make sure the MBS buffer has plenty to set. */ - if (NULL == - archive_string_ensure(as, as->length + len * 2 + 1)) - return (-1); - do { - defchar_used = 0; - if (to_cp == CP_UTF8 || sc == NULL) - dp = NULL; - else - dp = &defchar_used; - count = WideCharToMultiByte(to_cp, 0, ws, wslen, - as->s + as->length, (int)as->buffer_length-1, NULL, dp); - if (count == 0 && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - /* Expand the MBS buffer and retry. */ - if (NULL == archive_string_ensure(as, - as->buffer_length + len)) - return (-1); - continue; - } - if (count == 0) - ret = -1; - break; - } while (1); - } - as->length += count; - as->s[as->length] = '\0'; - return (defchar_used?-1:ret); -} - -#elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB) - -/* - * Translates a wide character string into current locale character set - * and appends to the archive_string. Note: returns -1 if conversion - * fails. - */ -int -archive_string_append_from_wcs(struct archive_string *as, - const wchar_t *w, size_t len) -{ - /* We cannot use the standard wcstombs() here because it - * cannot tell us how big the output buffer should be. So - * I've built a loop around wcrtomb() or wctomb() that - * converts a character at a time and resizes the string as - * needed. We prefer wcrtomb() when it's available because - * it's thread-safe. */ - int n, ret_val = 0; - char *p; - char *end; -#if HAVE_WCRTOMB - mbstate_t shift_state; - - memset(&shift_state, 0, sizeof(shift_state)); -#else - /* Clear the shift state before starting. */ - wctomb(NULL, L'\0'); -#endif - /* - * Allocate buffer for MBS. - * We need this allocation here since it is possible that - * as->s is still NULL. - */ - if (archive_string_ensure(as, as->length + len + 1) == NULL) - return (-1); - - p = as->s + as->length; - end = as->s + as->buffer_length - MB_CUR_MAX -1; - while (*w != L'\0' && len > 0) { - if (p >= end) { - as->length = p - as->s; - as->s[as->length] = '\0'; - /* Re-allocate buffer for MBS. */ - if (archive_string_ensure(as, - as->length + len * 2 + 1) == NULL) - return (-1); - p = as->s + as->length; - end = as->s + as->buffer_length - MB_CUR_MAX -1; - } -#if HAVE_WCRTOMB - n = wcrtomb(p, *w++, &shift_state); -#else - n = wctomb(p, *w++); -#endif - if (n == -1) { - if (errno == EILSEQ) { - /* Skip an illegal wide char. */ - *p++ = '?'; - ret_val = -1; - } else { - ret_val = -1; - break; - } - } else - p += n; - len--; - } - as->length = p - as->s; - as->s[as->length] = '\0'; - return (ret_val); -} - -#else /* HAVE_WCTOMB || HAVE_WCRTOMB */ - -/* - * TODO: Test if __STDC_ISO_10646__ is defined. - * Non-Windows uses ISO C wcrtomb() or wctomb() to perform the conversion - * one character at a time. If a non-Windows platform doesn't have - * either of these, fall back to the built-in UTF8 conversion. - */ -int -archive_string_append_from_wcs(struct archive_string *as, - const wchar_t *w, size_t len) -{ - (void)as;/* UNUSED */ - (void)w;/* UNUSED */ - (void)len;/* UNUSED */ - errno = ENOSYS; - return (-1); -} - -#endif /* HAVE_WCTOMB || HAVE_WCRTOMB */ - -/* - * Find a string conversion object by a pair of 'from' charset name - * and 'to' charset name from an archive object. - * Return NULL if not found. - */ -static struct archive_string_conv * -find_sconv_object(struct archive *a, const char *fc, const char *tc) -{ - struct archive_string_conv *sc; - - if (a == NULL) - return (NULL); - - for (sc = a->sconv; sc != NULL; sc = sc->next) { - if (strcmp(sc->from_charset, fc) == 0 && - strcmp(sc->to_charset, tc) == 0) - break; - } - return (sc); -} - -/* - * Register a string object to an archive object. - */ -static void -add_sconv_object(struct archive *a, struct archive_string_conv *sc) -{ - struct archive_string_conv **psc; - - /* Add a new sconv to sconv list. */ - psc = &(a->sconv); - while (*psc != NULL) - psc = &((*psc)->next); - *psc = sc; -} - -static void -add_converter(struct archive_string_conv *sc, int (*converter) - (struct archive_string *, const void *, size_t, - struct archive_string_conv *)) -{ - if (sc == NULL || sc->nconverter >= 2) - __archive_errx(1, "Programing error"); - sc->converter[sc->nconverter++] = converter; -} - -static void -setup_converter(struct archive_string_conv *sc) -{ - - /* Reset. */ - sc->nconverter = 0; - - /* - * Perform special sequence for the incorrect UTF-8 filenames - * made by libarchive2.x. - */ - if (sc->flag & SCONV_UTF8_LIBARCHIVE_2) { - add_converter(sc, strncat_from_utf8_libarchive2); - return; - } - - /* - * Convert a string to UTF-16BE/LE. - */ - if (sc->flag & SCONV_TO_UTF16) { - /* - * If the current locale is UTF-8, we can translate - * a UTF-8 string into a UTF-16BE string. - */ - if (sc->flag & SCONV_FROM_UTF8) { - add_converter(sc, archive_string_append_unicode); - return; - } - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (sc->flag & SCONV_WIN_CP) { - if (sc->flag & SCONV_TO_UTF16BE) - add_converter(sc, win_strncat_to_utf16be); - else - add_converter(sc, win_strncat_to_utf16le); - return; - } -#endif - -#if defined(HAVE_ICONV) - if (sc->cd != (iconv_t)-1) { - add_converter(sc, iconv_strncat_in_locale); - return; - } -#endif - - if (sc->flag & SCONV_BEST_EFFORT) { - if (sc->flag & SCONV_TO_UTF16BE) - add_converter(sc, - best_effort_strncat_to_utf16be); - else - add_converter(sc, - best_effort_strncat_to_utf16le); - } else - /* Make sure we have no converter. */ - sc->nconverter = 0; - return; - } - - /* - * Convert a string from UTF-16BE/LE. - */ - if (sc->flag & SCONV_FROM_UTF16) { - /* - * At least we should normalize a UTF-16BE string. - */ - if (sc->flag & SCONV_NORMALIZATION_D) - add_converter(sc,archive_string_normalize_D); - else if (sc->flag & SCONV_NORMALIZATION_C) - add_converter(sc, archive_string_normalize_C); - - if (sc->flag & SCONV_TO_UTF8) { - /* - * If the current locale is UTF-8, we can translate - * a UTF-16BE/LE string into a UTF-8 string directly. - */ - if (!(sc->flag & - (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C))) - add_converter(sc, - archive_string_append_unicode); - return; - } - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (sc->flag & SCONV_WIN_CP) { - if (sc->flag & SCONV_FROM_UTF16BE) - add_converter(sc, win_strncat_from_utf16be); - else - add_converter(sc, win_strncat_from_utf16le); - return; - } -#endif - -#if defined(HAVE_ICONV) - if (sc->cd != (iconv_t)-1) { - add_converter(sc, iconv_strncat_in_locale); - return; - } -#endif - - if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE)) - == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE)) - add_converter(sc, best_effort_strncat_from_utf16be); - else if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE)) - == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE)) - add_converter(sc, best_effort_strncat_from_utf16le); - else - /* Make sure we have no converter. */ - sc->nconverter = 0; - return; - } - - if (sc->flag & SCONV_FROM_UTF8) { - /* - * At least we should normalize a UTF-8 string. - */ - if (sc->flag & SCONV_NORMALIZATION_D) - add_converter(sc,archive_string_normalize_D); - else if (sc->flag & SCONV_NORMALIZATION_C) - add_converter(sc, archive_string_normalize_C); - - /* - * Copy UTF-8 string with a check of CESU-8. - * Apparently, iconv does not check surrogate pairs in UTF-8 - * when both from-charset and to-charset are UTF-8, and then - * we use our UTF-8 copy code. - */ - if (sc->flag & SCONV_TO_UTF8) { - /* - * If the current locale is UTF-8, we can translate - * a UTF-16BE string into a UTF-8 string directly. - */ - if (!(sc->flag & - (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C))) - add_converter(sc, strncat_from_utf8_to_utf8); - return; - } - } - -#if defined(_WIN32) && !defined(__CYGWIN__) - /* - * On Windows we can use Windows API for a string conversion. - */ - if (sc->flag & SCONV_WIN_CP) { - add_converter(sc, strncat_in_codepage); - return; - } -#endif - -#if HAVE_ICONV - if (sc->cd != (iconv_t)-1) { - add_converter(sc, iconv_strncat_in_locale); - /* - * iconv generally does not support UTF-8-MAC and so - * we have to the output of iconv from NFC to NFD if - * need. - */ - if ((sc->flag & SCONV_FROM_CHARSET) && - (sc->flag & SCONV_TO_UTF8)) { - if (sc->flag & SCONV_NORMALIZATION_D) - add_converter(sc, archive_string_normalize_D); - } - return; - } -#endif - - /* - * Try conversion in the best effort or no conversion. - */ - if ((sc->flag & SCONV_BEST_EFFORT) || sc->same) - add_converter(sc, best_effort_strncat_in_locale); - else - /* Make sure we have no converter. */ - sc->nconverter = 0; -} - -/* - * Return canonicalized charset-name but this supports just UTF-8, UTF-16BE - * and CP932 which are referenced in create_sconv_object(). - */ -static const char * -canonical_charset_name(const char *charset) -{ - char cs[16]; - char *p; - const char *s; - - if (charset == NULL || charset[0] == '\0' - || strlen(charset) > 15) - return (charset); - - /* Copy name to uppercase. */ - p = cs; - s = charset; - while (*s) { - char c = *s++; - if (c >= 'a' && c <= 'z') - c -= 'a' - 'A'; - *p++ = c; - } - *p++ = '\0'; - - if (strcmp(cs, "UTF-8") == 0 || - strcmp(cs, "UTF8") == 0) - return ("UTF-8"); - if (strcmp(cs, "UTF-16BE") == 0 || - strcmp(cs, "UTF16BE") == 0) - return ("UTF-16BE"); - if (strcmp(cs, "UTF-16LE") == 0 || - strcmp(cs, "UTF16LE") == 0) - return ("UTF-16LE"); - if (strcmp(cs, "CP932") == 0) - return ("CP932"); - return (charset); -} - -/* - * Create a string conversion object. - */ -static struct archive_string_conv * -create_sconv_object(const char *fc, const char *tc, - unsigned current_codepage, int flag) -{ - struct archive_string_conv *sc; - - sc = calloc(1, sizeof(*sc)); - if (sc == NULL) - return (NULL); - sc->next = NULL; - sc->from_charset = strdup(fc); - if (sc->from_charset == NULL) { - free(sc); - return (NULL); - } - sc->to_charset = strdup(tc); - if (sc->to_charset == NULL) { - free(sc->from_charset); - free(sc); - return (NULL); - } - archive_string_init(&sc->utftmp); - - if (flag & SCONV_TO_CHARSET) { - /* - * Convert characters from the current locale charset to - * a specified charset. - */ - sc->from_cp = current_codepage; - sc->to_cp = make_codepage_from_charset(tc); -#if defined(_WIN32) && !defined(__CYGWIN__) - if (IsValidCodePage(sc->to_cp)) - flag |= SCONV_WIN_CP; -#endif - } else if (flag & SCONV_FROM_CHARSET) { - /* - * Convert characters from a specified charset to - * the current locale charset. - */ - sc->to_cp = current_codepage; - sc->from_cp = make_codepage_from_charset(fc); -#if defined(_WIN32) && !defined(__CYGWIN__) - if (IsValidCodePage(sc->from_cp)) - flag |= SCONV_WIN_CP; -#endif - } - - /* - * Check if "from charset" and "to charset" are the same. - */ - if (strcmp(fc, tc) == 0 || - (sc->from_cp != (unsigned)-1 && sc->from_cp == sc->to_cp)) - sc->same = 1; - else - sc->same = 0; - - /* - * Mark if "from charset" or "to charset" are UTF-8 or UTF-16BE/LE. - */ - if (strcmp(tc, "UTF-8") == 0) - flag |= SCONV_TO_UTF8; - else if (strcmp(tc, "UTF-16BE") == 0) - flag |= SCONV_TO_UTF16BE; - else if (strcmp(tc, "UTF-16LE") == 0) - flag |= SCONV_TO_UTF16LE; - if (strcmp(fc, "UTF-8") == 0) - flag |= SCONV_FROM_UTF8; - else if (strcmp(fc, "UTF-16BE") == 0) - flag |= SCONV_FROM_UTF16BE; - else if (strcmp(fc, "UTF-16LE") == 0) - flag |= SCONV_FROM_UTF16LE; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (sc->to_cp == CP_UTF8) - flag |= SCONV_TO_UTF8; - else if (sc->to_cp == CP_UTF16BE) - flag |= SCONV_TO_UTF16BE | SCONV_WIN_CP; - else if (sc->to_cp == CP_UTF16LE) - flag |= SCONV_TO_UTF16LE | SCONV_WIN_CP; - if (sc->from_cp == CP_UTF8) - flag |= SCONV_FROM_UTF8; - else if (sc->from_cp == CP_UTF16BE) - flag |= SCONV_FROM_UTF16BE | SCONV_WIN_CP; - else if (sc->from_cp == CP_UTF16LE) - flag |= SCONV_FROM_UTF16LE | SCONV_WIN_CP; -#endif - - /* - * Set a flag for Unicode NFD. Usually iconv cannot correctly - * handle it. So we have to translate NFD characters to NFC ones - * ourselves before iconv handles. Another reason is to prevent - * that the same sight of two filenames, one is NFC and other - * is NFD, would be in its directory. - * On Mac OS X, although its filesystem layer automatically - * convert filenames to NFD, it would be useful for filename - * comparing to find out the same filenames that we normalize - * that to be NFD ourselves. - */ - if ((flag & SCONV_FROM_CHARSET) && - (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) { -#if defined(__APPLE__) - if (flag & SCONV_TO_UTF8) - flag |= SCONV_NORMALIZATION_D; - else -#endif - flag |= SCONV_NORMALIZATION_C; - } -#if defined(__APPLE__) - /* - * In case writing an archive file, make sure that a filename - * going to be passed to iconv is a Unicode NFC string since - * a filename in HFS Plus filesystem is a Unicode NFD one and - * iconv cannot handle it with "UTF-8" charset. It is simpler - * than a use of "UTF-8-MAC" charset. - */ - if ((flag & SCONV_TO_CHARSET) && - (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && - !(flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) - flag |= SCONV_NORMALIZATION_C; - /* - * In case reading an archive file. make sure that a filename - * will be passed to users is a Unicode NFD string in order to - * correctly compare the filename with other one which comes - * from HFS Plus filesystem. - */ - if ((flag & SCONV_FROM_CHARSET) && - !(flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && - (flag & SCONV_TO_UTF8)) - flag |= SCONV_NORMALIZATION_D; -#endif - -#if defined(HAVE_ICONV) - sc->cd_w = (iconv_t)-1; - /* - * Create an iconv object. - */ - if (((flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) && - (flag & (SCONV_FROM_UTF8 | SCONV_FROM_UTF16))) || - (flag & SCONV_WIN_CP)) { - /* This case we won't use iconv. */ - sc->cd = (iconv_t)-1; - } else { - sc->cd = iconv_open(tc, fc); - if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) { - /* - * Unfortunately, all of iconv implements do support - * "CP932" character-set, so we should use "SJIS" - * instead if iconv_open failed. - */ - if (strcmp(tc, "CP932") == 0) - sc->cd = iconv_open("SJIS", fc); - else if (strcmp(fc, "CP932") == 0) - sc->cd = iconv_open(tc, "SJIS"); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - /* - * archive_mstring on Windows directly convert multi-bytes - * into archive_wstring in order not to depend on locale - * so that you can do a I18N programming. This will be - * used only in archive_mstring_copy_mbs_len_l so far. - */ - if (flag & SCONV_FROM_CHARSET) { - sc->cd_w = iconv_open("UTF-8", fc); - if (sc->cd_w == (iconv_t)-1 && - (sc->flag & SCONV_BEST_EFFORT)) { - if (strcmp(fc, "CP932") == 0) - sc->cd_w = iconv_open("UTF-8", "SJIS"); - } - } -#endif /* _WIN32 && !__CYGWIN__ */ - } -#endif /* HAVE_ICONV */ - - sc->flag = flag; - - /* - * Set up converters. - */ - setup_converter(sc); - - return (sc); -} - -/* - * Free a string conversion object. - */ -static void -free_sconv_object(struct archive_string_conv *sc) -{ - free(sc->from_charset); - free(sc->to_charset); - archive_string_free(&sc->utftmp); -#if HAVE_ICONV - if (sc->cd != (iconv_t)-1) - iconv_close(sc->cd); - if (sc->cd_w != (iconv_t)-1) - iconv_close(sc->cd_w); -#endif - free(sc); -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -static unsigned -my_atoi(const char *p) -{ - unsigned cp; - - cp = 0; - while (*p) { - if (*p >= '0' && *p <= '9') - cp = cp * 10 + (*p - '0'); - else - return (-1); - p++; - } - return (cp); -} - -/* - * Translate Charset name (as used by iconv) into CodePage (as used by Windows) - * Return -1 if failed. - * - * Note: This translation code may be insufficient. - */ -static struct charset { - const char *name; - unsigned cp; -} charsets[] = { - /* MUST BE SORTED! */ - {"ASCII", 1252}, - {"ASMO-708", 708}, - {"BIG5", 950}, - {"CHINESE", 936}, - {"CP367", 1252}, - {"CP819", 1252}, - {"CP1025", 21025}, - {"DOS-720", 720}, - {"DOS-862", 862}, - {"EUC-CN", 51936}, - {"EUC-JP", 51932}, - {"EUC-KR", 949}, - {"EUCCN", 51936}, - {"EUCJP", 51932}, - {"EUCKR", 949}, - {"GB18030", 54936}, - {"GB2312", 936}, - {"HEBREW", 1255}, - {"HZ-GB-2312", 52936}, - {"IBM273", 20273}, - {"IBM277", 20277}, - {"IBM278", 20278}, - {"IBM280", 20280}, - {"IBM284", 20284}, - {"IBM285", 20285}, - {"IBM290", 20290}, - {"IBM297", 20297}, - {"IBM367", 1252}, - {"IBM420", 20420}, - {"IBM423", 20423}, - {"IBM424", 20424}, - {"IBM819", 1252}, - {"IBM871", 20871}, - {"IBM880", 20880}, - {"IBM905", 20905}, - {"IBM924", 20924}, - {"ISO-8859-1", 28591}, - {"ISO-8859-13", 28603}, - {"ISO-8859-15", 28605}, - {"ISO-8859-2", 28592}, - {"ISO-8859-3", 28593}, - {"ISO-8859-4", 28594}, - {"ISO-8859-5", 28595}, - {"ISO-8859-6", 28596}, - {"ISO-8859-7", 28597}, - {"ISO-8859-8", 28598}, - {"ISO-8859-9", 28599}, - {"ISO8859-1", 28591}, - {"ISO8859-13", 28603}, - {"ISO8859-15", 28605}, - {"ISO8859-2", 28592}, - {"ISO8859-3", 28593}, - {"ISO8859-4", 28594}, - {"ISO8859-5", 28595}, - {"ISO8859-6", 28596}, - {"ISO8859-7", 28597}, - {"ISO8859-8", 28598}, - {"ISO8859-9", 28599}, - {"JOHAB", 1361}, - {"KOI8-R", 20866}, - {"KOI8-U", 21866}, - {"KS_C_5601-1987", 949}, - {"LATIN1", 1252}, - {"LATIN2", 28592}, - {"MACINTOSH", 10000}, - {"SHIFT-JIS", 932}, - {"SHIFT_JIS", 932}, - {"SJIS", 932}, - {"US", 1252}, - {"US-ASCII", 1252}, - {"UTF-16", 1200}, - {"UTF-16BE", 1201}, - {"UTF-16LE", 1200}, - {"UTF-8", CP_UTF8}, - {"X-EUROPA", 29001}, - {"X-MAC-ARABIC", 10004}, - {"X-MAC-CE", 10029}, - {"X-MAC-CHINESEIMP", 10008}, - {"X-MAC-CHINESETRAD", 10002}, - {"X-MAC-CROATIAN", 10082}, - {"X-MAC-CYRILLIC", 10007}, - {"X-MAC-GREEK", 10006}, - {"X-MAC-HEBREW", 10005}, - {"X-MAC-ICELANDIC", 10079}, - {"X-MAC-JAPANESE", 10001}, - {"X-MAC-KOREAN", 10003}, - {"X-MAC-ROMANIAN", 10010}, - {"X-MAC-THAI", 10021}, - {"X-MAC-TURKISH", 10081}, - {"X-MAC-UKRAINIAN", 10017}, -}; -static unsigned -make_codepage_from_charset(const char *charset) -{ - char cs[16]; - char *p; - unsigned cp; - int a, b; - - if (charset == NULL || strlen(charset) > 15) - return -1; - - /* Copy name to uppercase. */ - p = cs; - while (*charset) { - char c = *charset++; - if (c >= 'a' && c <= 'z') - c -= 'a' - 'A'; - *p++ = c; - } - *p++ = '\0'; - cp = -1; - - /* Look it up in the table first, so that we can easily - * override CP367, which we map to 1252 instead of 367. */ - a = 0; - b = sizeof(charsets)/sizeof(charsets[0]); - while (b > a) { - int c = (b + a) / 2; - int r = strcmp(charsets[c].name, cs); - if (r < 0) - a = c + 1; - else if (r > 0) - b = c; - else - return charsets[c].cp; - } - - /* If it's not in the table, try to parse it. */ - switch (*cs) { - case 'C': - if (cs[1] == 'P' && cs[2] >= '0' && cs[2] <= '9') { - cp = my_atoi(cs + 2); - } else if (strcmp(cs, "CP_ACP") == 0) - cp = get_current_codepage(); - else if (strcmp(cs, "CP_OEMCP") == 0) - cp = get_current_oemcp(); - break; - case 'I': - if (cs[1] == 'B' && cs[2] == 'M' && - cs[3] >= '0' && cs[3] <= '9') { - cp = my_atoi(cs + 3); - } - break; - case 'W': - if (strncmp(cs, "WINDOWS-", 8) == 0) { - cp = my_atoi(cs + 8); - if (cp != 874 && (cp < 1250 || cp > 1258)) - cp = -1;/* This may invalid code. */ - } - break; - } - return (cp); -} - -/* - * Return ANSI Code Page of current locale set by setlocale(). - */ -static unsigned -get_current_codepage(void) -{ - char *locale, *p; - unsigned cp; - - locale = setlocale(LC_CTYPE, NULL); - if (locale == NULL) - return (GetACP()); - if (locale[0] == 'C' && locale[1] == '\0') - return (CP_C_LOCALE); - p = strrchr(locale, '.'); - if (p == NULL) - return (GetACP()); - cp = my_atoi(p+1); - if (cp <= 0) - return (GetACP()); - return (cp); -} - -/* - * Translation table between Locale Name and ACP/OEMCP. - */ -static struct { - unsigned acp; - unsigned ocp; - const char *locale; -} acp_ocp_map[] = { - { 950, 950, "Chinese_Taiwan" }, - { 936, 936, "Chinese_People's Republic of China" }, - { 950, 950, "Chinese_Taiwan" }, - { 1250, 852, "Czech_Czech Republic" }, - { 1252, 850, "Danish_Denmark" }, - { 1252, 850, "Dutch_Netherlands" }, - { 1252, 850, "Dutch_Belgium" }, - { 1252, 437, "English_United States" }, - { 1252, 850, "English_Australia" }, - { 1252, 850, "English_Canada" }, - { 1252, 850, "English_New Zealand" }, - { 1252, 850, "English_United Kingdom" }, - { 1252, 437, "English_United States" }, - { 1252, 850, "Finnish_Finland" }, - { 1252, 850, "French_France" }, - { 1252, 850, "French_Belgium" }, - { 1252, 850, "French_Canada" }, - { 1252, 850, "French_Switzerland" }, - { 1252, 850, "German_Germany" }, - { 1252, 850, "German_Austria" }, - { 1252, 850, "German_Switzerland" }, - { 1253, 737, "Greek_Greece" }, - { 1250, 852, "Hungarian_Hungary" }, - { 1252, 850, "Icelandic_Iceland" }, - { 1252, 850, "Italian_Italy" }, - { 1252, 850, "Italian_Switzerland" }, - { 932, 932, "Japanese_Japan" }, - { 949, 949, "Korean_Korea" }, - { 1252, 850, "Norwegian (BokmOl)_Norway" }, - { 1252, 850, "Norwegian (BokmOl)_Norway" }, - { 1252, 850, "Norwegian-Nynorsk_Norway" }, - { 1250, 852, "Polish_Poland" }, - { 1252, 850, "Portuguese_Portugal" }, - { 1252, 850, "Portuguese_Brazil" }, - { 1251, 866, "Russian_Russia" }, - { 1250, 852, "Slovak_Slovakia" }, - { 1252, 850, "Spanish_Spain" }, - { 1252, 850, "Spanish_Mexico" }, - { 1252, 850, "Spanish_Spain" }, - { 1252, 850, "Swedish_Sweden" }, - { 1254, 857, "Turkish_Turkey" }, - { 0, 0, NULL} -}; - -/* - * Return OEM Code Page of current locale set by setlocale(). - */ -static unsigned -get_current_oemcp(void) -{ - int i; - char *locale, *p; - size_t len; - - locale = setlocale(LC_CTYPE, NULL); - if (locale == NULL) - return (GetOEMCP()); - if (locale[0] == 'C' && locale[1] == '\0') - return (CP_C_LOCALE); - - p = strrchr(locale, '.'); - if (p == NULL) - return (GetOEMCP()); - len = p - locale; - for (i = 0; acp_ocp_map[i].acp; i++) { - if (strncmp(acp_ocp_map[i].locale, locale, len) == 0) - return (acp_ocp_map[i].ocp); - } - return (GetOEMCP()); -} -#else - -/* - * POSIX platform does not use CodePage. - */ - -static unsigned -get_current_codepage(void) -{ - return (-1);/* Unknown */ -} -static unsigned -make_codepage_from_charset(const char *charset) -{ - (void)charset; /* UNUSED */ - return (-1);/* Unknown */ -} -static unsigned -get_current_oemcp(void) -{ - return (-1);/* Unknown */ -} - -#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ - -/* - * Return a string conversion object. - */ -static struct archive_string_conv * -get_sconv_object(struct archive *a, const char *fc, const char *tc, int flag) -{ - struct archive_string_conv *sc; - unsigned current_codepage; - - /* Check if we have made the sconv object. */ - sc = find_sconv_object(a, fc, tc); - if (sc != NULL) - return (sc); - - if (a == NULL) - current_codepage = get_current_codepage(); - else - current_codepage = a->current_codepage; - - sc = create_sconv_object(canonical_charset_name(fc), - canonical_charset_name(tc), current_codepage, flag); - if (sc == NULL) { - if (a != NULL) - archive_set_error(a, ENOMEM, - "Could not allocate memory for " - "a string conversion object"); - return (NULL); - } - - /* - * If there is no converter for current string conversion object, - * we cannot handle this conversion. - */ - if (sc->nconverter == 0) { - if (a != NULL) { -#if HAVE_ICONV - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "iconv_open failed : Cannot handle ``%s''", - (flag & SCONV_TO_CHARSET)?tc:fc); -#else - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "A character-set conversion not fully supported " - "on this platform"); -#endif - } - /* Failed; free a sconv object. */ - free_sconv_object(sc); - return (NULL); - } - - /* - * Success! - */ - if (a != NULL) - add_sconv_object(a, sc); - return (sc); -} - -static const char * -get_current_charset(struct archive *a) -{ - const char *cur_charset; - - if (a == NULL) - cur_charset = default_iconv_charset(""); - else { - cur_charset = default_iconv_charset(a->current_code); - if (a->current_code == NULL) { - a->current_code = strdup(cur_charset); - a->current_codepage = get_current_codepage(); - a->current_oemcp = get_current_oemcp(); - } - } - return (cur_charset); -} - -/* - * Make and Return a string conversion object. - * Return NULL if the platform does not support the specified conversion - * and best_effort is 0. - * If best_effort is set, A string conversion object must be returned - * unless memory allocation for the object fails, but the conversion - * might fail when non-ASCII code is found. - */ -struct archive_string_conv * -archive_string_conversion_to_charset(struct archive *a, const char *charset, - int best_effort) -{ - int flag = SCONV_TO_CHARSET; - - if (best_effort) - flag |= SCONV_BEST_EFFORT; - return (get_sconv_object(a, get_current_charset(a), charset, flag)); -} - -struct archive_string_conv * -archive_string_conversion_from_charset(struct archive *a, const char *charset, - int best_effort) -{ - int flag = SCONV_FROM_CHARSET; - - if (best_effort) - flag |= SCONV_BEST_EFFORT; - return (get_sconv_object(a, charset, get_current_charset(a), flag)); -} - -/* - * archive_string_default_conversion_*_archive() are provided for Windows - * platform because other archiver application use CP_OEMCP for - * MultiByteToWideChar() and WideCharToMultiByte() for the filenames - * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP - * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP). - * So we should make a string conversion between CP_ACP and CP_OEMCP - * for compatibility. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -struct archive_string_conv * -archive_string_default_conversion_for_read(struct archive *a) -{ - const char *cur_charset = get_current_charset(a); - char oemcp[16]; - - /* NOTE: a check of cur_charset is unneeded but we need - * that get_current_charset() has been surely called at - * this time whatever C compiler optimized. */ - if (cur_charset != NULL && - (a->current_codepage == CP_C_LOCALE || - a->current_codepage == a->current_oemcp)) - return (NULL);/* no conversion. */ - - _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp); - /* Make sure a null termination must be set. */ - oemcp[sizeof(oemcp)-1] = '\0'; - return (get_sconv_object(a, oemcp, cur_charset, - SCONV_FROM_CHARSET)); -} - -struct archive_string_conv * -archive_string_default_conversion_for_write(struct archive *a) -{ - const char *cur_charset = get_current_charset(a); - char oemcp[16]; - - /* NOTE: a check of cur_charset is unneeded but we need - * that get_current_charset() has been surely called at - * this time whatever C compiler optimized. */ - if (cur_charset != NULL && - (a->current_codepage == CP_C_LOCALE || - a->current_codepage == a->current_oemcp)) - return (NULL);/* no conversion. */ - - _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp); - /* Make sure a null termination must be set. */ - oemcp[sizeof(oemcp)-1] = '\0'; - return (get_sconv_object(a, cur_charset, oemcp, - SCONV_TO_CHARSET)); -} -#else -struct archive_string_conv * -archive_string_default_conversion_for_read(struct archive *a) -{ - (void)a; /* UNUSED */ - return (NULL); -} - -struct archive_string_conv * -archive_string_default_conversion_for_write(struct archive *a) -{ - (void)a; /* UNUSED */ - return (NULL); -} -#endif - -/* - * Dispose of all character conversion objects in the archive object. - */ -void -archive_string_conversion_free(struct archive *a) -{ - struct archive_string_conv *sc; - struct archive_string_conv *sc_next; - - for (sc = a->sconv; sc != NULL; sc = sc_next) { - sc_next = sc->next; - free_sconv_object(sc); - } - a->sconv = NULL; - free(a->current_code); - a->current_code = NULL; -} - -/* - * Return a conversion charset name. - */ -const char * -archive_string_conversion_charset_name(struct archive_string_conv *sc) -{ - if (sc->flag & SCONV_TO_CHARSET) - return (sc->to_charset); - else - return (sc->from_charset); -} - -/* - * Change the behavior of a string conversion. - */ -void -archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt) -{ - switch (opt) { - /* - * A filename in UTF-8 was made with libarchive 2.x in a wrong - * assumption that wchar_t was Unicode. - * This option enables simulating the assumption in order to read - * that filename correctly. - */ - case SCONV_SET_OPT_UTF8_LIBARCHIVE2X: -#if (defined(_WIN32) && !defined(__CYGWIN__)) \ - || defined(__STDC_ISO_10646__) || defined(__APPLE__) - /* - * Nothing to do for it since wchar_t on these platforms - * is really Unicode. - */ - (void)sc; /* UNUSED */ -#else - if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) { - sc->flag |= SCONV_UTF8_LIBARCHIVE_2; - /* Set up string converters. */ - setup_converter(sc); - } -#endif - break; - case SCONV_SET_OPT_NORMALIZATION_C: - if ((sc->flag & SCONV_NORMALIZATION_C) == 0) { - sc->flag |= SCONV_NORMALIZATION_C; - sc->flag &= ~SCONV_NORMALIZATION_D; - /* Set up string converters. */ - setup_converter(sc); - } - break; - case SCONV_SET_OPT_NORMALIZATION_D: -#if defined(HAVE_ICONV) - /* - * If iconv will take the string, do not change the - * setting of the normalization. - */ - if (!(sc->flag & SCONV_WIN_CP) && - (sc->flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && - !(sc->flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) - break; -#endif - if ((sc->flag & SCONV_NORMALIZATION_D) == 0) { - sc->flag |= SCONV_NORMALIZATION_D; - sc->flag &= ~SCONV_NORMALIZATION_C; - /* Set up string converters. */ - setup_converter(sc); - } - break; - default: - break; - } -} - -/* - * - * Copy one archive_string to another in locale conversion. - * - * archive_strncat_l(); - * archive_strncpy_l(); - * - */ - -static size_t -mbsnbytes(const void *_p, size_t n) -{ - size_t s; - const char *p, *pp; - - if (_p == NULL) - return (0); - p = (const char *)_p; - - /* Like strlen(p), except won't examine positions beyond p[n]. */ - s = 0; - pp = p; - while (s < n && *pp) { - pp++; - s++; - } - return (s); -} - -static size_t -utf16nbytes(const void *_p, size_t n) -{ - size_t s; - const char *p, *pp; - - if (_p == NULL) - return (0); - p = (const char *)_p; - - /* Like strlen(p), except won't examine positions beyond p[n]. */ - s = 0; - pp = p; - n >>= 1; - while (s < n && (pp[0] || pp[1])) { - pp += 2; - s++; - } - return (s<<1); -} - -int -archive_strncpy_l(struct archive_string *as, const void *_p, size_t n, - struct archive_string_conv *sc) -{ - as->length = 0; - return (archive_strncat_l(as, _p, n, sc)); -} - -int -archive_strncat_l(struct archive_string *as, const void *_p, size_t n, - struct archive_string_conv *sc) -{ - const void *s; - size_t length = 0; - int i, r = 0, r2; - - if (_p != NULL && n > 0) { - if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) - length = utf16nbytes(_p, n); - else - length = mbsnbytes(_p, n); - } - - /* We must allocate memory even if there is no data for conversion - * or copy. This simulates archive_string_append behavior. */ - if (length == 0) { - int tn = 1; - if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) - tn = 2; - if (archive_string_ensure(as, as->length + tn) == NULL) - return (-1); - as->s[as->length] = 0; - if (tn == 2) - as->s[as->length+1] = 0; - return (0); - } - - /* - * If sc is NULL, we just make a copy. - */ - if (sc == NULL) { - if (archive_string_append(as, _p, length) == NULL) - return (-1);/* No memory */ - return (0); - } - - s = _p; - i = 0; - if (sc->nconverter > 1) { - sc->utftmp.length = 0; - r2 = sc->converter[0](&(sc->utftmp), s, length, sc); - if (r2 != 0 && errno == ENOMEM) - return (r2); - if (r > r2) - r = r2; - s = sc->utftmp.s; - length = sc->utftmp.length; - ++i; - } - r2 = sc->converter[i](as, s, length, sc); - if (r > r2) - r = r2; - return (r); -} - -#if HAVE_ICONV - -/* - * Return -1 if conversion fails. - */ -static int -iconv_strncat_in_locale(struct archive_string *as, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - ICONV_CONST char *itp; - size_t remaining; - iconv_t cd; - char *outp; - size_t avail, bs; - int return_value = 0; /* success */ - int to_size, from_size; - - if (sc->flag & SCONV_TO_UTF16) - to_size = 2; - else - to_size = 1; - if (sc->flag & SCONV_FROM_UTF16) - from_size = 2; - else - from_size = 1; - - if (archive_string_ensure(as, as->length + length*2+to_size) == NULL) - return (-1); - - cd = sc->cd; - itp = (char *)(uintptr_t)_p; - remaining = length; - outp = as->s + as->length; - avail = as->buffer_length - as->length - to_size; - while (remaining >= (size_t)from_size) { - size_t result = iconv(cd, &itp, &remaining, &outp, &avail); - - if (result != (size_t)-1) - break; /* Conversion completed. */ - - if (errno == EILSEQ || errno == EINVAL) { - /* - * If an output charset is UTF-8 or UTF-16BE/LE, - * unknown character should be U+FFFD - * (replacement character). - */ - if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) { - size_t rbytes; - if (sc->flag & SCONV_TO_UTF8) - rbytes = sizeof(utf8_replacement_char); - else - rbytes = 2; - - if (avail < rbytes) { - as->length = outp - as->s; - bs = as->buffer_length + - (remaining * to_size) + rbytes; - if (NULL == - archive_string_ensure(as, bs)) - return (-1); - outp = as->s + as->length; - avail = as->buffer_length - - as->length - to_size; - } - if (sc->flag & SCONV_TO_UTF8) - memcpy(outp, utf8_replacement_char, sizeof(utf8_replacement_char)); - else if (sc->flag & SCONV_TO_UTF16BE) - archive_be16enc(outp, UNICODE_R_CHAR); - else - archive_le16enc(outp, UNICODE_R_CHAR); - outp += rbytes; - avail -= rbytes; - } else { - /* Skip the illegal input bytes. */ - *outp++ = '?'; - avail--; - } - itp += from_size; - remaining -= from_size; - return_value = -1; /* failure */ - } else { - /* E2BIG no output buffer, - * Increase an output buffer. */ - as->length = outp - as->s; - bs = as->buffer_length + remaining * 2; - if (NULL == archive_string_ensure(as, bs)) - return (-1); - outp = as->s + as->length; - avail = as->buffer_length - as->length - to_size; - } - } - as->length = outp - as->s; - as->s[as->length] = 0; - if (to_size == 2) - as->s[as->length+1] = 0; - return (return_value); -} - -#endif /* HAVE_ICONV */ - - -#if defined(_WIN32) && !defined(__CYGWIN__) - -/* - * Translate a string from a some CodePage to an another CodePage by - * Windows APIs, and copy the result. Return -1 if conversion fails. - */ -static int -strncat_in_codepage(struct archive_string *as, - const void *_p, size_t length, struct archive_string_conv *sc) -{ - const char *s = (const char *)_p; - struct archive_wstring aws; - size_t l; - int r, saved_flag; - - archive_string_init(&aws); - saved_flag = sc->flag; - sc->flag &= ~(SCONV_NORMALIZATION_D | SCONV_NORMALIZATION_C); - r = archive_wstring_append_from_mbs_in_codepage(&aws, s, length, sc); - sc->flag = saved_flag; - if (r != 0) { - archive_wstring_free(&aws); - if (errno != ENOMEM) - archive_string_append(as, s, length); - return (-1); - } - - l = as->length; - r = archive_string_append_from_wcs_in_codepage( - as, aws.s, aws.length, sc); - if (r != 0 && errno != ENOMEM && l == as->length) - archive_string_append(as, s, length); - archive_wstring_free(&aws); - return (r); -} - -/* - * Test whether MBS ==> WCS is okay. - */ -static int -invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) -{ - const char *p = (const char *)_p; - unsigned codepage; - DWORD mbflag = MB_ERR_INVALID_CHARS; - - if (sc->flag & SCONV_FROM_CHARSET) - codepage = sc->to_cp; - else - codepage = sc->from_cp; - - if (codepage == CP_C_LOCALE) - return (0); - if (codepage != CP_UTF8) - mbflag |= MB_PRECOMPOSED; - - if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0) - return (-1); /* Invalid */ - return (0); /* Okay */ -} - -#else - -/* - * Test whether MBS ==> WCS is okay. - */ -static int -invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) -{ - const char *p = (const char *)_p; - size_t r; - -#if HAVE_MBRTOWC - mbstate_t shift_state; - - memset(&shift_state, 0, sizeof(shift_state)); -#else - /* Clear the shift state before starting. */ - mbtowc(NULL, NULL, 0); -#endif - while (n) { - wchar_t wc; - -#if HAVE_MBRTOWC - r = mbrtowc(&wc, p, n, &shift_state); -#else - r = mbtowc(&wc, p, n); -#endif - if (r == (size_t)-1 || r == (size_t)-2) - return (-1);/* Invalid. */ - if (r == 0) - break; - p += r; - n -= r; - } - (void)sc; /* UNUSED */ - return (0); /* All Okey. */ -} - -#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ - -/* - * Basically returns -1 because we cannot make a conversion of charset - * without iconv but in some cases this would return 0. - * Returns 0 if all copied characters are ASCII. - * Returns 0 if both from-locale and to-locale are the same and those - * can be WCS with no error. - */ -static int -best_effort_strncat_in_locale(struct archive_string *as, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - size_t remaining; - const uint8_t *itp; - int return_value = 0; /* success */ - - /* - * If both from-locale and to-locale is the same, this makes a copy. - * And then this checks all copied MBS can be WCS if so returns 0. - */ - if (sc->same) { - if (archive_string_append(as, _p, length) == NULL) - return (-1);/* No memory */ - return (invalid_mbs(_p, length, sc)); - } - - /* - * If a character is ASCII, this just copies it. If not, this - * assigns '?' character instead but in UTF-8 locale this assigns - * byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD, - * a Replacement Character in Unicode. - */ - - remaining = length; - itp = (const uint8_t *)_p; - while (*itp && remaining > 0) { - if (*itp > 127) { - // Non-ASCII: Substitute with suitable replacement - if (sc->flag & SCONV_TO_UTF8) { - if (archive_string_append(as, utf8_replacement_char, sizeof(utf8_replacement_char)) == NULL) { - __archive_errx(1, "Out of memory"); - } - } else { - archive_strappend_char(as, '?'); - } - return_value = -1; - } else { - archive_strappend_char(as, *itp); - } - ++itp; - } - return (return_value); -} - - -/* - * Unicode conversion functions. - * - UTF-8 <===> UTF-8 in removing surrogate pairs. - * - UTF-8 NFD ===> UTF-8 NFC in removing surrogate pairs. - * - UTF-8 made by libarchive 2.x ===> UTF-8. - * - UTF-16BE <===> UTF-8. - * - */ - -/* - * Utility to convert a single UTF-8 sequence. - * - * Usually return used bytes, return used byte in negative value when - * a unicode character is replaced with U+FFFD. - * See also http://unicode.org/review/pr-121.html Public Review Issue #121 - * Recommended Practice for Replacement Characters. - */ -static int -_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - static const char utf8_count[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ - }; - int ch, i; - int cnt; - uint32_t wc; - - /* Sanity check. */ - if (n == 0) - return (0); - /* - * Decode 1-4 bytes depending on the value of the first byte. - */ - ch = (unsigned char)*s; - if (ch == 0) - return (0); /* Standard: return 0 for end-of-string. */ - cnt = utf8_count[ch]; - - /* Invalid sequence or there are not plenty bytes. */ - if ((int)n < cnt) { - cnt = (int)n; - for (i = 1; i < cnt; i++) { - if ((s[i] & 0xc0) != 0x80) { - cnt = i; - break; - } - } - goto invalid_sequence; - } - - /* Make a Unicode code point from a single UTF-8 sequence. */ - switch (cnt) { - case 1: /* 1 byte sequence. */ - *pwc = ch & 0x7f; - return (cnt); - case 2: /* 2 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) { - cnt = 1; - goto invalid_sequence; - } - *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); - return (cnt); - case 3: /* 3 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) { - cnt = 1; - goto invalid_sequence; - } - if ((s[2] & 0xc0) != 0x80) { - cnt = 2; - goto invalid_sequence; - } - wc = ((ch & 0x0f) << 12) - | ((s[1] & 0x3f) << 6) - | (s[2] & 0x3f); - if (wc < 0x800) - goto invalid_sequence;/* Overlong sequence. */ - break; - case 4: /* 4 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) { - cnt = 1; - goto invalid_sequence; - } - if ((s[2] & 0xc0) != 0x80) { - cnt = 2; - goto invalid_sequence; - } - if ((s[3] & 0xc0) != 0x80) { - cnt = 3; - goto invalid_sequence; - } - wc = ((ch & 0x07) << 18) - | ((s[1] & 0x3f) << 12) - | ((s[2] & 0x3f) << 6) - | (s[3] & 0x3f); - if (wc < 0x10000) - goto invalid_sequence;/* Overlong sequence. */ - break; - default: /* Others are all invalid sequence. */ - if (ch == 0xc0 || ch == 0xc1) - cnt = 2; - else if (ch >= 0xf5 && ch <= 0xf7) - cnt = 4; - else if (ch >= 0xf8 && ch <= 0xfb) - cnt = 5; - else if (ch == 0xfc || ch == 0xfd) - cnt = 6; - else - cnt = 1; - if ((int)n < cnt) - cnt = (int)n; - for (i = 1; i < cnt; i++) { - if ((s[i] & 0xc0) != 0x80) { - cnt = i; - break; - } - } - goto invalid_sequence; - } - - /* The code point larger than 0x10FFFF is not legal - * Unicode values. */ - if (wc > UNICODE_MAX) - goto invalid_sequence; - /* Correctly gets a Unicode, returns used bytes. */ - *pwc = wc; - return (cnt); -invalid_sequence: - *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */ - return (cnt * -1); -} - -static int -utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - int cnt; - - cnt = _utf8_to_unicode(pwc, s, n); - /* Any of Surrogate pair is not legal Unicode values. */ - if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc)) - return (-3); - return (cnt); -} - -static inline uint32_t -combine_surrogate_pair(uint32_t uc, uint32_t uc2) -{ - uc -= 0xD800; - uc *= 0x400; - uc += uc2 - 0xDC00; - uc += 0x10000; - return (uc); -} - -/* - * Convert a single UTF-8/CESU-8 sequence to a Unicode code point in - * removing surrogate pairs. - * - * CESU-8: The Compatibility Encoding Scheme for UTF-16. - * - * Usually return used bytes, return used byte in negative value when - * a unicode character is replaced with U+FFFD. - */ -static int -cesu8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - uint32_t wc = 0; - int cnt; - - cnt = _utf8_to_unicode(&wc, s, n); - if (cnt == 3 && IS_HIGH_SURROGATE_LA(wc)) { - uint32_t wc2 = 0; - if (n - 3 < 3) { - /* Invalid byte sequence. */ - goto invalid_sequence; - } - cnt = _utf8_to_unicode(&wc2, s+3, n-3); - if (cnt != 3 || !IS_LOW_SURROGATE_LA(wc2)) { - /* Invalid byte sequence. */ - goto invalid_sequence; - } - wc = combine_surrogate_pair(wc, wc2); - cnt = 6; - } else if (cnt == 3 && IS_LOW_SURROGATE_LA(wc)) { - /* Invalid byte sequence. */ - goto invalid_sequence; - } - *pwc = wc; - return (cnt); -invalid_sequence: - *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */ - if (cnt > 0) - cnt *= -1; - return (cnt); -} - -/* - * Convert a Unicode code point to a single UTF-8 sequence. - * - * NOTE:This function does not check if the Unicode is legal or not. - * Please you definitely check it before calling this. - */ -static size_t -unicode_to_utf8(char *p, size_t remaining, uint32_t uc) -{ - char *_p = p; - - /* Invalid Unicode char maps to Replacement character */ - if (uc > UNICODE_MAX) - uc = UNICODE_R_CHAR; - /* Translate code point to UTF8 */ - if (uc <= 0x7f) { - if (remaining == 0) - return (0); - *p++ = (char)uc; - } else if (uc <= 0x7ff) { - if (remaining < 2) - return (0); - *p++ = 0xc0 | ((uc >> 6) & 0x1f); - *p++ = 0x80 | (uc & 0x3f); - } else if (uc <= 0xffff) { - if (remaining < 3) - return (0); - *p++ = 0xe0 | ((uc >> 12) & 0x0f); - *p++ = 0x80 | ((uc >> 6) & 0x3f); - *p++ = 0x80 | (uc & 0x3f); - } else { - if (remaining < 4) - return (0); - *p++ = 0xf0 | ((uc >> 18) & 0x07); - *p++ = 0x80 | ((uc >> 12) & 0x3f); - *p++ = 0x80 | ((uc >> 6) & 0x3f); - *p++ = 0x80 | (uc & 0x3f); - } - return (p - _p); -} - -static int -utf16be_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - return (utf16_to_unicode(pwc, s, n, 1)); -} - -static int -utf16le_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - return (utf16_to_unicode(pwc, s, n, 0)); -} - -static int -utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be) -{ - const char *utf16 = s; - unsigned uc; - - if (n == 0) - return (0); - if (n == 1) { - /* set the Replacement Character instead. */ - *pwc = UNICODE_R_CHAR; - return (-1); - } - - if (be) - uc = archive_be16dec(utf16); - else - uc = archive_le16dec(utf16); - utf16 += 2; - - /* If this is a surrogate pair, assemble the full code point.*/ - if (IS_HIGH_SURROGATE_LA(uc)) { - unsigned uc2; - - if (n >= 4) { - if (be) - uc2 = archive_be16dec(utf16); - else - uc2 = archive_le16dec(utf16); - } else - uc2 = 0; - if (IS_LOW_SURROGATE_LA(uc2)) { - uc = combine_surrogate_pair(uc, uc2); - utf16 += 2; - } else { - /* Undescribed code point should be U+FFFD - * (replacement character). */ - *pwc = UNICODE_R_CHAR; - return (-2); - } - } - - /* - * Surrogate pair values(0xd800 through 0xdfff) are only - * used by UTF-16, so, after above calculation, the code - * must not be surrogate values, and Unicode has no codes - * larger than 0x10ffff. Thus, those are not legal Unicode - * values. - */ - if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) { - /* Undescribed code point should be U+FFFD - * (replacement character). */ - *pwc = UNICODE_R_CHAR; - return (((int)(utf16 - s)) * -1); - } - *pwc = uc; - return ((int)(utf16 - s)); -} - -static size_t -unicode_to_utf16be(char *p, size_t remaining, uint32_t uc) -{ - char *utf16 = p; - - if (uc > 0xffff) { - /* We have a code point that won't fit into a - * wchar_t; convert it to a surrogate pair. */ - if (remaining < 4) - return (0); - uc -= 0x10000; - archive_be16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800); - archive_be16enc(utf16+2, (uc & 0x3ff) + 0xDC00); - return (4); - } else { - if (remaining < 2) - return (0); - archive_be16enc(utf16, uc); - return (2); - } -} - -static size_t -unicode_to_utf16le(char *p, size_t remaining, uint32_t uc) -{ - char *utf16 = p; - - if (uc > 0xffff) { - /* We have a code point that won't fit into a - * wchar_t; convert it to a surrogate pair. */ - if (remaining < 4) - return (0); - uc -= 0x10000; - archive_le16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800); - archive_le16enc(utf16+2, (uc & 0x3ff) + 0xDC00); - return (4); - } else { - if (remaining < 2) - return (0); - archive_le16enc(utf16, uc); - return (2); - } -} - -/* - * Copy UTF-8 string in checking surrogate pair. - * If any surrogate pair are found, it would be canonicalized. - */ -static int -strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, - size_t len, struct archive_string_conv *sc) -{ - const char *s; - char *p, *endp; - int n, ret = 0; - - (void)sc; /* UNUSED */ - - if (archive_string_ensure(as, as->length + len + 1) == NULL) - return (-1); - - s = (const char *)_p; - p = as->s + as->length; - endp = as->s + as->buffer_length -1; - do { - uint32_t uc; - const char *ss = s; - size_t w; - - /* - * Forward byte sequence until a conversion of that is needed. - */ - while ((n = utf8_to_unicode(&uc, s, len)) > 0) { - s += n; - len -= n; - } - if (ss < s) { - if (p + (s - ss) > endp) { - as->length = p - as->s; - if (archive_string_ensure(as, - as->buffer_length + len + 1) == NULL) - return (-1); - p = as->s + as->length; - endp = as->s + as->buffer_length -1; - } - - memcpy(p, ss, s - ss); - p += s - ss; - } - - /* - * If n is negative, current byte sequence needs a replacement. - */ - if (n < 0) { - if (n == -3 && IS_SURROGATE_PAIR_LA(uc)) { - /* Current byte sequence may be CESU-8. */ - n = cesu8_to_unicode(&uc, s, len); - } - if (n < 0) { - ret = -1; - n *= -1;/* Use a replaced unicode character. */ - } - - /* Rebuild UTF-8 byte sequence. */ - while ((w = unicode_to_utf8(p, endp - p, uc)) == 0) { - as->length = p - as->s; - if (archive_string_ensure(as, - as->buffer_length + len + 1) == NULL) - return (-1); - p = as->s + as->length; - endp = as->s + as->buffer_length -1; - } - p += w; - s += n; - len -= n; - } - } while (n > 0); - as->length = p - as->s; - as->s[as->length] = '\0'; - return (ret); -} - -static int -archive_string_append_unicode(struct archive_string *as, const void *_p, - size_t len, struct archive_string_conv *sc) -{ - const char *s; - char *p, *endp; - uint32_t uc; - size_t w; - int n, ret = 0, ts, tm; - int (*parse)(uint32_t *, const char *, size_t); - size_t (*unparse)(char *, size_t, uint32_t); - - if (sc->flag & SCONV_TO_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - } else if (sc->flag & SCONV_TO_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - } else if (sc->flag & SCONV_TO_UTF8) { - unparse = unicode_to_utf8; - ts = 1; - } else { - /* - * This case is going to be converted to another - * character-set through iconv. - */ - if (sc->flag & SCONV_FROM_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - } else if (sc->flag & SCONV_FROM_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - } else { - unparse = unicode_to_utf8; - ts = 1; - } - } - - if (sc->flag & SCONV_FROM_UTF16BE) { - parse = utf16be_to_unicode; - tm = 1; - } else if (sc->flag & SCONV_FROM_UTF16LE) { - parse = utf16le_to_unicode; - tm = 1; - } else { - parse = cesu8_to_unicode; - tm = ts; - } - - if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) - return (-1); - - s = (const char *)_p; - p = as->s + as->length; - endp = as->s + as->buffer_length - ts; - while ((n = parse(&uc, s, len)) != 0) { - if (n < 0) { - /* Use a replaced unicode character. */ - n *= -1; - ret = -1; - } - s += n; - len -= n; - while ((w = unparse(p, endp - p, uc)) == 0) { - /* There is not enough output buffer so - * we have to expand it. */ - as->length = p - as->s; - if (archive_string_ensure(as, - as->buffer_length + len * tm + ts) == NULL) - return (-1); - p = as->s + as->length; - endp = as->s + as->buffer_length - ts; - } - p += w; - } - as->length = p - as->s; - as->s[as->length] = '\0'; - if (ts == 2) - as->s[as->length+1] = '\0'; - return (ret); -} - -/* - * Following Constants for Hangul compositions this information comes from - * Unicode Standard Annex #15 http://unicode.org/reports/tr15/ - */ -#define HC_SBASE 0xAC00 -#define HC_LBASE 0x1100 -#define HC_VBASE 0x1161 -#define HC_TBASE 0x11A7 -#define HC_LCOUNT 19 -#define HC_VCOUNT 21 -#define HC_TCOUNT 28 -#define HC_NCOUNT (HC_VCOUNT * HC_TCOUNT) -#define HC_SCOUNT (HC_LCOUNT * HC_NCOUNT) - -static uint32_t -get_nfc(uint32_t uc, uint32_t uc2) -{ - int t, b; - - t = 0; - b = sizeof(u_composition_table)/sizeof(u_composition_table[0]) -1; - while (b >= t) { - int m = (t + b) / 2; - if (u_composition_table[m].cp1 < uc) - t = m + 1; - else if (u_composition_table[m].cp1 > uc) - b = m - 1; - else if (u_composition_table[m].cp2 < uc2) - t = m + 1; - else if (u_composition_table[m].cp2 > uc2) - b = m - 1; - else - return (u_composition_table[m].nfc); - } - return (0); -} - -#define FDC_MAX 10 /* The maximum number of Following Decomposable - * Characters. */ - -/* - * Update first code point. - */ -#define UPDATE_UC(new_uc) do { \ - uc = new_uc; \ - ucptr = NULL; \ -} while (0) - -/* - * Replace first code point with second code point. - */ -#define REPLACE_UC_WITH_UC2() do { \ - uc = uc2; \ - ucptr = uc2ptr; \ - n = n2; \ -} while (0) - -#define EXPAND_BUFFER() do { \ - as->length = p - as->s; \ - if (archive_string_ensure(as, \ - as->buffer_length + len * tm + ts) == NULL)\ - return (-1); \ - p = as->s + as->length; \ - endp = as->s + as->buffer_length - ts; \ -} while (0) - -#define UNPARSE(p, endp, uc) do { \ - while ((w = unparse(p, (endp) - (p), uc)) == 0) {\ - EXPAND_BUFFER(); \ - } \ - p += w; \ -} while (0) - -/* - * Write first code point. - * If the code point has not be changed from its original code, - * this just copies it from its original buffer pointer. - * If not, this converts it to UTF-8 byte sequence and copies it. - */ -#define WRITE_UC() do { \ - if (ucptr) { \ - if (p + n > endp) \ - EXPAND_BUFFER(); \ - switch (n) { \ - case 4: \ - *p++ = *ucptr++; \ - /* FALL THROUGH */ \ - case 3: \ - *p++ = *ucptr++; \ - /* FALL THROUGH */ \ - case 2: \ - *p++ = *ucptr++; \ - /* FALL THROUGH */ \ - case 1: \ - *p++ = *ucptr; \ - break; \ - } \ - ucptr = NULL; \ - } else { \ - UNPARSE(p, endp, uc); \ - } \ -} while (0) - -/* - * Collect following decomposable code points. - */ -#define COLLECT_CPS(start) do { \ - int _i; \ - for (_i = start; _i < FDC_MAX ; _i++) { \ - nx = parse(&ucx[_i], s, len); \ - if (nx <= 0) \ - break; \ - cx = CCC(ucx[_i]); \ - if (cl >= cx && cl != 228 && cx != 228)\ - break; \ - s += nx; \ - len -= nx; \ - cl = cx; \ - ccx[_i] = cx; \ - } \ - if (_i >= FDC_MAX) { \ - ret = -1; \ - ucx_size = FDC_MAX; \ - } else \ - ucx_size = _i; \ -} while (0) - -/* - * Normalize UTF-8/UTF-16BE characters to Form C and copy the result. - * - * TODO: Convert composition exclusions, which are never converted - * from NFC,NFD,NFKC and NFKD, to Form C. - */ -static int -archive_string_normalize_C(struct archive_string *as, const void *_p, - size_t len, struct archive_string_conv *sc) -{ - const char *s = (const char *)_p; - char *p, *endp; - uint32_t uc, uc2; - size_t w; - int always_replace, n, n2, ret = 0, spair, ts, tm; - int (*parse)(uint32_t *, const char *, size_t); - size_t (*unparse)(char *, size_t, uint32_t); - - always_replace = 1; - ts = 1;/* text size. */ - if (sc->flag & SCONV_TO_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - if (sc->flag & SCONV_FROM_UTF16BE) - always_replace = 0; - } else if (sc->flag & SCONV_TO_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - if (sc->flag & SCONV_FROM_UTF16LE) - always_replace = 0; - } else if (sc->flag & SCONV_TO_UTF8) { - unparse = unicode_to_utf8; - if (sc->flag & SCONV_FROM_UTF8) - always_replace = 0; - } else { - /* - * This case is going to be converted to another - * character-set through iconv. - */ - always_replace = 0; - if (sc->flag & SCONV_FROM_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - } else if (sc->flag & SCONV_FROM_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - } else { - unparse = unicode_to_utf8; - } - } - - if (sc->flag & SCONV_FROM_UTF16BE) { - parse = utf16be_to_unicode; - tm = 1; - spair = 4;/* surrogate pair size in UTF-16. */ - } else if (sc->flag & SCONV_FROM_UTF16LE) { - parse = utf16le_to_unicode; - tm = 1; - spair = 4;/* surrogate pair size in UTF-16. */ - } else { - parse = cesu8_to_unicode; - tm = ts; - spair = 6;/* surrogate pair size in UTF-8. */ - } - - if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) - return (-1); - - p = as->s + as->length; - endp = as->s + as->buffer_length - ts; - while ((n = parse(&uc, s, len)) != 0) { - const char *ucptr, *uc2ptr; - - if (n < 0) { - /* Use a replaced unicode character. */ - UNPARSE(p, endp, uc); - s += n*-1; - len -= n*-1; - ret = -1; - continue; - } else if (n == spair || always_replace) - /* uc is converted from a surrogate pair. - * this should be treated as a changed code. */ - ucptr = NULL; - else - ucptr = s; - s += n; - len -= n; - - /* Read second code point. */ - while ((n2 = parse(&uc2, s, len)) > 0) { - uint32_t ucx[FDC_MAX]; - int ccx[FDC_MAX]; - int cl, cx, i, nx, ucx_size; - int LIndex,SIndex; - uint32_t nfc; - - if (n2 == spair || always_replace) - /* uc2 is converted from a surrogate pair. - * this should be treated as a changed code. */ - uc2ptr = NULL; - else - uc2ptr = s; - s += n2; - len -= n2; - - /* - * If current second code point is out of decomposable - * code points, finding compositions is unneeded. - */ - if (!IS_DECOMPOSABLE_BLOCK(uc2)) { - WRITE_UC(); - REPLACE_UC_WITH_UC2(); - continue; - } - - /* - * Try to combine current code points. - */ - /* - * We have to combine Hangul characters according to - * http://uniicode.org/reports/tr15/#Hangul - */ - if (0 <= (LIndex = uc - HC_LBASE) && - LIndex < HC_LCOUNT) { - /* - * Hangul Composition. - * 1. Two current code points are L and V. - */ - int VIndex = uc2 - HC_VBASE; - if (0 <= VIndex && VIndex < HC_VCOUNT) { - /* Make syllable of form LV. */ - UPDATE_UC(HC_SBASE + - (LIndex * HC_VCOUNT + VIndex) * - HC_TCOUNT); - } else { - WRITE_UC(); - REPLACE_UC_WITH_UC2(); - } - continue; - } else if (0 <= (SIndex = uc - HC_SBASE) && - SIndex < HC_SCOUNT && (SIndex % HC_TCOUNT) == 0) { - /* - * Hangul Composition. - * 2. Two current code points are LV and T. - */ - int TIndex = uc2 - HC_TBASE; - if (0 < TIndex && TIndex < HC_TCOUNT) { - /* Make syllable of form LVT. */ - UPDATE_UC(uc + TIndex); - } else { - WRITE_UC(); - REPLACE_UC_WITH_UC2(); - } - continue; - } else if ((nfc = get_nfc(uc, uc2)) != 0) { - /* A composition to current code points - * is found. */ - UPDATE_UC(nfc); - continue; - } else if ((cl = CCC(uc2)) == 0) { - /* Clearly 'uc2' the second code point is not - * a decomposable code. */ - WRITE_UC(); - REPLACE_UC_WITH_UC2(); - continue; - } - - /* - * Collect following decomposable code points. - */ - cx = 0; - ucx[0] = uc2; - ccx[0] = cl; - COLLECT_CPS(1); - - /* - * Find a composed code in the collected code points. - */ - i = 1; - while (i < ucx_size) { - int j; - - if ((nfc = get_nfc(uc, ucx[i])) == 0) { - i++; - continue; - } - - /* - * nfc is composed of uc and ucx[i]. - */ - UPDATE_UC(nfc); - - /* - * Remove ucx[i] by shifting - * following code points. - */ - for (j = i; j+1 < ucx_size; j++) { - ucx[j] = ucx[j+1]; - ccx[j] = ccx[j+1]; - } - ucx_size --; - - /* - * Collect following code points blocked - * by ucx[i] the removed code point. - */ - if (ucx_size > 0 && i == ucx_size && - nx > 0 && cx == cl) { - cl = ccx[ucx_size-1]; - COLLECT_CPS(ucx_size); - } - /* - * Restart finding a composed code with - * the updated uc from the top of the - * collected code points. - */ - i = 0; - } - - /* - * Apparently the current code points are not - * decomposed characters or already composed. - */ - WRITE_UC(); - for (i = 0; i < ucx_size; i++) - UNPARSE(p, endp, ucx[i]); - - /* - * Flush out remaining canonical combining characters. - */ - if (nx > 0 && cx == cl && len > 0) { - while ((nx = parse(&ucx[0], s, len)) - > 0) { - cx = CCC(ucx[0]); - if (cl > cx) - break; - s += nx; - len -= nx; - cl = cx; - UNPARSE(p, endp, ucx[0]); - } - } - break; - } - if (n2 < 0) { - WRITE_UC(); - /* Use a replaced unicode character. */ - UNPARSE(p, endp, uc2); - s += n2*-1; - len -= n2*-1; - ret = -1; - continue; - } else if (n2 == 0) { - WRITE_UC(); - break; - } - } - as->length = p - as->s; - as->s[as->length] = '\0'; - if (ts == 2) - as->s[as->length+1] = '\0'; - return (ret); -} - -static int -get_nfd(uint32_t *cp1, uint32_t *cp2, uint32_t uc) -{ - int t, b; - - /* - * These are not converted to NFD on Mac OS. - */ - if ((uc >= 0x2000 && uc <= 0x2FFF) || - (uc >= 0xF900 && uc <= 0xFAFF) || - (uc >= 0x2F800 && uc <= 0x2FAFF)) - return (0); - /* - * Those code points are not converted to NFD on Mac OS. - * I do not know the reason because it is undocumented. - * NFC NFD - * 1109A ==> 11099 110BA - * 1109C ==> 1109B 110BA - * 110AB ==> 110A5 110BA - */ - if (uc == 0x1109A || uc == 0x1109C || uc == 0x110AB) - return (0); - - t = 0; - b = sizeof(u_decomposition_table)/sizeof(u_decomposition_table[0]) -1; - while (b >= t) { - int m = (t + b) / 2; - if (u_decomposition_table[m].nfc < uc) - t = m + 1; - else if (u_decomposition_table[m].nfc > uc) - b = m - 1; - else { - *cp1 = u_decomposition_table[m].cp1; - *cp2 = u_decomposition_table[m].cp2; - return (1); - } - } - return (0); -} - -#define REPLACE_UC_WITH(cp) do { \ - uc = cp; \ - ucptr = NULL; \ -} while (0) - -/* - * Normalize UTF-8 characters to Form D and copy the result. - */ -static int -archive_string_normalize_D(struct archive_string *as, const void *_p, - size_t len, struct archive_string_conv *sc) -{ - const char *s = (const char *)_p; - char *p, *endp; - uint32_t uc, uc2; - size_t w; - int always_replace, n, n2, ret = 0, spair, ts, tm; - int (*parse)(uint32_t *, const char *, size_t); - size_t (*unparse)(char *, size_t, uint32_t); - - always_replace = 1; - ts = 1;/* text size. */ - if (sc->flag & SCONV_TO_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - if (sc->flag & SCONV_FROM_UTF16BE) - always_replace = 0; - } else if (sc->flag & SCONV_TO_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - if (sc->flag & SCONV_FROM_UTF16LE) - always_replace = 0; - } else if (sc->flag & SCONV_TO_UTF8) { - unparse = unicode_to_utf8; - if (sc->flag & SCONV_FROM_UTF8) - always_replace = 0; - } else { - /* - * This case is going to be converted to another - * character-set through iconv. - */ - always_replace = 0; - if (sc->flag & SCONV_FROM_UTF16BE) { - unparse = unicode_to_utf16be; - ts = 2; - } else if (sc->flag & SCONV_FROM_UTF16LE) { - unparse = unicode_to_utf16le; - ts = 2; - } else { - unparse = unicode_to_utf8; - } - } - - if (sc->flag & SCONV_FROM_UTF16BE) { - parse = utf16be_to_unicode; - tm = 1; - spair = 4;/* surrogate pair size in UTF-16. */ - } else if (sc->flag & SCONV_FROM_UTF16LE) { - parse = utf16le_to_unicode; - tm = 1; - spair = 4;/* surrogate pair size in UTF-16. */ - } else { - parse = cesu8_to_unicode; - tm = ts; - spair = 6;/* surrogate pair size in UTF-8. */ - } - - if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) - return (-1); - - p = as->s + as->length; - endp = as->s + as->buffer_length - ts; - while ((n = parse(&uc, s, len)) != 0) { - const char *ucptr; - uint32_t cp1, cp2; - int SIndex; - struct { - uint32_t uc; - int ccc; - } fdc[FDC_MAX]; - int fdi, fdj; - int ccc; - -check_first_code: - if (n < 0) { - /* Use a replaced unicode character. */ - UNPARSE(p, endp, uc); - s += n*-1; - len -= n*-1; - ret = -1; - continue; - } else if (n == spair || always_replace) - /* uc is converted from a surrogate pair. - * this should be treated as a changed code. */ - ucptr = NULL; - else - ucptr = s; - s += n; - len -= n; - - /* Hangul Decomposition. */ - if ((SIndex = uc - HC_SBASE) >= 0 && SIndex < HC_SCOUNT) { - int L = HC_LBASE + SIndex / HC_NCOUNT; - int V = HC_VBASE + (SIndex % HC_NCOUNT) / HC_TCOUNT; - int T = HC_TBASE + SIndex % HC_TCOUNT; - - REPLACE_UC_WITH(L); - WRITE_UC(); - REPLACE_UC_WITH(V); - WRITE_UC(); - if (T != HC_TBASE) { - REPLACE_UC_WITH(T); - WRITE_UC(); - } - continue; - } - if (IS_DECOMPOSABLE_BLOCK(uc) && CCC(uc) != 0) { - WRITE_UC(); - continue; - } - - fdi = 0; - while (get_nfd(&cp1, &cp2, uc) && fdi < FDC_MAX) { - int k; - - for (k = fdi; k > 0; k--) - fdc[k] = fdc[k-1]; - fdc[0].ccc = CCC(cp2); - fdc[0].uc = cp2; - fdi++; - REPLACE_UC_WITH(cp1); - } - - /* Read following code points. */ - while ((n2 = parse(&uc2, s, len)) > 0 && - (ccc = CCC(uc2)) != 0 && fdi < FDC_MAX) { - int j, k; - - s += n2; - len -= n2; - for (j = 0; j < fdi; j++) { - if (fdc[j].ccc > ccc) - break; - } - if (j < fdi) { - for (k = fdi; k > j; k--) - fdc[k] = fdc[k-1]; - fdc[j].ccc = ccc; - fdc[j].uc = uc2; - } else { - fdc[fdi].ccc = ccc; - fdc[fdi].uc = uc2; - } - fdi++; - } - - WRITE_UC(); - for (fdj = 0; fdj < fdi; fdj++) { - REPLACE_UC_WITH(fdc[fdj].uc); - WRITE_UC(); - } - - if (n2 == 0) - break; - REPLACE_UC_WITH(uc2); - n = n2; - goto check_first_code; - } - as->length = p - as->s; - as->s[as->length] = '\0'; - if (ts == 2) - as->s[as->length+1] = '\0'; - return (ret); -} - -/* - * libarchive 2.x made incorrect UTF-8 strings in the wrong assumption - * that WCS is Unicode. It is true for several platforms but some are false. - * And then people who did not use UTF-8 locale on the non Unicode WCS - * platform and made a tar file with libarchive(mostly bsdtar) 2.x. Those - * now cannot get right filename from libarchive 3.x and later since we - * fixed the wrong assumption and it is incompatible to older its versions. - * So we provide special option, "compat-2x.x", for resolving it. - * That option enable the string conversion of libarchive 2.x. - * - * Translates the wrong UTF-8 string made by libarchive 2.x into current - * locale character set and appends to the archive_string. - * Note: returns -1 if conversion fails. - */ -static int -strncat_from_utf8_libarchive2(struct archive_string *as, - const void *_p, size_t len, struct archive_string_conv *sc) -{ - const char *s; - int n; - char *p; - char *end; - uint32_t unicode; -#if HAVE_WCRTOMB - mbstate_t shift_state; - - memset(&shift_state, 0, sizeof(shift_state)); -#else - /* Clear the shift state before starting. */ - wctomb(NULL, L'\0'); -#endif - (void)sc; /* UNUSED */ - /* - * Allocate buffer for MBS. - * We need this allocation here since it is possible that - * as->s is still NULL. - */ - if (archive_string_ensure(as, as->length + len + 1) == NULL) - return (-1); - - s = (const char *)_p; - p = as->s + as->length; - end = as->s + as->buffer_length - MB_CUR_MAX -1; - while ((n = _utf8_to_unicode(&unicode, s, len)) != 0) { - wchar_t wc; - - if (p >= end) { - as->length = p - as->s; - /* Re-allocate buffer for MBS. */ - if (archive_string_ensure(as, - as->length + len * 2 + 1) == NULL) - return (-1); - p = as->s + as->length; - end = as->s + as->buffer_length - MB_CUR_MAX -1; - } - - /* - * As libarchive 2.x, translates the UTF-8 characters into - * wide-characters in the assumption that WCS is Unicode. - */ - if (n < 0) { - n *= -1; - wc = L'?'; - } else - wc = (wchar_t)unicode; - - s += n; - len -= n; - /* - * Translates the wide-character into the current locale MBS. - */ -#if HAVE_WCRTOMB - n = (int)wcrtomb(p, wc, &shift_state); -#else - n = (int)wctomb(p, wc); -#endif - if (n == -1) - return (-1); - p += n; - } - as->length = p - as->s; - as->s[as->length] = '\0'; - return (0); -} - - -/* - * Conversion functions between current locale dependent MBS and UTF-16BE. - * strncat_from_utf16be() : UTF-16BE --> MBS - * strncat_to_utf16be() : MBS --> UTF16BE - */ - -#if defined(_WIN32) && !defined(__CYGWIN__) - -/* - * Convert a UTF-16BE/LE string to current locale and copy the result. - * Return -1 if conversion fails. - */ -static int -win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, - struct archive_string_conv *sc, int be) -{ - struct archive_string tmp; - const char *u16; - int ll; - BOOL defchar; - char *mbs; - size_t mbs_size, b; - int ret = 0; - - bytes &= ~1; - if (archive_string_ensure(as, as->length + bytes +1) == NULL) - return (-1); - - mbs = as->s + as->length; - mbs_size = as->buffer_length - as->length -1; - - if (sc->to_cp == CP_C_LOCALE) { - /* - * "C" locale special process. - */ - u16 = _p; - ll = 0; - for (b = 0; b < bytes; b += 2) { - uint16_t val; - if (be) - val = archive_be16dec(u16+b); - else - val = archive_le16dec(u16+b); - if (val > 255) { - *mbs++ = '?'; - ret = -1; - } else - *mbs++ = (char)(val&0xff); - ll++; - } - as->length += ll; - as->s[as->length] = '\0'; - return (ret); - } - - archive_string_init(&tmp); - if (be) { - if (is_big_endian()) { - u16 = _p; - } else { - if (archive_string_ensure(&tmp, bytes+2) == NULL) - return (-1); - memcpy(tmp.s, _p, bytes); - for (b = 0; b < bytes; b += 2) { - uint16_t val = archive_be16dec(tmp.s+b); - archive_le16enc(tmp.s+b, val); - } - u16 = tmp.s; - } - } else { - if (!is_big_endian()) { - u16 = _p; - } else { - if (archive_string_ensure(&tmp, bytes+2) == NULL) - return (-1); - memcpy(tmp.s, _p, bytes); - for (b = 0; b < bytes; b += 2) { - uint16_t val = archive_le16dec(tmp.s+b); - archive_be16enc(tmp.s+b, val); - } - u16 = tmp.s; - } - } - - do { - defchar = 0; - ll = WideCharToMultiByte(sc->to_cp, 0, - (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size, - NULL, &defchar); - /* Exit loop if we succeeded */ - if (ll != 0 || - GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - break; - } - /* Else expand buffer and loop to try again. */ - ll = WideCharToMultiByte(sc->to_cp, 0, - (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL); - if (archive_string_ensure(as, ll +1) == NULL) - return (-1); - mbs = as->s + as->length; - mbs_size = as->buffer_length - as->length -1; - } while (1); - archive_string_free(&tmp); - as->length += ll; - as->s[as->length] = '\0'; - if (ll == 0 || defchar) - ret = -1; - return (ret); -} - -static int -win_strncat_from_utf16be(struct archive_string *as, const void *_p, - size_t bytes, struct archive_string_conv *sc) -{ - return (win_strncat_from_utf16(as, _p, bytes, sc, 1)); -} - -static int -win_strncat_from_utf16le(struct archive_string *as, const void *_p, - size_t bytes, struct archive_string_conv *sc) -{ - return (win_strncat_from_utf16(as, _p, bytes, sc, 0)); -} - -static int -is_big_endian(void) -{ - uint16_t d = 1; - - return (archive_be16dec(&d) == 1); -} - -/* - * Convert a current locale string to UTF-16BE/LE and copy the result. - * Return -1 if conversion fails. - */ -static int -win_strncat_to_utf16(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc, int bigendian) -{ - const char *s = (const char *)_p; - char *u16; - size_t count, avail; - - if (archive_string_ensure(as16, - as16->length + (length + 1) * 2) == NULL) - return (-1); - - u16 = as16->s + as16->length; - avail = as16->buffer_length - 2; - if (sc->from_cp == CP_C_LOCALE) { - /* - * "C" locale special process. - */ - count = 0; - while (count < length && *s) { - if (bigendian) - archive_be16enc(u16, *s); - else - archive_le16enc(u16, *s); - u16 += 2; - s++; - count++; - } - as16->length += count << 1; - as16->s[as16->length] = 0; - as16->s[as16->length+1] = 0; - return (0); - } - do { - count = MultiByteToWideChar(sc->from_cp, - MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1); - /* Exit loop if we succeeded */ - if (count != 0 || - GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - break; - } - /* Expand buffer and try again */ - count = MultiByteToWideChar(sc->from_cp, - MB_PRECOMPOSED, s, (int)length, NULL, 0); - if (archive_string_ensure(as16, (count +1) * 2) - == NULL) - return (-1); - u16 = as16->s + as16->length; - avail = as16->buffer_length - 2; - } while (1); - as16->length += count * 2; - as16->s[as16->length] = 0; - as16->s[as16->length+1] = 0; - if (count == 0) - return (-1); - - if (is_big_endian()) { - if (!bigendian) { - while (count > 0) { - uint16_t v = archive_be16dec(u16); - archive_le16enc(u16, v); - u16 += 2; - count--; - } - } - } else { - if (bigendian) { - while (count > 0) { - uint16_t v = archive_le16dec(u16); - archive_be16enc(u16, v); - u16 += 2; - count--; - } - } - } - return (0); -} - -static int -win_strncat_to_utf16be(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - return (win_strncat_to_utf16(as16, _p, length, sc, 1)); -} - -static int -win_strncat_to_utf16le(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - return (win_strncat_to_utf16(as16, _p, length, sc, 0)); -} - -#endif /* _WIN32 && !__CYGWIN__ */ - -/* - * Do the best effort for conversions. - * We cannot handle UTF-16BE character-set without such iconv, - * but there is a chance if a string consists just ASCII code or - * a current locale is UTF-8. - */ - -/* - * Convert a UTF-16BE string to current locale and copy the result. - * Return -1 if conversion fails. - */ -static int -best_effort_strncat_from_utf16(struct archive_string *as, const void *_p, - size_t bytes, struct archive_string_conv *sc, int be) -{ - const char *utf16 = (const char *)_p; - char *mbs; - uint32_t uc; - int n, ret; - - (void)sc; /* UNUSED */ - /* - * Other case, we should do the best effort. - * If all character are ASCII(<0x7f), we can convert it. - * if not , we set a alternative character and return -1. - */ - ret = 0; - if (archive_string_ensure(as, as->length + bytes +1) == NULL) - return (-1); - mbs = as->s + as->length; - - while ((n = utf16_to_unicode(&uc, utf16, bytes, be)) != 0) { - if (n < 0) { - n *= -1; - ret = -1; - } - bytes -= n; - utf16 += n; - - if (uc > 127) { - /* We cannot handle it. */ - *mbs++ = '?'; - ret = -1; - } else - *mbs++ = (char)uc; - } - as->length = mbs - as->s; - as->s[as->length] = '\0'; - return (ret); -} - -static int -best_effort_strncat_from_utf16be(struct archive_string *as, const void *_p, - size_t bytes, struct archive_string_conv *sc) -{ - return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 1)); -} - -static int -best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p, - size_t bytes, struct archive_string_conv *sc) -{ - return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 0)); -} - -/* - * Convert a current locale string to UTF-16BE/LE and copy the result. - * Return -1 if conversion fails. - */ -static int -best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc, int bigendian) -{ - const char *s = (const char *)_p; - char *utf16; - size_t remaining; - int ret; - - (void)sc; /* UNUSED */ - /* - * Other case, we should do the best effort. - * If all character are ASCII(<0x7f), we can convert it. - * if not , we set a alternative character and return -1. - */ - ret = 0; - remaining = length; - - if (archive_string_ensure(as16, - as16->length + (length + 1) * 2) == NULL) - return (-1); - - utf16 = as16->s + as16->length; - while (remaining--) { - unsigned c = *s++; - if (c > 127) { - /* We cannot handle it. */ - c = UNICODE_R_CHAR; - ret = -1; - } - if (bigendian) - archive_be16enc(utf16, c); - else - archive_le16enc(utf16, c); - utf16 += 2; - } - as16->length = utf16 - as16->s; - as16->s[as16->length] = 0; - as16->s[as16->length+1] = 0; - return (ret); -} - -static int -best_effort_strncat_to_utf16be(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - return (best_effort_strncat_to_utf16(as16, _p, length, sc, 1)); -} - -static int -best_effort_strncat_to_utf16le(struct archive_string *as16, const void *_p, - size_t length, struct archive_string_conv *sc) -{ - return (best_effort_strncat_to_utf16(as16, _p, length, sc, 0)); -} - - -/* - * Multistring operations. - */ - -void -archive_mstring_clean(struct archive_mstring *aes) -{ - archive_wstring_free(&(aes->aes_wcs)); - archive_string_free(&(aes->aes_mbs)); - archive_string_free(&(aes->aes_utf8)); - archive_string_free(&(aes->aes_mbs_in_locale)); - aes->aes_set = 0; -} - -void -archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src) -{ - dest->aes_set = src->aes_set; - archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); - archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); - archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs)); -} - -int -archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes, - const char **p) -{ - struct archive_string_conv *sc; - int r; - - /* If we already have a UTF8 form, return that immediately. */ - if (aes->aes_set & AES_SET_UTF8) { - *p = aes->aes_utf8.s; - return (0); - } - - *p = NULL; - if (aes->aes_set & AES_SET_MBS) { - sc = archive_string_conversion_to_charset(a, "UTF-8", 1); - if (sc == NULL) - return (-1);/* Couldn't allocate memory for sc. */ - r = archive_strncpy_l(&(aes->aes_utf8), aes->aes_mbs.s, - aes->aes_mbs.length, sc); - if (a == NULL) - free_sconv_object(sc); - if (r == 0) { - aes->aes_set |= AES_SET_UTF8; - *p = aes->aes_utf8.s; - return (0);/* success. */ - } else - return (-1);/* failure. */ - } - return (0);/* success. */ -} - -int -archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes, - const char **p) -{ - int r, ret = 0; - - (void)a; /* UNUSED */ - /* If we already have an MBS form, return that immediately. */ - if (aes->aes_set & AES_SET_MBS) { - *p = aes->aes_mbs.s; - return (ret); - } - - *p = NULL; - /* If there's a WCS form, try converting with the native locale. */ - if (aes->aes_set & AES_SET_WCS) { - archive_string_empty(&(aes->aes_mbs)); - r = archive_string_append_from_wcs(&(aes->aes_mbs), - aes->aes_wcs.s, aes->aes_wcs.length); - *p = aes->aes_mbs.s; - if (r == 0) { - aes->aes_set |= AES_SET_MBS; - return (ret); - } else - ret = -1; - } - - /* - * Only a UTF-8 form cannot avail because its conversion already - * failed at archive_mstring_update_utf8(). - */ - return (ret); -} - -int -archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes, - const wchar_t **wp) -{ - int r, ret = 0; - - (void)a;/* UNUSED */ - /* Return WCS form if we already have it. */ - if (aes->aes_set & AES_SET_WCS) { - *wp = aes->aes_wcs.s; - return (ret); - } - - *wp = NULL; - /* Try converting MBS to WCS using native locale. */ - if (aes->aes_set & AES_SET_MBS) { - archive_wstring_empty(&(aes->aes_wcs)); - r = archive_wstring_append_from_mbs(&(aes->aes_wcs), - aes->aes_mbs.s, aes->aes_mbs.length); - if (r == 0) { - aes->aes_set |= AES_SET_WCS; - *wp = aes->aes_wcs.s; - } else - ret = -1;/* failure. */ - } - return (ret); -} - -int -archive_mstring_get_mbs_l(struct archive_mstring *aes, - const char **p, size_t *length, struct archive_string_conv *sc) -{ - int r, ret = 0; - -#if defined(_WIN32) && !defined(__CYGWIN__) - /* - * Internationalization programming on Windows must use Wide - * characters because Windows platform cannot make locale UTF-8. - */ - if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) { - archive_string_empty(&(aes->aes_mbs_in_locale)); - r = archive_string_append_from_wcs_in_codepage( - &(aes->aes_mbs_in_locale), aes->aes_wcs.s, - aes->aes_wcs.length, sc); - if (r == 0) { - *p = aes->aes_mbs_in_locale.s; - if (length != NULL) - *length = aes->aes_mbs_in_locale.length; - return (0); - } else if (errno == ENOMEM) - return (-1); - else - ret = -1; - } -#endif - - /* If there is not an MBS form but is a WCS form, try converting - * with the native locale to be used for translating it to specified - * character-set. */ - if ((aes->aes_set & AES_SET_MBS) == 0 && - (aes->aes_set & AES_SET_WCS) != 0) { - archive_string_empty(&(aes->aes_mbs)); - r = archive_string_append_from_wcs(&(aes->aes_mbs), - aes->aes_wcs.s, aes->aes_wcs.length); - if (r == 0) - aes->aes_set |= AES_SET_MBS; - else if (errno == ENOMEM) - return (-1); - else - ret = -1; - } - /* If we already have an MBS form, use it to be translated to - * specified character-set. */ - if (aes->aes_set & AES_SET_MBS) { - if (sc == NULL) { - /* Conversion is unneeded. */ - *p = aes->aes_mbs.s; - if (length != NULL) - *length = aes->aes_mbs.length; - return (0); - } - ret = archive_strncpy_l(&(aes->aes_mbs_in_locale), - aes->aes_mbs.s, aes->aes_mbs.length, sc); - *p = aes->aes_mbs_in_locale.s; - if (length != NULL) - *length = aes->aes_mbs_in_locale.length; - } else { - *p = NULL; - if (length != NULL) - *length = 0; - } - return (ret); -} - -int -archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs) -{ - if (mbs == NULL) { - aes->aes_set = 0; - return (0); - } - return (archive_mstring_copy_mbs_len(aes, mbs, strlen(mbs))); -} - -int -archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs, - size_t len) -{ - if (mbs == NULL) { - aes->aes_set = 0; - return (0); - } - aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ - archive_strncpy(&(aes->aes_mbs), mbs, len); - archive_string_empty(&(aes->aes_utf8)); - archive_wstring_empty(&(aes->aes_wcs)); - return (0); -} - -int -archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs) -{ - return archive_mstring_copy_wcs_len(aes, wcs, - wcs == NULL ? 0 : wcslen(wcs)); -} - -int -archive_mstring_copy_utf8(struct archive_mstring *aes, const char *utf8) -{ - if (utf8 == NULL) { - aes->aes_set = 0; - } - aes->aes_set = AES_SET_UTF8; - archive_string_empty(&(aes->aes_mbs)); - archive_string_empty(&(aes->aes_wcs)); - archive_strncpy(&(aes->aes_utf8), utf8, strlen(utf8)); - return (int)strlen(utf8); -} - -int -archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs, - size_t len) -{ - if (wcs == NULL) { - aes->aes_set = 0; - } - aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ - archive_string_empty(&(aes->aes_mbs)); - archive_string_empty(&(aes->aes_utf8)); - archive_wstrncpy(&(aes->aes_wcs), wcs, len); - return (0); -} - -int -archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, - const char *mbs, size_t len, struct archive_string_conv *sc) -{ - int r; - - if (mbs == NULL) { - aes->aes_set = 0; - return (0); - } - archive_string_empty(&(aes->aes_mbs)); - archive_wstring_empty(&(aes->aes_wcs)); - archive_string_empty(&(aes->aes_utf8)); -#if defined(_WIN32) && !defined(__CYGWIN__) - /* - * Internationalization programming on Windows must use Wide - * characters because Windows platform cannot make locale UTF-8. - */ - if (sc == NULL) { - if (archive_string_append(&(aes->aes_mbs), - mbs, mbsnbytes(mbs, len)) == NULL) { - aes->aes_set = 0; - r = -1; - } else { - aes->aes_set = AES_SET_MBS; - r = 0; - } -#if defined(HAVE_ICONV) - } else if (sc != NULL && sc->cd_w != (iconv_t)-1) { - /* - * This case happens only when MultiByteToWideChar() cannot - * handle sc->from_cp, and we have to iconv in order to - * translate character-set to wchar_t,UTF-16. - */ - iconv_t cd = sc->cd; - unsigned from_cp; - int flag; - - /* - * Translate multi-bytes from some character-set to UTF-8. - */ - sc->cd = sc->cd_w; - r = archive_strncpy_l(&(aes->aes_utf8), mbs, len, sc); - sc->cd = cd; - if (r != 0) { - aes->aes_set = 0; - return (r); - } - aes->aes_set = AES_SET_UTF8; - - /* - * Append the UTF-8 string into wstring. - */ - flag = sc->flag; - sc->flag &= ~(SCONV_NORMALIZATION_C - | SCONV_TO_UTF16| SCONV_FROM_UTF16); - from_cp = sc->from_cp; - sc->from_cp = CP_UTF8; - r = archive_wstring_append_from_mbs_in_codepage(&(aes->aes_wcs), - aes->aes_utf8.s, aes->aes_utf8.length, sc); - sc->flag = flag; - sc->from_cp = from_cp; - if (r == 0) - aes->aes_set |= AES_SET_WCS; -#endif - } else { - r = archive_wstring_append_from_mbs_in_codepage( - &(aes->aes_wcs), mbs, len, sc); - if (r == 0) - aes->aes_set = AES_SET_WCS; - else - aes->aes_set = 0; - } -#else - r = archive_strncpy_l(&(aes->aes_mbs), mbs, len, sc); - if (r == 0) - aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ - else - aes->aes_set = 0; -#endif - return (r); -} - -/* - * The 'update' form tries to proactively update all forms of - * this string (WCS and MBS) and returns an error if any of - * them fail. This is used by the 'pax' handler, for instance, - * to detect and report character-conversion failures early while - * still allowing clients to get potentially useful values from - * the more tolerant lazy conversions. (get_mbs and get_wcs will - * strive to give the user something useful, so you can get hopefully - * usable values even if some of the character conversions are failing.) - */ -int -archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes, - const char *utf8) -{ - struct archive_string_conv *sc; - int r; - - if (utf8 == NULL) { - aes->aes_set = 0; - return (0); /* Succeeded in clearing everything. */ - } - - /* Save the UTF8 string. */ - archive_strcpy(&(aes->aes_utf8), utf8); - - /* Empty the mbs and wcs strings. */ - archive_string_empty(&(aes->aes_mbs)); - archive_wstring_empty(&(aes->aes_wcs)); - - aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ - - /* Try converting UTF-8 to MBS, return false on failure. */ - sc = archive_string_conversion_from_charset(a, "UTF-8", 1); - if (sc == NULL) - return (-1);/* Couldn't allocate memory for sc. */ - r = archive_strcpy_l(&(aes->aes_mbs), utf8, sc); - if (a == NULL) - free_sconv_object(sc); - if (r != 0) - return (-1); - aes->aes_set = AES_SET_UTF8 | AES_SET_MBS; /* Both UTF8 and MBS set. */ - - /* Try converting MBS to WCS, return false on failure. */ - if (archive_wstring_append_from_mbs(&(aes->aes_wcs), aes->aes_mbs.s, - aes->aes_mbs.length)) - return (-1); - aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; - - /* All conversions succeeded. */ - return (0); -} diff --git a/3rdparty/libarchive/libarchive/archive_string.h b/3rdparty/libarchive/libarchive/archive_string.h deleted file mode 100644 index 56dfbb28..00000000 --- a/3rdparty/libarchive/libarchive/archive_string.h +++ /dev/null @@ -1,243 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_string.h 201092 2009-12-28 02:26:06Z kientzle $ - * - */ - -#ifndef __LIBARCHIVE_BUILD -#ifndef __LIBARCHIVE_TEST -#error This header is only to be used internally to libarchive. -#endif -#endif - -#ifndef ARCHIVE_STRING_H_INCLUDED -#define ARCHIVE_STRING_H_INCLUDED - -#include -#ifdef HAVE_STDLIB_H -#include /* required for wchar_t on some systems */ -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_WCHAR_H -#include -#endif - -#include "archive.h" - -/* - * Basic resizable/reusable string support similar to Java's "StringBuffer." - * - * Unlike sbuf(9), the buffers here are fully reusable and track the - * length throughout. - */ - -struct archive_string { - char *s; /* Pointer to the storage */ - size_t length; /* Length of 's' in characters */ - size_t buffer_length; /* Length of malloc-ed storage in bytes. */ -}; - -struct archive_wstring { - wchar_t *s; /* Pointer to the storage */ - size_t length; /* Length of 's' in characters */ - size_t buffer_length; /* Length of malloc-ed storage in bytes. */ -}; - -struct archive_string_conv; - -/* Initialize an archive_string object on the stack or elsewhere. */ -#define archive_string_init(a) \ - do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0) - -/* Append a C char to an archive_string, resizing as necessary. */ -struct archive_string * -archive_strappend_char(struct archive_string *, char); - -/* Ditto for a wchar_t and an archive_wstring. */ -struct archive_wstring * -archive_wstrappend_wchar(struct archive_wstring *, wchar_t); - -/* Append a raw array to an archive_string, resizing as necessary */ -struct archive_string * -archive_array_append(struct archive_string *, const char *, size_t); - -/* Convert a Unicode string to current locale and append the result. */ -/* Returns -1 if conversion fails. */ -int -archive_string_append_from_wcs(struct archive_string *, const wchar_t *, size_t); - - -/* Create a string conversion object. - * Return NULL and set a error message if the conversion is not supported - * on the platform. */ -struct archive_string_conv * -archive_string_conversion_to_charset(struct archive *, const char *, int); -struct archive_string_conv * -archive_string_conversion_from_charset(struct archive *, const char *, int); -/* Create the default string conversion object for reading/writing an archive. - * Return NULL if the conversion is unneeded. - * Note: On non Windows platform this always returns NULL. - */ -struct archive_string_conv * -archive_string_default_conversion_for_read(struct archive *); -struct archive_string_conv * -archive_string_default_conversion_for_write(struct archive *); -/* Dispose of a string conversion object. */ -void -archive_string_conversion_free(struct archive *); -const char * -archive_string_conversion_charset_name(struct archive_string_conv *); -void -archive_string_conversion_set_opt(struct archive_string_conv *, int); -#define SCONV_SET_OPT_UTF8_LIBARCHIVE2X 1 -#define SCONV_SET_OPT_NORMALIZATION_C 2 -#define SCONV_SET_OPT_NORMALIZATION_D 4 - - -/* Copy one archive_string to another in locale conversion. - * Return -1 if conversion fails. */ -int -archive_strncpy_l(struct archive_string *, const void *, size_t, - struct archive_string_conv *); - -/* Copy one archive_string to another in locale conversion. - * Return -1 if conversion fails. */ -int -archive_strncat_l(struct archive_string *, const void *, size_t, - struct archive_string_conv *); - - -/* Copy one archive_string to another */ -#define archive_string_copy(dest, src) \ - ((dest)->length = 0, archive_string_concat((dest), (src))) -#define archive_wstring_copy(dest, src) \ - ((dest)->length = 0, archive_wstring_concat((dest), (src))) - -/* Concatenate one archive_string to another */ -void archive_string_concat(struct archive_string *dest, struct archive_string *src); -void archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src); - -/* Ensure that the underlying buffer is at least as large as the request. */ -struct archive_string * -archive_string_ensure(struct archive_string *, size_t); -struct archive_wstring * -archive_wstring_ensure(struct archive_wstring *, size_t); - -/* Append C string, which may lack trailing \0. */ -/* The source is declared void * here because this gets used with - * "signed char *", "unsigned char *" and "char *" arguments. - * Declaring it "char *" as with some of the other functions just - * leads to a lot of extra casts. */ -struct archive_string * -archive_strncat(struct archive_string *, const void *, size_t); -struct archive_wstring * -archive_wstrncat(struct archive_wstring *, const wchar_t *, size_t); - -/* Append a C string to an archive_string, resizing as necessary. */ -struct archive_string * -archive_strcat(struct archive_string *, const void *); -struct archive_wstring * -archive_wstrcat(struct archive_wstring *, const wchar_t *); - -/* Copy a C string to an archive_string, resizing as necessary. */ -#define archive_strcpy(as,p) \ - archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p))) -#define archive_wstrcpy(as,p) \ - archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(p))) -#define archive_strcpy_l(as,p,lo) \ - archive_strncpy_l((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo)) - -/* Copy a C string to an archive_string with limit, resizing as necessary. */ -#define archive_strncpy(as,p,l) \ - ((as)->length=0, archive_strncat((as), (p), (l))) -#define archive_wstrncpy(as,p,l) \ - ((as)->length = 0, archive_wstrncat((as), (p), (l))) - -/* Return length of string. */ -#define archive_strlen(a) ((a)->length) - -/* Set string length to zero. */ -#define archive_string_empty(a) ((a)->length = 0) -#define archive_wstring_empty(a) ((a)->length = 0) - -/* Release any allocated storage resources. */ -void archive_string_free(struct archive_string *); -void archive_wstring_free(struct archive_wstring *); - -/* Like 'vsprintf', but resizes the underlying string as necessary. */ -/* Note: This only implements a small subset of standard printf functionality. */ -void archive_string_vsprintf(struct archive_string *, const char *, - va_list) __LA_PRINTF(2, 0); -void archive_string_sprintf(struct archive_string *, const char *, ...) - __LA_PRINTF(2, 3); - -/* Translates from MBS to Unicode. */ -/* Returns non-zero if conversion failed in any way. */ -int archive_wstring_append_from_mbs(struct archive_wstring *dest, - const char *, size_t); - - -/* A "multistring" can hold Unicode, UTF8, or MBS versions of - * the string. If you set and read the same version, no translation - * is done. If you set and read different versions, the library - * will attempt to transparently convert. - */ -struct archive_mstring { - struct archive_string aes_mbs; - struct archive_string aes_utf8; - struct archive_wstring aes_wcs; - struct archive_string aes_mbs_in_locale; - /* Bitmap of which of the above are valid. Because we're lazy - * about malloc-ing and reusing the underlying storage, we - * can't rely on NULL pointers to indicate whether a string - * has been set. */ - int aes_set; -#define AES_SET_MBS 1 -#define AES_SET_UTF8 2 -#define AES_SET_WCS 4 -}; - -void archive_mstring_clean(struct archive_mstring *); -void archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src); -int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **); -int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **); -int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **); -int archive_mstring_get_mbs_l(struct archive_mstring *, const char **, - size_t *, struct archive_string_conv *); -int archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs); -int archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs, - size_t); -int archive_mstring_copy_utf8(struct archive_mstring *, const char *utf8); -int archive_mstring_copy_wcs(struct archive_mstring *, const wchar_t *wcs); -int archive_mstring_copy_wcs_len(struct archive_mstring *, - const wchar_t *wcs, size_t); -int archive_mstring_copy_mbs_len_l(struct archive_mstring *, - const char *mbs, size_t, struct archive_string_conv *); -int archive_mstring_update_utf8(struct archive *, struct archive_mstring *aes, const char *utf8); - - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_string_composition.h b/3rdparty/libarchive/libarchive/archive_string_composition.h deleted file mode 100644 index 8902ac1f..00000000 --- a/3rdparty/libarchive/libarchive/archive_string_composition.h +++ /dev/null @@ -1,2292 +0,0 @@ -/*- - * Copyright (c) 2011-2012 libarchive Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - * - */ - -/* - * ATTENTION! - * This file is generated by build/utils/gen_archive_string_composition_h.sh - * from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt - * - * See also http://unicode.org/report/tr15/ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_STRING_COMPOSITION_H_INCLUDED -#define ARCHIVE_STRING_COMPOSITION_H_INCLUDED - -struct unicode_composition_table { - uint32_t cp1; - uint32_t cp2; - uint32_t nfc; -}; - -static const struct unicode_composition_table u_composition_table[] = { - { 0x0003C , 0x00338 , 0x0226E }, - { 0x0003D , 0x00338 , 0x02260 }, - { 0x0003E , 0x00338 , 0x0226F }, - { 0x00041 , 0x00300 , 0x000C0 }, - { 0x00041 , 0x00301 , 0x000C1 }, - { 0x00041 , 0x00302 , 0x000C2 }, - { 0x00041 , 0x00303 , 0x000C3 }, - { 0x00041 , 0x00304 , 0x00100 }, - { 0x00041 , 0x00306 , 0x00102 }, - { 0x00041 , 0x00307 , 0x00226 }, - { 0x00041 , 0x00308 , 0x000C4 }, - { 0x00041 , 0x00309 , 0x01EA2 }, - { 0x00041 , 0x0030A , 0x000C5 }, - { 0x00041 , 0x0030C , 0x001CD }, - { 0x00041 , 0x0030F , 0x00200 }, - { 0x00041 , 0x00311 , 0x00202 }, - { 0x00041 , 0x00323 , 0x01EA0 }, - { 0x00041 , 0x00325 , 0x01E00 }, - { 0x00041 , 0x00328 , 0x00104 }, - { 0x00042 , 0x00307 , 0x01E02 }, - { 0x00042 , 0x00323 , 0x01E04 }, - { 0x00042 , 0x00331 , 0x01E06 }, - { 0x00043 , 0x00301 , 0x00106 }, - { 0x00043 , 0x00302 , 0x00108 }, - { 0x00043 , 0x00307 , 0x0010A }, - { 0x00043 , 0x0030C , 0x0010C }, - { 0x00043 , 0x00327 , 0x000C7 }, - { 0x00044 , 0x00307 , 0x01E0A }, - { 0x00044 , 0x0030C , 0x0010E }, - { 0x00044 , 0x00323 , 0x01E0C }, - { 0x00044 , 0x00327 , 0x01E10 }, - { 0x00044 , 0x0032D , 0x01E12 }, - { 0x00044 , 0x00331 , 0x01E0E }, - { 0x00045 , 0x00300 , 0x000C8 }, - { 0x00045 , 0x00301 , 0x000C9 }, - { 0x00045 , 0x00302 , 0x000CA }, - { 0x00045 , 0x00303 , 0x01EBC }, - { 0x00045 , 0x00304 , 0x00112 }, - { 0x00045 , 0x00306 , 0x00114 }, - { 0x00045 , 0x00307 , 0x00116 }, - { 0x00045 , 0x00308 , 0x000CB }, - { 0x00045 , 0x00309 , 0x01EBA }, - { 0x00045 , 0x0030C , 0x0011A }, - { 0x00045 , 0x0030F , 0x00204 }, - { 0x00045 , 0x00311 , 0x00206 }, - { 0x00045 , 0x00323 , 0x01EB8 }, - { 0x00045 , 0x00327 , 0x00228 }, - { 0x00045 , 0x00328 , 0x00118 }, - { 0x00045 , 0x0032D , 0x01E18 }, - { 0x00045 , 0x00330 , 0x01E1A }, - { 0x00046 , 0x00307 , 0x01E1E }, - { 0x00047 , 0x00301 , 0x001F4 }, - { 0x00047 , 0x00302 , 0x0011C }, - { 0x00047 , 0x00304 , 0x01E20 }, - { 0x00047 , 0x00306 , 0x0011E }, - { 0x00047 , 0x00307 , 0x00120 }, - { 0x00047 , 0x0030C , 0x001E6 }, - { 0x00047 , 0x00327 , 0x00122 }, - { 0x00048 , 0x00302 , 0x00124 }, - { 0x00048 , 0x00307 , 0x01E22 }, - { 0x00048 , 0x00308 , 0x01E26 }, - { 0x00048 , 0x0030C , 0x0021E }, - { 0x00048 , 0x00323 , 0x01E24 }, - { 0x00048 , 0x00327 , 0x01E28 }, - { 0x00048 , 0x0032E , 0x01E2A }, - { 0x00049 , 0x00300 , 0x000CC }, - { 0x00049 , 0x00301 , 0x000CD }, - { 0x00049 , 0x00302 , 0x000CE }, - { 0x00049 , 0x00303 , 0x00128 }, - { 0x00049 , 0x00304 , 0x0012A }, - { 0x00049 , 0x00306 , 0x0012C }, - { 0x00049 , 0x00307 , 0x00130 }, - { 0x00049 , 0x00308 , 0x000CF }, - { 0x00049 , 0x00309 , 0x01EC8 }, - { 0x00049 , 0x0030C , 0x001CF }, - { 0x00049 , 0x0030F , 0x00208 }, - { 0x00049 , 0x00311 , 0x0020A }, - { 0x00049 , 0x00323 , 0x01ECA }, - { 0x00049 , 0x00328 , 0x0012E }, - { 0x00049 , 0x00330 , 0x01E2C }, - { 0x0004A , 0x00302 , 0x00134 }, - { 0x0004B , 0x00301 , 0x01E30 }, - { 0x0004B , 0x0030C , 0x001E8 }, - { 0x0004B , 0x00323 , 0x01E32 }, - { 0x0004B , 0x00327 , 0x00136 }, - { 0x0004B , 0x00331 , 0x01E34 }, - { 0x0004C , 0x00301 , 0x00139 }, - { 0x0004C , 0x0030C , 0x0013D }, - { 0x0004C , 0x00323 , 0x01E36 }, - { 0x0004C , 0x00327 , 0x0013B }, - { 0x0004C , 0x0032D , 0x01E3C }, - { 0x0004C , 0x00331 , 0x01E3A }, - { 0x0004D , 0x00301 , 0x01E3E }, - { 0x0004D , 0x00307 , 0x01E40 }, - { 0x0004D , 0x00323 , 0x01E42 }, - { 0x0004E , 0x00300 , 0x001F8 }, - { 0x0004E , 0x00301 , 0x00143 }, - { 0x0004E , 0x00303 , 0x000D1 }, - { 0x0004E , 0x00307 , 0x01E44 }, - { 0x0004E , 0x0030C , 0x00147 }, - { 0x0004E , 0x00323 , 0x01E46 }, - { 0x0004E , 0x00327 , 0x00145 }, - { 0x0004E , 0x0032D , 0x01E4A }, - { 0x0004E , 0x00331 , 0x01E48 }, - { 0x0004F , 0x00300 , 0x000D2 }, - { 0x0004F , 0x00301 , 0x000D3 }, - { 0x0004F , 0x00302 , 0x000D4 }, - { 0x0004F , 0x00303 , 0x000D5 }, - { 0x0004F , 0x00304 , 0x0014C }, - { 0x0004F , 0x00306 , 0x0014E }, - { 0x0004F , 0x00307 , 0x0022E }, - { 0x0004F , 0x00308 , 0x000D6 }, - { 0x0004F , 0x00309 , 0x01ECE }, - { 0x0004F , 0x0030B , 0x00150 }, - { 0x0004F , 0x0030C , 0x001D1 }, - { 0x0004F , 0x0030F , 0x0020C }, - { 0x0004F , 0x00311 , 0x0020E }, - { 0x0004F , 0x0031B , 0x001A0 }, - { 0x0004F , 0x00323 , 0x01ECC }, - { 0x0004F , 0x00328 , 0x001EA }, - { 0x00050 , 0x00301 , 0x01E54 }, - { 0x00050 , 0x00307 , 0x01E56 }, - { 0x00052 , 0x00301 , 0x00154 }, - { 0x00052 , 0x00307 , 0x01E58 }, - { 0x00052 , 0x0030C , 0x00158 }, - { 0x00052 , 0x0030F , 0x00210 }, - { 0x00052 , 0x00311 , 0x00212 }, - { 0x00052 , 0x00323 , 0x01E5A }, - { 0x00052 , 0x00327 , 0x00156 }, - { 0x00052 , 0x00331 , 0x01E5E }, - { 0x00053 , 0x00301 , 0x0015A }, - { 0x00053 , 0x00302 , 0x0015C }, - { 0x00053 , 0x00307 , 0x01E60 }, - { 0x00053 , 0x0030C , 0x00160 }, - { 0x00053 , 0x00323 , 0x01E62 }, - { 0x00053 , 0x00326 , 0x00218 }, - { 0x00053 , 0x00327 , 0x0015E }, - { 0x00054 , 0x00307 , 0x01E6A }, - { 0x00054 , 0x0030C , 0x00164 }, - { 0x00054 , 0x00323 , 0x01E6C }, - { 0x00054 , 0x00326 , 0x0021A }, - { 0x00054 , 0x00327 , 0x00162 }, - { 0x00054 , 0x0032D , 0x01E70 }, - { 0x00054 , 0x00331 , 0x01E6E }, - { 0x00055 , 0x00300 , 0x000D9 }, - { 0x00055 , 0x00301 , 0x000DA }, - { 0x00055 , 0x00302 , 0x000DB }, - { 0x00055 , 0x00303 , 0x00168 }, - { 0x00055 , 0x00304 , 0x0016A }, - { 0x00055 , 0x00306 , 0x0016C }, - { 0x00055 , 0x00308 , 0x000DC }, - { 0x00055 , 0x00309 , 0x01EE6 }, - { 0x00055 , 0x0030A , 0x0016E }, - { 0x00055 , 0x0030B , 0x00170 }, - { 0x00055 , 0x0030C , 0x001D3 }, - { 0x00055 , 0x0030F , 0x00214 }, - { 0x00055 , 0x00311 , 0x00216 }, - { 0x00055 , 0x0031B , 0x001AF }, - { 0x00055 , 0x00323 , 0x01EE4 }, - { 0x00055 , 0x00324 , 0x01E72 }, - { 0x00055 , 0x00328 , 0x00172 }, - { 0x00055 , 0x0032D , 0x01E76 }, - { 0x00055 , 0x00330 , 0x01E74 }, - { 0x00056 , 0x00303 , 0x01E7C }, - { 0x00056 , 0x00323 , 0x01E7E }, - { 0x00057 , 0x00300 , 0x01E80 }, - { 0x00057 , 0x00301 , 0x01E82 }, - { 0x00057 , 0x00302 , 0x00174 }, - { 0x00057 , 0x00307 , 0x01E86 }, - { 0x00057 , 0x00308 , 0x01E84 }, - { 0x00057 , 0x00323 , 0x01E88 }, - { 0x00058 , 0x00307 , 0x01E8A }, - { 0x00058 , 0x00308 , 0x01E8C }, - { 0x00059 , 0x00300 , 0x01EF2 }, - { 0x00059 , 0x00301 , 0x000DD }, - { 0x00059 , 0x00302 , 0x00176 }, - { 0x00059 , 0x00303 , 0x01EF8 }, - { 0x00059 , 0x00304 , 0x00232 }, - { 0x00059 , 0x00307 , 0x01E8E }, - { 0x00059 , 0x00308 , 0x00178 }, - { 0x00059 , 0x00309 , 0x01EF6 }, - { 0x00059 , 0x00323 , 0x01EF4 }, - { 0x0005A , 0x00301 , 0x00179 }, - { 0x0005A , 0x00302 , 0x01E90 }, - { 0x0005A , 0x00307 , 0x0017B }, - { 0x0005A , 0x0030C , 0x0017D }, - { 0x0005A , 0x00323 , 0x01E92 }, - { 0x0005A , 0x00331 , 0x01E94 }, - { 0x00061 , 0x00300 , 0x000E0 }, - { 0x00061 , 0x00301 , 0x000E1 }, - { 0x00061 , 0x00302 , 0x000E2 }, - { 0x00061 , 0x00303 , 0x000E3 }, - { 0x00061 , 0x00304 , 0x00101 }, - { 0x00061 , 0x00306 , 0x00103 }, - { 0x00061 , 0x00307 , 0x00227 }, - { 0x00061 , 0x00308 , 0x000E4 }, - { 0x00061 , 0x00309 , 0x01EA3 }, - { 0x00061 , 0x0030A , 0x000E5 }, - { 0x00061 , 0x0030C , 0x001CE }, - { 0x00061 , 0x0030F , 0x00201 }, - { 0x00061 , 0x00311 , 0x00203 }, - { 0x00061 , 0x00323 , 0x01EA1 }, - { 0x00061 , 0x00325 , 0x01E01 }, - { 0x00061 , 0x00328 , 0x00105 }, - { 0x00062 , 0x00307 , 0x01E03 }, - { 0x00062 , 0x00323 , 0x01E05 }, - { 0x00062 , 0x00331 , 0x01E07 }, - { 0x00063 , 0x00301 , 0x00107 }, - { 0x00063 , 0x00302 , 0x00109 }, - { 0x00063 , 0x00307 , 0x0010B }, - { 0x00063 , 0x0030C , 0x0010D }, - { 0x00063 , 0x00327 , 0x000E7 }, - { 0x00064 , 0x00307 , 0x01E0B }, - { 0x00064 , 0x0030C , 0x0010F }, - { 0x00064 , 0x00323 , 0x01E0D }, - { 0x00064 , 0x00327 , 0x01E11 }, - { 0x00064 , 0x0032D , 0x01E13 }, - { 0x00064 , 0x00331 , 0x01E0F }, - { 0x00065 , 0x00300 , 0x000E8 }, - { 0x00065 , 0x00301 , 0x000E9 }, - { 0x00065 , 0x00302 , 0x000EA }, - { 0x00065 , 0x00303 , 0x01EBD }, - { 0x00065 , 0x00304 , 0x00113 }, - { 0x00065 , 0x00306 , 0x00115 }, - { 0x00065 , 0x00307 , 0x00117 }, - { 0x00065 , 0x00308 , 0x000EB }, - { 0x00065 , 0x00309 , 0x01EBB }, - { 0x00065 , 0x0030C , 0x0011B }, - { 0x00065 , 0x0030F , 0x00205 }, - { 0x00065 , 0x00311 , 0x00207 }, - { 0x00065 , 0x00323 , 0x01EB9 }, - { 0x00065 , 0x00327 , 0x00229 }, - { 0x00065 , 0x00328 , 0x00119 }, - { 0x00065 , 0x0032D , 0x01E19 }, - { 0x00065 , 0x00330 , 0x01E1B }, - { 0x00066 , 0x00307 , 0x01E1F }, - { 0x00067 , 0x00301 , 0x001F5 }, - { 0x00067 , 0x00302 , 0x0011D }, - { 0x00067 , 0x00304 , 0x01E21 }, - { 0x00067 , 0x00306 , 0x0011F }, - { 0x00067 , 0x00307 , 0x00121 }, - { 0x00067 , 0x0030C , 0x001E7 }, - { 0x00067 , 0x00327 , 0x00123 }, - { 0x00068 , 0x00302 , 0x00125 }, - { 0x00068 , 0x00307 , 0x01E23 }, - { 0x00068 , 0x00308 , 0x01E27 }, - { 0x00068 , 0x0030C , 0x0021F }, - { 0x00068 , 0x00323 , 0x01E25 }, - { 0x00068 , 0x00327 , 0x01E29 }, - { 0x00068 , 0x0032E , 0x01E2B }, - { 0x00068 , 0x00331 , 0x01E96 }, - { 0x00069 , 0x00300 , 0x000EC }, - { 0x00069 , 0x00301 , 0x000ED }, - { 0x00069 , 0x00302 , 0x000EE }, - { 0x00069 , 0x00303 , 0x00129 }, - { 0x00069 , 0x00304 , 0x0012B }, - { 0x00069 , 0x00306 , 0x0012D }, - { 0x00069 , 0x00308 , 0x000EF }, - { 0x00069 , 0x00309 , 0x01EC9 }, - { 0x00069 , 0x0030C , 0x001D0 }, - { 0x00069 , 0x0030F , 0x00209 }, - { 0x00069 , 0x00311 , 0x0020B }, - { 0x00069 , 0x00323 , 0x01ECB }, - { 0x00069 , 0x00328 , 0x0012F }, - { 0x00069 , 0x00330 , 0x01E2D }, - { 0x0006A , 0x00302 , 0x00135 }, - { 0x0006A , 0x0030C , 0x001F0 }, - { 0x0006B , 0x00301 , 0x01E31 }, - { 0x0006B , 0x0030C , 0x001E9 }, - { 0x0006B , 0x00323 , 0x01E33 }, - { 0x0006B , 0x00327 , 0x00137 }, - { 0x0006B , 0x00331 , 0x01E35 }, - { 0x0006C , 0x00301 , 0x0013A }, - { 0x0006C , 0x0030C , 0x0013E }, - { 0x0006C , 0x00323 , 0x01E37 }, - { 0x0006C , 0x00327 , 0x0013C }, - { 0x0006C , 0x0032D , 0x01E3D }, - { 0x0006C , 0x00331 , 0x01E3B }, - { 0x0006D , 0x00301 , 0x01E3F }, - { 0x0006D , 0x00307 , 0x01E41 }, - { 0x0006D , 0x00323 , 0x01E43 }, - { 0x0006E , 0x00300 , 0x001F9 }, - { 0x0006E , 0x00301 , 0x00144 }, - { 0x0006E , 0x00303 , 0x000F1 }, - { 0x0006E , 0x00307 , 0x01E45 }, - { 0x0006E , 0x0030C , 0x00148 }, - { 0x0006E , 0x00323 , 0x01E47 }, - { 0x0006E , 0x00327 , 0x00146 }, - { 0x0006E , 0x0032D , 0x01E4B }, - { 0x0006E , 0x00331 , 0x01E49 }, - { 0x0006F , 0x00300 , 0x000F2 }, - { 0x0006F , 0x00301 , 0x000F3 }, - { 0x0006F , 0x00302 , 0x000F4 }, - { 0x0006F , 0x00303 , 0x000F5 }, - { 0x0006F , 0x00304 , 0x0014D }, - { 0x0006F , 0x00306 , 0x0014F }, - { 0x0006F , 0x00307 , 0x0022F }, - { 0x0006F , 0x00308 , 0x000F6 }, - { 0x0006F , 0x00309 , 0x01ECF }, - { 0x0006F , 0x0030B , 0x00151 }, - { 0x0006F , 0x0030C , 0x001D2 }, - { 0x0006F , 0x0030F , 0x0020D }, - { 0x0006F , 0x00311 , 0x0020F }, - { 0x0006F , 0x0031B , 0x001A1 }, - { 0x0006F , 0x00323 , 0x01ECD }, - { 0x0006F , 0x00328 , 0x001EB }, - { 0x00070 , 0x00301 , 0x01E55 }, - { 0x00070 , 0x00307 , 0x01E57 }, - { 0x00072 , 0x00301 , 0x00155 }, - { 0x00072 , 0x00307 , 0x01E59 }, - { 0x00072 , 0x0030C , 0x00159 }, - { 0x00072 , 0x0030F , 0x00211 }, - { 0x00072 , 0x00311 , 0x00213 }, - { 0x00072 , 0x00323 , 0x01E5B }, - { 0x00072 , 0x00327 , 0x00157 }, - { 0x00072 , 0x00331 , 0x01E5F }, - { 0x00073 , 0x00301 , 0x0015B }, - { 0x00073 , 0x00302 , 0x0015D }, - { 0x00073 , 0x00307 , 0x01E61 }, - { 0x00073 , 0x0030C , 0x00161 }, - { 0x00073 , 0x00323 , 0x01E63 }, - { 0x00073 , 0x00326 , 0x00219 }, - { 0x00073 , 0x00327 , 0x0015F }, - { 0x00074 , 0x00307 , 0x01E6B }, - { 0x00074 , 0x00308 , 0x01E97 }, - { 0x00074 , 0x0030C , 0x00165 }, - { 0x00074 , 0x00323 , 0x01E6D }, - { 0x00074 , 0x00326 , 0x0021B }, - { 0x00074 , 0x00327 , 0x00163 }, - { 0x00074 , 0x0032D , 0x01E71 }, - { 0x00074 , 0x00331 , 0x01E6F }, - { 0x00075 , 0x00300 , 0x000F9 }, - { 0x00075 , 0x00301 , 0x000FA }, - { 0x00075 , 0x00302 , 0x000FB }, - { 0x00075 , 0x00303 , 0x00169 }, - { 0x00075 , 0x00304 , 0x0016B }, - { 0x00075 , 0x00306 , 0x0016D }, - { 0x00075 , 0x00308 , 0x000FC }, - { 0x00075 , 0x00309 , 0x01EE7 }, - { 0x00075 , 0x0030A , 0x0016F }, - { 0x00075 , 0x0030B , 0x00171 }, - { 0x00075 , 0x0030C , 0x001D4 }, - { 0x00075 , 0x0030F , 0x00215 }, - { 0x00075 , 0x00311 , 0x00217 }, - { 0x00075 , 0x0031B , 0x001B0 }, - { 0x00075 , 0x00323 , 0x01EE5 }, - { 0x00075 , 0x00324 , 0x01E73 }, - { 0x00075 , 0x00328 , 0x00173 }, - { 0x00075 , 0x0032D , 0x01E77 }, - { 0x00075 , 0x00330 , 0x01E75 }, - { 0x00076 , 0x00303 , 0x01E7D }, - { 0x00076 , 0x00323 , 0x01E7F }, - { 0x00077 , 0x00300 , 0x01E81 }, - { 0x00077 , 0x00301 , 0x01E83 }, - { 0x00077 , 0x00302 , 0x00175 }, - { 0x00077 , 0x00307 , 0x01E87 }, - { 0x00077 , 0x00308 , 0x01E85 }, - { 0x00077 , 0x0030A , 0x01E98 }, - { 0x00077 , 0x00323 , 0x01E89 }, - { 0x00078 , 0x00307 , 0x01E8B }, - { 0x00078 , 0x00308 , 0x01E8D }, - { 0x00079 , 0x00300 , 0x01EF3 }, - { 0x00079 , 0x00301 , 0x000FD }, - { 0x00079 , 0x00302 , 0x00177 }, - { 0x00079 , 0x00303 , 0x01EF9 }, - { 0x00079 , 0x00304 , 0x00233 }, - { 0x00079 , 0x00307 , 0x01E8F }, - { 0x00079 , 0x00308 , 0x000FF }, - { 0x00079 , 0x00309 , 0x01EF7 }, - { 0x00079 , 0x0030A , 0x01E99 }, - { 0x00079 , 0x00323 , 0x01EF5 }, - { 0x0007A , 0x00301 , 0x0017A }, - { 0x0007A , 0x00302 , 0x01E91 }, - { 0x0007A , 0x00307 , 0x0017C }, - { 0x0007A , 0x0030C , 0x0017E }, - { 0x0007A , 0x00323 , 0x01E93 }, - { 0x0007A , 0x00331 , 0x01E95 }, - { 0x000A8 , 0x00300 , 0x01FED }, - { 0x000A8 , 0x00301 , 0x00385 }, - { 0x000A8 , 0x00342 , 0x01FC1 }, - { 0x000C2 , 0x00300 , 0x01EA6 }, - { 0x000C2 , 0x00301 , 0x01EA4 }, - { 0x000C2 , 0x00303 , 0x01EAA }, - { 0x000C2 , 0x00309 , 0x01EA8 }, - { 0x000C4 , 0x00304 , 0x001DE }, - { 0x000C5 , 0x00301 , 0x001FA }, - { 0x000C6 , 0x00301 , 0x001FC }, - { 0x000C6 , 0x00304 , 0x001E2 }, - { 0x000C7 , 0x00301 , 0x01E08 }, - { 0x000CA , 0x00300 , 0x01EC0 }, - { 0x000CA , 0x00301 , 0x01EBE }, - { 0x000CA , 0x00303 , 0x01EC4 }, - { 0x000CA , 0x00309 , 0x01EC2 }, - { 0x000CF , 0x00301 , 0x01E2E }, - { 0x000D4 , 0x00300 , 0x01ED2 }, - { 0x000D4 , 0x00301 , 0x01ED0 }, - { 0x000D4 , 0x00303 , 0x01ED6 }, - { 0x000D4 , 0x00309 , 0x01ED4 }, - { 0x000D5 , 0x00301 , 0x01E4C }, - { 0x000D5 , 0x00304 , 0x0022C }, - { 0x000D5 , 0x00308 , 0x01E4E }, - { 0x000D6 , 0x00304 , 0x0022A }, - { 0x000D8 , 0x00301 , 0x001FE }, - { 0x000DC , 0x00300 , 0x001DB }, - { 0x000DC , 0x00301 , 0x001D7 }, - { 0x000DC , 0x00304 , 0x001D5 }, - { 0x000DC , 0x0030C , 0x001D9 }, - { 0x000E2 , 0x00300 , 0x01EA7 }, - { 0x000E2 , 0x00301 , 0x01EA5 }, - { 0x000E2 , 0x00303 , 0x01EAB }, - { 0x000E2 , 0x00309 , 0x01EA9 }, - { 0x000E4 , 0x00304 , 0x001DF }, - { 0x000E5 , 0x00301 , 0x001FB }, - { 0x000E6 , 0x00301 , 0x001FD }, - { 0x000E6 , 0x00304 , 0x001E3 }, - { 0x000E7 , 0x00301 , 0x01E09 }, - { 0x000EA , 0x00300 , 0x01EC1 }, - { 0x000EA , 0x00301 , 0x01EBF }, - { 0x000EA , 0x00303 , 0x01EC5 }, - { 0x000EA , 0x00309 , 0x01EC3 }, - { 0x000EF , 0x00301 , 0x01E2F }, - { 0x000F4 , 0x00300 , 0x01ED3 }, - { 0x000F4 , 0x00301 , 0x01ED1 }, - { 0x000F4 , 0x00303 , 0x01ED7 }, - { 0x000F4 , 0x00309 , 0x01ED5 }, - { 0x000F5 , 0x00301 , 0x01E4D }, - { 0x000F5 , 0x00304 , 0x0022D }, - { 0x000F5 , 0x00308 , 0x01E4F }, - { 0x000F6 , 0x00304 , 0x0022B }, - { 0x000F8 , 0x00301 , 0x001FF }, - { 0x000FC , 0x00300 , 0x001DC }, - { 0x000FC , 0x00301 , 0x001D8 }, - { 0x000FC , 0x00304 , 0x001D6 }, - { 0x000FC , 0x0030C , 0x001DA }, - { 0x00102 , 0x00300 , 0x01EB0 }, - { 0x00102 , 0x00301 , 0x01EAE }, - { 0x00102 , 0x00303 , 0x01EB4 }, - { 0x00102 , 0x00309 , 0x01EB2 }, - { 0x00103 , 0x00300 , 0x01EB1 }, - { 0x00103 , 0x00301 , 0x01EAF }, - { 0x00103 , 0x00303 , 0x01EB5 }, - { 0x00103 , 0x00309 , 0x01EB3 }, - { 0x00112 , 0x00300 , 0x01E14 }, - { 0x00112 , 0x00301 , 0x01E16 }, - { 0x00113 , 0x00300 , 0x01E15 }, - { 0x00113 , 0x00301 , 0x01E17 }, - { 0x0014C , 0x00300 , 0x01E50 }, - { 0x0014C , 0x00301 , 0x01E52 }, - { 0x0014D , 0x00300 , 0x01E51 }, - { 0x0014D , 0x00301 , 0x01E53 }, - { 0x0015A , 0x00307 , 0x01E64 }, - { 0x0015B , 0x00307 , 0x01E65 }, - { 0x00160 , 0x00307 , 0x01E66 }, - { 0x00161 , 0x00307 , 0x01E67 }, - { 0x00168 , 0x00301 , 0x01E78 }, - { 0x00169 , 0x00301 , 0x01E79 }, - { 0x0016A , 0x00308 , 0x01E7A }, - { 0x0016B , 0x00308 , 0x01E7B }, - { 0x0017F , 0x00307 , 0x01E9B }, - { 0x001A0 , 0x00300 , 0x01EDC }, - { 0x001A0 , 0x00301 , 0x01EDA }, - { 0x001A0 , 0x00303 , 0x01EE0 }, - { 0x001A0 , 0x00309 , 0x01EDE }, - { 0x001A0 , 0x00323 , 0x01EE2 }, - { 0x001A1 , 0x00300 , 0x01EDD }, - { 0x001A1 , 0x00301 , 0x01EDB }, - { 0x001A1 , 0x00303 , 0x01EE1 }, - { 0x001A1 , 0x00309 , 0x01EDF }, - { 0x001A1 , 0x00323 , 0x01EE3 }, - { 0x001AF , 0x00300 , 0x01EEA }, - { 0x001AF , 0x00301 , 0x01EE8 }, - { 0x001AF , 0x00303 , 0x01EEE }, - { 0x001AF , 0x00309 , 0x01EEC }, - { 0x001AF , 0x00323 , 0x01EF0 }, - { 0x001B0 , 0x00300 , 0x01EEB }, - { 0x001B0 , 0x00301 , 0x01EE9 }, - { 0x001B0 , 0x00303 , 0x01EEF }, - { 0x001B0 , 0x00309 , 0x01EED }, - { 0x001B0 , 0x00323 , 0x01EF1 }, - { 0x001B7 , 0x0030C , 0x001EE }, - { 0x001EA , 0x00304 , 0x001EC }, - { 0x001EB , 0x00304 , 0x001ED }, - { 0x00226 , 0x00304 , 0x001E0 }, - { 0x00227 , 0x00304 , 0x001E1 }, - { 0x00228 , 0x00306 , 0x01E1C }, - { 0x00229 , 0x00306 , 0x01E1D }, - { 0x0022E , 0x00304 , 0x00230 }, - { 0x0022F , 0x00304 , 0x00231 }, - { 0x00292 , 0x0030C , 0x001EF }, - { 0x00391 , 0x00300 , 0x01FBA }, - { 0x00391 , 0x00301 , 0x00386 }, - { 0x00391 , 0x00304 , 0x01FB9 }, - { 0x00391 , 0x00306 , 0x01FB8 }, - { 0x00391 , 0x00313 , 0x01F08 }, - { 0x00391 , 0x00314 , 0x01F09 }, - { 0x00391 , 0x00345 , 0x01FBC }, - { 0x00395 , 0x00300 , 0x01FC8 }, - { 0x00395 , 0x00301 , 0x00388 }, - { 0x00395 , 0x00313 , 0x01F18 }, - { 0x00395 , 0x00314 , 0x01F19 }, - { 0x00397 , 0x00300 , 0x01FCA }, - { 0x00397 , 0x00301 , 0x00389 }, - { 0x00397 , 0x00313 , 0x01F28 }, - { 0x00397 , 0x00314 , 0x01F29 }, - { 0x00397 , 0x00345 , 0x01FCC }, - { 0x00399 , 0x00300 , 0x01FDA }, - { 0x00399 , 0x00301 , 0x0038A }, - { 0x00399 , 0x00304 , 0x01FD9 }, - { 0x00399 , 0x00306 , 0x01FD8 }, - { 0x00399 , 0x00308 , 0x003AA }, - { 0x00399 , 0x00313 , 0x01F38 }, - { 0x00399 , 0x00314 , 0x01F39 }, - { 0x0039F , 0x00300 , 0x01FF8 }, - { 0x0039F , 0x00301 , 0x0038C }, - { 0x0039F , 0x00313 , 0x01F48 }, - { 0x0039F , 0x00314 , 0x01F49 }, - { 0x003A1 , 0x00314 , 0x01FEC }, - { 0x003A5 , 0x00300 , 0x01FEA }, - { 0x003A5 , 0x00301 , 0x0038E }, - { 0x003A5 , 0x00304 , 0x01FE9 }, - { 0x003A5 , 0x00306 , 0x01FE8 }, - { 0x003A5 , 0x00308 , 0x003AB }, - { 0x003A5 , 0x00314 , 0x01F59 }, - { 0x003A9 , 0x00300 , 0x01FFA }, - { 0x003A9 , 0x00301 , 0x0038F }, - { 0x003A9 , 0x00313 , 0x01F68 }, - { 0x003A9 , 0x00314 , 0x01F69 }, - { 0x003A9 , 0x00345 , 0x01FFC }, - { 0x003AC , 0x00345 , 0x01FB4 }, - { 0x003AE , 0x00345 , 0x01FC4 }, - { 0x003B1 , 0x00300 , 0x01F70 }, - { 0x003B1 , 0x00301 , 0x003AC }, - { 0x003B1 , 0x00304 , 0x01FB1 }, - { 0x003B1 , 0x00306 , 0x01FB0 }, - { 0x003B1 , 0x00313 , 0x01F00 }, - { 0x003B1 , 0x00314 , 0x01F01 }, - { 0x003B1 , 0x00342 , 0x01FB6 }, - { 0x003B1 , 0x00345 , 0x01FB3 }, - { 0x003B5 , 0x00300 , 0x01F72 }, - { 0x003B5 , 0x00301 , 0x003AD }, - { 0x003B5 , 0x00313 , 0x01F10 }, - { 0x003B5 , 0x00314 , 0x01F11 }, - { 0x003B7 , 0x00300 , 0x01F74 }, - { 0x003B7 , 0x00301 , 0x003AE }, - { 0x003B7 , 0x00313 , 0x01F20 }, - { 0x003B7 , 0x00314 , 0x01F21 }, - { 0x003B7 , 0x00342 , 0x01FC6 }, - { 0x003B7 , 0x00345 , 0x01FC3 }, - { 0x003B9 , 0x00300 , 0x01F76 }, - { 0x003B9 , 0x00301 , 0x003AF }, - { 0x003B9 , 0x00304 , 0x01FD1 }, - { 0x003B9 , 0x00306 , 0x01FD0 }, - { 0x003B9 , 0x00308 , 0x003CA }, - { 0x003B9 , 0x00313 , 0x01F30 }, - { 0x003B9 , 0x00314 , 0x01F31 }, - { 0x003B9 , 0x00342 , 0x01FD6 }, - { 0x003BF , 0x00300 , 0x01F78 }, - { 0x003BF , 0x00301 , 0x003CC }, - { 0x003BF , 0x00313 , 0x01F40 }, - { 0x003BF , 0x00314 , 0x01F41 }, - { 0x003C1 , 0x00313 , 0x01FE4 }, - { 0x003C1 , 0x00314 , 0x01FE5 }, - { 0x003C5 , 0x00300 , 0x01F7A }, - { 0x003C5 , 0x00301 , 0x003CD }, - { 0x003C5 , 0x00304 , 0x01FE1 }, - { 0x003C5 , 0x00306 , 0x01FE0 }, - { 0x003C5 , 0x00308 , 0x003CB }, - { 0x003C5 , 0x00313 , 0x01F50 }, - { 0x003C5 , 0x00314 , 0x01F51 }, - { 0x003C5 , 0x00342 , 0x01FE6 }, - { 0x003C9 , 0x00300 , 0x01F7C }, - { 0x003C9 , 0x00301 , 0x003CE }, - { 0x003C9 , 0x00313 , 0x01F60 }, - { 0x003C9 , 0x00314 , 0x01F61 }, - { 0x003C9 , 0x00342 , 0x01FF6 }, - { 0x003C9 , 0x00345 , 0x01FF3 }, - { 0x003CA , 0x00300 , 0x01FD2 }, - { 0x003CA , 0x00301 , 0x00390 }, - { 0x003CA , 0x00342 , 0x01FD7 }, - { 0x003CB , 0x00300 , 0x01FE2 }, - { 0x003CB , 0x00301 , 0x003B0 }, - { 0x003CB , 0x00342 , 0x01FE7 }, - { 0x003CE , 0x00345 , 0x01FF4 }, - { 0x003D2 , 0x00301 , 0x003D3 }, - { 0x003D2 , 0x00308 , 0x003D4 }, - { 0x00406 , 0x00308 , 0x00407 }, - { 0x00410 , 0x00306 , 0x004D0 }, - { 0x00410 , 0x00308 , 0x004D2 }, - { 0x00413 , 0x00301 , 0x00403 }, - { 0x00415 , 0x00300 , 0x00400 }, - { 0x00415 , 0x00306 , 0x004D6 }, - { 0x00415 , 0x00308 , 0x00401 }, - { 0x00416 , 0x00306 , 0x004C1 }, - { 0x00416 , 0x00308 , 0x004DC }, - { 0x00417 , 0x00308 , 0x004DE }, - { 0x00418 , 0x00300 , 0x0040D }, - { 0x00418 , 0x00304 , 0x004E2 }, - { 0x00418 , 0x00306 , 0x00419 }, - { 0x00418 , 0x00308 , 0x004E4 }, - { 0x0041A , 0x00301 , 0x0040C }, - { 0x0041E , 0x00308 , 0x004E6 }, - { 0x00423 , 0x00304 , 0x004EE }, - { 0x00423 , 0x00306 , 0x0040E }, - { 0x00423 , 0x00308 , 0x004F0 }, - { 0x00423 , 0x0030B , 0x004F2 }, - { 0x00427 , 0x00308 , 0x004F4 }, - { 0x0042B , 0x00308 , 0x004F8 }, - { 0x0042D , 0x00308 , 0x004EC }, - { 0x00430 , 0x00306 , 0x004D1 }, - { 0x00430 , 0x00308 , 0x004D3 }, - { 0x00433 , 0x00301 , 0x00453 }, - { 0x00435 , 0x00300 , 0x00450 }, - { 0x00435 , 0x00306 , 0x004D7 }, - { 0x00435 , 0x00308 , 0x00451 }, - { 0x00436 , 0x00306 , 0x004C2 }, - { 0x00436 , 0x00308 , 0x004DD }, - { 0x00437 , 0x00308 , 0x004DF }, - { 0x00438 , 0x00300 , 0x0045D }, - { 0x00438 , 0x00304 , 0x004E3 }, - { 0x00438 , 0x00306 , 0x00439 }, - { 0x00438 , 0x00308 , 0x004E5 }, - { 0x0043A , 0x00301 , 0x0045C }, - { 0x0043E , 0x00308 , 0x004E7 }, - { 0x00443 , 0x00304 , 0x004EF }, - { 0x00443 , 0x00306 , 0x0045E }, - { 0x00443 , 0x00308 , 0x004F1 }, - { 0x00443 , 0x0030B , 0x004F3 }, - { 0x00447 , 0x00308 , 0x004F5 }, - { 0x0044B , 0x00308 , 0x004F9 }, - { 0x0044D , 0x00308 , 0x004ED }, - { 0x00456 , 0x00308 , 0x00457 }, - { 0x00474 , 0x0030F , 0x00476 }, - { 0x00475 , 0x0030F , 0x00477 }, - { 0x004D8 , 0x00308 , 0x004DA }, - { 0x004D9 , 0x00308 , 0x004DB }, - { 0x004E8 , 0x00308 , 0x004EA }, - { 0x004E9 , 0x00308 , 0x004EB }, - { 0x00627 , 0x00653 , 0x00622 }, - { 0x00627 , 0x00654 , 0x00623 }, - { 0x00627 , 0x00655 , 0x00625 }, - { 0x00648 , 0x00654 , 0x00624 }, - { 0x0064A , 0x00654 , 0x00626 }, - { 0x006C1 , 0x00654 , 0x006C2 }, - { 0x006D2 , 0x00654 , 0x006D3 }, - { 0x006D5 , 0x00654 , 0x006C0 }, - { 0x00928 , 0x0093C , 0x00929 }, - { 0x00930 , 0x0093C , 0x00931 }, - { 0x00933 , 0x0093C , 0x00934 }, - { 0x009C7 , 0x009BE , 0x009CB }, - { 0x009C7 , 0x009D7 , 0x009CC }, - { 0x00B47 , 0x00B3E , 0x00B4B }, - { 0x00B47 , 0x00B56 , 0x00B48 }, - { 0x00B47 , 0x00B57 , 0x00B4C }, - { 0x00B92 , 0x00BD7 , 0x00B94 }, - { 0x00BC6 , 0x00BBE , 0x00BCA }, - { 0x00BC6 , 0x00BD7 , 0x00BCC }, - { 0x00BC7 , 0x00BBE , 0x00BCB }, - { 0x00C46 , 0x00C56 , 0x00C48 }, - { 0x00CBF , 0x00CD5 , 0x00CC0 }, - { 0x00CC6 , 0x00CC2 , 0x00CCA }, - { 0x00CC6 , 0x00CD5 , 0x00CC7 }, - { 0x00CC6 , 0x00CD6 , 0x00CC8 }, - { 0x00CCA , 0x00CD5 , 0x00CCB }, - { 0x00D46 , 0x00D3E , 0x00D4A }, - { 0x00D46 , 0x00D57 , 0x00D4C }, - { 0x00D47 , 0x00D3E , 0x00D4B }, - { 0x00DD9 , 0x00DCA , 0x00DDA }, - { 0x00DD9 , 0x00DCF , 0x00DDC }, - { 0x00DD9 , 0x00DDF , 0x00DDE }, - { 0x00DDC , 0x00DCA , 0x00DDD }, - { 0x01025 , 0x0102E , 0x01026 }, - { 0x01B05 , 0x01B35 , 0x01B06 }, - { 0x01B07 , 0x01B35 , 0x01B08 }, - { 0x01B09 , 0x01B35 , 0x01B0A }, - { 0x01B0B , 0x01B35 , 0x01B0C }, - { 0x01B0D , 0x01B35 , 0x01B0E }, - { 0x01B11 , 0x01B35 , 0x01B12 }, - { 0x01B3A , 0x01B35 , 0x01B3B }, - { 0x01B3C , 0x01B35 , 0x01B3D }, - { 0x01B3E , 0x01B35 , 0x01B40 }, - { 0x01B3F , 0x01B35 , 0x01B41 }, - { 0x01B42 , 0x01B35 , 0x01B43 }, - { 0x01E36 , 0x00304 , 0x01E38 }, - { 0x01E37 , 0x00304 , 0x01E39 }, - { 0x01E5A , 0x00304 , 0x01E5C }, - { 0x01E5B , 0x00304 , 0x01E5D }, - { 0x01E62 , 0x00307 , 0x01E68 }, - { 0x01E63 , 0x00307 , 0x01E69 }, - { 0x01EA0 , 0x00302 , 0x01EAC }, - { 0x01EA0 , 0x00306 , 0x01EB6 }, - { 0x01EA1 , 0x00302 , 0x01EAD }, - { 0x01EA1 , 0x00306 , 0x01EB7 }, - { 0x01EB8 , 0x00302 , 0x01EC6 }, - { 0x01EB9 , 0x00302 , 0x01EC7 }, - { 0x01ECC , 0x00302 , 0x01ED8 }, - { 0x01ECD , 0x00302 , 0x01ED9 }, - { 0x01F00 , 0x00300 , 0x01F02 }, - { 0x01F00 , 0x00301 , 0x01F04 }, - { 0x01F00 , 0x00342 , 0x01F06 }, - { 0x01F00 , 0x00345 , 0x01F80 }, - { 0x01F01 , 0x00300 , 0x01F03 }, - { 0x01F01 , 0x00301 , 0x01F05 }, - { 0x01F01 , 0x00342 , 0x01F07 }, - { 0x01F01 , 0x00345 , 0x01F81 }, - { 0x01F02 , 0x00345 , 0x01F82 }, - { 0x01F03 , 0x00345 , 0x01F83 }, - { 0x01F04 , 0x00345 , 0x01F84 }, - { 0x01F05 , 0x00345 , 0x01F85 }, - { 0x01F06 , 0x00345 , 0x01F86 }, - { 0x01F07 , 0x00345 , 0x01F87 }, - { 0x01F08 , 0x00300 , 0x01F0A }, - { 0x01F08 , 0x00301 , 0x01F0C }, - { 0x01F08 , 0x00342 , 0x01F0E }, - { 0x01F08 , 0x00345 , 0x01F88 }, - { 0x01F09 , 0x00300 , 0x01F0B }, - { 0x01F09 , 0x00301 , 0x01F0D }, - { 0x01F09 , 0x00342 , 0x01F0F }, - { 0x01F09 , 0x00345 , 0x01F89 }, - { 0x01F0A , 0x00345 , 0x01F8A }, - { 0x01F0B , 0x00345 , 0x01F8B }, - { 0x01F0C , 0x00345 , 0x01F8C }, - { 0x01F0D , 0x00345 , 0x01F8D }, - { 0x01F0E , 0x00345 , 0x01F8E }, - { 0x01F0F , 0x00345 , 0x01F8F }, - { 0x01F10 , 0x00300 , 0x01F12 }, - { 0x01F10 , 0x00301 , 0x01F14 }, - { 0x01F11 , 0x00300 , 0x01F13 }, - { 0x01F11 , 0x00301 , 0x01F15 }, - { 0x01F18 , 0x00300 , 0x01F1A }, - { 0x01F18 , 0x00301 , 0x01F1C }, - { 0x01F19 , 0x00300 , 0x01F1B }, - { 0x01F19 , 0x00301 , 0x01F1D }, - { 0x01F20 , 0x00300 , 0x01F22 }, - { 0x01F20 , 0x00301 , 0x01F24 }, - { 0x01F20 , 0x00342 , 0x01F26 }, - { 0x01F20 , 0x00345 , 0x01F90 }, - { 0x01F21 , 0x00300 , 0x01F23 }, - { 0x01F21 , 0x00301 , 0x01F25 }, - { 0x01F21 , 0x00342 , 0x01F27 }, - { 0x01F21 , 0x00345 , 0x01F91 }, - { 0x01F22 , 0x00345 , 0x01F92 }, - { 0x01F23 , 0x00345 , 0x01F93 }, - { 0x01F24 , 0x00345 , 0x01F94 }, - { 0x01F25 , 0x00345 , 0x01F95 }, - { 0x01F26 , 0x00345 , 0x01F96 }, - { 0x01F27 , 0x00345 , 0x01F97 }, - { 0x01F28 , 0x00300 , 0x01F2A }, - { 0x01F28 , 0x00301 , 0x01F2C }, - { 0x01F28 , 0x00342 , 0x01F2E }, - { 0x01F28 , 0x00345 , 0x01F98 }, - { 0x01F29 , 0x00300 , 0x01F2B }, - { 0x01F29 , 0x00301 , 0x01F2D }, - { 0x01F29 , 0x00342 , 0x01F2F }, - { 0x01F29 , 0x00345 , 0x01F99 }, - { 0x01F2A , 0x00345 , 0x01F9A }, - { 0x01F2B , 0x00345 , 0x01F9B }, - { 0x01F2C , 0x00345 , 0x01F9C }, - { 0x01F2D , 0x00345 , 0x01F9D }, - { 0x01F2E , 0x00345 , 0x01F9E }, - { 0x01F2F , 0x00345 , 0x01F9F }, - { 0x01F30 , 0x00300 , 0x01F32 }, - { 0x01F30 , 0x00301 , 0x01F34 }, - { 0x01F30 , 0x00342 , 0x01F36 }, - { 0x01F31 , 0x00300 , 0x01F33 }, - { 0x01F31 , 0x00301 , 0x01F35 }, - { 0x01F31 , 0x00342 , 0x01F37 }, - { 0x01F38 , 0x00300 , 0x01F3A }, - { 0x01F38 , 0x00301 , 0x01F3C }, - { 0x01F38 , 0x00342 , 0x01F3E }, - { 0x01F39 , 0x00300 , 0x01F3B }, - { 0x01F39 , 0x00301 , 0x01F3D }, - { 0x01F39 , 0x00342 , 0x01F3F }, - { 0x01F40 , 0x00300 , 0x01F42 }, - { 0x01F40 , 0x00301 , 0x01F44 }, - { 0x01F41 , 0x00300 , 0x01F43 }, - { 0x01F41 , 0x00301 , 0x01F45 }, - { 0x01F48 , 0x00300 , 0x01F4A }, - { 0x01F48 , 0x00301 , 0x01F4C }, - { 0x01F49 , 0x00300 , 0x01F4B }, - { 0x01F49 , 0x00301 , 0x01F4D }, - { 0x01F50 , 0x00300 , 0x01F52 }, - { 0x01F50 , 0x00301 , 0x01F54 }, - { 0x01F50 , 0x00342 , 0x01F56 }, - { 0x01F51 , 0x00300 , 0x01F53 }, - { 0x01F51 , 0x00301 , 0x01F55 }, - { 0x01F51 , 0x00342 , 0x01F57 }, - { 0x01F59 , 0x00300 , 0x01F5B }, - { 0x01F59 , 0x00301 , 0x01F5D }, - { 0x01F59 , 0x00342 , 0x01F5F }, - { 0x01F60 , 0x00300 , 0x01F62 }, - { 0x01F60 , 0x00301 , 0x01F64 }, - { 0x01F60 , 0x00342 , 0x01F66 }, - { 0x01F60 , 0x00345 , 0x01FA0 }, - { 0x01F61 , 0x00300 , 0x01F63 }, - { 0x01F61 , 0x00301 , 0x01F65 }, - { 0x01F61 , 0x00342 , 0x01F67 }, - { 0x01F61 , 0x00345 , 0x01FA1 }, - { 0x01F62 , 0x00345 , 0x01FA2 }, - { 0x01F63 , 0x00345 , 0x01FA3 }, - { 0x01F64 , 0x00345 , 0x01FA4 }, - { 0x01F65 , 0x00345 , 0x01FA5 }, - { 0x01F66 , 0x00345 , 0x01FA6 }, - { 0x01F67 , 0x00345 , 0x01FA7 }, - { 0x01F68 , 0x00300 , 0x01F6A }, - { 0x01F68 , 0x00301 , 0x01F6C }, - { 0x01F68 , 0x00342 , 0x01F6E }, - { 0x01F68 , 0x00345 , 0x01FA8 }, - { 0x01F69 , 0x00300 , 0x01F6B }, - { 0x01F69 , 0x00301 , 0x01F6D }, - { 0x01F69 , 0x00342 , 0x01F6F }, - { 0x01F69 , 0x00345 , 0x01FA9 }, - { 0x01F6A , 0x00345 , 0x01FAA }, - { 0x01F6B , 0x00345 , 0x01FAB }, - { 0x01F6C , 0x00345 , 0x01FAC }, - { 0x01F6D , 0x00345 , 0x01FAD }, - { 0x01F6E , 0x00345 , 0x01FAE }, - { 0x01F6F , 0x00345 , 0x01FAF }, - { 0x01F70 , 0x00345 , 0x01FB2 }, - { 0x01F74 , 0x00345 , 0x01FC2 }, - { 0x01F7C , 0x00345 , 0x01FF2 }, - { 0x01FB6 , 0x00345 , 0x01FB7 }, - { 0x01FBF , 0x00300 , 0x01FCD }, - { 0x01FBF , 0x00301 , 0x01FCE }, - { 0x01FBF , 0x00342 , 0x01FCF }, - { 0x01FC6 , 0x00345 , 0x01FC7 }, - { 0x01FF6 , 0x00345 , 0x01FF7 }, - { 0x01FFE , 0x00300 , 0x01FDD }, - { 0x01FFE , 0x00301 , 0x01FDE }, - { 0x01FFE , 0x00342 , 0x01FDF }, - { 0x02190 , 0x00338 , 0x0219A }, - { 0x02192 , 0x00338 , 0x0219B }, - { 0x02194 , 0x00338 , 0x021AE }, - { 0x021D0 , 0x00338 , 0x021CD }, - { 0x021D2 , 0x00338 , 0x021CF }, - { 0x021D4 , 0x00338 , 0x021CE }, - { 0x02203 , 0x00338 , 0x02204 }, - { 0x02208 , 0x00338 , 0x02209 }, - { 0x0220B , 0x00338 , 0x0220C }, - { 0x02223 , 0x00338 , 0x02224 }, - { 0x02225 , 0x00338 , 0x02226 }, - { 0x0223C , 0x00338 , 0x02241 }, - { 0x02243 , 0x00338 , 0x02244 }, - { 0x02245 , 0x00338 , 0x02247 }, - { 0x02248 , 0x00338 , 0x02249 }, - { 0x0224D , 0x00338 , 0x0226D }, - { 0x02261 , 0x00338 , 0x02262 }, - { 0x02264 , 0x00338 , 0x02270 }, - { 0x02265 , 0x00338 , 0x02271 }, - { 0x02272 , 0x00338 , 0x02274 }, - { 0x02273 , 0x00338 , 0x02275 }, - { 0x02276 , 0x00338 , 0x02278 }, - { 0x02277 , 0x00338 , 0x02279 }, - { 0x0227A , 0x00338 , 0x02280 }, - { 0x0227B , 0x00338 , 0x02281 }, - { 0x0227C , 0x00338 , 0x022E0 }, - { 0x0227D , 0x00338 , 0x022E1 }, - { 0x02282 , 0x00338 , 0x02284 }, - { 0x02283 , 0x00338 , 0x02285 }, - { 0x02286 , 0x00338 , 0x02288 }, - { 0x02287 , 0x00338 , 0x02289 }, - { 0x02291 , 0x00338 , 0x022E2 }, - { 0x02292 , 0x00338 , 0x022E3 }, - { 0x022A2 , 0x00338 , 0x022AC }, - { 0x022A8 , 0x00338 , 0x022AD }, - { 0x022A9 , 0x00338 , 0x022AE }, - { 0x022AB , 0x00338 , 0x022AF }, - { 0x022B2 , 0x00338 , 0x022EA }, - { 0x022B3 , 0x00338 , 0x022EB }, - { 0x022B4 , 0x00338 , 0x022EC }, - { 0x022B5 , 0x00338 , 0x022ED }, - { 0x03046 , 0x03099 , 0x03094 }, - { 0x0304B , 0x03099 , 0x0304C }, - { 0x0304D , 0x03099 , 0x0304E }, - { 0x0304F , 0x03099 , 0x03050 }, - { 0x03051 , 0x03099 , 0x03052 }, - { 0x03053 , 0x03099 , 0x03054 }, - { 0x03055 , 0x03099 , 0x03056 }, - { 0x03057 , 0x03099 , 0x03058 }, - { 0x03059 , 0x03099 , 0x0305A }, - { 0x0305B , 0x03099 , 0x0305C }, - { 0x0305D , 0x03099 , 0x0305E }, - { 0x0305F , 0x03099 , 0x03060 }, - { 0x03061 , 0x03099 , 0x03062 }, - { 0x03064 , 0x03099 , 0x03065 }, - { 0x03066 , 0x03099 , 0x03067 }, - { 0x03068 , 0x03099 , 0x03069 }, - { 0x0306F , 0x03099 , 0x03070 }, - { 0x0306F , 0x0309A , 0x03071 }, - { 0x03072 , 0x03099 , 0x03073 }, - { 0x03072 , 0x0309A , 0x03074 }, - { 0x03075 , 0x03099 , 0x03076 }, - { 0x03075 , 0x0309A , 0x03077 }, - { 0x03078 , 0x03099 , 0x03079 }, - { 0x03078 , 0x0309A , 0x0307A }, - { 0x0307B , 0x03099 , 0x0307C }, - { 0x0307B , 0x0309A , 0x0307D }, - { 0x0309D , 0x03099 , 0x0309E }, - { 0x030A6 , 0x03099 , 0x030F4 }, - { 0x030AB , 0x03099 , 0x030AC }, - { 0x030AD , 0x03099 , 0x030AE }, - { 0x030AF , 0x03099 , 0x030B0 }, - { 0x030B1 , 0x03099 , 0x030B2 }, - { 0x030B3 , 0x03099 , 0x030B4 }, - { 0x030B5 , 0x03099 , 0x030B6 }, - { 0x030B7 , 0x03099 , 0x030B8 }, - { 0x030B9 , 0x03099 , 0x030BA }, - { 0x030BB , 0x03099 , 0x030BC }, - { 0x030BD , 0x03099 , 0x030BE }, - { 0x030BF , 0x03099 , 0x030C0 }, - { 0x030C1 , 0x03099 , 0x030C2 }, - { 0x030C4 , 0x03099 , 0x030C5 }, - { 0x030C6 , 0x03099 , 0x030C7 }, - { 0x030C8 , 0x03099 , 0x030C9 }, - { 0x030CF , 0x03099 , 0x030D0 }, - { 0x030CF , 0x0309A , 0x030D1 }, - { 0x030D2 , 0x03099 , 0x030D3 }, - { 0x030D2 , 0x0309A , 0x030D4 }, - { 0x030D5 , 0x03099 , 0x030D6 }, - { 0x030D5 , 0x0309A , 0x030D7 }, - { 0x030D8 , 0x03099 , 0x030D9 }, - { 0x030D8 , 0x0309A , 0x030DA }, - { 0x030DB , 0x03099 , 0x030DC }, - { 0x030DB , 0x0309A , 0x030DD }, - { 0x030EF , 0x03099 , 0x030F7 }, - { 0x030F0 , 0x03099 , 0x030F8 }, - { 0x030F1 , 0x03099 , 0x030F9 }, - { 0x030F2 , 0x03099 , 0x030FA }, - { 0x030FD , 0x03099 , 0x030FE }, - { 0x11099 , 0x110BA , 0x1109A }, - { 0x1109B , 0x110BA , 0x1109C }, - { 0x110A5 , 0x110BA , 0x110AB }, -}; - -#define CANONICAL_CLASS_MIN 0x0300 -#define CANONICAL_CLASS_MAX 0x1D244 - -#define IS_DECOMPOSABLE_BLOCK(uc) \ - (((uc)>>8) <= 0x1D2 && u_decomposable_blocks[(uc)>>8]) -static const char u_decomposable_blocks[0x1D2+1] = { - 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0, - 1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, - 0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, -}; - -/* Get Canonical Combining Class(CCC). */ -#define CCC(uc) \ - (((uc) > 0x1D244)?0:\ - ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F]) - -/* The table of the value of Canonical Combining Class */ -static const unsigned char ccc_val[][16] = { - /* idx=0: XXXX0 - XXXXF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=1: 00300 - 0030F */ - {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=2: 00310 - 0031F */ - {230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220 }, - /* idx=3: 00320 - 0032F */ - {220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220 }, - /* idx=4: 00330 - 0033F */ - {220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230 }, - /* idx=5: 00340 - 0034F */ - {230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0 }, - /* idx=6: 00350 - 0035F */ - {230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220, 230, 233, 234, 234, 233 }, - /* idx=7: 00360 - 0036F */ - {234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=8: 00480 - 0048F */ - {0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=9: 00590 - 0059F */ - {0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230 }, - /* idx=10: 005A0 - 005AF */ - {230, 230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230 }, - /* idx=11: 005B0 - 005BF */ - {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23 }, - /* idx=12: 005C0 - 005CF */ - {0, 24, 25, 0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=13: 00610 - 0061F */ - {230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, 0, 0 }, - /* idx=14: 00640 - 0064F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31 }, - /* idx=15: 00650 - 0065F */ - {32, 33, 34, 230, 230, 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 220 }, - /* idx=16: 00670 - 0067F */ - {35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=17: 006D0 - 006DF */ - {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230 }, - /* idx=18: 006E0 - 006EF */ - {230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0 }, - /* idx=19: 00710 - 0071F */ - {0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=20: 00730 - 0073F */ - {230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230 }, - /* idx=21: 00740 - 0074F */ - {230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, 0, 0 }, - /* idx=22: 007E0 - 007EF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230 }, - /* idx=23: 007F0 - 007FF */ - {230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=24: 00810 - 0081F */ - {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230 }, - /* idx=25: 00820 - 0082F */ - {230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0 }, - /* idx=26: 00850 - 0085F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0, 0, 0 }, - /* idx=27: 00930 - 0093F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=28: 00940 - 0094F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=29: 00950 - 0095F */ - {0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=30: 009B0 - 009BF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=31: 009C0 - 009CF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=32: 00A30 - 00A3F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=33: 00A40 - 00A4F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=34: 00AB0 - 00ABF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=35: 00AC0 - 00ACF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=36: 00B30 - 00B3F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=37: 00B40 - 00B4F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=38: 00BC0 - 00BCF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=39: 00C40 - 00C4F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=40: 00C50 - 00C5F */ - {0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=41: 00CB0 - 00CBF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, - /* idx=42: 00CC0 - 00CCF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=43: 00D40 - 00D4F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=44: 00DC0 - 00DCF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 }, - /* idx=45: 00E30 - 00E3F */ - {0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0 }, - /* idx=46: 00E40 - 00E4F */ - {0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0 }, - /* idx=47: 00EB0 - 00EBF */ - {0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0, 0, 0, 0, 0 }, - /* idx=48: 00EC0 - 00ECF */ - {0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0 }, - /* idx=49: 00F10 - 00F1F */ - {0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0 }, - /* idx=50: 00F30 - 00F3F */ - {0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0 }, - /* idx=51: 00F70 - 00F7F */ - {0, 129, 130, 0, 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0 }, - /* idx=52: 00F80 - 00F8F */ - {130, 0, 230, 230, 9, 0, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=53: 00FC0 - 00FCF */ - {0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=54: 01030 - 0103F */ - {0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0 }, - /* idx=55: 01080 - 0108F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, - /* idx=56: 01350 - 0135F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230 }, - /* idx=57: 01710 - 0171F */ - {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=58: 01730 - 0173F */ - {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=59: 017D0 - 017DF */ - {0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0 }, - /* idx=60: 018A0 - 018AF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0 }, - /* idx=61: 01930 - 0193F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0 }, - /* idx=62: 01A10 - 01A1F */ - {0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=63: 01A60 - 01A6F */ - {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=64: 01A70 - 01A7F */ - {0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 220 }, - /* idx=65: 01B30 - 01B3F */ - {0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=66: 01B40 - 01B4F */ - {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=67: 01B60 - 01B6F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230 }, - /* idx=68: 01B70 - 01B7F */ - {230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=69: 01BA0 - 01BAF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 }, - /* idx=70: 01BE0 - 01BEF */ - {0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=71: 01BF0 - 01BFF */ - {0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=72: 01C30 - 01C3F */ - {0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=73: 01CD0 - 01CDF */ - {230, 230, 230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220 }, - /* idx=74: 01CE0 - 01CEF */ - {230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0 }, - /* idx=75: 01DC0 - 01DCF */ - {230, 230, 220, 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220 }, - /* idx=76: 01DD0 - 01DDF */ - {202, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=77: 01DE0 - 01DEF */ - {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=78: 01DF0 - 01DFF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 220, 230, 220 }, - /* idx=79: 020D0 - 020DF */ - {230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0 }, - /* idx=80: 020E0 - 020EF */ - {0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220 }, - /* idx=81: 020F0 - 020FF */ - {230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=82: 02CE0 - 02CEF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 }, - /* idx=83: 02CF0 - 02CFF */ - {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=84: 02D70 - 02D7F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }, - /* idx=85: 02DE0 - 02DEF */ - {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=86: 02DF0 - 02DFF */ - {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=87: 03020 - 0302F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224 }, - /* idx=88: 03090 - 0309F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0 }, - /* idx=89: 0A660 - 0A66F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 }, - /* idx=90: 0A670 - 0A67F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0 }, - /* idx=91: 0A6F0 - 0A6FF */ - {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=92: 0A800 - 0A80F */ - {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=93: 0A8C0 - 0A8CF */ - {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=94: 0A8E0 - 0A8EF */ - {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, - /* idx=95: 0A8F0 - 0A8FF */ - {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=96: 0A920 - 0A92F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0 }, - /* idx=97: 0A950 - 0A95F */ - {0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=98: 0A9B0 - 0A9BF */ - {0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=99: 0A9C0 - 0A9CF */ - {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=100: 0AAB0 - 0AABF */ - {230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0, 230, 230 }, - /* idx=101: 0AAC0 - 0AACF */ - {0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=102: 0ABE0 - 0ABEF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, - /* idx=103: 0FB10 - 0FB1F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0 }, - /* idx=104: 0FE20 - 0FE2F */ - {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=105: 101F0 - 101FF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, - /* idx=106: 10A00 - 10A0F */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230 }, - /* idx=107: 10A30 - 10A3F */ - {0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, 0, 0, 0, 9 }, - /* idx=108: 11040 - 1104F */ - {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=109: 110B0 - 110BF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0 }, - /* idx=110: 1D160 - 1D16F */ - {0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216 }, - /* idx=111: 1D170 - 1D17F */ - {216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220 }, - /* idx=112: 1D180 - 1D18F */ - {220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0 }, - /* idx=113: 1D1A0 - 1D1AF */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0 }, - /* idx=114: 1D240 - 1D24F */ - {0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, -}; - -/* The index table to ccc_val[*][16] */ -static const unsigned char ccc_val_index[][16] = { - /* idx=0: XXX00 - XXXFF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=1: 00300 - 003FF */ - { 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=2: 00400 - 004FF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=3: 00500 - 005FF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,10,11,12, 0, 0, 0 }, - /* idx=4: 00600 - 006FF */ - { 0,13, 0, 0,14,15, 0,16, 0, 0, 0, 0, 0,17,18, 0 }, - /* idx=5: 00700 - 007FF */ - { 0,19, 0,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0,22,23 }, - /* idx=6: 00800 - 008FF */ - { 0,24,25, 0, 0,26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=7: 00900 - 009FF */ - { 0, 0, 0,27,28,29, 0, 0, 0, 0, 0,30,31, 0, 0, 0 }, - /* idx=8: 00A00 - 00AFF */ - { 0, 0, 0,32,33, 0, 0, 0, 0, 0, 0,34,35, 0, 0, 0 }, - /* idx=9: 00B00 - 00BFF */ - { 0, 0, 0,36,37, 0, 0, 0, 0, 0, 0, 0,38, 0, 0, 0 }, - /* idx=10: 00C00 - 00CFF */ - { 0, 0, 0, 0,39,40, 0, 0, 0, 0, 0,41,42, 0, 0, 0 }, - /* idx=11: 00D00 - 00DFF */ - { 0, 0, 0, 0,43, 0, 0, 0, 0, 0, 0, 0,44, 0, 0, 0 }, - /* idx=12: 00E00 - 00EFF */ - { 0, 0, 0,45,46, 0, 0, 0, 0, 0, 0,47,48, 0, 0, 0 }, - /* idx=13: 00F00 - 00FFF */ - { 0,49, 0,50, 0, 0, 0,51,52, 0, 0, 0,53, 0, 0, 0 }, - /* idx=14: 01000 - 010FF */ - { 0, 0, 0,54, 0, 0, 0, 0,55, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=15: 01300 - 013FF */ - { 0, 0, 0, 0, 0,56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=16: 01700 - 017FF */ - { 0,57, 0,58, 0, 0, 0, 0, 0, 0, 0, 0, 0,59, 0, 0 }, - /* idx=17: 01800 - 018FF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,60, 0, 0, 0, 0, 0 }, - /* idx=18: 01900 - 019FF */ - { 0, 0, 0,61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=19: 01A00 - 01AFF */ - { 0,62, 0, 0, 0, 0,63,64, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=20: 01B00 - 01BFF */ - { 0, 0, 0,65,66, 0,67,68, 0, 0,69, 0, 0, 0,70,71 }, - /* idx=21: 01C00 - 01CFF */ - { 0, 0, 0,72, 0, 0, 0, 0, 0, 0, 0, 0, 0,73,74, 0 }, - /* idx=22: 01D00 - 01DFF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,75,76,77,78 }, - /* idx=23: 02000 - 020FF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,79,80,81 }, - /* idx=24: 02C00 - 02CFF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,82,83 }, - /* idx=25: 02D00 - 02DFF */ - { 0, 0, 0, 0, 0, 0, 0,84, 0, 0, 0, 0, 0, 0,85,86 }, - /* idx=26: 03000 - 030FF */ - { 0, 0,87, 0, 0, 0, 0, 0, 0,88, 0, 0, 0, 0, 0, 0 }, - /* idx=27: 0A600 - 0A6FF */ - { 0, 0, 0, 0, 0, 0,89,90, 0, 0, 0, 0, 0, 0, 0,91 }, - /* idx=28: 0A800 - 0A8FF */ - {92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,93, 0,94,95 }, - /* idx=29: 0A900 - 0A9FF */ - { 0, 0,96, 0, 0,97, 0, 0, 0, 0, 0,98,99, 0, 0, 0 }, - /* idx=30: 0AA00 - 0AAFF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,101, 0, 0, 0 }, - /* idx=31: 0AB00 - 0ABFF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0 }, - /* idx=32: 0FB00 - 0FBFF */ - { 0,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=33: 0FE00 - 0FEFF */ - { 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=34: 10100 - 101FF */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105 }, - /* idx=35: 10A00 - 10AFF */ - {106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* idx=36: 11000 - 110FF */ - { 0, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0 }, - /* idx=37: 1D100 - 1D1FF */ - { 0, 0, 0, 0, 0, 0,110,111,112, 0,113, 0, 0, 0, 0, 0 }, - /* idx=38: 1D200 - 1D2FF */ - { 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, -}; - -/* The index table to ccc_val_index[*][16] */ -static const unsigned char ccc_index[] = { - 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 0, 0,15, 0, 0, 0,16, - 17,18,19,20,21,22, 0, 0,23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,24,25, 0, 0, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,27, 0, - 28,29,30,31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0, 0,33, 0, 0,34, 0, 0, 0, 0, 0, 0, - 0, 0,35, 0, 0, 0, 0, 0,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,}; - -struct unicode_decomposition_table { - uint32_t nfc; - uint32_t cp1; - uint32_t cp2; -}; - -static const struct unicode_decomposition_table u_decomposition_table[] = { - { 0x000C0 , 0x00041 , 0x00300 }, - { 0x000C1 , 0x00041 , 0x00301 }, - { 0x000C2 , 0x00041 , 0x00302 }, - { 0x000C3 , 0x00041 , 0x00303 }, - { 0x000C4 , 0x00041 , 0x00308 }, - { 0x000C5 , 0x00041 , 0x0030A }, - { 0x000C7 , 0x00043 , 0x00327 }, - { 0x000C8 , 0x00045 , 0x00300 }, - { 0x000C9 , 0x00045 , 0x00301 }, - { 0x000CA , 0x00045 , 0x00302 }, - { 0x000CB , 0x00045 , 0x00308 }, - { 0x000CC , 0x00049 , 0x00300 }, - { 0x000CD , 0x00049 , 0x00301 }, - { 0x000CE , 0x00049 , 0x00302 }, - { 0x000CF , 0x00049 , 0x00308 }, - { 0x000D1 , 0x0004E , 0x00303 }, - { 0x000D2 , 0x0004F , 0x00300 }, - { 0x000D3 , 0x0004F , 0x00301 }, - { 0x000D4 , 0x0004F , 0x00302 }, - { 0x000D5 , 0x0004F , 0x00303 }, - { 0x000D6 , 0x0004F , 0x00308 }, - { 0x000D9 , 0x00055 , 0x00300 }, - { 0x000DA , 0x00055 , 0x00301 }, - { 0x000DB , 0x00055 , 0x00302 }, - { 0x000DC , 0x00055 , 0x00308 }, - { 0x000DD , 0x00059 , 0x00301 }, - { 0x000E0 , 0x00061 , 0x00300 }, - { 0x000E1 , 0x00061 , 0x00301 }, - { 0x000E2 , 0x00061 , 0x00302 }, - { 0x000E3 , 0x00061 , 0x00303 }, - { 0x000E4 , 0x00061 , 0x00308 }, - { 0x000E5 , 0x00061 , 0x0030A }, - { 0x000E7 , 0x00063 , 0x00327 }, - { 0x000E8 , 0x00065 , 0x00300 }, - { 0x000E9 , 0x00065 , 0x00301 }, - { 0x000EA , 0x00065 , 0x00302 }, - { 0x000EB , 0x00065 , 0x00308 }, - { 0x000EC , 0x00069 , 0x00300 }, - { 0x000ED , 0x00069 , 0x00301 }, - { 0x000EE , 0x00069 , 0x00302 }, - { 0x000EF , 0x00069 , 0x00308 }, - { 0x000F1 , 0x0006E , 0x00303 }, - { 0x000F2 , 0x0006F , 0x00300 }, - { 0x000F3 , 0x0006F , 0x00301 }, - { 0x000F4 , 0x0006F , 0x00302 }, - { 0x000F5 , 0x0006F , 0x00303 }, - { 0x000F6 , 0x0006F , 0x00308 }, - { 0x000F9 , 0x00075 , 0x00300 }, - { 0x000FA , 0x00075 , 0x00301 }, - { 0x000FB , 0x00075 , 0x00302 }, - { 0x000FC , 0x00075 , 0x00308 }, - { 0x000FD , 0x00079 , 0x00301 }, - { 0x000FF , 0x00079 , 0x00308 }, - { 0x00100 , 0x00041 , 0x00304 }, - { 0x00101 , 0x00061 , 0x00304 }, - { 0x00102 , 0x00041 , 0x00306 }, - { 0x00103 , 0x00061 , 0x00306 }, - { 0x00104 , 0x00041 , 0x00328 }, - { 0x00105 , 0x00061 , 0x00328 }, - { 0x00106 , 0x00043 , 0x00301 }, - { 0x00107 , 0x00063 , 0x00301 }, - { 0x00108 , 0x00043 , 0x00302 }, - { 0x00109 , 0x00063 , 0x00302 }, - { 0x0010A , 0x00043 , 0x00307 }, - { 0x0010B , 0x00063 , 0x00307 }, - { 0x0010C , 0x00043 , 0x0030C }, - { 0x0010D , 0x00063 , 0x0030C }, - { 0x0010E , 0x00044 , 0x0030C }, - { 0x0010F , 0x00064 , 0x0030C }, - { 0x00112 , 0x00045 , 0x00304 }, - { 0x00113 , 0x00065 , 0x00304 }, - { 0x00114 , 0x00045 , 0x00306 }, - { 0x00115 , 0x00065 , 0x00306 }, - { 0x00116 , 0x00045 , 0x00307 }, - { 0x00117 , 0x00065 , 0x00307 }, - { 0x00118 , 0x00045 , 0x00328 }, - { 0x00119 , 0x00065 , 0x00328 }, - { 0x0011A , 0x00045 , 0x0030C }, - { 0x0011B , 0x00065 , 0x0030C }, - { 0x0011C , 0x00047 , 0x00302 }, - { 0x0011D , 0x00067 , 0x00302 }, - { 0x0011E , 0x00047 , 0x00306 }, - { 0x0011F , 0x00067 , 0x00306 }, - { 0x00120 , 0x00047 , 0x00307 }, - { 0x00121 , 0x00067 , 0x00307 }, - { 0x00122 , 0x00047 , 0x00327 }, - { 0x00123 , 0x00067 , 0x00327 }, - { 0x00124 , 0x00048 , 0x00302 }, - { 0x00125 , 0x00068 , 0x00302 }, - { 0x00128 , 0x00049 , 0x00303 }, - { 0x00129 , 0x00069 , 0x00303 }, - { 0x0012A , 0x00049 , 0x00304 }, - { 0x0012B , 0x00069 , 0x00304 }, - { 0x0012C , 0x00049 , 0x00306 }, - { 0x0012D , 0x00069 , 0x00306 }, - { 0x0012E , 0x00049 , 0x00328 }, - { 0x0012F , 0x00069 , 0x00328 }, - { 0x00130 , 0x00049 , 0x00307 }, - { 0x00134 , 0x0004A , 0x00302 }, - { 0x00135 , 0x0006A , 0x00302 }, - { 0x00136 , 0x0004B , 0x00327 }, - { 0x00137 , 0x0006B , 0x00327 }, - { 0x00139 , 0x0004C , 0x00301 }, - { 0x0013A , 0x0006C , 0x00301 }, - { 0x0013B , 0x0004C , 0x00327 }, - { 0x0013C , 0x0006C , 0x00327 }, - { 0x0013D , 0x0004C , 0x0030C }, - { 0x0013E , 0x0006C , 0x0030C }, - { 0x00143 , 0x0004E , 0x00301 }, - { 0x00144 , 0x0006E , 0x00301 }, - { 0x00145 , 0x0004E , 0x00327 }, - { 0x00146 , 0x0006E , 0x00327 }, - { 0x00147 , 0x0004E , 0x0030C }, - { 0x00148 , 0x0006E , 0x0030C }, - { 0x0014C , 0x0004F , 0x00304 }, - { 0x0014D , 0x0006F , 0x00304 }, - { 0x0014E , 0x0004F , 0x00306 }, - { 0x0014F , 0x0006F , 0x00306 }, - { 0x00150 , 0x0004F , 0x0030B }, - { 0x00151 , 0x0006F , 0x0030B }, - { 0x00154 , 0x00052 , 0x00301 }, - { 0x00155 , 0x00072 , 0x00301 }, - { 0x00156 , 0x00052 , 0x00327 }, - { 0x00157 , 0x00072 , 0x00327 }, - { 0x00158 , 0x00052 , 0x0030C }, - { 0x00159 , 0x00072 , 0x0030C }, - { 0x0015A , 0x00053 , 0x00301 }, - { 0x0015B , 0x00073 , 0x00301 }, - { 0x0015C , 0x00053 , 0x00302 }, - { 0x0015D , 0x00073 , 0x00302 }, - { 0x0015E , 0x00053 , 0x00327 }, - { 0x0015F , 0x00073 , 0x00327 }, - { 0x00160 , 0x00053 , 0x0030C }, - { 0x00161 , 0x00073 , 0x0030C }, - { 0x00162 , 0x00054 , 0x00327 }, - { 0x00163 , 0x00074 , 0x00327 }, - { 0x00164 , 0x00054 , 0x0030C }, - { 0x00165 , 0x00074 , 0x0030C }, - { 0x00168 , 0x00055 , 0x00303 }, - { 0x00169 , 0x00075 , 0x00303 }, - { 0x0016A , 0x00055 , 0x00304 }, - { 0x0016B , 0x00075 , 0x00304 }, - { 0x0016C , 0x00055 , 0x00306 }, - { 0x0016D , 0x00075 , 0x00306 }, - { 0x0016E , 0x00055 , 0x0030A }, - { 0x0016F , 0x00075 , 0x0030A }, - { 0x00170 , 0x00055 , 0x0030B }, - { 0x00171 , 0x00075 , 0x0030B }, - { 0x00172 , 0x00055 , 0x00328 }, - { 0x00173 , 0x00075 , 0x00328 }, - { 0x00174 , 0x00057 , 0x00302 }, - { 0x00175 , 0x00077 , 0x00302 }, - { 0x00176 , 0x00059 , 0x00302 }, - { 0x00177 , 0x00079 , 0x00302 }, - { 0x00178 , 0x00059 , 0x00308 }, - { 0x00179 , 0x0005A , 0x00301 }, - { 0x0017A , 0x0007A , 0x00301 }, - { 0x0017B , 0x0005A , 0x00307 }, - { 0x0017C , 0x0007A , 0x00307 }, - { 0x0017D , 0x0005A , 0x0030C }, - { 0x0017E , 0x0007A , 0x0030C }, - { 0x001A0 , 0x0004F , 0x0031B }, - { 0x001A1 , 0x0006F , 0x0031B }, - { 0x001AF , 0x00055 , 0x0031B }, - { 0x001B0 , 0x00075 , 0x0031B }, - { 0x001CD , 0x00041 , 0x0030C }, - { 0x001CE , 0x00061 , 0x0030C }, - { 0x001CF , 0x00049 , 0x0030C }, - { 0x001D0 , 0x00069 , 0x0030C }, - { 0x001D1 , 0x0004F , 0x0030C }, - { 0x001D2 , 0x0006F , 0x0030C }, - { 0x001D3 , 0x00055 , 0x0030C }, - { 0x001D4 , 0x00075 , 0x0030C }, - { 0x001D5 , 0x000DC , 0x00304 }, - { 0x001D6 , 0x000FC , 0x00304 }, - { 0x001D7 , 0x000DC , 0x00301 }, - { 0x001D8 , 0x000FC , 0x00301 }, - { 0x001D9 , 0x000DC , 0x0030C }, - { 0x001DA , 0x000FC , 0x0030C }, - { 0x001DB , 0x000DC , 0x00300 }, - { 0x001DC , 0x000FC , 0x00300 }, - { 0x001DE , 0x000C4 , 0x00304 }, - { 0x001DF , 0x000E4 , 0x00304 }, - { 0x001E0 , 0x00226 , 0x00304 }, - { 0x001E1 , 0x00227 , 0x00304 }, - { 0x001E2 , 0x000C6 , 0x00304 }, - { 0x001E3 , 0x000E6 , 0x00304 }, - { 0x001E6 , 0x00047 , 0x0030C }, - { 0x001E7 , 0x00067 , 0x0030C }, - { 0x001E8 , 0x0004B , 0x0030C }, - { 0x001E9 , 0x0006B , 0x0030C }, - { 0x001EA , 0x0004F , 0x00328 }, - { 0x001EB , 0x0006F , 0x00328 }, - { 0x001EC , 0x001EA , 0x00304 }, - { 0x001ED , 0x001EB , 0x00304 }, - { 0x001EE , 0x001B7 , 0x0030C }, - { 0x001EF , 0x00292 , 0x0030C }, - { 0x001F0 , 0x0006A , 0x0030C }, - { 0x001F4 , 0x00047 , 0x00301 }, - { 0x001F5 , 0x00067 , 0x00301 }, - { 0x001F8 , 0x0004E , 0x00300 }, - { 0x001F9 , 0x0006E , 0x00300 }, - { 0x001FA , 0x000C5 , 0x00301 }, - { 0x001FB , 0x000E5 , 0x00301 }, - { 0x001FC , 0x000C6 , 0x00301 }, - { 0x001FD , 0x000E6 , 0x00301 }, - { 0x001FE , 0x000D8 , 0x00301 }, - { 0x001FF , 0x000F8 , 0x00301 }, - { 0x00200 , 0x00041 , 0x0030F }, - { 0x00201 , 0x00061 , 0x0030F }, - { 0x00202 , 0x00041 , 0x00311 }, - { 0x00203 , 0x00061 , 0x00311 }, - { 0x00204 , 0x00045 , 0x0030F }, - { 0x00205 , 0x00065 , 0x0030F }, - { 0x00206 , 0x00045 , 0x00311 }, - { 0x00207 , 0x00065 , 0x00311 }, - { 0x00208 , 0x00049 , 0x0030F }, - { 0x00209 , 0x00069 , 0x0030F }, - { 0x0020A , 0x00049 , 0x00311 }, - { 0x0020B , 0x00069 , 0x00311 }, - { 0x0020C , 0x0004F , 0x0030F }, - { 0x0020D , 0x0006F , 0x0030F }, - { 0x0020E , 0x0004F , 0x00311 }, - { 0x0020F , 0x0006F , 0x00311 }, - { 0x00210 , 0x00052 , 0x0030F }, - { 0x00211 , 0x00072 , 0x0030F }, - { 0x00212 , 0x00052 , 0x00311 }, - { 0x00213 , 0x00072 , 0x00311 }, - { 0x00214 , 0x00055 , 0x0030F }, - { 0x00215 , 0x00075 , 0x0030F }, - { 0x00216 , 0x00055 , 0x00311 }, - { 0x00217 , 0x00075 , 0x00311 }, - { 0x00218 , 0x00053 , 0x00326 }, - { 0x00219 , 0x00073 , 0x00326 }, - { 0x0021A , 0x00054 , 0x00326 }, - { 0x0021B , 0x00074 , 0x00326 }, - { 0x0021E , 0x00048 , 0x0030C }, - { 0x0021F , 0x00068 , 0x0030C }, - { 0x00226 , 0x00041 , 0x00307 }, - { 0x00227 , 0x00061 , 0x00307 }, - { 0x00228 , 0x00045 , 0x00327 }, - { 0x00229 , 0x00065 , 0x00327 }, - { 0x0022A , 0x000D6 , 0x00304 }, - { 0x0022B , 0x000F6 , 0x00304 }, - { 0x0022C , 0x000D5 , 0x00304 }, - { 0x0022D , 0x000F5 , 0x00304 }, - { 0x0022E , 0x0004F , 0x00307 }, - { 0x0022F , 0x0006F , 0x00307 }, - { 0x00230 , 0x0022E , 0x00304 }, - { 0x00231 , 0x0022F , 0x00304 }, - { 0x00232 , 0x00059 , 0x00304 }, - { 0x00233 , 0x00079 , 0x00304 }, - { 0x00385 , 0x000A8 , 0x00301 }, - { 0x00386 , 0x00391 , 0x00301 }, - { 0x00388 , 0x00395 , 0x00301 }, - { 0x00389 , 0x00397 , 0x00301 }, - { 0x0038A , 0x00399 , 0x00301 }, - { 0x0038C , 0x0039F , 0x00301 }, - { 0x0038E , 0x003A5 , 0x00301 }, - { 0x0038F , 0x003A9 , 0x00301 }, - { 0x00390 , 0x003CA , 0x00301 }, - { 0x003AA , 0x00399 , 0x00308 }, - { 0x003AB , 0x003A5 , 0x00308 }, - { 0x003AC , 0x003B1 , 0x00301 }, - { 0x003AD , 0x003B5 , 0x00301 }, - { 0x003AE , 0x003B7 , 0x00301 }, - { 0x003AF , 0x003B9 , 0x00301 }, - { 0x003B0 , 0x003CB , 0x00301 }, - { 0x003CA , 0x003B9 , 0x00308 }, - { 0x003CB , 0x003C5 , 0x00308 }, - { 0x003CC , 0x003BF , 0x00301 }, - { 0x003CD , 0x003C5 , 0x00301 }, - { 0x003CE , 0x003C9 , 0x00301 }, - { 0x003D3 , 0x003D2 , 0x00301 }, - { 0x003D4 , 0x003D2 , 0x00308 }, - { 0x00400 , 0x00415 , 0x00300 }, - { 0x00401 , 0x00415 , 0x00308 }, - { 0x00403 , 0x00413 , 0x00301 }, - { 0x00407 , 0x00406 , 0x00308 }, - { 0x0040C , 0x0041A , 0x00301 }, - { 0x0040D , 0x00418 , 0x00300 }, - { 0x0040E , 0x00423 , 0x00306 }, - { 0x00419 , 0x00418 , 0x00306 }, - { 0x00439 , 0x00438 , 0x00306 }, - { 0x00450 , 0x00435 , 0x00300 }, - { 0x00451 , 0x00435 , 0x00308 }, - { 0x00453 , 0x00433 , 0x00301 }, - { 0x00457 , 0x00456 , 0x00308 }, - { 0x0045C , 0x0043A , 0x00301 }, - { 0x0045D , 0x00438 , 0x00300 }, - { 0x0045E , 0x00443 , 0x00306 }, - { 0x00476 , 0x00474 , 0x0030F }, - { 0x00477 , 0x00475 , 0x0030F }, - { 0x004C1 , 0x00416 , 0x00306 }, - { 0x004C2 , 0x00436 , 0x00306 }, - { 0x004D0 , 0x00410 , 0x00306 }, - { 0x004D1 , 0x00430 , 0x00306 }, - { 0x004D2 , 0x00410 , 0x00308 }, - { 0x004D3 , 0x00430 , 0x00308 }, - { 0x004D6 , 0x00415 , 0x00306 }, - { 0x004D7 , 0x00435 , 0x00306 }, - { 0x004DA , 0x004D8 , 0x00308 }, - { 0x004DB , 0x004D9 , 0x00308 }, - { 0x004DC , 0x00416 , 0x00308 }, - { 0x004DD , 0x00436 , 0x00308 }, - { 0x004DE , 0x00417 , 0x00308 }, - { 0x004DF , 0x00437 , 0x00308 }, - { 0x004E2 , 0x00418 , 0x00304 }, - { 0x004E3 , 0x00438 , 0x00304 }, - { 0x004E4 , 0x00418 , 0x00308 }, - { 0x004E5 , 0x00438 , 0x00308 }, - { 0x004E6 , 0x0041E , 0x00308 }, - { 0x004E7 , 0x0043E , 0x00308 }, - { 0x004EA , 0x004E8 , 0x00308 }, - { 0x004EB , 0x004E9 , 0x00308 }, - { 0x004EC , 0x0042D , 0x00308 }, - { 0x004ED , 0x0044D , 0x00308 }, - { 0x004EE , 0x00423 , 0x00304 }, - { 0x004EF , 0x00443 , 0x00304 }, - { 0x004F0 , 0x00423 , 0x00308 }, - { 0x004F1 , 0x00443 , 0x00308 }, - { 0x004F2 , 0x00423 , 0x0030B }, - { 0x004F3 , 0x00443 , 0x0030B }, - { 0x004F4 , 0x00427 , 0x00308 }, - { 0x004F5 , 0x00447 , 0x00308 }, - { 0x004F8 , 0x0042B , 0x00308 }, - { 0x004F9 , 0x0044B , 0x00308 }, - { 0x00622 , 0x00627 , 0x00653 }, - { 0x00623 , 0x00627 , 0x00654 }, - { 0x00624 , 0x00648 , 0x00654 }, - { 0x00625 , 0x00627 , 0x00655 }, - { 0x00626 , 0x0064A , 0x00654 }, - { 0x006C0 , 0x006D5 , 0x00654 }, - { 0x006C2 , 0x006C1 , 0x00654 }, - { 0x006D3 , 0x006D2 , 0x00654 }, - { 0x00929 , 0x00928 , 0x0093C }, - { 0x00931 , 0x00930 , 0x0093C }, - { 0x00934 , 0x00933 , 0x0093C }, - { 0x009CB , 0x009C7 , 0x009BE }, - { 0x009CC , 0x009C7 , 0x009D7 }, - { 0x00B48 , 0x00B47 , 0x00B56 }, - { 0x00B4B , 0x00B47 , 0x00B3E }, - { 0x00B4C , 0x00B47 , 0x00B57 }, - { 0x00B94 , 0x00B92 , 0x00BD7 }, - { 0x00BCA , 0x00BC6 , 0x00BBE }, - { 0x00BCB , 0x00BC7 , 0x00BBE }, - { 0x00BCC , 0x00BC6 , 0x00BD7 }, - { 0x00C48 , 0x00C46 , 0x00C56 }, - { 0x00CC0 , 0x00CBF , 0x00CD5 }, - { 0x00CC7 , 0x00CC6 , 0x00CD5 }, - { 0x00CC8 , 0x00CC6 , 0x00CD6 }, - { 0x00CCA , 0x00CC6 , 0x00CC2 }, - { 0x00CCB , 0x00CCA , 0x00CD5 }, - { 0x00D4A , 0x00D46 , 0x00D3E }, - { 0x00D4B , 0x00D47 , 0x00D3E }, - { 0x00D4C , 0x00D46 , 0x00D57 }, - { 0x00DDA , 0x00DD9 , 0x00DCA }, - { 0x00DDC , 0x00DD9 , 0x00DCF }, - { 0x00DDD , 0x00DDC , 0x00DCA }, - { 0x00DDE , 0x00DD9 , 0x00DDF }, - { 0x01026 , 0x01025 , 0x0102E }, - { 0x01B06 , 0x01B05 , 0x01B35 }, - { 0x01B08 , 0x01B07 , 0x01B35 }, - { 0x01B0A , 0x01B09 , 0x01B35 }, - { 0x01B0C , 0x01B0B , 0x01B35 }, - { 0x01B0E , 0x01B0D , 0x01B35 }, - { 0x01B12 , 0x01B11 , 0x01B35 }, - { 0x01B3B , 0x01B3A , 0x01B35 }, - { 0x01B3D , 0x01B3C , 0x01B35 }, - { 0x01B40 , 0x01B3E , 0x01B35 }, - { 0x01B41 , 0x01B3F , 0x01B35 }, - { 0x01B43 , 0x01B42 , 0x01B35 }, - { 0x01E00 , 0x00041 , 0x00325 }, - { 0x01E01 , 0x00061 , 0x00325 }, - { 0x01E02 , 0x00042 , 0x00307 }, - { 0x01E03 , 0x00062 , 0x00307 }, - { 0x01E04 , 0x00042 , 0x00323 }, - { 0x01E05 , 0x00062 , 0x00323 }, - { 0x01E06 , 0x00042 , 0x00331 }, - { 0x01E07 , 0x00062 , 0x00331 }, - { 0x01E08 , 0x000C7 , 0x00301 }, - { 0x01E09 , 0x000E7 , 0x00301 }, - { 0x01E0A , 0x00044 , 0x00307 }, - { 0x01E0B , 0x00064 , 0x00307 }, - { 0x01E0C , 0x00044 , 0x00323 }, - { 0x01E0D , 0x00064 , 0x00323 }, - { 0x01E0E , 0x00044 , 0x00331 }, - { 0x01E0F , 0x00064 , 0x00331 }, - { 0x01E10 , 0x00044 , 0x00327 }, - { 0x01E11 , 0x00064 , 0x00327 }, - { 0x01E12 , 0x00044 , 0x0032D }, - { 0x01E13 , 0x00064 , 0x0032D }, - { 0x01E14 , 0x00112 , 0x00300 }, - { 0x01E15 , 0x00113 , 0x00300 }, - { 0x01E16 , 0x00112 , 0x00301 }, - { 0x01E17 , 0x00113 , 0x00301 }, - { 0x01E18 , 0x00045 , 0x0032D }, - { 0x01E19 , 0x00065 , 0x0032D }, - { 0x01E1A , 0x00045 , 0x00330 }, - { 0x01E1B , 0x00065 , 0x00330 }, - { 0x01E1C , 0x00228 , 0x00306 }, - { 0x01E1D , 0x00229 , 0x00306 }, - { 0x01E1E , 0x00046 , 0x00307 }, - { 0x01E1F , 0x00066 , 0x00307 }, - { 0x01E20 , 0x00047 , 0x00304 }, - { 0x01E21 , 0x00067 , 0x00304 }, - { 0x01E22 , 0x00048 , 0x00307 }, - { 0x01E23 , 0x00068 , 0x00307 }, - { 0x01E24 , 0x00048 , 0x00323 }, - { 0x01E25 , 0x00068 , 0x00323 }, - { 0x01E26 , 0x00048 , 0x00308 }, - { 0x01E27 , 0x00068 , 0x00308 }, - { 0x01E28 , 0x00048 , 0x00327 }, - { 0x01E29 , 0x00068 , 0x00327 }, - { 0x01E2A , 0x00048 , 0x0032E }, - { 0x01E2B , 0x00068 , 0x0032E }, - { 0x01E2C , 0x00049 , 0x00330 }, - { 0x01E2D , 0x00069 , 0x00330 }, - { 0x01E2E , 0x000CF , 0x00301 }, - { 0x01E2F , 0x000EF , 0x00301 }, - { 0x01E30 , 0x0004B , 0x00301 }, - { 0x01E31 , 0x0006B , 0x00301 }, - { 0x01E32 , 0x0004B , 0x00323 }, - { 0x01E33 , 0x0006B , 0x00323 }, - { 0x01E34 , 0x0004B , 0x00331 }, - { 0x01E35 , 0x0006B , 0x00331 }, - { 0x01E36 , 0x0004C , 0x00323 }, - { 0x01E37 , 0x0006C , 0x00323 }, - { 0x01E38 , 0x01E36 , 0x00304 }, - { 0x01E39 , 0x01E37 , 0x00304 }, - { 0x01E3A , 0x0004C , 0x00331 }, - { 0x01E3B , 0x0006C , 0x00331 }, - { 0x01E3C , 0x0004C , 0x0032D }, - { 0x01E3D , 0x0006C , 0x0032D }, - { 0x01E3E , 0x0004D , 0x00301 }, - { 0x01E3F , 0x0006D , 0x00301 }, - { 0x01E40 , 0x0004D , 0x00307 }, - { 0x01E41 , 0x0006D , 0x00307 }, - { 0x01E42 , 0x0004D , 0x00323 }, - { 0x01E43 , 0x0006D , 0x00323 }, - { 0x01E44 , 0x0004E , 0x00307 }, - { 0x01E45 , 0x0006E , 0x00307 }, - { 0x01E46 , 0x0004E , 0x00323 }, - { 0x01E47 , 0x0006E , 0x00323 }, - { 0x01E48 , 0x0004E , 0x00331 }, - { 0x01E49 , 0x0006E , 0x00331 }, - { 0x01E4A , 0x0004E , 0x0032D }, - { 0x01E4B , 0x0006E , 0x0032D }, - { 0x01E4C , 0x000D5 , 0x00301 }, - { 0x01E4D , 0x000F5 , 0x00301 }, - { 0x01E4E , 0x000D5 , 0x00308 }, - { 0x01E4F , 0x000F5 , 0x00308 }, - { 0x01E50 , 0x0014C , 0x00300 }, - { 0x01E51 , 0x0014D , 0x00300 }, - { 0x01E52 , 0x0014C , 0x00301 }, - { 0x01E53 , 0x0014D , 0x00301 }, - { 0x01E54 , 0x00050 , 0x00301 }, - { 0x01E55 , 0x00070 , 0x00301 }, - { 0x01E56 , 0x00050 , 0x00307 }, - { 0x01E57 , 0x00070 , 0x00307 }, - { 0x01E58 , 0x00052 , 0x00307 }, - { 0x01E59 , 0x00072 , 0x00307 }, - { 0x01E5A , 0x00052 , 0x00323 }, - { 0x01E5B , 0x00072 , 0x00323 }, - { 0x01E5C , 0x01E5A , 0x00304 }, - { 0x01E5D , 0x01E5B , 0x00304 }, - { 0x01E5E , 0x00052 , 0x00331 }, - { 0x01E5F , 0x00072 , 0x00331 }, - { 0x01E60 , 0x00053 , 0x00307 }, - { 0x01E61 , 0x00073 , 0x00307 }, - { 0x01E62 , 0x00053 , 0x00323 }, - { 0x01E63 , 0x00073 , 0x00323 }, - { 0x01E64 , 0x0015A , 0x00307 }, - { 0x01E65 , 0x0015B , 0x00307 }, - { 0x01E66 , 0x00160 , 0x00307 }, - { 0x01E67 , 0x00161 , 0x00307 }, - { 0x01E68 , 0x01E62 , 0x00307 }, - { 0x01E69 , 0x01E63 , 0x00307 }, - { 0x01E6A , 0x00054 , 0x00307 }, - { 0x01E6B , 0x00074 , 0x00307 }, - { 0x01E6C , 0x00054 , 0x00323 }, - { 0x01E6D , 0x00074 , 0x00323 }, - { 0x01E6E , 0x00054 , 0x00331 }, - { 0x01E6F , 0x00074 , 0x00331 }, - { 0x01E70 , 0x00054 , 0x0032D }, - { 0x01E71 , 0x00074 , 0x0032D }, - { 0x01E72 , 0x00055 , 0x00324 }, - { 0x01E73 , 0x00075 , 0x00324 }, - { 0x01E74 , 0x00055 , 0x00330 }, - { 0x01E75 , 0x00075 , 0x00330 }, - { 0x01E76 , 0x00055 , 0x0032D }, - { 0x01E77 , 0x00075 , 0x0032D }, - { 0x01E78 , 0x00168 , 0x00301 }, - { 0x01E79 , 0x00169 , 0x00301 }, - { 0x01E7A , 0x0016A , 0x00308 }, - { 0x01E7B , 0x0016B , 0x00308 }, - { 0x01E7C , 0x00056 , 0x00303 }, - { 0x01E7D , 0x00076 , 0x00303 }, - { 0x01E7E , 0x00056 , 0x00323 }, - { 0x01E7F , 0x00076 , 0x00323 }, - { 0x01E80 , 0x00057 , 0x00300 }, - { 0x01E81 , 0x00077 , 0x00300 }, - { 0x01E82 , 0x00057 , 0x00301 }, - { 0x01E83 , 0x00077 , 0x00301 }, - { 0x01E84 , 0x00057 , 0x00308 }, - { 0x01E85 , 0x00077 , 0x00308 }, - { 0x01E86 , 0x00057 , 0x00307 }, - { 0x01E87 , 0x00077 , 0x00307 }, - { 0x01E88 , 0x00057 , 0x00323 }, - { 0x01E89 , 0x00077 , 0x00323 }, - { 0x01E8A , 0x00058 , 0x00307 }, - { 0x01E8B , 0x00078 , 0x00307 }, - { 0x01E8C , 0x00058 , 0x00308 }, - { 0x01E8D , 0x00078 , 0x00308 }, - { 0x01E8E , 0x00059 , 0x00307 }, - { 0x01E8F , 0x00079 , 0x00307 }, - { 0x01E90 , 0x0005A , 0x00302 }, - { 0x01E91 , 0x0007A , 0x00302 }, - { 0x01E92 , 0x0005A , 0x00323 }, - { 0x01E93 , 0x0007A , 0x00323 }, - { 0x01E94 , 0x0005A , 0x00331 }, - { 0x01E95 , 0x0007A , 0x00331 }, - { 0x01E96 , 0x00068 , 0x00331 }, - { 0x01E97 , 0x00074 , 0x00308 }, - { 0x01E98 , 0x00077 , 0x0030A }, - { 0x01E99 , 0x00079 , 0x0030A }, - { 0x01E9B , 0x0017F , 0x00307 }, - { 0x01EA0 , 0x00041 , 0x00323 }, - { 0x01EA1 , 0x00061 , 0x00323 }, - { 0x01EA2 , 0x00041 , 0x00309 }, - { 0x01EA3 , 0x00061 , 0x00309 }, - { 0x01EA4 , 0x000C2 , 0x00301 }, - { 0x01EA5 , 0x000E2 , 0x00301 }, - { 0x01EA6 , 0x000C2 , 0x00300 }, - { 0x01EA7 , 0x000E2 , 0x00300 }, - { 0x01EA8 , 0x000C2 , 0x00309 }, - { 0x01EA9 , 0x000E2 , 0x00309 }, - { 0x01EAA , 0x000C2 , 0x00303 }, - { 0x01EAB , 0x000E2 , 0x00303 }, - { 0x01EAC , 0x01EA0 , 0x00302 }, - { 0x01EAD , 0x01EA1 , 0x00302 }, - { 0x01EAE , 0x00102 , 0x00301 }, - { 0x01EAF , 0x00103 , 0x00301 }, - { 0x01EB0 , 0x00102 , 0x00300 }, - { 0x01EB1 , 0x00103 , 0x00300 }, - { 0x01EB2 , 0x00102 , 0x00309 }, - { 0x01EB3 , 0x00103 , 0x00309 }, - { 0x01EB4 , 0x00102 , 0x00303 }, - { 0x01EB5 , 0x00103 , 0x00303 }, - { 0x01EB6 , 0x01EA0 , 0x00306 }, - { 0x01EB7 , 0x01EA1 , 0x00306 }, - { 0x01EB8 , 0x00045 , 0x00323 }, - { 0x01EB9 , 0x00065 , 0x00323 }, - { 0x01EBA , 0x00045 , 0x00309 }, - { 0x01EBB , 0x00065 , 0x00309 }, - { 0x01EBC , 0x00045 , 0x00303 }, - { 0x01EBD , 0x00065 , 0x00303 }, - { 0x01EBE , 0x000CA , 0x00301 }, - { 0x01EBF , 0x000EA , 0x00301 }, - { 0x01EC0 , 0x000CA , 0x00300 }, - { 0x01EC1 , 0x000EA , 0x00300 }, - { 0x01EC2 , 0x000CA , 0x00309 }, - { 0x01EC3 , 0x000EA , 0x00309 }, - { 0x01EC4 , 0x000CA , 0x00303 }, - { 0x01EC5 , 0x000EA , 0x00303 }, - { 0x01EC6 , 0x01EB8 , 0x00302 }, - { 0x01EC7 , 0x01EB9 , 0x00302 }, - { 0x01EC8 , 0x00049 , 0x00309 }, - { 0x01EC9 , 0x00069 , 0x00309 }, - { 0x01ECA , 0x00049 , 0x00323 }, - { 0x01ECB , 0x00069 , 0x00323 }, - { 0x01ECC , 0x0004F , 0x00323 }, - { 0x01ECD , 0x0006F , 0x00323 }, - { 0x01ECE , 0x0004F , 0x00309 }, - { 0x01ECF , 0x0006F , 0x00309 }, - { 0x01ED0 , 0x000D4 , 0x00301 }, - { 0x01ED1 , 0x000F4 , 0x00301 }, - { 0x01ED2 , 0x000D4 , 0x00300 }, - { 0x01ED3 , 0x000F4 , 0x00300 }, - { 0x01ED4 , 0x000D4 , 0x00309 }, - { 0x01ED5 , 0x000F4 , 0x00309 }, - { 0x01ED6 , 0x000D4 , 0x00303 }, - { 0x01ED7 , 0x000F4 , 0x00303 }, - { 0x01ED8 , 0x01ECC , 0x00302 }, - { 0x01ED9 , 0x01ECD , 0x00302 }, - { 0x01EDA , 0x001A0 , 0x00301 }, - { 0x01EDB , 0x001A1 , 0x00301 }, - { 0x01EDC , 0x001A0 , 0x00300 }, - { 0x01EDD , 0x001A1 , 0x00300 }, - { 0x01EDE , 0x001A0 , 0x00309 }, - { 0x01EDF , 0x001A1 , 0x00309 }, - { 0x01EE0 , 0x001A0 , 0x00303 }, - { 0x01EE1 , 0x001A1 , 0x00303 }, - { 0x01EE2 , 0x001A0 , 0x00323 }, - { 0x01EE3 , 0x001A1 , 0x00323 }, - { 0x01EE4 , 0x00055 , 0x00323 }, - { 0x01EE5 , 0x00075 , 0x00323 }, - { 0x01EE6 , 0x00055 , 0x00309 }, - { 0x01EE7 , 0x00075 , 0x00309 }, - { 0x01EE8 , 0x001AF , 0x00301 }, - { 0x01EE9 , 0x001B0 , 0x00301 }, - { 0x01EEA , 0x001AF , 0x00300 }, - { 0x01EEB , 0x001B0 , 0x00300 }, - { 0x01EEC , 0x001AF , 0x00309 }, - { 0x01EED , 0x001B0 , 0x00309 }, - { 0x01EEE , 0x001AF , 0x00303 }, - { 0x01EEF , 0x001B0 , 0x00303 }, - { 0x01EF0 , 0x001AF , 0x00323 }, - { 0x01EF1 , 0x001B0 , 0x00323 }, - { 0x01EF2 , 0x00059 , 0x00300 }, - { 0x01EF3 , 0x00079 , 0x00300 }, - { 0x01EF4 , 0x00059 , 0x00323 }, - { 0x01EF5 , 0x00079 , 0x00323 }, - { 0x01EF6 , 0x00059 , 0x00309 }, - { 0x01EF7 , 0x00079 , 0x00309 }, - { 0x01EF8 , 0x00059 , 0x00303 }, - { 0x01EF9 , 0x00079 , 0x00303 }, - { 0x01F00 , 0x003B1 , 0x00313 }, - { 0x01F01 , 0x003B1 , 0x00314 }, - { 0x01F02 , 0x01F00 , 0x00300 }, - { 0x01F03 , 0x01F01 , 0x00300 }, - { 0x01F04 , 0x01F00 , 0x00301 }, - { 0x01F05 , 0x01F01 , 0x00301 }, - { 0x01F06 , 0x01F00 , 0x00342 }, - { 0x01F07 , 0x01F01 , 0x00342 }, - { 0x01F08 , 0x00391 , 0x00313 }, - { 0x01F09 , 0x00391 , 0x00314 }, - { 0x01F0A , 0x01F08 , 0x00300 }, - { 0x01F0B , 0x01F09 , 0x00300 }, - { 0x01F0C , 0x01F08 , 0x00301 }, - { 0x01F0D , 0x01F09 , 0x00301 }, - { 0x01F0E , 0x01F08 , 0x00342 }, - { 0x01F0F , 0x01F09 , 0x00342 }, - { 0x01F10 , 0x003B5 , 0x00313 }, - { 0x01F11 , 0x003B5 , 0x00314 }, - { 0x01F12 , 0x01F10 , 0x00300 }, - { 0x01F13 , 0x01F11 , 0x00300 }, - { 0x01F14 , 0x01F10 , 0x00301 }, - { 0x01F15 , 0x01F11 , 0x00301 }, - { 0x01F18 , 0x00395 , 0x00313 }, - { 0x01F19 , 0x00395 , 0x00314 }, - { 0x01F1A , 0x01F18 , 0x00300 }, - { 0x01F1B , 0x01F19 , 0x00300 }, - { 0x01F1C , 0x01F18 , 0x00301 }, - { 0x01F1D , 0x01F19 , 0x00301 }, - { 0x01F20 , 0x003B7 , 0x00313 }, - { 0x01F21 , 0x003B7 , 0x00314 }, - { 0x01F22 , 0x01F20 , 0x00300 }, - { 0x01F23 , 0x01F21 , 0x00300 }, - { 0x01F24 , 0x01F20 , 0x00301 }, - { 0x01F25 , 0x01F21 , 0x00301 }, - { 0x01F26 , 0x01F20 , 0x00342 }, - { 0x01F27 , 0x01F21 , 0x00342 }, - { 0x01F28 , 0x00397 , 0x00313 }, - { 0x01F29 , 0x00397 , 0x00314 }, - { 0x01F2A , 0x01F28 , 0x00300 }, - { 0x01F2B , 0x01F29 , 0x00300 }, - { 0x01F2C , 0x01F28 , 0x00301 }, - { 0x01F2D , 0x01F29 , 0x00301 }, - { 0x01F2E , 0x01F28 , 0x00342 }, - { 0x01F2F , 0x01F29 , 0x00342 }, - { 0x01F30 , 0x003B9 , 0x00313 }, - { 0x01F31 , 0x003B9 , 0x00314 }, - { 0x01F32 , 0x01F30 , 0x00300 }, - { 0x01F33 , 0x01F31 , 0x00300 }, - { 0x01F34 , 0x01F30 , 0x00301 }, - { 0x01F35 , 0x01F31 , 0x00301 }, - { 0x01F36 , 0x01F30 , 0x00342 }, - { 0x01F37 , 0x01F31 , 0x00342 }, - { 0x01F38 , 0x00399 , 0x00313 }, - { 0x01F39 , 0x00399 , 0x00314 }, - { 0x01F3A , 0x01F38 , 0x00300 }, - { 0x01F3B , 0x01F39 , 0x00300 }, - { 0x01F3C , 0x01F38 , 0x00301 }, - { 0x01F3D , 0x01F39 , 0x00301 }, - { 0x01F3E , 0x01F38 , 0x00342 }, - { 0x01F3F , 0x01F39 , 0x00342 }, - { 0x01F40 , 0x003BF , 0x00313 }, - { 0x01F41 , 0x003BF , 0x00314 }, - { 0x01F42 , 0x01F40 , 0x00300 }, - { 0x01F43 , 0x01F41 , 0x00300 }, - { 0x01F44 , 0x01F40 , 0x00301 }, - { 0x01F45 , 0x01F41 , 0x00301 }, - { 0x01F48 , 0x0039F , 0x00313 }, - { 0x01F49 , 0x0039F , 0x00314 }, - { 0x01F4A , 0x01F48 , 0x00300 }, - { 0x01F4B , 0x01F49 , 0x00300 }, - { 0x01F4C , 0x01F48 , 0x00301 }, - { 0x01F4D , 0x01F49 , 0x00301 }, - { 0x01F50 , 0x003C5 , 0x00313 }, - { 0x01F51 , 0x003C5 , 0x00314 }, - { 0x01F52 , 0x01F50 , 0x00300 }, - { 0x01F53 , 0x01F51 , 0x00300 }, - { 0x01F54 , 0x01F50 , 0x00301 }, - { 0x01F55 , 0x01F51 , 0x00301 }, - { 0x01F56 , 0x01F50 , 0x00342 }, - { 0x01F57 , 0x01F51 , 0x00342 }, - { 0x01F59 , 0x003A5 , 0x00314 }, - { 0x01F5B , 0x01F59 , 0x00300 }, - { 0x01F5D , 0x01F59 , 0x00301 }, - { 0x01F5F , 0x01F59 , 0x00342 }, - { 0x01F60 , 0x003C9 , 0x00313 }, - { 0x01F61 , 0x003C9 , 0x00314 }, - { 0x01F62 , 0x01F60 , 0x00300 }, - { 0x01F63 , 0x01F61 , 0x00300 }, - { 0x01F64 , 0x01F60 , 0x00301 }, - { 0x01F65 , 0x01F61 , 0x00301 }, - { 0x01F66 , 0x01F60 , 0x00342 }, - { 0x01F67 , 0x01F61 , 0x00342 }, - { 0x01F68 , 0x003A9 , 0x00313 }, - { 0x01F69 , 0x003A9 , 0x00314 }, - { 0x01F6A , 0x01F68 , 0x00300 }, - { 0x01F6B , 0x01F69 , 0x00300 }, - { 0x01F6C , 0x01F68 , 0x00301 }, - { 0x01F6D , 0x01F69 , 0x00301 }, - { 0x01F6E , 0x01F68 , 0x00342 }, - { 0x01F6F , 0x01F69 , 0x00342 }, - { 0x01F70 , 0x003B1 , 0x00300 }, - { 0x01F72 , 0x003B5 , 0x00300 }, - { 0x01F74 , 0x003B7 , 0x00300 }, - { 0x01F76 , 0x003B9 , 0x00300 }, - { 0x01F78 , 0x003BF , 0x00300 }, - { 0x01F7A , 0x003C5 , 0x00300 }, - { 0x01F7C , 0x003C9 , 0x00300 }, - { 0x01F80 , 0x01F00 , 0x00345 }, - { 0x01F81 , 0x01F01 , 0x00345 }, - { 0x01F82 , 0x01F02 , 0x00345 }, - { 0x01F83 , 0x01F03 , 0x00345 }, - { 0x01F84 , 0x01F04 , 0x00345 }, - { 0x01F85 , 0x01F05 , 0x00345 }, - { 0x01F86 , 0x01F06 , 0x00345 }, - { 0x01F87 , 0x01F07 , 0x00345 }, - { 0x01F88 , 0x01F08 , 0x00345 }, - { 0x01F89 , 0x01F09 , 0x00345 }, - { 0x01F8A , 0x01F0A , 0x00345 }, - { 0x01F8B , 0x01F0B , 0x00345 }, - { 0x01F8C , 0x01F0C , 0x00345 }, - { 0x01F8D , 0x01F0D , 0x00345 }, - { 0x01F8E , 0x01F0E , 0x00345 }, - { 0x01F8F , 0x01F0F , 0x00345 }, - { 0x01F90 , 0x01F20 , 0x00345 }, - { 0x01F91 , 0x01F21 , 0x00345 }, - { 0x01F92 , 0x01F22 , 0x00345 }, - { 0x01F93 , 0x01F23 , 0x00345 }, - { 0x01F94 , 0x01F24 , 0x00345 }, - { 0x01F95 , 0x01F25 , 0x00345 }, - { 0x01F96 , 0x01F26 , 0x00345 }, - { 0x01F97 , 0x01F27 , 0x00345 }, - { 0x01F98 , 0x01F28 , 0x00345 }, - { 0x01F99 , 0x01F29 , 0x00345 }, - { 0x01F9A , 0x01F2A , 0x00345 }, - { 0x01F9B , 0x01F2B , 0x00345 }, - { 0x01F9C , 0x01F2C , 0x00345 }, - { 0x01F9D , 0x01F2D , 0x00345 }, - { 0x01F9E , 0x01F2E , 0x00345 }, - { 0x01F9F , 0x01F2F , 0x00345 }, - { 0x01FA0 , 0x01F60 , 0x00345 }, - { 0x01FA1 , 0x01F61 , 0x00345 }, - { 0x01FA2 , 0x01F62 , 0x00345 }, - { 0x01FA3 , 0x01F63 , 0x00345 }, - { 0x01FA4 , 0x01F64 , 0x00345 }, - { 0x01FA5 , 0x01F65 , 0x00345 }, - { 0x01FA6 , 0x01F66 , 0x00345 }, - { 0x01FA7 , 0x01F67 , 0x00345 }, - { 0x01FA8 , 0x01F68 , 0x00345 }, - { 0x01FA9 , 0x01F69 , 0x00345 }, - { 0x01FAA , 0x01F6A , 0x00345 }, - { 0x01FAB , 0x01F6B , 0x00345 }, - { 0x01FAC , 0x01F6C , 0x00345 }, - { 0x01FAD , 0x01F6D , 0x00345 }, - { 0x01FAE , 0x01F6E , 0x00345 }, - { 0x01FAF , 0x01F6F , 0x00345 }, - { 0x01FB0 , 0x003B1 , 0x00306 }, - { 0x01FB1 , 0x003B1 , 0x00304 }, - { 0x01FB2 , 0x01F70 , 0x00345 }, - { 0x01FB3 , 0x003B1 , 0x00345 }, - { 0x01FB4 , 0x003AC , 0x00345 }, - { 0x01FB6 , 0x003B1 , 0x00342 }, - { 0x01FB7 , 0x01FB6 , 0x00345 }, - { 0x01FB8 , 0x00391 , 0x00306 }, - { 0x01FB9 , 0x00391 , 0x00304 }, - { 0x01FBA , 0x00391 , 0x00300 }, - { 0x01FBC , 0x00391 , 0x00345 }, - { 0x01FC1 , 0x000A8 , 0x00342 }, - { 0x01FC2 , 0x01F74 , 0x00345 }, - { 0x01FC3 , 0x003B7 , 0x00345 }, - { 0x01FC4 , 0x003AE , 0x00345 }, - { 0x01FC6 , 0x003B7 , 0x00342 }, - { 0x01FC7 , 0x01FC6 , 0x00345 }, - { 0x01FC8 , 0x00395 , 0x00300 }, - { 0x01FCA , 0x00397 , 0x00300 }, - { 0x01FCC , 0x00397 , 0x00345 }, - { 0x01FCD , 0x01FBF , 0x00300 }, - { 0x01FCE , 0x01FBF , 0x00301 }, - { 0x01FCF , 0x01FBF , 0x00342 }, - { 0x01FD0 , 0x003B9 , 0x00306 }, - { 0x01FD1 , 0x003B9 , 0x00304 }, - { 0x01FD2 , 0x003CA , 0x00300 }, - { 0x01FD6 , 0x003B9 , 0x00342 }, - { 0x01FD7 , 0x003CA , 0x00342 }, - { 0x01FD8 , 0x00399 , 0x00306 }, - { 0x01FD9 , 0x00399 , 0x00304 }, - { 0x01FDA , 0x00399 , 0x00300 }, - { 0x01FDD , 0x01FFE , 0x00300 }, - { 0x01FDE , 0x01FFE , 0x00301 }, - { 0x01FDF , 0x01FFE , 0x00342 }, - { 0x01FE0 , 0x003C5 , 0x00306 }, - { 0x01FE1 , 0x003C5 , 0x00304 }, - { 0x01FE2 , 0x003CB , 0x00300 }, - { 0x01FE4 , 0x003C1 , 0x00313 }, - { 0x01FE5 , 0x003C1 , 0x00314 }, - { 0x01FE6 , 0x003C5 , 0x00342 }, - { 0x01FE7 , 0x003CB , 0x00342 }, - { 0x01FE8 , 0x003A5 , 0x00306 }, - { 0x01FE9 , 0x003A5 , 0x00304 }, - { 0x01FEA , 0x003A5 , 0x00300 }, - { 0x01FEC , 0x003A1 , 0x00314 }, - { 0x01FED , 0x000A8 , 0x00300 }, - { 0x01FF2 , 0x01F7C , 0x00345 }, - { 0x01FF3 , 0x003C9 , 0x00345 }, - { 0x01FF4 , 0x003CE , 0x00345 }, - { 0x01FF6 , 0x003C9 , 0x00342 }, - { 0x01FF7 , 0x01FF6 , 0x00345 }, - { 0x01FF8 , 0x0039F , 0x00300 }, - { 0x01FFA , 0x003A9 , 0x00300 }, - { 0x01FFC , 0x003A9 , 0x00345 }, - { 0x0219A , 0x02190 , 0x00338 }, - { 0x0219B , 0x02192 , 0x00338 }, - { 0x021AE , 0x02194 , 0x00338 }, - { 0x021CD , 0x021D0 , 0x00338 }, - { 0x021CE , 0x021D4 , 0x00338 }, - { 0x021CF , 0x021D2 , 0x00338 }, - { 0x02204 , 0x02203 , 0x00338 }, - { 0x02209 , 0x02208 , 0x00338 }, - { 0x0220C , 0x0220B , 0x00338 }, - { 0x02224 , 0x02223 , 0x00338 }, - { 0x02226 , 0x02225 , 0x00338 }, - { 0x02241 , 0x0223C , 0x00338 }, - { 0x02244 , 0x02243 , 0x00338 }, - { 0x02247 , 0x02245 , 0x00338 }, - { 0x02249 , 0x02248 , 0x00338 }, - { 0x02260 , 0x0003D , 0x00338 }, - { 0x02262 , 0x02261 , 0x00338 }, - { 0x0226D , 0x0224D , 0x00338 }, - { 0x0226E , 0x0003C , 0x00338 }, - { 0x0226F , 0x0003E , 0x00338 }, - { 0x02270 , 0x02264 , 0x00338 }, - { 0x02271 , 0x02265 , 0x00338 }, - { 0x02274 , 0x02272 , 0x00338 }, - { 0x02275 , 0x02273 , 0x00338 }, - { 0x02278 , 0x02276 , 0x00338 }, - { 0x02279 , 0x02277 , 0x00338 }, - { 0x02280 , 0x0227A , 0x00338 }, - { 0x02281 , 0x0227B , 0x00338 }, - { 0x02284 , 0x02282 , 0x00338 }, - { 0x02285 , 0x02283 , 0x00338 }, - { 0x02288 , 0x02286 , 0x00338 }, - { 0x02289 , 0x02287 , 0x00338 }, - { 0x022AC , 0x022A2 , 0x00338 }, - { 0x022AD , 0x022A8 , 0x00338 }, - { 0x022AE , 0x022A9 , 0x00338 }, - { 0x022AF , 0x022AB , 0x00338 }, - { 0x022E0 , 0x0227C , 0x00338 }, - { 0x022E1 , 0x0227D , 0x00338 }, - { 0x022E2 , 0x02291 , 0x00338 }, - { 0x022E3 , 0x02292 , 0x00338 }, - { 0x022EA , 0x022B2 , 0x00338 }, - { 0x022EB , 0x022B3 , 0x00338 }, - { 0x022EC , 0x022B4 , 0x00338 }, - { 0x022ED , 0x022B5 , 0x00338 }, - { 0x0304C , 0x0304B , 0x03099 }, - { 0x0304E , 0x0304D , 0x03099 }, - { 0x03050 , 0x0304F , 0x03099 }, - { 0x03052 , 0x03051 , 0x03099 }, - { 0x03054 , 0x03053 , 0x03099 }, - { 0x03056 , 0x03055 , 0x03099 }, - { 0x03058 , 0x03057 , 0x03099 }, - { 0x0305A , 0x03059 , 0x03099 }, - { 0x0305C , 0x0305B , 0x03099 }, - { 0x0305E , 0x0305D , 0x03099 }, - { 0x03060 , 0x0305F , 0x03099 }, - { 0x03062 , 0x03061 , 0x03099 }, - { 0x03065 , 0x03064 , 0x03099 }, - { 0x03067 , 0x03066 , 0x03099 }, - { 0x03069 , 0x03068 , 0x03099 }, - { 0x03070 , 0x0306F , 0x03099 }, - { 0x03071 , 0x0306F , 0x0309A }, - { 0x03073 , 0x03072 , 0x03099 }, - { 0x03074 , 0x03072 , 0x0309A }, - { 0x03076 , 0x03075 , 0x03099 }, - { 0x03077 , 0x03075 , 0x0309A }, - { 0x03079 , 0x03078 , 0x03099 }, - { 0x0307A , 0x03078 , 0x0309A }, - { 0x0307C , 0x0307B , 0x03099 }, - { 0x0307D , 0x0307B , 0x0309A }, - { 0x03094 , 0x03046 , 0x03099 }, - { 0x0309E , 0x0309D , 0x03099 }, - { 0x030AC , 0x030AB , 0x03099 }, - { 0x030AE , 0x030AD , 0x03099 }, - { 0x030B0 , 0x030AF , 0x03099 }, - { 0x030B2 , 0x030B1 , 0x03099 }, - { 0x030B4 , 0x030B3 , 0x03099 }, - { 0x030B6 , 0x030B5 , 0x03099 }, - { 0x030B8 , 0x030B7 , 0x03099 }, - { 0x030BA , 0x030B9 , 0x03099 }, - { 0x030BC , 0x030BB , 0x03099 }, - { 0x030BE , 0x030BD , 0x03099 }, - { 0x030C0 , 0x030BF , 0x03099 }, - { 0x030C2 , 0x030C1 , 0x03099 }, - { 0x030C5 , 0x030C4 , 0x03099 }, - { 0x030C7 , 0x030C6 , 0x03099 }, - { 0x030C9 , 0x030C8 , 0x03099 }, - { 0x030D0 , 0x030CF , 0x03099 }, - { 0x030D1 , 0x030CF , 0x0309A }, - { 0x030D3 , 0x030D2 , 0x03099 }, - { 0x030D4 , 0x030D2 , 0x0309A }, - { 0x030D6 , 0x030D5 , 0x03099 }, - { 0x030D7 , 0x030D5 , 0x0309A }, - { 0x030D9 , 0x030D8 , 0x03099 }, - { 0x030DA , 0x030D8 , 0x0309A }, - { 0x030DC , 0x030DB , 0x03099 }, - { 0x030DD , 0x030DB , 0x0309A }, - { 0x030F4 , 0x030A6 , 0x03099 }, - { 0x030F7 , 0x030EF , 0x03099 }, - { 0x030F8 , 0x030F0 , 0x03099 }, - { 0x030F9 , 0x030F1 , 0x03099 }, - { 0x030FA , 0x030F2 , 0x03099 }, - { 0x030FE , 0x030FD , 0x03099 }, - { 0x1109A , 0x11099 , 0x110BA }, - { 0x1109C , 0x1109B , 0x110BA }, - { 0x110AB , 0x110A5 , 0x110BA }, -}; - -#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */ - diff --git a/3rdparty/libarchive/libarchive/archive_string_sprintf.c b/3rdparty/libarchive/libarchive/archive_string_sprintf.c deleted file mode 100644 index 969a5603..00000000 --- a/3rdparty/libarchive/libarchive/archive_string_sprintf.c +++ /dev/null @@ -1,192 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03-06 05:14:55Z kientzle $"); - -/* - * The use of printf()-family functions can be troublesome - * for space-constrained applications. In addition, correctly - * implementing this function in terms of vsnprintf() requires - * two calls (one to determine the size, another to format the - * result), which in turn requires duplicating the argument list - * using va_copy, which isn't yet universally available. - * - * So, I've implemented a bare minimum of printf()-like capability - * here. This is only used to format error messages, so doesn't - * require any floating-point support or field-width handling. - */ -#ifdef HAVE_ERRNO_H -#include -#endif -#include - -#include "archive_string.h" -#include "archive_private.h" - -/* - * Utility functions to format signed/unsigned integers and append - * them to an archive_string. - */ -static void -append_uint(struct archive_string *as, uintmax_t d, unsigned base) -{ - static const char digits[] = "0123456789abcdef"; - if (d >= base) - append_uint(as, d/base, base); - archive_strappend_char(as, digits[d % base]); -} - -static void -append_int(struct archive_string *as, intmax_t d, unsigned base) -{ - uintmax_t ud; - - if (d < 0) { - archive_strappend_char(as, '-'); - ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d); - } else - ud = d; - append_uint(as, ud, base); -} - - -void -archive_string_sprintf(struct archive_string *as, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - archive_string_vsprintf(as, fmt, ap); - va_end(ap); -} - -/* - * Like 'vsprintf', but ensures the target is big enough, resizing if - * necessary. - */ -void -archive_string_vsprintf(struct archive_string *as, const char *fmt, - va_list ap) -{ - char long_flag; - intmax_t s; /* Signed integer temp. */ - uintmax_t u; /* Unsigned integer temp. */ - const char *p, *p2; - const wchar_t *pw; - - if (archive_string_ensure(as, 64) == NULL) - __archive_errx(1, "Out of memory"); - - if (fmt == NULL) { - as->s[0] = 0; - return; - } - - for (p = fmt; *p != '\0'; p++) { - const char *saved_p = p; - - if (*p != '%') { - archive_strappend_char(as, *p); - continue; - } - - p++; - - long_flag = '\0'; - switch(*p) { - case 'j': - case 'l': - case 'z': - long_flag = *p; - p++; - break; - } - - switch (*p) { - case '%': - archive_strappend_char(as, '%'); - break; - case 'c': - s = va_arg(ap, int); - archive_strappend_char(as, (char)s); - break; - case 'd': - switch(long_flag) { - case 'j': s = va_arg(ap, intmax_t); break; - case 'l': s = va_arg(ap, long); break; - case 'z': s = va_arg(ap, ssize_t); break; - default: s = va_arg(ap, int); break; - } - append_int(as, s, 10); - break; - case 's': - switch(long_flag) { - case 'l': - pw = va_arg(ap, wchar_t *); - if (pw == NULL) - pw = L"(null)"; - if (archive_string_append_from_wcs(as, pw, - wcslen(pw)) != 0 && errno == ENOMEM) - __archive_errx(1, "Out of memory"); - break; - default: - p2 = va_arg(ap, char *); - if (p2 == NULL) - p2 = "(null)"; - archive_strcat(as, p2); - break; - } - break; - case 'S': - pw = va_arg(ap, wchar_t *); - if (pw == NULL) - pw = L"(null)"; - if (archive_string_append_from_wcs(as, pw, - wcslen(pw)) != 0 && errno == ENOMEM) - __archive_errx(1, "Out of memory"); - break; - case 'o': case 'u': case 'x': case 'X': - /* Common handling for unsigned integer formats. */ - switch(long_flag) { - case 'j': u = va_arg(ap, uintmax_t); break; - case 'l': u = va_arg(ap, unsigned long); break; - case 'z': u = va_arg(ap, size_t); break; - default: u = va_arg(ap, unsigned int); break; - } - /* Format it in the correct base. */ - switch (*p) { - case 'o': append_uint(as, u, 8); break; - case 'u': append_uint(as, u, 10); break; - default: append_uint(as, u, 16); break; - } - break; - default: - /* Rewind and print the initial '%' literally. */ - p = saved_p; - archive_strappend_char(as, *p); - } - } -} diff --git a/3rdparty/libarchive/libarchive/archive_util.c b/3rdparty/libarchive/libarchive/archive_util.c deleted file mode 100644 index bac9ba1c..00000000 --- a/3rdparty/libarchive/libarchive/archive_util.c +++ /dev/null @@ -1,585 +0,0 @@ -/*- - * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) -#include -#endif -#ifdef HAVE_ZLIB_H -#include -#endif -#ifdef HAVE_LZMA_H -#include -#endif -#ifdef HAVE_BZLIB_H -#include -#endif -#ifdef HAVE_LZ4_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_random_private.h" -#include "archive_string.h" - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -static int archive_utility_string_sort_helper(char **, unsigned int); - -/* Generic initialization of 'struct archive' objects. */ -int -__archive_clean(struct archive *a) -{ - archive_string_conversion_free(a); - return (ARCHIVE_OK); -} - -int -archive_version_number(void) -{ - return (ARCHIVE_VERSION_NUMBER); -} - -const char * -archive_version_string(void) -{ - return (ARCHIVE_VERSION_STRING); -} - -int -archive_errno(struct archive *a) -{ - return (a->archive_error_number); -} - -const char * -archive_error_string(struct archive *a) -{ - - if (a->error != NULL && *a->error != '\0') - return (a->error); - else - return (NULL); -} - -int -archive_file_count(struct archive *a) -{ - return (a->file_count); -} - -int -archive_format(struct archive *a) -{ - return (a->archive_format); -} - -const char * -archive_format_name(struct archive *a) -{ - return (a->archive_format_name); -} - - -int -archive_compression(struct archive *a) -{ - return archive_filter_code(a, 0); -} - -const char * -archive_compression_name(struct archive *a) -{ - return archive_filter_name(a, 0); -} - - -/* - * Return a count of the number of compressed bytes processed. - */ -int64_t -archive_position_compressed(struct archive *a) -{ - return archive_filter_bytes(a, -1); -} - -/* - * Return a count of the number of uncompressed bytes processed. - */ -int64_t -archive_position_uncompressed(struct archive *a) -{ - return archive_filter_bytes(a, 0); -} - -void -archive_clear_error(struct archive *a) -{ - archive_string_empty(&a->error_string); - a->error = NULL; - a->archive_error_number = 0; -} - -void -archive_set_error(struct archive *a, int error_number, const char *fmt, ...) -{ - va_list ap; - - a->archive_error_number = error_number; - if (fmt == NULL) { - a->error = NULL; - return; - } - - archive_string_empty(&(a->error_string)); - va_start(ap, fmt); - archive_string_vsprintf(&(a->error_string), fmt, ap); - va_end(ap); - a->error = a->error_string.s; -} - -void -archive_copy_error(struct archive *dest, struct archive *src) -{ - dest->archive_error_number = src->archive_error_number; - - archive_string_copy(&dest->error_string, &src->error_string); - dest->error = dest->error_string.s; -} - -void -__archive_errx(int retvalue, const char *msg) -{ - static const char msg1[] = "Fatal Internal Error in libarchive: "; - size_t s; - - s = write(2, msg1, strlen(msg1)); - (void)s; /* UNUSED */ - s = write(2, msg, strlen(msg)); - (void)s; /* UNUSED */ - s = write(2, "\n", 1); - (void)s; /* UNUSED */ - exit(retvalue); -} - -/* - * Create a temporary file - */ -#if defined(_WIN32) && !defined(__CYGWIN__) - -/* - * Do not use Windows tmpfile() function. - * It will make a temporary file under the root directory - * and it'll cause permission error if a user who is - * non-Administrator creates temporary files. - * Also Windows version of mktemp family including _mktemp_s - * are not secure. - */ -int -__archive_mktemp(const char *tmpdir) -{ - static const wchar_t prefix[] = L"libarchive_"; - static const wchar_t suffix[] = L"XXXXXXXXXX"; - static const wchar_t num[] = { - L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', - L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', - L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', - L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', - L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', - L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', - L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', - L'u', L'v', L'w', L'x', L'y', L'z' - }; - HCRYPTPROV hProv; - struct archive_wstring temp_name; - wchar_t *ws; - DWORD attr; - wchar_t *xp, *ep; - int fd; - - hProv = (HCRYPTPROV)NULL; - fd = -1; - ws = NULL; - archive_string_init(&temp_name); - - /* Get a temporary directory. */ - if (tmpdir == NULL) { - size_t l; - wchar_t *tmp; - - l = GetTempPathW(0, NULL); - if (l == 0) { - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - tmp = malloc(l*sizeof(wchar_t)); - if (tmp == NULL) { - errno = ENOMEM; - goto exit_tmpfile; - } - GetTempPathW((DWORD)l, tmp); - archive_wstrcpy(&temp_name, tmp); - free(tmp); - } else { - if (archive_wstring_append_from_mbs(&temp_name, tmpdir, - strlen(tmpdir)) < 0) - goto exit_tmpfile; - if (temp_name.s[temp_name.length-1] != L'/') - archive_wstrappend_wchar(&temp_name, L'/'); - } - - /* Check if temp_name is a directory. */ - attr = GetFileAttributesW(temp_name.s); - if (attr == (DWORD)-1) { - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - ws = __la_win_permissive_name_w(temp_name.s); - if (ws == NULL) { - errno = EINVAL; - goto exit_tmpfile; - } - attr = GetFileAttributesW(ws); - if (attr == (DWORD)-1) { - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - } - if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { - errno = ENOTDIR; - goto exit_tmpfile; - } - - /* - * Create a temporary file. - */ - archive_wstrcat(&temp_name, prefix); - archive_wstrcat(&temp_name, suffix); - ep = temp_name.s + archive_strlen(&temp_name); - xp = ep - wcslen(suffix); - - if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - - for (;;) { - wchar_t *p; - HANDLE h; - - /* Generate a random file name through CryptGenRandom(). */ - p = xp; - if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), - (BYTE*)p)) { - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - for (; p < ep; p++) - *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; - - free(ws); - ws = __la_win_permissive_name_w(temp_name.s); - if (ws == NULL) { - errno = EINVAL; - goto exit_tmpfile; - } - /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to - * delete this temporary file immediately when this - * file closed. */ - h = CreateFileW(ws, - GENERIC_READ | GENERIC_WRITE | DELETE, - 0,/* Not share */ - NULL, - CREATE_NEW,/* Create a new file only */ - FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); - if (h == INVALID_HANDLE_VALUE) { - /* The same file already exists. retry with - * a new filename. */ - if (GetLastError() == ERROR_FILE_EXISTS) - continue; - /* Otherwise, fail creation temporary file. */ - la_dosmaperr(GetLastError()); - goto exit_tmpfile; - } - fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); - if (fd == -1) { - CloseHandle(h); - goto exit_tmpfile; - } else - break;/* success! */ - } -exit_tmpfile: - if (hProv != (HCRYPTPROV)NULL) - CryptReleaseContext(hProv, 0); - free(ws); - archive_wstring_free(&temp_name); - return (fd); -} - -#else - -static int -get_tempdir(struct archive_string *temppath) -{ - const char *tmp; - - tmp = getenv("TMPDIR"); - if (tmp == NULL) -#ifdef _PATH_TMP - tmp = _PATH_TMP; -#else - tmp = "/tmp"; -#endif - archive_strcpy(temppath, tmp); - if (temppath->s[temppath->length-1] != '/') - archive_strappend_char(temppath, '/'); - return (ARCHIVE_OK); -} - -#if defined(HAVE_MKSTEMP) - -/* - * We can use mkstemp(). - */ - -int -__archive_mktemp(const char *tmpdir) -{ - struct archive_string temp_name; - int fd = -1; - - archive_string_init(&temp_name); - if (tmpdir == NULL) { - if (get_tempdir(&temp_name) != ARCHIVE_OK) - goto exit_tmpfile; - } else { - archive_strcpy(&temp_name, tmpdir); - if (temp_name.s[temp_name.length-1] != '/') - archive_strappend_char(&temp_name, '/'); - } - archive_strcat(&temp_name, "libarchive_XXXXXX"); - fd = mkstemp(temp_name.s); - if (fd < 0) - goto exit_tmpfile; - __archive_ensure_cloexec_flag(fd); - unlink(temp_name.s); -exit_tmpfile: - archive_string_free(&temp_name); - return (fd); -} - -#else - -/* - * We use a private routine. - */ - -int -__archive_mktemp(const char *tmpdir) -{ - static const char num[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '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' - }; - struct archive_string temp_name; - struct stat st; - int fd; - char *tp, *ep; - - fd = -1; - archive_string_init(&temp_name); - if (tmpdir == NULL) { - if (get_tempdir(&temp_name) != ARCHIVE_OK) - goto exit_tmpfile; - } else - archive_strcpy(&temp_name, tmpdir); - if (temp_name.s[temp_name.length-1] == '/') { - temp_name.s[temp_name.length-1] = '\0'; - temp_name.length --; - } - if (stat(temp_name.s, &st) < 0) - goto exit_tmpfile; - if (!S_ISDIR(st.st_mode)) { - errno = ENOTDIR; - goto exit_tmpfile; - } - archive_strcat(&temp_name, "/libarchive_"); - tp = temp_name.s + archive_strlen(&temp_name); - archive_strcat(&temp_name, "XXXXXXXXXX"); - ep = temp_name.s + archive_strlen(&temp_name); - - do { - char *p; - - p = tp; - archive_random(p, ep - p); - while (p < ep) { - int d = *((unsigned char *)p) % sizeof(num); - *p++ = num[d]; - } - fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, - 0600); - } while (fd < 0 && errno == EEXIST); - if (fd < 0) - goto exit_tmpfile; - __archive_ensure_cloexec_flag(fd); - unlink(temp_name.s); -exit_tmpfile: - archive_string_free(&temp_name); - return (fd); -} - -#endif /* HAVE_MKSTEMP */ -#endif /* !_WIN32 || __CYGWIN__ */ - -/* - * Set FD_CLOEXEC flag to a file descriptor if it is not set. - * We have to set the flag if the platform does not provide O_CLOEXEC - * or F_DUPFD_CLOEXEC flags. - * - * Note: This function is absolutely called after creating a new file - * descriptor even if the platform seemingly provides O_CLOEXEC or - * F_DUPFD_CLOEXEC macros because it is possible that the platform - * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. - */ -void -__archive_ensure_cloexec_flag(int fd) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)fd; /* UNUSED */ -#else - int flags; - - if (fd >= 0) { - flags = fcntl(fd, F_GETFD); - if (flags != -1 && (flags & FD_CLOEXEC) == 0) - fcntl(fd, F_SETFD, flags | FD_CLOEXEC); - } -#endif -} - -/* - * Utility function to sort a group of strings using quicksort. - */ -static int -archive_utility_string_sort_helper(char **strings, unsigned int n) -{ - unsigned int i, lesser_count, greater_count; - char **lesser, **greater, **tmp, *pivot; - int retval1, retval2; - - /* A list of 0 or 1 elements is already sorted */ - if (n <= 1) - return (ARCHIVE_OK); - - lesser_count = greater_count = 0; - lesser = greater = NULL; - pivot = strings[0]; - for (i = 1; i < n; i++) - { - if (strcmp(strings[i], pivot) < 0) - { - lesser_count++; - tmp = (char **)realloc(lesser, - lesser_count * sizeof(char *)); - if (!tmp) { - free(greater); - free(lesser); - return (ARCHIVE_FATAL); - } - lesser = tmp; - lesser[lesser_count - 1] = strings[i]; - } - else - { - greater_count++; - tmp = (char **)realloc(greater, - greater_count * sizeof(char *)); - if (!tmp) { - free(greater); - free(lesser); - return (ARCHIVE_FATAL); - } - greater = tmp; - greater[greater_count - 1] = strings[i]; - } - } - - /* quicksort(lesser) */ - retval1 = archive_utility_string_sort_helper(lesser, lesser_count); - for (i = 0; i < lesser_count; i++) - strings[i] = lesser[i]; - free(lesser); - - /* pivot */ - strings[lesser_count] = pivot; - - /* quicksort(greater) */ - retval2 = archive_utility_string_sort_helper(greater, greater_count); - for (i = 0; i < greater_count; i++) - strings[lesser_count + 1 + i] = greater[i]; - free(greater); - - return (retval1 < retval2) ? retval1 : retval2; -} - -int -archive_utility_string_sort(char **strings) -{ - unsigned int size = 0; - while (strings[size] != NULL) - size++; - return archive_utility_string_sort_helper(strings, size); -} diff --git a/3rdparty/libarchive/libarchive/archive_virtual.c b/3rdparty/libarchive/libarchive/archive_virtual.c deleted file mode 100644 index de2595a9..00000000 --- a/3rdparty/libarchive/libarchive/archive_virtual.c +++ /dev/null @@ -1,162 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_virtual.c 201098 2009-12-28 02:58:14Z kientzle $"); - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" - -int -archive_filter_code(struct archive *a, int n) -{ - return ((a->vtable->archive_filter_code)(a, n)); -} - -int -archive_filter_count(struct archive *a) -{ - return ((a->vtable->archive_filter_count)(a)); -} - -const char * -archive_filter_name(struct archive *a, int n) -{ - return ((a->vtable->archive_filter_name)(a, n)); -} - -int64_t -archive_filter_bytes(struct archive *a, int n) -{ - return ((a->vtable->archive_filter_bytes)(a, n)); -} - -int -archive_free(struct archive *a) -{ - if (a == NULL) - return (ARCHIVE_OK); - return ((a->vtable->archive_free)(a)); -} - -int -archive_write_close(struct archive *a) -{ - return ((a->vtable->archive_close)(a)); -} - -int -archive_read_close(struct archive *a) -{ - return ((a->vtable->archive_close)(a)); -} - -int -archive_write_fail(struct archive *a) -{ - a->state = ARCHIVE_STATE_FATAL; - return a->state; -} - -int -archive_write_free(struct archive *a) -{ - return archive_free(a); -} - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* For backwards compatibility; will be removed with libarchive 4.0. */ -int -archive_write_finish(struct archive *a) -{ - return archive_write_free(a); -} -#endif - -int -archive_read_free(struct archive *a) -{ - return archive_free(a); -} - -#if ARCHIVE_VERSION_NUMBER < 4000000 -/* For backwards compatibility; will be removed with libarchive 4.0. */ -int -archive_read_finish(struct archive *a) -{ - return archive_read_free(a); -} -#endif - -int -archive_write_header(struct archive *a, struct archive_entry *entry) -{ - ++a->file_count; - return ((a->vtable->archive_write_header)(a, entry)); -} - -int -archive_write_finish_entry(struct archive *a) -{ - return ((a->vtable->archive_write_finish_entry)(a)); -} - -ssize_t -archive_write_data(struct archive *a, const void *buff, size_t s) -{ - return ((a->vtable->archive_write_data)(a, buff, s)); -} - -ssize_t -archive_write_data_block(struct archive *a, const void *buff, size_t s, int64_t o) -{ - if (a->vtable->archive_write_data_block == NULL) { - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "archive_write_data_block not supported"); - a->state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - return ((a->vtable->archive_write_data_block)(a, buff, s, o)); -} - -int -archive_read_next_header(struct archive *a, struct archive_entry **entry) -{ - return ((a->vtable->archive_read_next_header)(a, entry)); -} - -int -archive_read_next_header2(struct archive *a, struct archive_entry *entry) -{ - return ((a->vtable->archive_read_next_header2)(a, entry)); -} - -int -archive_read_data_block(struct archive *a, - const void **buff, size_t *s, int64_t *o) -{ - return ((a->vtable->archive_read_data_block)(a, buff, s, o)); -} diff --git a/3rdparty/libarchive/libarchive/archive_windows.c b/3rdparty/libarchive/libarchive/archive_windows.c deleted file mode 100644 index 6ff8749a..00000000 --- a/3rdparty/libarchive/libarchive/archive_windows.c +++ /dev/null @@ -1,908 +0,0 @@ -/*- - * Copyright (c) 2009-2011 Michihiro NAKAJIMA - * Copyright (c) 2003-2007 Kees Zeelenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * A set of compatibility glue for building libarchive on Windows platforms. - * - * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg - * for the GnuWin32 project, trimmed significantly by Tim Kientzle. - * - * Much of the original file was unnecessary for libarchive, because - * many of the features it emulated were not strictly necessary for - * libarchive. I hope for this to shrink further as libarchive - * internals are gradually reworked to sit more naturally on both - * POSIX and Windows. Any ideas for this are greatly appreciated. - * - * The biggest remaining issue is the dev/ino emulation; libarchive - * has a couple of public APIs that rely on dev/ino uniquely - * identifying a file. This doesn't match well with Windows. I'm - * considering alternative APIs. - */ - -#if defined(_WIN32) && !defined(__CYGWIN__) - -#include "archive_platform.h" -#include "archive_private.h" -#include "archive_entry.h" -#include -#include -#include -#ifdef HAVE_SYS_UTIME_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) - -#if defined(__LA_LSEEK_NEEDED) -static BOOL SetFilePointerEx_perso(HANDLE hFile, - LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, - DWORD dwMoveMethod) -{ - LARGE_INTEGER li; - li.QuadPart = liDistanceToMove.QuadPart; - li.LowPart = SetFilePointer( - hFile, li.LowPart, &li.HighPart, dwMoveMethod); - if(lpNewFilePointer) { - lpNewFilePointer->QuadPart = li.QuadPart; - } - return li.LowPart != -1 || GetLastError() == NO_ERROR; -} -#endif - -struct ustat { - int64_t st_atime; - uint32_t st_atime_nsec; - int64_t st_ctime; - uint32_t st_ctime_nsec; - int64_t st_mtime; - uint32_t st_mtime_nsec; - gid_t st_gid; - /* 64bits ino */ - int64_t st_ino; - mode_t st_mode; - uint32_t st_nlink; - uint64_t st_size; - uid_t st_uid; - dev_t st_dev; - dev_t st_rdev; -}; - -/* Transform 64-bits ino into 32-bits by hashing. - * You do not forget that really unique number size is 64-bits. - */ -#define INOSIZE (8*sizeof(ino_t)) /* 32 */ -static __inline ino_t -getino(struct ustat *ub) -{ - ULARGE_INTEGER ino64; - ino64.QuadPart = ub->st_ino; - /* I don't know this hashing is correct way */ - return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE))); -} - -/* - * Prepend "\\?\" to the path name and convert it to unicode to permit - * an extended-length path for a maximum total path length of 32767 - * characters. - * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx - */ -wchar_t * -__la_win_permissive_name(const char *name) -{ - wchar_t *wn; - wchar_t *ws; - size_t ll; - - ll = strlen(name); - wn = malloc((ll + 1) * sizeof(wchar_t)); - if (wn == NULL) - return (NULL); - ll = mbstowcs(wn, name, ll); - if (ll == (size_t)-1) { - free(wn); - return (NULL); - } - wn[ll] = L'\0'; - ws = __la_win_permissive_name_w(wn); - free(wn); - return (ws); -} - -wchar_t * -__la_win_permissive_name_w(const wchar_t *wname) -{ - wchar_t *wn, *wnp; - wchar_t *ws, *wsp; - DWORD l, len, slen; - int unc; - - /* Get a full-pathname. */ - l = GetFullPathNameW(wname, 0, NULL, NULL); - if (l == 0) - return (NULL); - /* NOTE: GetFullPathNameW has a bug that if the length of the file - * name is just 1 then it returns incomplete buffer size. Thus, we - * have to add three to the size to allocate a sufficient buffer - * size for the full-pathname of the file name. */ - l += 3; - wnp = malloc(l * sizeof(wchar_t)); - if (wnp == NULL) - return (NULL); - len = GetFullPathNameW(wname, l, wnp, NULL); - wn = wnp; - - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'?' && wnp[3] == L'\\') - /* We have already a permissive name. */ - return (wn); - - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'.' && wnp[3] == L'\\') { - /* This is a device name */ - if (((wnp[4] >= L'a' && wnp[4] <= L'z') || - (wnp[4] >= L'A' && wnp[4] <= L'Z')) && - wnp[5] == L':' && wnp[6] == L'\\') - wnp[2] = L'?';/* Not device name. */ - return (wn); - } - - unc = 0; - if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { - wchar_t *p = &wnp[2]; - - /* Skip server-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\') { - wchar_t *rp = ++p; - /* Skip share-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\' && p != rp) { - /* Now, match patterns such as - * "\\server-name\share-name\" */ - wnp += 2; - len -= 2; - unc = 1; - } - } - } - - slen = 4 + (unc * 4) + len + 1; - ws = wsp = malloc(slen * sizeof(wchar_t)); - if (ws == NULL) { - free(wn); - return (NULL); - } - /* prepend "\\?\" */ - wcsncpy(wsp, L"\\\\?\\", 4); - wsp += 4; - slen -= 4; - if (unc) { - /* append "UNC\" ---> "\\?\UNC\" */ - wcsncpy(wsp, L"UNC\\", 4); - wsp += 4; - slen -= 4; - } - wcsncpy(wsp, wnp, slen); - wsp[slen - 1] = L'\0'; /* Ensure null termination. */ - free(wn); - return (ws); -} - -/* - * Create a file handle. - * This can exceed MAX_PATH limitation. - */ -static HANDLE -la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) -{ - wchar_t *wpath; - HANDLE handle; - - handle = CreateFileA(path, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, - hTemplateFile); - if (handle != INVALID_HANDLE_VALUE) - return (handle); - if (GetLastError() != ERROR_PATH_NOT_FOUND) - return (handle); - wpath = __la_win_permissive_name(path); - if (wpath == NULL) - return (handle); - handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, - hTemplateFile); - free(wpath); - return (handle); -} - -#if defined(__LA_LSEEK_NEEDED) -__int64 -__la_lseek(int fd, __int64 offset, int whence) -{ - LARGE_INTEGER distance; - LARGE_INTEGER newpointer; - HANDLE handle; - - if (fd < 0) { - errno = EBADF; - return (-1); - } - handle = (HANDLE)_get_osfhandle(fd); - if (GetFileType(handle) != FILE_TYPE_DISK) { - errno = EBADF; - return (-1); - } - distance.QuadPart = offset; - if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == ERROR_BROKEN_PIPE) - return (0); - if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - return (-1); - } - return (newpointer.QuadPart); -} -#endif - -/* This can exceed MAX_PATH limitation. */ -int -__la_open(const char *path, int flags, ...) -{ - va_list ap; - wchar_t *ws; - int r, pmode; - DWORD attr; - - va_start(ap, flags); - pmode = va_arg(ap, int); - va_end(ap); - ws = NULL; - if ((flags & ~O_BINARY) == O_RDONLY) { - /* - * When we open a directory, _open function returns - * "Permission denied" error. - */ - attr = GetFileAttributesA(path); - if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) { - ws = __la_win_permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - attr = GetFileAttributesW(ws); - } - if (attr == (DWORD)-1) { - la_dosmaperr(GetLastError()); - free(ws); - return (-1); - } - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - HANDLE handle; - - if (ws != NULL) - handle = CreateFileW(ws, 0, 0, NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | - FILE_ATTRIBUTE_READONLY, - NULL); - else - handle = CreateFileA(path, 0, 0, NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | - FILE_ATTRIBUTE_READONLY, - NULL); - free(ws); - if (handle == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - r = _open_osfhandle((intptr_t)handle, _O_RDONLY); - return (r); - } - } - if (ws == NULL) { -#if defined(__BORLANDC__) - /* Borland has no mode argument. - TODO: Fix mode of new file. */ - r = _open(path, flags); -#else - r = _open(path, flags, pmode); -#endif - if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { - /* Simulate other POSIX system action to pass our test suite. */ - attr = GetFileAttributesA(path); - if (attr == (DWORD)-1) - la_dosmaperr(GetLastError()); - else if (attr & FILE_ATTRIBUTE_DIRECTORY) - errno = EISDIR; - else - errno = EACCES; - return (-1); - } - if (r >= 0 || errno != ENOENT) - return (r); - ws = __la_win_permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - } - r = _wopen(ws, flags, pmode); - if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { - /* Simulate other POSIX system action to pass our test suite. */ - attr = GetFileAttributesW(ws); - if (attr == (DWORD)-1) - la_dosmaperr(GetLastError()); - else if (attr & FILE_ATTRIBUTE_DIRECTORY) - errno = EISDIR; - else - errno = EACCES; - } - free(ws); - return (r); -} - -ssize_t -__la_read(int fd, void *buf, size_t nbytes) -{ - HANDLE handle; - DWORD bytes_read, lasterr; - int r; - -#ifdef _WIN64 - if (nbytes > UINT32_MAX) - nbytes = UINT32_MAX; -#endif - if (fd < 0) { - errno = EBADF; - return (-1); - } - /* Do not pass 0 to third parameter of ReadFile(), read bytes. - * This will not return to application side. */ - if (nbytes == 0) - return (0); - handle = (HANDLE)_get_osfhandle(fd); - r = ReadFile(handle, buf, (uint32_t)nbytes, - &bytes_read, NULL); - if (r == 0) { - lasterr = GetLastError(); - if (lasterr == ERROR_NO_DATA) { - errno = EAGAIN; - return (-1); - } - if (lasterr == ERROR_BROKEN_PIPE) - return (0); - if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - return (-1); - } - return ((ssize_t)bytes_read); -} - -/* Convert Windows FILETIME to UTC */ -__inline static void -fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ - } else { - *t = 0; - *ns = 0; - } -} - -/* Stat by handle - * Windows' stat() does not accept the path added "\\?\" especially "?" - * character. - * It means we cannot access the long name path longer than MAX_PATH. - * So I've implemented simular Windows' stat() to access the long name path. - * And I've added some feature. - * 1. set st_ino by nFileIndexHigh and nFileIndexLow of - * BY_HANDLE_FILE_INFORMATION. - * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. - * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. - */ -static int -__hstat(HANDLE handle, struct ustat *st) -{ - BY_HANDLE_FILE_INFORMATION info; - ULARGE_INTEGER ino64; - DWORD ftype; - mode_t mode; - time_t t; - long ns; - - switch (ftype = GetFileType(handle)) { - case FILE_TYPE_UNKNOWN: - errno = EBADF; - return (-1); - case FILE_TYPE_CHAR: - case FILE_TYPE_PIPE: - if (ftype == FILE_TYPE_CHAR) { - st->st_mode = S_IFCHR; - st->st_size = 0; - } else { - DWORD avail; - - st->st_mode = S_IFIFO; - if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) - st->st_size = avail; - else - st->st_size = 0; - } - st->st_atime = 0; - st->st_atime_nsec = 0; - st->st_mtime = 0; - st->st_mtime_nsec = 0; - st->st_ctime = 0; - st->st_ctime_nsec = 0; - st->st_ino = 0; - st->st_nlink = 1; - st->st_uid = 0; - st->st_gid = 0; - st->st_rdev = 0; - st->st_dev = 0; - return (0); - case FILE_TYPE_DISK: - break; - default: - /* This ftype is undocumented type. */ - la_dosmaperr(GetLastError()); - return (-1); - } - - ZeroMemory(&info, sizeof(info)); - if (!GetFileInformationByHandle (handle, &info)) { - la_dosmaperr(GetLastError()); - return (-1); - } - - mode = S_IRUSR | S_IRGRP | S_IROTH; - if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; - else - mode |= S_IFREG; - st->st_mode = mode; - - fileTimeToUTC(&info.ftLastAccessTime, &t, &ns); - st->st_atime = t; - st->st_atime_nsec = ns; - fileTimeToUTC(&info.ftLastWriteTime, &t, &ns); - st->st_mtime = t; - st->st_mtime_nsec = ns; - fileTimeToUTC(&info.ftCreationTime, &t, &ns); - st->st_ctime = t; - st->st_ctime_nsec = ns; - st->st_size = - ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) - + (int64_t)(info.nFileSizeLow); -#ifdef SIMULATE_WIN_STAT - st->st_ino = 0; - st->st_nlink = 1; - st->st_dev = 0; -#else - /* Getting FileIndex as i-node. We should remove a sequence which - * is high-16-bits of nFileIndexHigh. */ - ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; - ino64.LowPart = info.nFileIndexLow; - st->st_ino = ino64.QuadPart; - st->st_nlink = info.nNumberOfLinks; - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ++st->st_nlink;/* Add parent directory. */ - st->st_dev = info.dwVolumeSerialNumber; -#endif - st->st_uid = 0; - st->st_gid = 0; - st->st_rdev = 0; - return (0); -} - -static void -copy_stat(struct stat *st, struct ustat *us) -{ - st->st_atime = us->st_atime; - st->st_ctime = us->st_ctime; - st->st_mtime = us->st_mtime; - st->st_gid = us->st_gid; - st->st_ino = getino(us); - st->st_mode = us->st_mode; - st->st_nlink = us->st_nlink; - st->st_size = (off_t)us->st_size; - st->st_uid = us->st_uid; - st->st_dev = us->st_dev; - st->st_rdev = us->st_rdev; -} - -/* - * TODO: Remove a use of __la_fstat and __la_stat. - * We should use GetFileInformationByHandle in place - * where We still use the *stat functions. - */ -int -__la_fstat(int fd, struct stat *st) -{ - struct ustat u; - int ret; - - if (fd < 0) { - errno = EBADF; - return (-1); - } - ret = __hstat((HANDLE)_get_osfhandle(fd), &u); - if (ret >= 0) { - copy_stat(st, &u); - if (u.st_mode & (S_IFCHR | S_IFIFO)) { - st->st_dev = fd; - st->st_rdev = fd; - } - } - return (ret); -} - -/* This can exceed MAX_PATH limitation. */ -int -__la_stat(const char *path, struct stat *st) -{ - HANDLE handle; - struct ustat u; - int ret; - - handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - if (handle == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - ret = __hstat(handle, &u); - CloseHandle(handle); - if (ret >= 0) { - char *p; - - copy_stat(st, &u); - p = strrchr(path, '.'); - if (p != NULL && strlen(p) == 4) { - char exttype[4]; - - ++ p; - exttype[0] = toupper(*p++); - exttype[1] = toupper(*p++); - exttype[2] = toupper(*p++); - exttype[3] = '\0'; - if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || - !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) - st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - } - } - return (ret); -} - -/* - * This waitpid is limited implementation. - */ -pid_t -__la_waitpid(HANDLE child, int *status, int option) -{ - DWORD cs; - - (void)option;/* UNUSED */ - do { - if (GetExitCodeProcess(child, &cs) == 0) { - CloseHandle(child); - la_dosmaperr(GetLastError()); - *status = 0; - return (-1); - } - } while (cs == STILL_ACTIVE); - - *status = (int)(cs & 0xff); - return (0); -} - -ssize_t -__la_write(int fd, const void *buf, size_t nbytes) -{ - DWORD bytes_written; - -#ifdef _WIN64 - if (nbytes > UINT32_MAX) - nbytes = UINT32_MAX; -#endif - if (fd < 0) { - errno = EBADF; - return (-1); - } - if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, - &bytes_written, NULL)) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - return (-1); - } - return (bytes_written); -} - -/* - * Replace the Windows path separator '\' with '/'. - */ -static int -replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp) -{ - wchar_t *w; - size_t path_length; - - if (wp == NULL) - return(0); - if (wcschr(wp, L'\\') == NULL) - return(0); - path_length = wcslen(wp); - if (archive_wstring_ensure(ws, path_length) == NULL) - return(-1); - archive_wstrncpy(ws, wp, path_length); - for (w = ws->s; *w; w++) { - if (*w == L'\\') - *w = L'/'; - } - return(1); -} - -static int -fix_pathseparator(struct archive_entry *entry) -{ - struct archive_wstring ws; - const wchar_t *wp; - int ret = ARCHIVE_OK; - - archive_string_init(&ws); - wp = archive_entry_pathname_w(entry); - switch (replace_pathseparator(&ws, wp)) { - case 0: /* Not replaced. */ - break; - case 1: /* Replaced. */ - archive_entry_copy_pathname_w(entry, ws.s); - break; - default: - ret = ARCHIVE_FAILED; - } - wp = archive_entry_hardlink_w(entry); - switch (replace_pathseparator(&ws, wp)) { - case 0: /* Not replaced. */ - break; - case 1: /* Replaced. */ - archive_entry_copy_hardlink_w(entry, ws.s); - break; - default: - ret = ARCHIVE_FAILED; - } - wp = archive_entry_symlink_w(entry); - switch (replace_pathseparator(&ws, wp)) { - case 0: /* Not replaced. */ - break; - case 1: /* Replaced. */ - archive_entry_copy_symlink_w(entry, ws.s); - break; - default: - ret = ARCHIVE_FAILED; - } - archive_wstring_free(&ws); - return(ret); -} - -struct archive_entry * -__la_win_entry_in_posix_pathseparator(struct archive_entry *entry) -{ - struct archive_entry *entry_main; - const wchar_t *wp; - int has_backslash = 0; - int ret; - - wp = archive_entry_pathname_w(entry); - if (wp != NULL && wcschr(wp, L'\\') != NULL) - has_backslash = 1; - if (!has_backslash) { - wp = archive_entry_hardlink_w(entry); - if (wp != NULL && wcschr(wp, L'\\') != NULL) - has_backslash = 1; - } - if (!has_backslash) { - wp = archive_entry_symlink_w(entry); - if (wp != NULL && wcschr(wp, L'\\') != NULL) - has_backslash = 1; - } - /* - * If there is no backslash chars, return the original. - */ - if (!has_backslash) - return (entry); - - /* Copy entry so we can modify it as needed. */ - entry_main = archive_entry_clone(entry); - if (entry_main == NULL) - return (NULL); - /* Replace the Windows path-separator '\' with '/'. */ - ret = fix_pathseparator(entry_main); - if (ret < ARCHIVE_WARN) { - archive_entry_free(entry_main); - return (NULL); - } - return (entry_main); -} - - -/* - * The following function was modified from PostgreSQL sources and is - * subject to the copyright below. - */ -/*------------------------------------------------------------------------- - * - * win32error.c - * Map win32 error codes to errno values - * - * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group - * - * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -/* -PostgreSQL Database Management System -(formerly known as Postgres, then as Postgres95) - -Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group - -Portions Copyright (c) 1994, The Regents of the University of California - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose, without fee, and without a written agreement -is hereby granted, provided that the above copyright notice and this -paragraph and the following two paragraphs appear in all copies. - -IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR -DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING -LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS -DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS -ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO -PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -*/ - -static const struct { - DWORD winerr; - int doserr; -} doserrors[] = -{ - { ERROR_INVALID_FUNCTION, EINVAL }, - { ERROR_FILE_NOT_FOUND, ENOENT }, - { ERROR_PATH_NOT_FOUND, ENOENT }, - { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, - { ERROR_ACCESS_DENIED, EACCES }, - { ERROR_INVALID_HANDLE, EBADF }, - { ERROR_ARENA_TRASHED, ENOMEM }, - { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, - { ERROR_INVALID_BLOCK, ENOMEM }, - { ERROR_BAD_ENVIRONMENT, E2BIG }, - { ERROR_BAD_FORMAT, ENOEXEC }, - { ERROR_INVALID_ACCESS, EINVAL }, - { ERROR_INVALID_DATA, EINVAL }, - { ERROR_INVALID_DRIVE, ENOENT }, - { ERROR_CURRENT_DIRECTORY, EACCES }, - { ERROR_NOT_SAME_DEVICE, EXDEV }, - { ERROR_NO_MORE_FILES, ENOENT }, - { ERROR_LOCK_VIOLATION, EACCES }, - { ERROR_SHARING_VIOLATION, EACCES }, - { ERROR_BAD_NETPATH, ENOENT }, - { ERROR_NETWORK_ACCESS_DENIED, EACCES }, - { ERROR_BAD_NET_NAME, ENOENT }, - { ERROR_FILE_EXISTS, EEXIST }, - { ERROR_CANNOT_MAKE, EACCES }, - { ERROR_FAIL_I24, EACCES }, - { ERROR_INVALID_PARAMETER, EINVAL }, - { ERROR_NO_PROC_SLOTS, EAGAIN }, - { ERROR_DRIVE_LOCKED, EACCES }, - { ERROR_BROKEN_PIPE, EPIPE }, - { ERROR_DISK_FULL, ENOSPC }, - { ERROR_INVALID_TARGET_HANDLE, EBADF }, - { ERROR_INVALID_HANDLE, EINVAL }, - { ERROR_WAIT_NO_CHILDREN, ECHILD }, - { ERROR_CHILD_NOT_COMPLETE, ECHILD }, - { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, - { ERROR_NEGATIVE_SEEK, EINVAL }, - { ERROR_SEEK_ON_DEVICE, EACCES }, - { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, - { ERROR_NOT_LOCKED, EACCES }, - { ERROR_BAD_PATHNAME, ENOENT }, - { ERROR_MAX_THRDS_REACHED, EAGAIN }, - { ERROR_LOCK_FAILED, EACCES }, - { ERROR_ALREADY_EXISTS, EEXIST }, - { ERROR_FILENAME_EXCED_RANGE, ENOENT }, - { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, - { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } -}; - -void -__la_dosmaperr(unsigned long e) -{ - int i; - - if (e == 0) - { - errno = 0; - return; - } - - for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++) - { - if (doserrors[i].winerr == e) - { - errno = doserrors[i].doserr; - return; - } - } - - /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */ - errno = EINVAL; - return; -} - -#endif /* _WIN32 && !__CYGWIN__ */ diff --git a/3rdparty/libarchive/libarchive/archive_windows.h b/3rdparty/libarchive/libarchive/archive_windows.h deleted file mode 100644 index e77cd08f..00000000 --- a/3rdparty/libarchive/libarchive/archive_windows.h +++ /dev/null @@ -1,318 +0,0 @@ -/*- - * Copyright (c) 2009-2011 Michihiro NAKAJIMA - * Copyright (c) 2003-2006 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -/* - * TODO: A lot of stuff in here isn't actually used by libarchive and - * can be trimmed out. Note that this file is used by libarchive and - * libarchive_test but nowhere else. (But note that it gets compiled - * with many different Windows environments, including MinGW, Visual - * Studio, and Cygwin. Significant changes should be tested in all three.) - */ - -/* - * TODO: Don't use off_t in here. Use __int64 instead. Note that - * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's - * more modern file handling APIs all use __int64 instead of off_t. - */ - -#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED -#define LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED - -/* Start of configuration for native Win32 */ -#ifndef MINGW_HAS_SECURE_API -#define MINGW_HAS_SECURE_API 1 -#endif - -#include -#define set_errno(val) ((errno)=val) -#include -#include //brings in NULL -#if defined(HAVE_STDINT_H) -#include -#endif -#include -#include -#include -#include -#include -#if defined(__MINGW32__) && defined(HAVE_UNISTD_H) -/* Prevent build error from a type mismatch of ftruncate(). - * This unistd.h defines it as ftruncate(int, off_t). */ -#include -#endif -#define NOCRYPT -#include -//#define EFTYPE 7 - -#if defined(__BORLANDC__) -#pragma warn -8068 /* Constant out of range in comparison. */ -#pragma warn -8072 /* Suspicious pointer arithmetic. */ -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -/* Alias the Windows _function to the POSIX equivalent. */ -#define close _close -#define fcntl(fd, cmd, flg) /* No operation. */ -#ifndef fileno -#define fileno _fileno -#endif -#ifdef fstat -#undef fstat -#endif -#define fstat __la_fstat -#if !defined(__BORLANDC__) -#ifdef lseek -#undef lseek -#endif -#define lseek _lseeki64 -#else -#define lseek __la_lseek -#define __LA_LSEEK_NEEDED -#endif -#define lstat __la_stat -#define open __la_open -#define read __la_read -#if !defined(__BORLANDC__) && !defined(__WATCOMC__) -#define setmode _setmode -#endif -#ifdef stat -#undef stat -#endif -#define stat(path,stref) __la_stat(path,stref) -#if !defined(__WATCOMC__) -#if !defined(__BORLANDC__) -#define strdup _strdup -#endif -#define tzset _tzset -#if !defined(__BORLANDC__) -#define umask _umask -#endif -#endif -#define waitpid __la_waitpid -#define write __la_write - -#if !defined(__WATCOMC__) - -#ifndef O_RDONLY -#define O_RDONLY _O_RDONLY -#define O_WRONLY _O_WRONLY -#define O_TRUNC _O_TRUNC -#define O_CREAT _O_CREAT -#define O_EXCL _O_EXCL -#define O_BINARY _O_BINARY -#endif - -#ifndef _S_IFIFO - #define _S_IFIFO 0010000 /* pipe */ -#endif -#ifndef _S_IFCHR - #define _S_IFCHR 0020000 /* character special */ -#endif -#ifndef _S_IFDIR - #define _S_IFDIR 0040000 /* directory */ -#endif -#ifndef _S_IFBLK - #define _S_IFBLK 0060000 /* block special */ -#endif -#ifndef _S_IFLNK - #define _S_IFLNK 0120000 /* symbolic link */ -#endif -#ifndef _S_IFSOCK - #define _S_IFSOCK 0140000 /* socket */ -#endif -#ifndef _S_IFREG - #define _S_IFREG 0100000 /* regular */ -#endif -#ifndef _S_IFMT - #define _S_IFMT 0170000 /* file type mask */ -#endif - -#ifndef S_IFIFO -#define S_IFIFO _S_IFIFO -#endif -//#define S_IFCHR _S_IFCHR -//#define S_IFDIR _S_IFDIR -#ifndef S_IFBLK -#define S_IFBLK _S_IFBLK -#endif -#ifndef S_IFLNK -#define S_IFLNK _S_IFLNK -#endif -#ifndef S_IFSOCK -#define S_IFSOCK _S_IFSOCK -#endif -//#define S_IFREG _S_IFREG -//#define S_IFMT _S_IFMT - -#ifndef S_ISBLK -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */ -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */ -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */ -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */ -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */ -#endif -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */ -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */ - -#define _S_ISUID 0004000 /* set user id on execution */ -#define _S_ISGID 0002000 /* set group id on execution */ -#define _S_ISVTX 0001000 /* save swapped text even after use */ - -#define S_ISUID _S_ISUID -#define S_ISGID _S_ISGID -#define S_ISVTX _S_ISVTX - -#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) -#define _S_IXUSR _S_IEXEC /* read permission, user */ -#define _S_IWUSR _S_IWRITE /* write permission, user */ -#define _S_IRUSR _S_IREAD /* execute/search permission, user */ -#define _S_IRWXG (_S_IRWXU >> 3) -#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */ -#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */ -#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */ -#define _S_IRWXO (_S_IRWXG >> 3) -#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */ -#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */ -#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */ - -#ifndef S_IRWXU -#define S_IRWXU _S_IRWXU -#define S_IXUSR _S_IXUSR -#define S_IWUSR _S_IWUSR -#define S_IRUSR _S_IRUSR -#endif -#ifndef S_IRWXG -#define S_IRWXG _S_IRWXG -#define S_IXGRP _S_IXGRP -#define S_IWGRP _S_IWGRP -#endif -#ifndef S_IRGRP -#define S_IRGRP _S_IRGRP -#endif -#ifndef S_IRWXO -#define S_IRWXO _S_IRWXO -#define S_IXOTH _S_IXOTH -#define S_IWOTH _S_IWOTH -#define S_IROTH _S_IROTH -#endif - -#endif - -#define F_DUPFD 0 /* Duplicate file descriptor. */ -#define F_GETFD 1 /* Get file descriptor flags. */ -#define F_SETFD 2 /* Set file descriptor flags. */ -#define F_GETFL 3 /* Get file status flags. */ -#define F_SETFL 4 /* Set file status flags. */ -#define F_GETOWN 5 /* Get owner (receiver of SIGIO). */ -#define F_SETOWN 6 /* Set owner (receiver of SIGIO). */ -#define F_GETLK 7 /* Get record locking info. */ -#define F_SETLK 8 /* Set record locking info (non-blocking). */ -#define F_SETLKW 9 /* Set record locking info (blocking). */ - -/* XXX missing */ -#define F_GETLK64 7 /* Get record locking info. */ -#define F_SETLK64 8 /* Set record locking info (non-blocking). */ -#define F_SETLKW64 9 /* Set record locking info (blocking). */ - -/* File descriptor flags used with F_GETFD and F_SETFD. */ -#define FD_CLOEXEC 1 /* Close on exec. */ - -//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else... -#define O_NONBLOCK 0x0004 /* Non-blocking I/O. */ -//#define O_NDELAY O_NONBLOCK - -/* Symbolic constants for the access() function */ -#if !defined(F_OK) - #define R_OK 4 /* Test for read permission */ - #define W_OK 2 /* Test for write permission */ - #define X_OK 1 /* Test for execute permission */ - #define F_OK 0 /* Test for existence of file */ -#endif - - -/* Replacement POSIX function */ -extern int __la_fstat(int fd, struct stat *st); -extern int __la_lstat(const char *path, struct stat *st); -#if defined(__LA_LSEEK_NEEDED) -extern __int64 __la_lseek(int fd, __int64 offset, int whence); -#endif -extern int __la_open(const char *path, int flags, ...); -extern ssize_t __la_read(int fd, void *buf, size_t nbytes); -extern int __la_stat(const char *path, struct stat *st); -extern pid_t __la_waitpid(HANDLE child, int *status, int option); -extern ssize_t __la_write(int fd, const void *buf, size_t nbytes); - -#define _stat64i32(path, st) __la_stat(path, st) -#define _stat64(path, st) __la_stat(path, st) -/* for status returned by la_waitpid */ -#define WIFEXITED(sts) ((sts & 0x100) == 0) -#define WEXITSTATUS(sts) (sts & 0x0FF) - -extern wchar_t *__la_win_permissive_name(const char *name); -extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname); -extern void __la_dosmaperr(unsigned long e); -#define la_dosmaperr(e) __la_dosmaperr(e) -extern struct archive_entry *__la_win_entry_in_posix_pathseparator( - struct archive_entry *); - -#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__) -typedef int mbstate_t; -size_t wcrtomb(char *, wchar_t, mbstate_t *); -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1300 -WINBASEAPI BOOL WINAPI GetVolumePathNameW( - LPCWSTR lpszFileName, - LPWSTR lpszVolumePathName, - DWORD cchBufferLength - ); -# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */ -typedef struct _FILE_ALLOCATED_RANGE_BUFFER { - LARGE_INTEGER FileOffset; - LARGE_INTEGER Length; -} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER; -# define FSCTL_SET_SPARSE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA) -# define FSCTL_QUERY_ALLOCATED_RANGES \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA) -# endif -#endif - -#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */ diff --git a/3rdparty/libarchive/libarchive/archive_write.c b/3rdparty/libarchive/libarchive/archive_write.c deleted file mode 100644 index 0634a229..00000000 --- a/3rdparty/libarchive/libarchive/archive_write.c +++ /dev/null @@ -1,734 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03:00Z kientzle $"); - -/* - * This file contains the "essential" portions of the write API, that - * is, stuff that will essentially always be used by any client that - * actually needs to write an archive. Optional pieces have been, as - * far as possible, separated out into separate files to reduce - * needlessly bloating statically-linked clients. - */ - -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_write_private.h" - -static struct archive_vtable *archive_write_vtable(void); - -static int _archive_filter_code(struct archive *, int); -static const char *_archive_filter_name(struct archive *, int); -static int64_t _archive_filter_bytes(struct archive *, int); -static int _archive_write_filter_count(struct archive *); -static int _archive_write_close(struct archive *); -static int _archive_write_free(struct archive *); -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 { - size_t buffer_size; - size_t avail; - char *buffer; - char *next; -}; - -static struct archive_vtable * -archive_write_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_close; - av.archive_filter_bytes = _archive_filter_bytes; - av.archive_filter_code = _archive_filter_code; - av.archive_filter_name = _archive_filter_name; - av.archive_filter_count = _archive_write_filter_count; - av.archive_free = _archive_write_free; - av.archive_write_header = _archive_write_header; - av.archive_write_finish_entry = _archive_write_finish_entry; - av.archive_write_data = _archive_write_data; - inited = 1; - } - return (&av); -} - -/* - * Allocate, initialize and return an archive object. - */ -struct archive * -archive_write_new(void) -{ - struct archive_write *a; - unsigned char *nulls; - - a = (struct archive_write *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_WRITE_MAGIC; - a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_write_vtable(); - /* - * The value 10240 here matches the traditional tar default, - * but is otherwise arbitrary. - * TODO: Set the default block size from the format selected. - */ - a->bytes_per_block = 10240; - a->bytes_in_last_block = -1; /* Default */ - - /* Initialize a block of nulls for padding purposes. */ - a->null_length = 1024; - nulls = (unsigned char *)calloc(1, a->null_length); - if (nulls == NULL) { - free(a); - return (NULL); - } - a->nulls = nulls; - return (&a->archive); -} - -/* - * Set the block size. Returns 0 if successful. - */ -int -archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block) -{ - struct archive_write *a = (struct archive_write *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block"); - a->bytes_per_block = bytes_per_block; - return (ARCHIVE_OK); -} - -/* - * Get the current block size. -1 if it has never been set. - */ -int -archive_write_get_bytes_per_block(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block"); - return (a->bytes_per_block); -} - -/* - * Set the size for the last block. - * Returns 0 if successful. - */ -int -archive_write_set_bytes_in_last_block(struct archive *_a, int bytes) -{ - struct archive_write *a = (struct archive_write *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block"); - a->bytes_in_last_block = bytes; - return (ARCHIVE_OK); -} - -/* - * Return the value set above. -1 indicates it has not been set. - */ -int -archive_write_get_bytes_in_last_block(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block"); - return (a->bytes_in_last_block); -} - -/* - * dev/ino of a file to be rejected. Used to prevent adding - * an archive to itself recursively. - */ -int -archive_write_set_skip_file(struct archive *_a, int64_t d, int64_t i) -{ - struct archive_write *a = (struct archive_write *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_set_skip_file"); - a->skip_file_set = 1; - a->skip_file_dev = d; - a->skip_file_ino = i; - return (ARCHIVE_OK); -} - -/* - * Allocate and return the next filter structure. - */ -struct archive_write_filter * -__archive_write_allocate_filter(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *f; - - f = calloc(1, sizeof(*f)); - f->archive = _a; - if (a->filter_first == NULL) - a->filter_first = f; - else - a->filter_last->next_filter = f; - a->filter_last = f; - return f; -} - -/* - * Write data to a particular filter. - */ -int -__archive_write_filter(struct archive_write_filter *f, - const void *buff, size_t length) -{ - int r; - if (length == 0) - return(ARCHIVE_OK); - if (f->write == NULL) - /* If unset, a fatal error has already occurred, so this filter - * didn't open. We cannot write anything. */ - return(ARCHIVE_FATAL); - r = (f->write)(f, buff, length); - f->bytes_written += length; - return (r); -} - -/* - * Open a filter. - */ -int -__archive_write_open_filter(struct archive_write_filter *f) -{ - if (f->open == NULL) - return (ARCHIVE_OK); - return (f->open)(f); -} - -/* - * Close a filter. - */ -int -__archive_write_close_filter(struct archive_write_filter *f) -{ - if (f->close != NULL) - return (f->close)(f); - if (f->next_filter != NULL) - return (__archive_write_close_filter(f->next_filter)); - return (ARCHIVE_OK); -} - -int -__archive_write_output(struct archive_write *a, const void *buff, size_t length) -{ - return (__archive_write_filter(a->filter_first, buff, length)); -} - -int -__archive_write_nulls(struct archive_write *a, size_t length) -{ - if (length == 0) - return (ARCHIVE_OK); - - while (length > 0) { - size_t to_write = length < a->null_length ? length : a->null_length; - int r = __archive_write_output(a, a->nulls, to_write); - if (r < ARCHIVE_OK) - return (r); - length -= to_write; - } - return (ARCHIVE_OK); -} - -static int -archive_write_client_open(struct archive_write_filter *f) -{ - struct archive_write *a = (struct archive_write *)f->archive; - struct archive_none *state; - void *buffer; - size_t buffer_size; - - f->bytes_per_block = archive_write_get_bytes_per_block(f->archive); - f->bytes_in_last_block = - archive_write_get_bytes_in_last_block(f->archive); - buffer_size = f->bytes_per_block; - - state = (struct archive_none *)calloc(1, sizeof(*state)); - buffer = (char *)malloc(buffer_size); - if (state == NULL || buffer == NULL) { - free(state); - 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; - - if (a->client_opener == NULL) - return (ARCHIVE_OK); - return (a->client_opener(f->archive, a->client_data)); -} - -static int -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; - const char *buff = (const char *)_buff; - ssize_t remaining, to_copy; - ssize_t bytes_written; - - remaining = length; - - /* - * If there is no buffer for blocking, just pass the data - * straight through to the client write callback. In - * particular, this supports "no write delay" operation for - * special applications. Just set the block size to zero. - */ - if (state->buffer_size == 0) { - while (remaining > 0) { - bytes_written = (a->client_writer)(&a->archive, - a->client_data, buff, remaining); - if (bytes_written <= 0) - return (ARCHIVE_FATAL); - remaining -= bytes_written; - buff += bytes_written; - } - return (ARCHIVE_OK); - } - - /* If the copy buffer isn't empty, try to fill it. */ - if (state->avail < state->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; - 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; - while (to_write > 0) { - bytes_written = (a->client_writer)(&a->archive, - a->client_data, p, to_write); - if (bytes_written <= 0) - return (ARCHIVE_FATAL); - if ((size_t)bytes_written > to_write) { - archive_set_error(&(a->archive), - -1, "write overrun"); - return (ARCHIVE_FATAL); - } - p += bytes_written; - to_write -= bytes_written; - } - state->next = state->buffer; - state->avail = state->buffer_size; - } - } - - while ((size_t)remaining >= state->buffer_size) { - /* Write out full blocks directly to client. */ - bytes_written = (a->client_writer)(&a->archive, - a->client_data, buff, state->buffer_size); - if (bytes_written <= 0) - return (ARCHIVE_FATAL); - buff += bytes_written; - remaining -= bytes_written; - } - - if (remaining > 0) { - /* Copy last bit into copy buffer. */ - memcpy(state->next, buff, remaining); - state->next += remaining; - state->avail -= remaining; - } - return (ARCHIVE_OK); -} - -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; - ssize_t block_length; - ssize_t target_block_length; - ssize_t bytes_written; - 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; - - /* Tricky calculation to determine size of last block */ - if (a->bytes_in_last_block <= 0) - /* Default or Zero: pad to full block */ - target_block_length = a->bytes_per_block; - else - /* Round to next multiple of bytes_in_last_block. */ - target_block_length = a->bytes_in_last_block * - ( (block_length + a->bytes_in_last_block - 1) / - a->bytes_in_last_block); - 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, - target_block_length - block_length); - block_length = target_block_length; - } - bytes_written = (a->client_writer)(&a->archive, - a->client_data, state->buffer, block_length); - ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK; - } - if (a->client_closer) - (*a->client_closer)(&a->archive, a->client_data); - free(state->buffer); - free(state); - /* Clear the close handler myself not to be called again. */ - f->close = NULL; - a->client_data = NULL; - /* Clear passphrase. */ - if (a->passphrase != NULL) { - memset(a->passphrase, 0, strlen(a->passphrase)); - free(a->passphrase); - a->passphrase = NULL; - } - return (ret); -} - -/* - * Open the archive using the current settings. - */ -int -archive_write_open(struct archive *_a, void *client_data, - archive_open_callback *opener, archive_write_callback *writer, - archive_close_callback *closer) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *client_filter; - int ret, r1; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW, "archive_write_open"); - archive_clear_error(&a->archive); - - a->client_writer = writer; - a->client_opener = opener; - a->client_closer = closer; - a->client_data = client_data; - - client_filter = __archive_write_allocate_filter(_a); - client_filter->open = archive_write_client_open; - client_filter->write = archive_write_client_write; - client_filter->close = archive_write_client_close; - - ret = __archive_write_open_filter(a->filter_first); - if (ret < ARCHIVE_WARN) { - r1 = __archive_write_close_filter(a->filter_first); - return (r1 < ret ? r1 : ret); - } - - a->archive.state = ARCHIVE_STATE_HEADER; - if (a->format_init) - ret = (a->format_init)(a); - return (ret); -} - -/* - * Close out the archive. - */ -static int -_archive_write_close(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - int r = ARCHIVE_OK, r1 = ARCHIVE_OK; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, - "archive_write_close"); - if (a->archive.state == ARCHIVE_STATE_NEW - || a->archive.state == ARCHIVE_STATE_CLOSED) - return (ARCHIVE_OK); /* Okay to close() when not open. */ - - archive_clear_error(&a->archive); - - /* Finish the last entry if a finish callback is specified */ - if (a->archive.state == ARCHIVE_STATE_DATA - && a->format_finish_entry != NULL) - r = ((a->format_finish_entry)(a)); - - /* Finish off the archive. */ - /* TODO: have format closers invoke compression close. */ - if (a->format_close != NULL) { - r1 = (a->format_close)(a); - if (r1 < r) - r = r1; - } - - /* Finish the compression and close the stream. */ - r1 = __archive_write_close_filter(a->filter_first); - if (r1 < r) - r = r1; - - if (a->archive.state != ARCHIVE_STATE_FATAL) - a->archive.state = ARCHIVE_STATE_CLOSED; - return (r); -} - -static int -_archive_write_filter_count(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *p = a->filter_first; - int count = 0; - while(p) { - count++; - p = p->next_filter; - } - return count; -} - -void -__archive_write_filters_free(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - int r = ARCHIVE_OK, r1; - - while (a->filter_first != NULL) { - struct archive_write_filter *next - = a->filter_first->next_filter; - if (a->filter_first->free != NULL) { - r1 = (*a->filter_first->free)(a->filter_first); - if (r > r1) - r = r1; - } - free(a->filter_first); - a->filter_first = next; - } - a->filter_last = NULL; -} - -/* - * Destroy the archive structure. - * - * Be careful: user might just call write_new and then write_free. - * Don't assume we actually wrote anything or performed any non-trivial - * initialization. - */ -static int -_archive_write_free(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - int r = ARCHIVE_OK, r1; - - if (_a == NULL) - return (ARCHIVE_OK); - /* It is okay to call free() in state FATAL. */ - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_free"); - if (a->archive.state != ARCHIVE_STATE_FATAL) - r = archive_write_close(&a->archive); - - /* Release format resources. */ - if (a->format_free != NULL) { - r1 = (a->format_free)(a); - if (r1 < r) - r = r1; - } - - __archive_write_filters_free(_a); - - /* Release various dynamic buffers. */ - free((void *)(uintptr_t)(const void *)a->nulls); - archive_string_free(&a->archive.error_string); - if (a->passphrase != NULL) { - /* A passphrase should be cleaned. */ - memset(a->passphrase, 0, strlen(a->passphrase)); - free(a->passphrase); - } - a->archive.magic = 0; - __archive_clean(&a->archive); - free(a); - return (r); -} - -/* - * Write the appropriate header. - */ -static int -_archive_write_header(struct archive *_a, struct archive_entry *entry) -{ - struct archive_write *a = (struct archive_write *)_a; - int ret, r2; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header"); - archive_clear_error(&a->archive); - - if (a->format_write_header == NULL) { - archive_set_error(&(a->archive), -1, - "Format must be set before you can write to an archive."); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - - /* In particular, "retry" and "fatal" get returned immediately. */ - ret = archive_write_finish_entry(&a->archive); - if (ret == ARCHIVE_FATAL) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN) - return (ret); - - if (a->skip_file_set && - archive_entry_dev_is_set(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, - "Can't add archive to itself"); - return (ARCHIVE_FAILED); - } - - /* Format and write header. */ - r2 = ((a->format_write_header)(a, entry)); - if (r2 == ARCHIVE_FAILED) { - return (ARCHIVE_FAILED); - } - if (r2 == ARCHIVE_FATAL) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); - } - if (r2 < ret) - ret = r2; - - a->archive.state = ARCHIVE_STATE_DATA; - return (ret); -} - -static int -_archive_write_finish_entry(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - int ret = ARCHIVE_OK; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_finish_entry"); - if (a->archive.state & ARCHIVE_STATE_DATA - && a->format_finish_entry != NULL) - ret = (a->format_finish_entry)(a); - a->archive.state = ARCHIVE_STATE_HEADER; - return (ret); -} - -/* - * Note that the compressor is responsible for blocking. - */ -static ssize_t -_archive_write_data(struct archive *_a, const void *buff, size_t s) -{ - struct archive_write *a = (struct archive_write *)_a; - const size_t max_write = INT_MAX; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_DATA, "archive_write_data"); - /* In particular, this catches attempts to pass negative values. */ - if (s > max_write) - s = max_write; - archive_clear_error(&a->archive); - return ((a->format_write_data)(a, buff, s)); -} - -static struct archive_write_filter * -filter_lookup(struct archive *_a, int n) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *f = a->filter_first; - if (n == -1) - return a->filter_last; - if (n < 0) - return NULL; - while (n > 0 && f != NULL) { - f = f->next_filter; - --n; - } - return f; -} - -static int -_archive_filter_code(struct archive *_a, int n) -{ - struct archive_write_filter *f = filter_lookup(_a, n); - return f == NULL ? -1 : f->code; -} - -static const char * -_archive_filter_name(struct archive *_a, int n) -{ - struct archive_write_filter *f = filter_lookup(_a, n); - return f != NULL ? f->name : NULL; -} - -static int64_t -_archive_filter_bytes(struct archive *_a, int n) -{ - struct archive_write_filter *f = filter_lookup(_a, n); - return f == NULL ? -1 : f->bytes_written; -} diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter.c b/3rdparty/libarchive/libarchive/archive_write_add_filter.c deleted file mode 100644 index 08f518ad..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter.c +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * Copyright (c) 2012 Ondrej Holy - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" - -/* A table that maps filter codes to functions. */ -static const -struct { int code; int (*setter)(struct archive *); } codes[] = -{ - { ARCHIVE_FILTER_NONE, archive_write_add_filter_none }, - { ARCHIVE_FILTER_GZIP, archive_write_add_filter_gzip }, - { ARCHIVE_FILTER_BZIP2, archive_write_add_filter_bzip2 }, - { ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress }, - { ARCHIVE_FILTER_GRZIP, archive_write_add_filter_grzip }, - { ARCHIVE_FILTER_LRZIP, archive_write_add_filter_lrzip }, - { ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 }, - { ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip }, - { ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma }, - { ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip }, - { ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode }, - { ARCHIVE_FILTER_XZ, archive_write_add_filter_xz }, - { -1, NULL } -}; - -int -archive_write_add_filter(struct archive *a, int code) -{ - int i; - - for (i = 0; codes[i].code != -1; i++) { - if (code == codes[i].code) - return ((codes[i].setter)(a)); - } - - archive_set_error(a, EINVAL, "No such filter"); - return (ARCHIVE_FATAL); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c deleted file mode 100644 index 85eb087b..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c +++ /dev/null @@ -1,314 +0,0 @@ -/*- - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" -#include "archive_write_private.h" - -#define LBYTES 57 - -struct private_b64encode { - int mode; - struct archive_string name; - struct archive_string encoded_buff; - size_t bs; - size_t hold_len; - unsigned char hold[LBYTES]; -}; - -static int archive_filter_b64encode_options(struct archive_write_filter *, - const char *, const char *); -static int archive_filter_b64encode_open(struct archive_write_filter *); -static int archive_filter_b64encode_write(struct archive_write_filter *, - const void *, size_t); -static int archive_filter_b64encode_close(struct archive_write_filter *); -static int archive_filter_b64encode_free(struct archive_write_filter *); -static void b64_encode(struct archive_string *, const unsigned char *, size_t); -static int64_t atol8(const char *, size_t); - -static const char base64[] = { - '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', '+', '/' -}; - -/* - * Add a compress filter to this write handle. - */ -int -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; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW, "archive_write_add_filter_uu"); - - state = (struct private_b64encode *)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; - - f->data = state; - f->name = "b64encode"; - f->code = ARCHIVE_FILTER_UU; - f->open = archive_filter_b64encode_open; - f->options = archive_filter_b64encode_options; - f->write = archive_filter_b64encode_write; - f->close = archive_filter_b64encode_close; - f->free = archive_filter_b64encode_free; - - return (ARCHIVE_OK); -} - -/* - * Set write options. - */ -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; - - if (strcmp(key, "mode") == 0) { - if (value == NULL) { - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "mode option requires octal digits"); - return (ARCHIVE_FAILED); - } - state->mode = (int)atol8(value, strlen(value)) & 0777; - return (ARCHIVE_OK); - } else if (strcmp(key, "name") == 0) { - if (value == NULL) { - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "name option requires a string"); - return (ARCHIVE_FAILED); - } - archive_strcpy(&state->name, value); - return (ARCHIVE_OK); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -/* - * Setup callback. - */ -static int -archive_filter_b64encode_open(struct archive_write_filter *f) -{ - struct private_b64encode *state = (struct private_b64encode *)f->data; - size_t bs = 65536, bpb; - int ret; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != ARCHIVE_OK) - return (ret); - - if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { - /* Buffer size should be a multiple number of the of bytes - * per block for performance. */ - bpb = archive_write_get_bytes_per_block(f->archive); - if (bpb > bs) - bs = bpb; - else if (bpb != 0) - bs -= bs % bpb; - } - - state->bs = bs; - if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate data for b64encode buffer"); - return (ARCHIVE_FATAL); - } - - archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n", - state->mode, state->name.s); - - f->data = state; - return (0); -} - -static void -b64_encode(struct archive_string *as, const unsigned char *p, size_t len) -{ - int c; - - for (; len >= 3; p += 3, len -= 3) { - c = p[0] >> 2; - archive_strappend_char(as, base64[c]); - c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4); - archive_strappend_char(as, base64[c]); - c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6); - archive_strappend_char(as, base64[c]); - c = p[2] & 0x3f; - archive_strappend_char(as, base64[c]); - } - if (len > 0) { - c = p[0] >> 2; - archive_strappend_char(as, base64[c]); - c = (p[0] & 0x03) << 4; - if (len == 1) { - archive_strappend_char(as, base64[c]); - archive_strappend_char(as, '='); - archive_strappend_char(as, '='); - } else { - c |= (p[1] & 0xf0) >> 4; - archive_strappend_char(as, base64[c]); - c = (p[1] & 0x0f) << 2; - archive_strappend_char(as, base64[c]); - archive_strappend_char(as, '='); - } - } - archive_strappend_char(as, '\n'); -} - -/* - * Write data to the encoded stream. - */ -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; - const unsigned char *p = buff; - int ret = ARCHIVE_OK; - - if (length == 0) - return (ret); - - if (state->hold_len) { - while (state->hold_len < LBYTES && length > 0) { - state->hold[state->hold_len++] = *p++; - length--; - } - if (state->hold_len < LBYTES) - return (ret); - b64_encode(&state->encoded_buff, state->hold, LBYTES); - state->hold_len = 0; - } - - for (; length >= LBYTES; length -= LBYTES, p += LBYTES) - b64_encode(&state->encoded_buff, p, LBYTES); - - /* Save remaining bytes. */ - if (length > 0) { - memcpy(state->hold, p, length); - state->hold_len = length; - } - while (archive_strlen(&state->encoded_buff) >= state->bs) { - ret = __archive_write_filter(f->next_filter, - state->encoded_buff.s, state->bs); - memmove(state->encoded_buff.s, - state->encoded_buff.s + state->bs, - state->encoded_buff.length - state->bs); - state->encoded_buff.length -= state->bs; - } - - return (ret); -} - - -/* - * Finish the compression... - */ -static int -archive_filter_b64encode_close(struct archive_write_filter *f) -{ - struct private_b64encode *state = (struct private_b64encode *)f->data; - int ret, ret2; - - /* Flush remaining bytes. */ - if (state->hold_len != 0) - b64_encode(&state->encoded_buff, state->hold, state->hold_len); - archive_string_sprintf(&state->encoded_buff, "====\n"); - /* Write the last block */ - archive_write_set_bytes_in_last_block(f->archive, 1); - ret = __archive_write_filter(f->next_filter, - state->encoded_buff.s, archive_strlen(&state->encoded_buff)); - ret2 = __archive_write_close_filter(f->next_filter); - if (ret > ret2) - ret = ret2; - return (ret); -} - -static int -archive_filter_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); - return (ARCHIVE_OK); -} - -static int64_t -atol8(const char *p, size_t char_cnt) -{ - int64_t l; - int digit; - - l = 0; - while (char_cnt-- > 0) { - if (*p >= '0' && *p <= '7') - digit = *p - '0'; - else - break; - p++; - l <<= 3; - l |= digit; - } - return (l); -} - diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c deleted file mode 100644 index 85a8d475..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" - -/* A table that maps names to functions. */ -static const -struct { const char *name; int (*setter)(struct archive *); } names[] = -{ - { "b64encode", archive_write_add_filter_b64encode }, - { "bzip2", archive_write_add_filter_bzip2 }, - { "compress", archive_write_add_filter_compress }, - { "grzip", archive_write_add_filter_grzip }, - { "gzip", archive_write_add_filter_gzip }, - { "lrzip", archive_write_add_filter_lrzip }, - { "lz4", archive_write_add_filter_lz4 }, - { "lzip", archive_write_add_filter_lzip }, - { "lzma", archive_write_add_filter_lzma }, - { "lzop", archive_write_add_filter_lzop }, - { "uuencode", archive_write_add_filter_uuencode }, - { "xz", archive_write_add_filter_xz }, - { NULL, NULL } -}; - -int -archive_write_add_filter_by_name(struct archive *a, const char *name) -{ - int i; - - for (i = 0; names[i].name != NULL; i++) { - if (strcmp(name, names[i].name) == 0) - return ((names[i].setter)(a)); - } - - archive_set_error(a, EINVAL, "No such filter '%s'", name); - a->state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c deleted file mode 100644 index 68ed9579..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c +++ /dev/null @@ -1,407 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_BZLIB_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_write_private.h" - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_write_set_compression_bzip2(struct archive *a) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_bzip2(a)); -} -#endif - -struct private_data { - 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 - struct archive_write_program_data *pdata; -#endif -}; - -static int archive_compressor_bzip2_close(struct archive_write_filter *); -static int archive_compressor_bzip2_free(struct archive_write_filter *); -static int archive_compressor_bzip2_open(struct archive_write_filter *); -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); - -/* - * Add a bzip2 compression filter to this write handle. - */ -int -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; - - archive_check_magic(&a->archive, 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"; -#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) - return (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, - "Using external bzip2 program"); - return (ARCHIVE_WARN); -#endif -} - -/* - * Set write options. - */ -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; - - if (strcmp(key, "compression-level") == 0) { - if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || - value[1] != '\0') - return (ARCHIVE_WARN); - data->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; - return (ARCHIVE_OK); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) -/* Don't compile this if we don't have bzlib. */ - -/* - * Yuck. bzlib.h is not const-correct, so I need this one bit - * of ugly hackery to convert a const * pointer to a non-const pointer. - */ -#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); - -/* - * Setup callback. - */ -static int -archive_compressor_bzip2_open(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - int ret; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != 0) - return (ret); - - if (data->compressed == NULL) { - size_t bs = 65536, bpb; - if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { - /* Buffer size should be a multiple number of the of bytes - * per block for performance. */ - bpb = archive_write_get_bytes_per_block(f->archive); - if (bpb > bs) - bs = bpb; - else if (bpb != 0) - bs -= bs % bpb; - } - data->compressed_buffer_size = bs; - data->compressed - = (char *)malloc(data->compressed_buffer_size); - if (data->compressed == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate data for compression buffer"); - return (ARCHIVE_FATAL); - } - } - - memset(&data->stream, 0, sizeof(data->stream)); - data->stream.next_out = data->compressed; - data->stream.avail_out = data->compressed_buffer_size; - f->write = archive_compressor_bzip2_write; - - /* Initialize compression library */ - ret = BZ2_bzCompressInit(&(data->stream), - data->compression_level, 0, 30); - if (ret == BZ_OK) { - f->data = data; - return (ARCHIVE_OK); - } - - /* Library setup failed: clean up. */ - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library"); - - /* Override the error message if we know what really went wrong. */ - switch (ret) { - case BZ_PARAM_ERROR: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "invalid setup parameter"); - break; - case BZ_MEM_ERROR: - archive_set_error(f->archive, ENOMEM, - "Internal error initializing compression library: " - "out of memory"); - break; - case BZ_CONFIG_ERROR: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "mis-compiled library"); - break; - } - - return (ARCHIVE_FATAL); - -} - -/* - * Write data to the compressed stream. - * - * Returns ARCHIVE_OK if all data written, error otherwise. - */ -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; - - /* Compress input data to output buffer */ - SET_NEXT_IN(data, buff); - data->stream.avail_in = length; - if (drive_compressor(f, data, 0)) - return (ARCHIVE_FATAL); - return (ARCHIVE_OK); -} - - -/* - * Finish the compression. - */ -static int -archive_compressor_bzip2_close(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - int ret, r1; - - /* Finish compression cycle. */ - ret = drive_compressor(f, data, 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); - } - - switch (BZ2_bzCompressEnd(&(data->stream))) { - case BZ_OK: - break; - default: - archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Failed to clean up compressor"); - ret = ARCHIVE_FATAL; - } - - r1 = __archive_write_close_filter(f->next_filter); - return (r1 < ret ? r1 : ret); -} - -static int -archive_compressor_bzip2_free(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - 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. - * - * Note that this handles both the regular write case (finishing == - * false) and the end-of-archive case (finishing == true). - */ -static int -drive_compressor(struct archive_write_filter *f, - struct private_data *data, int finishing) -{ - int ret; - - for (;;) { - if (data->stream.avail_out == 0) { - ret = __archive_write_filter(f->next_filter, - data->compressed, - data->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 = data->compressed_buffer_size; - } - - /* If there's nothing to do, we're done. */ - if (!finishing && data->stream.avail_in == 0) - return (ARCHIVE_OK); - - ret = BZ2_bzCompress(&(data->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) - return (ARCHIVE_OK); - break; - case BZ_FINISH_OK: /* Finishing: There's more work to do */ - break; - case BZ_STREAM_END: /* Finishing: all done */ - /* Only occurs in finishing case */ - return (ARCHIVE_OK); - default: - /* Any other return value indicates an error */ - archive_set_error(f->archive, - ARCHIVE_ERRNO_PROGRAMMER, - "Bzip2 compression failed;" - " BZ2_bzCompress() returned %d", - ret); - return (ARCHIVE_FATAL); - } - } -} - -#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 archive_string as; - int r; - - archive_string_init(&as); - archive_strcpy(&as, "bzip2"); - - /* Specify compression level. */ - if (data->compression_level > 0) { - archive_strcat(&as, " -"); - archive_strappend_char(&as, '0' + data->compression_level); - } - f->write = archive_compressor_bzip2_write; - - r = __archive_write_program_open(f, data->pdata, as.s); - archive_string_free(&as); - return (r); -} - -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; - - return __archive_write_program_write(f, data->pdata, buff, length); -} - -static int -archive_compressor_bzip2_close(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - - return __archive_write_program_close(f, data->pdata); -} - -static int -archive_compressor_bzip2_free(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - - __archive_write_program_free(data->pdata); - free(data); - return (ARCHIVE_OK); -} - -#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */ diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c deleted file mode 100644 index 04eb06c1..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c +++ /dev/null @@ -1,442 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#include -#ifdef HAVE_ZLIB_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" -#include "archive_write_private.h" - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_write_set_compression_gzip(struct archive *a) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_gzip(a)); -} -#endif - -/* Don't compile this if we don't have zlib. */ - -struct private_data { - int compression_level; - int timestamp; -#ifdef HAVE_ZLIB_H - z_stream stream; - int64_t total_in; - unsigned char *compressed; - size_t compressed_buffer_size; - unsigned long crc; -#else - struct archive_write_program_data *pdata; -#endif -}; - -/* - * Yuck. zlib.h is not const-correct, so I need this one bit - * of ugly hackery to convert a const * pointer to a non-const pointer. - */ -#define SET_NEXT_IN(st,src) \ - (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src) - -static int archive_compressor_gzip_options(struct archive_write_filter *, - const char *, const char *); -static int archive_compressor_gzip_open(struct archive_write_filter *); -static int archive_compressor_gzip_write(struct archive_write_filter *, - const void *, size_t); -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); -#endif - - -/* - * Add a gzip compression filter to this write handle. - */ -int -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"); - - 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"; -#ifdef HAVE_ZLIB_H - data->compression_level = Z_DEFAULT_COMPRESSION; - return (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, - "Using external gzip program"); - return (ARCHIVE_WARN); -#endif -} - -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(data); - f->data = NULL; - return (ARCHIVE_OK); -} - -/* - * Set write options. - */ -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; - - if (strcmp(key, "compression-level") == 0) { - if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || - value[1] != '\0') - return (ARCHIVE_WARN); - data->compression_level = value[0] - '0'; - return (ARCHIVE_OK); - } - if (strcmp(key, "timestamp") == 0) { - data->timestamp = (value == NULL)?-1:1; - return (ARCHIVE_OK); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -#ifdef HAVE_ZLIB_H -/* - * Setup callback. - */ -static int -archive_compressor_gzip_open(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - int ret; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != ARCHIVE_OK) - return (ret); - - if (data->compressed == NULL) { - size_t bs = 65536, bpb; - if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { - /* Buffer size should be a multiple number of - * the of bytes per block for performance. */ - bpb = archive_write_get_bytes_per_block(f->archive); - if (bpb > bs) - bs = bpb; - else if (bpb != 0) - bs -= bs % bpb; - } - data->compressed_buffer_size = bs; - data->compressed - = (unsigned char *)malloc(data->compressed_buffer_size); - if (data->compressed == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate data for compression buffer"); - return (ARCHIVE_FATAL); - } - } - - data->crc = crc32(0L, NULL, 0); - data->stream.next_out = data->compressed; - data->stream.avail_out = (uInt)data->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] = 0; /* No options */ - 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; - } else - memset(&data->compressed[4], 0, 4); - data->compressed[8] = 0; /* No deflate options */ - data->compressed[9] = 3; /* OS=Unix */ - data->stream.next_out += 10; - data->stream.avail_out -= 10; - - f->write = archive_compressor_gzip_write; - - /* Initialize compression library. */ - ret = deflateInit2(&(data->stream), - data->compression_level, - Z_DEFLATED, - -15 /* < 0 to suppress zlib header */, - 8, - Z_DEFAULT_STRATEGY); - - if (ret == Z_OK) { - f->data = data; - return (ARCHIVE_OK); - } - - /* Library setup failed: clean up. */ - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error " - "initializing compression library"); - - /* Override the error message if we know what really went wrong. */ - switch (ret) { - case Z_STREAM_ERROR: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing " - "compression library: invalid setup parameter"); - break; - case Z_MEM_ERROR: - archive_set_error(f->archive, ENOMEM, - "Internal error initializing compression library"); - break; - case Z_VERSION_ERROR: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing " - "compression library: invalid library version"); - break; - } - - return (ARCHIVE_FATAL); -} - -/* - * Write data to the compressed stream. - */ -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; - int ret; - - /* Update statistics */ - data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length); - data->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) - return (ret); - - return (ARCHIVE_OK); -} - -/* - * Finish the compression... - */ -static int -archive_compressor_gzip_close(struct archive_write_filter *f) -{ - unsigned char trailer[8]; - struct private_data *data = (struct private_data *)f->data; - int ret, r1; - - /* Finish compression cycle */ - ret = drive_compressor(f, data, 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); - } - 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; - ret = __archive_write_filter(f->next_filter, trailer, 8); - } - - switch (deflateEnd(&(data->stream))) { - case Z_OK: - break; - default: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Failed to clean up compressor"); - ret = ARCHIVE_FATAL; - } - r1 = __archive_write_close_filter(f->next_filter); - return (r1 < ret ? r1 : ret); -} - -/* - * Utility function to push input data through compressor, - * writing full output blocks as necessary. - * - * Note that this handles both the regular write case (finishing == - * false) and the end-of-archive case (finishing == true). - */ -static int -drive_compressor(struct archive_write_filter *f, - struct private_data *data, int finishing) -{ - int ret; - - for (;;) { - if (data->stream.avail_out == 0) { - ret = __archive_write_filter(f->next_filter, - data->compressed, - data->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; - } - - /* If there's nothing to do, we're done. */ - if (!finishing && data->stream.avail_in == 0) - return (ARCHIVE_OK); - - ret = deflate(&(data->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) - return (ARCHIVE_OK); - /* In finishing case, this return always means - * there's more work */ - break; - case Z_STREAM_END: - /* This return can only occur in finishing case. */ - return (ARCHIVE_OK); - default: - /* Any other return value indicates an error. */ - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "GZip compression failed:" - " deflate() call returned status %d", - ret); - return (ARCHIVE_FATAL); - } - } -} - -#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 archive_string as; - int r; - - archive_string_init(&as); - archive_strcpy(&as, "gzip"); - - /* Specify compression level. */ - if (data->compression_level > 0) { - archive_strcat(&as, " -"); - archive_strappend_char(&as, '0' + data->compression_level); - } - if (data->timestamp < 0) - /* Do not save timestamp. */ - archive_strcat(&as, " -n"); - else if (data->timestamp > 0) - /* Save timestamp. */ - archive_strcat(&as, " -N"); - - f->write = archive_compressor_gzip_write; - r = __archive_write_program_open(f, data->pdata, as.s); - archive_string_free(&as); - return (r); -} - -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; - - return __archive_write_program_write(f, data->pdata, buff, length); -} - -static int -archive_compressor_gzip_close(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - - return __archive_write_program_close(f, data->pdata); -} - -#endif /* HAVE_ZLIB_H */ diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c deleted file mode 100644 index 3c06c642..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_none.c 201080 2009-12-28 02:03:54Z kientzle $"); - -#include "archive.h" - -int -archive_write_set_compression_none(struct archive *a) -{ - (void)a; /* UNUSED */ - return (ARCHIVE_OK); -} - -int -archive_write_add_filter_none(struct archive *a) -{ - (void)a; /* UNUSED */ - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c deleted file mode 100644 index 660f693f..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * Copyright (c) 2007 Joerg Sonnenberger - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $"); - -#ifdef HAVE_SYS_WAIT_H -# include -#endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" -#include "archive_write_private.h" -#include "filter_fork.h" - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_write_set_compression_program(struct archive *a, const char *cmd) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_program(a, cmd)); -} -#endif - -struct archive_write_program_data { -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE child; -#else - pid_t child; -#endif - int child_stdin, child_stdout; - - char *child_buf; - size_t child_buf_len, child_buf_avail; - char *program_name; -}; - -struct private_data { - struct archive_write_program_data *pdata; - struct archive_string description; - char *cmd; -}; - -static int archive_compressor_program_open(struct archive_write_filter *); -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 *); - -/* - * 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) -{ - struct archive_write_filter *f = __archive_write_allocate_filter(_a); - struct private_data *data; - static const char prefix[] = "Program: "; - - 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) - goto memerr; - data = (struct private_data *)f->data; - - data->cmd = strdup(cmd); - if (data->cmd == NULL) - goto memerr; - - data->pdata = __archive_write_program_allocate(cmd); - if (data->pdata == NULL) - goto memerr; - - /* Make up a description string. */ - if (archive_string_ensure(&data->description, - strlen(prefix) + strlen(cmd) + 1) == NULL) - goto memerr; - archive_strcpy(&data->description, prefix); - archive_strcat(&data->description, cmd); - - f->name = data->description.s; - f->code = ARCHIVE_FILTER_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, - "Can't allocate memory for filter program"); - return (ARCHIVE_FATAL); -} - -static int -archive_compressor_program_open(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - - return __archive_write_program_open(f, data->pdata, data->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; - - return __archive_write_program_write(f, data->pdata, buff, length); -} - -static int -archive_compressor_program_close(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - - return __archive_write_program_close(f, data->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; - } - return (ARCHIVE_OK); -} - -/* - * Allocate resources for executing an external program. - */ -struct archive_write_program_data * -__archive_write_program_allocate(const char *program) -{ - struct archive_write_program_data *data; - - data = calloc(1, sizeof(struct archive_write_program_data)); - if (data == NULL) - return (data); - data->child_stdin = -1; - data->child_stdout = -1; - data->program_name = strdup(program); - return (data); -} - -/* - * Release the resources. - */ -int -__archive_write_program_free(struct archive_write_program_data *data) -{ - - if (data) { -#if defined(_WIN32) && !defined(__CYGWIN__) - if (data->child) - CloseHandle(data->child); -#endif - free(data->program_name); - free(data->child_buf); - free(data); - } - return (ARCHIVE_OK); -} - -int -__archive_write_program_open(struct archive_write_filter *f, - struct archive_write_program_data *data, const char *cmd) -{ - pid_t child; - int ret; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != ARCHIVE_OK) - return (ret); - - if (data->child_buf == NULL) { - data->child_buf_len = 65536; - data->child_buf_avail = 0; - data->child_buf = malloc(data->child_buf_len); - - if (data->child_buf == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate compression buffer"); - return (ARCHIVE_FATAL); - } - } - - child = __archive_create_child(cmd, &data->child_stdin, - &data->child_stdout); - if (child == -1) { - archive_set_error(f->archive, EINVAL, - "Can't launch external program: %s", cmd); - return (ARCHIVE_FATAL); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child); - if (data->child == NULL) { - close(data->child_stdin); - data->child_stdin = -1; - close(data->child_stdout); - data->child_stdout = -1; - archive_set_error(f->archive, EINVAL, - "Can't launch external program: %s", cmd); - return (ARCHIVE_FATAL); - } -#else - data->child = child; -#endif - return (ARCHIVE_OK); -} - -static ssize_t -child_write(struct archive_write_filter *f, - struct archive_write_program_data *data, const char *buf, size_t buf_len) -{ - ssize_t ret; - - if (data->child_stdin == -1) - return (-1); - - if (buf_len == 0) - return (-1); - - for (;;) { - do { - ret = write(data->child_stdin, buf, buf_len); - } while (ret == -1 && errno == EINTR); - - if (ret > 0) - return (ret); - if (ret == 0) { - close(data->child_stdin); - data->child_stdin = -1; - fcntl(data->child_stdout, F_SETFL, 0); - return (0); - } - if (ret == -1 && errno != EAGAIN) - return (-1); - - if (data->child_stdout == -1) { - fcntl(data->child_stdin, F_SETFL, 0); - __archive_check_child(data->child_stdin, - data->child_stdout); - continue; - } - - do { - ret = read(data->child_stdout, - data->child_buf + data->child_buf_avail, - data->child_buf_len - data->child_buf_avail); - } while (ret == -1 && errno == EINTR); - - if (ret == 0 || (ret == -1 && errno == EPIPE)) { - close(data->child_stdout); - data->child_stdout = -1; - fcntl(data->child_stdin, F_SETFL, 0); - continue; - } - if (ret == -1 && errno == EAGAIN) { - __archive_check_child(data->child_stdin, - data->child_stdout); - continue; - } - if (ret == -1) - return (-1); - - data->child_buf_avail += ret; - - ret = __archive_write_filter(f->next_filter, - data->child_buf, data->child_buf_avail); - if (ret != ARCHIVE_OK) - return (-1); - data->child_buf_avail = 0; - } -} - -/* - * Write data to the filter stream. - */ -int -__archive_write_program_write(struct archive_write_filter *f, - struct archive_write_program_data *data, const void *buff, size_t length) -{ - ssize_t ret; - const char *buf; - - if (data->child == 0) - return (ARCHIVE_OK); - - buf = buff; - while (length > 0) { - ret = child_write(f, data, buf, length); - if (ret == -1 || ret == 0) { - archive_set_error(f->archive, EIO, - "Can't write to program: %s", data->program_name); - return (ARCHIVE_FATAL); - } - length -= ret; - buf += ret; - } - return (ARCHIVE_OK); -} - -/* - * Finish the filtering... - */ -int -__archive_write_program_close(struct archive_write_filter *f, - struct archive_write_program_data *data) -{ - int ret, r1, status; - ssize_t bytes_read; - - if (data->child == 0) - return __archive_write_close_filter(f->next_filter); - - ret = 0; - close(data->child_stdin); - data->child_stdin = -1; - fcntl(data->child_stdout, F_SETFL, 0); - - for (;;) { - do { - bytes_read = read(data->child_stdout, - data->child_buf + data->child_buf_avail, - data->child_buf_len - data->child_buf_avail); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE)) - break; - - if (bytes_read == -1) { - archive_set_error(f->archive, errno, - "Error reading from program: %s", data->program_name); - ret = ARCHIVE_FATAL; - goto cleanup; - } - data->child_buf_avail += bytes_read; - - ret = __archive_write_filter(f->next_filter, - data->child_buf, data->child_buf_avail); - if (ret != ARCHIVE_OK) { - ret = ARCHIVE_FATAL; - goto cleanup; - } - data->child_buf_avail = 0; - } - -cleanup: - /* Shut down the child. */ - if (data->child_stdin != -1) - close(data->child_stdin); - if (data->child_stdout != -1) - close(data->child_stdout); - while (waitpid(data->child, &status, 0) == -1 && errno == EINTR) - continue; -#if defined(_WIN32) && !defined(__CYGWIN__) - CloseHandle(data->child); -#endif - data->child = 0; - - if (status != 0) { - archive_set_error(f->archive, EIO, - "Error closing program: %s", data->program_name); - ret = ARCHIVE_FATAL; - } - r1 = __archive_write_close_filter(f->next_filter); - return (r1 < ret ? r1 : ret); -} - diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c deleted file mode 100644 index b0f25a6e..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c +++ /dev/null @@ -1,547 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * Copyright (c) 2009-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#include -#ifdef HAVE_LZMA_H -#include -#endif - -#include "archive.h" -#include "archive_endian.h" -#include "archive_private.h" -#include "archive_write_private.h" - -#if ARCHIVE_VERSION_NUMBER < 4000000 -int -archive_write_set_compression_lzip(struct archive *a) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_lzip(a)); -} - -int -archive_write_set_compression_lzma(struct archive *a) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_lzma(a)); -} - -int -archive_write_set_compression_xz(struct archive *a) -{ - __archive_write_filters_free(a); - return (archive_write_add_filter_xz(a)); -} - -#endif - -#ifndef HAVE_LZMA_H -int -archive_write_add_filter_xz(struct archive *a) -{ - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "xz compression not supported on this platform"); - return (ARCHIVE_FATAL); -} - -int -archive_write_add_filter_lzma(struct archive *a) -{ - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "lzma compression not supported on this platform"); - return (ARCHIVE_FATAL); -} - -int -archive_write_add_filter_lzip(struct archive *a) -{ - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "lzma compression not supported on this platform"); - return (ARCHIVE_FATAL); -} -#else -/* Don't compile this if we don't have liblzma. */ - -struct private_data { - int compression_level; - uint32_t threads; - lzma_stream stream; - lzma_filter lzmafilters[2]; - lzma_options_lzma lzma_opt; - int64_t total_in; - unsigned char *compressed; - size_t compressed_buffer_size; - int64_t total_out; - /* the CRC32 value of uncompressed data for lzip */ - uint32_t crc32; -}; - -static int archive_compressor_xz_options(struct archive_write_filter *, - const char *, const char *); -static int archive_compressor_xz_open(struct archive_write_filter *); -static int archive_compressor_xz_write(struct archive_write_filter *, - const void *, size_t); -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 option_value { - uint32_t dict_size; - uint32_t nice_len; - lzma_match_finder mf; -}; -static const struct option_value option_values[] = { - { 1 << 16, 32, LZMA_MF_HC3}, - { 1 << 20, 32, LZMA_MF_HC3}, - { 3 << 19, 32, LZMA_MF_HC4}, - { 1 << 21, 32, LZMA_MF_BT4}, - { 3 << 20, 32, LZMA_MF_BT4}, - { 1 << 22, 32, LZMA_MF_BT4}, - { 1 << 23, 64, LZMA_MF_BT4}, - { 1 << 24, 64, LZMA_MF_BT4}, - { 3 << 23, 64, LZMA_MF_BT4}, - { 1 << 25, 64, LZMA_MF_BT4} -}; - -static int -common_setup(struct archive_write_filter *f) -{ - 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; - f->close = archive_compressor_xz_close; - f->free = archive_compressor_xz_free; - f->options = &archive_compressor_xz_options; - return (ARCHIVE_OK); -} - -/* - * Add an xz compression filter to this write handle. - */ -int -archive_write_add_filter_xz(struct archive *_a) -{ - struct archive_write_filter *f; - int r; - - 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); -} - -/* 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) -{ - struct archive_write_filter *f; - int r; - - 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); -} - -int -archive_write_add_filter_lzip(struct archive *_a) -{ - struct archive_write_filter *f; - int r; - - 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); -} - -static int -archive_compressor_xz_init_stream(struct archive_write_filter *f, - struct private_data *data) -{ - static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT; - int ret; -#ifdef HAVE_LZMA_STREAM_ENCODER_MT - lzma_mt mt_options; -#endif - - data->stream = lzma_stream_init_data; - data->stream.next_out = data->compressed; - data->stream.avail_out = data->compressed_buffer_size; - if (f->code == ARCHIVE_FILTER_XZ) { -#ifdef HAVE_LZMA_STREAM_ENCODER_MT - if (data->threads != 1) { - memset(&mt_options, 0, sizeof(mt_options)); - mt_options.threads = data->threads; - mt_options.timeout = 300; - mt_options.filters = data->lzmafilters; - mt_options.check = LZMA_CHECK_CRC64; - ret = lzma_stream_encoder_mt(&(data->stream), - &mt_options); - } else -#endif - ret = lzma_stream_encoder(&(data->stream), - data->lzmafilters, LZMA_CHECK_CRC64); - } else if (f->code == ARCHIVE_FILTER_LZMA) { - ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt); - } else { /* ARCHIVE_FILTER_LZIP */ - int dict_size = data->lzma_opt.dict_size; - int ds, log2dic, wedges; - - /* Calculate a coded dictionary size */ - if (dict_size < (1 << 12) || dict_size > (1 << 27)) { - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Unacceptable dictionary size for lzip: %d", - dict_size); - return (ARCHIVE_FATAL); - } - for (log2dic = 27; log2dic >= 12; log2dic--) { - if (dict_size & (1 << log2dic)) - break; - } - if (dict_size > (1 << log2dic)) { - log2dic++; - wedges = - ((1 << log2dic) - dict_size) / (1 << (log2dic - 4)); - } else - wedges = 0; - ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f); - - data->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; - - ret = lzma_raw_encoder(&(data->stream), data->lzmafilters); - } - if (ret == LZMA_OK) - return (ARCHIVE_OK); - - switch (ret) { - case LZMA_MEM_ERROR: - archive_set_error(f->archive, ENOMEM, - "Internal error initializing compression library: " - "Cannot allocate memory"); - break; - default: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "It's a bug in liblzma"); - break; - } - return (ARCHIVE_FATAL); -} - -/* - * Setup callback. - */ -static int -archive_compressor_xz_open(struct archive_write_filter *f) -{ - struct private_data *data = f->data; - int ret; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != ARCHIVE_OK) - return (ret); - - if (data->compressed == NULL) { - size_t bs = 65536, bpb; - if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { - /* Buffer size should be a multiple number of the of bytes - * per block for performance. */ - bpb = archive_write_get_bytes_per_block(f->archive); - if (bpb > bs) - bs = bpb; - else if (bpb != 0) - bs -= bs % bpb; - } - data->compressed_buffer_size = bs; - data->compressed - = (unsigned char *)malloc(data->compressed_buffer_size); - if (data->compressed == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate data for compression buffer"); - return (ARCHIVE_FATAL); - } - } - - 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]; - - 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 */ - } else { - if (lzma_lzma_preset(&data->lzma_opt, data->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 */ - } - ret = archive_compressor_xz_init_stream(f, data); - if (ret == LZMA_OK) { - f->data = data; - return (0); - } - return (ARCHIVE_FATAL); -} - -/* - * Set write options. - */ -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; - - if (strcmp(key, "compression-level") == 0) { - if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || - value[1] != '\0') - return (ARCHIVE_WARN); - data->compression_level = value[0] - '0'; - if (data->compression_level > 6) - data->compression_level = 6; - return (ARCHIVE_OK); - } else if (strcmp(key, "threads") == 0) { - if (value == NULL) - return (ARCHIVE_WARN); - data->threads = (int)strtoul(value, NULL, 10); - if (data->threads == 0 && errno != 0) { - data->threads = 1; - return (ARCHIVE_WARN); - } - if (data->threads == 0) { -#ifdef HAVE_LZMA_STREAM_ENCODER_MT - data->threads = lzma_cputhreads(); -#else - data->threads = 1; -#endif - } - return (ARCHIVE_OK); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -/* - * Write data to the compressed stream. - */ -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; - int ret; - - /* Update statistics */ - data->total_in += length; - if (f->code == ARCHIVE_FILTER_LZIP) - data->crc32 = lzma_crc32(buff, length, data->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) - return (ret); - - return (ARCHIVE_OK); -} - - -/* - * Finish the compression... - */ -static int -archive_compressor_xz_close(struct archive_write_filter *f) -{ - struct private_data *data = (struct private_data *)f->data; - int ret, r1; - - ret = drive_compressor(f, data, 1); - if (ret == ARCHIVE_OK) { - data->total_out += - data->compressed_buffer_size - data->stream.avail_out; - ret = __archive_write_filter(f->next_filter, - data->compressed, - data->compressed_buffer_size - data->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); - ret = __archive_write_filter(f->next_filter, - data->compressed, 20); - } - } - lzma_end(&(data->stream)); - r1 = __archive_write_close_filter(f->next_filter); - return (r1 < ret ? r1 : 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); - f->data = NULL; - return (ARCHIVE_OK); -} - -/* - * Utility function to push input data through compressor, - * writing full output blocks as necessary. - * - * Note that this handles both the regular write case (finishing == - * false) and the end-of-archive case (finishing == true). - */ -static int -drive_compressor(struct archive_write_filter *f, - struct private_data *data, int finishing) -{ - int ret; - - for (;;) { - if (data->stream.avail_out == 0) { - data->total_out += data->compressed_buffer_size; - ret = __archive_write_filter(f->next_filter, - data->compressed, - data->compressed_buffer_size); - if (ret != ARCHIVE_OK) - return (ARCHIVE_FATAL); - data->stream.next_out = data->compressed; - data->stream.avail_out = data->compressed_buffer_size; - } - - /* If there's nothing to do, we're done. */ - if (!finishing && data->stream.avail_in == 0) - return (ARCHIVE_OK); - - ret = lzma_code(&(data->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) - return (ARCHIVE_OK); - /* In finishing case, this return always means - * there's more work */ - break; - case LZMA_STREAM_END: - /* This return can only occur in finishing case. */ - if (finishing) - return (ARCHIVE_OK); - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "lzma compression data error"); - return (ARCHIVE_FATAL); - case LZMA_MEMLIMIT_ERROR: - archive_set_error(f->archive, ENOMEM, - "lzma compression error: " - "%ju MiB would have been needed", - (uintmax_t)((lzma_memusage(&(data->stream)) - + 1024 * 1024 -1) - / (1024 * 1024))); - return (ARCHIVE_FATAL); - default: - /* Any other return value indicates an error. */ - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "lzma compression failed:" - " lzma_code() call returned status %d", - ret); - return (ARCHIVE_FATAL); - } - } -} - -#endif /* HAVE_LZMA_H */ diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_posix.c b/3rdparty/libarchive/libarchive/archive_write_disk_posix.c deleted file mode 100644 index 6ad53992..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_disk_posix.c +++ /dev/null @@ -1,4327 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#if !defined(_WIN32) || defined(__CYGWIN__) - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_ACL_H -#include -#endif -#ifdef HAVE_SYS_EXTATTR_H -#include -#endif -#if HAVE_SYS_XATTR_H -#include -#elif HAVE_ATTR_XATTR_H -#include -#endif -#ifdef HAVE_SYS_EA_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_UTIME_H -#include -#endif -#ifdef HAVE_COPYFILE_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif -#ifdef HAVE_LANGINFO_H -#include -#endif -#ifdef HAVE_LINUX_FS_H -#include /* for Linux file flags */ -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include /* Linux file flags, broken on Cygwin */ -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_UTIME_H -#include -#endif -#ifdef F_GETTIMES /* Tru64 specific */ -#include -#endif - -/* - * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared. - * - * It assumes that the input is an integer type of no more than 64 bits. - * If the number is less than zero, t must be a signed type, so it fits in - * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t - * without loss. But it could be a large unsigned value, so we have to clip it - * to INT64_MAX.* - */ -#define to_int64_time(t) \ - ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t)) - -#if __APPLE__ -#include -#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H -#include -#define HAVE_QUARANTINE 1 -#endif -#endif - -#ifdef HAVE_ZLIB_H -#include -#endif - -/* TODO: Support Mac OS 'quarantine' feature. This is really just a - * standard tag to mark files that have been downloaded as "tainted". - * On Mac OS, we should mark the extracted files as tainted if the - * archive being read was tainted. Windows has a similar feature; we - * should investigate ways to support this generically. */ - -#include "archive.h" -#include "archive_acl_private.h" -#include "archive_string.h" -#include "archive_endian.h" -#include "archive_entry.h" -#include "archive_private.h" -#include "archive_write_disk_private.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -/* Ignore non-int O_NOFOLLOW constant. */ -/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ -#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) -#undef O_NOFOLLOW -#endif - -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 0 -#endif - -struct fixup_entry { - struct fixup_entry *next; - struct archive_acl acl; - mode_t mode; - int64_t atime; - int64_t birthtime; - int64_t mtime; - int64_t ctime; - unsigned long atime_nanos; - unsigned long birthtime_nanos; - unsigned long mtime_nanos; - unsigned long ctime_nanos; - unsigned long fflags_set; - size_t mac_metadata_size; - void *mac_metadata; - int fixup; /* bitmask of what needs fixing */ - char *name; -}; - -/* - * We use a bitmask to track which operations remain to be done for - * this file. In particular, this helps us avoid unnecessary - * operations when it's possible to take care of one step as a - * side-effect of another. For example, mkdir() can specify the mode - * for the newly-created object but symlink() cannot. This means we - * can skip chmod() if mkdir() succeeded, but we must explicitly - * chmod() if we're trying to create a directory that already exists - * (mkdir() failed) or if we're restoring a symlink. Similarly, we - * need to verify UID/GID before trying to restore SUID/SGID bits; - * that verification can occur explicitly through a stat() call or - * implicitly because of a successful chown() call. - */ -#define TODO_MODE_FORCE 0x40000000 -#define TODO_MODE_BASE 0x20000000 -#define TODO_SUID 0x10000000 -#define TODO_SUID_CHECK 0x08000000 -#define TODO_SGID 0x04000000 -#define TODO_SGID_CHECK 0x02000000 -#define TODO_APPLEDOUBLE 0x01000000 -#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) -#define TODO_TIMES ARCHIVE_EXTRACT_TIME -#define TODO_OWNER ARCHIVE_EXTRACT_OWNER -#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS -#define TODO_ACLS ARCHIVE_EXTRACT_ACL -#define TODO_XATTR ARCHIVE_EXTRACT_XATTR -#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA -#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED - -struct archive_write_disk { - struct archive archive; - - mode_t user_umask; - struct fixup_entry *fixup_list; - struct fixup_entry *current_fixup; - int64_t user_uid; - int skip_file_set; - int64_t skip_file_dev; - int64_t skip_file_ino; - time_t start_time; - - int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); - void (*cleanup_gid)(void *private); - void *lookup_gid_data; - int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); - void (*cleanup_uid)(void *private); - void *lookup_uid_data; - - /* - * Full path of last file to satisfy symlink checks. - */ - struct archive_string path_safe; - - /* - * Cached stat data from disk for the current entry. - * If this is valid, pst points to st. Otherwise, - * pst is null. - */ - struct stat st; - struct stat *pst; - - /* Information about the object being restored right now. */ - struct archive_entry *entry; /* Entry being extracted. */ - char *name; /* Name of entry, possibly edited. */ - struct archive_string _name_data; /* backing store for 'name' */ - /* Tasks remaining for this object. */ - int todo; - /* Tasks deferred until end-of-archive. */ - int deferred; - /* Options requested by the client. */ - int flags; - /* Handle for the file we're restoring. */ - int fd; - /* Current offset for writing data to the file. */ - int64_t offset; - /* Last offset actually written to disk. */ - int64_t fd_offset; - /* Total bytes actually written to files. */ - int64_t total_bytes_written; - /* Maximum size of file, -1 if unknown. */ - int64_t filesize; - /* Dir we were in before this restore; only for deep paths. */ - int restore_pwd; - /* Mode we should use for this entry; affected by _PERM and umask. */ - mode_t mode; - /* UID/GID to use in restoring this entry. */ - int64_t uid; - int64_t gid; - /* - * HFS+ Compression. - */ - /* Xattr "com.apple.decmpfs". */ - uint32_t decmpfs_attr_size; - unsigned char *decmpfs_header_p; - /* ResourceFork set options used for fsetxattr. */ - int rsrc_xattr_options; - /* Xattr "com.apple.ResourceFork". */ - unsigned char *resource_fork; - size_t resource_fork_allocated_size; - unsigned int decmpfs_block_count; - uint32_t *decmpfs_block_info; - /* Buffer for compressed data. */ - unsigned char *compressed_buffer; - size_t compressed_buffer_size; - size_t compressed_buffer_remaining; - /* The offset of the ResourceFork where compressed data will - * be placed. */ - uint32_t compressed_rsrc_position; - uint32_t compressed_rsrc_position_v; - /* Buffer for uncompressed data. */ - char *uncompressed_buffer; - size_t block_remaining_bytes; - size_t file_remaining_bytes; -#ifdef HAVE_ZLIB_H - z_stream stream; - int stream_valid; - int decmpfs_compression_level; -#endif -}; - -/* - * Default mode for dirs created automatically (will be modified by umask). - * Note that POSIX specifies 0777 for implicitly-created dirs, "modified - * by the process' file creation mask." - */ -#define DEFAULT_DIR_MODE 0777 -/* - * Dir modes are restored in two steps: During the extraction, the permissions - * in the archive are modified to match the following limits. During - * the post-extract fixup pass, the permissions from the archive are - * applied. - */ -#define MINIMUM_DIR_MODE 0700 -#define MAXIMUM_DIR_MODE 0775 - -/* - * Maximum uncompressed size of a decmpfs block. - */ -#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) -/* - * HFS+ compression type. - */ -#define CMP_XATTR 3/* Compressed data in xattr. */ -#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ -/* - * HFS+ compression resource fork. - */ -#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ -#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ -/* Size to write compressed data to resource fork. */ -#define COMPRESSED_W_SIZE (64 * 1024) -/* decmpfs definitions. */ -#define MAX_DECMPFS_XATTR_SIZE 3802 -#ifndef DECMPFS_XATTR_NAME -#define DECMPFS_XATTR_NAME "com.apple.decmpfs" -#endif -#define DECMPFS_MAGIC 0x636d7066 -#define DECMPFS_COMPRESSION_MAGIC 0 -#define DECMPFS_COMPRESSION_TYPE 4 -#define DECMPFS_UNCOMPRESSED_SIZE 8 -#define DECMPFS_HEADER_SIZE 16 - -#define HFS_BLOCKS(s) ((s) >> 12) - -static void fsobj_error(int *, struct archive_string *, int, const char *, - const char *); -static int check_symlinks_fsobj(char *, int *, struct archive_string *, - int); -static int check_symlinks(struct archive_write_disk *); -static int create_filesystem_object(struct archive_write_disk *); -static struct fixup_entry *current_fixup(struct archive_write_disk *, - const char *pathname); -#if defined(HAVE_FCHDIR) && defined(PATH_MAX) -static void edit_deep_directories(struct archive_write_disk *ad); -#endif -static int cleanup_pathname_fsobj(char *, int *, struct archive_string *, - int); -static int cleanup_pathname(struct archive_write_disk *); -static int create_dir(struct archive_write_disk *, char *); -static int create_parent_dir(struct archive_write_disk *, char *); -static ssize_t hfs_write_data_block(struct archive_write_disk *, - const char *, size_t); -static int fixup_appledouble(struct archive_write_disk *, const char *); -static int older(struct stat *, struct archive_entry *); -static int restore_entry(struct archive_write_disk *); -static int set_mac_metadata(struct archive_write_disk *, const char *, - const void *, size_t); -static int set_xattrs(struct archive_write_disk *); -static int clear_nochange_fflags(struct archive_write_disk *); -static int set_fflags(struct archive_write_disk *); -static int set_fflags_platform(struct archive_write_disk *, int fd, - const char *name, mode_t mode, - unsigned long fflags_set, unsigned long fflags_clear); -static int set_ownership(struct archive_write_disk *); -static int set_mode(struct archive_write_disk *, int mode); -static int set_time(int, int, const char *, time_t, long, time_t, long); -static int set_times(struct archive_write_disk *, int, int, const char *, - time_t, long, time_t, long, time_t, long, time_t, long); -static int set_times_from_entry(struct archive_write_disk *); -static struct fixup_entry *sort_dir_list(struct fixup_entry *p); -static ssize_t write_data_block(struct archive_write_disk *, - const char *, size_t); - -static struct archive_vtable *archive_write_disk_vtable(void); - -static int _archive_write_disk_close(struct archive *); -static int _archive_write_disk_free(struct archive *); -static int _archive_write_disk_header(struct archive *, - struct archive_entry *); -static int64_t _archive_write_disk_filter_bytes(struct archive *, int); -static int _archive_write_disk_finish_entry(struct archive *); -static ssize_t _archive_write_disk_data(struct archive *, const void *, - size_t); -static ssize_t _archive_write_disk_data_block(struct archive *, const void *, - size_t, int64_t); - -static int -lazy_stat(struct archive_write_disk *a) -{ - if (a->pst != NULL) { - /* Already have stat() data available. */ - return (ARCHIVE_OK); - } -#ifdef HAVE_FSTAT - if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { - a->pst = &a->st; - return (ARCHIVE_OK); - } -#endif - /* - * XXX At this point, symlinks should not be hit, otherwise - * XXX a race occurred. Do we want to check explicitly for that? - */ - if (lstat(a->name, &a->st) == 0) { - a->pst = &a->st; - return (ARCHIVE_OK); - } - archive_set_error(&a->archive, errno, "Couldn't stat file"); - return (ARCHIVE_WARN); -} - -static struct archive_vtable * -archive_write_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_disk_close; - av.archive_filter_bytes = _archive_write_disk_filter_bytes; - av.archive_free = _archive_write_disk_free; - av.archive_write_header = _archive_write_disk_header; - av.archive_write_finish_entry - = _archive_write_disk_finish_entry; - av.archive_write_data = _archive_write_disk_data; - av.archive_write_data_block = _archive_write_disk_data_block; - inited = 1; - } - return (&av); -} - -static int64_t -_archive_write_disk_filter_bytes(struct archive *_a, int n) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - (void)n; /* UNUSED */ - if (n == -1 || n == 0) - return (a->total_bytes_written); - return (-1); -} - - -int -archive_write_disk_set_options(struct archive *_a, int flags) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - - a->flags = flags; - return (ARCHIVE_OK); -} - - -/* - * Extract this entry to disk. - * - * TODO: Validate hardlinks. According to the standards, we're - * supposed to check each extracted hardlink and squawk if it refers - * to a file that we didn't restore. I'm not entirely convinced this - * is a good idea, but more importantly: Is there any way to validate - * hardlinks without keeping a complete list of filenames from the - * entire archive?? Ugh. - * - */ -static int -_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - struct fixup_entry *fe; - int ret, r; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_disk_header"); - archive_clear_error(&a->archive); - if (a->archive.state & ARCHIVE_STATE_DATA) { - r = _archive_write_disk_finish_entry(&a->archive); - if (r == ARCHIVE_FATAL) - return (r); - } - - /* Set up for this particular entry. */ - a->pst = NULL; - a->current_fixup = NULL; - a->deferred = 0; - if (a->entry) { - archive_entry_free(a->entry); - a->entry = NULL; - } - a->entry = archive_entry_clone(entry); - a->fd = -1; - a->fd_offset = 0; - a->offset = 0; - a->restore_pwd = -1; - a->uid = a->user_uid; - a->mode = archive_entry_mode(a->entry); - if (archive_entry_size_is_set(a->entry)) - a->filesize = archive_entry_size(a->entry); - else - a->filesize = -1; - archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); - a->name = a->_name_data.s; - archive_clear_error(&a->archive); - - /* - * Clean up the requested path. This is necessary for correct - * dir restores; the dir restore logic otherwise gets messed - * up by nonsense like "dir/.". - */ - ret = cleanup_pathname(a); - if (ret != ARCHIVE_OK) - return (ret); - - /* - * Query the umask so we get predictable mode settings. - * This gets done on every call to _write_header in case the - * user edits their umask during the extraction for some - * reason. - */ - umask(a->user_umask = umask(0)); - - /* Figure out what we need to do for this entry. */ - a->todo = TODO_MODE_BASE; - if (a->flags & ARCHIVE_EXTRACT_PERM) { - a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ - /* - * SGID requires an extra "check" step because we - * cannot easily predict the GID that the system will - * assign. (Different systems assign GIDs to files - * based on a variety of criteria, including process - * credentials and the gid of the enclosing - * directory.) We can only restore the SGID bit if - * the file has the right GID, and we only know the - * GID if we either set it (see set_ownership) or if - * we've actually called stat() on the file after it - * was restored. Since there are several places at - * which we might verify the GID, we need a TODO bit - * to keep track. - */ - if (a->mode & S_ISGID) - a->todo |= TODO_SGID | TODO_SGID_CHECK; - /* - * Verifying the SUID is simpler, but can still be - * done in multiple ways, hence the separate "check" bit. - */ - if (a->mode & S_ISUID) - a->todo |= TODO_SUID | TODO_SUID_CHECK; - } else { - /* - * User didn't request full permissions, so don't - * restore SUID, SGID bits and obey umask. - */ - a->mode &= ~S_ISUID; - a->mode &= ~S_ISGID; - a->mode &= ~S_ISVTX; - a->mode &= ~a->user_umask; - } - if (a->flags & ARCHIVE_EXTRACT_OWNER) - a->todo |= TODO_OWNER; - if (a->flags & ARCHIVE_EXTRACT_TIME) - a->todo |= TODO_TIMES; - if (a->flags & ARCHIVE_EXTRACT_ACL) { -#if ARCHIVE_ACL_DARWIN - /* - * On MacOS, platform ACLs get stored in mac_metadata, too. - * If we intend to extract mac_metadata and it is present - * we skip extracting libarchive NFSv4 ACLs. - */ - size_t metadata_size; - - if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || - archive_entry_mac_metadata(a->entry, - &metadata_size) == NULL || metadata_size == 0) -#endif -#if ARCHIVE_ACL_LIBRICHACL - /* - * RichACLs are stored in an extended attribute. - * If we intend to extract extended attributes and have this - * attribute we skip extracting libarchive NFSv4 ACLs. - */ - short extract_acls = 1; - if (a->flags & ARCHIVE_EXTRACT_XATTR && ( - archive_entry_acl_types(a->entry) & - ARCHIVE_ENTRY_ACL_TYPE_NFS4)) { - const char *attr_name; - const void *attr_value; - size_t attr_size; - int i = archive_entry_xattr_reset(a->entry); - while (i--) { - archive_entry_xattr_next(a->entry, &attr_name, - &attr_value, &attr_size); - if (attr_name != NULL && attr_value != NULL && - attr_size > 0 && strcmp(attr_name, - "trusted.richacl") == 0) { - extract_acls = 0; - break; - } - } - } - if (extract_acls) -#endif -#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL - { -#endif - if (archive_entry_filetype(a->entry) == AE_IFDIR) - a->deferred |= TODO_ACLS; - else - a->todo |= TODO_ACLS; -#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL - } -#endif - } - if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { - if (archive_entry_filetype(a->entry) == AE_IFDIR) - a->deferred |= TODO_MAC_METADATA; - else - a->todo |= TODO_MAC_METADATA; - } -#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) - if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { - unsigned long set, clear; - archive_entry_fflags(a->entry, &set, &clear); - if ((set & ~clear) & UF_COMPRESSED) { - a->todo |= TODO_HFS_COMPRESSION; - a->decmpfs_block_count = (unsigned)-1; - } - } - if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && - (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { - a->todo |= TODO_HFS_COMPRESSION; - a->decmpfs_block_count = (unsigned)-1; - } - { - const char *p; - - /* Check if the current file name is a type of the - * resource fork file. */ - p = strrchr(a->name, '/'); - if (p == NULL) - p = a->name; - else - p++; - if (p[0] == '.' && p[1] == '_') { - /* Do not compress "._XXX" files. */ - a->todo &= ~TODO_HFS_COMPRESSION; - if (a->filesize > 0) - a->todo |= TODO_APPLEDOUBLE; - } - } -#endif - - if (a->flags & ARCHIVE_EXTRACT_XATTR) { -#if ARCHIVE_XATTR_DARWIN - /* - * On MacOS, extended attributes get stored in mac_metadata, - * too. If we intend to extract mac_metadata and it is present - * we skip extracting extended attributes. - */ - size_t metadata_size; - - if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || - archive_entry_mac_metadata(a->entry, - &metadata_size) == NULL || metadata_size == 0) -#endif - a->todo |= TODO_XATTR; - } - if (a->flags & ARCHIVE_EXTRACT_FFLAGS) - a->todo |= TODO_FFLAGS; - if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { - ret = check_symlinks(a); - if (ret != ARCHIVE_OK) - return (ret); - } -#if defined(HAVE_FCHDIR) && defined(PATH_MAX) - /* If path exceeds PATH_MAX, shorten the path. */ - edit_deep_directories(a); -#endif - - ret = restore_entry(a); - -#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) - /* - * Check if the filesystem the file is restoring on supports - * HFS+ Compression. If not, cancel HFS+ Compression. - */ - if (a->todo | TODO_HFS_COMPRESSION) { - /* - * NOTE: UF_COMPRESSED is ignored even if the filesystem - * supports HFS+ Compression because the file should - * have at least an extended attribute "com.apple.decmpfs" - * before the flag is set to indicate that the file have - * been compressed. If the filesystem does not support - * HFS+ Compression the system call will fail. - */ - if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) - a->todo &= ~TODO_HFS_COMPRESSION; - } -#endif - - /* - * TODO: There are rumours that some extended attributes must - * be restored before file data is written. If this is true, - * then we either need to write all extended attributes both - * before and after restoring the data, or find some rule for - * determining which must go first and which last. Due to the - * many ways people are using xattrs, this may prove to be an - * intractable problem. - */ - -#ifdef HAVE_FCHDIR - /* If we changed directory above, restore it here. */ - if (a->restore_pwd >= 0) { - r = fchdir(a->restore_pwd); - if (r != 0) { - archive_set_error(&a->archive, errno, - "chdir() failure"); - ret = ARCHIVE_FATAL; - } - close(a->restore_pwd); - a->restore_pwd = -1; - } -#endif - - /* - * Fixup uses the unedited pathname from archive_entry_pathname(), - * because it is relative to the base dir and the edited path - * might be relative to some intermediate dir as a result of the - * deep restore logic. - */ - if (a->deferred & TODO_MODE) { - fe = current_fixup(a, archive_entry_pathname(entry)); - if (fe == NULL) - return (ARCHIVE_FATAL); - fe->fixup |= TODO_MODE_BASE; - fe->mode = a->mode; - } - - if ((a->deferred & TODO_TIMES) - && (archive_entry_mtime_is_set(entry) - || archive_entry_atime_is_set(entry))) { - fe = current_fixup(a, archive_entry_pathname(entry)); - if (fe == NULL) - return (ARCHIVE_FATAL); - fe->mode = a->mode; - fe->fixup |= TODO_TIMES; - if (archive_entry_atime_is_set(entry)) { - fe->atime = archive_entry_atime(entry); - fe->atime_nanos = archive_entry_atime_nsec(entry); - } else { - /* If atime is unset, use start time. */ - fe->atime = a->start_time; - fe->atime_nanos = 0; - } - if (archive_entry_mtime_is_set(entry)) { - fe->mtime = archive_entry_mtime(entry); - fe->mtime_nanos = archive_entry_mtime_nsec(entry); - } else { - /* If mtime is unset, use start time. */ - fe->mtime = a->start_time; - fe->mtime_nanos = 0; - } - if (archive_entry_birthtime_is_set(entry)) { - fe->birthtime = archive_entry_birthtime(entry); - fe->birthtime_nanos = archive_entry_birthtime_nsec( - entry); - } else { - /* If birthtime is unset, use mtime. */ - fe->birthtime = fe->mtime; - fe->birthtime_nanos = fe->mtime_nanos; - } - } - - if (a->deferred & TODO_ACLS) { - fe = current_fixup(a, archive_entry_pathname(entry)); - if (fe == NULL) - return (ARCHIVE_FATAL); - fe->fixup |= TODO_ACLS; - archive_acl_copy(&fe->acl, archive_entry_acl(entry)); - } - - if (a->deferred & TODO_MAC_METADATA) { - const void *metadata; - size_t metadata_size; - metadata = archive_entry_mac_metadata(a->entry, &metadata_size); - if (metadata != NULL && metadata_size > 0) { - fe = current_fixup(a, archive_entry_pathname(entry)); - if (fe == NULL) - return (ARCHIVE_FATAL); - fe->mac_metadata = malloc(metadata_size); - if (fe->mac_metadata != NULL) { - memcpy(fe->mac_metadata, metadata, - metadata_size); - fe->mac_metadata_size = metadata_size; - fe->fixup |= TODO_MAC_METADATA; - } - } - } - - if (a->deferred & TODO_FFLAGS) { - fe = current_fixup(a, archive_entry_pathname(entry)); - if (fe == NULL) - return (ARCHIVE_FATAL); - fe->fixup |= TODO_FFLAGS; - /* TODO: Complete this.. defer fflags from below. */ - } - - /* We've created the object and are ready to pour data into it. */ - if (ret >= ARCHIVE_WARN) - a->archive.state = ARCHIVE_STATE_DATA; - /* - * If it's not open, tell our client not to try writing. - * In particular, dirs, links, etc, don't get written to. - */ - if (a->fd < 0) { - archive_entry_set_size(entry, 0); - a->filesize = 0; - } - - return (ret); -} - -int -archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); - a->skip_file_set = 1; - a->skip_file_dev = d; - a->skip_file_ino = i; - return (ARCHIVE_OK); -} - -static ssize_t -write_data_block(struct archive_write_disk *a, const char *buff, size_t size) -{ - uint64_t start_size = size; - ssize_t bytes_written = 0; - ssize_t block_size = 0, bytes_to_write; - - if (size == 0) - return (ARCHIVE_OK); - - if (a->filesize == 0 || a->fd < 0) { - archive_set_error(&a->archive, 0, - "Attempt to write to an empty file"); - return (ARCHIVE_WARN); - } - - if (a->flags & ARCHIVE_EXTRACT_SPARSE) { -#if HAVE_STRUCT_STAT_ST_BLKSIZE - int r; - if ((r = lazy_stat(a)) != ARCHIVE_OK) - return (r); - block_size = a->pst->st_blksize; -#else - /* XXX TODO XXX Is there a more appropriate choice here ? */ - /* This needn't match the filesystem allocation size. */ - block_size = 16*1024; -#endif - } - - /* If this write would run beyond the file size, truncate it. */ - if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) - start_size = size = (size_t)(a->filesize - a->offset); - - /* Write the data. */ - while (size > 0) { - if (block_size == 0) { - bytes_to_write = size; - } else { - /* We're sparsifying the file. */ - const char *p, *end; - int64_t block_end; - - /* Skip leading zero bytes. */ - for (p = buff, end = buff + size; p < end; ++p) { - if (*p != '\0') - break; - } - a->offset += p - buff; - size -= p - buff; - buff = p; - if (size == 0) - break; - - /* Calculate next block boundary after offset. */ - block_end - = (a->offset / block_size + 1) * block_size; - - /* If the adjusted write would cross block boundary, - * truncate it to the block boundary. */ - bytes_to_write = size; - if (a->offset + bytes_to_write > block_end) - bytes_to_write = block_end - a->offset; - } - /* Seek if necessary to the specified offset. */ - if (a->offset != a->fd_offset) { - if (lseek(a->fd, a->offset, SEEK_SET) < 0) { - archive_set_error(&a->archive, errno, - "Seek failed"); - return (ARCHIVE_FATAL); - } - a->fd_offset = a->offset; - } - bytes_written = write(a->fd, buff, bytes_to_write); - if (bytes_written < 0) { - archive_set_error(&a->archive, errno, "Write failed"); - return (ARCHIVE_WARN); - } - buff += bytes_written; - size -= bytes_written; - a->total_bytes_written += bytes_written; - a->offset += bytes_written; - a->fd_offset = a->offset; - } - return (start_size - size); -} - -#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ - && defined(HAVE_ZLIB_H) - -/* - * Set UF_COMPRESSED file flag. - * This have to be called after hfs_write_decmpfs() because if the - * file does not have "com.apple.decmpfs" xattr the flag is ignored. - */ -static int -hfs_set_compressed_fflag(struct archive_write_disk *a) -{ - int r; - - if ((r = lazy_stat(a)) != ARCHIVE_OK) - return (r); - - a->st.st_flags |= UF_COMPRESSED; - if (fchflags(a->fd, a->st.st_flags) != 0) { - archive_set_error(&a->archive, errno, - "Failed to set UF_COMPRESSED file flag"); - return (ARCHIVE_WARN); - } - return (ARCHIVE_OK); -} - -/* - * HFS+ Compression decmpfs - * - * +------------------------------+ +0 - * | Magic(LE 4 bytes) | - * +------------------------------+ - * | Type(LE 4 bytes) | - * +------------------------------+ - * | Uncompressed size(LE 8 bytes)| - * +------------------------------+ +16 - * | | - * | Compressed data | - * | (Placed only if Type == 3) | - * | | - * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE - * - * Type is 3: decmpfs has compressed data. - * Type is 4: Resource Fork has compressed data. - */ -/* - * Write "com.apple.decmpfs" - */ -static int -hfs_write_decmpfs(struct archive_write_disk *a) -{ - int r; - uint32_t compression_type; - - r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, - a->decmpfs_attr_size, 0, 0); - if (r < 0) { - archive_set_error(&a->archive, errno, - "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); - compression_type = archive_le32dec( - &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); - if (compression_type == CMP_RESOURCE_FORK) - fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, - XATTR_SHOWCOMPRESSION); - return (ARCHIVE_WARN); - } - return (ARCHIVE_OK); -} - -/* - * HFS+ Compression Resource Fork - * - * +-----------------------------+ - * | Header(260 bytes) | - * +-----------------------------+ - * | Block count(LE 4 bytes) | - * +-----------------------------+ --+ - * +-- | Offset (LE 4 bytes) | | - * | | [distance from Block count] | | Block 0 - * | +-----------------------------+ | - * | | Compressed size(LE 4 bytes) | | - * | +-----------------------------+ --+ - * | | | - * | | .................. | - * | | | - * | +-----------------------------+ --+ - * | | Offset (LE 4 bytes) | | - * | +-----------------------------+ | Block (Block count -1) - * | | Compressed size(LE 4 bytes) | | - * +-> +-----------------------------+ --+ - * | Compressed data(n bytes) | Block 0 - * +-----------------------------+ - * | | - * | .................. | - * | | - * +-----------------------------+ - * | Compressed data(n bytes) | Block (Block count -1) - * +-----------------------------+ - * | Footer(50 bytes) | - * +-----------------------------+ - * - */ -/* - * Write the header of "com.apple.ResourceFork" - */ -static int -hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, - size_t bytes, uint32_t position) -{ - int ret; - - ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, - position, a->rsrc_xattr_options); - if (ret < 0) { - archive_set_error(&a->archive, errno, - "Cannot restore xattr: %s at %u pos %u bytes", - XATTR_RESOURCEFORK_NAME, - (unsigned)position, - (unsigned)bytes); - return (ARCHIVE_WARN); - } - a->rsrc_xattr_options &= ~XATTR_CREATE; - return (ARCHIVE_OK); -} - -static int -hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) -{ - int ret; - - ret = hfs_write_resource_fork(a, a->compressed_buffer, - bytes_compressed, a->compressed_rsrc_position); - if (ret == ARCHIVE_OK) - a->compressed_rsrc_position += bytes_compressed; - return (ret); -} - -static int -hfs_write_resource_fork_header(struct archive_write_disk *a) -{ - unsigned char *buff; - uint32_t rsrc_bytes; - uint32_t rsrc_header_bytes; - - /* - * Write resource fork header + block info. - */ - buff = a->resource_fork; - rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; - rsrc_header_bytes = - RSRC_H_SIZE + /* Header base size. */ - 4 + /* Block count. */ - (a->decmpfs_block_count * 8);/* Block info */ - archive_be32enc(buff, 0x100); - archive_be32enc(buff + 4, rsrc_bytes); - archive_be32enc(buff + 8, rsrc_bytes - 256); - archive_be32enc(buff + 12, 0x32); - memset(buff + 16, 0, 240); - archive_be32enc(buff + 256, rsrc_bytes - 260); - return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); -} - -static size_t -hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) -{ - static const char rsrc_footer[RSRC_F_SIZE] = { - 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, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', - 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - if (buff_size < sizeof(rsrc_footer)) - return (0); - memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); - return (sizeof(rsrc_footer)); -} - -static int -hfs_reset_compressor(struct archive_write_disk *a) -{ - int ret; - - if (a->stream_valid) - ret = deflateReset(&a->stream); - else - ret = deflateInit(&a->stream, a->decmpfs_compression_level); - - if (ret != Z_OK) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Failed to initialize compressor"); - return (ARCHIVE_FATAL); - } else - a->stream_valid = 1; - - return (ARCHIVE_OK); -} - -static int -hfs_decompress(struct archive_write_disk *a) -{ - uint32_t *block_info; - unsigned int block_count; - uint32_t data_pos, data_size; - ssize_t r; - ssize_t bytes_written, bytes_to_write; - unsigned char *b; - - block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); - block_count = archive_le32dec(block_info++); - while (block_count--) { - data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); - data_size = archive_le32dec(block_info++); - r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, - a->compressed_buffer, data_size, data_pos, 0); - if (r != data_size) { - archive_set_error(&a->archive, - (r < 0)?errno:ARCHIVE_ERRNO_MISC, - "Failed to read resource fork"); - return (ARCHIVE_WARN); - } - if (a->compressed_buffer[0] == 0xff) { - bytes_to_write = data_size -1; - b = a->compressed_buffer + 1; - } else { - uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; - int zr; - - zr = uncompress((Bytef *)a->uncompressed_buffer, - &dest_len, a->compressed_buffer, data_size); - if (zr != Z_OK) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Failed to decompress resource fork"); - return (ARCHIVE_WARN); - } - bytes_to_write = dest_len; - b = (unsigned char *)a->uncompressed_buffer; - } - do { - bytes_written = write(a->fd, b, bytes_to_write); - if (bytes_written < 0) { - archive_set_error(&a->archive, errno, - "Write failed"); - return (ARCHIVE_WARN); - } - bytes_to_write -= bytes_written; - b += bytes_written; - } while (bytes_to_write > 0); - } - r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); - if (r == -1) { - archive_set_error(&a->archive, errno, - "Failed to remove resource fork"); - return (ARCHIVE_WARN); - } - return (ARCHIVE_OK); -} - -static int -hfs_drive_compressor(struct archive_write_disk *a, const char *buff, - size_t size) -{ - unsigned char *buffer_compressed; - size_t bytes_compressed; - size_t bytes_used; - int ret; - - ret = hfs_reset_compressor(a); - if (ret != ARCHIVE_OK) - return (ret); - - if (a->compressed_buffer == NULL) { - size_t block_size; - - block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + - + compressBound(MAX_DECMPFS_BLOCK_SIZE); - a->compressed_buffer = malloc(block_size); - if (a->compressed_buffer == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Resource Fork"); - return (ARCHIVE_FATAL); - } - a->compressed_buffer_size = block_size; - a->compressed_buffer_remaining = block_size; - } - - buffer_compressed = a->compressed_buffer + - a->compressed_buffer_size - a->compressed_buffer_remaining; - a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; - a->stream.avail_in = size; - a->stream.next_out = buffer_compressed; - a->stream.avail_out = a->compressed_buffer_remaining; - do { - ret = deflate(&a->stream, Z_FINISH); - switch (ret) { - case Z_OK: - case Z_STREAM_END: - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Failed to compress data"); - return (ARCHIVE_FAILED); - } - } while (ret == Z_OK); - bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; - - /* - * If the compressed size is larger than the original size, - * throw away compressed data, use uncompressed data instead. - */ - if (bytes_compressed > size) { - buffer_compressed[0] = 0xFF;/* uncompressed marker. */ - memcpy(buffer_compressed + 1, buff, size); - bytes_compressed = size + 1; - } - a->compressed_buffer_remaining -= bytes_compressed; - - /* - * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE - * and the block count in the file is only one, store compressed - * data to decmpfs xattr instead of the resource fork. - */ - if (a->decmpfs_block_count == 1 && - (a->decmpfs_attr_size + bytes_compressed) - <= MAX_DECMPFS_XATTR_SIZE) { - archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], - CMP_XATTR); - memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, - buffer_compressed, bytes_compressed); - a->decmpfs_attr_size += bytes_compressed; - a->compressed_buffer_remaining = a->compressed_buffer_size; - /* - * Finish HFS+ Compression. - * - Write the decmpfs xattr. - * - Set the UF_COMPRESSED file flag. - */ - ret = hfs_write_decmpfs(a); - if (ret == ARCHIVE_OK) - ret = hfs_set_compressed_fflag(a); - return (ret); - } - - /* Update block info. */ - archive_le32enc(a->decmpfs_block_info++, - a->compressed_rsrc_position_v - RSRC_H_SIZE); - archive_le32enc(a->decmpfs_block_info++, bytes_compressed); - a->compressed_rsrc_position_v += bytes_compressed; - - /* - * Write the compressed data to the resource fork. - */ - bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; - while (bytes_used >= COMPRESSED_W_SIZE) { - ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); - if (ret != ARCHIVE_OK) - return (ret); - bytes_used -= COMPRESSED_W_SIZE; - if (bytes_used > COMPRESSED_W_SIZE) - memmove(a->compressed_buffer, - a->compressed_buffer + COMPRESSED_W_SIZE, - bytes_used); - else - memcpy(a->compressed_buffer, - a->compressed_buffer + COMPRESSED_W_SIZE, - bytes_used); - } - a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; - - /* - * If the current block is the last block, write the remaining - * compressed data and the resource fork footer. - */ - if (a->file_remaining_bytes == 0) { - size_t rsrc_size; - int64_t bk; - - /* Append the resource footer. */ - rsrc_size = hfs_set_resource_fork_footer( - a->compressed_buffer + bytes_used, - a->compressed_buffer_remaining); - ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); - a->compressed_buffer_remaining = a->compressed_buffer_size; - - /* If the compressed size is not enough smaller than - * the uncompressed size. cancel HFS+ compression. - * TODO: study a behavior of ditto utility and improve - * the condition to fall back into no HFS+ compression. */ - bk = HFS_BLOCKS(a->compressed_rsrc_position); - bk += bk >> 7; - if (bk > HFS_BLOCKS(a->filesize)) - return hfs_decompress(a); - /* - * Write the resourcefork header. - */ - if (ret == ARCHIVE_OK) - ret = hfs_write_resource_fork_header(a); - /* - * Finish HFS+ Compression. - * - Write the decmpfs xattr. - * - Set the UF_COMPRESSED file flag. - */ - if (ret == ARCHIVE_OK) - ret = hfs_write_decmpfs(a); - if (ret == ARCHIVE_OK) - ret = hfs_set_compressed_fflag(a); - } - return (ret); -} - -static ssize_t -hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, - size_t size) -{ - const char *buffer_to_write; - size_t bytes_to_write; - int ret; - - if (a->decmpfs_block_count == (unsigned)-1) { - void *new_block; - size_t new_size; - unsigned int block_count; - - if (a->decmpfs_header_p == NULL) { - new_block = malloc(MAX_DECMPFS_XATTR_SIZE - + sizeof(uint32_t)); - if (new_block == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for decmpfs"); - return (ARCHIVE_FATAL); - } - a->decmpfs_header_p = new_block; - } - a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; - archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], - DECMPFS_MAGIC); - archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], - CMP_RESOURCE_FORK); - 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; - /* - * Allocate buffer for resource fork. - * Set up related pointers; - */ - new_size = - RSRC_H_SIZE + /* header */ - 4 + /* Block count */ - (block_count * sizeof(uint32_t) * 2) + - RSRC_F_SIZE; /* footer */ - if (new_size > a->resource_fork_allocated_size) { - new_block = realloc(a->resource_fork, new_size); - if (new_block == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for ResourceFork"); - return (ARCHIVE_FATAL); - } - a->resource_fork_allocated_size = new_size; - a->resource_fork = new_block; - } - - /* Allocate uncompressed buffer */ - if (a->uncompressed_buffer == NULL) { - new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); - if (new_block == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for decmpfs"); - return (ARCHIVE_FATAL); - } - a->uncompressed_buffer = new_block; - } - a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; - a->file_remaining_bytes = a->filesize; - a->compressed_buffer_remaining = a->compressed_buffer_size; - - /* - * Set up a resource fork. - */ - a->rsrc_xattr_options = XATTR_CREATE; - /* Get the position where we are going to set a bunch - * of block info. */ - 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); - /* Get the position where we are going to set compressed - * data. */ - a->compressed_rsrc_position = - RSRC_H_SIZE + 4 + (block_count * 8); - a->compressed_rsrc_position_v = a->compressed_rsrc_position; - a->decmpfs_block_count = block_count; - } - - /* Ignore redundant bytes. */ - if (a->file_remaining_bytes == 0) - return ((ssize_t)size); - - /* Do not overrun a block size. */ - if (size > a->block_remaining_bytes) - bytes_to_write = a->block_remaining_bytes; - else - bytes_to_write = size; - /* Do not overrun the file size. */ - if (bytes_to_write > a->file_remaining_bytes) - bytes_to_write = a->file_remaining_bytes; - - /* For efficiency, if a copy length is full of the uncompressed - * buffer size, do not copy writing data to it. */ - if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) - buffer_to_write = buff; - else { - memcpy(a->uncompressed_buffer + - MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, - buff, bytes_to_write); - buffer_to_write = a->uncompressed_buffer; - } - a->block_remaining_bytes -= bytes_to_write; - a->file_remaining_bytes -= bytes_to_write; - - if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { - ret = hfs_drive_compressor(a, buffer_to_write, - MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); - if (ret < 0) - return (ret); - a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; - } - /* Ignore redundant bytes. */ - if (a->file_remaining_bytes == 0) - return ((ssize_t)size); - return (bytes_to_write); -} - -static ssize_t -hfs_write_data_block(struct archive_write_disk *a, const char *buff, - size_t size) -{ - uint64_t start_size = size; - ssize_t bytes_written = 0; - ssize_t bytes_to_write; - - if (size == 0) - return (ARCHIVE_OK); - - if (a->filesize == 0 || a->fd < 0) { - archive_set_error(&a->archive, 0, - "Attempt to write to an empty file"); - return (ARCHIVE_WARN); - } - - /* If this write would run beyond the file size, truncate it. */ - if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) - start_size = size = (size_t)(a->filesize - a->offset); - - /* Write the data. */ - while (size > 0) { - bytes_to_write = size; - /* Seek if necessary to the specified offset. */ - if (a->offset < a->fd_offset) { - /* Can't support backward move. */ - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Seek failed"); - return (ARCHIVE_FATAL); - } else if (a->offset > a->fd_offset) { - int64_t skip = a->offset - a->fd_offset; - char nullblock[1024]; - - memset(nullblock, 0, sizeof(nullblock)); - while (skip > 0) { - if (skip > (int64_t)sizeof(nullblock)) - bytes_written = hfs_write_decmpfs_block( - a, nullblock, sizeof(nullblock)); - else - bytes_written = hfs_write_decmpfs_block( - a, nullblock, skip); - if (bytes_written < 0) { - archive_set_error(&a->archive, errno, - "Write failed"); - return (ARCHIVE_WARN); - } - skip -= bytes_written; - } - - a->fd_offset = a->offset; - } - bytes_written = - hfs_write_decmpfs_block(a, buff, bytes_to_write); - if (bytes_written < 0) - return (bytes_written); - buff += bytes_written; - size -= bytes_written; - a->total_bytes_written += bytes_written; - a->offset += bytes_written; - a->fd_offset = a->offset; - } - return (start_size - size); -} -#else -static ssize_t -hfs_write_data_block(struct archive_write_disk *a, const char *buff, - size_t size) -{ - return (write_data_block(a, buff, size)); -} -#endif - -static ssize_t -_archive_write_disk_data_block(struct archive *_a, - const void *buff, size_t size, int64_t offset) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - ssize_t r; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_DATA, "archive_write_data_block"); - - a->offset = offset; - if (a->todo & TODO_HFS_COMPRESSION) - r = hfs_write_data_block(a, buff, size); - else - r = write_data_block(a, buff, size); - if (r < ARCHIVE_OK) - return (r); - if ((size_t)r < size) { - archive_set_error(&a->archive, 0, - "Too much data: Truncating file at %ju bytes", - (uintmax_t)a->filesize); - return (ARCHIVE_WARN); - } -#if ARCHIVE_VERSION_NUMBER < 3999000 - return (ARCHIVE_OK); -#else - return (size); -#endif -} - -static ssize_t -_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_DATA, "archive_write_data"); - - if (a->todo & TODO_HFS_COMPRESSION) - return (hfs_write_data_block(a, buff, size)); - return (write_data_block(a, buff, size)); -} - -static int -_archive_write_disk_finish_entry(struct archive *_a) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - int ret = ARCHIVE_OK; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_finish_entry"); - if (a->archive.state & ARCHIVE_STATE_HEADER) - return (ARCHIVE_OK); - archive_clear_error(&a->archive); - - /* Pad or truncate file to the right size. */ - if (a->fd < 0) { - /* There's no file. */ - } else if (a->filesize < 0) { - /* File size is unknown, so we can't set the size. */ - } else if (a->fd_offset == a->filesize) { - /* Last write ended at exactly the filesize; we're done. */ - /* Hopefully, this is the common case. */ -#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) - } else if (a->todo & TODO_HFS_COMPRESSION) { - char null_d[1024]; - ssize_t r; - - if (a->file_remaining_bytes) - memset(null_d, 0, sizeof(null_d)); - while (a->file_remaining_bytes) { - if (a->file_remaining_bytes > sizeof(null_d)) - r = hfs_write_data_block( - a, null_d, sizeof(null_d)); - else - r = hfs_write_data_block( - a, null_d, a->file_remaining_bytes); - if (r < 0) - return ((int)r); - } -#endif - } else { -#if HAVE_FTRUNCATE - if (ftruncate(a->fd, a->filesize) == -1 && - a->filesize == 0) { - archive_set_error(&a->archive, errno, - "File size could not be restored"); - return (ARCHIVE_FAILED); - } -#endif - /* - * Not all platforms implement the XSI option to - * extend files via ftruncate. Stat() the file again - * to see what happened. - */ - a->pst = NULL; - if ((ret = lazy_stat(a)) != ARCHIVE_OK) - return (ret); - /* We can use lseek()/write() to extend the file if - * ftruncate didn't work or isn't available. */ - if (a->st.st_size < a->filesize) { - const char nul = '\0'; - if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { - archive_set_error(&a->archive, errno, - "Seek failed"); - return (ARCHIVE_FATAL); - } - if (write(a->fd, &nul, 1) < 0) { - archive_set_error(&a->archive, errno, - "Write to restore size failed"); - return (ARCHIVE_FATAL); - } - a->pst = NULL; - } - } - - /* Restore metadata. */ - - /* - * This is specific to Mac OS X. - * If the current file is an AppleDouble file, it should be - * linked with the data fork file and remove it. - */ - if (a->todo & TODO_APPLEDOUBLE) { - int r2 = fixup_appledouble(a, a->name); - if (r2 == ARCHIVE_EOF) { - /* The current file has been successfully linked - * with the data fork file and removed. So there - * is nothing to do on the current file. */ - goto finish_metadata; - } - if (r2 < ret) ret = r2; - } - - /* - * Look up the "real" UID only if we're going to need it. - * TODO: the TODO_SGID condition can be dropped here, can't it? - */ - if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { - a->uid = archive_write_disk_uid(&a->archive, - archive_entry_uname(a->entry), - archive_entry_uid(a->entry)); - } - /* Look up the "real" GID only if we're going to need it. */ - /* TODO: the TODO_SUID condition can be dropped here, can't it? */ - if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { - a->gid = archive_write_disk_gid(&a->archive, - archive_entry_gname(a->entry), - archive_entry_gid(a->entry)); - } - - /* - * Restore ownership before set_mode tries to restore suid/sgid - * bits. If we set the owner, we know what it is and can skip - * a stat() call to examine the ownership of the file on disk. - */ - if (a->todo & TODO_OWNER) { - int r2 = set_ownership(a); - if (r2 < ret) ret = r2; - } - - /* - * set_mode must precede ACLs on systems such as Solaris and - * FreeBSD where setting the mode implicitly clears extended ACLs - */ - if (a->todo & TODO_MODE) { - int r2 = set_mode(a, a->mode); - if (r2 < ret) ret = r2; - } - - /* - * Security-related extended attributes (such as - * security.capability on Linux) have to be restored last, - * since they're implicitly removed by other file changes. - */ - if (a->todo & TODO_XATTR) { - int r2 = set_xattrs(a); - if (r2 < ret) ret = r2; - } - - /* - * Some flags prevent file modification; they must be restored after - * file contents are written. - */ - if (a->todo & TODO_FFLAGS) { - int r2 = set_fflags(a); - if (r2 < ret) ret = r2; - } - - /* - * Time must follow most other metadata; - * otherwise atime will get changed. - */ - if (a->todo & TODO_TIMES) { - int r2 = set_times_from_entry(a); - if (r2 < ret) ret = r2; - } - - /* - * Mac extended metadata includes ACLs. - */ - if (a->todo & TODO_MAC_METADATA) { - const void *metadata; - size_t metadata_size; - metadata = archive_entry_mac_metadata(a->entry, &metadata_size); - if (metadata != NULL && metadata_size > 0) { - int r2 = set_mac_metadata(a, archive_entry_pathname( - a->entry), metadata, metadata_size); - if (r2 < ret) ret = r2; - } - } - - /* - * ACLs must be restored after timestamps because there are - * ACLs that prevent attribute changes (including time). - */ - if (a->todo & TODO_ACLS) { - int r2; - r2 = archive_write_disk_set_acls(&a->archive, a->fd, - archive_entry_pathname(a->entry), - archive_entry_acl(a->entry), - archive_entry_mode(a->entry)); - if (r2 < ret) ret = r2; - } - -finish_metadata: - /* If there's an fd, we can close it now. */ - if (a->fd >= 0) { - close(a->fd); - a->fd = -1; - } - /* If there's an entry, we can release it now. */ - if (a->entry) { - archive_entry_free(a->entry); - a->entry = NULL; - } - a->archive.state = ARCHIVE_STATE_HEADER; - return (ret); -} - -int -archive_write_disk_set_group_lookup(struct archive *_a, - void *private_data, - int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), - void (*cleanup_gid)(void *private)) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); - - if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) - (a->cleanup_gid)(a->lookup_gid_data); - - a->lookup_gid = lookup_gid; - a->cleanup_gid = cleanup_gid; - a->lookup_gid_data = private_data; - return (ARCHIVE_OK); -} - -int -archive_write_disk_set_user_lookup(struct archive *_a, - void *private_data, - int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), - void (*cleanup_uid)(void *private)) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); - - if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) - (a->cleanup_uid)(a->lookup_uid_data); - - a->lookup_uid = lookup_uid; - a->cleanup_uid = cleanup_uid; - a->lookup_uid_data = private_data; - return (ARCHIVE_OK); -} - -int64_t -archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_gid"); - if (a->lookup_gid) - return (a->lookup_gid)(a->lookup_gid_data, name, id); - return (id); -} - -int64_t -archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_uid"); - if (a->lookup_uid) - return (a->lookup_uid)(a->lookup_uid_data, name, id); - return (id); -} - -/* - * Create a new archive_write_disk object and initialize it with global state. - */ -struct archive * -archive_write_disk_new(void) -{ - struct archive_write_disk *a; - - a = (struct archive_write_disk *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; - /* We're ready to write a header immediately. */ - a->archive.state = ARCHIVE_STATE_HEADER; - a->archive.vtable = archive_write_disk_vtable(); - a->start_time = time(NULL); - /* Query and restore the umask. */ - umask(a->user_umask = umask(0)); -#ifdef HAVE_GETEUID - a->user_uid = geteuid(); -#endif /* HAVE_GETEUID */ - if (archive_string_ensure(&a->path_safe, 512) == NULL) { - free(a); - return (NULL); - } -#ifdef HAVE_ZLIB_H - a->decmpfs_compression_level = 5; -#endif - return (&a->archive); -} - - -/* - * If pathname is longer than PATH_MAX, chdir to a suitable - * intermediate dir and edit the path down to a shorter suffix. Note - * that this routine never returns an error; if the chdir() attempt - * fails for any reason, we just go ahead with the long pathname. The - * object creation is likely to fail, but any error will get handled - * at that time. - */ -#if defined(HAVE_FCHDIR) && defined(PATH_MAX) -static void -edit_deep_directories(struct archive_write_disk *a) -{ - int ret; - char *tail = a->name; - - /* If path is short, avoid the open() below. */ - if (strlen(tail) < PATH_MAX) - return; - - /* Try to record our starting dir. */ - a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(a->restore_pwd); - if (a->restore_pwd < 0) - return; - - /* As long as the path is too long... */ - while (strlen(tail) >= PATH_MAX) { - /* Locate a dir prefix shorter than PATH_MAX. */ - tail += PATH_MAX - 8; - while (tail > a->name && *tail != '/') - tail--; - /* Exit if we find a too-long path component. */ - if (tail <= a->name) - return; - /* Create the intermediate dir and chdir to it. */ - *tail = '\0'; /* Terminate dir portion */ - ret = create_dir(a, a->name); - if (ret == ARCHIVE_OK && chdir(a->name) != 0) - ret = ARCHIVE_FAILED; - *tail = '/'; /* Restore the / we removed. */ - if (ret != ARCHIVE_OK) - return; - tail++; - /* The chdir() succeeded; we've now shortened the path. */ - a->name = tail; - } - return; -} -#endif - -/* - * The main restore function. - */ -static int -restore_entry(struct archive_write_disk *a) -{ - int ret = ARCHIVE_OK, en; - - if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { - /* - * TODO: Fix this. Apparently, there are platforms - * that still allow root to hose the entire filesystem - * by unlinking a dir. The S_ISDIR() test above - * prevents us from using unlink() here if the new - * object is a dir, but that doesn't mean the old - * object isn't a dir. - */ - if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) - (void)clear_nochange_fflags(a); - if (unlink(a->name) == 0) { - /* We removed it, reset cached stat. */ - a->pst = NULL; - } else if (errno == ENOENT) { - /* File didn't exist, that's just as good. */ - } else if (rmdir(a->name) == 0) { - /* It was a dir, but now it's gone. */ - a->pst = NULL; - } else { - /* We tried, but couldn't get rid of it. */ - archive_set_error(&a->archive, errno, - "Could not unlink"); - return(ARCHIVE_FAILED); - } - } - - /* Try creating it first; if this fails, we'll try to recover. */ - en = create_filesystem_object(a); - - if ((en == ENOTDIR || en == ENOENT) - && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { - /* If the parent dir doesn't exist, try creating it. */ - create_parent_dir(a, a->name); - /* Now try to create the object again. */ - en = create_filesystem_object(a); - } - - if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) { - archive_set_error(&a->archive, en, - "Hard-link target '%s' does not exist.", - archive_entry_hardlink(a->entry)); - return (ARCHIVE_FAILED); - } - - if ((en == EISDIR || en == EEXIST) - && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { - /* If we're not overwriting, we're done. */ - archive_entry_unset_size(a->entry); - return (ARCHIVE_OK); - } - - /* - * Some platforms return EISDIR if you call - * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some - * return EEXIST. POSIX is ambiguous, requiring EISDIR - * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) - * on an existing item. - */ - if (en == EISDIR) { - /* A dir is in the way of a non-dir, rmdir it. */ - if (rmdir(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't remove already-existing dir"); - return (ARCHIVE_FAILED); - } - a->pst = NULL; - /* Try again. */ - en = create_filesystem_object(a); - } else if (en == EEXIST) { - /* - * We know something is in the way, but we don't know what; - * we need to find out before we go any further. - */ - int r = 0; - /* - * The SECURE_SYMLINKS logic has already removed a - * symlink to a dir if the client wants that. So - * follow the symlink if we're creating a dir. - */ - if (S_ISDIR(a->mode)) - r = stat(a->name, &a->st); - /* - * If it's not a dir (or it's a broken symlink), - * then don't follow it. - */ - if (r != 0 || !S_ISDIR(a->mode)) - r = lstat(a->name, &a->st); - if (r != 0) { - archive_set_error(&a->archive, errno, - "Can't stat existing object"); - return (ARCHIVE_FAILED); - } - - /* - * NO_OVERWRITE_NEWER doesn't apply to directories. - */ - if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) - && !S_ISDIR(a->st.st_mode)) { - if (!older(&(a->st), a->entry)) { - archive_entry_unset_size(a->entry); - return (ARCHIVE_OK); - } - } - - /* If it's our archive, we're done. */ - 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, - "Refusing to overwrite archive"); - return (ARCHIVE_FAILED); - } - - if (!S_ISDIR(a->st.st_mode)) { - /* A non-dir is in the way, unlink it. */ - if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) - (void)clear_nochange_fflags(a); - if (unlink(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't unlink already-existing object"); - return (ARCHIVE_FAILED); - } - a->pst = NULL; - /* Try again. */ - en = create_filesystem_object(a); - } else if (!S_ISDIR(a->mode)) { - /* A dir is in the way of a non-dir, rmdir it. */ - if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) - (void)clear_nochange_fflags(a); - if (rmdir(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't replace existing directory with non-directory"); - return (ARCHIVE_FAILED); - } - /* Try again. */ - en = create_filesystem_object(a); - } else { - /* - * There's a dir in the way of a dir. Don't - * waste time with rmdir()/mkdir(), just fix - * up the permissions on the existing dir. - * Note that we don't change perms on existing - * dirs unless _EXTRACT_PERM is specified. - */ - if ((a->mode != a->st.st_mode) - && (a->todo & TODO_MODE_FORCE)) - a->deferred |= (a->todo & TODO_MODE); - /* Ownership doesn't need deferred fixup. */ - en = 0; /* Forget the EEXIST. */ - } - } - - if (en) { - /* Everything failed; give up here. */ - if ((&a->archive)->error == NULL) - archive_set_error(&a->archive, en, "Can't create '%s'", - a->name); - return (ARCHIVE_FAILED); - } - - a->pst = NULL; /* Cached stat data no longer valid. */ - return (ret); -} - -/* - * Returns 0 if creation succeeds, or else returns errno value from - * the failed system call. Note: This function should only ever perform - * a single system call. - */ -static int -create_filesystem_object(struct archive_write_disk *a) -{ - /* Create the entry. */ - const char *linkname; - mode_t final_mode, mode; - int r; - /* these for check_symlinks_fsobj */ - char *linkname_copy; /* non-const copy of linkname */ - struct stat st; - struct archive_string error_string; - int error_number; - - /* We identify hard/symlinks according to the link names. */ - /* Since link(2) and symlink(2) don't handle modes, we're done here. */ - linkname = archive_entry_hardlink(a->entry); - if (linkname != NULL) { -#if !HAVE_LINK - return (EPERM); -#else - archive_string_init(&error_string); - linkname_copy = strdup(linkname); - if (linkname_copy == NULL) { - return (EPERM); - } - /* - * TODO: consider using the cleaned-up path as the link - * target? - */ - r = cleanup_pathname_fsobj(linkname_copy, &error_number, - &error_string, a->flags); - if (r != ARCHIVE_OK) { - archive_set_error(&a->archive, error_number, "%s", - error_string.s); - free(linkname_copy); - archive_string_free(&error_string); - /* - * EPERM is more appropriate than error_number for our - * callers - */ - return (EPERM); - } - r = check_symlinks_fsobj(linkname_copy, &error_number, - &error_string, a->flags); - if (r != ARCHIVE_OK) { - archive_set_error(&a->archive, error_number, "%s", - error_string.s); - free(linkname_copy); - archive_string_free(&error_string); - /* - * EPERM is more appropriate than error_number for our - * callers - */ - return (EPERM); - } - free(linkname_copy); - archive_string_free(&error_string); - r = link(linkname, a->name) ? errno : 0; - /* - * New cpio and pax formats allow hardlink entries - * to carry data, so we may have to open the file - * for hardlink entries. - * - * If the hardlink was successfully created and - * the archive doesn't have carry data for it, - * consider it to be non-authoritative for meta data. - * This is consistent with GNU tar and BSD pax. - * If the hardlink does carry data, let the last - * archive entry decide ownership. - */ - if (r == 0 && a->filesize <= 0) { - a->todo = 0; - a->deferred = 0; - } else if (r == 0 && a->filesize > 0) { -#ifdef HAVE_LSTAT - r = lstat(a->name, &st); -#else - r = stat(a->name, &st); -#endif - if (r != 0) - r = errno; - else if ((st.st_mode & AE_IFMT) == AE_IFREG) { - a->fd = open(a->name, O_WRONLY | O_TRUNC | - O_BINARY | O_CLOEXEC | O_NOFOLLOW); - __archive_ensure_cloexec_flag(a->fd); - if (a->fd < 0) - r = errno; - } - } - return (r); -#endif - } - linkname = archive_entry_symlink(a->entry); - if (linkname != NULL) { -#if HAVE_SYMLINK - return symlink(linkname, a->name) ? errno : 0; -#else - return (EPERM); -#endif - } - - /* - * The remaining system calls all set permissions, so let's - * try to take advantage of that to avoid an extra chmod() - * call. (Recall that umask is set to zero right now!) - */ - - /* Mode we want for the final restored object (w/o file type bits). */ - final_mode = a->mode & 07777; - /* - * The mode that will actually be restored in this step. Note - * that SUID, SGID, etc, require additional work to ensure - * security, so we never restore them at this point. - */ - mode = final_mode & 0777 & ~a->user_umask; - - switch (a->mode & AE_IFMT) { - default: - /* POSIX requires that we fall through here. */ - /* FALLTHROUGH */ - case AE_IFREG: - a->fd = open(a->name, - O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); - __archive_ensure_cloexec_flag(a->fd); - r = (a->fd < 0); - break; - case AE_IFCHR: -#ifdef HAVE_MKNOD - /* Note: we use AE_IFCHR for the case label, and - * S_IFCHR for the mknod() call. This is correct. */ - r = mknod(a->name, mode | S_IFCHR, - archive_entry_rdev(a->entry)); - break; -#else - /* TODO: Find a better way to warn about our inability - * to restore a char device node. */ - return (EINVAL); -#endif /* HAVE_MKNOD */ - case AE_IFBLK: -#ifdef HAVE_MKNOD - r = mknod(a->name, mode | S_IFBLK, - archive_entry_rdev(a->entry)); - break; -#else - /* TODO: Find a better way to warn about our inability - * to restore a block device node. */ - return (EINVAL); -#endif /* HAVE_MKNOD */ - case AE_IFDIR: - mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; - r = mkdir(a->name, mode); - if (r == 0) { - /* Defer setting dir times. */ - a->deferred |= (a->todo & TODO_TIMES); - a->todo &= ~TODO_TIMES; - /* Never use an immediate chmod(). */ - /* We can't avoid the chmod() entirely if EXTRACT_PERM - * because of SysV SGID inheritance. */ - if ((mode != final_mode) - || (a->flags & ARCHIVE_EXTRACT_PERM)) - a->deferred |= (a->todo & TODO_MODE); - a->todo &= ~TODO_MODE; - } - break; - case AE_IFIFO: -#ifdef HAVE_MKFIFO - r = mkfifo(a->name, mode); - break; -#else - /* TODO: Find a better way to warn about our inability - * to restore a fifo. */ - return (EINVAL); -#endif /* HAVE_MKFIFO */ - } - - /* All the system calls above set errno on failure. */ - if (r) - return (errno); - - /* If we managed to set the final mode, we've avoided a chmod(). */ - if (mode == final_mode) - a->todo &= ~TODO_MODE; - return (0); -} - -/* - * Cleanup function for archive_extract. Mostly, this involves processing - * the fixup list, which is used to address a number of problems: - * * Dir permissions might prevent us from restoring a file in that - * dir, so we restore the dir with minimum 0700 permissions first, - * then correct the mode at the end. - * * Similarly, the act of restoring a file touches the directory - * and changes the timestamp on the dir, so we have to touch-up dir - * timestamps at the end as well. - * * Some file flags can interfere with the restore by, for example, - * preventing the creation of hardlinks to those files. - * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. - * - * Note that tar/cpio do not require that archives be in a particular - * order; there is no way to know when the last file has been restored - * within a directory, so there's no way to optimize the memory usage - * here by fixing up the directory any earlier than the - * end-of-archive. - * - * XXX TODO: Directory ACLs should be restored here, for the same - * reason we set directory perms here. XXX - */ -static int -_archive_write_disk_close(struct archive *_a) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - struct fixup_entry *next, *p; - int ret; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_disk_close"); - ret = _archive_write_disk_finish_entry(&a->archive); - - /* Sort dir list so directories are fixed up in depth-first order. */ - p = sort_dir_list(a->fixup_list); - - while (p != NULL) { - a->pst = NULL; /* Mark stat cache as out-of-date. */ - if (p->fixup & TODO_TIMES) { - set_times(a, -1, p->mode, p->name, - p->atime, p->atime_nanos, - p->birthtime, p->birthtime_nanos, - p->mtime, p->mtime_nanos, - p->ctime, p->ctime_nanos); - } - if (p->fixup & TODO_MODE_BASE) - chmod(p->name, p->mode); - if (p->fixup & TODO_ACLS) - archive_write_disk_set_acls(&a->archive, -1, p->name, - &p->acl, p->mode); - if (p->fixup & TODO_FFLAGS) - set_fflags_platform(a, -1, p->name, - p->mode, p->fflags_set, 0); - if (p->fixup & TODO_MAC_METADATA) - set_mac_metadata(a, p->name, p->mac_metadata, - p->mac_metadata_size); - next = p->next; - archive_acl_clear(&p->acl); - free(p->mac_metadata); - free(p->name); - free(p); - p = next; - } - a->fixup_list = NULL; - return (ret); -} - -static int -_archive_write_disk_free(struct archive *_a) -{ - struct archive_write_disk *a; - int ret; - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); - a = (struct archive_write_disk *)_a; - ret = _archive_write_disk_close(&a->archive); - archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); - archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); - if (a->entry) - archive_entry_free(a->entry); - archive_string_free(&a->_name_data); - archive_string_free(&a->archive.error_string); - archive_string_free(&a->path_safe); - a->archive.magic = 0; - __archive_clean(&a->archive); - free(a->decmpfs_header_p); - free(a->resource_fork); - free(a->compressed_buffer); - free(a->uncompressed_buffer); -#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ - && defined(HAVE_ZLIB_H) - if (a->stream_valid) { - switch (deflateEnd(&a->stream)) { - case Z_OK: - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Failed to clean up compressor"); - ret = ARCHIVE_FATAL; - break; - } - } -#endif - free(a); - return (ret); -} - -/* - * Simple O(n log n) merge sort to order the fixup list. In - * particular, we want to restore dir timestamps depth-first. - */ -static struct fixup_entry * -sort_dir_list(struct fixup_entry *p) -{ - struct fixup_entry *a, *b, *t; - - if (p == NULL) - return (NULL); - /* A one-item list is already sorted. */ - if (p->next == NULL) - return (p); - - /* Step 1: split the list. */ - t = p; - a = p->next->next; - while (a != NULL) { - /* Step a twice, t once. */ - a = a->next; - if (a != NULL) - a = a->next; - t = t->next; - } - /* Now, t is at the mid-point, so break the list here. */ - b = t->next; - t->next = NULL; - a = p; - - /* Step 2: Recursively sort the two sub-lists. */ - a = sort_dir_list(a); - b = sort_dir_list(b); - - /* Step 3: Merge the returned lists. */ - /* Pick the first element for the merged list. */ - if (strcmp(a->name, b->name) > 0) { - t = p = a; - a = a->next; - } else { - t = p = b; - b = b->next; - } - - /* Always put the later element on the list first. */ - while (a != NULL && b != NULL) { - if (strcmp(a->name, b->name) > 0) { - t->next = a; - a = a->next; - } else { - t->next = b; - b = b->next; - } - t = t->next; - } - - /* Only one list is non-empty, so just splice it on. */ - if (a != NULL) - t->next = a; - if (b != NULL) - t->next = b; - - return (p); -} - -/* - * Returns a new, initialized fixup entry. - * - * TODO: Reduce the memory requirements for this list by using a tree - * structure rather than a simple list of names. - */ -static struct fixup_entry * -new_fixup(struct archive_write_disk *a, const char *pathname) -{ - struct fixup_entry *fe; - - fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); - if (fe == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for a fixup"); - return (NULL); - } - fe->next = a->fixup_list; - a->fixup_list = fe; - fe->fixup = 0; - fe->name = strdup(pathname); - return (fe); -} - -/* - * Returns a fixup structure for the current entry. - */ -static struct fixup_entry * -current_fixup(struct archive_write_disk *a, const char *pathname) -{ - if (a->current_fixup == NULL) - a->current_fixup = new_fixup(a, pathname); - return (a->current_fixup); -} - -/* Error helper for new *_fsobj functions */ -static void -fsobj_error(int *a_eno, struct archive_string *a_estr, - int err, const char *errstr, const char *path) -{ - if (a_eno) - *a_eno = err; - if (a_estr) - archive_string_sprintf(a_estr, "%s%s", errstr, path); -} - -/* - * TODO: Someday, integrate this with the deep dir support; they both - * scan the path and both can be optimized by comparing against other - * recent paths. - */ -/* TODO: Extend this to support symlinks on Windows Vista and later. */ - -/* - * Checks the given path to see if any elements along it are symlinks. Returns - * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. - */ -static int -check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, - int flags) -{ -#if !defined(HAVE_LSTAT) - /* Platform doesn't have lstat, so we can't look for symlinks. */ - (void)path; /* UNUSED */ - (void)error_number; /* UNUSED */ - (void)error_string; /* UNUSED */ - (void)flags; /* UNUSED */ - return (ARCHIVE_OK); -#else - int res = ARCHIVE_OK; - char *tail; - char *head; - int last; - char c; - int r; - struct stat st; - int restore_pwd; - - /* Nothing to do here if name is empty */ - if(path[0] == '\0') - return (ARCHIVE_OK); - - /* - * Guard against symlink tricks. Reject any archive entry whose - * destination would be altered by a symlink. - * - * Walk the filename in chunks separated by '/'. For each segment: - * - if it doesn't exist, continue - * - if it's symlink, abort or remove it - * - if it's a directory and it's not the last chunk, cd into it - * As we go: - * head points to the current (relative) path - * tail points to the temporary \0 terminating the segment we're - * currently examining - * c holds what used to be in *tail - * last is 1 if this is the last tail - */ - restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(restore_pwd); - if (restore_pwd < 0) - return (ARCHIVE_FATAL); - head = path; - tail = path; - last = 0; - /* TODO: reintroduce a safe cache here? */ - /* Skip the root directory if the path is absolute. */ - if(tail == path && tail[0] == '/') - ++tail; - /* Keep going until we've checked the entire name. - * head, tail, path all alias the same string, which is - * temporarily zeroed at tail, so be careful restoring the - * stashed (c=tail[0]) for error messages. - * Exiting the loop with break is okay; continue is not. - */ - while (!last) { - /* - * Skip the separator we just consumed, plus any adjacent ones - */ - while (*tail == '/') - ++tail; - /* Skip the next path element. */ - while (*tail != '\0' && *tail != '/') - ++tail; - /* is this the last path component? */ - last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); - /* temporarily truncate the string here */ - c = tail[0]; - tail[0] = '\0'; - /* Check that we haven't hit a symlink. */ - r = lstat(head, &st); - if (r != 0) { - tail[0] = c; - /* We've hit a dir that doesn't exist; stop now. */ - if (errno == ENOENT) { - break; - } else { - /* - * Treat any other error as fatal - best to be - * paranoid here. - * Note: This effectively disables deep - * directory support when security checks are - * enabled. Otherwise, very long pathnames that - * trigger an error here could evade the - * sandbox. - * TODO: We could do better, but it would - * probably require merging the symlink checks - * with the deep-directory editing. - */ - fsobj_error(a_eno, a_estr, errno, - "Could not stat ", path); - res = ARCHIVE_FAILED; - break; - } - } else if (S_ISDIR(st.st_mode)) { - if (!last) { - if (chdir(head) != 0) { - tail[0] = c; - fsobj_error(a_eno, a_estr, errno, - "Could not chdir ", path); - res = (ARCHIVE_FATAL); - break; - } - /* Our view is now from inside this dir: */ - head = tail + 1; - } - } else if (S_ISLNK(st.st_mode)) { - if (last) { - /* - * Last element is symlink; remove it - * so we can overwrite it with the - * item being extracted. - */ - if (unlink(head)) { - tail[0] = c; - fsobj_error(a_eno, a_estr, errno, - "Could not remove symlink ", - path); - res = ARCHIVE_FAILED; - break; - } - /* - * Even if we did remove it, a warning - * is in order. The warning is silly, - * though, if we're just replacing one - * symlink with another symlink. - */ - tail[0] = c; - /* - * FIXME: not sure how important this is to - * restore - */ - /* - if (!S_ISLNK(path)) { - fsobj_error(a_eno, a_estr, 0, - "Removing symlink ", path); - } - */ - /* Symlink gone. No more problem! */ - res = ARCHIVE_OK; - break; - } else if (flags & ARCHIVE_EXTRACT_UNLINK) { - /* User asked us to remove problems. */ - if (unlink(head) != 0) { - tail[0] = c; - fsobj_error(a_eno, a_estr, 0, - "Cannot remove intervening " - "symlink ", path); - res = ARCHIVE_FAILED; - break; - } - tail[0] = c; - } else if ((flags & - ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) { - /* - * We are not the last element and we want to - * follow symlinks if they are a directory. - * - * This is needed to extract hardlinks over - * symlinks. - */ - r = stat(head, &st); - if (r != 0) { - tail[0] = c; - if (errno == ENOENT) { - break; - } else { - fsobj_error(a_eno, a_estr, - errno, - "Could not stat ", path); - res = (ARCHIVE_FAILED); - break; - } - } else if (S_ISDIR(st.st_mode)) { - if (chdir(head) != 0) { - tail[0] = c; - fsobj_error(a_eno, a_estr, - errno, - "Could not chdir ", path); - res = (ARCHIVE_FATAL); - break; - } - /* - * Our view is now from inside - * this dir: - */ - head = tail + 1; - } else { - tail[0] = c; - fsobj_error(a_eno, a_estr, 0, - "Cannot extract through " - "symlink ", path); - res = ARCHIVE_FAILED; - break; - } - } else { - tail[0] = c; - fsobj_error(a_eno, a_estr, 0, - "Cannot extract through symlink ", path); - res = ARCHIVE_FAILED; - break; - } - } - /* be sure to always maintain this */ - tail[0] = c; - if (tail[0] != '\0') - tail++; /* Advance to the next segment. */ - } - /* Catches loop exits via break */ - tail[0] = c; -#ifdef HAVE_FCHDIR - /* If we changed directory above, restore it here. */ - if (restore_pwd >= 0) { - r = fchdir(restore_pwd); - if (r != 0) { - fsobj_error(a_eno, a_estr, errno, - "chdir() failure", ""); - } - close(restore_pwd); - restore_pwd = -1; - if (r != 0) { - res = (ARCHIVE_FATAL); - } - } -#endif - /* TODO: reintroduce a safe cache here? */ - return res; -#endif -} - -/* - * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise - * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} - */ -static int -check_symlinks(struct archive_write_disk *a) -{ - struct archive_string error_string; - int error_number; - int rc; - archive_string_init(&error_string); - rc = check_symlinks_fsobj(a->name, &error_number, &error_string, - a->flags); - if (rc != ARCHIVE_OK) { - archive_set_error(&a->archive, error_number, "%s", - error_string.s); - } - archive_string_free(&error_string); - a->pst = NULL; /* to be safe */ - return rc; -} - - -#if defined(__CYGWIN__) -/* - * 1. Convert a path separator from '\' to '/' . - * We shouldn't check multibyte character directly because some - * character-set have been using the '\' character for a part of - * its multibyte character code. - * 2. Replace unusable characters in Windows with underscore('_'). - * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx - */ -static void -cleanup_pathname_win(char *path) -{ - wchar_t wc; - char *p; - size_t alen, l; - int mb, complete, utf8; - - alen = 0; - mb = 0; - complete = 1; - utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; - for (p = path; *p != '\0'; p++) { - ++alen; - if (*p == '\\') { - /* If previous byte is smaller than 128, - * this is not second byte of multibyte characters, - * so we can replace '\' with '/'. */ - if (utf8 || !mb) - *p = '/'; - else - complete = 0;/* uncompleted. */ - } else if (*(unsigned char *)p > 127) - mb = 1; - else - mb = 0; - /* Rewrite the path name if its next character is unusable. */ - if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || - *p == '<' || *p == '>' || *p == '|') - *p = '_'; - } - if (complete) - return; - - /* - * Convert path separator in wide-character. - */ - p = path; - while (*p != '\0' && alen) { - l = mbtowc(&wc, p, alen); - if (l == (size_t)-1) { - while (*p != '\0') { - if (*p == '\\') - *p = '/'; - ++p; - } - break; - } - if (l == 1 && wc == L'\\') - *p = '/'; - p += l; - alen -= l; - } -} -#endif - -/* - * Canonicalize the pathname. In particular, this strips duplicate - * '/' characters, '.' elements, and trailing '/'. It also raises an - * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is - * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS - * is set) if the path is absolute. - */ -static int -cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr, - int flags) -{ - char *dest, *src; - char separator = '\0'; - - dest = src = path; - if (*src == '\0') { - fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, - "Invalid empty ", "pathname"); - return (ARCHIVE_FAILED); - } - -#if defined(__CYGWIN__) - cleanup_pathname_win(path); -#endif - /* Skip leading '/'. */ - if (*src == '/') { - if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { - fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, - "Path is ", "absolute"); - return (ARCHIVE_FAILED); - } - - separator = *src++; - } - - /* Scan the pathname one element at a time. */ - for (;;) { - /* src points to first char after '/' */ - if (src[0] == '\0') { - break; - } else if (src[0] == '/') { - /* Found '//', ignore second one. */ - src++; - continue; - } else if (src[0] == '.') { - if (src[1] == '\0') { - /* Ignore trailing '.' */ - break; - } else if (src[1] == '/') { - /* Skip './'. */ - src += 2; - continue; - } else if (src[1] == '.') { - if (src[2] == '/' || src[2] == '\0') { - /* Conditionally warn about '..' */ - if (flags - & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { - fsobj_error(a_eno, a_estr, - ARCHIVE_ERRNO_MISC, - "Path contains ", "'..'"); - return (ARCHIVE_FAILED); - } - } - /* - * Note: Under no circumstances do we - * remove '..' elements. In - * particular, restoring - * '/foo/../bar/' should create the - * 'foo' dir as a side-effect. - */ - } - } - - /* Copy current element, including leading '/'. */ - if (separator) - *dest++ = '/'; - while (*src != '\0' && *src != '/') { - *dest++ = *src++; - } - - if (*src == '\0') - break; - - /* Skip '/' separator. */ - separator = *src++; - } - /* - * We've just copied zero or more path elements, not including the - * final '/'. - */ - if (dest == path) { - /* - * Nothing got copied. The path must have been something - * like '.' or '/' or './' or '/././././/./'. - */ - if (separator) - *dest++ = '/'; - else - *dest++ = '.'; - } - /* Terminate the result. */ - *dest = '\0'; - return (ARCHIVE_OK); -} - -static int -cleanup_pathname(struct archive_write_disk *a) -{ - struct archive_string error_string; - int error_number; - int rc; - archive_string_init(&error_string); - rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, - a->flags); - if (rc != ARCHIVE_OK) { - archive_set_error(&a->archive, error_number, "%s", - error_string.s); - } - archive_string_free(&error_string); - return rc; -} - -/* - * Create the parent directory of the specified path, assuming path - * is already in mutable storage. - */ -static int -create_parent_dir(struct archive_write_disk *a, char *path) -{ - char *slash; - int r; - - /* Remove tail element to obtain parent name. */ - slash = strrchr(path, '/'); - if (slash == NULL) - return (ARCHIVE_OK); - *slash = '\0'; - r = create_dir(a, path); - *slash = '/'; - return (r); -} - -/* - * Create the specified dir, recursing to create parents as necessary. - * - * Returns ARCHIVE_OK if the path exists when we're done here. - * Otherwise, returns ARCHIVE_FAILED. - * Assumes path is in mutable storage; path is unchanged on exit. - */ -static int -create_dir(struct archive_write_disk *a, char *path) -{ - struct stat st; - struct fixup_entry *le; - char *slash, *base; - mode_t mode_final, mode; - int r; - - /* Check for special names and just skip them. */ - slash = strrchr(path, '/'); - if (slash == NULL) - base = path; - else - base = slash + 1; - - if (base[0] == '\0' || - (base[0] == '.' && base[1] == '\0') || - (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { - /* Don't bother trying to create null path, '.', or '..'. */ - if (slash != NULL) { - *slash = '\0'; - r = create_dir(a, path); - *slash = '/'; - return (r); - } - return (ARCHIVE_OK); - } - - /* - * Yes, this should be stat() and not lstat(). Using lstat() - * here loses the ability to extract through symlinks. Also note - * that this should not use the a->st cache. - */ - if (stat(path, &st) == 0) { - if (S_ISDIR(st.st_mode)) - return (ARCHIVE_OK); - if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { - archive_set_error(&a->archive, EEXIST, - "Can't create directory '%s'", path); - return (ARCHIVE_FAILED); - } - if (unlink(path) != 0) { - archive_set_error(&a->archive, errno, - "Can't create directory '%s': " - "Conflicting file cannot be removed", - path); - return (ARCHIVE_FAILED); - } - } else if (errno != ENOENT && errno != ENOTDIR) { - /* Stat failed? */ - archive_set_error(&a->archive, errno, - "Can't test directory '%s'", path); - return (ARCHIVE_FAILED); - } else if (slash != NULL) { - *slash = '\0'; - r = create_dir(a, path); - *slash = '/'; - if (r != ARCHIVE_OK) - return (r); - } - - /* - * Mode we want for the final restored directory. Per POSIX, - * implicitly-created dirs must be created obeying the umask. - * There's no mention whether this is different for privileged - * restores (which the rest of this code handles by pretending - * umask=0). I've chosen here to always obey the user's umask for - * implicit dirs, even if _EXTRACT_PERM was specified. - */ - mode_final = DEFAULT_DIR_MODE & ~a->user_umask; - /* Mode we want on disk during the restore process. */ - mode = mode_final; - mode |= MINIMUM_DIR_MODE; - mode &= MAXIMUM_DIR_MODE; - if (mkdir(path, mode) == 0) { - if (mode != mode_final) { - le = new_fixup(a, path); - if (le == NULL) - return (ARCHIVE_FATAL); - le->fixup |=TODO_MODE_BASE; - le->mode = mode_final; - } - return (ARCHIVE_OK); - } - - /* - * Without the following check, a/b/../b/c/d fails at the - * second visit to 'b', so 'd' can't be created. Note that we - * don't add it to the fixup list here, as it's already been - * added. - */ - if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) - return (ARCHIVE_OK); - - archive_set_error(&a->archive, errno, "Failed to create dir '%s'", - path); - return (ARCHIVE_FAILED); -} - -/* - * Note: Although we can skip setting the user id if the desired user - * id matches the current user, we cannot skip setting the group, as - * many systems set the gid based on the containing directory. So - * we have to perform a chown syscall if we want to set the SGID - * bit. (The alternative is to stat() and then possibly chown(); it's - * more efficient to skip the stat() and just always chown().) Note - * that a successful chown() here clears the TODO_SGID_CHECK bit, which - * allows set_mode to skip the stat() check for the GID. - */ -static int -set_ownership(struct archive_write_disk *a) -{ -#ifndef __CYGWIN__ -/* unfortunately, on win32 there is no 'root' user with uid 0, - so we just have to try the chown and see if it works */ - - /* If we know we can't change it, don't bother trying. */ - if (a->user_uid != 0 && a->user_uid != a->uid) { - archive_set_error(&a->archive, errno, - "Can't set UID=%jd", (intmax_t)a->uid); - return (ARCHIVE_WARN); - } -#endif - -#ifdef HAVE_FCHOWN - /* If we have an fd, we can avoid a race. */ - if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { - /* We've set owner and know uid/gid are correct. */ - a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); - return (ARCHIVE_OK); - } -#endif - - /* We prefer lchown() but will use chown() if that's all we have. */ - /* Of course, if we have neither, this will always fail. */ -#ifdef HAVE_LCHOWN - if (lchown(a->name, a->uid, a->gid) == 0) { - /* We've set owner and know uid/gid are correct. */ - a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); - return (ARCHIVE_OK); - } -#elif HAVE_CHOWN - if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { - /* We've set owner and know uid/gid are correct. */ - a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); - return (ARCHIVE_OK); - } -#endif - - archive_set_error(&a->archive, errno, - "Can't set user=%jd/group=%jd for %s", - (intmax_t)a->uid, (intmax_t)a->gid, a->name); - return (ARCHIVE_WARN); -} - -/* - * Note: Returns 0 on success, non-zero on failure. - */ -static int -set_time(int fd, int mode, const char *name, - time_t atime, long atime_nsec, - time_t mtime, long mtime_nsec) -{ - /* Select the best implementation for this platform. */ -#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) - /* - * utimensat() and futimens() are defined in - * POSIX.1-2008. They support ns resolution and setting times - * on fds and symlinks. - */ - struct timespec ts[2]; - (void)mode; /* UNUSED */ - ts[0].tv_sec = atime; - ts[0].tv_nsec = atime_nsec; - ts[1].tv_sec = mtime; - ts[1].tv_nsec = mtime_nsec; - if (fd >= 0) - return futimens(fd, ts); - return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); - -#elif HAVE_UTIMES - /* - * The utimes()-family functions support µs-resolution and - * setting times fds and symlinks. utimes() is documented as - * LEGACY by POSIX, futimes() and lutimes() are not described - * in POSIX. - */ - struct timeval times[2]; - - times[0].tv_sec = atime; - times[0].tv_usec = atime_nsec / 1000; - times[1].tv_sec = mtime; - times[1].tv_usec = mtime_nsec / 1000; - -#ifdef HAVE_FUTIMES - if (fd >= 0) - return (futimes(fd, times)); -#else - (void)fd; /* UNUSED */ -#endif -#ifdef HAVE_LUTIMES - (void)mode; /* UNUSED */ - return (lutimes(name, times)); -#else - if (S_ISLNK(mode)) - return (0); - return (utimes(name, times)); -#endif - -#elif defined(HAVE_UTIME) - /* - * utime() is POSIX-standard but only supports 1s resolution and - * does not support fds or symlinks. - */ - struct utimbuf times; - (void)fd; /* UNUSED */ - (void)name; /* UNUSED */ - (void)atime_nsec; /* UNUSED */ - (void)mtime_nsec; /* UNUSED */ - times.actime = atime; - times.modtime = mtime; - if (S_ISLNK(mode)) - return (ARCHIVE_OK); - return (utime(name, ×)); - -#else - /* - * We don't know how to set the time on this platform. - */ - (void)fd; /* UNUSED */ - (void)mode; /* UNUSED */ - (void)name; /* UNUSED */ - (void)atime_nsec; /* UNUSED */ - (void)mtime_nsec; /* UNUSED */ - return (ARCHIVE_WARN); -#endif -} - -#ifdef F_SETTIMES -static int -set_time_tru64(int fd, int mode, const char *name, - time_t atime, long atime_nsec, - time_t mtime, long mtime_nsec, - time_t ctime, long ctime_nsec) -{ - struct attr_timbuf tstamp; - tstamp.atime.tv_sec = atime; - tstamp.mtime.tv_sec = mtime; - tstamp.ctime.tv_sec = ctime; -#if defined (__hpux) && defined (__ia64) - tstamp.atime.tv_nsec = atime_nsec; - tstamp.mtime.tv_nsec = mtime_nsec; - tstamp.ctime.tv_nsec = ctime_nsec; -#else - tstamp.atime.tv_usec = atime_nsec / 1000; - tstamp.mtime.tv_usec = mtime_nsec / 1000; - tstamp.ctime.tv_usec = ctime_nsec / 1000; -#endif - return (fcntl(fd,F_SETTIMES,&tstamp)); -} -#endif /* F_SETTIMES */ - -static int -set_times(struct archive_write_disk *a, - int fd, int mode, const char *name, - time_t atime, long atime_nanos, - time_t birthtime, long birthtime_nanos, - time_t mtime, long mtime_nanos, - time_t cctime, long ctime_nanos) -{ - /* Note: set_time doesn't use libarchive return conventions! - * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ - int r1 = 0, r2 = 0; - -#ifdef F_SETTIMES - /* - * on Tru64 try own fcntl first which can restore even the - * ctime, fall back to default code path below if it fails - * or if we are not running as root - */ - if (a->user_uid == 0 && - set_time_tru64(fd, mode, name, - atime, atime_nanos, mtime, - mtime_nanos, cctime, ctime_nanos) == 0) { - return (ARCHIVE_OK); - } -#else /* Tru64 */ - (void)cctime; /* UNUSED */ - (void)ctime_nanos; /* UNUSED */ -#endif /* Tru64 */ - -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME - /* - * If you have struct stat.st_birthtime, we assume BSD - * birthtime semantics, in which {f,l,}utimes() updates - * birthtime to earliest mtime. So we set the time twice, - * first using the birthtime, then using the mtime. If - * birthtime == mtime, this isn't necessary, so we skip it. - * If birthtime > mtime, then this won't work, so we skip it. - */ - if (birthtime < mtime - || (birthtime == mtime && birthtime_nanos < mtime_nanos)) - r1 = set_time(fd, mode, name, - atime, atime_nanos, - birthtime, birthtime_nanos); -#else - (void)birthtime; /* UNUSED */ - (void)birthtime_nanos; /* UNUSED */ -#endif - r2 = set_time(fd, mode, name, - atime, atime_nanos, - mtime, mtime_nanos); - if (r1 != 0 || r2 != 0) { - archive_set_error(&a->archive, errno, - "Can't restore time"); - return (ARCHIVE_WARN); - } - return (ARCHIVE_OK); -} - -static int -set_times_from_entry(struct archive_write_disk *a) -{ - time_t atime, birthtime, mtime, cctime; - long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; - - /* Suitable defaults. */ - atime = birthtime = mtime = cctime = a->start_time; - atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; - - /* If no time was provided, we're done. */ - if (!archive_entry_atime_is_set(a->entry) -#if HAVE_STRUCT_STAT_ST_BIRTHTIME - && !archive_entry_birthtime_is_set(a->entry) -#endif - && !archive_entry_mtime_is_set(a->entry)) - return (ARCHIVE_OK); - - if (archive_entry_atime_is_set(a->entry)) { - atime = archive_entry_atime(a->entry); - atime_nsec = archive_entry_atime_nsec(a->entry); - } - if (archive_entry_birthtime_is_set(a->entry)) { - birthtime = archive_entry_birthtime(a->entry); - birthtime_nsec = archive_entry_birthtime_nsec(a->entry); - } - if (archive_entry_mtime_is_set(a->entry)) { - mtime = archive_entry_mtime(a->entry); - mtime_nsec = archive_entry_mtime_nsec(a->entry); - } - if (archive_entry_ctime_is_set(a->entry)) { - cctime = archive_entry_ctime(a->entry); - ctime_nsec = archive_entry_ctime_nsec(a->entry); - } - - return set_times(a, a->fd, a->mode, a->name, - atime, atime_nsec, - birthtime, birthtime_nsec, - mtime, mtime_nsec, - cctime, ctime_nsec); -} - -static int -set_mode(struct archive_write_disk *a, int mode) -{ - int r = ARCHIVE_OK; - mode &= 07777; /* Strip off file type bits. */ - - if (a->todo & TODO_SGID_CHECK) { - /* - * If we don't know the GID is right, we must stat() - * to verify it. We can't just check the GID of this - * process, since systems sometimes set GID from - * the enclosing dir or based on ACLs. - */ - if ((r = lazy_stat(a)) != ARCHIVE_OK) - return (r); - if (a->pst->st_gid != a->gid) { - mode &= ~ S_ISGID; - if (a->flags & ARCHIVE_EXTRACT_OWNER) { - /* - * This is only an error if you - * requested owner restore. If you - * didn't, we'll try to restore - * sgid/suid, but won't consider it a - * problem if we can't. - */ - archive_set_error(&a->archive, -1, - "Can't restore SGID bit"); - r = ARCHIVE_WARN; - } - } - /* While we're here, double-check the UID. */ - if (a->pst->st_uid != a->uid - && (a->todo & TODO_SUID)) { - mode &= ~ S_ISUID; - if (a->flags & ARCHIVE_EXTRACT_OWNER) { - archive_set_error(&a->archive, -1, - "Can't restore SUID bit"); - r = ARCHIVE_WARN; - } - } - a->todo &= ~TODO_SGID_CHECK; - a->todo &= ~TODO_SUID_CHECK; - } else if (a->todo & TODO_SUID_CHECK) { - /* - * If we don't know the UID is right, we can just check - * the user, since all systems set the file UID from - * the process UID. - */ - if (a->user_uid != a->uid) { - mode &= ~ S_ISUID; - if (a->flags & ARCHIVE_EXTRACT_OWNER) { - archive_set_error(&a->archive, -1, - "Can't make file SUID"); - r = ARCHIVE_WARN; - } - } - a->todo &= ~TODO_SUID_CHECK; - } - - if (S_ISLNK(a->mode)) { -#ifdef HAVE_LCHMOD - /* - * If this is a symlink, use lchmod(). If the - * platform doesn't support lchmod(), just skip it. A - * platform that doesn't provide a way to set - * permissions on symlinks probably ignores - * permissions on symlinks, so a failure here has no - * impact. - */ - if (lchmod(a->name, mode) != 0) { - switch (errno) { - case ENOTSUP: - case ENOSYS: -#if ENOTSUP != EOPNOTSUPP - case EOPNOTSUPP: -#endif - /* - * if lchmod is defined but the platform - * doesn't support it, silently ignore - * error - */ - break; - default: - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } - } -#endif - } else if (!S_ISDIR(a->mode)) { - /* - * If it's not a symlink and not a dir, then use - * fchmod() or chmod(), depending on whether we have - * an fd. Dirs get their perms set during the - * post-extract fixup, which is handled elsewhere. - */ -#ifdef HAVE_FCHMOD - if (a->fd >= 0) { - if (fchmod(a->fd, mode) != 0) { - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } - } else -#endif - /* If this platform lacks fchmod(), then - * we'll just use chmod(). */ - if (chmod(a->name, mode) != 0) { - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } - } - return (r); -} - -static int -set_fflags(struct archive_write_disk *a) -{ - struct fixup_entry *le; - unsigned long set, clear; - int r; - int critical_flags; - mode_t mode = archive_entry_mode(a->entry); - - /* - * Make 'critical_flags' hold all file flags that can't be - * immediately restored. For example, on BSD systems, - * SF_IMMUTABLE prevents hardlinks from being created, so - * should not be set until after any hardlinks are created. To - * preserve some semblance of portability, this uses #ifdef - * extensively. Ugly, but it works. - * - * Yes, Virginia, this does create a security race. It's mitigated - * somewhat by the practice of creating dirs 0700 until the extract - * is done, but it would be nice if we could do more than that. - * People restoring critical file systems should be wary of - * other programs that might try to muck with files as they're - * being restored. - */ - /* Hopefully, the compiler will optimize this mess into a constant. */ - critical_flags = 0; -#ifdef SF_IMMUTABLE - critical_flags |= SF_IMMUTABLE; -#endif -#ifdef UF_IMMUTABLE - critical_flags |= UF_IMMUTABLE; -#endif -#ifdef SF_APPEND - critical_flags |= SF_APPEND; -#endif -#ifdef UF_APPEND - critical_flags |= UF_APPEND; -#endif -#if defined(FS_APPEND_FL) - critical_flags |= FS_APPEND_FL; -#elif defined(EXT2_APPEND_FL) - critical_flags |= EXT2_APPEND_FL; -#endif -#if defined(FS_IMMUTABLE_FL) - critical_flags |= FS_IMMUTABLE_FL; -#elif defined(EXT2_IMMUTABLE_FL) - critical_flags |= EXT2_IMMUTABLE_FL; -#endif -#ifdef FS_JOURNAL_DATA_FL - critical_flags |= FS_JOURNAL_DATA_FL; -#endif - - if (a->todo & TODO_FFLAGS) { - archive_entry_fflags(a->entry, &set, &clear); - - /* - * The first test encourages the compiler to eliminate - * all of this if it's not necessary. - */ - if ((critical_flags != 0) && (set & critical_flags)) { - le = current_fixup(a, a->name); - if (le == NULL) - return (ARCHIVE_FATAL); - le->fixup |= TODO_FFLAGS; - le->fflags_set = set; - /* Store the mode if it's not already there. */ - if ((le->fixup & TODO_MODE) == 0) - le->mode = mode; - } else { - r = set_fflags_platform(a, a->fd, - a->name, mode, set, clear); - if (r != ARCHIVE_OK) - return (r); - } - } - return (ARCHIVE_OK); -} - -static int -clear_nochange_fflags(struct archive_write_disk *a) -{ - int nochange_flags; - mode_t mode = archive_entry_mode(a->entry); - - /* Hopefully, the compiler will optimize this mess into a constant. */ - nochange_flags = 0; -#ifdef SF_IMMUTABLE - nochange_flags |= SF_IMMUTABLE; -#endif -#ifdef UF_IMMUTABLE - nochange_flags |= UF_IMMUTABLE; -#endif -#ifdef SF_APPEND - nochange_flags |= SF_APPEND; -#endif -#ifdef UF_APPEND - nochange_flags |= UF_APPEND; -#endif -#ifdef EXT2_APPEND_FL - nochange_flags |= EXT2_APPEND_FL; -#endif -#ifdef EXT2_IMMUTABLE_FL - nochange_flags |= EXT2_IMMUTABLE_FL; -#endif - - return (set_fflags_platform(a, a->fd, a->name, mode, 0, - nochange_flags)); -} - - -#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) -/* - * BSD reads flags using stat() and sets them with one of {f,l,}chflags() - */ -static int -set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, - mode_t mode, unsigned long set, unsigned long clear) -{ - int r; - - (void)mode; /* UNUSED */ - if (set == 0 && clear == 0) - return (ARCHIVE_OK); - - /* - * XXX Is the stat here really necessary? Or can I just use - * the 'set' flags directly? In particular, I'm not sure - * about the correct approach if we're overwriting an existing - * file that already has flags on it. XXX - */ - if ((r = lazy_stat(a)) != ARCHIVE_OK) - return (r); - - a->st.st_flags &= ~clear; - a->st.st_flags |= set; -#ifdef HAVE_FCHFLAGS - /* If platform has fchflags() and we were given an fd, use it. */ - if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) - return (ARCHIVE_OK); -#endif - /* - * If we can't use the fd to set the flags, we'll use the - * pathname to set flags. We prefer lchflags() but will use - * chflags() if we must. - */ -#ifdef HAVE_LCHFLAGS - if (lchflags(name, a->st.st_flags) == 0) - return (ARCHIVE_OK); -#elif defined(HAVE_CHFLAGS) - if (S_ISLNK(a->st.st_mode)) { - archive_set_error(&a->archive, errno, - "Can't set file flags on symlink."); - return (ARCHIVE_WARN); - } - if (chflags(name, a->st.st_flags) == 0) - return (ARCHIVE_OK); -#endif - archive_set_error(&a->archive, errno, - "Failed to set file flags"); - return (ARCHIVE_WARN); -} - -#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \ - defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ - (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \ - defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) -/* - * Linux uses ioctl() to read and write file flags. - */ -static int -set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, - mode_t mode, unsigned long set, unsigned long clear) -{ - int ret; - int myfd = fd; - int newflags, oldflags; - int sf_mask = 0; - - if (set == 0 && clear == 0) - return (ARCHIVE_OK); - /* Only regular files and dirs can have flags. */ - if (!S_ISREG(mode) && !S_ISDIR(mode)) - return (ARCHIVE_OK); - - /* If we weren't given an fd, open it ourselves. */ - if (myfd < 0) { - myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(myfd); - } - if (myfd < 0) - return (ARCHIVE_OK); - - /* - * Linux has no define for the flags that are only settable by - * the root user. This code may seem a little complex, but - * there seem to be some Linux systems that lack these - * defines. (?) The code below degrades reasonably gracefully - * if sf_mask is incomplete. - */ -#if defined(FS_IMMUTABLE_FL) - sf_mask |= FS_IMMUTABLE_FL; -#elif defined(EXT2_IMMUTABLE_FL) - sf_mask |= EXT2_IMMUTABLE_FL; -#endif -#if defined(FS_APPEND_FL) - sf_mask |= FS_APPEND_FL; -#elif defined(EXT2_APPEND_FL) - sf_mask |= EXT2_APPEND_FL; -#endif -#if defined(FS_JOURNAL_DATA_FL) - sf_mask |= FS_JOURNAL_DATA_FL; -#endif - /* - * XXX As above, this would be way simpler if we didn't have - * to read the current flags from disk. XXX - */ - ret = ARCHIVE_OK; - - /* Read the current file flags. */ - if (ioctl(myfd, -#ifdef FS_IOC_GETFLAGS - FS_IOC_GETFLAGS, -#else - EXT2_IOC_GETFLAGS, -#endif - &oldflags) < 0) - goto fail; - - /* Try setting the flags as given. */ - newflags = (oldflags & ~clear) | set; - if (ioctl(myfd, -#ifdef FS_IOC_SETFLAGS - FS_IOC_SETFLAGS, -#else - EXT2_IOC_SETFLAGS, -#endif - &newflags) >= 0) - goto cleanup; - if (errno != EPERM) - goto fail; - - /* If we couldn't set all the flags, try again with a subset. */ - newflags &= ~sf_mask; - oldflags &= sf_mask; - newflags |= oldflags; - if (ioctl(myfd, -#ifdef FS_IOC_SETFLAGS - FS_IOC_SETFLAGS, -#else - EXT2_IOC_SETFLAGS, -#endif - &newflags) >= 0) - goto cleanup; - - /* We couldn't set the flags, so report the failure. */ -fail: - archive_set_error(&a->archive, errno, - "Failed to set file flags"); - ret = ARCHIVE_WARN; -cleanup: - if (fd < 0) - close(myfd); - return (ret); -} - -#else - -/* - * Of course, some systems have neither BSD chflags() nor Linux' flags - * support through ioctl(). - */ -static int -set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, - mode_t mode, unsigned long set, unsigned long clear) -{ - (void)a; /* UNUSED */ - (void)fd; /* UNUSED */ - (void)name; /* UNUSED */ - (void)mode; /* UNUSED */ - (void)set; /* UNUSED */ - (void)clear; /* UNUSED */ - return (ARCHIVE_OK); -} - -#endif /* __linux */ - -#ifndef HAVE_COPYFILE_H -/* Default is to simply drop Mac extended metadata. */ -static int -set_mac_metadata(struct archive_write_disk *a, const char *pathname, - const void *metadata, size_t metadata_size) -{ - (void)a; /* UNUSED */ - (void)pathname; /* UNUSED */ - (void)metadata; /* UNUSED */ - (void)metadata_size; /* UNUSED */ - return (ARCHIVE_OK); -} - -static int -fixup_appledouble(struct archive_write_disk *a, const char *pathname) -{ - (void)a; /* UNUSED */ - (void)pathname; /* UNUSED */ - return (ARCHIVE_OK); -} -#else - -/* - * On Mac OS, we use copyfile() to unpack the metadata and - * apply it to the target file. - */ - -#if defined(HAVE_SYS_XATTR_H) -static int -copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) -{ - ssize_t xattr_size; - char *xattr_names = NULL, *xattr_val = NULL; - int ret = ARCHIVE_OK, xattr_i; - - xattr_size = flistxattr(tmpfd, NULL, 0, 0); - if (xattr_size == -1) { - archive_set_error(&a->archive, errno, - "Failed to read metadata(xattr)"); - ret = ARCHIVE_WARN; - goto exit_xattr; - } - xattr_names = malloc(xattr_size); - if (xattr_names == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for metadata(xattr)"); - ret = ARCHIVE_FATAL; - goto exit_xattr; - } - xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); - if (xattr_size == -1) { - archive_set_error(&a->archive, errno, - "Failed to read metadata(xattr)"); - ret = ARCHIVE_WARN; - goto exit_xattr; - } - for (xattr_i = 0; xattr_i < xattr_size; - xattr_i += strlen(xattr_names + xattr_i) + 1) { - char *xattr_val_saved; - ssize_t s; - int f; - - s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); - if (s == -1) { - archive_set_error(&a->archive, errno, - "Failed to get metadata(xattr)"); - ret = ARCHIVE_WARN; - goto exit_xattr; - } - xattr_val_saved = xattr_val; - xattr_val = realloc(xattr_val, s); - if (xattr_val == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Failed to get metadata(xattr)"); - ret = ARCHIVE_WARN; - free(xattr_val_saved); - goto exit_xattr; - } - s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); - if (s == -1) { - archive_set_error(&a->archive, errno, - "Failed to get metadata(xattr)"); - ret = ARCHIVE_WARN; - goto exit_xattr; - } - f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); - if (f == -1) { - archive_set_error(&a->archive, errno, - "Failed to get metadata(xattr)"); - ret = ARCHIVE_WARN; - goto exit_xattr; - } - } -exit_xattr: - free(xattr_names); - free(xattr_val); - return (ret); -} -#endif - -static int -copy_acls(struct archive_write_disk *a, int tmpfd, int dffd) -{ -#ifndef HAVE_SYS_ACL_H - return 0; -#else - acl_t acl, dfacl = NULL; - int acl_r, ret = ARCHIVE_OK; - - acl = acl_get_fd(tmpfd); - if (acl == NULL) { - if (errno == ENOENT) - /* There are not any ACLs. */ - return (ret); - archive_set_error(&a->archive, errno, - "Failed to get metadata(acl)"); - ret = ARCHIVE_WARN; - goto exit_acl; - } - dfacl = acl_dup(acl); - acl_r = acl_set_fd(dffd, dfacl); - if (acl_r == -1) { - archive_set_error(&a->archive, errno, - "Failed to get metadata(acl)"); - ret = ARCHIVE_WARN; - goto exit_acl; - } -exit_acl: - if (acl) - acl_free(acl); - if (dfacl) - acl_free(dfacl); - return (ret); -#endif -} - -static int -create_tempdatafork(struct archive_write_disk *a, const char *pathname) -{ - struct archive_string tmpdatafork; - int tmpfd; - - archive_string_init(&tmpdatafork); - archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); - tmpfd = mkstemp(tmpdatafork.s); - if (tmpfd < 0) { - archive_set_error(&a->archive, errno, - "Failed to mkstemp"); - archive_string_free(&tmpdatafork); - return (-1); - } - if (copyfile(pathname, tmpdatafork.s, 0, - COPYFILE_UNPACK | COPYFILE_NOFOLLOW - | COPYFILE_ACL | COPYFILE_XATTR) < 0) { - archive_set_error(&a->archive, errno, - "Failed to restore metadata"); - close(tmpfd); - tmpfd = -1; - } - unlink(tmpdatafork.s); - archive_string_free(&tmpdatafork); - return (tmpfd); -} - -static int -copy_metadata(struct archive_write_disk *a, const char *metadata, - const char *datafork, int datafork_compressed) -{ - int ret = ARCHIVE_OK; - - if (datafork_compressed) { - int dffd, tmpfd; - - tmpfd = create_tempdatafork(a, metadata); - if (tmpfd == -1) - return (ARCHIVE_WARN); - - /* - * Do not open the data fork compressed by HFS+ compression - * with at least a writing mode(O_RDWR or O_WRONLY). it - * makes the data fork uncompressed. - */ - dffd = open(datafork, 0); - if (dffd == -1) { - archive_set_error(&a->archive, errno, - "Failed to open the data fork for metadata"); - close(tmpfd); - return (ARCHIVE_WARN); - } - -#if defined(HAVE_SYS_XATTR_H) - ret = copy_xattrs(a, tmpfd, dffd); - if (ret == ARCHIVE_OK) -#endif - ret = copy_acls(a, tmpfd, dffd); - close(tmpfd); - close(dffd); - } else { - if (copyfile(metadata, datafork, 0, - COPYFILE_UNPACK | COPYFILE_NOFOLLOW - | COPYFILE_ACL | COPYFILE_XATTR) < 0) { - archive_set_error(&a->archive, errno, - "Failed to restore metadata"); - ret = ARCHIVE_WARN; - } - } - return (ret); -} - -static int -set_mac_metadata(struct archive_write_disk *a, const char *pathname, - const void *metadata, size_t metadata_size) -{ - struct archive_string tmp; - ssize_t written; - int fd; - int ret = ARCHIVE_OK; - - /* This would be simpler if copyfile() could just accept the - * metadata as a block of memory; then we could sidestep this - * silly dance of writing the data to disk just so that - * copyfile() can read it back in again. */ - archive_string_init(&tmp); - archive_strcpy(&tmp, pathname); - archive_strcat(&tmp, ".XXXXXX"); - fd = mkstemp(tmp.s); - - if (fd < 0) { - archive_set_error(&a->archive, errno, - "Failed to restore metadata"); - archive_string_free(&tmp); - return (ARCHIVE_WARN); - } - written = write(fd, metadata, metadata_size); - close(fd); - if ((size_t)written != metadata_size) { - archive_set_error(&a->archive, errno, - "Failed to restore metadata"); - ret = ARCHIVE_WARN; - } else { - int compressed; - -#if defined(UF_COMPRESSED) - if ((a->todo & TODO_HFS_COMPRESSION) != 0 && - (ret = lazy_stat(a)) == ARCHIVE_OK) - compressed = a->st.st_flags & UF_COMPRESSED; - else -#endif - compressed = 0; - ret = copy_metadata(a, tmp.s, pathname, compressed); - } - unlink(tmp.s); - archive_string_free(&tmp); - return (ret); -} - -static int -fixup_appledouble(struct archive_write_disk *a, const char *pathname) -{ - char buff[8]; - struct stat st; - const char *p; - struct archive_string datafork; - int fd = -1, ret = ARCHIVE_OK; - - archive_string_init(&datafork); - /* Check if the current file name is a type of the resource - * fork file. */ - p = strrchr(pathname, '/'); - if (p == NULL) - p = pathname; - else - p++; - if (p[0] != '.' || p[1] != '_') - goto skip_appledouble; - - /* - * Check if the data fork file exists. - * - * TODO: Check if this write disk object has handled it. - */ - archive_strncpy(&datafork, pathname, p - pathname); - archive_strcat(&datafork, p + 2); - if (lstat(datafork.s, &st) == -1 || - (st.st_mode & AE_IFMT) != AE_IFREG) - goto skip_appledouble; - - /* - * Check if the file is in the AppleDouble form. - */ - fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(fd); - if (fd == -1) { - archive_set_error(&a->archive, errno, - "Failed to open a restoring file"); - ret = ARCHIVE_WARN; - goto skip_appledouble; - } - if (read(fd, buff, 8) == -1) { - archive_set_error(&a->archive, errno, - "Failed to read a restoring file"); - close(fd); - ret = ARCHIVE_WARN; - goto skip_appledouble; - } - close(fd); - /* Check AppleDouble Magic Code. */ - if (archive_be32dec(buff) != 0x00051607) - goto skip_appledouble; - /* Check AppleDouble Version. */ - if (archive_be32dec(buff+4) != 0x00020000) - goto skip_appledouble; - - ret = copy_metadata(a, pathname, datafork.s, -#if defined(UF_COMPRESSED) - st.st_flags & UF_COMPRESSED); -#else - 0); -#endif - if (ret == ARCHIVE_OK) { - unlink(pathname); - ret = ARCHIVE_EOF; - } -skip_appledouble: - archive_string_free(&datafork); - return (ret); -} -#endif - -#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX -/* - * Restore extended attributes - Linux, Darwin and AIX implementations: - * AIX' ea interface is syntaxwise identical to the Linux xattr interface. - */ -static int -set_xattrs(struct archive_write_disk *a) -{ - struct archive_entry *entry = a->entry; - struct archive_string errlist; - int ret = ARCHIVE_OK; - int i = archive_entry_xattr_reset(entry); - short fail = 0; - - archive_string_init(&errlist); - - while (i--) { - const char *name; - const void *value; - size_t size; - int e; - - archive_entry_xattr_next(entry, &name, &value, &size); - - if (name == NULL) - continue; -#if ARCHIVE_XATTR_LINUX - /* Linux: quietly skip POSIX.1e ACL extended attributes */ - if (strncmp(name, "system.", 7) == 0 && - (strcmp(name + 7, "posix_acl_access") == 0 || - strcmp(name + 7, "posix_acl_default") == 0)) - continue; - if (strncmp(name, "trusted.SGI_", 12) == 0 && - (strcmp(name + 12, "ACL_DEFAULT") == 0 || - strcmp(name + 12, "ACL_FILE") == 0)) - continue; - - /* Linux: xfsroot namespace is obsolete and unsupported */ - if (strncmp(name, "xfsroot.", 8) == 0) { - fail = 1; - archive_strcat(&errlist, name); - archive_strappend_char(&errlist, ' '); - continue; - } -#endif - - if (a->fd >= 0) { -#if ARCHIVE_XATTR_LINUX - e = fsetxattr(a->fd, name, value, size, 0); -#elif ARCHIVE_XATTR_DARWIN - e = fsetxattr(a->fd, name, value, size, 0, 0); -#elif ARCHIVE_XATTR_AIX - e = fsetea(a->fd, name, value, size, 0); -#endif - } else { -#if ARCHIVE_XATTR_LINUX - e = lsetxattr(archive_entry_pathname(entry), - name, value, size, 0); -#elif ARCHIVE_XATTR_DARWIN - e = setxattr(archive_entry_pathname(entry), - name, value, size, 0, XATTR_NOFOLLOW); -#elif ARCHIVE_XATTR_AIX - e = lsetea(archive_entry_pathname(entry), - name, value, size, 0); -#endif - } - if (e == -1) { - ret = ARCHIVE_WARN; - archive_strcat(&errlist, name); - archive_strappend_char(&errlist, ' '); - if (errno != ENOTSUP && errno != ENOSYS) - fail = 1; - } - } - - if (ret == ARCHIVE_WARN) { - if (fail && errlist.length > 0) { - errlist.length--; - errlist.s[errlist.length] = '\0'; - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Cannot restore extended attributes: %s", - errlist.s); - } else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Cannot restore extended " - "attributes on this file system."); - } - - archive_string_free(&errlist); - return (ret); -} -#elif ARCHIVE_XATTR_FREEBSD -/* - * Restore extended attributes - FreeBSD implementation - */ -static int -set_xattrs(struct archive_write_disk *a) -{ - struct archive_entry *entry = a->entry; - struct archive_string errlist; - int ret = ARCHIVE_OK; - int i = archive_entry_xattr_reset(entry); - short fail = 0; - - archive_string_init(&errlist); - - while (i--) { - const char *name; - const void *value; - size_t size; - archive_entry_xattr_next(entry, &name, &value, &size); - if (name != NULL) { - int e; - int namespace; - - if (strncmp(name, "user.", 5) == 0) { - /* "user." attributes go to user namespace */ - name += 5; - namespace = EXTATTR_NAMESPACE_USER; - } else { - /* Other namespaces are unsupported */ - archive_strcat(&errlist, name); - archive_strappend_char(&errlist, ' '); - fail = 1; - ret = ARCHIVE_WARN; - continue; - } - - if (a->fd >= 0) { - e = extattr_set_fd(a->fd, namespace, name, - value, size); - } else { - e = extattr_set_link( - archive_entry_pathname(entry), namespace, - name, value, size); - } - if (e != (int)size) { - archive_strcat(&errlist, name); - archive_strappend_char(&errlist, ' '); - ret = ARCHIVE_WARN; - if (errno != ENOTSUP && errno != ENOSYS) - fail = 1; - } - } - } - - if (ret == ARCHIVE_WARN) { - if (fail && errlist.length > 0) { - errlist.length--; - errlist.s[errlist.length] = '\0'; - - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Cannot restore extended attributes: %s", - errlist.s); - } else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Cannot restore extended " - "attributes on this file system."); - } - - archive_string_free(&errlist); - return (ret); -} -#else -/* - * Restore extended attributes - stub implementation for unsupported systems - */ -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; - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Cannot restore extended attributes on this system"); - return (ARCHIVE_WARN); - } - /* Warning was already emitted; suppress further warnings. */ - return (ARCHIVE_OK); -} -#endif - -/* - * Test if file on disk is older than entry. - */ -static int -older(struct stat *st, struct archive_entry *entry) -{ - /* First, test the seconds and return if we have a definite answer. */ - /* Definitely older. */ - if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry))) - return (1); - /* Definitely younger. */ - if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry))) - return (0); - /* If this platform supports fractional seconds, try those. */ -#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC - /* Definitely older. */ - if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) - return (1); -#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - /* Definitely older. */ - if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) - return (1); -#elif HAVE_STRUCT_STAT_ST_MTIME_N - /* older. */ - if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) - return (1); -#elif HAVE_STRUCT_STAT_ST_UMTIME - /* older. */ - if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) - return (1); -#elif HAVE_STRUCT_STAT_ST_MTIME_USEC - /* older. */ - if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) - return (1); -#else - /* This system doesn't have high-res timestamps. */ -#endif - /* Same age or newer, so not older. */ - return (0); -} - -#ifndef ARCHIVE_ACL_SUPPORT -int -archive_write_disk_set_acls(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl, __LA_MODE_T mode) -{ - (void)a; /* UNUSED */ - (void)fd; /* UNUSED */ - (void)name; /* UNUSED */ - (void)abstract_acl; /* UNUSED */ - (void)mode; /* UNUSED */ - return (ARCHIVE_OK); -} -#endif - -#endif /* !_WIN32 || __CYGWIN__ */ - diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_private.h b/3rdparty/libarchive/libarchive/archive_write_disk_private.h deleted file mode 100644 index b655dea2..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_disk_private.h +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_write_disk_private.h 201086 2009-12-28 02:17:53Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED -#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED - -#include "archive_platform_acl.h" -#include "archive_acl_private.h" -#include "archive_entry.h" - -struct archive_write_disk; - -int archive_write_disk_set_acls(struct archive *, int, const char *, - struct archive_acl *, __LA_MODE_T); - -#endif diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c b/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c deleted file mode 100644 index 5c766d75..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c +++ /dev/null @@ -1,265 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk_set_standard_lookup.c 201083 2009-12-28 02:09:57Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" -#include "archive_write_disk_private.h" - -struct bucket { - char *name; - int hash; - id_t id; -}; - -static const size_t cache_size = 127; -static unsigned int hash(const char *); -static int64_t lookup_gid(void *, const char *uname, int64_t); -static int64_t lookup_uid(void *, const char *uname, int64_t); -static void cleanup(void *); - -/* - * Installs functions that use getpwnam()/getgrnam()---along with - * a simple cache to accelerate such lookups---into the archive_write_disk - * object. This is in a separate file because getpwnam()/getgrnam() - * can pull in a LOT of library code (including NIS/LDAP functions, which - * pull in DNS resolvers, etc). This can easily top 500kB, which makes - * it inappropriate for some space-constrained applications. - * - * Applications that are size-sensitive may want to just use the - * real default functions (defined in archive_write_disk.c) that just - * use the uid/gid without the lookup. Or define your own custom functions - * if you prefer. - * - * TODO: Replace these hash tables with simpler move-to-front LRU - * lists with a bounded size (128 items?). The hash is a bit faster, - * but has a bad pathology in which it thrashes a single bucket. Even - * walking a list of 128 items is a lot faster than calling - * getpwnam()! - */ -int -archive_write_disk_set_standard_lookup(struct archive *a) -{ - struct bucket *ucache = calloc(cache_size, sizeof(struct bucket)); - struct bucket *gcache = calloc(cache_size, sizeof(struct bucket)); - if (ucache == NULL || gcache == NULL) { - free(ucache); - free(gcache); - return (ARCHIVE_FATAL); - } - archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup); - archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup); - return (ARCHIVE_OK); -} - -static int64_t -lookup_gid(void *private_data, const char *gname, int64_t gid) -{ - int h; - struct bucket *b; - struct bucket *gcache = (struct bucket *)private_data; - - /* If no gname, just use the gid provided. */ - if (gname == NULL || *gname == '\0') - return (gid); - - /* Try to find gname in the cache. */ - h = hash(gname); - b = &gcache[h % cache_size ]; - if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0) - return ((gid_t)b->id); - - /* Free the cache slot for a new entry. */ - if (b->name != NULL) - free(b->name); - b->name = strdup(gname); - /* Note: If strdup fails, that's okay; we just won't cache. */ - b->hash = h; -#if HAVE_GRP_H -# if HAVE_GETGRNAM_R - { - char _buffer[128]; - size_t bufsize = 128; - char *buffer = _buffer; - char *allocated = NULL; - struct group grent, *result; - int r; - - for (;;) { - result = &grent; /* Old getgrnam_r ignores last arg. */ - r = getgrnam_r(gname, &grent, buffer, bufsize, &result); - if (r == 0) - break; - if (r != ERANGE) - break; - bufsize *= 2; - free(allocated); - allocated = malloc(bufsize); - if (allocated == NULL) - break; - buffer = allocated; - } - if (result != NULL) - gid = result->gr_gid; - free(allocated); - } -# else /* HAVE_GETGRNAM_R */ - { - struct group *result; - - result = getgrnam(gname); - if (result != NULL) - gid = result->gr_gid; - } -# endif /* HAVE_GETGRNAM_R */ -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: do a gname->gid lookup for Windows. */ -#else - #error No way to perform gid lookups on this platform -#endif - b->id = (gid_t)gid; - - return (gid); -} - -static int64_t -lookup_uid(void *private_data, const char *uname, int64_t uid) -{ - int h; - struct bucket *b; - struct bucket *ucache = (struct bucket *)private_data; - - /* If no uname, just use the uid provided. */ - if (uname == NULL || *uname == '\0') - return (uid); - - /* Try to find uname in the cache. */ - h = hash(uname); - b = &ucache[h % cache_size ]; - if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0) - return ((uid_t)b->id); - - /* Free the cache slot for a new entry. */ - if (b->name != NULL) - free(b->name); - b->name = strdup(uname); - /* Note: If strdup fails, that's okay; we just won't cache. */ - b->hash = h; -#if HAVE_PWD_H -# if HAVE_GETPWNAM_R - { - char _buffer[128]; - size_t bufsize = 128; - char *buffer = _buffer; - char *allocated = NULL; - struct passwd pwent, *result; - int r; - - for (;;) { - result = &pwent; /* Old getpwnam_r ignores last arg. */ - r = getpwnam_r(uname, &pwent, buffer, bufsize, &result); - if (r == 0) - break; - if (r != ERANGE) - break; - bufsize *= 2; - free(allocated); - allocated = malloc(bufsize); - if (allocated == NULL) - break; - buffer = allocated; - } - if (result != NULL) - uid = result->pw_uid; - free(allocated); - } -# else /* HAVE_GETPWNAM_R */ - { - struct passwd *result; - - result = getpwnam(uname); - if (result != NULL) - uid = result->pw_uid; - } -#endif /* HAVE_GETPWNAM_R */ -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: do a uname->uid lookup for Windows. */ -#else - #error No way to look up uids on this platform -#endif - b->id = (uid_t)uid; - - return (uid); -} - -static void -cleanup(void *private) -{ - size_t i; - struct bucket *cache = (struct bucket *)private; - - for (i = 0; i < cache_size; i++) - free(cache[i].name); - free(cache); -} - - -static unsigned int -hash(const char *p) -{ - /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm, - as used by ELF for hashing function names. */ - unsigned g, h = 0; - while (*p != '\0') { - h = (h << 4) + *p++; - if ((g = h & 0xF0000000) != 0) { - h ^= g >> 24; - h &= 0x0FFFFFFF; - } - } - return h; -} diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_windows.c b/3rdparty/libarchive/libarchive/archive_write_disk_windows.c deleted file mode 100644 index 94b016ed..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_disk_windows.c +++ /dev/null @@ -1,2511 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#if defined(_WIN32) && !defined(__CYGWIN__) - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_UTIME_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#include - -/* TODO: Support Mac OS 'quarantine' feature. This is really just a - * standard tag to mark files that have been downloaded as "tainted". - * On Mac OS, we should mark the extracted files as tainted if the - * archive being read was tainted. Windows has a similar feature; we - * should investigate ways to support this generically. */ - -#include "archive.h" -#include "archive_acl_private.h" -#include "archive_string.h" -#include "archive_entry.h" -#include "archive_private.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef IO_REPARSE_TAG_SYMLINK -/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ -#define IO_REPARSE_TAG_SYMLINK 0xA000000CL -#endif - -static BOOL SetFilePointerEx_perso(HANDLE hFile, - LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, - DWORD dwMoveMethod) -{ - LARGE_INTEGER li; - li.QuadPart = liDistanceToMove.QuadPart; - li.LowPart = SetFilePointer( - hFile, li.LowPart, &li.HighPart, dwMoveMethod); - if(lpNewFilePointer) { - lpNewFilePointer->QuadPart = li.QuadPart; - } - return li.LowPart != (DWORD)-1 || GetLastError() == NO_ERROR; -} - -struct fixup_entry { - struct fixup_entry *next; - struct archive_acl acl; - mode_t mode; - int64_t atime; - int64_t birthtime; - int64_t mtime; - int64_t ctime; - unsigned long atime_nanos; - unsigned long birthtime_nanos; - unsigned long mtime_nanos; - unsigned long ctime_nanos; - unsigned long fflags_set; - int fixup; /* bitmask of what needs fixing */ - wchar_t *name; -}; - -/* - * We use a bitmask to track which operations remain to be done for - * this file. In particular, this helps us avoid unnecessary - * operations when it's possible to take care of one step as a - * side-effect of another. For example, mkdir() can specify the mode - * for the newly-created object but symlink() cannot. This means we - * can skip chmod() if mkdir() succeeded, but we must explicitly - * chmod() if we're trying to create a directory that already exists - * (mkdir() failed) or if we're restoring a symlink. Similarly, we - * need to verify UID/GID before trying to restore SUID/SGID bits; - * that verification can occur explicitly through a stat() call or - * implicitly because of a successful chown() call. - */ -#define TODO_MODE_FORCE 0x40000000 -#define TODO_MODE_BASE 0x20000000 -#define TODO_SUID 0x10000000 -#define TODO_SUID_CHECK 0x08000000 -#define TODO_SGID 0x04000000 -#define TODO_SGID_CHECK 0x02000000 -#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) -#define TODO_TIMES ARCHIVE_EXTRACT_TIME -#define TODO_OWNER ARCHIVE_EXTRACT_OWNER -#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS -#define TODO_ACLS ARCHIVE_EXTRACT_ACL -#define TODO_XATTR ARCHIVE_EXTRACT_XATTR -#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA - -struct archive_write_disk { - struct archive archive; - - mode_t user_umask; - struct fixup_entry *fixup_list; - struct fixup_entry *current_fixup; - int64_t user_uid; - int skip_file_set; - int64_t skip_file_dev; - int64_t skip_file_ino; - time_t start_time; - - int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); - void (*cleanup_gid)(void *private); - void *lookup_gid_data; - int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); - void (*cleanup_uid)(void *private); - void *lookup_uid_data; - - /* - * Full path of last file to satisfy symlink checks. - */ - struct archive_wstring path_safe; - - /* - * Cached stat data from disk for the current entry. - * If this is valid, pst points to st. Otherwise, - * pst is null. - */ - BY_HANDLE_FILE_INFORMATION st; - BY_HANDLE_FILE_INFORMATION *pst; - - /* Information about the object being restored right now. */ - struct archive_entry *entry; /* Entry being extracted. */ - wchar_t *name; /* Name of entry, possibly edited. */ - struct archive_wstring _name_data; /* backing store for 'name' */ - /* Tasks remaining for this object. */ - int todo; - /* Tasks deferred until end-of-archive. */ - int deferred; - /* Options requested by the client. */ - int flags; - /* Handle for the file we're restoring. */ - HANDLE fh; - /* Current offset for writing data to the file. */ - int64_t offset; - /* Last offset actually written to disk. */ - int64_t fd_offset; - /* Total bytes actually written to files. */ - int64_t total_bytes_written; - /* Maximum size of file, -1 if unknown. */ - int64_t filesize; - /* Dir we were in before this restore; only for deep paths. */ - int restore_pwd; - /* Mode we should use for this entry; affected by _PERM and umask. */ - mode_t mode; - /* UID/GID to use in restoring this entry. */ - int64_t uid; - int64_t gid; -}; - -/* - * Default mode for dirs created automatically (will be modified by umask). - * Note that POSIX specifies 0777 for implicitly-created dirs, "modified - * by the process' file creation mask." - */ -#define DEFAULT_DIR_MODE 0777 -/* - * Dir modes are restored in two steps: During the extraction, the permissions - * in the archive are modified to match the following limits. During - * the post-extract fixup pass, the permissions from the archive are - * applied. - */ -#define MINIMUM_DIR_MODE 0700 -#define MAXIMUM_DIR_MODE 0775 - -static int check_symlinks(struct archive_write_disk *); -static int create_filesystem_object(struct archive_write_disk *); -static struct fixup_entry *current_fixup(struct archive_write_disk *, - const wchar_t *pathname); -static int cleanup_pathname(struct archive_write_disk *); -static int create_dir(struct archive_write_disk *, wchar_t *); -static int create_parent_dir(struct archive_write_disk *, wchar_t *); -static int la_chmod(const wchar_t *, mode_t); -static int older(BY_HANDLE_FILE_INFORMATION *, struct archive_entry *); -static int permissive_name_w(struct archive_write_disk *); -static int restore_entry(struct archive_write_disk *); -static int set_acls(struct archive_write_disk *, HANDLE h, - const wchar_t *, struct archive_acl *); -static int set_xattrs(struct archive_write_disk *); -static int set_fflags(struct archive_write_disk *); -static int set_ownership(struct archive_write_disk *); -static int set_mode(struct archive_write_disk *, int mode); -static int set_times(struct archive_write_disk *, HANDLE, int, - const wchar_t *, time_t, long, time_t, long, time_t, - long, time_t, long); -static int set_times_from_entry(struct archive_write_disk *); -static struct fixup_entry *sort_dir_list(struct fixup_entry *p); -static ssize_t write_data_block(struct archive_write_disk *, - const char *, size_t); - -static struct archive_vtable *archive_write_disk_vtable(void); - -static int _archive_write_disk_close(struct archive *); -static int _archive_write_disk_free(struct archive *); -static int _archive_write_disk_header(struct archive *, - struct archive_entry *); -static int64_t _archive_write_disk_filter_bytes(struct archive *, int); -static int _archive_write_disk_finish_entry(struct archive *); -static ssize_t _archive_write_disk_data(struct archive *, const void *, - size_t); -static ssize_t _archive_write_disk_data_block(struct archive *, const void *, - size_t, int64_t); - -#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber) -/* Treat FileIndex as i-node. We should remove a sequence number - * which is high-16-bits of nFileIndexHigh. */ -#define bhfi_ino(bhfi) \ - ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \ - + (bhfi)->nFileIndexLow) -#define bhfi_size(bhfi) \ - ((((int64_t)(bhfi)->nFileSizeHigh) << 32) + (bhfi)->nFileSizeLow) - -static int -file_information(struct archive_write_disk *a, wchar_t *path, - BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat) -{ - HANDLE h; - int r; - DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; - WIN32_FIND_DATAW findData; - - if (sim_lstat || mode != NULL) { - h = FindFirstFileW(path, &findData); - if (h == INVALID_HANDLE_VALUE && - GetLastError() == ERROR_INVALID_NAME) { - wchar_t *full; - full = __la_win_permissive_name_w(path); - h = FindFirstFileW(full, &findData); - free(full); - } - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - FindClose(h); - } - - /* Is symlink file ? */ - if (sim_lstat && - ((findData.dwFileAttributes - & FILE_ATTRIBUTE_REPARSE_POINT) && - (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))) - flag |= FILE_FLAG_OPEN_REPARSE_POINT; - - h = CreateFileW(a->name, 0, 0, NULL, - OPEN_EXISTING, flag, NULL); - if (h == INVALID_HANDLE_VALUE && - GetLastError() == ERROR_INVALID_NAME) { - wchar_t *full; - full = __la_win_permissive_name_w(path); - h = CreateFileW(full, 0, 0, NULL, - OPEN_EXISTING, flag, NULL); - free(full); - } - if (h == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - r = GetFileInformationByHandle(h, st); - CloseHandle(h); - if (r == 0) { - la_dosmaperr(GetLastError()); - return (-1); - } - - if (mode == NULL) - return (0); - - *mode = S_IRUSR | S_IRGRP | S_IROTH; - if ((st->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) - *mode |= S_IWUSR | S_IWGRP | S_IWOTH; - if ((st->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && - findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) - *mode |= S_IFLNK; - else if (st->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - *mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; - else { - const wchar_t *p; - - *mode |= S_IFREG; - p = wcsrchr(path, L'.'); - if (p != NULL && wcslen(p) == 4) { - switch (p[1]) { - case L'B': case L'b': - if ((p[2] == L'A' || p[2] == L'a' ) && - (p[3] == L'T' || p[3] == L't' )) - *mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - case L'C': case L'c': - if (((p[2] == L'M' || p[2] == L'm' ) && - (p[3] == L'D' || p[3] == L'd' ))) - *mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - case L'E': case L'e': - if ((p[2] == L'X' || p[2] == L'x' ) && - (p[3] == L'E' || p[3] == L'e' )) - *mode |= S_IXUSR | S_IXGRP | S_IXOTH; - break; - default: - break; - } - } - } - return (0); -} - -/* - * Note: The path, for example, "aa/a/../b../c" will be converted to "aa/c" - * by GetFullPathNameW() W32 API, which __la_win_permissive_name_w uses. - * It means we cannot handle multiple dirs in one archive_entry. - * So we have to make the full-pathname in another way, which does not - * break "../" path string. - */ -static int -permissive_name_w(struct archive_write_disk *a) -{ - wchar_t *wn, *wnp; - wchar_t *ws, *wsp; - DWORD l; - - wnp = a->name; - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'?' && wnp[3] == L'\\') - /* We have already a permissive name. */ - return (0); - - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'.' && wnp[3] == L'\\') { - /* This is a device name */ - if (((wnp[4] >= L'a' && wnp[4] <= L'z') || - (wnp[4] >= L'A' && wnp[4] <= L'Z')) && - wnp[5] == L':' && wnp[6] == L'\\') { - wnp[2] = L'?';/* Not device name. */ - return (0); - } - } - - /* - * A full-pathname starting with a drive name like "C:\abc". - */ - if (((wnp[0] >= L'a' && wnp[0] <= L'z') || - (wnp[0] >= L'A' && wnp[0] <= L'Z')) && - wnp[1] == L':' && wnp[2] == L'\\') { - wn = _wcsdup(wnp); - if (wn == NULL) - return (-1); - archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1); - a->name = a->_name_data.s; - /* Prepend "\\?\" */ - archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); - archive_wstrcat(&(a->_name_data), wn); - free(wn); - return (0); - } - - /* - * A full-pathname pointing to a network drive - * like "\\\\file". - */ - if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { - const wchar_t *p = &wnp[2]; - - /* Skip server-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\') { - const wchar_t *rp = ++p; - /* Skip share-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\' && p != rp) { - /* Now, match patterns such as - * "\\server-name\share-name\" */ - wn = _wcsdup(wnp); - if (wn == NULL) - return (-1); - archive_wstring_ensure(&(a->_name_data), - 8 + wcslen(wn) + 1); - a->name = a->_name_data.s; - /* Prepend "\\?\UNC\" */ - archive_wstrncpy(&(a->_name_data), - L"\\\\?\\UNC\\", 8); - archive_wstrcat(&(a->_name_data), wn+2); - free(wn); - return (0); - } - } - return (0); - } - - /* - * Get current working directory. - */ - l = GetCurrentDirectoryW(0, NULL); - if (l == 0) - return (-1); - ws = malloc(l * sizeof(wchar_t)); - l = GetCurrentDirectoryW(l, ws); - if (l == 0) { - free(ws); - return (-1); - } - wsp = ws; - - /* - * A full-pathname starting without a drive name like "\abc". - */ - if (wnp[0] == L'\\') { - wn = _wcsdup(wnp); - if (wn == NULL) - return (-1); - archive_wstring_ensure(&(a->_name_data), - 4 + 2 + wcslen(wn) + 1); - a->name = a->_name_data.s; - /* Prepend "\\?\" and drive name. */ - archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); - archive_wstrncat(&(a->_name_data), wsp, 2); - archive_wstrcat(&(a->_name_data), wn); - free(wsp); - free(wn); - return (0); - } - - wn = _wcsdup(wnp); - if (wn == NULL) - return (-1); - archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1); - a->name = a->_name_data.s; - /* Prepend "\\?\" and drive name if not already added. */ - if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' && - wsp[2] == L'?' && wsp[3] == L'\\') - { - archive_wstrncpy(&(a->_name_data), wsp, l); - } - else - { - archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); - archive_wstrncat(&(a->_name_data), wsp, l); - } - archive_wstrncat(&(a->_name_data), L"\\", 1); - archive_wstrcat(&(a->_name_data), wn); - a->name = a->_name_data.s; - free(wsp); - free(wn); - return (0); -} - -static int -la_chmod(const wchar_t *path, mode_t mode) -{ - DWORD attr; - BOOL r; - wchar_t *fullname; - int ret = 0; - - fullname = NULL; - attr = GetFileAttributesW(path); - if (attr == (DWORD)-1 && - GetLastError() == ERROR_INVALID_NAME) { - fullname = __la_win_permissive_name_w(path); - attr = GetFileAttributesW(fullname); - } - if (attr == (DWORD)-1) { - la_dosmaperr(GetLastError()); - ret = -1; - goto exit_chmode; - } - if (mode & _S_IWRITE) - attr &= ~FILE_ATTRIBUTE_READONLY; - else - attr |= FILE_ATTRIBUTE_READONLY; - if (fullname != NULL) - r = SetFileAttributesW(fullname, attr); - else - r = SetFileAttributesW(path, attr); - if (r == 0) { - la_dosmaperr(GetLastError()); - ret = -1; - } -exit_chmode: - free(fullname); - return (ret); -} - -static void * -la_GetFunctionKernel32(const char *name) -{ - static HINSTANCE lib; - static int set; - if (!set) { - set = 1; - lib = LoadLibrary(TEXT("kernel32.dll")); - } - if (lib == NULL) { - fprintf(stderr, "Can't load kernel32.dll?!\n"); - exit(1); - } - return (void *)GetProcAddress(lib, name); -} - -static int -la_CreateHardLinkW(wchar_t *linkname, wchar_t *target) -{ - static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES); - static int set; - BOOL ret; - - if (!set) { - set = 1; - f = la_GetFunctionKernel32("CreateHardLinkW"); - } - if (!f) - return (0); - ret = (*f)(linkname, target, NULL); - if (!ret) { - /* Under windows 2000, it is necessary to remove - * the "\\?\" prefix. */ -#define IS_UNC(name) ((name[0] == L'U' || name[0] == L'u') && \ - (name[1] == L'N' || name[1] == L'n') && \ - (name[2] == L'C' || name[2] == L'c') && \ - name[3] == L'\\') - if (!wcsncmp(linkname,L"\\\\?\\", 4)) { - linkname += 4; - if (IS_UNC(linkname)) - linkname += 4; - } - if (!wcsncmp(target,L"\\\\?\\", 4)) { - target += 4; - if (IS_UNC(target)) - target += 4; - } -#undef IS_UNC - ret = (*f)(linkname, target, NULL); - } - return (ret); -} - -static int -la_ftruncate(HANDLE handle, int64_t length) -{ - LARGE_INTEGER distance; - - if (GetFileType(handle) != FILE_TYPE_DISK) { - errno = EBADF; - return (-1); - } - distance.QuadPart = length; - if (!SetFilePointerEx_perso(handle, distance, NULL, FILE_BEGIN)) { - la_dosmaperr(GetLastError()); - return (-1); - } - if (!SetEndOfFile(handle)) { - la_dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -static int -lazy_stat(struct archive_write_disk *a) -{ - if (a->pst != NULL) { - /* Already have stat() data available. */ - return (ARCHIVE_OK); - } - if (a->fh != INVALID_HANDLE_VALUE && - GetFileInformationByHandle(a->fh, &a->st) == 0) { - a->pst = &a->st; - return (ARCHIVE_OK); - } - - /* - * XXX At this point, symlinks should not be hit, otherwise - * XXX a race occurred. Do we want to check explicitly for that? - */ - if (file_information(a, a->name, &a->st, NULL, 1) == 0) { - a->pst = &a->st; - return (ARCHIVE_OK); - } - archive_set_error(&a->archive, errno, "Couldn't stat file"); - return (ARCHIVE_WARN); -} - -static struct archive_vtable * -archive_write_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_disk_close; - av.archive_filter_bytes = _archive_write_disk_filter_bytes; - av.archive_free = _archive_write_disk_free; - av.archive_write_header = _archive_write_disk_header; - av.archive_write_finish_entry - = _archive_write_disk_finish_entry; - av.archive_write_data = _archive_write_disk_data; - av.archive_write_data_block = _archive_write_disk_data_block; - inited = 1; - } - return (&av); -} - -static int64_t -_archive_write_disk_filter_bytes(struct archive *_a, int n) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - (void)n; /* UNUSED */ - if (n == -1 || n == 0) - return (a->total_bytes_written); - return (-1); -} - - -int -archive_write_disk_set_options(struct archive *_a, int flags) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - - a->flags = flags; - return (ARCHIVE_OK); -} - - -/* - * Extract this entry to disk. - * - * TODO: Validate hardlinks. According to the standards, we're - * supposed to check each extracted hardlink and squawk if it refers - * to a file that we didn't restore. I'm not entirely convinced this - * is a good idea, but more importantly: Is there any way to validate - * hardlinks without keeping a complete list of filenames from the - * entire archive?? Ugh. - * - */ -static int -_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - struct fixup_entry *fe; - int ret, r; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_disk_header"); - archive_clear_error(&a->archive); - if (a->archive.state & ARCHIVE_STATE_DATA) { - r = _archive_write_disk_finish_entry(&a->archive); - if (r == ARCHIVE_FATAL) - return (r); - } - - /* Set up for this particular entry. */ - a->pst = NULL; - a->current_fixup = NULL; - a->deferred = 0; - if (a->entry) { - archive_entry_free(a->entry); - a->entry = NULL; - } - a->entry = archive_entry_clone(entry); - a->fh = INVALID_HANDLE_VALUE; - a->fd_offset = 0; - a->offset = 0; - a->restore_pwd = -1; - a->uid = a->user_uid; - a->mode = archive_entry_mode(a->entry); - if (archive_entry_size_is_set(a->entry)) - a->filesize = archive_entry_size(a->entry); - else - a->filesize = -1; - archive_wstrcpy(&(a->_name_data), archive_entry_pathname_w(a->entry)); - a->name = a->_name_data.s; - archive_clear_error(&a->archive); - - /* - * Clean up the requested path. This is necessary for correct - * dir restores; the dir restore logic otherwise gets messed - * up by nonsense like "dir/.". - */ - ret = cleanup_pathname(a); - if (ret != ARCHIVE_OK) - return (ret); - - /* - * Generate a full-pathname and use it from here. - */ - if (permissive_name_w(a) < 0) { - errno = EINVAL; - return (ARCHIVE_FAILED); - } - - /* - * Query the umask so we get predictable mode settings. - * This gets done on every call to _write_header in case the - * user edits their umask during the extraction for some - * reason. - */ - umask(a->user_umask = umask(0)); - - /* Figure out what we need to do for this entry. */ - a->todo = TODO_MODE_BASE; - if (a->flags & ARCHIVE_EXTRACT_PERM) { - a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ - /* - * SGID requires an extra "check" step because we - * cannot easily predict the GID that the system will - * assign. (Different systems assign GIDs to files - * based on a variety of criteria, including process - * credentials and the gid of the enclosing - * directory.) We can only restore the SGID bit if - * the file has the right GID, and we only know the - * GID if we either set it (see set_ownership) or if - * we've actually called stat() on the file after it - * was restored. Since there are several places at - * which we might verify the GID, we need a TODO bit - * to keep track. - */ - if (a->mode & S_ISGID) - a->todo |= TODO_SGID | TODO_SGID_CHECK; - /* - * Verifying the SUID is simpler, but can still be - * done in multiple ways, hence the separate "check" bit. - */ - if (a->mode & S_ISUID) - a->todo |= TODO_SUID | TODO_SUID_CHECK; - } else { - /* - * User didn't request full permissions, so don't - * restore SUID, SGID bits and obey umask. - */ - a->mode &= ~S_ISUID; - a->mode &= ~S_ISGID; - a->mode &= ~S_ISVTX; - a->mode &= ~a->user_umask; - } -#if 0 - if (a->flags & ARCHIVE_EXTRACT_OWNER) - a->todo |= TODO_OWNER; -#endif - if (a->flags & ARCHIVE_EXTRACT_TIME) - a->todo |= TODO_TIMES; - if (a->flags & ARCHIVE_EXTRACT_ACL) { - if (archive_entry_filetype(a->entry) == AE_IFDIR) - a->deferred |= TODO_ACLS; - else - a->todo |= TODO_ACLS; - } - if (a->flags & ARCHIVE_EXTRACT_XATTR) - a->todo |= TODO_XATTR; - if (a->flags & ARCHIVE_EXTRACT_FFLAGS) - a->todo |= TODO_FFLAGS; - if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { - ret = check_symlinks(a); - if (ret != ARCHIVE_OK) - return (ret); - } - - ret = restore_entry(a); - - /* - * TODO: There are rumours that some extended attributes must - * be restored before file data is written. If this is true, - * then we either need to write all extended attributes both - * before and after restoring the data, or find some rule for - * determining which must go first and which last. Due to the - * many ways people are using xattrs, this may prove to be an - * intractable problem. - */ - - /* - * Fixup uses the unedited pathname from archive_entry_pathname(), - * because it is relative to the base dir and the edited path - * might be relative to some intermediate dir as a result of the - * deep restore logic. - */ - if (a->deferred & TODO_MODE) { - fe = current_fixup(a, archive_entry_pathname_w(entry)); - fe->fixup |= TODO_MODE_BASE; - fe->mode = a->mode; - } - - if ((a->deferred & TODO_TIMES) - && (archive_entry_mtime_is_set(entry) - || archive_entry_atime_is_set(entry))) { - fe = current_fixup(a, archive_entry_pathname_w(entry)); - fe->mode = a->mode; - fe->fixup |= TODO_TIMES; - if (archive_entry_atime_is_set(entry)) { - fe->atime = archive_entry_atime(entry); - fe->atime_nanos = archive_entry_atime_nsec(entry); - } else { - /* If atime is unset, use start time. */ - fe->atime = a->start_time; - fe->atime_nanos = 0; - } - if (archive_entry_mtime_is_set(entry)) { - fe->mtime = archive_entry_mtime(entry); - fe->mtime_nanos = archive_entry_mtime_nsec(entry); - } else { - /* If mtime is unset, use start time. */ - fe->mtime = a->start_time; - fe->mtime_nanos = 0; - } - if (archive_entry_birthtime_is_set(entry)) { - fe->birthtime = archive_entry_birthtime(entry); - fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); - } else { - /* If birthtime is unset, use mtime. */ - fe->birthtime = fe->mtime; - fe->birthtime_nanos = fe->mtime_nanos; - } - } - - if (a->deferred & TODO_ACLS) { - fe = current_fixup(a, archive_entry_pathname_w(entry)); - archive_acl_copy(&fe->acl, archive_entry_acl(entry)); - } - - if (a->deferred & TODO_FFLAGS) { - fe = current_fixup(a, archive_entry_pathname_w(entry)); - fe->fixup |= TODO_FFLAGS; - /* TODO: Complete this.. defer fflags from below. */ - } - - /* - * On Windows, A creating sparse file requires a special mark. - */ - if (a->fh != INVALID_HANDLE_VALUE && - archive_entry_sparse_count(entry) > 0) { - int64_t base = 0, offset, length; - int i, cnt = archive_entry_sparse_reset(entry); - int sparse = 0; - - for (i = 0; i < cnt; i++) { - archive_entry_sparse_next(entry, &offset, &length); - if (offset - base >= 4096) { - sparse = 1;/* we have a hole. */ - break; - } - base = offset + length; - } - if (sparse) { - DWORD dmy; - /* Mark this file as sparse. */ - DeviceIoControl(a->fh, FSCTL_SET_SPARSE, - NULL, 0, NULL, 0, &dmy, NULL); - } - } - - /* We've created the object and are ready to pour data into it. */ - if (ret >= ARCHIVE_WARN) - a->archive.state = ARCHIVE_STATE_DATA; - /* - * If it's not open, tell our client not to try writing. - * In particular, dirs, links, etc, don't get written to. - */ - if (a->fh == INVALID_HANDLE_VALUE) { - archive_entry_set_size(entry, 0); - a->filesize = 0; - } - - return (ret); -} - -int -archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); - a->skip_file_set = 1; - a->skip_file_dev = d; - a->skip_file_ino = i; - return (ARCHIVE_OK); -} - -static ssize_t -write_data_block(struct archive_write_disk *a, const char *buff, size_t size) -{ - OVERLAPPED ol; - uint64_t start_size = size; - DWORD bytes_written = 0; - ssize_t block_size = 0, bytes_to_write; - - if (size == 0) - return (ARCHIVE_OK); - - if (a->filesize == 0 || a->fh == INVALID_HANDLE_VALUE) { - archive_set_error(&a->archive, 0, - "Attempt to write to an empty file"); - return (ARCHIVE_WARN); - } - - if (a->flags & ARCHIVE_EXTRACT_SPARSE) { - /* XXX TODO XXX Is there a more appropriate choice here ? */ - /* This needn't match the filesystem allocation size. */ - block_size = 16*1024; - } - - /* If this write would run beyond the file size, truncate it. */ - if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) - start_size = size = (size_t)(a->filesize - a->offset); - - /* Write the data. */ - while (size > 0) { - if (block_size == 0) { - bytes_to_write = size; - } else { - /* We're sparsifying the file. */ - const char *p, *end; - int64_t block_end; - - /* Skip leading zero bytes. */ - for (p = buff, end = buff + size; p < end; ++p) { - if (*p != '\0') - break; - } - a->offset += p - buff; - size -= p - buff; - buff = p; - if (size == 0) - break; - - /* Calculate next block boundary after offset. */ - block_end - = (a->offset / block_size + 1) * block_size; - - /* If the adjusted write would cross block boundary, - * truncate it to the block boundary. */ - bytes_to_write = size; - if (a->offset + bytes_to_write > block_end) - bytes_to_write = (DWORD)(block_end - a->offset); - } - memset(&ol, 0, sizeof(ol)); - ol.Offset = (DWORD)(a->offset & 0xFFFFFFFF); - ol.OffsetHigh = (DWORD)(a->offset >> 32); - if (!WriteFile(a->fh, buff, (uint32_t)bytes_to_write, - &bytes_written, &ol)) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - archive_set_error(&a->archive, errno, "Write failed"); - return (ARCHIVE_WARN); - } - buff += bytes_written; - size -= bytes_written; - a->total_bytes_written += bytes_written; - a->offset += bytes_written; - a->fd_offset = a->offset; - } - return ((ssize_t)(start_size - size)); -} - -static ssize_t -_archive_write_disk_data_block(struct archive *_a, - const void *buff, size_t size, int64_t offset) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - ssize_t r; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_DATA, "archive_write_data_block"); - - a->offset = offset; - r = write_data_block(a, buff, size); - if (r < ARCHIVE_OK) - return (r); - if ((size_t)r < size) { - archive_set_error(&a->archive, 0, - "Write request too large"); - return (ARCHIVE_WARN); - } -#if ARCHIVE_VERSION_NUMBER < 3999000 - return (ARCHIVE_OK); -#else - return (size); -#endif -} - -static ssize_t -_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_DATA, "archive_write_data"); - - return (write_data_block(a, buff, size)); -} - -static int -_archive_write_disk_finish_entry(struct archive *_a) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - int ret = ARCHIVE_OK; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_finish_entry"); - if (a->archive.state & ARCHIVE_STATE_HEADER) - return (ARCHIVE_OK); - archive_clear_error(&a->archive); - - /* Pad or truncate file to the right size. */ - if (a->fh == INVALID_HANDLE_VALUE) { - /* There's no file. */ - } else if (a->filesize < 0) { - /* File size is unknown, so we can't set the size. */ - } else if (a->fd_offset == a->filesize) { - /* Last write ended at exactly the filesize; we're done. */ - /* Hopefully, this is the common case. */ - } else { - if (la_ftruncate(a->fh, a->filesize) == -1) { - archive_set_error(&a->archive, errno, - "File size could not be restored"); - return (ARCHIVE_FAILED); - } - } - - /* Restore metadata. */ - - /* - * Look up the "real" UID only if we're going to need it. - * TODO: the TODO_SGID condition can be dropped here, can't it? - */ - if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { - a->uid = archive_write_disk_uid(&a->archive, - archive_entry_uname(a->entry), - archive_entry_uid(a->entry)); - } - /* Look up the "real" GID only if we're going to need it. */ - /* TODO: the TODO_SUID condition can be dropped here, can't it? */ - if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { - a->gid = archive_write_disk_gid(&a->archive, - archive_entry_gname(a->entry), - archive_entry_gid(a->entry)); - } - - /* - * Restore ownership before set_mode tries to restore suid/sgid - * bits. If we set the owner, we know what it is and can skip - * a stat() call to examine the ownership of the file on disk. - */ - if (a->todo & TODO_OWNER) - ret = set_ownership(a); - - /* - * set_mode must precede ACLs on systems such as Solaris and - * FreeBSD where setting the mode implicitly clears extended ACLs - */ - if (a->todo & TODO_MODE) { - int r2 = set_mode(a, a->mode); - if (r2 < ret) ret = r2; - } - - /* - * Security-related extended attributes (such as - * security.capability on Linux) have to be restored last, - * since they're implicitly removed by other file changes. - */ - if (a->todo & TODO_XATTR) { - int r2 = set_xattrs(a); - if (r2 < ret) ret = r2; - } - - /* - * Some flags prevent file modification; they must be restored after - * file contents are written. - */ - if (a->todo & TODO_FFLAGS) { - int r2 = set_fflags(a); - if (r2 < ret) ret = r2; - } - - /* - * Time must follow most other metadata; - * otherwise atime will get changed. - */ - if (a->todo & TODO_TIMES) { - int r2 = set_times_from_entry(a); - if (r2 < ret) ret = r2; - } - - /* - * ACLs must be restored after timestamps because there are - * ACLs that prevent attribute changes (including time). - */ - if (a->todo & TODO_ACLS) { - int r2 = set_acls(a, a->fh, - archive_entry_pathname_w(a->entry), - archive_entry_acl(a->entry)); - if (r2 < ret) ret = r2; - } - - /* If there's an fd, we can close it now. */ - if (a->fh != INVALID_HANDLE_VALUE) { - CloseHandle(a->fh); - a->fh = INVALID_HANDLE_VALUE; - } - /* If there's an entry, we can release it now. */ - if (a->entry) { - archive_entry_free(a->entry); - a->entry = NULL; - } - a->archive.state = ARCHIVE_STATE_HEADER; - return (ret); -} - -int -archive_write_disk_set_group_lookup(struct archive *_a, - void *private_data, - int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), - void (*cleanup_gid)(void *private)) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); - - if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) - (a->cleanup_gid)(a->lookup_gid_data); - - a->lookup_gid = lookup_gid; - a->cleanup_gid = cleanup_gid; - a->lookup_gid_data = private_data; - return (ARCHIVE_OK); -} - -int -archive_write_disk_set_user_lookup(struct archive *_a, - void *private_data, - int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), - void (*cleanup_uid)(void *private)) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); - - if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) - (a->cleanup_uid)(a->lookup_uid_data); - - a->lookup_uid = lookup_uid; - a->cleanup_uid = cleanup_uid; - a->lookup_uid_data = private_data; - return (ARCHIVE_OK); -} - -int64_t -archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_gid"); - if (a->lookup_gid) - return (a->lookup_gid)(a->lookup_gid_data, name, id); - return (id); -} - -int64_t -archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY, "archive_write_disk_uid"); - if (a->lookup_uid) - return (a->lookup_uid)(a->lookup_uid_data, name, id); - return (id); -} - -/* - * Create a new archive_write_disk object and initialize it with global state. - */ -struct archive * -archive_write_disk_new(void) -{ - struct archive_write_disk *a; - - a = (struct archive_write_disk *)calloc(1, sizeof(*a)); - if (a == NULL) - return (NULL); - a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; - /* We're ready to write a header immediately. */ - a->archive.state = ARCHIVE_STATE_HEADER; - a->archive.vtable = archive_write_disk_vtable(); - a->start_time = time(NULL); - /* Query and restore the umask. */ - umask(a->user_umask = umask(0)); - if (archive_wstring_ensure(&a->path_safe, 512) == NULL) { - free(a); - return (NULL); - } - return (&a->archive); -} - -static int -disk_unlink(wchar_t *path) -{ - wchar_t *fullname; - int r; - - r = _wunlink(path); - if (r != 0 && GetLastError() == ERROR_INVALID_NAME) { - fullname = __la_win_permissive_name_w(path); - r = _wunlink(fullname); - free(fullname); - } - return (r); -} - -static int -disk_rmdir(wchar_t *path) -{ - wchar_t *fullname; - int r; - - r = _wrmdir(path); - if (r != 0 && GetLastError() == ERROR_INVALID_NAME) { - fullname = __la_win_permissive_name_w(path); - r = _wrmdir(fullname); - free(fullname); - } - return (r); -} - -/* - * The main restore function. - */ -static int -restore_entry(struct archive_write_disk *a) -{ - int ret = ARCHIVE_OK, en; - - if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { - /* - * TODO: Fix this. Apparently, there are platforms - * that still allow root to hose the entire filesystem - * by unlinking a dir. The S_ISDIR() test above - * prevents us from using unlink() here if the new - * object is a dir, but that doesn't mean the old - * object isn't a dir. - */ - if (disk_unlink(a->name) == 0) { - /* We removed it, reset cached stat. */ - a->pst = NULL; - } else if (errno == ENOENT) { - /* File didn't exist, that's just as good. */ - } else if (disk_rmdir(a->name) == 0) { - /* It was a dir, but now it's gone. */ - a->pst = NULL; - } else { - /* We tried, but couldn't get rid of it. */ - archive_set_error(&a->archive, errno, - "Could not unlink"); - return(ARCHIVE_FAILED); - } - } - - /* Try creating it first; if this fails, we'll try to recover. */ - en = create_filesystem_object(a); - - if ((en == ENOTDIR || en == ENOENT) - && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { - wchar_t *full; - /* If the parent dir doesn't exist, try creating it. */ - create_parent_dir(a, a->name); - /* Now try to create the object again. */ - full = __la_win_permissive_name_w(a->name); - if (full == NULL) { - en = EINVAL; - } else { - /* Remove multiple directories such as "a/../b../c" */ - archive_wstrcpy(&(a->_name_data), full); - a->name = a->_name_data.s; - free(full); - en = create_filesystem_object(a); - } - } - - if ((en == EISDIR || en == EEXIST) - && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { - /* If we're not overwriting, we're done. */ - archive_entry_unset_size(a->entry); - return (ARCHIVE_OK); - } - - /* - * Some platforms return EISDIR if you call - * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some - * return EEXIST. POSIX is ambiguous, requiring EISDIR - * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) - * on an existing item. - */ - if (en == EISDIR) { - /* A dir is in the way of a non-dir, rmdir it. */ - if (disk_rmdir(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't remove already-existing dir"); - return (ARCHIVE_FAILED); - } - a->pst = NULL; - /* Try again. */ - en = create_filesystem_object(a); - } else if (en == EEXIST) { - mode_t st_mode; - /* - * We know something is in the way, but we don't know what; - * we need to find out before we go any further. - */ - int r = 0; - /* - * The SECURE_SYMLINK logic has already removed a - * symlink to a dir if the client wants that. So - * follow the symlink if we're creating a dir. - */ - if (S_ISDIR(a->mode)) - r = file_information(a, a->name, &a->st, &st_mode, 0); - /* - * If it's not a dir (or it's a broken symlink), - * then don't follow it. - */ - if (r != 0 || !S_ISDIR(a->mode)) - r = file_information(a, a->name, &a->st, &st_mode, 1); - if (r != 0) { - archive_set_error(&a->archive, errno, - "Can't stat existing object"); - return (ARCHIVE_FAILED); - } - - /* - * NO_OVERWRITE_NEWER doesn't apply to directories. - */ - if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) - && !S_ISDIR(st_mode)) { - if (!older(&(a->st), a->entry)) { - archive_entry_unset_size(a->entry); - return (ARCHIVE_OK); - } - } - - /* If it's our archive, we're done. */ - if (a->skip_file_set && - bhfi_dev(&a->st) == a->skip_file_dev && - bhfi_ino(&a->st) == a->skip_file_ino) { - archive_set_error(&a->archive, 0, - "Refusing to overwrite archive"); - return (ARCHIVE_FAILED); - } - - if (!S_ISDIR(st_mode)) { - /* A non-dir is in the way, unlink it. */ - if (disk_unlink(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't unlink already-existing object"); - return (ARCHIVE_FAILED); - } - a->pst = NULL; - /* Try again. */ - en = create_filesystem_object(a); - } else if (!S_ISDIR(a->mode)) { - /* A dir is in the way of a non-dir, rmdir it. */ - if (disk_rmdir(a->name) != 0) { - archive_set_error(&a->archive, errno, - "Can't remove already-existing dir"); - return (ARCHIVE_FAILED); - } - /* Try again. */ - en = create_filesystem_object(a); - } else { - /* - * There's a dir in the way of a dir. Don't - * waste time with rmdir()/mkdir(), just fix - * up the permissions on the existing dir. - * Note that we don't change perms on existing - * dirs unless _EXTRACT_PERM is specified. - */ - if ((a->mode != st_mode) - && (a->todo & TODO_MODE_FORCE)) - a->deferred |= (a->todo & TODO_MODE); - /* Ownership doesn't need deferred fixup. */ - en = 0; /* Forget the EEXIST. */ - } - } - - if (en) { - /* Everything failed; give up here. */ - archive_set_error(&a->archive, en, "Can't create '%ls'", - a->name); - return (ARCHIVE_FAILED); - } - - a->pst = NULL; /* Cached stat data no longer valid. */ - return (ret); -} - -/* - * Returns 0 if creation succeeds, or else returns errno value from - * the failed system call. Note: This function should only ever perform - * a single system call. - */ -static int -create_filesystem_object(struct archive_write_disk *a) -{ - /* Create the entry. */ - const wchar_t *linkname; - wchar_t *fullname; - mode_t final_mode, mode; - int r; - - /* We identify hard/symlinks according to the link names. */ - /* Since link(2) and symlink(2) don't handle modes, we're done here. */ - linkname = archive_entry_hardlink_w(a->entry); - if (linkname != NULL) { - wchar_t *linkfull, *namefull; - - linkfull = __la_win_permissive_name_w(linkname); - namefull = __la_win_permissive_name_w(a->name); - if (linkfull == NULL || namefull == NULL) { - errno = EINVAL; - r = -1; - } else { - r = la_CreateHardLinkW(namefull, linkfull); - if (r == 0) { - la_dosmaperr(GetLastError()); - r = errno; - } else - r = 0; - } - /* - * New cpio and pax formats allow hardlink entries - * to carry data, so we may have to open the file - * for hardlink entries. - * - * If the hardlink was successfully created and - * the archive doesn't have carry data for it, - * consider it to be non-authoritative for meta data. - * This is consistent with GNU tar and BSD pax. - * If the hardlink does carry data, let the last - * archive entry decide ownership. - */ - if (r == 0 && a->filesize <= 0) { - a->todo = 0; - a->deferred = 0; - } else if (r == 0 && a->filesize > 0) { - a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL, - TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (a->fh == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - r = errno; - } - } - free(linkfull); - free(namefull); - return (r); - } - linkname = archive_entry_symlink_w(a->entry); - if (linkname != NULL) { -#if HAVE_SYMLINK - return symlink(linkname, a->name) ? errno : 0; -#else - return (EPERM); -#endif - } - - /* - * The remaining system calls all set permissions, so let's - * try to take advantage of that to avoid an extra chmod() - * call. (Recall that umask is set to zero right now!) - */ - - /* Mode we want for the final restored object (w/o file type bits). */ - final_mode = a->mode & 07777; - /* - * The mode that will actually be restored in this step. Note - * that SUID, SGID, etc, require additional work to ensure - * security, so we never restore them at this point. - */ - mode = final_mode & 0777 & ~a->user_umask; - - switch (a->mode & AE_IFMT) { - default: - /* POSIX requires that we fall through here. */ - /* FALLTHROUGH */ - case AE_IFREG: - fullname = a->name; - /* O_WRONLY | O_CREAT | O_EXCL */ - a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - if (a->fh == INVALID_HANDLE_VALUE && - GetLastError() == ERROR_INVALID_NAME && - fullname == a->name) { - fullname = __la_win_permissive_name_w(a->name); - a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - } - if (a->fh == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attr; - /* Simulate an errno of POSIX system. */ - attr = GetFileAttributesW(fullname); - if (attr == (DWORD)-1) - la_dosmaperr(GetLastError()); - else if (attr & FILE_ATTRIBUTE_DIRECTORY) - errno = EISDIR; - else - errno = EACCES; - } else - la_dosmaperr(GetLastError()); - r = 1; - } else - r = 0; - if (fullname != a->name) - free(fullname); - break; - case AE_IFCHR: - case AE_IFBLK: - /* TODO: Find a better way to warn about our inability - * to restore a block device node. */ - return (EINVAL); - case AE_IFDIR: - mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; - fullname = a->name; - r = CreateDirectoryW(fullname, NULL); - if (r == 0 && GetLastError() == ERROR_INVALID_NAME && - fullname == a->name) { - fullname = __la_win_permissive_name_w(a->name); - r = CreateDirectoryW(fullname, NULL); - } - if (r != 0) { - r = 0; - /* Defer setting dir times. */ - a->deferred |= (a->todo & TODO_TIMES); - a->todo &= ~TODO_TIMES; - /* Never use an immediate chmod(). */ - /* We can't avoid the chmod() entirely if EXTRACT_PERM - * because of SysV SGID inheritance. */ - if ((mode != final_mode) - || (a->flags & ARCHIVE_EXTRACT_PERM)) - a->deferred |= (a->todo & TODO_MODE); - a->todo &= ~TODO_MODE; - } else { - la_dosmaperr(GetLastError()); - r = -1; - } - if (fullname != a->name) - free(fullname); - break; - case AE_IFIFO: - /* TODO: Find a better way to warn about our inability - * to restore a fifo. */ - return (EINVAL); - } - - /* All the system calls above set errno on failure. */ - if (r) - return (errno); - - /* If we managed to set the final mode, we've avoided a chmod(). */ - if (mode == final_mode) - a->todo &= ~TODO_MODE; - return (0); -} - -/* - * Cleanup function for archive_extract. Mostly, this involves processing - * the fixup list, which is used to address a number of problems: - * * Dir permissions might prevent us from restoring a file in that - * dir, so we restore the dir with minimum 0700 permissions first, - * then correct the mode at the end. - * * Similarly, the act of restoring a file touches the directory - * and changes the timestamp on the dir, so we have to touch-up dir - * timestamps at the end as well. - * * Some file flags can interfere with the restore by, for example, - * preventing the creation of hardlinks to those files. - * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. - * - * Note that tar/cpio do not require that archives be in a particular - * order; there is no way to know when the last file has been restored - * within a directory, so there's no way to optimize the memory usage - * here by fixing up the directory any earlier than the - * end-of-archive. - * - * XXX TODO: Directory ACLs should be restored here, for the same - * reason we set directory perms here. XXX - */ -static int -_archive_write_disk_close(struct archive *_a) -{ - struct archive_write_disk *a = (struct archive_write_disk *)_a; - struct fixup_entry *next, *p; - int ret; - - archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_disk_close"); - ret = _archive_write_disk_finish_entry(&a->archive); - - /* Sort dir list so directories are fixed up in depth-first order. */ - p = sort_dir_list(a->fixup_list); - - while (p != NULL) { - a->pst = NULL; /* Mark stat cache as out-of-date. */ - if (p->fixup & TODO_TIMES) { - set_times(a, INVALID_HANDLE_VALUE, p->mode, p->name, - p->atime, p->atime_nanos, - p->birthtime, p->birthtime_nanos, - p->mtime, p->mtime_nanos, - p->ctime, p->ctime_nanos); - } - if (p->fixup & TODO_MODE_BASE) - la_chmod(p->name, p->mode); - if (p->fixup & TODO_ACLS) - set_acls(a, INVALID_HANDLE_VALUE, p->name, &p->acl); - next = p->next; - archive_acl_clear(&p->acl); - free(p->name); - free(p); - p = next; - } - a->fixup_list = NULL; - return (ret); -} - -static int -_archive_write_disk_free(struct archive *_a) -{ - struct archive_write_disk *a; - int ret; - if (_a == NULL) - return (ARCHIVE_OK); - archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, - ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); - a = (struct archive_write_disk *)_a; - ret = _archive_write_disk_close(&a->archive); - archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); - archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); - if (a->entry) - archive_entry_free(a->entry); - archive_wstring_free(&a->_name_data); - archive_string_free(&a->archive.error_string); - archive_wstring_free(&a->path_safe); - a->archive.magic = 0; - __archive_clean(&a->archive); - free(a); - return (ret); -} - -/* - * Simple O(n log n) merge sort to order the fixup list. In - * particular, we want to restore dir timestamps depth-first. - */ -static struct fixup_entry * -sort_dir_list(struct fixup_entry *p) -{ - struct fixup_entry *a, *b, *t; - - if (p == NULL) - return (NULL); - /* A one-item list is already sorted. */ - if (p->next == NULL) - return (p); - - /* Step 1: split the list. */ - t = p; - a = p->next->next; - while (a != NULL) { - /* Step a twice, t once. */ - a = a->next; - if (a != NULL) - a = a->next; - t = t->next; - } - /* Now, t is at the mid-point, so break the list here. */ - b = t->next; - t->next = NULL; - a = p; - - /* Step 2: Recursively sort the two sub-lists. */ - a = sort_dir_list(a); - b = sort_dir_list(b); - - /* Step 3: Merge the returned lists. */ - /* Pick the first element for the merged list. */ - if (wcscmp(a->name, b->name) > 0) { - t = p = a; - a = a->next; - } else { - t = p = b; - b = b->next; - } - - /* Always put the later element on the list first. */ - while (a != NULL && b != NULL) { - if (wcscmp(a->name, b->name) > 0) { - t->next = a; - a = a->next; - } else { - t->next = b; - b = b->next; - } - t = t->next; - } - - /* Only one list is non-empty, so just splice it on. */ - if (a != NULL) - t->next = a; - if (b != NULL) - t->next = b; - - return (p); -} - -/* - * Returns a new, initialized fixup entry. - * - * TODO: Reduce the memory requirements for this list by using a tree - * structure rather than a simple list of names. - */ -static struct fixup_entry * -new_fixup(struct archive_write_disk *a, const wchar_t *pathname) -{ - struct fixup_entry *fe; - - fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); - if (fe == NULL) - return (NULL); - fe->next = a->fixup_list; - a->fixup_list = fe; - fe->fixup = 0; - fe->name = _wcsdup(pathname); - return (fe); -} - -/* - * Returns a fixup structure for the current entry. - */ -static struct fixup_entry * -current_fixup(struct archive_write_disk *a, const wchar_t *pathname) -{ - if (a->current_fixup == NULL) - a->current_fixup = new_fixup(a, pathname); - return (a->current_fixup); -} - -/* TODO: Make this work. */ -/* - * TODO: The deep-directory support bypasses this; disable deep directory - * support if we're doing symlink checks. - */ -/* - * TODO: Someday, integrate this with the deep dir support; they both - * scan the path and both can be optimized by comparing against other - * recent paths. - */ -/* TODO: Extend this to support symlinks on Windows Vista and later. */ -static int -check_symlinks(struct archive_write_disk *a) -{ - wchar_t *pn, *p; - wchar_t c; - int r; - BY_HANDLE_FILE_INFORMATION st; - mode_t st_mode; - - /* - * Guard against symlink tricks. Reject any archive entry whose - * destination would be altered by a symlink. - */ - /* Whatever we checked last time doesn't need to be re-checked. */ - pn = a->name; - p = a->path_safe.s; - while ((*pn != '\0') && (*p == *pn)) - ++p, ++pn; - c = pn[0]; - /* Keep going until we've checked the entire name. */ - while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) { - /* Skip the next path element. */ - while (*pn != '\0' && *pn != '\\') - ++pn; - c = pn[0]; - pn[0] = '\0'; - /* Check that we haven't hit a symlink. */ - r = file_information(a, a->name, &st, &st_mode, 1); - if (r != 0) { - /* We've hit a dir that doesn't exist; stop now. */ - if (errno == ENOENT) - break; - } else if (S_ISLNK(st_mode)) { - if (c == '\0') { - /* - * Last element is symlink; remove it - * so we can overwrite it with the - * item being extracted. - */ - if (disk_unlink(a->name)) { - archive_set_error(&a->archive, errno, - "Could not remove symlink %ls", - a->name); - pn[0] = c; - return (ARCHIVE_FAILED); - } - a->pst = NULL; - /* - * Even if we did remove it, a warning - * is in order. The warning is silly, - * though, if we're just replacing one - * symlink with another symlink. - */ - if (!S_ISLNK(a->mode)) { - archive_set_error(&a->archive, 0, - "Removing symlink %ls", - a->name); - } - /* Symlink gone. No more problem! */ - pn[0] = c; - return (0); - } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { - /* User asked us to remove problems. */ - if (disk_unlink(a->name) != 0) { - archive_set_error(&a->archive, 0, - "Cannot remove intervening " - "symlink %ls", a->name); - pn[0] = c; - return (ARCHIVE_FAILED); - } - a->pst = NULL; - } else { - archive_set_error(&a->archive, 0, - "Cannot extract through symlink %ls", - a->name); - pn[0] = c; - return (ARCHIVE_FAILED); - } - } - } - pn[0] = c; - /* We've checked and/or cleaned the whole path, so remember it. */ - archive_wstrcpy(&a->path_safe, a->name); - return (ARCHIVE_OK); -} - -static int -guidword(wchar_t *p, int n) -{ - int i; - - for (i = 0; i < n; i++) { - if ((*p >= L'0' && *p <= L'9') || - (*p >= L'a' && *p <= L'f') || - (*p >= L'A' && *p <= L'F')) - p++; - else - return (-1); - } - return (0); -} - -/* - * Canonicalize the pathname. In particular, this strips duplicate - * '\' characters, '.' elements, and trailing '\'. It also raises an - * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is - * set) any '..' in the path. - */ -static int -cleanup_pathname(struct archive_write_disk *a) -{ - wchar_t *dest, *src, *p, *top; - wchar_t separator = L'\0'; - - p = a->name; - if (*p == L'\0') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid empty pathname"); - return (ARCHIVE_FAILED); - } - - /* Replace '/' by '\' */ - for (; *p != L'\0'; p++) { - if (*p == L'/') - *p = L'\\'; - } - p = a->name; - - /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or - * "\\?\Volume{GUID}\" - * (absolute path prefixes used by Windows API) */ - if (p[0] == L'\\' && p[1] == L'\\' && - (p[2] == L'.' || p[2] == L'?') && p[3] == L'\\') - { - /* A path begin with "\\?\UNC\" */ - if (p[2] == L'?' && - (p[4] == L'U' || p[4] == L'u') && - (p[5] == L'N' || p[5] == L'n') && - (p[6] == L'C' || p[6] == L'c') && - p[7] == L'\\') - p += 8; - /* A path begin with "\\?\Volume{GUID}\" */ - else if (p[2] == L'?' && - (p[4] == L'V' || p[4] == L'v') && - (p[5] == L'O' || p[5] == L'o') && - (p[6] == L'L' || p[6] == L'l') && - (p[7] == L'U' || p[7] == L'u') && - (p[8] == L'M' || p[8] == L'm') && - (p[9] == L'E' || p[9] == L'e') && - p[10] == L'{') { - if (guidword(p+11, 8) == 0 && p[19] == L'-' && - guidword(p+20, 4) == 0 && p[24] == L'-' && - guidword(p+25, 4) == 0 && p[29] == L'-' && - guidword(p+30, 4) == 0 && p[34] == L'-' && - guidword(p+35, 12) == 0 && p[47] == L'}' && - p[48] == L'\\') - p += 49; - else - p += 4; - /* A path begin with "\\.\PhysicalDriveX" */ - } else if (p[2] == L'.' && - (p[4] == L'P' || p[4] == L'p') && - (p[5] == L'H' || p[5] == L'h') && - (p[6] == L'Y' || p[6] == L'y') && - (p[7] == L'S' || p[7] == L's') && - (p[8] == L'I' || p[8] == L'i') && - (p[9] == L'C' || p[9] == L'c') && - (p[9] == L'A' || p[9] == L'a') && - (p[9] == L'L' || p[9] == L'l') && - (p[9] == L'D' || p[9] == L'd') && - (p[9] == L'R' || p[9] == L'r') && - (p[9] == L'I' || p[9] == L'i') && - (p[9] == L'V' || p[9] == L'v') && - (p[9] == L'E' || p[9] == L'e') && - (p[10] >= L'0' && p[10] <= L'9') && - p[11] == L'\0') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Path is a physical drive name"); - return (ARCHIVE_FAILED); - } else - p += 4; - } - - /* Skip leading drive letter from archives created - * on Windows. */ - if (((p[0] >= L'a' && p[0] <= L'z') || - (p[0] >= L'A' && p[0] <= L'Z')) && - p[1] == L':') { - if (p[2] == L'\0') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Path is a drive name"); - return (ARCHIVE_FAILED); - } - if (p[2] == L'\\') - p += 2; - } - - top = dest = src = p; - /* Rewrite the path name if its character is a unusable. */ - for (; *p != L'\0'; p++) { - if (*p == L':' || *p == L'*' || *p == L'?' || *p == L'"' || - *p == L'<' || *p == L'>' || *p == L'|') - *p = L'_'; - } - /* Skip leading '\'. */ - if (*src == L'\\') - separator = *src++; - - /* Scan the pathname one element at a time. */ - for (;;) { - /* src points to first char after '\' */ - if (src[0] == L'\0') { - break; - } else if (src[0] == L'\\') { - /* Found '\\'('//'), ignore second one. */ - src++; - continue; - } else if (src[0] == L'.') { - if (src[1] == L'\0') { - /* Ignore trailing '.' */ - break; - } else if (src[1] == L'\\') { - /* Skip '.\'. */ - src += 2; - continue; - } else if (src[1] == L'.') { - if (src[2] == L'\\' || src[2] == L'\0') { - /* Conditionally warn about '..' */ - if (a->flags & - ARCHIVE_EXTRACT_SECURE_NODOTDOT) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Path contains '..'"); - return (ARCHIVE_FAILED); - } - } - /* - * Note: Under no circumstances do we - * remove '..' elements. In - * particular, restoring - * '\foo\..\bar\' should create the - * 'foo' dir as a side-effect. - */ - } - } - - /* Copy current element, including leading '\'. */ - if (separator) - *dest++ = L'\\'; - while (*src != L'\0' && *src != L'\\') { - *dest++ = *src++; - } - - if (*src == L'\0') - break; - - /* Skip '\' separator. */ - separator = *src++; - } - /* - * We've just copied zero or more path elements, not including the - * final '\'. - */ - if (dest == top) { - /* - * Nothing got copied. The path must have been something - * like '.' or '\' or './' or '/././././/./'. - */ - if (separator) - *dest++ = L'\\'; - else - *dest++ = L'.'; - } - /* Terminate the result. */ - *dest = L'\0'; - return (ARCHIVE_OK); -} - -/* - * Create the parent directory of the specified path, assuming path - * is already in mutable storage. - */ -static int -create_parent_dir(struct archive_write_disk *a, wchar_t *path) -{ - wchar_t *slash; - int r; - - /* Remove tail element to obtain parent name. */ - slash = wcsrchr(path, L'\\'); - if (slash == NULL) - return (ARCHIVE_OK); - *slash = L'\0'; - r = create_dir(a, path); - *slash = L'\\'; - return (r); -} - -/* - * Create the specified dir, recursing to create parents as necessary. - * - * Returns ARCHIVE_OK if the path exists when we're done here. - * Otherwise, returns ARCHIVE_FAILED. - * Assumes path is in mutable storage; path is unchanged on exit. - */ -static int -create_dir(struct archive_write_disk *a, wchar_t *path) -{ - BY_HANDLE_FILE_INFORMATION st; - struct fixup_entry *le; - wchar_t *slash, *base, *full; - mode_t mode_final, mode, st_mode; - int r; - - /* Check for special names and just skip them. */ - slash = wcsrchr(path, L'\\'); - if (slash == NULL) - base = path; - else - base = slash + 1; - - if (base[0] == L'\0' || - (base[0] == L'.' && base[1] == L'\0') || - (base[0] == L'.' && base[1] == L'.' && base[2] == L'\0')) { - /* Don't bother trying to create null path, '.', or '..'. */ - if (slash != NULL) { - *slash = L'\0'; - r = create_dir(a, path); - *slash = L'\\'; - return (r); - } - return (ARCHIVE_OK); - } - - /* - * Yes, this should be stat() and not lstat(). Using lstat() - * here loses the ability to extract through symlinks. Also note - * that this should not use the a->st cache. - */ - if (file_information(a, path, &st, &st_mode, 0) == 0) { - if (S_ISDIR(st_mode)) - return (ARCHIVE_OK); - if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { - archive_set_error(&a->archive, EEXIST, - "Can't create directory '%ls'", path); - return (ARCHIVE_FAILED); - } - if (disk_unlink(path) != 0) { - archive_set_error(&a->archive, errno, - "Can't create directory '%ls': " - "Conflicting file cannot be removed", - path); - return (ARCHIVE_FAILED); - } - } else if (errno != ENOENT && errno != ENOTDIR) { - /* Stat failed? */ - archive_set_error(&a->archive, errno, - "Can't test directory '%ls'", path); - return (ARCHIVE_FAILED); - } else if (slash != NULL) { - *slash = '\0'; - r = create_dir(a, path); - *slash = '\\'; - if (r != ARCHIVE_OK) - return (r); - } - - /* - * Mode we want for the final restored directory. Per POSIX, - * implicitly-created dirs must be created obeying the umask. - * There's no mention whether this is different for privileged - * restores (which the rest of this code handles by pretending - * umask=0). I've chosen here to always obey the user's umask for - * implicit dirs, even if _EXTRACT_PERM was specified. - */ - mode_final = DEFAULT_DIR_MODE & ~a->user_umask; - /* Mode we want on disk during the restore process. */ - mode = mode_final; - mode |= MINIMUM_DIR_MODE; - mode &= MAXIMUM_DIR_MODE; - /* - * Apply __la_win_permissive_name_w to path in order to - * remove '../' path string. - */ - full = __la_win_permissive_name_w(path); - if (full == NULL) - errno = EINVAL; - else if (CreateDirectoryW(full, NULL) != 0) { - if (mode != mode_final) { - le = new_fixup(a, path); - le->fixup |=TODO_MODE_BASE; - le->mode = mode_final; - } - free(full); - return (ARCHIVE_OK); - } else { - la_dosmaperr(GetLastError()); - } - free(full); - - /* - * Without the following check, a/b/../b/c/d fails at the - * second visit to 'b', so 'd' can't be created. Note that we - * don't add it to the fixup list here, as it's already been - * added. - */ - if (file_information(a, path, &st, &st_mode, 0) == 0 && - S_ISDIR(st_mode)) - return (ARCHIVE_OK); - - archive_set_error(&a->archive, errno, "Failed to create dir '%ls'", - path); - return (ARCHIVE_FAILED); -} - -/* - * Note: Although we can skip setting the user id if the desired user - * id matches the current user, we cannot skip setting the group, as - * many systems set the gid based on the containing directory. So - * we have to perform a chown syscall if we want to set the SGID - * bit. (The alternative is to stat() and then possibly chown(); it's - * more efficient to skip the stat() and just always chown().) Note - * that a successful chown() here clears the TODO_SGID_CHECK bit, which - * allows set_mode to skip the stat() check for the GID. - */ -static int -set_ownership(struct archive_write_disk *a) -{ -/* unfortunately, on win32 there is no 'root' user with uid 0, - so we just have to try the chown and see if it works */ - - /* If we know we can't change it, don't bother trying. */ - if (a->user_uid != 0 && a->user_uid != a->uid) { - archive_set_error(&a->archive, errno, - "Can't set UID=%jd", (intmax_t)a->uid); - return (ARCHIVE_WARN); - } - - archive_set_error(&a->archive, errno, - "Can't set user=%jd/group=%jd for %ls", - (intmax_t)a->uid, (intmax_t)a->gid, a->name); - return (ARCHIVE_WARN); -} - -static int -set_times(struct archive_write_disk *a, - HANDLE h, int mode, const wchar_t *name, - time_t atime, long atime_nanos, - time_t birthtime, long birthtime_nanos, - time_t mtime, long mtime_nanos, - time_t ctime_sec, long ctime_nanos) -{ -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ - + (((nsec)/1000)*10)) - - HANDLE hw = 0; - ULARGE_INTEGER wintm; - FILETIME *pfbtime; - FILETIME fatime, fbtime, fmtime; - - (void)ctime_sec; /* UNUSED */ - (void)ctime_nanos; /* UNUSED */ - - if (h != INVALID_HANDLE_VALUE) { - hw = NULL; - } else { - wchar_t *ws; - - if (S_ISLNK(mode)) - return (ARCHIVE_OK); - ws = __la_win_permissive_name_w(name); - if (ws == NULL) - goto settimes_failed; - hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES, - 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - free(ws); - if (hw == INVALID_HANDLE_VALUE) - goto settimes_failed; - h = hw; - } - - wintm.QuadPart = WINTIME(atime, atime_nanos); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - wintm.QuadPart = WINTIME(mtime, mtime_nanos); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - /* - * SetFileTime() supports birthtime. - */ - if (birthtime > 0 || birthtime_nanos > 0) { - wintm.QuadPart = WINTIME(birthtime, birthtime_nanos); - fbtime.dwLowDateTime = wintm.LowPart; - fbtime.dwHighDateTime = wintm.HighPart; - pfbtime = &fbtime; - } else - pfbtime = NULL; - if (SetFileTime(h, pfbtime, &fatime, &fmtime) == 0) - goto settimes_failed; - CloseHandle(hw); - return (ARCHIVE_OK); - -settimes_failed: - CloseHandle(hw); - archive_set_error(&a->archive, EINVAL, "Can't restore time"); - return (ARCHIVE_WARN); -} - -static int -set_times_from_entry(struct archive_write_disk *a) -{ - time_t atime, birthtime, mtime, ctime_sec; - long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; - - /* Suitable defaults. */ - atime = birthtime = mtime = ctime_sec = a->start_time; - atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; - - /* If no time was provided, we're done. */ - if (!archive_entry_atime_is_set(a->entry) - && !archive_entry_birthtime_is_set(a->entry) - && !archive_entry_mtime_is_set(a->entry)) - return (ARCHIVE_OK); - - if (archive_entry_atime_is_set(a->entry)) { - atime = archive_entry_atime(a->entry); - atime_nsec = archive_entry_atime_nsec(a->entry); - } - if (archive_entry_birthtime_is_set(a->entry)) { - birthtime = archive_entry_birthtime(a->entry); - birthtime_nsec = archive_entry_birthtime_nsec(a->entry); - } - if (archive_entry_mtime_is_set(a->entry)) { - mtime = archive_entry_mtime(a->entry); - mtime_nsec = archive_entry_mtime_nsec(a->entry); - } - if (archive_entry_ctime_is_set(a->entry)) { - ctime_sec = archive_entry_ctime(a->entry); - ctime_nsec = archive_entry_ctime_nsec(a->entry); - } - - return set_times(a, a->fh, a->mode, a->name, - atime, atime_nsec, - birthtime, birthtime_nsec, - mtime, mtime_nsec, - ctime_sec, ctime_nsec); -} - -static int -set_mode(struct archive_write_disk *a, int mode) -{ - int r = ARCHIVE_OK; - mode &= 07777; /* Strip off file type bits. */ - - if (a->todo & TODO_SGID_CHECK) { - /* - * If we don't know the GID is right, we must stat() - * to verify it. We can't just check the GID of this - * process, since systems sometimes set GID from - * the enclosing dir or based on ACLs. - */ - if ((r = lazy_stat(a)) != ARCHIVE_OK) - return (r); - if (0 != a->gid) { - mode &= ~ S_ISGID; - } - /* While we're here, double-check the UID. */ - if (0 != a->uid - && (a->todo & TODO_SUID)) { - mode &= ~ S_ISUID; - } - a->todo &= ~TODO_SGID_CHECK; - a->todo &= ~TODO_SUID_CHECK; - } else if (a->todo & TODO_SUID_CHECK) { - /* - * If we don't know the UID is right, we can just check - * the user, since all systems set the file UID from - * the process UID. - */ - if (a->user_uid != a->uid) { - mode &= ~ S_ISUID; - } - a->todo &= ~TODO_SUID_CHECK; - } - - if (S_ISLNK(a->mode)) { -#ifdef HAVE_LCHMOD - /* - * If this is a symlink, use lchmod(). If the - * platform doesn't support lchmod(), just skip it. A - * platform that doesn't provide a way to set - * permissions on symlinks probably ignores - * permissions on symlinks, so a failure here has no - * impact. - */ - if (lchmod(a->name, mode) != 0) { - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } -#endif - } else if (!S_ISDIR(a->mode)) { - /* - * If it's not a symlink and not a dir, then use - * fchmod() or chmod(), depending on whether we have - * an fd. Dirs get their perms set during the - * post-extract fixup, which is handled elsewhere. - */ -#ifdef HAVE_FCHMOD - if (a->fd >= 0) { - if (fchmod(a->fd, mode) != 0) { - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } - } else -#endif - /* If this platform lacks fchmod(), then - * we'll just use chmod(). */ - if (la_chmod(a->name, mode) != 0) { - archive_set_error(&a->archive, errno, - "Can't set permissions to 0%o", (int)mode); - r = ARCHIVE_WARN; - } - } - return (r); -} - -static int -set_fflags(struct archive_write_disk *a) -{ - (void)a; /* UNUSED */ - return (ARCHIVE_OK); -} - -/* Default empty function body to satisfy mainline code. */ -static int -set_acls(struct archive_write_disk *a, HANDLE h, const wchar_t *name, - struct archive_acl *acl) -{ - (void)a; /* UNUSED */ - (void)h; /* UNUSED */ - (void)name; /* UNUSED */ - (void)acl; /* UNUSED */ - return (ARCHIVE_OK); -} - -/* - * Restore extended attributes - stub implementation for unsupported systems - */ -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; - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Cannot restore extended attributes on this system"); - return (ARCHIVE_WARN); - } - /* Warning was already emitted; suppress further warnings. */ - return (ARCHIVE_OK); -} - -static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - /* milli seconds base */ - *t = (time_t)(utc.QuadPart / 10000000); - /* nano seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - *t = 0; - *ns = 0; - } -} -/* - * Test if file on disk is older than entry. - */ -static int -older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry) -{ - time_t sec; - long nsec; - - fileTimeToUtc(&st->ftLastWriteTime, &sec, &nsec); - /* First, test the seconds and return if we have a definite answer. */ - /* Definitely older. */ - if (sec < archive_entry_mtime(entry)) - return (1); - /* Definitely younger. */ - if (sec > archive_entry_mtime(entry)) - return (0); - if (nsec < archive_entry_mtime_nsec(entry)) - return (1); - /* Same age or newer, so not older. */ - return (0); -} - -#endif /* _WIN32 && !__CYGWIN__ */ - diff --git a/3rdparty/libarchive/libarchive/archive_write_open_fd.c b/3rdparty/libarchive/libarchive/archive_write_open_fd.c deleted file mode 100644 index d5c426cf..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_open_fd.c +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_fd.c 201093 2009-12-28 02:28:44Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_IO_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" - -struct write_fd_data { - int fd; -}; - -static int file_close(struct archive *, void *); -static int file_open(struct archive *, void *); -static ssize_t file_write(struct archive *, void *, const void *buff, size_t); - -int -archive_write_open_fd(struct archive *a, int fd) -{ - struct write_fd_data *mine; - - mine = (struct write_fd_data *)malloc(sizeof(*mine)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - mine->fd = fd; -#if defined(__CYGWIN__) || defined(_WIN32) - setmode(mine->fd, O_BINARY); -#endif - return (archive_write_open(a, mine, - file_open, file_write, file_close)); -} - -static int -file_open(struct archive *a, void *client_data) -{ - struct write_fd_data *mine; - struct stat st; - - mine = (struct write_fd_data *)client_data; - - if (fstat(mine->fd, &st) != 0) { - archive_set_error(a, errno, "Couldn't stat fd %d", mine->fd); - return (ARCHIVE_FATAL); - } - - /* - * If this is a regular file, don't add it to itself. - */ - if (S_ISREG(st.st_mode)) - archive_write_set_skip_file(a, st.st_dev, st.st_ino); - - /* - * If client hasn't explicitly set the last block handling, - * then set it here. - */ - if (archive_write_get_bytes_in_last_block(a) < 0) { - /* If the output is a block or character device, fifo, - * or stdout, pad the last block, otherwise leave it - * unpadded. */ - if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || - S_ISFIFO(st.st_mode) || (mine->fd == 1)) - /* Last block will be fully padded. */ - archive_write_set_bytes_in_last_block(a, 0); - else - archive_write_set_bytes_in_last_block(a, 1); - } - - return (ARCHIVE_OK); -} - -static ssize_t -file_write(struct archive *a, void *client_data, const void *buff, size_t length) -{ - struct write_fd_data *mine; - ssize_t bytesWritten; - - mine = (struct write_fd_data *)client_data; - for (;;) { - bytesWritten = write(mine->fd, buff, length); - if (bytesWritten <= 0) { - if (errno == EINTR) - continue; - archive_set_error(a, errno, "Write error"); - return (-1); - } - return (bytesWritten); - } -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct write_fd_data *mine = (struct write_fd_data *)client_data; - - (void)a; /* UNUSED */ - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_open_file.c b/3rdparty/libarchive/libarchive/archive_write_open_file.c deleted file mode 100644 index f6b14123..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_open_file.c +++ /dev/null @@ -1,109 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_file.c,v 1.19 2007/01/09 08:05:56 kientzle Exp $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" - -struct write_FILE_data { - FILE *f; -}; - -static int file_close(struct archive *, void *); -static int file_open(struct archive *, void *); -static ssize_t file_write(struct archive *, void *, const void *buff, size_t); - -int -archive_write_open_FILE(struct archive *a, FILE *f) -{ - struct write_FILE_data *mine; - - mine = (struct write_FILE_data *)malloc(sizeof(*mine)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - mine->f = f; - return (archive_write_open(a, mine, - file_open, file_write, file_close)); -} - -static int -file_open(struct archive *a, void *client_data) -{ - (void)a; /* UNUSED */ - (void)client_data; /* UNUSED */ - - return (ARCHIVE_OK); -} - -static ssize_t -file_write(struct archive *a, void *client_data, const void *buff, size_t length) -{ - struct write_FILE_data *mine; - size_t bytesWritten; - - mine = client_data; - for (;;) { - bytesWritten = fwrite(buff, 1, length, mine->f); - if (bytesWritten <= 0) { - if (errno == EINTR) - continue; - archive_set_error(a, errno, "Write error"); - return (-1); - } - return (bytesWritten); - } -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct write_FILE_data *mine = client_data; - - (void)a; /* UNUSED */ - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_open_filename.c b/3rdparty/libarchive/libarchive/archive_write_open_filename.c deleted file mode 100644 index 66e0dfee..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_open_filename.c +++ /dev/null @@ -1,253 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 2009-04-17 00:39:35Z kientzle $"); - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_string.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -struct write_file_data { - int fd; - struct archive_mstring filename; -}; - -static int file_close(struct archive *, void *); -static int file_open(struct archive *, void *); -static ssize_t file_write(struct archive *, void *, const void *buff, size_t); -static int open_filename(struct archive *, int, const void *); - -int -archive_write_open_file(struct archive *a, const char *filename) -{ - return (archive_write_open_filename(a, filename)); -} - -int -archive_write_open_filename(struct archive *a, const char *filename) -{ - - if (filename == NULL || filename[0] == '\0') - return (archive_write_open_fd(a, 1)); - - return (open_filename(a, 1, filename)); -} - -int -archive_write_open_filename_w(struct archive *a, const wchar_t *filename) -{ - - if (filename == NULL || filename[0] == L'\0') - return (archive_write_open_fd(a, 1)); - - return (open_filename(a, 0, filename)); -} - -static int -open_filename(struct archive *a, int mbs_fn, const void *filename) -{ - struct write_file_data *mine; - int r; - - mine = (struct write_file_data *)calloc(1, sizeof(*mine)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - if (mbs_fn) - r = archive_mstring_copy_mbs(&mine->filename, filename); - else - r = archive_mstring_copy_wcs(&mine->filename, filename); - if (r < 0) { - if (errno == ENOMEM) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - if (mbs_fn) - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Can't convert '%s' to WCS", - (const char *)filename); - else - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Can't convert '%S' to MBS", - (const wchar_t *)filename); - return (ARCHIVE_FAILED); - } - mine->fd = -1; - return (archive_write_open(a, mine, - file_open, file_write, file_close)); -} - -static int -file_open(struct archive *a, void *client_data) -{ - int flags; - struct write_file_data *mine; - struct stat st; -#if defined(_WIN32) && !defined(__CYGWIN__) - wchar_t *fullpath; -#endif - const wchar_t *wcs; - const char *mbs; - - mine = (struct write_file_data *)client_data; - flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC; - - /* - * Open the file. - */ - mbs = NULL; wcs = NULL; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) { - if (errno == ENOMEM) - archive_set_error(a, errno, "No memory"); - else { - archive_mstring_get_mbs(a, &mine->filename, &mbs); - archive_set_error(a, errno, - "Can't convert '%s' to WCS", mbs); - } - return (ARCHIVE_FATAL); - } - fullpath = __la_win_permissive_name_w(wcs); - if (fullpath != NULL) { - mine->fd = _wopen(fullpath, flags, 0666); - free(fullpath); - } else - mine->fd = _wopen(wcs, flags, 0666); -#else - if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) { - if (errno == ENOMEM) - archive_set_error(a, errno, "No memory"); - else { - archive_mstring_get_wcs(a, &mine->filename, &wcs); - archive_set_error(a, errno, - "Can't convert '%S' to MBS", wcs); - } - return (ARCHIVE_FATAL); - } - mine->fd = open(mbs, flags, 0666); - __archive_ensure_cloexec_flag(mine->fd); -#endif - if (mine->fd < 0) { - if (mbs != NULL) - archive_set_error(a, errno, "Failed to open '%s'", mbs); - else - archive_set_error(a, errno, "Failed to open '%S'", wcs); - return (ARCHIVE_FATAL); - } - - if (fstat(mine->fd, &st) != 0) { - if (mbs != NULL) - archive_set_error(a, errno, "Couldn't stat '%s'", mbs); - else - archive_set_error(a, errno, "Couldn't stat '%S'", wcs); - return (ARCHIVE_FATAL); - } - - /* - * Set up default last block handling. - */ - if (archive_write_get_bytes_in_last_block(a) < 0) { - if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || - S_ISFIFO(st.st_mode)) - /* Pad last block when writing to device or FIFO. */ - archive_write_set_bytes_in_last_block(a, 0); - else - /* Don't pad last block otherwise. */ - archive_write_set_bytes_in_last_block(a, 1); - } - - /* - * If the output file is a regular file, don't add it to - * itself. If it's a device file, it's okay to add the device - * entry to the output archive. - */ - if (S_ISREG(st.st_mode)) - archive_write_set_skip_file(a, st.st_dev, st.st_ino); - - return (ARCHIVE_OK); -} - -static ssize_t -file_write(struct archive *a, void *client_data, const void *buff, - size_t length) -{ - struct write_file_data *mine; - ssize_t bytesWritten; - - mine = (struct write_file_data *)client_data; - for (;;) { - bytesWritten = write(mine->fd, buff, length); - if (bytesWritten <= 0) { - if (errno == EINTR) - continue; - archive_set_error(a, errno, "Write error"); - return (-1); - } - return (bytesWritten); - } -} - -static int -file_close(struct archive *a, void *client_data) -{ - struct write_file_data *mine = (struct write_file_data *)client_data; - - (void)a; /* UNUSED */ - - if (mine->fd >= 0) - close(mine->fd); - - archive_mstring_clean(&mine->filename); - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_open_memory.c b/3rdparty/libarchive/libarchive/archive_write_open_memory.c deleted file mode 100644 index ea6ae0ac..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_open_memory.c +++ /dev/null @@ -1,113 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_memory.c,v 1.3 2007/01/09 08:05:56 kientzle Exp $"); - -#include -#include -#include - -#include "archive.h" - -struct write_memory_data { - size_t used; - size_t size; - size_t * client_size; - unsigned char * buff; -}; - -static int memory_write_close(struct archive *, void *); -static int memory_write_open(struct archive *, void *); -static ssize_t memory_write(struct archive *, void *, const void *buff, size_t); - -/* - * Client provides a pointer to a block of memory to receive - * the data. The 'size' param both tells us the size of the - * client buffer and lets us tell the client the final size. - */ -int -archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) -{ - struct write_memory_data *mine; - - mine = (struct write_memory_data *)calloc(1, sizeof(*mine)); - if (mine == NULL) { - archive_set_error(a, ENOMEM, "No memory"); - return (ARCHIVE_FATAL); - } - mine->buff = buff; - mine->size = buffSize; - mine->client_size = used; - return (archive_write_open(a, mine, - memory_write_open, memory_write, memory_write_close)); -} - -static int -memory_write_open(struct archive *a, void *client_data) -{ - struct write_memory_data *mine; - mine = client_data; - mine->used = 0; - if (mine->client_size != NULL) - *mine->client_size = mine->used; - /* Disable padding if it hasn't been set explicitly. */ - if (-1 == archive_write_get_bytes_in_last_block(a)) - archive_write_set_bytes_in_last_block(a, 1); - return (ARCHIVE_OK); -} - -/* - * Copy the data into the client buffer. - * Note that we update mine->client_size on every write. - * In particular, this means the client can follow exactly - * how much has been written into their buffer at any time. - */ -static ssize_t -memory_write(struct archive *a, void *client_data, const void *buff, size_t length) -{ - struct write_memory_data *mine; - mine = client_data; - - if (mine->used + length > mine->size) { - archive_set_error(a, ENOMEM, "Buffer exhausted"); - return (ARCHIVE_FATAL); - } - memcpy(mine->buff + mine->used, buff, length); - mine->used += length; - if (mine->client_size != NULL) - *mine->client_size = mine->used; - return (length); -} - -static int -memory_write_close(struct archive *a, void *client_data) -{ - struct write_memory_data *mine; - (void)a; /* UNUSED */ - mine = client_data; - free(mine); - return (ARCHIVE_OK); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_private.h b/3rdparty/libarchive/libarchive/archive_write_private.h deleted file mode 100644 index 0dfd1b1b..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_private.h +++ /dev/null @@ -1,160 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/archive_write_private.h 201155 2009-12-29 05:20:12Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#ifndef __LIBARCHIVE_TEST -#error This header is only to be used internally to libarchive. -#endif -#endif - -#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED -#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED - -#include "archive.h" -#include "archive_string.h" -#include "archive_private.h" - -struct archive_write; - -struct archive_write_filter { - int64_t bytes_written; - struct archive *archive; /* Associated archive. */ - struct archive_write_filter *next_filter; /* Who I write to. */ - int (*options)(struct archive_write_filter *, - const char *key, const char *value); - int (*open)(struct archive_write_filter *); - int (*write)(struct archive_write_filter *, const void *, size_t); - int (*close)(struct archive_write_filter *); - int (*free)(struct archive_write_filter *); - void *data; - const char *name; - int code; - int bytes_per_block; - int bytes_in_last_block; -}; - -#if ARCHIVE_VERSION < 4000000 -void __archive_write_filters_free(struct archive *); -#endif - -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_filter(struct archive_write_filter *, const void *, size_t); -int __archive_write_open_filter(struct archive_write_filter *); -int __archive_write_close_filter(struct archive_write_filter *); - -struct archive_write { - struct archive archive; - - /* Dev/ino of the archive being written. */ - int skip_file_set; - int64_t skip_file_dev; - int64_t skip_file_ino; - - /* Utility: Pointer to a block of nulls. */ - const unsigned char *nulls; - size_t null_length; - - /* Callbacks to open/read/write/close archive stream. */ - archive_open_callback *client_opener; - archive_write_callback *client_writer; - archive_close_callback *client_closer; - void *client_data; - - /* - * Blocking information. Note that bytes_in_last_block is - * misleadingly named; I should find a better name. These - * control the final output from all compressors, including - * compression_none. - */ - int bytes_per_block; - int bytes_in_last_block; - - /* - * First and last write filters in the pipeline. - */ - struct archive_write_filter *filter_first; - struct archive_write_filter *filter_last; - - /* - * Pointers to format-specific functions for writing. They're - * initialized by archive_write_set_format_XXX() calls. - */ - void *format_data; - const char *format_name; - int (*format_init)(struct archive_write *); - int (*format_options)(struct archive_write *, - const char *key, const char *value); - int (*format_finish_entry)(struct archive_write *); - int (*format_write_header)(struct archive_write *, - struct archive_entry *); - ssize_t (*format_write_data)(struct archive_write *, - const void *buff, size_t); - int (*format_close)(struct archive_write *); - int (*format_free)(struct archive_write *); - - - /* - * Encryption passphrase. - */ - char *passphrase; - archive_passphrase_callback *passphrase_callback; - void *passphrase_client_data; -}; - -/* - * Utility function to format a USTAR header into a buffer. If - * "strict" is set, this tries to create the absolutely most portable - * version of a ustar header. If "strict" is set to 0, then it will - * relax certain requirements. - * - * Generally, format-specific declarations don't belong in this - * header; this is a rare example of a function that is shared by - * two very similar formats (ustar and pax). - */ -int -__archive_write_format_header_ustar(struct archive_write *, char buff[512], - struct archive_entry *, int tartype, int strict, - struct archive_string_conv *); - -struct archive_write_program_data; -struct archive_write_program_data * __archive_write_program_allocate(const char *program_name); -int __archive_write_program_free(struct archive_write_program_data *); -int __archive_write_program_open(struct archive_write_filter *, - struct archive_write_program_data *, const char *); -int __archive_write_program_close(struct archive_write_filter *, - struct archive_write_program_data *); -int __archive_write_program_write(struct archive_write_filter *, - struct archive_write_program_data *, const void *, size_t); - -/* - * Get a encryption passphrase. - */ -const char * __archive_write_get_passphrase(struct archive_write *a); -#endif diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format.c b/3rdparty/libarchive/libarchive/archive_write_set_format.c deleted file mode 100644 index 0f706231..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_set_format.c +++ /dev/null @@ -1,78 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format.c 201168 2009-12-29 06:15:32Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" - -/* A table that maps format codes to functions. */ -static const -struct { int code; int (*setter)(struct archive *); } codes[] = -{ - { ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip }, - { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio }, - { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio }, - { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc }, - { ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 }, - { ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree }, - { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw }, - { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar }, - { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar }, - { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump }, - { ARCHIVE_FORMAT_TAR, archive_write_set_format_pax_restricted }, - { ARCHIVE_FORMAT_TAR_GNUTAR, archive_write_set_format_gnutar }, - { ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_write_set_format_pax }, - { ARCHIVE_FORMAT_TAR_PAX_RESTRICTED, - archive_write_set_format_pax_restricted }, - { ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar }, - { ARCHIVE_FORMAT_WARC, archive_write_set_format_warc }, - { ARCHIVE_FORMAT_XAR, archive_write_set_format_xar }, - { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip }, - { 0, NULL } -}; - -int -archive_write_set_format(struct archive *a, int code) -{ - int i; - - for (i = 0; codes[i].code != 0; i++) { - if (code == codes[i].code) - return ((codes[i].setter)(a)); - } - - archive_set_error(a, EINVAL, "No such format"); - return (ARCHIVE_FATAL); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c b/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c deleted file mode 100644 index 86e8621e..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" - -/* A table that maps names to functions. */ -static const -struct { const char *name; int (*setter)(struct archive *); } names[] = -{ - { "7zip", archive_write_set_format_7zip }, - { "ar", archive_write_set_format_ar_bsd }, - { "arbsd", archive_write_set_format_ar_bsd }, - { "argnu", archive_write_set_format_ar_svr4 }, - { "arsvr4", archive_write_set_format_ar_svr4 }, - { "bsdtar", archive_write_set_format_pax_restricted }, - { "cd9660", archive_write_set_format_iso9660 }, - { "cpio", archive_write_set_format_cpio }, - { "gnutar", archive_write_set_format_gnutar }, - { "iso", archive_write_set_format_iso9660 }, - { "iso9660", archive_write_set_format_iso9660 }, - { "mtree", archive_write_set_format_mtree }, - { "mtree-classic", archive_write_set_format_mtree_classic }, - { "newc", archive_write_set_format_cpio_newc }, - { "odc", archive_write_set_format_cpio }, - { "oldtar", archive_write_set_format_v7tar }, - { "pax", archive_write_set_format_pax }, - { "paxr", archive_write_set_format_pax_restricted }, - { "posix", archive_write_set_format_pax }, - { "raw", archive_write_set_format_raw }, - { "rpax", archive_write_set_format_pax_restricted }, - { "shar", archive_write_set_format_shar }, - { "shardump", archive_write_set_format_shar_dump }, - { "ustar", archive_write_set_format_ustar }, - { "v7tar", archive_write_set_format_v7tar }, - { "v7", archive_write_set_format_v7tar }, - { "warc", archive_write_set_format_warc }, - { "xar", archive_write_set_format_xar }, - { "zip", archive_write_set_format_zip }, - { NULL, NULL } -}; - -int -archive_write_set_format_by_name(struct archive *a, const char *name) -{ - int i; - - for (i = 0; names[i].name != NULL; i++) { - if (strcmp(name, names[i].name) == 0) - return ((names[i].setter)(a)); - } - - archive_set_error(a, EINVAL, "No such format '%s'", name); - a->state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c deleted file mode 100644 index 2d858c9f..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c +++ /dev/null @@ -1,763 +0,0 @@ -/*- - * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). - * Author: Jonas Gastal - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $"); - - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_entry_locale.h" -#include "archive_private.h" -#include "archive_write_private.h" - -struct gnutar { - uint64_t entry_bytes_remaining; - uint64_t entry_padding; - const char * linkname; - size_t linkname_length; - const char * pathname; - size_t pathname_length; - const char * uname; - size_t uname_length; - const char * gname; - size_t gname_length; - struct archive_string_conv *opt_sconv; - struct archive_string_conv *sconv_default; - int init_default_conversion; -}; - -/* - * Define structure of GNU tar header. - */ -#define GNUTAR_name_offset 0 -#define GNUTAR_name_size 100 -#define GNUTAR_mode_offset 100 -#define GNUTAR_mode_size 7 -#define GNUTAR_mode_max_size 8 -#define GNUTAR_uid_offset 108 -#define GNUTAR_uid_size 7 -#define GNUTAR_uid_max_size 8 -#define GNUTAR_gid_offset 116 -#define GNUTAR_gid_size 7 -#define GNUTAR_gid_max_size 8 -#define GNUTAR_size_offset 124 -#define GNUTAR_size_size 11 -#define GNUTAR_size_max_size 12 -#define GNUTAR_mtime_offset 136 -#define GNUTAR_mtime_size 11 -#define GNUTAR_mtime_max_size 11 -#define GNUTAR_checksum_offset 148 -#define GNUTAR_checksum_size 8 -#define GNUTAR_typeflag_offset 156 -#define GNUTAR_typeflag_size 1 -#define GNUTAR_linkname_offset 157 -#define GNUTAR_linkname_size 100 -#define GNUTAR_magic_offset 257 -#define GNUTAR_magic_size 6 -#define GNUTAR_version_offset 263 -#define GNUTAR_version_size 2 -#define GNUTAR_uname_offset 265 -#define GNUTAR_uname_size 32 -#define GNUTAR_gname_offset 297 -#define GNUTAR_gname_size 32 -#define GNUTAR_rdevmajor_offset 329 -#define GNUTAR_rdevmajor_size 6 -#define GNUTAR_rdevmajor_max_size 8 -#define GNUTAR_rdevminor_offset 337 -#define GNUTAR_rdevminor_size 6 -#define GNUTAR_rdevminor_max_size 8 - -/* - * A filled-in copy of the header for initialization. - */ -static const char template_header[] = { - /* name: 100 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0, - /* Mode, null termination: 8 bytes */ - '0','0','0','0','0','0', '0','\0', - /* uid, null termination: 8 bytes */ - '0','0','0','0','0','0', '0','\0', - /* gid, null termination: 8 bytes */ - '0','0','0','0','0','0', '0','\0', - /* size, space termination: 12 bytes */ - '0','0','0','0','0','0','0','0','0','0','0', '\0', - /* mtime, space termination: 12 bytes */ - '0','0','0','0','0','0','0','0','0','0','0', '\0', - /* Initial checksum value: 8 spaces */ - ' ',' ',' ',' ',' ',' ',' ',' ', - /* Typeflag: 1 byte */ - '0', /* '0' = regular file */ - /* Linkname: 100 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0, - /* Magic: 8 bytes */ - 'u','s','t','a','r',' ', ' ','\0', - /* Uname: 32 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /* Gname: 32 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /* rdevmajor + null padding: 8 bytes */ - '\0','\0','\0','\0','\0','\0', '\0','\0', - /* rdevminor + null padding: 8 bytes */ - '\0','\0','\0','\0','\0','\0', '\0','\0', - /* Padding: 167 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0 -}; - -static int archive_write_gnutar_options(struct archive_write *, - const char *, const char *); -static int archive_format_gnutar_header(struct archive_write *, char h[512], - struct archive_entry *, int tartype); -static int archive_write_gnutar_header(struct archive_write *, - struct archive_entry *entry); -static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, - size_t s); -static int archive_write_gnutar_free(struct archive_write *); -static int archive_write_gnutar_close(struct archive_write *); -static int archive_write_gnutar_finish_entry(struct archive_write *); -static int format_256(int64_t, char *, int); -static int format_number(int64_t, char *, int size, int maxsize); -static int format_octal(int64_t, char *, int); - -/* - * Set output format to 'GNU tar' format. - */ -int -archive_write_set_format_gnutar(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - struct gnutar *gnutar; - - gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar)); - if (gnutar == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate gnutar data"); - return (ARCHIVE_FATAL); - } - a->format_data = gnutar; - a->format_name = "gnutar"; - a->format_options = archive_write_gnutar_options; - a->format_write_header = archive_write_gnutar_header; - a->format_write_data = archive_write_gnutar_data; - a->format_close = archive_write_gnutar_close; - a->format_free = archive_write_gnutar_free; - a->format_finish_entry = archive_write_gnutar_finish_entry; - a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; - a->archive.archive_format_name = "GNU tar"; - return (ARCHIVE_OK); -} - -static int -archive_write_gnutar_options(struct archive_write *a, const char *key, - const char *val) -{ - struct gnutar *gnutar = (struct gnutar *)a->format_data; - int ret = ARCHIVE_FAILED; - - if (strcmp(key, "hdrcharset") == 0) { - if (val == NULL || val[0] == 0) - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "%s: hdrcharset option needs a character-set name", - a->format_name); - else { - gnutar->opt_sconv = archive_string_conversion_to_charset( - &a->archive, val, 0); - if (gnutar->opt_sconv != NULL) - ret = ARCHIVE_OK; - else - ret = ARCHIVE_FATAL; - } - return (ret); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -static int -archive_write_gnutar_close(struct archive_write *a) -{ - return (__archive_write_nulls(a, 512*2)); -} - -static int -archive_write_gnutar_free(struct archive_write *a) -{ - struct gnutar *gnutar; - - gnutar = (struct gnutar *)a->format_data; - free(gnutar); - a->format_data = NULL; - return (ARCHIVE_OK); -} - -static int -archive_write_gnutar_finish_entry(struct archive_write *a) -{ - struct gnutar *gnutar; - int ret; - - gnutar = (struct gnutar *)a->format_data; - ret = __archive_write_nulls(a, (size_t) - (gnutar->entry_bytes_remaining + gnutar->entry_padding)); - gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; - return (ret); -} - -static ssize_t -archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) -{ - struct gnutar *gnutar; - 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); - gnutar->entry_bytes_remaining -= s; - if (ret != ARCHIVE_OK) - return (ret); - return (s); -} - -static int -archive_write_gnutar_header(struct archive_write *a, - struct archive_entry *entry) -{ - char buff[512]; - int r, ret, ret2 = ARCHIVE_OK; - int 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) { - gnutar->sconv_default = - archive_string_default_conversion_for_write( - &(a->archive)); - gnutar->init_default_conversion = 1; - } - sconv = gnutar->sconv_default; - } else - sconv = gnutar->opt_sconv; - - /* Only regular files (not hardlinks) have data. */ - if (archive_entry_hardlink(entry) != NULL || - archive_entry_symlink(entry) != NULL || - !(archive_entry_filetype(entry) == AE_IFREG)) - archive_entry_set_size(entry, 0); - - if (AE_IFDIR == archive_entry_filetype(entry)) { - const char *p; - size_t path_length; - /* - * Ensure a trailing '/'. Modify the entry so - * the client sees the change. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) - const wchar_t *wp; - - wp = archive_entry_pathname_w(entry); - if (wp != NULL && wp[wcslen(wp) -1] != L'/') { - struct archive_wstring ws; - - archive_string_init(&ws); - path_length = wcslen(wp); - if (archive_wstring_ensure(&ws, - path_length + 2) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - archive_wstring_free(&ws); - return(ARCHIVE_FATAL); - } - /* Should we keep '\' ? */ - if (wp[path_length -1] == L'\\') - path_length--; - archive_wstrncpy(&ws, wp, path_length); - archive_wstrappend_wchar(&ws, L'/'); - archive_entry_copy_pathname_w(entry, ws.s); - archive_wstring_free(&ws); - p = NULL; - } else -#endif - p = archive_entry_pathname(entry); - /* - * On Windows, this is a backup operation just in - * case getting WCS failed. On POSIX, this is a - * normal operation. - */ - if (p != NULL && p[strlen(p) - 1] != '/') { - struct archive_string as; - - archive_string_init(&as); - path_length = strlen(p); - if (archive_string_ensure(&as, - path_length + 2) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - archive_string_free(&as); - return(ARCHIVE_FATAL); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - /* NOTE: This might break the pathname - * if the current code page is CP932 and - * the pathname includes a character '\' - * as a part of its multibyte pathname. */ - if (p[strlen(p) -1] == '\\') - path_length--; - else -#endif - archive_strncpy(&as, p, path_length); - archive_strappend_char(&as, '/'); - archive_entry_copy_pathname(entry, as.s); - archive_string_free(&as); - } - } - -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pathname, hardlink and symlink - * are all slash '/', not the Windows path separator '\'. */ - entry_main = __la_win_entry_in_posix_pathseparator(entry); - if (entry_main == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - return(ARCHIVE_FATAL); - } - if (entry != entry_main) - entry = entry_main; - else - entry_main = NULL; -#else - entry_main = NULL; -#endif - r = archive_entry_pathname_l(entry, &(gnutar->pathname), - &(gnutar->pathname_length), sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Pathame"); - ret = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate pathname '%s' to %s", - archive_entry_pathname(entry), - archive_string_conversion_charset_name(sconv)); - ret2 = ARCHIVE_WARN; - } - r = archive_entry_uname_l(entry, &(gnutar->uname), - &(gnutar->uname_length), sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Uname"); - ret = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate uname '%s' to %s", - archive_entry_uname(entry), - archive_string_conversion_charset_name(sconv)); - ret2 = ARCHIVE_WARN; - } - r = archive_entry_gname_l(entry, &(gnutar->gname), - &(gnutar->gname_length), sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Gname"); - ret = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate gname '%s' to %s", - archive_entry_gname(entry), - archive_string_conversion_charset_name(sconv)); - ret2 = ARCHIVE_WARN; - } - - /* If linkname is longer than 100 chars we need to add a 'K' header. */ - r = archive_entry_hardlink_l(entry, &(gnutar->linkname), - &(gnutar->linkname_length), sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Linkname"); - ret = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate linkname '%s' to %s", - archive_entry_hardlink(entry), - archive_string_conversion_charset_name(sconv)); - ret2 = ARCHIVE_WARN; - } - if (gnutar->linkname_length == 0) { - r = archive_entry_symlink_l(entry, &(gnutar->linkname), - &(gnutar->linkname_length), sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Linkname"); - ret = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate linkname '%s' to %s", - archive_entry_hardlink(entry), - archive_string_conversion_charset_name(sconv)); - ret2 = ARCHIVE_WARN; - } - } - if (gnutar->linkname_length > GNUTAR_linkname_size) { - size_t length = gnutar->linkname_length + 1; - struct archive_entry *temp = archive_entry_new2(&a->archive); - - /* Uname/gname here don't really matter since no one reads them; - * these are the values that GNU tar happens to use on FreeBSD. */ - archive_entry_set_uname(temp, "root"); - archive_entry_set_gname(temp, "wheel"); - - archive_entry_set_pathname(temp, "././@LongLink"); - archive_entry_set_size(temp, length); - ret = archive_format_gnutar_header(a, buff, temp, 'K'); - archive_entry_free(temp); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - ret = __archive_write_output(a, buff, 512); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - /* Write name and trailing null byte. */ - ret = __archive_write_output(a, gnutar->linkname, length); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - /* Pad to 512 bytes */ - ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - } - - /* If pathname is longer than 100 chars we need to add an 'L' header. */ - if (gnutar->pathname_length > GNUTAR_name_size) { - const char *pathname = gnutar->pathname; - size_t length = gnutar->pathname_length + 1; - struct archive_entry *temp = archive_entry_new2(&a->archive); - - /* Uname/gname here don't really matter since no one reads them; - * these are the values that GNU tar happens to use on FreeBSD. */ - archive_entry_set_uname(temp, "root"); - archive_entry_set_gname(temp, "wheel"); - - archive_entry_set_pathname(temp, "././@LongLink"); - archive_entry_set_size(temp, length); - ret = archive_format_gnutar_header(a, buff, temp, 'L'); - archive_entry_free(temp); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - ret = __archive_write_output(a, buff, 512); - if(ret < ARCHIVE_WARN) - goto exit_write_header; - /* Write pathname + trailing null byte. */ - ret = __archive_write_output(a, pathname, length); - if(ret < ARCHIVE_WARN) - goto exit_write_header; - /* Pad to multiple of 512 bytes. */ - ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - } - - if (archive_entry_hardlink(entry) != NULL) { - tartype = '1'; - } else - switch (archive_entry_filetype(entry)) { - case AE_IFREG: tartype = '0' ; break; - case AE_IFLNK: tartype = '2' ; break; - case AE_IFCHR: tartype = '3' ; break; - case AE_IFBLK: tartype = '4' ; break; - case AE_IFDIR: tartype = '5' ; break; - case AE_IFIFO: tartype = '6' ; break; - case AE_IFSOCK: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "tar format cannot archive socket"); - ret = ARCHIVE_FAILED; - goto exit_write_header; - default: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "tar format cannot archive this (mode=0%lo)", - (unsigned long)archive_entry_mode(entry)); - ret = ARCHIVE_FAILED; - goto exit_write_header; - } - - ret = archive_format_gnutar_header(a, buff, entry, tartype); - if (ret < ARCHIVE_WARN) - goto exit_write_header; - if (ret2 < ret) - ret = ret2; - ret2 = __archive_write_output(a, buff, 512); - if (ret2 < ARCHIVE_WARN) { - ret = ret2; - goto exit_write_header; - } - if (ret2 < ret) - ret = ret2; - - gnutar->entry_bytes_remaining = archive_entry_size(entry); - gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining); -exit_write_header: - if (entry_main) - archive_entry_free(entry_main); - return (ret); -} - -static int -archive_format_gnutar_header(struct archive_write *a, char h[512], - struct archive_entry *entry, int tartype) -{ - unsigned int checksum; - int i, ret; - size_t copy_length; - const char *p; - struct gnutar *gnutar; - - gnutar = (struct gnutar *)a->format_data; - - ret = 0; - - /* - * The "template header" already includes the signature, - * various end-of-field markers, and other required elements. - */ - memcpy(h, &template_header, 512); - - /* - * Because the block is already null-filled, and strings - * are allowed to exactly fill their destination (without null), - * I use memcpy(dest, src, strlen()) here a lot to copy strings. - */ - - if (tartype == 'K' || tartype == 'L') { - p = archive_entry_pathname(entry); - copy_length = strlen(p); - } else { - p = gnutar->pathname; - copy_length = gnutar->pathname_length; - } - if (copy_length > GNUTAR_name_size) - copy_length = GNUTAR_name_size; - memcpy(h + GNUTAR_name_offset, p, copy_length); - - if ((copy_length = gnutar->linkname_length) > 0) { - if (copy_length > GNUTAR_linkname_size) - copy_length = GNUTAR_linkname_size; - memcpy(h + GNUTAR_linkname_offset, gnutar->linkname, - copy_length); - } - - /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */ - if (tartype == 'K' || tartype == 'L') { - p = archive_entry_uname(entry); - copy_length = strlen(p); - } else { - p = gnutar->uname; - copy_length = gnutar->uname_length; - } - if (copy_length > 0) { - if (copy_length > GNUTAR_uname_size) - copy_length = GNUTAR_uname_size; - memcpy(h + GNUTAR_uname_offset, p, copy_length); - } - - /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */ - if (tartype == 'K' || tartype == 'L') { - p = archive_entry_gname(entry); - copy_length = strlen(p); - } else { - p = gnutar->gname; - copy_length = gnutar->gname_length; - } - if (copy_length > 0) { - if (strlen(p) > GNUTAR_gname_size) - copy_length = GNUTAR_gname_size; - memcpy(h + GNUTAR_gname_offset, p, copy_length); - } - - /* By truncating the mode here, we ensure it always fits. */ - format_octal(archive_entry_mode(entry) & 07777, - h + GNUTAR_mode_offset, GNUTAR_mode_size); - - /* GNU tar supports base-256 here, so should never overflow. */ - if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset, - GNUTAR_uid_size, GNUTAR_uid_max_size)) { - archive_set_error(&a->archive, ERANGE, - "Numeric user ID %jd too large", - (intmax_t)archive_entry_uid(entry)); - ret = ARCHIVE_FAILED; - } - - /* GNU tar supports base-256 here, so should never overflow. */ - if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset, - GNUTAR_gid_size, GNUTAR_gid_max_size)) { - archive_set_error(&a->archive, ERANGE, - "Numeric group ID %jd too large", - (intmax_t)archive_entry_gid(entry)); - ret = ARCHIVE_FAILED; - } - - /* GNU tar supports base-256 here, so should never overflow. */ - if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset, - GNUTAR_size_size, GNUTAR_size_max_size)) { - archive_set_error(&a->archive, ERANGE, - "File size out of range"); - ret = ARCHIVE_FAILED; - } - - /* Shouldn't overflow before 2106, since mtime field is 33 bits. */ - format_octal(archive_entry_mtime(entry), - h + GNUTAR_mtime_offset, GNUTAR_mtime_size); - - if (archive_entry_filetype(entry) == AE_IFBLK - || archive_entry_filetype(entry) == AE_IFCHR) { - if (format_octal(archive_entry_rdevmajor(entry), - h + GNUTAR_rdevmajor_offset, - GNUTAR_rdevmajor_size)) { - archive_set_error(&a->archive, ERANGE, - "Major device number too large"); - ret = ARCHIVE_FAILED; - } - - if (format_octal(archive_entry_rdevminor(entry), - h + GNUTAR_rdevminor_offset, - GNUTAR_rdevminor_size)) { - archive_set_error(&a->archive, ERANGE, - "Minor device number too large"); - ret = ARCHIVE_FAILED; - } - } - - h[GNUTAR_typeflag_offset] = tartype; - - checksum = 0; - for (i = 0; i < 512; i++) - checksum += 255 & (unsigned int)h[i]; - h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ - /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ - format_octal(checksum, h + GNUTAR_checksum_offset, 6); - return (ret); -} - -/* - * Format a number into a field, falling back to base-256 if necessary. - */ -static int -format_number(int64_t v, char *p, int s, int maxsize) -{ - int64_t limit = ((int64_t)1 << (s*3)); - - if (v < limit) - return (format_octal(v, p, s)); - return (format_256(v, p, maxsize)); -} - -/* - * Format a number into the specified field using base-256. - */ -static int -format_256(int64_t v, char *p, int s) -{ - p += s; - while (s-- > 0) { - *--p = (char)(v & 0xff); - v >>= 8; - } - *p |= 0x80; /* Set the base-256 marker bit. */ - return (0); -} - -/* - * Format a number into the specified field using octal. - */ -static int -format_octal(int64_t v, char *p, int s) -{ - int len = s; - - /* Octal values can't be negative, so use 0. */ - if (v < 0) - v = 0; - - p += s; /* Start at the end and work backwards. */ - while (s-- > 0) { - *--p = (char)('0' + (v & 7)); - v >>= 3; - } - - if (v == 0) - return (0); - - /* If it overflowed, fill field with max value. */ - while (len-- > 0) - *p++ = '7'; - - return (-1); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c deleted file mode 100644 index c54aeabd..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c +++ /dev/null @@ -1,763 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z kientzle $"); - - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_entry_locale.h" -#include "archive_private.h" -#include "archive_write_private.h" - -struct ustar { - uint64_t entry_bytes_remaining; - uint64_t entry_padding; - - struct archive_string_conv *opt_sconv; - struct archive_string_conv *sconv_default; - int init_default_conversion; -}; - -/* - * Define structure of POSIX 'ustar' tar header. - */ -#define USTAR_name_offset 0 -#define USTAR_name_size 100 -#define USTAR_mode_offset 100 -#define USTAR_mode_size 6 -#define USTAR_mode_max_size 8 -#define USTAR_uid_offset 108 -#define USTAR_uid_size 6 -#define USTAR_uid_max_size 8 -#define USTAR_gid_offset 116 -#define USTAR_gid_size 6 -#define USTAR_gid_max_size 8 -#define USTAR_size_offset 124 -#define USTAR_size_size 11 -#define USTAR_size_max_size 12 -#define USTAR_mtime_offset 136 -#define USTAR_mtime_size 11 -#define USTAR_mtime_max_size 11 -#define USTAR_checksum_offset 148 -#define USTAR_checksum_size 8 -#define USTAR_typeflag_offset 156 -#define USTAR_typeflag_size 1 -#define USTAR_linkname_offset 157 -#define USTAR_linkname_size 100 -#define USTAR_magic_offset 257 -#define USTAR_magic_size 6 -#define USTAR_version_offset 263 -#define USTAR_version_size 2 -#define USTAR_uname_offset 265 -#define USTAR_uname_size 32 -#define USTAR_gname_offset 297 -#define USTAR_gname_size 32 -#define USTAR_rdevmajor_offset 329 -#define USTAR_rdevmajor_size 6 -#define USTAR_rdevmajor_max_size 8 -#define USTAR_rdevminor_offset 337 -#define USTAR_rdevminor_size 6 -#define USTAR_rdevminor_max_size 8 -#define USTAR_prefix_offset 345 -#define USTAR_prefix_size 155 -#define USTAR_padding_offset 500 -#define USTAR_padding_size 12 - -/* - * A filled-in copy of the header for initialization. - */ -static const char template_header[] = { - /* name: 100 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0, - /* Mode, space-null termination: 8 bytes */ - '0','0','0','0','0','0', ' ','\0', - /* uid, space-null termination: 8 bytes */ - '0','0','0','0','0','0', ' ','\0', - /* gid, space-null termination: 8 bytes */ - '0','0','0','0','0','0', ' ','\0', - /* size, space termination: 12 bytes */ - '0','0','0','0','0','0','0','0','0','0','0', ' ', - /* mtime, space termination: 12 bytes */ - '0','0','0','0','0','0','0','0','0','0','0', ' ', - /* Initial checksum value: 8 spaces */ - ' ',' ',' ',' ',' ',' ',' ',' ', - /* Typeflag: 1 byte */ - '0', /* '0' = regular file */ - /* Linkname: 100 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0, - /* Magic: 6 bytes, Version: 2 bytes */ - 'u','s','t','a','r','\0', '0','0', - /* Uname: 32 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /* Gname: 32 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - /* rdevmajor + space/null padding: 8 bytes */ - '0','0','0','0','0','0', ' ','\0', - /* rdevminor + space/null padding: 8 bytes */ - '0','0','0','0','0','0', ' ','\0', - /* Prefix: 155 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0, - /* Padding: 12 bytes */ - 0,0,0,0,0,0,0,0, 0,0,0,0 -}; - -static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff, - size_t s); -static int archive_write_ustar_free(struct archive_write *); -static int archive_write_ustar_close(struct archive_write *); -static int archive_write_ustar_finish_entry(struct archive_write *); -static int archive_write_ustar_header(struct archive_write *, - struct archive_entry *entry); -static int archive_write_ustar_options(struct archive_write *, - const char *, const char *); -static int format_256(int64_t, char *, int); -static int format_number(int64_t, char *, int size, int max, int strict); -static int format_octal(int64_t, char *, int); - -/* - * Set output format to 'ustar' format. - */ -int -archive_write_set_format_ustar(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - struct ustar *ustar; - - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, - 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); - - /* Basic internal sanity test. */ - if (sizeof(template_header) != 512) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Internal: template_header wrong size: %zu should be 512", - sizeof(template_header)); - return (ARCHIVE_FATAL); - } - - ustar = (struct ustar *)calloc(1, sizeof(*ustar)); - if (ustar == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - return (ARCHIVE_FATAL); - } - a->format_data = ustar; - a->format_name = "ustar"; - a->format_options = archive_write_ustar_options; - a->format_write_header = archive_write_ustar_header; - a->format_write_data = archive_write_ustar_data; - a->format_close = archive_write_ustar_close; - a->format_free = archive_write_ustar_free; - a->format_finish_entry = archive_write_ustar_finish_entry; - a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; - a->archive.archive_format_name = "POSIX ustar"; - return (ARCHIVE_OK); -} - -static int -archive_write_ustar_options(struct archive_write *a, const char *key, - const char *val) -{ - struct ustar *ustar = (struct ustar *)a->format_data; - int ret = ARCHIVE_FAILED; - - if (strcmp(key, "hdrcharset") == 0) { - if (val == NULL || val[0] == 0) - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "%s: hdrcharset option needs a character-set name", - a->format_name); - else { - ustar->opt_sconv = archive_string_conversion_to_charset( - &a->archive, val, 0); - if (ustar->opt_sconv != NULL) - ret = ARCHIVE_OK; - else - ret = ARCHIVE_FATAL; - } - return (ret); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -static int -archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) -{ - 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) { - ustar->sconv_default = - archive_string_default_conversion_for_write(&(a->archive)); - ustar->init_default_conversion = 1; - } - sconv = ustar->sconv_default; - } else - sconv = ustar->opt_sconv; - - /* Sanity check. */ - if (archive_entry_pathname(entry) == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Can't record entry in tar file without pathname"); - return (ARCHIVE_FAILED); - } - - /* Only regular files (not hardlinks) have data. */ - if (archive_entry_hardlink(entry) != NULL || - archive_entry_symlink(entry) != NULL || - !(archive_entry_filetype(entry) == AE_IFREG)) - archive_entry_set_size(entry, 0); - - if (AE_IFDIR == archive_entry_filetype(entry)) { - const char *p; - size_t path_length; - /* - * Ensure a trailing '/'. Modify the entry so - * the client sees the change. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) - const wchar_t *wp; - - wp = archive_entry_pathname_w(entry); - if (wp != NULL && wp[wcslen(wp) -1] != L'/') { - struct archive_wstring ws; - - archive_string_init(&ws); - path_length = wcslen(wp); - if (archive_wstring_ensure(&ws, - path_length + 2) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - archive_wstring_free(&ws); - return(ARCHIVE_FATAL); - } - /* Should we keep '\' ? */ - if (wp[path_length -1] == L'\\') - path_length--; - archive_wstrncpy(&ws, wp, path_length); - archive_wstrappend_wchar(&ws, L'/'); - archive_entry_copy_pathname_w(entry, ws.s); - archive_wstring_free(&ws); - p = NULL; - } else -#endif - p = archive_entry_pathname(entry); - /* - * On Windows, this is a backup operation just in - * case getting WCS failed. On POSIX, this is a - * normal operation. - */ - if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') { - struct archive_string as; - - archive_string_init(&as); - path_length = strlen(p); - if (archive_string_ensure(&as, - path_length + 2) == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - archive_string_free(&as); - return(ARCHIVE_FATAL); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - /* NOTE: This might break the pathname - * if the current code page is CP932 and - * the pathname includes a character '\' - * as a part of its multibyte pathname. */ - if (p[strlen(p) -1] == '\\') - path_length--; - else -#endif - archive_strncpy(&as, p, path_length); - archive_strappend_char(&as, '/'); - archive_entry_copy_pathname(entry, as.s); - archive_string_free(&as); - } - } - -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pathname, hardlink and symlink - * are all slash '/', not the Windows path separator '\'. */ - entry_main = __la_win_entry_in_posix_pathseparator(entry); - if (entry_main == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - return(ARCHIVE_FATAL); - } - if (entry != entry_main) - entry = entry_main; - else - entry_main = NULL; -#else - entry_main = NULL; -#endif - ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv); - if (ret < ARCHIVE_WARN) { - if (entry_main) - archive_entry_free(entry_main); - return (ret); - } - ret2 = __archive_write_output(a, buff, 512); - if (ret2 < ARCHIVE_WARN) { - if (entry_main) - archive_entry_free(entry_main); - return (ret2); - } - if (ret2 < ret) - ret = ret2; - - ustar->entry_bytes_remaining = archive_entry_size(entry); - ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining); - if (entry_main) - archive_entry_free(entry_main); - return (ret); -} - -/* - * Format a basic 512-byte "ustar" header. - * - * Returns -1 if format failed (due to field overflow). - * Note that this always formats as much of the header as possible. - * If "strict" is set to zero, it will extend numeric fields as - * necessary (overwriting terminators or using base-256 extensions). - * - * This is exported so that other 'tar' formats can use it. - */ -int -__archive_write_format_header_ustar(struct archive_write *a, char h[512], - struct archive_entry *entry, int tartype, int strict, - struct archive_string_conv *sconv) -{ - unsigned int checksum; - int i, r, ret; - size_t copy_length; - const char *p, *pp; - int mytartype; - - ret = 0; - mytartype = -1; - /* - * The "template header" already includes the "ustar" - * signature, various end-of-field markers and other required - * elements. - */ - memcpy(h, &template_header, 512); - - /* - * Because the block is already null-filled, and strings - * are allowed to exactly fill their destination (without null), - * I use memcpy(dest, src, strlen()) here a lot to copy strings. - */ - r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Pathname"); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate pathname '%s' to %s", - pp, archive_string_conversion_charset_name(sconv)); - ret = ARCHIVE_WARN; - } - if (copy_length <= USTAR_name_size) - memcpy(h + USTAR_name_offset, pp, copy_length); - else { - /* Store in two pieces, splitting at a '/'. */ - p = strchr(pp + copy_length - USTAR_name_size - 1, '/'); - /* - * Look for the next '/' if we chose the first character - * as the separator. (ustar format doesn't permit - * an empty prefix.) - */ - if (p == pp) - p = strchr(p + 1, '/'); - /* Fail if the name won't fit. */ - if (!p) { - /* No separator. */ - archive_set_error(&a->archive, ENAMETOOLONG, - "Pathname too long"); - ret = ARCHIVE_FAILED; - } else if (p[1] == '\0') { - /* - * The only feasible separator is a final '/'; - * this would result in a non-empty prefix and - * an empty name, which POSIX doesn't - * explicitly forbid, but it just feels wrong. - */ - archive_set_error(&a->archive, ENAMETOOLONG, - "Pathname too long"); - ret = ARCHIVE_FAILED; - } else if (p > pp + USTAR_prefix_size) { - /* Prefix is too long. */ - archive_set_error(&a->archive, ENAMETOOLONG, - "Pathname too long"); - ret = ARCHIVE_FAILED; - } else { - /* Copy prefix and remainder to appropriate places */ - memcpy(h + USTAR_prefix_offset, pp, p - pp); - memcpy(h + USTAR_name_offset, p + 1, - pp + copy_length - p - 1); - } - } - - r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Linkname"); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate linkname '%s' to %s", - p, archive_string_conversion_charset_name(sconv)); - ret = ARCHIVE_WARN; - } - if (copy_length > 0) - mytartype = '1'; - else { - r = archive_entry_symlink_l(entry, &p, ©_length, sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Linkname"); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate linkname '%s' to %s", - p, archive_string_conversion_charset_name(sconv)); - ret = ARCHIVE_WARN; - } - } - if (copy_length > 0) { - if (copy_length > USTAR_linkname_size) { - archive_set_error(&a->archive, ENAMETOOLONG, - "Link contents too long"); - ret = ARCHIVE_FAILED; - copy_length = USTAR_linkname_size; - } - memcpy(h + USTAR_linkname_offset, p, copy_length); - } - - r = archive_entry_uname_l(entry, &p, ©_length, sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Uname"); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate uname '%s' to %s", - p, archive_string_conversion_charset_name(sconv)); - ret = ARCHIVE_WARN; - } - if (copy_length > 0) { - if (copy_length > USTAR_uname_size) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Username too long"); - ret = ARCHIVE_FAILED; - copy_length = USTAR_uname_size; - } - memcpy(h + USTAR_uname_offset, p, copy_length); - } - - r = archive_entry_gname_l(entry, &p, ©_length, sconv); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Gname"); - return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate gname '%s' to %s", - p, archive_string_conversion_charset_name(sconv)); - ret = ARCHIVE_WARN; - } - if (copy_length > 0) { - if (strlen(p) > USTAR_gname_size) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Group name too long"); - ret = ARCHIVE_FAILED; - copy_length = USTAR_gname_size; - } - memcpy(h + USTAR_gname_offset, p, copy_length); - } - - if (format_number(archive_entry_mode(entry) & 07777, - h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "Numeric mode too large"); - ret = ARCHIVE_FAILED; - } - - if (format_number(archive_entry_uid(entry), - h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "Numeric user ID too large"); - ret = ARCHIVE_FAILED; - } - - if (format_number(archive_entry_gid(entry), - h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "Numeric group ID too large"); - ret = ARCHIVE_FAILED; - } - - if (format_number(archive_entry_size(entry), - h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "File size out of range"); - ret = ARCHIVE_FAILED; - } - - if (format_number(archive_entry_mtime(entry), - h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "File modification time too large"); - ret = ARCHIVE_FAILED; - } - - if (archive_entry_filetype(entry) == AE_IFBLK - || archive_entry_filetype(entry) == AE_IFCHR) { - if (format_number(archive_entry_rdevmajor(entry), - h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size, - USTAR_rdevmajor_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "Major device number too large"); - ret = ARCHIVE_FAILED; - } - - if (format_number(archive_entry_rdevminor(entry), - h + USTAR_rdevminor_offset, USTAR_rdevminor_size, - USTAR_rdevminor_max_size, strict)) { - archive_set_error(&a->archive, ERANGE, - "Minor device number too large"); - ret = ARCHIVE_FAILED; - } - } - - if (tartype >= 0) { - h[USTAR_typeflag_offset] = tartype; - } else if (mytartype >= 0) { - h[USTAR_typeflag_offset] = mytartype; - } else { - switch (archive_entry_filetype(entry)) { - case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break; - case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break; - case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break; - case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break; - case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break; - case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break; - case AE_IFSOCK: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "tar format cannot archive socket"); - return (ARCHIVE_FAILED); - default: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "tar format cannot archive this (mode=0%lo)", - (unsigned long)archive_entry_mode(entry)); - ret = ARCHIVE_FAILED; - } - } - - checksum = 0; - for (i = 0; i < 512; i++) - checksum += 255 & (unsigned int)h[i]; - h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ - /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ - format_octal(checksum, h + USTAR_checksum_offset, 6); - return (ret); -} - -/* - * Format a number into a field, with some intelligence. - */ -static int -format_number(int64_t v, char *p, int s, int maxsize, int strict) -{ - int64_t limit; - - limit = ((int64_t)1 << (s*3)); - - /* "Strict" only permits octal values with proper termination. */ - if (strict) - return (format_octal(v, p, s)); - - /* - * In non-strict mode, we allow the number to overwrite one or - * more bytes of the field termination. Even old tar - * implementations should be able to handle this with no - * problem. - */ - if (v >= 0) { - while (s <= maxsize) { - if (v < limit) - return (format_octal(v, p, s)); - s++; - limit <<= 3; - } - } - - /* Base-256 can handle any number, positive or negative. */ - return (format_256(v, p, maxsize)); -} - -/* - * Format a number into the specified field using base-256. - */ -static int -format_256(int64_t v, char *p, int s) -{ - p += s; - while (s-- > 0) { - *--p = (char)(v & 0xff); - v >>= 8; - } - *p |= 0x80; /* Set the base-256 marker bit. */ - return (0); -} - -/* - * Format a number into the specified field. - */ -static int -format_octal(int64_t v, char *p, int s) -{ - int len; - - len = s; - - /* Octal values can't be negative, so use 0. */ - if (v < 0) { - while (len-- > 0) - *p++ = '0'; - return (-1); - } - - p += s; /* Start at the end and work backwards. */ - while (s-- > 0) { - *--p = (char)('0' + (v & 7)); - v >>= 3; - } - - if (v == 0) - return (0); - - /* If it overflowed, fill field with max value. */ - while (len-- > 0) - *p++ = '7'; - - return (-1); -} - -static int -archive_write_ustar_close(struct archive_write *a) -{ - return (__archive_write_nulls(a, 512*2)); -} - -static int -archive_write_ustar_free(struct archive_write *a) -{ - struct ustar *ustar; - - ustar = (struct ustar *)a->format_data; - free(ustar); - a->format_data = NULL; - return (ARCHIVE_OK); -} - -static int -archive_write_ustar_finish_entry(struct archive_write *a) -{ - struct ustar *ustar; - 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 = 0; - return (ret); -} - -static ssize_t -archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) -{ - struct ustar *ustar; - 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); - ustar->entry_bytes_remaining -= s; - if (ret != ARCHIVE_OK) - return (ret); - return (s); -} diff --git a/3rdparty/libarchive/libarchive/archive_write_set_options.c b/3rdparty/libarchive/libarchive/archive_write_set_options.c deleted file mode 100644 index 962309ad..00000000 --- a/3rdparty/libarchive/libarchive/archive_write_set_options.c +++ /dev/null @@ -1,130 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD$"); - -#include "archive_write_private.h" -#include "archive_options_private.h" - -static int archive_set_format_option(struct archive *a, - const char *m, const char *o, const char *v); -static int archive_set_filter_option(struct archive *a, - const char *m, const char *o, const char *v); -static int archive_set_option(struct archive *a, - const char *m, const char *o, const char *v); - -int -archive_write_set_format_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_WRITE_MAGIC, "archive_write_set_format_option", - archive_set_format_option); -} - -int -archive_write_set_filter_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_WRITE_MAGIC, "archive_write_set_filter_option", - archive_set_filter_option); -} - -int -archive_write_set_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_option(a, m, o, v, - ARCHIVE_WRITE_MAGIC, "archive_write_set_option", - archive_set_option); -} - -int -archive_write_set_options(struct archive *a, const char *options) -{ - return _archive_set_options(a, options, - ARCHIVE_WRITE_MAGIC, "archive_write_set_options", - archive_set_option); -} - -static int -archive_set_format_option(struct archive *_a, const char *m, const char *o, - const char *v) -{ - struct archive_write *a = (struct archive_write *)_a; - - if (a->format_name == NULL) - return (m == NULL)?ARCHIVE_FAILED:ARCHIVE_WARN - 1; - /* If the format name didn't match, return a special code for - * _archive_set_option[s]. */ - if (m != NULL && strcmp(m, a->format_name) != 0) - return (ARCHIVE_WARN - 1); - if (a->format_options == NULL) - return (ARCHIVE_WARN); - return a->format_options(a, o, v); -} - -static int -archive_set_filter_option(struct archive *_a, const char *m, const char *o, - const char *v) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *filter; - int r, rv = ARCHIVE_WARN; - - for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) { - if (filter->options == NULL) - continue; - if (m != NULL && strcmp(filter->name, m) != 0) - continue; - - r = filter->options(filter, o, v); - - if (r == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - if (m != NULL) - return (r); - - if (r == ARCHIVE_OK) - rv = ARCHIVE_OK; - } - /* If the filter name didn't match, return a special code for - * _archive_set_option[s]. */ - if (rv == ARCHIVE_WARN && m != NULL) - rv = ARCHIVE_WARN - 1; - return (rv); -} - -static int -archive_set_option(struct archive *a, const char *m, const char *o, - const char *v) -{ - return _archive_set_either_option(a, m, o, v, - archive_set_format_option, - archive_set_filter_option); -} diff --git a/3rdparty/libarchive/libarchive/config_freebsd.h b/3rdparty/libarchive/libarchive/config_freebsd.h deleted file mode 100644 index be25258f..00000000 --- a/3rdparty/libarchive/libarchive/config_freebsd.h +++ /dev/null @@ -1,259 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -/* FreeBSD 5.0 and later has ACL and extattr support. */ -#if __FreeBSD__ > 4 -#define ARCHIVE_ACL_FREEBSD 1 -#define HAVE_ACL_GET_PERM_NP 1 -#define HAVE_ARC4RANDOM_BUF 1 -#define HAVE_EXTATTR_GET_FILE 1 -#define HAVE_EXTATTR_LIST_FILE 1 -#define HAVE_EXTATTR_SET_FD 1 -#define HAVE_EXTATTR_SET_FILE 1 -#define HAVE_STRUCT_XVFSCONF 1 -#define HAVE_SYS_ACL_H 1 -#define HAVE_SYS_EXTATTR_H 1 -#if __FreeBSD__ > 7 -/* FreeBSD 8.0 and later has NFSv4 ACL support */ -#define ARCHIVE_ACL_FREEBSD_NFS4 1 -#define HAVE_ACL_GET_LINK_NP 1 -#define HAVE_ACL_IS_TRIVIAL_NP 1 -#define HAVE_ACL_SET_LINK_NP 1 -#endif /* __FreeBSD__ > 7 */ -#endif /* __FreeBSD__ > 4 */ - -#ifdef WITH_OPENSSL -#define HAVE_LIBCRYPTO 1 -#define HAVE_OPENSSL_EVP_H 1 -#define HAVE_OPENSSL_MD5_H 1 -#define HAVE_OPENSSL_RIPEMD_H 1 -#define HAVE_OPENSSL_SHA_H 1 -#define HAVE_OPENSSL_SHA256_INIT 1 -#define HAVE_OPENSSL_SHA384_INIT 1 -#define HAVE_OPENSSL_SHA512_INIT 1 -#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1 -#define HAVE_SHA256 1 -#define HAVE_SHA384 1 -#define HAVE_SHA512 1 -#else -#define HAVE_LIBMD 1 -#define HAVE_MD5_H 1 -#define HAVE_MD5INIT 1 -#define HAVE_RIPEMD_H 1 -#define HAVE_SHA_H 1 -#define HAVE_SHA1 1 -#define HAVE_SHA1_INIT 1 -#define HAVE_SHA256 1 -#define HAVE_SHA256_H 1 -#define HAVE_SHA256_INIT 1 -#define HAVE_SHA512 1 -#define HAVE_SHA512_H 1 -#define HAVE_SHA512_INIT 1 -#endif - -#define HAVE_BSDXML_H 1 -#define HAVE_BZLIB_H 1 -#define HAVE_CHFLAGS 1 -#define HAVE_CHOWN 1 -#define HAVE_CHROOT 1 -#define HAVE_CTIME_R 1 -#define HAVE_CTYPE_H 1 -#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1 -#define HAVE_DECL_INT32_MAX 1 -#define HAVE_DECL_INT32_MIN 1 -#define HAVE_DECL_INT64_MAX 1 -#define HAVE_DECL_INT64_MIN 1 -#define HAVE_DECL_INTMAX_MAX 1 -#define HAVE_DECL_INTMAX_MIN 1 -#define HAVE_DECL_SIZE_MAX 1 -#define HAVE_DECL_SSIZE_MAX 1 -#define HAVE_DECL_STRERROR_R 1 -#define HAVE_DECL_UINT32_MAX 1 -#define HAVE_DECL_UINT64_MAX 1 -#define HAVE_DECL_UINTMAX_MAX 1 -#define HAVE_DIRENT_H 1 -#define HAVE_DLFCN_H 1 -#define HAVE_D_MD_ORDER 1 -#define HAVE_EFTYPE 1 -#define HAVE_EILSEQ 1 -#define HAVE_ERRNO_H 1 -#define HAVE_FCHDIR 1 -#define HAVE_FCHFLAGS 1 -#define HAVE_FCHMOD 1 -#define HAVE_FCHOWN 1 -#define HAVE_FCNTL 1 -#define HAVE_FCNTL_H 1 -#define HAVE_FDOPENDIR 1 -#define HAVE_FORK 1 -#define HAVE_FSEEKO 1 -#define HAVE_FSTAT 1 -#define HAVE_FSTATAT 1 -#define HAVE_FSTATFS 1 -#define HAVE_FSTATVFS 1 -#define HAVE_FTRUNCATE 1 -#define HAVE_FUTIMES 1 -#define HAVE_FUTIMESAT 1 -#define HAVE_GETEUID 1 -#define HAVE_GETGRGID_R 1 -#define HAVE_GETGRNAM_R 1 -#define HAVE_GETPID 1 -#define HAVE_GETPWNAM_R 1 -#define HAVE_GETPWUID_R 1 -#define HAVE_GETVFSBYNAME 1 -#define HAVE_GMTIME_R 1 -#define HAVE_GRP_H 1 -#define HAVE_INTMAX_T 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LANGINFO_H 1 -#define HAVE_LCHFLAGS 1 -#define HAVE_LCHMOD 1 -#define HAVE_LCHOWN 1 -#define HAVE_LIBZ 1 -#define HAVE_LIMITS_H 1 -#define HAVE_LINK 1 -#define HAVE_LOCALE_H 1 -#define HAVE_LOCALTIME_R 1 -#define HAVE_LONG_LONG_INT 1 -#define HAVE_LSTAT 1 -#define HAVE_LUTIMES 1 -#define HAVE_MBRTOWC 1 -#define HAVE_MEMMOVE 1 -#define HAVE_MEMORY_H 1 -#define HAVE_MEMSET 1 -#define HAVE_MKDIR 1 -#define HAVE_MKFIFO 1 -#define HAVE_MKNOD 1 -#define HAVE_MKSTEMP 1 -#define HAVE_NL_LANGINFO 1 -#define HAVE_OPENAT 1 -#define HAVE_PATHS_H 1 -#define HAVE_PIPE 1 -#define HAVE_POLL 1 -#define HAVE_POLL_H 1 -#define HAVE_POSIX_SPAWNP 1 -#define HAVE_PTHREAD_H 1 -#define HAVE_PWD_H 1 -#define HAVE_READDIR_R 1 -#define HAVE_READLINK 1 -#define HAVE_READLINKAT 1 -#define HAVE_READPASSPHRASE 1 -#define HAVE_READPASSPHRASE_H 1 -#define HAVE_REGEX_H 1 -#define HAVE_SELECT 1 -#define HAVE_SETENV 1 -#define HAVE_SETLOCALE 1 -#define HAVE_SIGACTION 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_SPAWN_H 1 -#define HAVE_STATFS 1 -#define HAVE_STATVFS 1 -#define HAVE_STDARG_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRCHR 1 -#define HAVE_STRDUP 1 -#define HAVE_STRERROR 1 -#define HAVE_STRERROR_R 1 -#define HAVE_STRFTIME 1 -#define HAVE_STRINGS_H 1 -#define HAVE_STRING_H 1 -#define HAVE_STRRCHR 1 -#define HAVE_STRUCT_STATFS_F_NAMEMAX 1 -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 -#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 -#define HAVE_STRUCT_STAT_ST_FLAGS 1 -#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 -#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 -#define HAVE_STRUCT_TM_TM_GMTOFF 1 -#define HAVE_SYMLINK 1 -#define HAVE_SYS_CDEFS_H 1 -#define HAVE_SYS_IOCTL_H 1 -#define HAVE_SYS_MOUNT_H 1 -#define HAVE_SYS_PARAM_H 1 -#define HAVE_SYS_POLL_H 1 -#define HAVE_SYS_SELECT_H 1 -#define HAVE_SYS_STATVFS_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_SYS_UTSNAME_H 1 -#define HAVE_SYS_WAIT_H 1 -#define HAVE_TIMEGM 1 -#define HAVE_TIME_H 1 -#define HAVE_TZSET 1 -#define HAVE_UINTMAX_T 1 -#define HAVE_UNISTD_H 1 -#define HAVE_UNSETENV 1 -#define HAVE_UNSIGNED_LONG_LONG 1 -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#define HAVE_UTIME 1 -#define HAVE_UTIMES 1 -#define HAVE_UTIME_H 1 -#define HAVE_VFORK 1 -#define HAVE_VPRINTF 1 -#define HAVE_WCHAR_H 1 -#define HAVE_WCHAR_T 1 -#define HAVE_WCRTOMB 1 -#define HAVE_WCSCMP 1 -#define HAVE_WCSCPY 1 -#define HAVE_WCSLEN 1 -#define HAVE_WCTOMB 1 -#define HAVE_WCTYPE_H 1 -#define HAVE_WMEMCMP 1 -#define HAVE_WMEMCPY 1 -#define HAVE_WMEMMOVE 1 -#define HAVE_ZLIB_H 1 -#define TIME_WITH_SYS_TIME 1 - -#if __FreeBSD_version >= 1100056 -#define HAVE_FUTIMENS 1 -#define HAVE_UTIMENSAT 1 -#endif - -/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */ -#if __FreeBSD__ < 5 -#define intmax_t int64_t -#define uintmax_t uint64_t -#endif - -/* FreeBSD defines for archive_hash.h */ -#ifdef WITH_OPENSSL -#define ARCHIVE_CRYPTO_MD5_OPENSSL 1 -#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1 -#define ARCHIVE_CRYPTO_SHA1_OPENSSL -#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1 -#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1 -#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1 -#else -#define ARCHIVE_CRYPTO_MD5_LIBMD 1 -#define ARCHIVE_CRYPTO_SHA1_LIBMD 1 -#define ARCHIVE_CRYPTO_SHA256_LIBMD 1 -#define ARCHIVE_CRYPTO_SHA512_LIBMD 1 -#endif diff --git a/3rdparty/libarchive/libarchive/filter_fork.h b/3rdparty/libarchive/libarchive/filter_fork.h deleted file mode 100644 index a28272be..00000000 --- a/3rdparty/libarchive/libarchive/filter_fork.h +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2007 Joerg Sonnenberger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $ - */ - -#ifndef __LIBARCHIVE_BUILD -#error This header is only to be used internally to libarchive. -#endif - -#ifndef FILTER_FORK_H -#define FILTER_FORK_H - -pid_t -__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout); - -void -__archive_check_child(int in, int out); - -#endif diff --git a/3rdparty/libarchive/libarchive/filter_fork_posix.c b/3rdparty/libarchive/libarchive/filter_fork_posix.c deleted file mode 100644 index 02dbd4bb..00000000 --- a/3rdparty/libarchive/libarchive/filter_fork_posix.c +++ /dev/null @@ -1,238 +0,0 @@ -/*- - * Copyright (c) 2007 Joerg Sonnenberger - * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -/* This capability is only available on POSIX systems. */ -#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \ - (defined(HAVE_FORK) || defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP)) - -__FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $"); - -#if defined(HAVE_SYS_TYPES_H) -# include -#endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) -# if defined(HAVE_POLL_H) -# include -# elif defined(HAVE_SYS_POLL_H) -# include -# endif -#elif defined(HAVE_SELECT) -# if defined(HAVE_SYS_SELECT_H) -# include -# elif defined(HAVE_UNISTD_H) -# include -# endif -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -#ifdef HAVE_SPAWN_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "archive.h" -#include "archive_cmdline_private.h" - -#include "filter_fork.h" - -pid_t -__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) -{ - pid_t child; - int stdin_pipe[2], stdout_pipe[2], tmp; -#if HAVE_POSIX_SPAWNP - posix_spawn_file_actions_t actions; - int r; -#endif - struct archive_cmdline *cmdline; - - cmdline = __archive_cmdline_allocate(); - if (cmdline == NULL) - goto state_allocated; - if (__archive_cmdline_parse(cmdline, cmd) != ARCHIVE_OK) - goto state_allocated; - - if (pipe(stdin_pipe) == -1) - goto state_allocated; - if (stdin_pipe[0] == 1 /* stdout */) { - if ((tmp = dup(stdin_pipe[0])) == -1) - goto stdin_opened; - close(stdin_pipe[0]); - stdin_pipe[0] = tmp; - } - if (pipe(stdout_pipe) == -1) - goto stdin_opened; - if (stdout_pipe[1] == 0 /* stdin */) { - if ((tmp = dup(stdout_pipe[1])) == -1) - goto stdout_opened; - close(stdout_pipe[1]); - stdout_pipe[1] = tmp; - } - -#if HAVE_POSIX_SPAWNP - - r = posix_spawn_file_actions_init(&actions); - if (r != 0) { - errno = r; - goto stdout_opened; - } - r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]); - if (r != 0) - goto actions_inited; - r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]); - if (r != 0) - goto actions_inited; - /* Setup for stdin. */ - r = posix_spawn_file_actions_adddup2(&actions, stdin_pipe[0], 0); - if (r != 0) - goto actions_inited; - if (stdin_pipe[0] != 0 /* stdin */) { - r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[0]); - if (r != 0) - goto actions_inited; - } - /* Setup for stdout. */ - r = posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], 1); - if (r != 0) - goto actions_inited; - if (stdout_pipe[1] != 1 /* stdout */) { - r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]); - if (r != 0) - goto actions_inited; - } - r = posix_spawnp(&child, cmdline->path, &actions, NULL, - cmdline->argv, NULL); - if (r != 0) - goto actions_inited; - posix_spawn_file_actions_destroy(&actions); - -#else /* HAVE_POSIX_SPAWNP */ - -#if HAVE_VFORK - child = vfork(); -#else - child = fork(); -#endif - if (child == -1) - goto stdout_opened; - if (child == 0) { - close(stdin_pipe[1]); - close(stdout_pipe[0]); - if (dup2(stdin_pipe[0], 0 /* stdin */) == -1) - _exit(254); - if (stdin_pipe[0] != 0 /* stdin */) - close(stdin_pipe[0]); - if (dup2(stdout_pipe[1], 1 /* stdout */) == -1) - _exit(254); - if (stdout_pipe[1] != 1 /* stdout */) - close(stdout_pipe[1]); - execvp(cmdline->path, cmdline->argv); - _exit(254); - } -#endif /* HAVE_POSIX_SPAWNP */ - - close(stdin_pipe[0]); - close(stdout_pipe[1]); - - *child_stdin = stdin_pipe[1]; - fcntl(*child_stdin, F_SETFL, O_NONBLOCK); - *child_stdout = stdout_pipe[0]; - fcntl(*child_stdout, F_SETFL, O_NONBLOCK); - __archive_cmdline_free(cmdline); - - return child; - -#if HAVE_POSIX_SPAWNP -actions_inited: - errno = r; - posix_spawn_file_actions_destroy(&actions); -#endif -stdout_opened: - close(stdout_pipe[0]); - close(stdout_pipe[1]); -stdin_opened: - close(stdin_pipe[0]); - close(stdin_pipe[1]); -state_allocated: - __archive_cmdline_free(cmdline); - return -1; -} - -void -__archive_check_child(int in, int out) -{ -#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) - struct pollfd fds[2]; - int idx; - - idx = 0; - if (in != -1) { - fds[idx].fd = in; - fds[idx].events = POLLOUT; - ++idx; - } - if (out != -1) { - fds[idx].fd = out; - fds[idx].events = POLLIN; - ++idx; - } - - poll(fds, idx, -1); /* -1 == INFTIM, wait forever */ -#elif defined(HAVE_SELECT) - fd_set fds_in, fds_out, fds_error; - - FD_ZERO(&fds_in); - FD_ZERO(&fds_out); - FD_ZERO(&fds_error); - if (out != -1) { - FD_SET(out, &fds_in); - FD_SET(out, &fds_error); - } - if (in != -1) { - FD_SET(in, &fds_out); - FD_SET(in, &fds_error); - } - select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL); -#else - sleep(1); -#endif -} - -#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */ diff --git a/3rdparty/libarchive/libarchive/filter_fork_windows.c b/3rdparty/libarchive/libarchive/filter_fork_windows.c deleted file mode 100644 index ad271fe6..00000000 --- a/3rdparty/libarchive/libarchive/filter_fork_windows.c +++ /dev/null @@ -1,190 +0,0 @@ -/*- - * Copyright (c) 2009-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include "archive_cmdline_private.h" -#include "archive_string.h" - -#include "filter_fork.h" - -pid_t -__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) -{ - HANDLE childStdout[2], childStdin[2],childStderr; - SECURITY_ATTRIBUTES secAtts; - STARTUPINFOA staInfo; - PROCESS_INFORMATION childInfo; - struct archive_string cmdline; - struct archive_string fullpath; - struct archive_cmdline *acmd; - char *arg0, *ext; - int i, l; - DWORD fl, fl_old; - - childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE; - childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE; - childStderr = INVALID_HANDLE_VALUE; - archive_string_init(&cmdline); - archive_string_init(&fullpath); - - acmd = __archive_cmdline_allocate(); - if (acmd == NULL) - goto fail; - if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK) - goto fail; - - /* - * Search the full path of 'path'. - * NOTE: This does not need if we give CreateProcessA 'path' as - * a part of the cmdline and give CreateProcessA NULL as first - * parameter, but I do not like that way. - */ - ext = strrchr(acmd->path, '.'); - if (ext == NULL || strlen(ext) > 4) - /* 'path' does not have a proper extension, so we have to - * give SearchPath() ".exe" as the extension. */ - ext = ".exe"; - else - ext = NULL;/* 'path' has an extension. */ - - fl = MAX_PATH; - do { - if (archive_string_ensure(&fullpath, fl) == NULL) - goto fail; - fl_old = fl; - fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s, - &arg0); - } while (fl != 0 && fl > fl_old); - if (fl == 0) - goto fail; - - /* - * Make a command line. - */ - for (l = 0, i = 0; acmd->argv[i] != NULL; i++) { - if (i == 0) - continue; - l += (int)strlen(acmd->argv[i]) + 1; - } - if (archive_string_ensure(&cmdline, l + 1) == NULL) - goto fail; - for (i = 0; acmd->argv[i] != NULL; i++) { - if (i == 0) { - const char *p, *sp; - - if ((p = strchr(acmd->argv[i], '/')) != NULL || - (p = strchr(acmd->argv[i], '\\')) != NULL) - p++; - else - p = acmd->argv[i]; - if ((sp = strchr(p, ' ')) != NULL) - archive_strappend_char(&cmdline, '"'); - archive_strcat(&cmdline, p); - if (sp != NULL) - archive_strappend_char(&cmdline, '"'); - } else { - archive_strappend_char(&cmdline, ' '); - archive_strcat(&cmdline, acmd->argv[i]); - } - } - if (i <= 1) { - const char *sp; - - if ((sp = strchr(arg0, ' ')) != NULL) - archive_strappend_char(&cmdline, '"'); - archive_strcat(&cmdline, arg0); - if (sp != NULL) - archive_strappend_char(&cmdline, '"'); - } - - secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); - secAtts.bInheritHandle = TRUE; - secAtts.lpSecurityDescriptor = NULL; - if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0) - goto fail; - if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0)) - goto fail; - if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) - goto fail; - if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0)) - goto fail; - if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), - GetCurrentProcess(), &childStderr, 0, TRUE, - DUPLICATE_SAME_ACCESS) == 0) - goto fail; - - memset(&staInfo, 0, sizeof(staInfo)); - staInfo.cb = sizeof(staInfo); - staInfo.hStdError = childStderr; - staInfo.hStdOutput = childStdout[1]; - staInfo.hStdInput = childStdin[0]; - staInfo.wShowWindow = SW_HIDE; - staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0, - NULL, NULL, &staInfo, &childInfo) == 0) - goto fail; - WaitForInputIdle(childInfo.hProcess, INFINITE); - CloseHandle(childInfo.hProcess); - CloseHandle(childInfo.hThread); - - *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY); - *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY); - - CloseHandle(childStdout[1]); - CloseHandle(childStdin[0]); - - archive_string_free(&cmdline); - archive_string_free(&fullpath); - __archive_cmdline_free(acmd); - return (childInfo.dwProcessId); - -fail: - if (childStdout[0] != INVALID_HANDLE_VALUE) - CloseHandle(childStdout[0]); - if (childStdout[1] != INVALID_HANDLE_VALUE) - CloseHandle(childStdout[1]); - if (childStdin[0] != INVALID_HANDLE_VALUE) - CloseHandle(childStdin[0]); - if (childStdin[1] != INVALID_HANDLE_VALUE) - CloseHandle(childStdin[1]); - if (childStderr != INVALID_HANDLE_VALUE) - CloseHandle(childStderr); - archive_string_free(&cmdline); - archive_string_free(&fullpath); - __archive_cmdline_free(acmd); - return (-1); -} - -void -__archive_check_child(int in, int out) -{ - (void)in; /* UNUSED */ - (void)out; /* UNUSED */ - Sleep(100); -} - -#endif /* _WIN32 && !__CYGWIN__ */ diff --git a/3rdparty/libarchive/qt_attribution.json b/3rdparty/libarchive/qt_attribution.json deleted file mode 100644 index 3abf2fcb..00000000 --- a/3rdparty/libarchive/qt_attribution.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Id": "libarchive", - "Name": "libarchive", - "QDocModule": "applicationmanager", - "QtUsage": "Optionally used in Qt ApplicationManager. Configure with -config force-system-libarchive to avoid.", - - "Description": "Multi-format archive and compression library.", - "Homepage": "http://www.libarchive.org/", - "Version": "3.3.2", - - "License": "BSD 2-clause \"Simplified\" License", - "LicenseId": "BSD-2-Clause", - "LicenseFile": "COPYING", - "Copyright": "(c) 2003-2017 Tim Kientzle et al. - see COPYING and the individual file headers" -} diff --git a/3rdparty/libbacktrace.pri b/3rdparty/libbacktrace.pri deleted file mode 100644 index ec9d1da8..00000000 --- a/3rdparty/libbacktrace.pri +++ /dev/null @@ -1,2 +0,0 @@ - -QMAKE_USE_PRIVATE += backtrace diff --git a/3rdparty/libbacktrace/LICENSE b/3rdparty/libbacktrace/LICENSE deleted file mode 100644 index 74b5ddb5..00000000 --- a/3rdparty/libbacktrace/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (C) 2012-2016 Free Software Foundation, Inc. -Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. diff --git a/3rdparty/libbacktrace/README.md b/3rdparty/libbacktrace/README.md deleted file mode 100644 index 14a2da2d..00000000 --- a/3rdparty/libbacktrace/README.md +++ /dev/null @@ -1,25 +0,0 @@ -This is a standalone version of libbacktrace. - -libbacktrace prints stack traces. - -libbacktrace was originally writen by Ian Lance Taylor as part of GCC. - -Building libbacktrace requires CMake. - -How to build with ninja: - - mkdir build - cd build/ - cmake -GNinja -DENABLE_LIBBACKTRACE_TEST=true path/to/libbacktrace/source - ninja - -How to build with make: - - mkdir build - cd build/ - cmake -G'Unix Makefiles' -DENABLE_LIBBACKTRACE_TEST=true path/to/libbacktrace/source - make - -How to run the tests: - - ctest diff --git a/3rdparty/libbacktrace/auxincl/dwarf2.h b/3rdparty/libbacktrace/auxincl/dwarf2.h deleted file mode 100644 index 205df8d2..00000000 --- a/3rdparty/libbacktrace/auxincl/dwarf2.h +++ /dev/null @@ -1,109 +0,0 @@ -/* dwarf2.h -- minimal GCC dwarf2.h replacement for libbacktrace - Contributed by Alexander Monakov, ISP RAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_AUX_DWARF2_H -#define BACKTRACE_AUX_DWARF2_H - -/* Provide stub enum tags. */ -enum dwarf_attribute {_dummy_dwarf_attribute}; -enum dwarf_form {_dummy_dwarf_form}; -enum dwarf_tag {_dummy_dwarf_tag}; - -#define DW_AT_abstract_origin 0x31 -#define DW_AT_call_file 0x58 -#define DW_AT_call_line 0x59 -#define DW_AT_comp_dir 0x1b -#define DW_AT_high_pc 0x12 -#define DW_AT_linkage_name 0x6e -#define DW_AT_low_pc 0x11 -#define DW_AT_MIPS_linkage_name 0x2007 -#define DW_AT_name 0x03 -#define DW_AT_namelist_item 0x44 -#define DW_AT_ranges 0x55 -#define DW_AT_ranges_base 0x74 -#define DW_AT_specification 0x47 -#define DW_AT_stmt_list 0x10 -#define DW_FORM_addr 0x01 -#define DW_FORM_addrx 0x1b -#define DW_FORM_block 0x09 -#define DW_FORM_block1 0x0a -#define DW_FORM_block2 0x03 -#define DW_FORM_block4 0x04 -#define DW_FORM_data1 0x0b -#define DW_FORM_data16 0x1e -#define DW_FORM_data2 0x05 -#define DW_FORM_data4 0x06 -#define DW_FORM_data8 0x07 -#define DW_FORM_exprloc 0x18 -#define DW_FORM_flag 0x0c -#define DW_FORM_flag_present 0x19 -#define DW_FORM_GNU_addr_index 0x1f01 -#define DW_FORM_GNU_ref_alt 0x1f20 -#define DW_FORM_GNU_str_index 0x1f02 -#define DW_FORM_GNU_strp_alt 0x1f21 -#define DW_FORM_indirect 0x16 -#define DW_FORM_ref1 0x11 -#define DW_FORM_ref2 0x12 -#define DW_FORM_ref4 0x13 -#define DW_FORM_ref8 0x14 -#define DW_FORM_ref_addr 0x10 -#define DW_FORM_ref_sig8 0x20 -#define DW_FORM_ref_udata 0x15 -#define DW_FORM_sdata 0x0d -#define DW_FORM_sec_offset 0x17 -#define DW_FORM_string 0x08 -#define DW_FORM_strp 0x0e -#define DW_FORM_strp_sup 0x1d -#define DW_FORM_udata 0x0f -#define DW_LNE_define_file 0x03 -#define DW_LNE_define_file_MD5 0x05 -#define DW_LNE_end_sequence 0x01 -#define DW_LNE_set_address 0x02 -#define DW_LNE_set_discriminator 0x04 -#define DW_LNS_advance_line 0x03 -#define DW_LNS_advance_pc 0x02 -#define DW_LNS_const_add_pc 0x08 -#define DW_LNS_copy 0x01 -#define DW_LNS_extended_op 0x00 -#define DW_LNS_fixed_advance_pc 0x09 -#define DW_LNS_negate_stmt 0x06 -#define DW_LNS_set_basic_block 0x07 -#define DW_LNS_set_column 0x05 -#define DW_LNS_set_epilogue_begin 0x0b -#define DW_LNS_set_file 0x04 -#define DW_LNS_set_isa 0x0c -#define DW_LNS_set_prologue_end 0x0a -#define DW_TAG_compile_unit 0x11 -#define DW_TAG_entry_point 0x03 -#define DW_TAG_inlined_subroutine 0x1d -#define DW_TAG_subprogram 0x2e - -#endif diff --git a/3rdparty/libbacktrace/auxincl/filenames.h b/3rdparty/libbacktrace/auxincl/filenames.h deleted file mode 100644 index 90f95cd8..00000000 --- a/3rdparty/libbacktrace/auxincl/filenames.h +++ /dev/null @@ -1,41 +0,0 @@ -/* filenames.h -- minimal GCC filenames.h replacement for libbacktrace - Contributed by Alexander Monakov, ISP RAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_AUX_FILENAMES_H -#define BACKTRACE_AUX_FILENAMES_H - -/* Assume POSIX paths. */ - -#define IS_DIR_SEPARATOR(c) ((c) == '/') -#define IS_ABSOLUTE_PATH(f) ((f)[0] == '/') - -#endif - diff --git a/3rdparty/libbacktrace/libbacktrace.pro b/3rdparty/libbacktrace/libbacktrace.pro deleted file mode 100644 index ff3da892..00000000 --- a/3rdparty/libbacktrace/libbacktrace.pro +++ /dev/null @@ -1,47 +0,0 @@ -requires(linux|macos) - -TEMPLATE = lib -TARGET = qtbacktrace - -load(am-config) - -CONFIG += \ - static \ - hide_symbols \ - exceptions_off rtti_off warn_off \ - installed - -MODULE_INCLUDEPATH += $$PWD - -load(qt_helper_lib) - -win32-msvc* { - QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS -} -*-g++* { - QMAKE_CFLAGS += -Wno-unused -funwind-tables -Wno-switch -Wno-enum-compare -} -*-clang* { - CONFIG += warn_off - QMAKE_CFLAGS += -Wall -W -Wno-unused -} - -DEFINES *= _GNU_SOURCE - -INCLUDEPATH += $$PWD/auxincl $$PWD/libbacktrace - -linux: SOURCES += libbacktrace/elf.c -macos: SOURCES += libbacktrace/macho.c - -SOURCES += \ - libbacktrace/backtrace.c \ - libbacktrace/simple.c \ - libbacktrace/dwarf.c \ - libbacktrace/mmapio.c \ - libbacktrace/mmap.c \ - libbacktrace/atomic.c \ - libbacktrace/fileline.c \ - libbacktrace/posix.c \ - libbacktrace/print.c \ - libbacktrace/sort.c \ - libbacktrace/state.c \ diff --git a/3rdparty/libbacktrace/libbacktrace/ChangeLog b/3rdparty/libbacktrace/libbacktrace/ChangeLog deleted file mode 100644 index acc07047..00000000 --- a/3rdparty/libbacktrace/libbacktrace/ChangeLog +++ /dev/null @@ -1,590 +0,0 @@ -2016-05-18 Uros Bizjak - - PR target/71161 - * elf.c (phdr_callback) [__i386__]: Add - __attribute__((__force_align_arg_pointer__)). - -2016-03-02 Maxim Ostapenko - - * elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to - avoid possible crash. - (elf_add): Don't set *fileline_fn to elf_nodebug value in case of - missing debug info anymore. - -2016-02-06 John David Anglin - - * mmap.c (MAP_FAILED): Define if not defined. - -2016-01-04 Jakub Jelinek - - Update copyright years. - -2015-12-18 Andris Pavenis - - * configure.ac: Specify that DJGPP do not have mmap - even when sys/mman.h exists. - * configure: Regenerate - -2015-12-09 John David Anglin - - PR libgfortran/68115 - * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. - * configure: Regenerate. - * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call - to void. - -2015-09-17 Ian Lance Taylor - - * posix.c (backtrace_open): Cast second argument of open() to int. - -2015-09-11 Ian Lance Taylor - - * Makefile.am (backtrace.lo): Depend on internal.h. - (sort.lo, stest.lo): Add explicit dependencies. - * Makefile.in: Rebuild. - -2015-09-09 Hans-Peter Nilsson - - * backtrace.c: #include . - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * backtrace.c: #include "internal.h". - (struct backtrace_data): Add can_alloc field. - (unwind): If can_alloc is false, don't try to get file/line - information. - (backtrace_full): Set can_alloc field in bdata. - * alloc.c (backtrace_alloc): Don't call error_callback if it is - NULL. - * mmap.c (backtrace_alloc): Likewise. - * internal.h: Update comments for backtrace_alloc and - backtrace_free. - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * mmap.c (backtrace_alloc): Correct test for mmap failure. - -2015-08-31 Ulrich Weigand - - * configure.ac: For spu-*-* targets, set have_fcntl to no. - * configure: Regenerate. - -2015-08-27 Ulrich Weigand - - * configure.ac: Remove [disable-shared] argument to LT_INIT. - Remove setting PIC_FLAG when building as target library. - * configure: Regenerate. - -2015-08-26 Hans-Peter Nilsson - - * configure.ac: Only compile with -fPIC if the target - supports it. - * configure: Regenerate. - -2015-08-24 Ulrich Weigand - - * configure.ac: Set have_mmap to no on spu-*-* targets. - * configure: Regenerate. - -2015-08-13 Ian Lance Taylor - - * dwarf.c (read_function_entry): Add vec_inlined parameter. - Change all callers. - -2015-06-11 Martin Sebor - - PR sanitizer/65479 - * dwarf.c (struct line): Add new field idx. - (line_compare): Use it. - (add_line): Set it. - (read_line_info): Reset it. - -2015-05-29 Tristan Gingold - - * pecoff.c: New file. - * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. - * Makefile.in: Regenerate. - * filetype.awk: Detect pecoff. - * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. - Add pecoff. - * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is - true. - * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. - * configure: Regenerate. - * pecoff.c: New file. - -2015-05-13 Michael Haubenwallner - - * Makefile.in: Regenerated with automake-1.11.6. - * aclocal.m4: Likewise. - * configure: Likewise. - -2015-01-24 Matthias Klose - - * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. - * configure: Regenerate. - -2015-01-05 Jakub Jelinek - - Update copyright years. - -2014-11-21 H.J. Lu - - PR bootstrap/63784 - * configure: Regenerated. - -2014-11-11 David Malcolm - - * ChangeLog.jit: New. - -2014-11-11 Francois-Xavier Coudert - - PR target/63610 - * configure: Regenerate. - -2014-10-23 Ian Lance Taylor - - * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: - Fix to return void *. - -2014-05-08 Ian Lance Taylor - - * mmap.c (backtrace_free): If freeing a large aligned block of - memory, call munmap rather than holding onto it. - (backtrace_vector_grow): When growing a vector, double the number - of pages requested. When releasing the old version of a grown - vector, pass the correct size to backtrace_free. - -2014-03-07 Ian Lance Taylor - - * sort.c (backtrace_qsort): Use middle element as pivot. - -2014-03-06 Ian Lance Taylor - - * sort.c: New file. - * stest.c: New file. - * internal.h (backtrace_qsort): Declare. - * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. - (read_line_info, read_function_entry): Likewise. - (read_function_info, build_dwarf_data): Likewise. - * elf.c (elf_initialize_syminfo): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. - (stest_SOURCES, stest_LDADD): Define. - (check_PROGRAMS): Add stest. - -2014-02-07 Misty De Meo - - PR target/58710 - * configure.ac: Use AC_LINK_IFELSE in check for - _Unwind_GetIPInfo. - * configure: Regenerate. - -2014-01-02 Richard Sandiford - - Update copyright years - -2013-12-06 Jakub Jelinek - - * elf.c (ET_DYN): Undefine and define again. - (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, - return early -1 without closing the descriptor. - (struct phdr_data): Add exe_descriptor. - (phdr_callback): If pd->exe_descriptor is not -1, for very first - call if dlpi_name is NULL just call elf_add with the exe_descriptor, - otherwise backtrace_close the exe_descriptor if not -1. Adjust - call to elf_add. - (backtrace_initialize): Adjust call to elf_add. If it returns - -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. - -2013-12-05 Ian Lance Taylor - - * alloc.c (backtrace_vector_finish): Add error_callback and data - parameters. Call backtrace_vector_release. Return address base. - * mmap.c (backtrace_vector_finish): Add error_callback and data - parameters. Return address base. - * dwarf.c (read_function_info): Get new address base from - backtrace_vector_finish. - * internal.h (backtrace_vector_finish): Update declaration. - -2013-11-27 Ian Lance Taylor - - * dwarf.c (find_address_ranges): New static function, broken out - of build_address_map. - (build_address_map): Call it. - * btest.c (check): Check for missing filename or function, rather - than crashing. - (f3): Check that enough frames were returned. - -2013-11-19 Jakub Jelinek - - * backtrace.h (backtrace_syminfo_callback): Add symsize argument. - * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as - last argument. - * btest.c (struct symdata): Add size field. - (callback_three): Add symsize argument. Copy it to the data->size - field. - (f23): Set symdata.size to 0. - (test5): Likewise. If sizeof (int) > 1, lookup address of - ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size - values. - - * atomic.c: Include sys/types.h. - -2013-11-18 Ian Lance Taylor - - * configure.ac: Check for support of __atomic extensions. - * internal.h: Declare or #define atomic functions for use in - backtrace code. - * atomic.c: New file. - * dwarf.c (dwarf_lookup_pc): Use atomic functions. - (dwarf_fileline, backtrace_dwarf_add): Likewise. - * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. - (backtrace_initialize): Likewise. - * fileline.c (fileline_initialize): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. - * configure, config.h.in, Makefile.in: Rebuild. - -2013-11-18 Jakub Jelinek - - * elf.c (SHN_UNDEF): Define. - (elf_initialize_syminfo): Add base_address argument. Ignore symbols - with st_shndx == SHN_UNDEF. Add base_address to address fields. - (elf_add): Adjust caller. - - * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. - -2013-11-16 Ian Lance Taylor - - * backtrace.h (backtrace_create_state): Correct comment about - threading. - -2013-11-15 Ian Lance Taylor - - * backtrace.h (backtrace_syminfo): Update comment and parameter - name to take any address, not just a PC value. - * elf.c (STT_OBJECT): Define. - (elf_nosyms): Rename parameter pc to addr. - (elf_symbol_search): Rename local variable pc to addr. - (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. - (elf_syminfo): Rename parameter pc to addr. - * btest.c (global): New global variable. - (test5): New test. - (main): Call test5. - -2013-10-17 Ian Lance Taylor - - * elf.c (elf_add): Don't get the wrong offsets if a debug section - is missing. - -2013-10-15 David Malcolm - - * configure.ac: Add --enable-host-shared, setting up - pre-existing PIC_FLAG variable within Makefile.am et al. - * configure: Regenerate. - -2013-09-20 Alan Modra - - * configure: Regenerate. - -2013-07-23 Alexander Monakov - - * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. - -2013-07-23 Alexander Monakov - - * elf.c (backtrace_initialize): Pass elf_fileline_fn to - dl_iterate_phdr callbacks. - -2013-03-25 Ian Lance Taylor - - * alloc.c: #include . - * mmap.c: Likewise. - -2013-01-31 Ian Lance Taylor - - * dwarf.c (read_function_info): Permit fvec parameter to be NULL. - (dwarf_lookup_pc): Don't use ddata->fvec if threaded. - -2013-01-25 Jakub Jelinek - - PR other/56076 - * dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir - attribute was not seen. - -2013-01-16 Ian Lance Taylor - - * dwarf.c (struct unit): Add filename and abs_filename fields. - (build_address_map): Set new fields when reading unit. - (dwarf_lookup_pc): If we don't find an entry in the line table, - just return the main file name. - -2013-01-14 Richard Sandiford - - Update copyright years. - -2013-01-01 Ian Lance Taylor - - PR bootstrap/54834 - * Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I - $(MULTIBUILDTOP)/../../gcc/include. - * Makefile.in: Rebuild. - -2013-01-01 Ian Lance Taylor - - PR other/55536 - * mmap.c (backtrace_alloc): Don't call sync functions if not - threaded. - (backtrace_free): Likewise. - -2012-12-12 John David Anglin - - * mmapio.c: Define MAP_FAILED if not defined. - -2012-12-11 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@. - * configure.ac: If --with-target-subdir, add -frandom-seed=$@ - to EXTRA_FLAGS unconditionally, otherwise check whether the compiler - accepts it. - * Makefile.in: Regenerated. - * configure: Regenerated. - -2012-12-07 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Add -frandom-seed=$@. - * Makefile.in: Regenerated. - -2012-11-20 Ian Lance Taylor - - * dwarf.c (read_attribute): Always clear val. - -2012-11-13 Ian Lance Taylor - - PR other/55312 - * configure.ac: Only add -Werror if building a target library. - * configure: Rebuild. - -2012-11-12 Ian Lance Taylor - Rainer Orth - Gerald Pfeifer - - * configure.ac: Check for getexecname. - * fileline.c: #include . Define getexecname if not - available. - (fileline_initialize): Try to find the executable in a few - different ways. - * print.c (error_callback): Only print the filename if it came - from the backtrace state. - * configure, config.h.in: Rebuild. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Correct last patch: add - aligned, not size. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Make sure freed block is - aligned on 8-byte boundary. - -2012-10-26 Ian Lance Taylor - - PR other/55087 - * posix.c (backtrace_open): Add does_not_exist parameter. - * elf.c (phdr_callback): Do not warn if shared library could not - be opened. - * fileline.c (fileline_initialize): Update calls to - backtrace_open. - * internal.h (backtrace_open): Update declaration. - -2012-10-26 Jack Howarth - - PR target/55061 - * configure.ac: Check for _Unwind_GetIPInfo function declaration. - * configure: Regenerate. - -2012-10-24 Ian Lance Taylor - - PR target/55061 - * configure.ac: Check whether -funwind-tables option works. - * configure: Rebuild. - -2012-10-11 Ian Lance Taylor - - * configure.ac: Do not use dl_iterate_phdr on Solaris 10. - * configure: Rebuild. - -2012-10-10 Ian Lance Taylor - - * elf.c: Rename all Elf typedefs to start with b_elf, and be all - lower case. - -2012-10-10 Hans-Peter Nilsson - - * elf.c (elf_add_syminfo_data): Add casts to avoid warning. - -2012-10-09 Ian Lance Taylor - - * dwarf.c (dwarf_fileline): Add cast to avoid warning. - (backtrace_dwarf_add): Likewise. - -2012-10-09 Ian Lance Taylor - - Add support for tracing through shared libraries. - * configure.ac: Check for link.h and dl_iterate_phdr. - * elf.c: #include if system has dl_iterate_phdr. #undef - ELF macros before #defining them. - (dl_phdr_info, dl_iterate_phdr): Define if system does not have - dl_iterate_phdr. - (struct elf_syminfo_data): Add next field. - (elf_initialize_syminfo): Initialize next field. - (elf_add_syminfo_data): New static function. - (elf_add): New static function, broken out of - backtrace_initialize. Call backtrace_dwarf_add instead of - backtrace_dwarf_initialize. - (struct phdr_data): Define. - (phdr_callback): New static function. - (backtrace_initialize): Call elf_add. - * dwarf.c (struct dwarf_data): Add next and base_address fields. - (add_unit_addr): Add base_address parameter. Change all callers. - (add_unit_ranges, build_address_map): Likewise. - (add_line): Add ddata parameter. Change all callers. - (read_line_program, add_function_range): Likewise. - (dwarf_lookup_pc): New static function, broken out of - dwarf_fileline. - (dwarf_fileline): Call dwarf_lookup_pc. - (build_dwarf_data): New static function. - (backtrace_dwarf_add): New function. - (backtrace_dwarf_initialize): Remove. - * internal.h (backtrace_dwarf_initialize): Don't declare. - (backtrace_dwarf_add): Declare. - * configure, config.h.in: Rebuild. - -2012-10-04 Gerald Pfeifer - - * btest.c (f23): Avoid uninitialized variable warning. - -2012-10-04 Ian Lance Taylor - - * dwarf.c: If the system header files do not declare strnlen, - provide our own version. - -2012-10-03 Ian Lance Taylor - - * dwarf.c (read_uleb128): Fix overflow test. - (read_sleb128): Likewise. - (build_address_map): Don't change unit_buf.start. - -2012-10-02 Uros Bizjak - - PR other/54761 - * configure.ac (EXTRA_FLAGS): New. - * Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS). - * configure, Makefile.in: Regenerate. - -2012-09-29 Ian Lance Taylor - - PR other/54749 - * fileline.c (fileline_initialize): Pass errnum as -1 when - reporting that we could not read executable information after a - previous failure. - -2012-09-27 Ian Lance Taylor - - PR bootstrap/54732 - * configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE. - * Makefile.am: Add dependencies for all objects. - * configure, aclocal.m4, Makefile.in: Rebuild. - -2012-09-27 Ian Lance Taylor - - PR other/54726 - * elf.c (backtrace_initialize): Set *fileln_fn, not - state->fileln_fn. - -2012-09-19 Ian Lance Taylor - - * configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled - as a target library. - * configure: Rebuild. - -2012-09-19 Rainer Orth - Ian Lance Taylor - - * configure.ac (GCC_HEADER_STDINT): Invoke. - * backtrace.h: If we can't find , use "gstdint.h". - * btest.c: Don't include . - * dwarf.c: Likewise. - * configure, aclocal.m4, Makefile.in, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - PR bootstrap/54623 - * Makefile.am (AM_CPPFLAGS): Define. - (AM_CFLAGS): Remove -I options. - * Makefile.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * posix.c (O_BINARY): Define if not defined. - (backtrace_open): Pass O_BINARY to open. Only call fcntl if - HAVE_FCNTL is defined. - * configure.ac: Test for the fcntl function. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * btest.c (test1, test2, test3, test4): Add the unused attribute. - -2012-09-18 Ian Lance Taylor - - * dwarf.c: Correct test of HAVE_DECL_STRNLEN. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Add AC_USE_SYSTEM_EXTENSIONS. - * mmapio.c: Don't define _GNU_SOURCE. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Check whether strnlen is declared. - * dwarf.c: Declare strnlen if not declared. - * configure, config.h.in: Rebuild. - -2012-09-18 Rainer Orth - - * fileline.c: Include . - * mmap.c: Likewise. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54611 - * nounwind.c (backtrace_full): Rename from backtrace. Add state - parameter. - -2012-09-17 Gerald Pfeifer - - PR bootstrap/54611 - * nounwind.c (backtrace_simple): Add state parameter. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54609 - * unknown.c (unknown_fileline): Add state parameter, remove - fileline_data parameter, name error_callback parameter. - (backtrace_initialize): Add state parameter. - -2012-09-17 Ian Lance Taylor - - * Initial implementation. - -Copyright (C) 2012-2016 Free Software Foundation, Inc. - -Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. diff --git a/3rdparty/libbacktrace/libbacktrace/README b/3rdparty/libbacktrace/libbacktrace/README deleted file mode 100644 index e8b22574..00000000 --- a/3rdparty/libbacktrace/libbacktrace/README +++ /dev/null @@ -1,23 +0,0 @@ -The libbacktrace library -Initially written by Ian Lance Taylor - -The libbacktrace library may be linked into a program or library and -used to produce symbolic backtraces. Sample uses would be to print a -detailed backtrace when an error occurs or to gather detailed -profiling information. - -The libbacktrace library is provided under a BSD license. See the -source files for the exact license text. - -The public functions are declared and documented in the header file -backtrace.h, which should be #include'd by a user of the library. - -Building libbacktrace will generate a file backtrace-supported.h, -which a user of the library may use to determine whether backtraces -will work. See the source file backtrace-supported.h.in for the -macros that it defines. - -As of September 2012, libbacktrace only supports ELF executables with -DWARF debugging information. The library is written to make it -straightforward to add support for other object file and debugging -formats. diff --git a/3rdparty/libbacktrace/libbacktrace/atomic.c b/3rdparty/libbacktrace/libbacktrace/atomic.c deleted file mode 100644 index 502ad358..00000000 --- a/3rdparty/libbacktrace/libbacktrace/atomic.c +++ /dev/null @@ -1,113 +0,0 @@ -/* atomic.c -- Support for atomic functions if not present. - Copyright (C) 2013-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* This file holds implementations of the atomic functions that are - used if the host compiler has the sync functions but not the atomic - functions, as is true of versions of GCC before 4.7. */ - -#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) - -/* Do an atomic load of a pointer. */ - -void * -backtrace_atomic_load_pointer (void *arg) -{ - void **pp; - void *p; - - pp = (void **) arg; - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; - return p; -} - -/* Do an atomic load of an int. */ - -int -backtrace_atomic_load_int (int *p) -{ - int i; - - i = *p; - while (!__sync_bool_compare_and_swap (p, i, i)) - i = *p; - return i; -} - -/* Do an atomic store of a pointer. */ - -void -backtrace_atomic_store_pointer (void *arg, void *p) -{ - void **pp; - void *old; - - pp = (void **) arg; - old = *pp; - while (!__sync_bool_compare_and_swap (pp, old, p)) - old = *pp; -} - -/* Do an atomic store of a size_t value. */ - -void -backtrace_atomic_store_size_t (size_t *p, size_t v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -/* Do an atomic store of a int value. */ - -void -backtrace_atomic_store_int (int *p, int v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -#endif diff --git a/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h b/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h deleted file mode 100644 index d89221c7..00000000 --- a/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h +++ /dev/null @@ -1,3 +0,0 @@ -#define BACKTRACE_SUPPORTED 1 -#define BACKTRACE_USES_MALLOC 0 -#define BACKTRACE_SUPPORTS_THREADS 1 diff --git a/3rdparty/libbacktrace/libbacktrace/backtrace.c b/3rdparty/libbacktrace/libbacktrace/backtrace.c deleted file mode 100644 index c579e803..00000000 --- a/3rdparty/libbacktrace/libbacktrace/backtrace.c +++ /dev/null @@ -1,129 +0,0 @@ -/* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include - -#include "unwind.h" -#include "backtrace.h" -#include "internal.h" - -/* The main backtrace_full routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_full_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routines. */ - void *data; - /* Value to return from backtrace_full. */ - int ret; - /* Whether there is any memory available. */ - int can_alloc; -}; - -/* Unwind library callback routine. This is passed to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_data *bdata = (struct backtrace_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - if (!bdata->can_alloc) - bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); - else - bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, - bdata->error_callback, bdata->data); - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a stack backtrace. */ - -int __attribute__((noinline)) -backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_data bdata; - void *p; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - - /* If we can't allocate any memory at all, don't try to produce - file/line information. */ - p = backtrace_alloc (state, 4096, NULL, NULL); - if (p == NULL) - bdata.can_alloc = 0; - else - { - backtrace_free (state, p, 4096, NULL, NULL); - bdata.can_alloc = 1; - } - - _Unwind_Backtrace (unwind, &bdata); - return bdata.ret; -} diff --git a/3rdparty/libbacktrace/libbacktrace/backtrace.h b/3rdparty/libbacktrace/libbacktrace/backtrace.h deleted file mode 100644 index 0631f265..00000000 --- a/3rdparty/libbacktrace/libbacktrace/backtrace.h +++ /dev/null @@ -1,188 +0,0 @@ -/* backtrace.h -- Public header file for stack backtrace library. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_H -#define BACKTRACE_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* The backtrace state. This struct is intentionally not defined in - the public interface. */ - -struct backtrace_state; - -/* The type of the error callback argument to backtrace functions. - This function, if not NULL, will be called for certain error cases. - The DATA argument is passed to the function that calls this one. - The MSG argument is an error message. The ERRNUM argument, if - greater than 0, holds an errno value. The MSG buffer may become - invalid after this function returns. - - As a special case, the ERRNUM argument will be passed as -1 if no - debug info can be found for the executable, but the function - requires debug info (e.g., backtrace_full, backtrace_pcinfo). The - MSG in this case will be something along the lines of "no debug - info". Similarly, ERRNUM will be passed as -1 if there is no - symbol table, but the function requires a symbol table (e.g., - backtrace_syminfo). This may be used as a signal that some other - approach should be tried. */ - -typedef void (*backtrace_error_callback) (void *data, const char *msg, - int errnum); - -/* Create state information for the backtrace routines. This must be - called before any of the other routines, and its return value must - be passed to all of the other routines. FILENAME is the path name - of the executable file; if it is NULL the library will try - system-specific path names. If not NULL, FILENAME must point to a - permanent buffer. If THREADED is non-zero the state may be - accessed by multiple threads simultaneously, and the library will - use appropriate atomic operations. If THREADED is zero the state - may only be accessed by one thread at a time. This returns a state - pointer on success, NULL on error. If an error occurs, this will - call the ERROR_CALLBACK routine. - - Calling this function allocates resources that cannot be freed. - There is no backtrace_free_state function. The state is used to - cache information that is expensive to recompute. Programs are - expected to call this function at most once and to save the return - value for all later calls to backtrace functions. */ - -extern struct backtrace_state *backtrace_create_state ( - const char *filename, int threaded, - backtrace_error_callback error_callback, void *data); - -/* The type of the callback argument to the backtrace_full function. - DATA is the argument passed to backtrace_full. PC is the program - counter. FILENAME is the name of the file containing PC, or NULL - if not available. LINENO is the line number in FILENAME containing - PC, or 0 if not available. FUNCTION is the name of the function - containing PC, or NULL if not available. This should return 0 to - continuing tracing. The FILENAME and FUNCTION buffers may become - invalid after this function returns. */ - -typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, - const char *filename, int lineno, - const char *function); - -/* Get a full stack backtrace. SKIP is the number of frames to skip; - passing 0 will start the trace with the function calling - backtrace_full. DATA is passed to the callback routine. If any - call to CALLBACK returns a non-zero value, the stack backtrace - stops, and backtrace returns that value; this may be used to limit - the number of stack frames desired. If all calls to CALLBACK - return 0, backtrace returns 0. The backtrace_full function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function requires debug info for the executable. */ - -extern int backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to the backtrace_simple function. - DATA is the argument passed to simple_backtrace. PC is the program - counter. This should return 0 to continue tracing. */ - -typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc); - -/* Get a simple backtrace. SKIP is the number of frames to skip, as - in backtrace. DATA is passed to the callback routine. If any call - to CALLBACK returns a non-zero value, the stack backtrace stops, - and backtrace_simple returns that value. Otherwise - backtrace_simple returns 0. The backtrace_simple function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function does not require any debug info for the executable. */ - -extern int backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* Print the current backtrace in a user readable format to a FILE. - SKIP is the number of frames to skip, as in backtrace_full. Any - error messages are printed to stderr. This function requires debug - info for the executable. */ - -extern void backtrace_print (struct backtrace_state *state, int skip, FILE *); - -/* Given PC, a program counter in the current program, call the - callback function with filename, line number, and function name - information. This will normally call the callback function exactly - once. However, if the PC happens to describe an inlined call, and - the debugging information contains the necessary information, then - this may call the callback function multiple times. This will make - at least one call to either CALLBACK or ERROR_CALLBACK. This - returns the first non-zero value returned by CALLBACK, or 0. */ - -extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to backtrace_syminfo. DATA and - PC are the arguments passed to backtrace_syminfo. SYMNAME is the - name of the symbol for the corresponding code. SYMVAL is the - value and SYMSIZE is the size of the symbol. SYMNAME will be NULL - if no error occurred but the symbol could not be found. */ - -typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, - const char *symname, - uintptr_t symval, - uintptr_t symsize); - -/* Given ADDR, an address or program counter in the current program, - call the callback information with the symbol name and value - describing the function or variable in which ADDR may be found. - This will call either CALLBACK or ERROR_CALLBACK exactly once. - This returns 1 on success, 0 on failure. This function requires - the symbol table but does not require the debug info. Note that if - the symbol table is present but ADDR could not be found in the - table, CALLBACK will be called with a NULL SYMNAME argument. - Returns 1 on success, 0 on error. */ - -extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, - void *data); - -#ifdef __cplusplus -} /* End extern "C". */ -#endif - -#endif diff --git a/3rdparty/libbacktrace/libbacktrace/config.h b/3rdparty/libbacktrace/libbacktrace/config.h deleted file mode 100644 index c7a9e18c..00000000 --- a/3rdparty/libbacktrace/libbacktrace/config.h +++ /dev/null @@ -1,9 +0,0 @@ -#define BACKTRACE_ELF_SIZE __WORDSIZE -#define HAVE_DECL_STRNLEN 1 -#define HAVE_DL_ITERATE_PHDR 1 -#define HAVE_FCNTL 1 -// #define HAVE_GETEXECNAME 1 -#define HAVE_GETIPINFO 1 -#define HAVE_SYNC_FUNCTIONS 1 -#define HAVE_LIBDWARF_DWARF_H 1 - diff --git a/3rdparty/libbacktrace/libbacktrace/dwarf.c b/3rdparty/libbacktrace/libbacktrace/dwarf.c deleted file mode 100644 index af79dfe5..00000000 --- a/3rdparty/libbacktrace/libbacktrace/dwarf.c +++ /dev/null @@ -1,4280 +0,0 @@ -/* dwarf.c -- Get file/line information from DWARF for backtraces. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include - -#include "filenames.h" - -#include "backtrace.h" -#include "internal.h" - -/* DWARF constants. */ - -enum dwarf_tag { - DW_TAG_entry_point = 0x3, - DW_TAG_compile_unit = 0x11, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_subprogram = 0x2e, -}; - -enum dwarf_form { - DW_FORM_addr = 0x01, - DW_FORM_block2 = 0x03, - DW_FORM_block4 = 0x04, - DW_FORM_data2 = 0x05, - DW_FORM_data4 = 0x06, - DW_FORM_data8 = 0x07, - DW_FORM_string = 0x08, - DW_FORM_block = 0x09, - DW_FORM_block1 = 0x0a, - DW_FORM_data1 = 0x0b, - DW_FORM_flag = 0x0c, - DW_FORM_sdata = 0x0d, - DW_FORM_strp = 0x0e, - DW_FORM_udata = 0x0f, - DW_FORM_ref_addr = 0x10, - DW_FORM_ref1 = 0x11, - DW_FORM_ref2 = 0x12, - DW_FORM_ref4 = 0x13, - DW_FORM_ref8 = 0x14, - DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16, - DW_FORM_sec_offset = 0x17, - DW_FORM_exprloc = 0x18, - DW_FORM_flag_present = 0x19, - DW_FORM_ref_sig8 = 0x20, - DW_FORM_strx = 0x1a, - DW_FORM_addrx = 0x1b, - DW_FORM_ref_sup4 = 0x1c, - DW_FORM_strp_sup = 0x1d, - DW_FORM_data16 = 0x1e, - DW_FORM_line_strp = 0x1f, - DW_FORM_implicit_const = 0x21, - DW_FORM_loclistx = 0x22, - DW_FORM_rnglistx = 0x23, - DW_FORM_ref_sup8 = 0x24, - DW_FORM_strx1 = 0x25, - DW_FORM_strx2 = 0x26, - DW_FORM_strx3 = 0x27, - DW_FORM_strx4 = 0x28, - DW_FORM_addrx1 = 0x29, - DW_FORM_addrx2 = 0x2a, - DW_FORM_addrx3 = 0x2b, - DW_FORM_addrx4 = 0x2c, - DW_FORM_GNU_addr_index = 0x1f01, - DW_FORM_GNU_str_index = 0x1f02, - DW_FORM_GNU_ref_alt = 0x1f20, - DW_FORM_GNU_strp_alt = 0x1f21 -}; - -enum dwarf_attribute { - DW_AT_sibling = 0x01, - DW_AT_location = 0x02, - DW_AT_name = 0x03, - DW_AT_ordering = 0x09, - DW_AT_subscr_data = 0x0a, - DW_AT_byte_size = 0x0b, - DW_AT_bit_offset = 0x0c, - DW_AT_bit_size = 0x0d, - DW_AT_element_list = 0x0f, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12, - DW_AT_language = 0x13, - DW_AT_member = 0x14, - DW_AT_discr = 0x15, - DW_AT_discr_value = 0x16, - DW_AT_visibility = 0x17, - DW_AT_import = 0x18, - DW_AT_string_length = 0x19, - DW_AT_common_reference = 0x1a, - DW_AT_comp_dir = 0x1b, - DW_AT_const_value = 0x1c, - DW_AT_containing_type = 0x1d, - DW_AT_default_value = 0x1e, - DW_AT_inline = 0x20, - DW_AT_is_optional = 0x21, - DW_AT_lower_bound = 0x22, - DW_AT_producer = 0x25, - DW_AT_prototyped = 0x27, - DW_AT_return_addr = 0x2a, - DW_AT_start_scope = 0x2c, - DW_AT_bit_stride = 0x2e, - DW_AT_upper_bound = 0x2f, - DW_AT_abstract_origin = 0x31, - DW_AT_accessibility = 0x32, - DW_AT_address_class = 0x33, - DW_AT_artificial = 0x34, - DW_AT_base_types = 0x35, - DW_AT_calling_convention = 0x36, - DW_AT_count = 0x37, - DW_AT_data_member_location = 0x38, - DW_AT_decl_column = 0x39, - DW_AT_decl_file = 0x3a, - DW_AT_decl_line = 0x3b, - DW_AT_declaration = 0x3c, - DW_AT_discr_list = 0x3d, - DW_AT_encoding = 0x3e, - DW_AT_external = 0x3f, - DW_AT_frame_base = 0x40, - DW_AT_friend = 0x41, - DW_AT_identifier_case = 0x42, - DW_AT_macro_info = 0x43, - DW_AT_namelist_items = 0x44, - DW_AT_priority = 0x45, - DW_AT_segment = 0x46, - DW_AT_specification = 0x47, - DW_AT_static_link = 0x48, - DW_AT_type = 0x49, - DW_AT_use_location = 0x4a, - DW_AT_variable_parameter = 0x4b, - DW_AT_virtuality = 0x4c, - DW_AT_vtable_elem_location = 0x4d, - DW_AT_allocated = 0x4e, - DW_AT_associated = 0x4f, - DW_AT_data_location = 0x50, - DW_AT_byte_stride = 0x51, - DW_AT_entry_pc = 0x52, - DW_AT_use_UTF8 = 0x53, - DW_AT_extension = 0x54, - DW_AT_ranges = 0x55, - DW_AT_trampoline = 0x56, - DW_AT_call_column = 0x57, - DW_AT_call_file = 0x58, - DW_AT_call_line = 0x59, - DW_AT_description = 0x5a, - DW_AT_binary_scale = 0x5b, - DW_AT_decimal_scale = 0x5c, - DW_AT_small = 0x5d, - DW_AT_decimal_sign = 0x5e, - DW_AT_digit_count = 0x5f, - DW_AT_picture_string = 0x60, - DW_AT_mutable = 0x61, - DW_AT_threads_scaled = 0x62, - DW_AT_explicit = 0x63, - DW_AT_object_pointer = 0x64, - DW_AT_endianity = 0x65, - DW_AT_elemental = 0x66, - DW_AT_pure = 0x67, - DW_AT_recursive = 0x68, - DW_AT_signature = 0x69, - DW_AT_main_subprogram = 0x6a, - DW_AT_data_bit_offset = 0x6b, - DW_AT_const_expr = 0x6c, - DW_AT_enum_class = 0x6d, - DW_AT_linkage_name = 0x6e, - DW_AT_string_length_bit_size = 0x6f, - DW_AT_string_length_byte_size = 0x70, - DW_AT_rank = 0x71, - DW_AT_str_offsets_base = 0x72, - DW_AT_addr_base = 0x73, - DW_AT_rnglists_base = 0x74, - DW_AT_dwo_name = 0x76, - DW_AT_reference = 0x77, - DW_AT_rvalue_reference = 0x78, - DW_AT_macros = 0x79, - DW_AT_call_all_calls = 0x7a, - DW_AT_call_all_source_calls = 0x7b, - DW_AT_call_all_tail_calls = 0x7c, - DW_AT_call_return_pc = 0x7d, - DW_AT_call_value = 0x7e, - DW_AT_call_origin = 0x7f, - DW_AT_call_parameter = 0x80, - DW_AT_call_pc = 0x81, - DW_AT_call_tail_call = 0x82, - DW_AT_call_target = 0x83, - DW_AT_call_target_clobbered = 0x84, - DW_AT_call_data_location = 0x85, - DW_AT_call_data_value = 0x86, - DW_AT_noreturn = 0x87, - DW_AT_alignment = 0x88, - DW_AT_export_symbols = 0x89, - DW_AT_deleted = 0x8a, - DW_AT_defaulted = 0x8b, - DW_AT_loclists_base = 0x8c, - DW_AT_lo_user = 0x2000, - DW_AT_hi_user = 0x3fff, - DW_AT_MIPS_fde = 0x2001, - DW_AT_MIPS_loop_begin = 0x2002, - DW_AT_MIPS_tail_loop_begin = 0x2003, - DW_AT_MIPS_epilog_begin = 0x2004, - DW_AT_MIPS_loop_unroll_factor = 0x2005, - DW_AT_MIPS_software_pipeline_depth = 0x2006, - DW_AT_MIPS_linkage_name = 0x2007, - DW_AT_MIPS_stride = 0x2008, - DW_AT_MIPS_abstract_name = 0x2009, - DW_AT_MIPS_clone_origin = 0x200a, - DW_AT_MIPS_has_inlines = 0x200b, - DW_AT_HP_block_index = 0x2000, - DW_AT_HP_unmodifiable = 0x2001, - DW_AT_HP_prologue = 0x2005, - DW_AT_HP_epilogue = 0x2008, - DW_AT_HP_actuals_stmt_list = 0x2010, - DW_AT_HP_proc_per_section = 0x2011, - DW_AT_HP_raw_data_ptr = 0x2012, - DW_AT_HP_pass_by_reference = 0x2013, - DW_AT_HP_opt_level = 0x2014, - DW_AT_HP_prof_version_id = 0x2015, - DW_AT_HP_opt_flags = 0x2016, - DW_AT_HP_cold_region_low_pc = 0x2017, - DW_AT_HP_cold_region_high_pc = 0x2018, - DW_AT_HP_all_variables_modifiable = 0x2019, - DW_AT_HP_linkage_name = 0x201a, - DW_AT_HP_prof_flags = 0x201b, - DW_AT_HP_unit_name = 0x201f, - DW_AT_HP_unit_size = 0x2020, - DW_AT_HP_widened_byte_size = 0x2021, - DW_AT_HP_definition_points = 0x2022, - DW_AT_HP_default_location = 0x2023, - DW_AT_HP_is_result_param = 0x2029, - DW_AT_sf_names = 0x2101, - DW_AT_src_info = 0x2102, - DW_AT_mac_info = 0x2103, - DW_AT_src_coords = 0x2104, - DW_AT_body_begin = 0x2105, - DW_AT_body_end = 0x2106, - DW_AT_GNU_vector = 0x2107, - DW_AT_GNU_guarded_by = 0x2108, - DW_AT_GNU_pt_guarded_by = 0x2109, - DW_AT_GNU_guarded = 0x210a, - DW_AT_GNU_pt_guarded = 0x210b, - DW_AT_GNU_locks_excluded = 0x210c, - DW_AT_GNU_exclusive_locks_required = 0x210d, - DW_AT_GNU_shared_locks_required = 0x210e, - DW_AT_GNU_odr_signature = 0x210f, - DW_AT_GNU_template_name = 0x2110, - DW_AT_GNU_call_site_value = 0x2111, - DW_AT_GNU_call_site_data_value = 0x2112, - DW_AT_GNU_call_site_target = 0x2113, - DW_AT_GNU_call_site_target_clobbered = 0x2114, - DW_AT_GNU_tail_call = 0x2115, - DW_AT_GNU_all_tail_call_sites = 0x2116, - DW_AT_GNU_all_call_sites = 0x2117, - DW_AT_GNU_all_source_call_sites = 0x2118, - DW_AT_GNU_macros = 0x2119, - DW_AT_GNU_deleted = 0x211a, - DW_AT_GNU_dwo_name = 0x2130, - DW_AT_GNU_dwo_id = 0x2131, - DW_AT_GNU_ranges_base = 0x2132, - DW_AT_GNU_addr_base = 0x2133, - DW_AT_GNU_pubnames = 0x2134, - DW_AT_GNU_pubtypes = 0x2135, - DW_AT_GNU_discriminator = 0x2136, - DW_AT_GNU_locviews = 0x2137, - DW_AT_GNU_entry_view = 0x2138, - DW_AT_VMS_rtnbeg_pd_address = 0x2201, - DW_AT_use_GNAT_descriptive_type = 0x2301, - DW_AT_GNAT_descriptive_type = 0x2302, - DW_AT_GNU_numerator = 0x2303, - DW_AT_GNU_denominator = 0x2304, - DW_AT_GNU_bias = 0x2305, - DW_AT_upc_threads_scaled = 0x3210, - DW_AT_PGI_lbase = 0x3a00, - DW_AT_PGI_soffset = 0x3a01, - DW_AT_PGI_lstride = 0x3a02, - DW_AT_APPLE_optimized = 0x3fe1, - DW_AT_APPLE_flags = 0x3fe2, - DW_AT_APPLE_isa = 0x3fe3, - DW_AT_APPLE_block = 0x3fe4, - DW_AT_APPLE_major_runtime_vers = 0x3fe5, - DW_AT_APPLE_runtime_class = 0x3fe6, - DW_AT_APPLE_omit_frame_ptr = 0x3fe7, - DW_AT_APPLE_property_name = 0x3fe8, - DW_AT_APPLE_property_getter = 0x3fe9, - DW_AT_APPLE_property_setter = 0x3fea, - DW_AT_APPLE_property_attribute = 0x3feb, - DW_AT_APPLE_objc_complete_type = 0x3fec, - DW_AT_APPLE_property = 0x3fed -}; - -enum dwarf_line_number_op { - DW_LNS_extended_op = 0x0, - DW_LNS_copy = 0x1, - DW_LNS_advance_pc = 0x2, - DW_LNS_advance_line = 0x3, - DW_LNS_set_file = 0x4, - DW_LNS_set_column = 0x5, - DW_LNS_negate_stmt = 0x6, - DW_LNS_set_basic_block = 0x7, - DW_LNS_const_add_pc = 0x8, - DW_LNS_fixed_advance_pc = 0x9, - DW_LNS_set_prologue_end = 0xa, - DW_LNS_set_epilogue_begin = 0xb, - DW_LNS_set_isa = 0xc, -}; - -enum dwarf_extended_line_number_op { - DW_LNE_end_sequence = 0x1, - DW_LNE_set_address = 0x2, - DW_LNE_define_file = 0x3, - DW_LNE_set_discriminator = 0x4, -}; - -enum dwarf_line_number_content_type { - DW_LNCT_path = 0x1, - DW_LNCT_directory_index = 0x2, - DW_LNCT_timestamp = 0x3, - DW_LNCT_size = 0x4, - DW_LNCT_MD5 = 0x5, - DW_LNCT_lo_user = 0x2000, - DW_LNCT_hi_user = 0x3fff -}; - -enum dwarf_range_list_entry { - DW_RLE_end_of_list = 0x00, - DW_RLE_base_addressx = 0x01, - DW_RLE_startx_endx = 0x02, - DW_RLE_startx_length = 0x03, - DW_RLE_offset_pair = 0x04, - DW_RLE_base_address = 0x05, - DW_RLE_start_end = 0x06, - DW_RLE_start_length = 0x07 -}; - -enum dwarf_unit_type { - DW_UT_compile = 0x01, - DW_UT_type = 0x02, - DW_UT_partial = 0x03, - DW_UT_skeleton = 0x04, - DW_UT_split_compile = 0x05, - DW_UT_split_type = 0x06, - DW_UT_lo_user = 0x80, - DW_UT_hi_user = 0xff -}; - -#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN - -/* If strnlen is not declared, provide our own version. */ - -static size_t -xstrnlen (const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; ++i) - if (s[i] == '\0') - break; - return i; -} - -#define strnlen xstrnlen - -#endif - -/* A buffer to read DWARF info. */ - -struct dwarf_buf -{ - /* Buffer name for error messages. */ - const char *name; - /* Start of the buffer. */ - const unsigned char *start; - /* Next byte to read. */ - const unsigned char *buf; - /* The number of bytes remaining. */ - size_t left; - /* Whether the data is big-endian. */ - int is_bigendian; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data for error_callback. */ - void *data; - /* Non-zero if we've reported an underflow error. */ - int reported_underflow; -}; - -/* A single attribute in a DWARF abbreviation. */ - -struct attr -{ - /* The attribute name. */ - enum dwarf_attribute name; - /* The attribute form. */ - enum dwarf_form form; - /* The attribute value, for DW_FORM_implicit_const. */ - int64_t val; -}; - -/* A single DWARF abbreviation. */ - -struct abbrev -{ - /* The abbrev code--the number used to refer to the abbrev. */ - uint64_t code; - /* The entry tag. */ - enum dwarf_tag tag; - /* Non-zero if this abbrev has child entries. */ - int has_children; - /* The number of attributes. */ - size_t num_attrs; - /* The attributes. */ - struct attr *attrs; -}; - -/* The DWARF abbreviations for a compilation unit. This structure - only exists while reading the compilation unit. Most DWARF readers - seem to a hash table to map abbrev ID's to abbrev entries. - However, we primarily care about GCC, and GCC simply issues ID's in - numerical order starting at 1. So we simply keep a sorted vector, - and try to just look up the code. */ - -struct abbrevs -{ - /* The number of abbrevs in the vector. */ - size_t num_abbrevs; - /* The abbrevs, sorted by the code field. */ - struct abbrev *abbrevs; -}; - -/* The different kinds of attribute values. */ - -enum attr_val_encoding -{ - /* No attribute value. */ - ATTR_VAL_NONE, - /* An address. */ - ATTR_VAL_ADDRESS, - /* An index into the .debug_addr section, whose value is relative to - * the DW_AT_addr_base attribute of the compilation unit. */ - ATTR_VAL_ADDRESS_INDEX, - /* A unsigned integer. */ - ATTR_VAL_UINT, - /* A sigd integer. */ - ATTR_VAL_SINT, - /* A string. */ - ATTR_VAL_STRING, - /* An index into the .debug_str_offsets section. */ - ATTR_VAL_STRING_INDEX, - /* An offset to other data in the containing unit. */ - ATTR_VAL_REF_UNIT, - /* An offset to other data within the .debug_info section. */ - ATTR_VAL_REF_INFO, - /* An offset to other data within the alt .debug_info section. */ - ATTR_VAL_REF_ALT_INFO, - /* An offset to data in some other section. */ - ATTR_VAL_REF_SECTION, - /* A type signature. */ - ATTR_VAL_REF_TYPE, - /* An index into the .debug_rnglists section. */ - ATTR_VAL_RNGLISTS_INDEX, - /* A block of data (not represented). */ - ATTR_VAL_BLOCK, - /* An expression (not represented). */ - ATTR_VAL_EXPR, -}; - -/* An attribute value. */ - -struct attr_val -{ - /* How the value is stored in the field u. */ - enum attr_val_encoding encoding; - union - { - /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */ - uint64_t uint; - /* ATTR_VAL_SINT. */ - int64_t sint; - /* ATTR_VAL_STRING. */ - const char *string; - /* ATTR_VAL_BLOCK not stored. */ - } u; -}; - -/* The line number program header. */ - -struct line_header -{ - /* The version of the line number information. */ - int version; - /* Address size. */ - int addrsize; - /* The minimum instruction length. */ - unsigned int min_insn_len; - /* The maximum number of ops per instruction. */ - unsigned int max_ops_per_insn; - /* The line base for special opcodes. */ - int line_base; - /* The line range for special opcodes. */ - unsigned int line_range; - /* The opcode base--the first special opcode. */ - unsigned int opcode_base; - /* Opcode lengths, indexed by opcode - 1. */ - const unsigned char *opcode_lengths; - /* The number of directory entries. */ - size_t dirs_count; - /* The directory entries. */ - const char **dirs; - /* The number of filenames. */ - size_t filenames_count; - /* The filenames. */ - const char **filenames; -}; - -/* A format description from a line header. */ - -struct line_header_format -{ - int lnct; /* LNCT code. */ - enum dwarf_form form; /* Form of entry data. */ -}; - -/* Map a single PC value to a file/line. We will keep a vector of - these sorted by PC value. Each file/line will be correct from the - PC up to the PC of the next entry if there is one. We allocate one - extra entry at the end so that we can use bsearch. */ - -struct line -{ - /* PC. */ - uintptr_t pc; - /* File name. Many entries in the array are expected to point to - the same file name. */ - const char *filename; - /* Line number. */ - int lineno; - /* Index of the object in the original array read from the DWARF - section, before it has been sorted. The index makes it possible - to use Quicksort and maintain stability. */ - int idx; -}; - -/* A growable vector of line number information. This is used while - reading the line numbers. */ - -struct line_vector -{ - /* Memory. This is an array of struct line. */ - struct backtrace_vector vec; - /* Number of valid mappings. */ - size_t count; -}; - -/* A function described in the debug info. */ - -struct function -{ - /* The name of the function. */ - const char *name; - /* If this is an inlined function, the filename of the call - site. */ - const char *caller_filename; - /* If this is an inlined function, the line number of the call - site. */ - int caller_lineno; - /* Map PC ranges to inlined functions. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a function. This maps a PC value to a - specific function. */ - -struct function_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Function for this address range. */ - struct function *function; -}; - -/* A growable vector of function address ranges. */ - -struct function_vector -{ - /* Memory. This is an array of struct function_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* A DWARF compilation unit. This only holds the information we need - to map a PC to a file and line. */ - -struct unit -{ - /* The first entry for this compilation unit. */ - const unsigned char *unit_data; - /* The length of the data for this compilation unit. */ - size_t unit_data_len; - /* The offset of UNIT_DATA from the start of the information for - this compilation unit. */ - size_t unit_data_offset; - /* Offset of the start of the compilation unit from the start of the - .debug_info section. */ - size_t low_offset; - /* Offset of the end of the compilation unit from the start of the - .debug_info section. */ - size_t high_offset; - /* DWARF version. */ - int version; - /* Whether unit is DWARF64. */ - int is_dwarf64; - /* Address size. */ - int addrsize; - /* Offset into line number information. */ - off_t lineoff; - /* Offset of compilation unit in .debug_str_offsets. */ - uint64_t str_offsets_base; - /* Offset of compilation unit in .debug_addr. */ - uint64_t addr_base; - /* Offset of compilation unit in .debug_rnglists. */ - uint64_t rnglists_base; - /* Primary source file. */ - const char *filename; - /* Compilation command working directory. */ - const char *comp_dir; - /* Absolute file name, only set if needed. */ - const char *abs_filename; - /* The abbreviations for this unit. */ - struct abbrevs abbrevs; - - /* The fields above this point are read in during initialization and - may be accessed freely. The fields below this point are read in - as needed, and therefore require care, as different threads may - try to initialize them simultaneously. */ - - /* PC to line number mapping. This is NULL if the values have not - been read. This is (struct line *) -1 if there was an error - reading the values. */ - struct line *lines; - /* Number of entries in lines. */ - size_t lines_count; - /* PC ranges to function. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a compilation unit. This maps a PC value to a - specific compilation unit. Note that we invert the representation - in DWARF: instead of listing the units and attaching a list of - ranges, we list the ranges and have each one point to the unit. - This lets us do a binary search to find the unit. */ - -struct unit_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Compilation unit for this address range. */ - struct unit *u; -}; - -/* A growable vector of compilation unit address ranges. */ - -struct unit_addrs_vector -{ - /* Memory. This is an array of struct unit_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* A growable vector of compilation unit pointer. */ - -struct unit_vector -{ - struct backtrace_vector vec; - size_t count; -}; - -/* The information we need to map a PC to a file and line. */ - -struct dwarf_data -{ - /* The data for the next file we know about. */ - struct dwarf_data *next; - /* The data for .gnu_debugaltlink. */ - struct dwarf_data *altlink; - /* The base address for this file. */ - uintptr_t base_address; - /* A sorted list of address ranges. */ - struct unit_addrs *addrs; - /* Number of address ranges in list. */ - size_t addrs_count; - /* A sorted list of units. */ - struct unit **units; - /* Number of units in the list. */ - size_t units_count; - /* The unparsed DWARF debug data. */ - struct dwarf_sections dwarf_sections; - /* Whether the data is big-endian or not. */ - int is_bigendian; - /* A vector used for function addresses. We keep this here so that - we can grow the vector as we read more functions. */ - struct function_vector fvec; -}; - -/* Report an error for a DWARF buffer. */ - -static void -dwarf_buf_error (struct dwarf_buf *buf, const char *msg) -{ - char b[200]; - - snprintf (b, sizeof b, "%s in %s at %d", - msg, buf->name, (int) (buf->buf - buf->start)); - buf->error_callback (buf->data, b, 0); -} - -/* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -require (struct dwarf_buf *buf, size_t count) -{ - if (buf->left >= count) - return 1; - - if (!buf->reported_underflow) - { - dwarf_buf_error (buf, "DWARF underflow"); - buf->reported_underflow = 1; - } - - return 0; -} - -/* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -advance (struct dwarf_buf *buf, size_t count) -{ - if (!require (buf, count)) - return 0; - buf->buf += count; - buf->left -= count; - return 1; -} - -/* Read one zero-terminated string from BUF and advance past the string. */ - -static const char * -read_string (struct dwarf_buf *buf) -{ - const char *p = (const char *)buf->buf; - size_t len = strnlen (p, buf->left); - - /* - If len == left, we ran out of buffer before finding the zero terminator. - Generate an error by advancing len + 1. - - If len < left, advance by len + 1 to skip past the zero terminator. */ - size_t count = len + 1; - - if (!advance (buf, count)) - return NULL; - - return p; -} - -/* Read one byte from BUF and advance 1 byte. */ - -static unsigned char -read_byte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return p[0]; -} - -/* Read a signed char from BUF and advance 1 byte. */ - -static signed char -read_sbyte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return (*p ^ 0x80) - 0x80; -} - -/* Read a uint16 from BUF and advance 2 bytes. */ - -static uint16_t -read_uint16 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 2)) - return 0; - if (buf->is_bigendian) - return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; - else - return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; -} - -/* Read a 24 bit value from BUF and advance 3 bytes. */ - -static uint32_t -read_uint24 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 3)) - return 0; - if (buf->is_bigendian) - return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8) - | (uint32_t) p[2]); - else - return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8) - | (uint32_t) p[0]); -} - -/* Read a uint32 from BUF and advance 4 bytes. */ - -static uint32_t -read_uint32 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 4)) - return 0; - if (buf->is_bigendian) - return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) - | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); - else - return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) - | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); -} - -/* Read a uint64 from BUF and advance 8 bytes. */ - -static uint64_t -read_uint64 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 8)) - return 0; - if (buf->is_bigendian) - return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48) - | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32) - | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16) - | ((uint64_t) p[6] << 8) | (uint64_t) p[7]); - else - return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) - | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) - | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) - | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); -} - -/* Read an offset from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_offset (struct dwarf_buf *buf, int is_dwarf64) -{ - if (is_dwarf64) - return read_uint64 (buf); - else - return read_uint32 (buf); -} - -/* Read an address from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_address (struct dwarf_buf *buf, int addrsize) -{ - switch (addrsize) - { - case 1: - return read_byte (buf); - case 2: - return read_uint16 (buf); - case 4: - return read_uint32 (buf); - case 8: - return read_uint64 (buf); - default: - dwarf_buf_error (buf, "unrecognized address size"); - return 0; - } -} - -/* Return whether a value is the highest possible address, given the - address size. */ - -static int -is_highest_address (uint64_t address, int addrsize) -{ - switch (addrsize) - { - case 1: - return address == (unsigned char) -1; - case 2: - return address == (uint16_t) -1; - case 4: - return address == (uint32_t) -1; - case 8: - return address == (uint64_t) -1; - default: - return 0; - } -} - -/* Read an unsigned LEB128 number. */ - -static uint64_t -read_uleb128 (struct dwarf_buf *buf) -{ - uint64_t ret; - unsigned int shift; - int overflow; - unsigned char b; - - ret = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - ret |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - return ret; -} - -/* Read a signed LEB128 number. */ - -static int64_t -read_sleb128 (struct dwarf_buf *buf) -{ - uint64_t val; - unsigned int shift; - int overflow; - unsigned char b; - - val = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - val |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - if ((b & 0x40) != 0 && shift < 64) - val |= ((uint64_t) -1) << shift; - - return (int64_t) val; -} - -/* Return the length of an LEB128 number. */ - -static size_t -leb128_len (const unsigned char *p) -{ - size_t ret; - - ret = 1; - while ((*p & 0x80) != 0) - { - ++p; - ++ret; - } - return ret; -} - -/* Read initial_length from BUF and advance the appropriate number of bytes. */ - -static uint64_t -read_initial_length (struct dwarf_buf *buf, int *is_dwarf64) -{ - uint64_t len; - - len = read_uint32 (buf); - if (len == 0xffffffff) - { - len = read_uint64 (buf); - *is_dwarf64 = 1; - } - else - *is_dwarf64 = 0; - - return len; -} - -/* Free an abbreviations structure. */ - -static void -free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, - backtrace_error_callback error_callback, void *data) -{ - size_t i; - - for (i = 0; i < abbrevs->num_abbrevs; ++i) - backtrace_free (state, abbrevs->abbrevs[i].attrs, - abbrevs->abbrevs[i].num_attrs * sizeof (struct attr), - error_callback, data); - backtrace_free (state, abbrevs->abbrevs, - abbrevs->num_abbrevs * sizeof (struct abbrev), - error_callback, data); - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; -} - -/* Read an attribute value. Returns 1 on success, 0 on failure. If - the value can be represented as a uint64_t, sets *VAL and sets - *IS_VALID to 1. We don't try to store the value of other attribute - forms, because we don't care about them. */ - -static int -read_attribute (enum dwarf_form form, uint64_t implicit_val, - struct dwarf_buf *buf, int is_dwarf64, int version, - int addrsize, const struct dwarf_sections *dwarf_sections, - struct dwarf_data *altlink, struct attr_val *val) -{ - /* Avoid warnings about val.u.FIELD may be used uninitialized if - this function is inlined. The warnings aren't valid but can - occur because the different fields are set and used - conditionally. */ - memset (val, 0, sizeof *val); - - switch (form) - { - case DW_FORM_addr: - val->encoding = ATTR_VAL_ADDRESS; - val->u.uint = read_address (buf, addrsize); - return 1; - case DW_FORM_block2: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint16 (buf)); - case DW_FORM_block4: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint32 (buf)); - case DW_FORM_data2: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_data4: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_data8: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_data16: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, 16); - case DW_FORM_string: - val->encoding = ATTR_VAL_STRING; - val->u.string = read_string (buf); - return val->u.string == NULL ? 0 : 1; - case DW_FORM_block: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_block1: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_byte (buf)); - case DW_FORM_data1: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_flag: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_sdata: - val->encoding = ATTR_VAL_SINT; - val->u.sint = read_sleb128 (buf); - return 1; - case DW_FORM_strp: - { - uint64_t offset; - - offset = read_offset (buf, is_dwarf64); - if (offset >= dwarf_sections->size[DEBUG_STR]) - { - dwarf_buf_error (buf, "DW_FORM_strp out of range"); - return 0; - } - val->encoding = ATTR_VAL_STRING; - val->u.string = - (const char *) dwarf_sections->data[DEBUG_STR] + offset; - return 1; - } - case DW_FORM_line_strp: - { - uint64_t offset; - - offset = read_offset (buf, is_dwarf64); - if (offset >= dwarf_sections->size[DEBUG_LINE_STR]) - { - dwarf_buf_error (buf, "DW_FORM_line_strp out of range"); - return 0; - } - val->encoding = ATTR_VAL_STRING; - val->u.string = - (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset; - return 1; - } - case DW_FORM_udata: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_ref_addr: - val->encoding = ATTR_VAL_REF_INFO; - if (version == 2) - val->u.uint = read_address (buf, addrsize); - else - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_ref1: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_ref2: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_ref4: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_ref8: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_ref_udata: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_indirect: - { - uint64_t form; - - form = read_uleb128 (buf); - if (form == DW_FORM_implicit_const) - { - dwarf_buf_error (buf, - "DW_FORM_indirect to DW_FORM_implicit_const"); - return 0; - } - return read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64, - version, addrsize, dwarf_sections, altlink, - val); - } - case DW_FORM_sec_offset: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_exprloc: - val->encoding = ATTR_VAL_EXPR; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_flag_present: - val->encoding = ATTR_VAL_UINT; - val->u.uint = 1; - return 1; - case DW_FORM_ref_sig8: - val->encoding = ATTR_VAL_REF_TYPE; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2: - case DW_FORM_strx3: case DW_FORM_strx4: - { - uint64_t offset; - - switch (form) - { - case DW_FORM_strx: - offset = read_uleb128 (buf); - break; - case DW_FORM_strx1: - offset = read_byte (buf); - break; - case DW_FORM_strx2: - offset = read_uint16 (buf); - break; - case DW_FORM_strx3: - offset = read_uint24 (buf); - break; - case DW_FORM_strx4: - offset = read_uint32 (buf); - break; - default: - /* This case can't happen. */ - return 0; - } - val->encoding = ATTR_VAL_STRING_INDEX; - val->u.uint = offset; - return 1; - } - case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2: - case DW_FORM_addrx3: case DW_FORM_addrx4: - { - uint64_t offset; - - switch (form) - { - case DW_FORM_addrx: - offset = read_uleb128 (buf); - break; - case DW_FORM_addrx1: - offset = read_byte (buf); - break; - case DW_FORM_addrx2: - offset = read_uint16 (buf); - break; - case DW_FORM_addrx3: - offset = read_uint24 (buf); - break; - case DW_FORM_addrx4: - offset = read_uint32 (buf); - break; - default: - /* This case can't happen. */ - return 0; - } - val->encoding = ATTR_VAL_ADDRESS_INDEX; - val->u.uint = offset; - return 1; - } - case DW_FORM_ref_sup4: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_ref_sup8: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_implicit_const: - val->encoding = ATTR_VAL_UINT; - val->u.uint = implicit_val; - return 1; - case DW_FORM_loclistx: - /* We don't distinguish this from DW_FORM_sec_offset. It - * shouldn't matter since we don't care about loclists. */ - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_rnglistx: - val->encoding = ATTR_VAL_RNGLISTS_INDEX; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_addr_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_str_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_ref_alt: - val->u.uint = read_offset (buf, is_dwarf64); - if (altlink == NULL) - { - val->encoding = ATTR_VAL_NONE; - return 1; - } - val->encoding = ATTR_VAL_REF_ALT_INFO; - return 1; - case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt: - { - uint64_t offset; - - offset = read_offset (buf, is_dwarf64); - if (altlink == NULL) - { - val->encoding = ATTR_VAL_NONE; - return 1; - } - if (offset >= altlink->dwarf_sections.size[DEBUG_STR]) - { - dwarf_buf_error (buf, "DW_FORM_strp_sup out of range"); - return 0; - } - val->encoding = ATTR_VAL_STRING; - val->u.string = - (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset; - return 1; - } - default: - dwarf_buf_error (buf, "unrecognized DWARF form"); - return 0; - } -} - -/* If we can determine the value of a string attribute, set *STRING to - point to the string. Return 1 on success, 0 on error. If we don't - know the value, we consider that a success, and we don't change - *STRING. An error is only reported for some sort of out of range - offset. */ - -static int -resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64, - int is_bigendian, uint64_t str_offsets_base, - const struct attr_val *val, - backtrace_error_callback error_callback, void *data, - const char **string) -{ - switch (val->encoding) - { - case ATTR_VAL_STRING: - *string = val->u.string; - return 1; - - case ATTR_VAL_STRING_INDEX: - { - uint64_t offset; - struct dwarf_buf offset_buf; - - offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base; - if (offset + (is_dwarf64 ? 8 : 4) - >= dwarf_sections->size[DEBUG_STR_OFFSETS]) - { - error_callback (data, "DW_FORM_strx value out of range", 0); - return 0; - } - - offset_buf.name = ".debug_str_offsets"; - offset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS]; - offset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset; - offset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset; - offset_buf.is_bigendian = is_bigendian; - offset_buf.error_callback = error_callback; - offset_buf.data = data; - offset_buf.reported_underflow = 0; - - offset = read_offset (&offset_buf, is_dwarf64); - if (offset >= dwarf_sections->size[DEBUG_STR]) - { - dwarf_buf_error (&offset_buf, "DW_FORM_strx offset out of range"); - return 0; - } - *string = (const char *) dwarf_sections->data[DEBUG_STR] + offset; - return 1; - } - - default: - return 1; - } -} - -/* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX. - Return 1 on success, 0 on error. */ - -static int -resolve_addr_index (const struct dwarf_sections *dwarf_sections, - uint64_t addr_base, int addrsize, int is_bigendian, - uint64_t addr_index, - backtrace_error_callback error_callback, void *data, - uint64_t *address) -{ - uint64_t offset; - struct dwarf_buf addr_buf; - - offset = addr_index * addrsize + addr_base; - if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR]) - { - error_callback (data, "DW_FORM_addrx value out of range", 0); - return 0; - } - - addr_buf.name = ".debug_addr"; - addr_buf.start = dwarf_sections->data[DEBUG_ADDR]; - addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset; - addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset; - addr_buf.is_bigendian = is_bigendian; - addr_buf.error_callback = error_callback; - addr_buf.data = data; - addr_buf.reported_underflow = 0; - - *address = read_address (&addr_buf, addrsize); - return 1; -} - -/* Compare a unit offset against a unit for bsearch. */ - -static int -units_search (const void *vkey, const void *ventry) -{ - const size_t *key = (const size_t *) vkey; - const struct unit *entry = *((const struct unit *const *) ventry); - size_t offset; - - offset = *key; - if (offset < entry->low_offset) - return -1; - else if (offset >= entry->high_offset) - return 1; - else - return 0; -} - -/* Find a unit in PU containing OFFSET. */ - -static struct unit * -find_unit (struct unit **pu, size_t units_count, size_t offset) -{ - struct unit **u; - u = bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search); - return u == NULL ? NULL : *u; -} - -/* Compare function_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -function_addrs_compare (const void *v1, const void *v2) -{ - const struct function_addrs *a1 = (const struct function_addrs *) v1; - const struct function_addrs *a2 = (const struct function_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - return strcmp (a1->function->name, a2->function->name); -} - -/* Compare a PC against a function_addrs for bsearch. Note that if - there are multiple ranges containing PC, which one will be returned - is unpredictable. We compensate for that in dwarf_fileline. */ - -static int -function_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct function_addrs *entry = (const struct function_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Add a new compilation unit address range to a vector. This is - called via add_ranges. Returns 1 on success, 0 on failure. */ - -static int -add_unit_addr (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, void *data, - void *pvec) -{ - struct unit *u = (struct unit *) rdata; - struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec; - struct unit_addrs *p; - - /* Try to merge with the last entry. */ - if (vec->count > 0) - { - p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); - if ((lowpc == p->high || lowpc == p->high + 1) - && u == p->u) - { - if (highpc > p->high) - p->high = highpc; - return 1; - } - } - - p = ((struct unit_addrs *) - backtrace_vector_grow (state, sizeof (struct unit_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - p->low = lowpc; - p->high = highpc; - p->u = u; - - ++vec->count; - - return 1; -} - -/* Compare unit_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -unit_addrs_compare (const void *v1, const void *v2) -{ - const struct unit_addrs *a1 = (const struct unit_addrs *) v1; - const struct unit_addrs *a2 = (const struct unit_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - if (a1->u->lineoff < a2->u->lineoff) - return -1; - if (a1->u->lineoff > a2->u->lineoff) - return 1; - return 0; -} - -/* Compare a PC against a unit_addrs for bsearch. Note that if there - are multiple ranges containing PC, which one will be returned is - unpredictable. We compensate for that in dwarf_fileline. */ - -static int -unit_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct unit_addrs *entry = (const struct unit_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Sort the line vector by PC. We want a stable sort here to maintain - the order of lines for the same PC values. Since the sequence is - being sorted in place, their addresses cannot be relied on to - maintain stability. That is the purpose of the index member. */ - -static int -line_compare (const void *v1, const void *v2) -{ - const struct line *ln1 = (const struct line *) v1; - const struct line *ln2 = (const struct line *) v2; - - if (ln1->pc < ln2->pc) - return -1; - else if (ln1->pc > ln2->pc) - return 1; - else if (ln1->idx < ln2->idx) - return -1; - else if (ln1->idx > ln2->idx) - return 1; - else - return 0; -} - -/* Find a PC in a line vector. We always allocate an extra entry at - the end of the lines vector, so that this routine can safely look - at the next entry. Note that when there are multiple mappings for - the same PC value, this will return the last one. */ - -static int -line_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct line *entry = (const struct line *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->pc) - return -1; - else if (pc >= (entry + 1)->pc) - return 1; - else - return 0; -} - -/* Sort the abbrevs by the abbrev code. This function is passed to - both qsort and bsearch. */ - -static int -abbrev_compare (const void *v1, const void *v2) -{ - const struct abbrev *a1 = (const struct abbrev *) v1; - const struct abbrev *a2 = (const struct abbrev *) v2; - - if (a1->code < a2->code) - return -1; - else if (a1->code > a2->code) - return 1; - else - { - /* This really shouldn't happen. It means there are two - different abbrevs with the same code, and that means we don't - know which one lookup_abbrev should return. */ - return 0; - } -} - -/* Read the abbreviation table for a compilation unit. Returns 1 on - success, 0 on failure. */ - -static int -read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct abbrevs *abbrevs) -{ - struct dwarf_buf abbrev_buf; - struct dwarf_buf count_buf; - size_t num_abbrevs; - - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; - - if (abbrev_offset >= dwarf_abbrev_size) - { - error_callback (data, "abbrev offset out of range", 0); - return 0; - } - - abbrev_buf.name = ".debug_abbrev"; - abbrev_buf.start = dwarf_abbrev; - abbrev_buf.buf = dwarf_abbrev + abbrev_offset; - abbrev_buf.left = dwarf_abbrev_size - abbrev_offset; - abbrev_buf.is_bigendian = is_bigendian; - abbrev_buf.error_callback = error_callback; - abbrev_buf.data = data; - abbrev_buf.reported_underflow = 0; - - /* Count the number of abbrevs in this list. */ - - count_buf = abbrev_buf; - num_abbrevs = 0; - while (read_uleb128 (&count_buf) != 0) - { - if (count_buf.reported_underflow) - return 0; - ++num_abbrevs; - // Skip tag. - read_uleb128 (&count_buf); - // Skip has_children. - read_byte (&count_buf); - // Skip attributes. - while (read_uleb128 (&count_buf) != 0) - { - uint64_t form; - - form = read_uleb128 (&count_buf); - if ((enum dwarf_form) form == DW_FORM_implicit_const) - read_sleb128 (&count_buf); - } - // Skip form of last attribute. - read_uleb128 (&count_buf); - } - - if (count_buf.reported_underflow) - return 0; - - if (num_abbrevs == 0) - return 1; - - abbrevs->abbrevs = ((struct abbrev *) - backtrace_alloc (state, - num_abbrevs * sizeof (struct abbrev), - error_callback, data)); - if (abbrevs->abbrevs == NULL) - return 0; - abbrevs->num_abbrevs = num_abbrevs; - memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev)); - - num_abbrevs = 0; - while (1) - { - uint64_t code; - struct abbrev a; - size_t num_attrs; - struct attr *attrs; - - if (abbrev_buf.reported_underflow) - goto fail; - - code = read_uleb128 (&abbrev_buf); - if (code == 0) - break; - - a.code = code; - a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf); - a.has_children = read_byte (&abbrev_buf); - - count_buf = abbrev_buf; - num_attrs = 0; - while (read_uleb128 (&count_buf) != 0) - { - uint64_t form; - - ++num_attrs; - form = read_uleb128 (&count_buf); - if ((enum dwarf_form) form == DW_FORM_implicit_const) - read_sleb128 (&count_buf); - } - - if (num_attrs == 0) - { - attrs = NULL; - read_uleb128 (&abbrev_buf); - read_uleb128 (&abbrev_buf); - } - else - { - attrs = ((struct attr *) - backtrace_alloc (state, num_attrs * sizeof *attrs, - error_callback, data)); - if (attrs == NULL) - goto fail; - num_attrs = 0; - while (1) - { - uint64_t name; - uint64_t form; - - name = read_uleb128 (&abbrev_buf); - form = read_uleb128 (&abbrev_buf); - if (name == 0) - break; - attrs[num_attrs].name = (enum dwarf_attribute) name; - attrs[num_attrs].form = (enum dwarf_form) form; - if ((enum dwarf_form) form == DW_FORM_implicit_const) - attrs[num_attrs].val = read_sleb128 (&abbrev_buf); - else - attrs[num_attrs].val = 0; - ++num_attrs; - } - } - - a.num_attrs = num_attrs; - a.attrs = attrs; - - abbrevs->abbrevs[num_abbrevs] = a; - ++num_abbrevs; - } - - backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - - return 1; - - fail: - free_abbrevs (state, abbrevs, error_callback, data); - return 0; -} - -/* Return the abbrev information for an abbrev code. */ - -static const struct abbrev * -lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, - backtrace_error_callback error_callback, void *data) -{ - struct abbrev key; - void *p; - - /* With GCC, where abbrevs are simply numbered in order, we should - be able to just look up the entry. */ - if (code - 1 < abbrevs->num_abbrevs - && abbrevs->abbrevs[code - 1].code == code) - return &abbrevs->abbrevs[code - 1]; - - /* Otherwise we have to search. */ - memset (&key, 0, sizeof key); - key.code = code; - p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - if (p == NULL) - { - error_callback (data, "invalid abbreviation code", 0); - return NULL; - } - return (const struct abbrev *) p; -} - -/* This struct is used to gather address range information while - reading attributes. We use this while building a mapping from - address ranges to compilation units and then again while mapping - from address ranges to function entries. Normally either - lowpc/highpc is set or ranges is set. */ - -struct pcrange { - uint64_t lowpc; /* The low PC value. */ - int have_lowpc; /* Whether a low PC value was found. */ - int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */ - uint64_t highpc; /* The high PC value. */ - int have_highpc; /* Whether a high PC value was found. */ - int highpc_is_relative; /* Whether highpc is relative to lowpc. */ - int highpc_is_addr_index; /* Whether highpc is in .debug_addr. */ - uint64_t ranges; /* Offset in ranges section. */ - int have_ranges; /* Whether ranges is valid. */ - int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */ -}; - -/* Update PCRANGE from an attribute value. */ - -static void -update_pcrange (const struct attr* attr, const struct attr_val* val, - struct pcrange *pcrange) -{ - switch (attr->name) - { - case DW_AT_low_pc: - if (val->encoding == ATTR_VAL_ADDRESS) - { - pcrange->lowpc = val->u.uint; - pcrange->have_lowpc = 1; - } - else if (val->encoding == ATTR_VAL_ADDRESS_INDEX) - { - pcrange->lowpc = val->u.uint; - pcrange->have_lowpc = 1; - pcrange->lowpc_is_addr_index = 1; - } - break; - - case DW_AT_high_pc: - if (val->encoding == ATTR_VAL_ADDRESS) - { - pcrange->highpc = val->u.uint; - pcrange->have_highpc = 1; - } - else if (val->encoding == ATTR_VAL_UINT) - { - pcrange->highpc = val->u.uint; - pcrange->have_highpc = 1; - pcrange->highpc_is_relative = 1; - } - else if (val->encoding == ATTR_VAL_ADDRESS_INDEX) - { - pcrange->highpc = val->u.uint; - pcrange->have_highpc = 1; - pcrange->highpc_is_addr_index = 1; - } - break; - - case DW_AT_ranges: - if (val->encoding == ATTR_VAL_UINT - || val->encoding == ATTR_VAL_REF_SECTION) - { - pcrange->ranges = val->u.uint; - pcrange->have_ranges = 1; - } - else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX) - { - pcrange->ranges = val->u.uint; - pcrange->have_ranges = 1; - pcrange->ranges_is_index = 1; - } - break; - - default: - break; - } -} - -/* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on - error. */ - -static int -add_low_high_range (struct backtrace_state *state, - const struct dwarf_sections *dwarf_sections, - uintptr_t base_address, int is_bigendian, - struct unit *u, const struct pcrange *pcrange, - int (*add_range) (struct backtrace_state *state, - void *rdata, uint64_t lowpc, - uint64_t highpc, - backtrace_error_callback error_callback, - void *data, void *vec), - void *rdata, - backtrace_error_callback error_callback, void *data, - void *vec) -{ - uint64_t lowpc; - uint64_t highpc; - - lowpc = pcrange->lowpc; - if (pcrange->lowpc_is_addr_index) - { - if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize, - is_bigendian, lowpc, error_callback, data, - &lowpc)) - return 0; - } - - highpc = pcrange->highpc; - if (pcrange->highpc_is_addr_index) - { - if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize, - is_bigendian, highpc, error_callback, data, - &highpc)) - return 0; - } - if (pcrange->highpc_is_relative) - highpc += lowpc; - - /* Add in the base address of the module when recording PC values, - so that we can look up the PC directly. */ - lowpc += base_address; - highpc += base_address; - - return add_range (state, rdata, lowpc, highpc, error_callback, data, vec); -} - -/* Call ADD_RANGE for each range read from .debug_ranges, as used in - DWARF versions 2 through 4. */ - -static int -add_ranges_from_ranges ( - struct backtrace_state *state, - const struct dwarf_sections *dwarf_sections, - uintptr_t base_address, int is_bigendian, - struct unit *u, uint64_t base, - const struct pcrange *pcrange, - int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, void *data, - void *vec), - void *rdata, - backtrace_error_callback error_callback, void *data, - void *vec) -{ - struct dwarf_buf ranges_buf; - - if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES]) - { - error_callback (data, "ranges offset out of range", 0); - return 0; - } - - ranges_buf.name = ".debug_ranges"; - ranges_buf.start = dwarf_sections->data[DEBUG_RANGES]; - ranges_buf.buf = dwarf_sections->data[DEBUG_RANGES] + pcrange->ranges; - ranges_buf.left = dwarf_sections->size[DEBUG_RANGES] - pcrange->ranges; - ranges_buf.is_bigendian = is_bigendian; - ranges_buf.error_callback = error_callback; - ranges_buf.data = data; - ranges_buf.reported_underflow = 0; - - while (1) - { - uint64_t low; - uint64_t high; - - if (ranges_buf.reported_underflow) - return 0; - - low = read_address (&ranges_buf, u->addrsize); - high = read_address (&ranges_buf, u->addrsize); - - if (low == 0 && high == 0) - break; - - if (is_highest_address (low, u->addrsize)) - base = high; - else - { - if (!add_range (state, rdata, - low + base + base_address, - high + base + base_address, - error_callback, data, vec)) - return 0; - } - } - - if (ranges_buf.reported_underflow) - return 0; - - return 1; -} - -/* Call ADD_RANGE for each range read from .debug_rnglists, as used in - DWARF version 5. */ - -static int -add_ranges_from_rnglists ( - struct backtrace_state *state, - const struct dwarf_sections *dwarf_sections, - uintptr_t base_address, int is_bigendian, - struct unit *u, uint64_t base, - const struct pcrange *pcrange, - int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, void *data, - void *vec), - void *rdata, - backtrace_error_callback error_callback, void *data, - void *vec) -{ - uint64_t offset; - struct dwarf_buf rnglists_buf; - - if (!pcrange->ranges_is_index) - offset = pcrange->ranges; - else - offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4); - if (offset >= dwarf_sections->size[DEBUG_RNGLISTS]) - { - error_callback (data, "rnglists offset out of range", 0); - return 0; - } - - rnglists_buf.name = ".debug_rnglists"; - rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS]; - rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset; - rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset; - rnglists_buf.is_bigendian = is_bigendian; - rnglists_buf.error_callback = error_callback; - rnglists_buf.data = data; - rnglists_buf.reported_underflow = 0; - - if (pcrange->ranges_is_index) - { - offset = read_offset (&rnglists_buf, u->is_dwarf64); - offset += u->rnglists_base; - if (offset >= dwarf_sections->size[DEBUG_RNGLISTS]) - { - error_callback (data, "rnglists index offset out of range", 0); - return 0; - } - rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset; - rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset; - } - - while (1) - { - unsigned char rle; - - rle = read_byte (&rnglists_buf); - if (rle == DW_RLE_end_of_list) - break; - switch (rle) - { - case DW_RLE_base_addressx: - { - uint64_t index; - - index = read_uleb128 (&rnglists_buf); - if (!resolve_addr_index (dwarf_sections, u->addr_base, - u->addrsize, is_bigendian, index, - error_callback, data, &base)) - return 0; - } - break; - - case DW_RLE_startx_endx: - { - uint64_t index; - uint64_t low; - uint64_t high; - - index = read_uleb128 (&rnglists_buf); - if (!resolve_addr_index (dwarf_sections, u->addr_base, - u->addrsize, is_bigendian, index, - error_callback, data, &low)) - return 0; - index = read_uleb128 (&rnglists_buf); - if (!resolve_addr_index (dwarf_sections, u->addr_base, - u->addrsize, is_bigendian, index, - error_callback, data, &high)) - return 0; - if (!add_range (state, rdata, low + base_address, - high + base_address, error_callback, data, - vec)) - return 0; - } - break; - - case DW_RLE_startx_length: - { - uint64_t index; - uint64_t low; - uint64_t length; - - index = read_uleb128 (&rnglists_buf); - if (!resolve_addr_index (dwarf_sections, u->addr_base, - u->addrsize, is_bigendian, index, - error_callback, data, &low)) - return 0; - length = read_uleb128 (&rnglists_buf); - low += base_address; - if (!add_range (state, rdata, low, low + length, - error_callback, data, vec)) - return 0; - } - break; - - case DW_RLE_offset_pair: - { - uint64_t low; - uint64_t high; - - low = read_uleb128 (&rnglists_buf); - high = read_uleb128 (&rnglists_buf); - if (!add_range (state, rdata, low + base + base_address, - high + base + base_address, - error_callback, data, vec)) - return 0; - } - break; - - case DW_RLE_base_address: - base = read_address (&rnglists_buf, u->addrsize); - break; - - case DW_RLE_start_end: - { - uint64_t low; - uint64_t high; - - low = read_address (&rnglists_buf, u->addrsize); - high = read_address (&rnglists_buf, u->addrsize); - if (!add_range (state, rdata, low + base_address, - high + base_address, error_callback, data, - vec)) - return 0; - } - break; - - case DW_RLE_start_length: - { - uint64_t low; - uint64_t length; - - low = read_address (&rnglists_buf, u->addrsize); - length = read_uleb128 (&rnglists_buf); - low += base_address; - if (!add_range (state, rdata, low, low + length, - error_callback, data, vec)) - return 0; - } - break; - - default: - dwarf_buf_error (&rnglists_buf, "unrecognized DW_RLE value"); - return 0; - } - } - - if (rnglists_buf.reported_underflow) - return 0; - - return 1; -} - -/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is - passed to ADD_RANGE, and is either a struct unit * or a struct - function *. VEC is the vector we are adding ranges to, and is - either a struct unit_addrs_vector * or a struct function_vector *. - Returns 1 on success, 0 on error. */ - -static int -add_ranges (struct backtrace_state *state, - const struct dwarf_sections *dwarf_sections, - uintptr_t base_address, int is_bigendian, - struct unit *u, uint64_t base, const struct pcrange *pcrange, - int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, - void *data, void *vec), - void *rdata, - backtrace_error_callback error_callback, void *data, - void *vec) -{ - if (pcrange->have_lowpc && pcrange->have_highpc) - return add_low_high_range (state, dwarf_sections, base_address, - is_bigendian, u, pcrange, add_range, rdata, - error_callback, data, vec); - - if (!pcrange->have_ranges) - { - /* Did not find any address ranges to add. */ - return 1; - } - - if (u->version < 5) - return add_ranges_from_ranges (state, dwarf_sections, base_address, - is_bigendian, u, base, pcrange, add_range, - rdata, error_callback, data, vec); - else - return add_ranges_from_rnglists (state, dwarf_sections, base_address, - is_bigendian, u, base, pcrange, add_range, - rdata, error_callback, data, vec); -} - -/* Find the address range covered by a compilation unit, reading from - UNIT_BUF and adding values to U. Returns 1 if all data could be - read, 0 if there is some error. */ - -static int -find_address_ranges (struct backtrace_state *state, uintptr_t base_address, - struct dwarf_buf *unit_buf, - const struct dwarf_sections *dwarf_sections, - int is_bigendian, struct dwarf_data *altlink, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct unit_addrs_vector *addrs, - enum dwarf_tag *unit_tag) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - struct pcrange pcrange; - struct attr_val name_val; - int have_name_val; - struct attr_val comp_dir_val; - int have_comp_dir_val; - size_t i; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - if (unit_tag != NULL) - *unit_tag = abbrev->tag; - - memset (&pcrange, 0, sizeof pcrange); - memset (&name_val, 0, sizeof name_val); - have_name_val = 0; - memset (&comp_dir_val, 0, sizeof comp_dir_val); - have_comp_dir_val = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, - unit_buf, u->is_dwarf64, u->version, - u->addrsize, dwarf_sections, altlink, &val)) - return 0; - - switch (abbrev->attrs[i].name) - { - case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges: - update_pcrange (&abbrev->attrs[i], &val, &pcrange); - break; - - case DW_AT_stmt_list: - if (abbrev->tag == DW_TAG_compile_unit - && (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION)) - u->lineoff = val.u.uint; - break; - - case DW_AT_name: - if (abbrev->tag == DW_TAG_compile_unit) - { - name_val = val; - have_name_val = 1; - } - break; - - case DW_AT_comp_dir: - if (abbrev->tag == DW_TAG_compile_unit) - { - comp_dir_val = val; - have_comp_dir_val = 1; - } - break; - - case DW_AT_str_offsets_base: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_REF_SECTION) - u->str_offsets_base = val.u.uint; - break; - - case DW_AT_addr_base: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_REF_SECTION) - u->addr_base = val.u.uint; - break; - - case DW_AT_rnglists_base: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_REF_SECTION) - u->rnglists_base = val.u.uint; - break; - - default: - break; - } - } - - // Resolve strings after we're sure that we have seen - // DW_AT_str_offsets_base. - if (have_name_val) - { - if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian, - u->str_offsets_base, &name_val, - error_callback, data, &u->filename)) - return 0; - } - if (have_comp_dir_val) - { - if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian, - u->str_offsets_base, &comp_dir_val, - error_callback, data, &u->comp_dir)) - return 0; - } - - if (abbrev->tag == DW_TAG_compile_unit - || abbrev->tag == DW_TAG_subprogram) - { - if (!add_ranges (state, dwarf_sections, base_address, - is_bigendian, u, pcrange.lowpc, &pcrange, - add_unit_addr, (void *) u, error_callback, data, - (void *) addrs)) - return 0; - - /* If we found the PC range in the DW_TAG_compile_unit, we - can stop now. */ - if (abbrev->tag == DW_TAG_compile_unit - && (pcrange.have_ranges - || (pcrange.have_lowpc && pcrange.have_highpc))) - return 1; - } - - if (abbrev->has_children) - { - if (!find_address_ranges (state, base_address, unit_buf, - dwarf_sections, is_bigendian, altlink, - error_callback, data, u, addrs, NULL)) - return 0; - } - } - - return 1; -} - -/* Build a mapping from address ranges to the compilation units where - the line number information for that range can be found. Returns 1 - on success, 0 on failure. */ - -static int -build_address_map (struct backtrace_state *state, uintptr_t base_address, - const struct dwarf_sections *dwarf_sections, - int is_bigendian, struct dwarf_data *altlink, - backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *addrs, - struct unit_vector *unit_vec) -{ - struct dwarf_buf info; - struct backtrace_vector units; - size_t units_count; - size_t i; - struct unit **pu; - size_t unit_offset = 0; - - memset (&addrs->vec, 0, sizeof addrs->vec); - memset (&unit_vec->vec, 0, sizeof unit_vec->vec); - addrs->count = 0; - unit_vec->count = 0; - - /* Read through the .debug_info section. FIXME: Should we use the - .debug_aranges section? gdb and addr2line don't use it, but I'm - not sure why. */ - - info.name = ".debug_info"; - info.start = dwarf_sections->data[DEBUG_INFO]; - info.buf = info.start; - info.left = dwarf_sections->size[DEBUG_INFO]; - info.is_bigendian = is_bigendian; - info.error_callback = error_callback; - info.data = data; - info.reported_underflow = 0; - - memset (&units, 0, sizeof units); - units_count = 0; - - while (info.left > 0) - { - const unsigned char *unit_data_start; - uint64_t len; - int is_dwarf64; - struct dwarf_buf unit_buf; - int version; - int unit_type; - uint64_t abbrev_offset; - int addrsize; - struct unit *u; - enum dwarf_tag unit_tag; - - if (info.reported_underflow) - goto fail; - - unit_data_start = info.buf; - - len = read_initial_length (&info, &is_dwarf64); - unit_buf = info; - unit_buf.left = len; - - if (!advance (&info, len)) - goto fail; - - version = read_uint16 (&unit_buf); - if (version < 2 || version > 5) - { - dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); - goto fail; - } - - if (version < 5) - unit_type = 0; - else - { - unit_type = read_byte (&unit_buf); - if (unit_type == DW_UT_type || unit_type == DW_UT_split_type) - { - /* This unit doesn't have anything we need. */ - continue; - } - } - - pu = ((struct unit **) - backtrace_vector_grow (state, sizeof (struct unit *), - error_callback, data, &units)); - if (pu == NULL) - goto fail; - - u = ((struct unit *) - backtrace_alloc (state, sizeof *u, error_callback, data)); - if (u == NULL) - goto fail; - - *pu = u; - ++units_count; - - if (version < 5) - addrsize = 0; /* Set below. */ - else - addrsize = read_byte (&unit_buf); - - memset (&u->abbrevs, 0, sizeof u->abbrevs); - abbrev_offset = read_offset (&unit_buf, is_dwarf64); - if (!read_abbrevs (state, abbrev_offset, - dwarf_sections->data[DEBUG_ABBREV], - dwarf_sections->size[DEBUG_ABBREV], - is_bigendian, error_callback, data, &u->abbrevs)) - goto fail; - - if (version < 5) - addrsize = read_byte (&unit_buf); - - switch (unit_type) - { - case 0: - break; - case DW_UT_compile: case DW_UT_partial: - break; - case DW_UT_skeleton: case DW_UT_split_compile: - read_uint64 (&unit_buf); /* dwo_id */ - break; - default: - break; - } - - u->low_offset = unit_offset; - unit_offset += len + (is_dwarf64 ? 12 : 4); - u->high_offset = unit_offset; - u->unit_data = unit_buf.buf; - u->unit_data_len = unit_buf.left; - u->unit_data_offset = unit_buf.buf - unit_data_start; - u->version = version; - u->is_dwarf64 = is_dwarf64; - u->addrsize = addrsize; - u->filename = NULL; - u->comp_dir = NULL; - u->abs_filename = NULL; - u->lineoff = 0; - - /* The actual line number mappings will be read as needed. */ - u->lines = NULL; - u->lines_count = 0; - u->function_addrs = NULL; - u->function_addrs_count = 0; - - if (!find_address_ranges (state, base_address, &unit_buf, dwarf_sections, - is_bigendian, altlink, error_callback, data, - u, addrs, &unit_tag)) - goto fail; - - if (unit_buf.reported_underflow) - goto fail; - } - if (info.reported_underflow) - goto fail; - - unit_vec->vec = units; - unit_vec->count = units_count; - return 1; - - fail: - if (units_count > 0) - { - pu = (struct unit **) units.base; - for (i = 0; i < units_count; i++) - { - free_abbrevs (state, &pu[i]->abbrevs, error_callback, data); - backtrace_free (state, pu[i], sizeof **pu, error_callback, data); - } - backtrace_vector_free (state, &units, error_callback, data); - } - if (addrs->count > 0) - { - backtrace_vector_free (state, &addrs->vec, error_callback, data); - addrs->count = 0; - } - return 0; -} - -/* Add a new mapping to the vector of line mappings that we are - building. Returns 1 on success, 0 on failure. */ - -static int -add_line (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, const char *filename, int lineno, - backtrace_error_callback error_callback, void *data, - struct line_vector *vec) -{ - struct line *ln; - - /* If we are adding the same mapping, ignore it. This can happen - when using discriminators. */ - if (vec->count > 0) - { - ln = (struct line *) vec->vec.base + (vec->count - 1); - if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno) - return 1; - } - - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec->vec)); - if (ln == NULL) - return 0; - - /* Add in the base address here, so that we can look up the PC - directly. */ - ln->pc = pc + ddata->base_address; - - ln->filename = filename; - ln->lineno = lineno; - ln->idx = vec->count; - - ++vec->count; - - return 1; -} - -/* Free the line header information. */ - -static void -free_line_header (struct backtrace_state *state, struct line_header *hdr, - backtrace_error_callback error_callback, void *data) -{ - if (hdr->dirs_count != 0) - backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), - error_callback, data); - backtrace_free (state, hdr->filenames, - hdr->filenames_count * sizeof (char *), - error_callback, data); -} - -/* Read the directories and file names for a line header for version - 2, setting fields in HDR. Return 1 on success, 0 on failure. */ - -static int -read_v2_paths (struct backtrace_state *state, struct unit *u, - struct dwarf_buf *hdr_buf, struct line_header *hdr) -{ - const unsigned char *p; - const unsigned char *pend; - size_t i; - - /* Count the number of directory entries. */ - hdr->dirs_count = 0; - p = hdr_buf->buf; - pend = p + hdr_buf->left; - while (p < pend && *p != '\0') - { - p += strnlen((const char *) p, pend - p) + 1; - ++hdr->dirs_count; - } - - hdr->dirs = NULL; - if (hdr->dirs_count != 0) - { - hdr->dirs = ((const char **) - backtrace_alloc (state, - hdr->dirs_count * sizeof (const char *), - hdr_buf->error_callback, - hdr_buf->data)); - if (hdr->dirs == NULL) - return 0; - } - - i = 0; - while (*hdr_buf->buf != '\0') - { - if (hdr_buf->reported_underflow) - return 0; - - hdr->dirs[i] = read_string (hdr_buf); - if (hdr->dirs[i] == NULL) - return 0; - ++i; - } - if (!advance (hdr_buf, 1)) - return 0; - - /* Count the number of file entries. */ - hdr->filenames_count = 0; - p = hdr_buf->buf; - pend = p + hdr_buf->left; - while (p < pend && *p != '\0') - { - p += strnlen ((const char *) p, pend - p) + 1; - p += leb128_len (p); - p += leb128_len (p); - p += leb128_len (p); - ++hdr->filenames_count; - } - - hdr->filenames = ((const char **) - backtrace_alloc (state, - hdr->filenames_count * sizeof (char *), - hdr_buf->error_callback, - hdr_buf->data)); - if (hdr->filenames == NULL) - return 0; - i = 0; - while (*hdr_buf->buf != '\0') - { - const char *filename; - uint64_t dir_index; - - if (hdr_buf->reported_underflow) - return 0; - - filename = read_string (hdr_buf); - if (filename == NULL) - return 0; - dir_index = read_uleb128 (hdr_buf); - if (IS_ABSOLUTE_PATH (filename) - || (dir_index == 0 && u->comp_dir == NULL)) - hdr->filenames[i] = filename; - else - { - const char *dir; - size_t dir_len; - size_t filename_len; - char *s; - - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (hdr_buf, - ("invalid directory index in " - "line number program header")); - return 0; - } - dir_len = strlen (dir); - filename_len = strlen (filename); - s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2, - hdr_buf->error_callback, - hdr_buf->data)); - if (s == NULL) - return 0; - memcpy (s, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, and the - directory or the file name use backslashes, then we - should use a backslash here. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - hdr->filenames[i] = s; - } - - /* Ignore the modification time and size. */ - read_uleb128 (hdr_buf); - read_uleb128 (hdr_buf); - - ++i; - } - - return 1; -} - -/* Read a single version 5 LNCT entry for a directory or file name in a - line header. Sets *STRING to the resulting name, ignoring other - data. Return 1 on success, 0 on failure. */ - -static int -read_lnct (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, struct dwarf_buf *hdr_buf, - const struct line_header *hdr, size_t formats_count, - const struct line_header_format *formats, const char **string) -{ - size_t i; - const char *dir; - const char *path; - - dir = NULL; - path = NULL; - for (i = 0; i < formats_count; i++) - { - struct attr_val val; - - if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64, - u->version, hdr->addrsize, &ddata->dwarf_sections, - ddata->altlink, &val)) - return 0; - switch (formats[i].lnct) - { - case DW_LNCT_path: - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, u->str_offsets_base, - &val, hdr_buf->error_callback, hdr_buf->data, - &path)) - return 0; - break; - case DW_LNCT_directory_index: - if (val.encoding == ATTR_VAL_UINT) - { - if (val.u.uint >= hdr->dirs_count) - { - dwarf_buf_error (hdr_buf, - ("invalid directory index in " - "line number program header")); - return 0; - } - dir = hdr->dirs[val.u.uint]; - } - break; - default: - /* We don't care about timestamps or sizes or hashes. */ - break; - } - } - - if (path == NULL) - { - dwarf_buf_error (hdr_buf, - "missing file name in line number program header"); - return 0; - } - - if (dir == NULL) - *string = path; - else - { - size_t dir_len; - size_t path_len; - char *s; - - dir_len = strlen (dir); - path_len = strlen (path); - s = (char *) backtrace_alloc (state, dir_len + path_len + 2, - hdr_buf->error_callback, hdr_buf->data); - if (s == NULL) - return 0; - memcpy (s, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, and the - directory or the path name use backslashes, then we should - use a backslash here. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, path, path_len + 1); - *string = s; - } - - return 1; -} - -/* Read a set of DWARF 5 line header format entries, setting *PCOUNT - and *PPATHS. Return 1 on success, 0 on failure. */ - -static int -read_line_header_format_entries (struct backtrace_state *state, - struct dwarf_data *ddata, - struct unit *u, - struct dwarf_buf *hdr_buf, - struct line_header *hdr, - size_t *pcount, - const char ***ppaths) -{ - size_t formats_count; - struct line_header_format *formats; - size_t paths_count; - const char **paths; - size_t i; - int ret; - - formats_count = read_byte (hdr_buf); - if (formats_count == 0) - formats = NULL; - else - { - formats = ((struct line_header_format *) - backtrace_alloc (state, - (formats_count - * sizeof (struct line_header_format)), - hdr_buf->error_callback, - hdr_buf->data)); - if (formats == NULL) - return 0; - - for (i = 0; i < formats_count; i++) - { - formats[i].lnct = (int) read_uleb128(hdr_buf); - formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf); - } - } - - paths_count = read_uleb128 (hdr_buf); - if (paths_count == 0) - { - *pcount = 0; - *ppaths = NULL; - ret = 1; - goto exit; - } - - paths = ((const char **) - backtrace_alloc (state, paths_count * sizeof (const char *), - hdr_buf->error_callback, hdr_buf->data)); - if (paths == NULL) - { - ret = 0; - goto exit; - } - for (i = 0; i < paths_count; i++) - { - if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count, - formats, &paths[i])) - { - backtrace_free (state, paths, - paths_count * sizeof (const char *), - hdr_buf->error_callback, hdr_buf->data); - ret = 0; - goto exit; - } - } - - *pcount = paths_count; - *ppaths = paths; - - ret = 1; - - exit: - if (formats != NULL) - backtrace_free (state, formats, - formats_count * sizeof (struct line_header_format), - hdr_buf->error_callback, hdr_buf->data); - - return ret; -} - -/* Read the line header. Return 1 on success, 0 on failure. */ - -static int -read_line_header (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf, - struct line_header *hdr) -{ - uint64_t hdrlen; - struct dwarf_buf hdr_buf; - - hdr->version = read_uint16 (line_buf); - if (hdr->version < 2 || hdr->version > 5) - { - dwarf_buf_error (line_buf, "unsupported line number version"); - return 0; - } - - if (hdr->version < 5) - hdr->addrsize = u->addrsize; - else - { - hdr->addrsize = read_byte (line_buf); - /* We could support a non-zero segment_selector_size but I doubt - we'll ever see it. */ - if (read_byte (line_buf) != 0) - { - dwarf_buf_error (line_buf, - "non-zero segment_selector_size not supported"); - return 0; - } - } - - hdrlen = read_offset (line_buf, is_dwarf64); - - hdr_buf = *line_buf; - hdr_buf.left = hdrlen; - - if (!advance (line_buf, hdrlen)) - return 0; - - hdr->min_insn_len = read_byte (&hdr_buf); - if (hdr->version < 4) - hdr->max_ops_per_insn = 1; - else - hdr->max_ops_per_insn = read_byte (&hdr_buf); - - /* We don't care about default_is_stmt. */ - read_byte (&hdr_buf); - - hdr->line_base = read_sbyte (&hdr_buf); - hdr->line_range = read_byte (&hdr_buf); - - hdr->opcode_base = read_byte (&hdr_buf); - hdr->opcode_lengths = hdr_buf.buf; - if (!advance (&hdr_buf, hdr->opcode_base - 1)) - return 0; - - if (hdr->version < 5) - { - if (!read_v2_paths (state, u, &hdr_buf, hdr)) - return 0; - } - else - { - if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr, - &hdr->dirs_count, - &hdr->dirs)) - return 0; - if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr, - &hdr->filenames_count, - &hdr->filenames)) - return 0; - } - - if (hdr_buf.reported_underflow) - return 0; - - return 1; -} - -/* Read the line program, adding line mappings to VEC. Return 1 on - success, 0 on failure. */ - -static int -read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, const struct line_header *hdr, - struct dwarf_buf *line_buf, struct line_vector *vec) -{ - uint64_t address; - unsigned int op_index; - const char *reset_filename; - const char *filename; - int lineno; - - address = 0; - op_index = 0; - if (hdr->filenames_count > 0) - reset_filename = hdr->filenames[0]; - else - reset_filename = ""; - filename = reset_filename; - lineno = 1; - while (line_buf->left > 0) - { - unsigned int op; - - op = read_byte (line_buf); - if (op >= hdr->opcode_base) - { - unsigned int advance; - - /* Special opcode. */ - op -= hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - lineno += hdr->line_base + (int) (op % hdr->line_range); - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - } - else if (op == DW_LNS_extended_op) - { - uint64_t len; - - len = read_uleb128 (line_buf); - op = read_byte (line_buf); - switch (op) - { - case DW_LNE_end_sequence: - /* FIXME: Should we mark the high PC here? It seems - that we already have that information from the - compilation unit. */ - address = 0; - op_index = 0; - filename = reset_filename; - lineno = 1; - break; - case DW_LNE_set_address: - address = read_address (line_buf, hdr->addrsize); - break; - case DW_LNE_define_file: - { - const char *f; - unsigned int dir_index; - - f = read_string (line_buf); - if (f == NULL) - return 0; - dir_index = read_uleb128 (line_buf); - /* Ignore that time and length. */ - read_uleb128 (line_buf); - read_uleb128 (line_buf); - if (IS_ABSOLUTE_PATH (f)) - filename = f; - else - { - const char *dir; - size_t dir_len; - size_t f_len; - char *p; - - if (dir_index == 0 && hdr->version < 5) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (line_buf, - ("invalid directory index " - "in line number program")); - return 0; - } - dir_len = strlen (dir); - f_len = strlen (f); - p = ((char *) - backtrace_alloc (state, dir_len + f_len + 2, - line_buf->error_callback, - line_buf->data)); - if (p == NULL) - return 0; - memcpy (p, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, - and the directory or the file name use - backslashes, then we should use a backslash - here. */ - p[dir_len] = '/'; - memcpy (p + dir_len + 1, f, f_len + 1); - filename = p; - } - } - break; - case DW_LNE_set_discriminator: - /* We don't care about discriminators. */ - read_uleb128 (line_buf); - break; - default: - if (!advance (line_buf, len - 1)) - return 0; - break; - } - } - else - { - switch (op) - { - case DW_LNS_copy: - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - break; - case DW_LNS_advance_pc: - { - uint64_t advance; - - advance = read_uleb128 (line_buf); - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_advance_line: - lineno += (int) read_sleb128 (line_buf); - break; - case DW_LNS_set_file: - { - uint64_t fileno; - - fileno = read_uleb128 (line_buf); - if (fileno == 0) - filename = ""; - else - { - if (fileno - 1 >= hdr->filenames_count) - { - dwarf_buf_error (line_buf, - ("invalid file number in " - "line number program")); - return 0; - } - filename = hdr->filenames[fileno - 1]; - } - } - break; - case DW_LNS_set_column: - read_uleb128 (line_buf); - break; - case DW_LNS_negate_stmt: - break; - case DW_LNS_set_basic_block: - break; - case DW_LNS_const_add_pc: - { - unsigned int advance; - - op = 255 - hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_fixed_advance_pc: - address += read_uint16 (line_buf); - op_index = 0; - break; - case DW_LNS_set_prologue_end: - break; - case DW_LNS_set_epilogue_begin: - break; - case DW_LNS_set_isa: - read_uleb128 (line_buf); - break; - default: - { - unsigned int i; - - for (i = hdr->opcode_lengths[op - 1]; i > 0; --i) - read_uleb128 (line_buf); - } - break; - } - } - } - - return 1; -} - -/* Read the line number information for a compilation unit. Returns 1 - on success, 0 on failure. */ - -static int -read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct line_header *hdr, struct line **lines, - size_t *lines_count) -{ - struct line_vector vec; - struct dwarf_buf line_buf; - uint64_t len; - int is_dwarf64; - struct line *ln; - - memset (&vec.vec, 0, sizeof vec.vec); - vec.count = 0; - - memset (hdr, 0, sizeof *hdr); - - if (u->lineoff != (off_t) (size_t) u->lineoff - || (size_t) u->lineoff >= ddata->dwarf_sections.size[DEBUG_LINE]) - { - error_callback (data, "unit line offset out of range", 0); - goto fail; - } - - line_buf.name = ".debug_line"; - line_buf.start = ddata->dwarf_sections.data[DEBUG_LINE]; - line_buf.buf = ddata->dwarf_sections.data[DEBUG_LINE] + u->lineoff; - line_buf.left = ddata->dwarf_sections.size[DEBUG_LINE] - u->lineoff; - line_buf.is_bigendian = ddata->is_bigendian; - line_buf.error_callback = error_callback; - line_buf.data = data; - line_buf.reported_underflow = 0; - - len = read_initial_length (&line_buf, &is_dwarf64); - line_buf.left = len; - - if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr)) - goto fail; - - if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) - goto fail; - - if (line_buf.reported_underflow) - goto fail; - - if (vec.count == 0) - { - /* This is not a failure in the sense of a generating an error, - but it is a failure in that sense that we have no useful - information. */ - goto fail; - } - - /* Allocate one extra entry at the end. */ - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec.vec)); - if (ln == NULL) - goto fail; - ln->pc = (uintptr_t) -1; - ln->filename = NULL; - ln->lineno = 0; - ln->idx = 0; - - if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) - goto fail; - - ln = (struct line *) vec.vec.base; - backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); - - *lines = ln; - *lines_count = vec.count; - - return 1; - - fail: - backtrace_vector_free (state, &vec.vec, error_callback, data); - free_line_header (state, hdr, error_callback, data); - *lines = (struct line *) (uintptr_t) -1; - *lines_count = 0; - return 0; -} - -static const char *read_referenced_name (struct dwarf_data *, struct unit *, - uint64_t, backtrace_error_callback, - void *); - -/* Read the name of a function from a DIE referenced by ATTR with VAL. */ - -static const char * -read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u, - struct attr *attr, struct attr_val *val, - backtrace_error_callback error_callback, - void *data) -{ - switch (attr->name) - { - case DW_AT_abstract_origin: - case DW_AT_specification: - break; - default: - return NULL; - } - - if (attr->form == DW_FORM_ref_sig8) - return NULL; - - if (val->encoding == ATTR_VAL_REF_INFO) - { - struct unit *unit - = find_unit (ddata->units, ddata->units_count, - val->u.uint); - if (unit == NULL) - return NULL; - - uint64_t offset = val->u.uint - unit->low_offset; - return read_referenced_name (ddata, unit, offset, error_callback, data); - } - - if (val->encoding == ATTR_VAL_UINT - || val->encoding == ATTR_VAL_REF_UNIT) - return read_referenced_name (ddata, u, val->u.uint, error_callback, data); - - if (val->encoding == ATTR_VAL_REF_ALT_INFO) - { - struct unit *alt_unit - = find_unit (ddata->altlink->units, ddata->altlink->units_count, - val->u.uint); - if (alt_unit == NULL) - return NULL; - - uint64_t offset = val->u.uint - alt_unit->low_offset; - return read_referenced_name (ddata->altlink, alt_unit, offset, - error_callback, data); - } - - return NULL; -} - -/* Read the name of a function from a DIE referenced by a - DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within - the same compilation unit. */ - -static const char * -read_referenced_name (struct dwarf_data *ddata, struct unit *u, - uint64_t offset, backtrace_error_callback error_callback, - void *data) -{ - struct dwarf_buf unit_buf; - uint64_t code; - const struct abbrev *abbrev; - const char *ret; - size_t i; - - /* OFFSET is from the start of the data for this compilation unit. - U->unit_data is the data, but it starts U->unit_data_offset bytes - from the beginning. */ - - if (offset < u->unit_data_offset - || offset - u->unit_data_offset >= u->unit_data_len) - { - error_callback (data, - "abstract origin or specification out of range", - 0); - return NULL; - } - - offset -= u->unit_data_offset; - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO]; - unit_buf.buf = u->unit_data + offset; - unit_buf.left = u->unit_data_len - offset; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - code = read_uleb128 (&unit_buf); - if (code == 0) - { - dwarf_buf_error (&unit_buf, "invalid abstract origin or specification"); - return NULL; - } - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return NULL; - - ret = NULL; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, - &unit_buf, u->is_dwarf64, u->version, u->addrsize, - &ddata->dwarf_sections, ddata->altlink, &val)) - return NULL; - - switch (abbrev->attrs[i].name) - { - case DW_AT_name: - /* Third name preference: don't override. A name we found in some - other way, will normally be more useful -- e.g., this name is - normally not mangled. */ - if (ret != NULL) - break; - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, u->str_offsets_base, - &val, error_callback, data, &ret)) - return NULL; - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - /* First name preference: override all. */ - { - const char *s; - - s = NULL; - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, u->str_offsets_base, - &val, error_callback, data, &s)) - return NULL; - if (s != NULL) - return s; - } - break; - - case DW_AT_specification: - /* Second name preference: override DW_AT_name, don't override - DW_AT_linkage_name. */ - { - const char *name; - - name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i], - &val, error_callback, data); - if (name != NULL) - ret = name; - } - break; - - default: - break; - } - } - - return ret; -} - -/* Add a range to a unit that maps to a function. This is called via - add_ranges. Returns 1 on success, 0 on error. */ - -static int -add_function_range (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, void *data, - void *pvec) -{ - struct function *function = (struct function *) rdata; - struct function_vector *vec = (struct function_vector *) pvec; - struct function_addrs *p; - - if (vec->count > 0) - { - p = (struct function_addrs *) vec->vec.base + (vec->count - 1); - if ((lowpc == p->high || lowpc == p->high + 1) - && function == p->function) - { - if (highpc > p->high) - p->high = highpc; - return 1; - } - } - - p = ((struct function_addrs *) - backtrace_vector_grow (state, sizeof (struct function_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - p->low = lowpc; - p->high = highpc; - p->function = function; - - ++vec->count; - - return 1; -} - -/* Read one entry plus all its children. Add function addresses to - VEC. Returns 1 on success, 0 on error. */ - -static int -read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct function_vector *vec_function, - struct function_vector *vec_inlined) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - int is_function; - struct function *function; - struct function_vector *vec; - size_t i; - struct pcrange pcrange; - int have_linkage_name; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - is_function = (abbrev->tag == DW_TAG_subprogram - || abbrev->tag == DW_TAG_entry_point - || abbrev->tag == DW_TAG_inlined_subroutine); - - if (abbrev->tag == DW_TAG_inlined_subroutine) - vec = vec_inlined; - else - vec = vec_function; - - function = NULL; - if (is_function) - { - function = ((struct function *) - backtrace_alloc (state, sizeof *function, - error_callback, data)); - if (function == NULL) - return 0; - memset (function, 0, sizeof *function); - } - - memset (&pcrange, 0, sizeof pcrange); - have_linkage_name = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, - unit_buf, u->is_dwarf64, u->version, - u->addrsize, &ddata->dwarf_sections, - ddata->altlink, &val)) - return 0; - - /* The compile unit sets the base address for any address - ranges in the function entries. */ - if (abbrev->tag == DW_TAG_compile_unit - && abbrev->attrs[i].name == DW_AT_low_pc) - { - if (val.encoding == ATTR_VAL_ADDRESS) - base = val.u.uint; - else if (val.encoding == ATTR_VAL_ADDRESS_INDEX) - { - if (!resolve_addr_index (&ddata->dwarf_sections, - u->addr_base, u->addrsize, - ddata->is_bigendian, val.u.uint, - error_callback, data, &base)) - return 0; - } - } - - if (is_function) - { - switch (abbrev->attrs[i].name) - { - case DW_AT_call_file: - if (val.encoding == ATTR_VAL_UINT) - { - if (val.u.uint == 0) - function->caller_filename = ""; - else - { - if (val.u.uint - 1 >= lhdr->filenames_count) - { - dwarf_buf_error (unit_buf, - ("invalid file number in " - "DW_AT_call_file attribute")); - return 0; - } - function->caller_filename = - lhdr->filenames[val.u.uint - 1]; - } - } - break; - - case DW_AT_call_line: - if (val.encoding == ATTR_VAL_UINT) - function->caller_lineno = val.u.uint; - break; - - case DW_AT_abstract_origin: - case DW_AT_specification: - /* Second name preference: override DW_AT_name, don't override - DW_AT_linkage_name. */ - if (have_linkage_name) - break; - { - const char *name; - - name - = read_referenced_name_from_attr (ddata, u, - &abbrev->attrs[i], &val, - error_callback, data); - if (name != NULL) - function->name = name; - } - break; - - case DW_AT_name: - /* Third name preference: don't override. */ - if (function->name != NULL) - break; - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, - u->str_offsets_base, &val, - error_callback, data, &function->name)) - return 0; - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - /* First name preference: override all. */ - { - const char *s; - - s = NULL; - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, - u->str_offsets_base, &val, - error_callback, data, &s)) - return 0; - if (s != NULL) - { - function->name = s; - have_linkage_name = 1; - } - } - break; - - case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges: - update_pcrange (&abbrev->attrs[i], &val, &pcrange); - break; - - default: - break; - } - } - } - - /* If we couldn't find a name for the function, we have no use - for it. */ - if (is_function && function->name == NULL) - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - - if (is_function) - { - if (pcrange.have_ranges - || (pcrange.have_lowpc && pcrange.have_highpc)) - { - if (!add_ranges (state, &ddata->dwarf_sections, - ddata->base_address, ddata->is_bigendian, - u, base, &pcrange, add_function_range, - (void *) function, error_callback, data, - (void *) vec)) - return 0; - } - else - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - } - - if (abbrev->has_children) - { - if (!is_function) - { - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - vec_inlined)) - return 0; - } - else - { - struct function_vector fvec; - - /* Gather any information for inlined functions in - FVEC. */ - - memset (&fvec, 0, sizeof fvec); - - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - &fvec)) - return 0; - - if (fvec.count > 0) - { - struct function_addrs *faddrs; - - if (!backtrace_vector_release (state, &fvec.vec, - error_callback, data)) - return 0; - - faddrs = (struct function_addrs *) fvec.vec.base; - backtrace_qsort (faddrs, fvec.count, - sizeof (struct function_addrs), - function_addrs_compare); - - function->function_addrs = faddrs; - function->function_addrs_count = fvec.count; - } - } - } - } - - return 1; -} - -/* Read function name information for a compilation unit. We look - through the whole unit looking for function tags. */ - -static void -read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct function_vector *fvec, - struct function_addrs **ret_addrs, - size_t *ret_addrs_count) -{ - struct function_vector lvec; - struct function_vector *pfvec; - struct dwarf_buf unit_buf; - struct function_addrs *addrs; - size_t addrs_count; - - /* Use FVEC if it is not NULL. Otherwise use our own vector. */ - if (fvec != NULL) - pfvec = fvec; - else - { - memset (&lvec, 0, sizeof lvec); - pfvec = &lvec; - } - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO]; - unit_buf.buf = u->unit_data; - unit_buf.left = u->unit_data_len; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - while (unit_buf.left > 0) - { - if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, - error_callback, data, pfvec, pfvec)) - return; - } - - if (pfvec->count == 0) - return; - - addrs_count = pfvec->count; - - if (fvec == NULL) - { - if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) - return; - addrs = (struct function_addrs *) pfvec->vec.base; - } - else - { - /* Finish this list of addresses, but leave the remaining space in - the vector available for the next function unit. */ - addrs = ((struct function_addrs *) - backtrace_vector_finish (state, &fvec->vec, - error_callback, data)); - if (addrs == NULL) - return; - fvec->count = 0; - } - - backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), - function_addrs_compare); - - *ret_addrs = addrs; - *ret_addrs_count = addrs_count; -} - -/* See if PC is inlined in FUNCTION. If it is, print out the inlined - information, and update FILENAME and LINENO for the caller. - Returns whatever CALLBACK returns, or 0 to keep going. */ - -static int -report_inlined_functions (uintptr_t pc, struct function *function, - backtrace_full_callback callback, void *data, - const char **filename, int *lineno) -{ - struct function_addrs *function_addrs; - struct function *inlined; - int ret; - - if (function->function_addrs_count == 0) - return 0; - - function_addrs = ((struct function_addrs *) - bsearch (&pc, function->function_addrs, - function->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return 0; - - while (((size_t) (function_addrs - function->function_addrs) + 1 - < function->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - /* We found an inlined call. */ - - inlined = function_addrs->function; - - /* Report any calls inlined into this one. */ - ret = report_inlined_functions (pc, inlined, callback, data, - filename, lineno); - if (ret != 0) - return ret; - - /* Report this inlined call. */ - ret = callback (data, pc, *filename, *lineno, inlined->name); - if (ret != 0) - return ret; - - /* Our caller will report the caller of the inlined function; tell - it the appropriate filename and line number. */ - *filename = inlined->caller_filename; - *lineno = inlined->caller_lineno; - - return 0; -} - -/* Look for a PC in the DWARF mapping for one module. On success, - call CALLBACK and return whatever it returns. On error, call - ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, - 0 if not. */ - -static int -dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data, - int *found) -{ - struct unit_addrs *entry; - struct unit *u; - int new_data; - struct line *lines; - struct line *ln; - struct function_addrs *function_addrs; - struct function *function; - const char *filename; - int lineno; - int ret; - - *found = 1; - - /* Find an address range that includes PC. */ - entry = (ddata->addrs_count == 0 - ? NULL - : bsearch (&pc, ddata->addrs, ddata->addrs_count, - sizeof (struct unit_addrs), unit_addrs_search)); - - if (entry == NULL) - { - *found = 0; - return 0; - } - - /* If there are multiple ranges that contain PC, use the last one, - in order to produce predictable results. If we assume that all - ranges are properly nested, then the last range will be the - smallest one. */ - while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count - && pc >= (entry + 1)->low - && pc < (entry + 1)->high) - ++entry; - - /* We need the lines, lines_count, function_addrs, - function_addrs_count fields of u. If they are not set, we need - to set them. When running in threaded mode, we need to allow for - the possibility that some other thread is setting them - simultaneously. */ - - u = entry->u; - lines = u->lines; - - /* Skip units with no useful line number information by walking - backward. Useless line number information is marked by setting - lines == -1. */ - while (entry > ddata->addrs - && pc >= (entry - 1)->low - && pc < (entry - 1)->high) - { - if (state->threaded) - lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); - - if (lines != (struct line *) (uintptr_t) -1) - break; - - --entry; - - u = entry->u; - lines = u->lines; - } - - if (state->threaded) - lines = backtrace_atomic_load_pointer (&u->lines); - - new_data = 0; - if (lines == NULL) - { - size_t function_addrs_count; - struct line_header lhdr; - size_t count; - - /* We have never read the line information for this unit. Read - it now. */ - - function_addrs = NULL; - function_addrs_count = 0; - if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr, - &lines, &count)) - { - struct function_vector *pfvec; - - /* If not threaded, reuse DDATA->FVEC for better memory - consumption. */ - if (state->threaded) - pfvec = NULL; - else - pfvec = &ddata->fvec; - read_function_info (state, ddata, &lhdr, error_callback, data, - entry->u, pfvec, &function_addrs, - &function_addrs_count); - free_line_header (state, &lhdr, error_callback, data); - new_data = 1; - } - - /* Atomically store the information we just read into the unit. - If another thread is simultaneously writing, it presumably - read the same information, and we don't care which one we - wind up with; we just leak the other one. We do have to - write the lines field last, so that the acquire-loads above - ensure that the other fields are set. */ - - if (!state->threaded) - { - u->lines_count = count; - u->function_addrs = function_addrs; - u->function_addrs_count = function_addrs_count; - u->lines = lines; - } - else - { - backtrace_atomic_store_size_t (&u->lines_count, count); - backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); - backtrace_atomic_store_size_t (&u->function_addrs_count, - function_addrs_count); - backtrace_atomic_store_pointer (&u->lines, lines); - } - } - - /* Now all fields of U have been initialized. */ - - if (lines == (struct line *) (uintptr_t) -1) - { - /* If reading the line number information failed in some way, - try again to see if there is a better compilation unit for - this PC. */ - if (new_data) - return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, found); - return callback (data, pc, NULL, 0, NULL); - } - - /* Search for PC within this unit. */ - - ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count, - sizeof (struct line), line_search); - if (ln == NULL) - { - /* The PC is between the low_pc and high_pc attributes of the - compilation unit, but no entry in the line table covers it. - This implies that the start of the compilation unit has no - line number information. */ - - if (entry->u->abs_filename == NULL) - { - const char *filename; - - filename = entry->u->filename; - if (filename != NULL - && !IS_ABSOLUTE_PATH (filename) - && entry->u->comp_dir != NULL) - { - size_t filename_len; - const char *dir; - size_t dir_len; - char *s; - - filename_len = strlen (filename); - dir = entry->u->comp_dir; - dir_len = strlen (dir); - s = (char *) backtrace_alloc (state, dir_len + filename_len + 2, - error_callback, data); - if (s == NULL) - { - *found = 0; - return 0; - } - memcpy (s, dir, dir_len); - /* FIXME: Should use backslash if DOS file system. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - filename = s; - } - entry->u->abs_filename = filename; - } - - return callback (data, pc, entry->u->abs_filename, 0, NULL); - } - - /* Search for function name within this unit. */ - - if (entry->u->function_addrs_count == 0) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - function_addrs = ((struct function_addrs *) - bsearch (&pc, entry->u->function_addrs, - entry->u->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - /* If there are multiple function ranges that contain PC, use the - last one, in order to produce predictable results. */ - - while (((size_t) (function_addrs - entry->u->function_addrs + 1) - < entry->u->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - function = function_addrs->function; - - filename = ln->filename; - lineno = ln->lineno; - - ret = report_inlined_functions (pc, function, callback, data, - &filename, &lineno); - if (ret != 0) - return ret; - - return callback (data, pc, filename, lineno, function->name); -} - - -/* Return the file/line information for a PC using the DWARF mapping - we built earlier. */ - -static int -dwarf_fileline (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct dwarf_data *ddata; - int found; - int ret; - - if (!state->threaded) - { - for (ddata = (struct dwarf_data *) state->fileline_data; - ddata != NULL; - ddata = ddata->next) - { - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - } - } - else - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - while (1) - { - ddata = backtrace_atomic_load_pointer (pp); - if (ddata == NULL) - break; - - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - - pp = &ddata->next; - } - } - - /* FIXME: See if any libraries have been dlopen'ed. */ - - return callback (data, pc, NULL, 0, NULL); -} - -/* Initialize our data structures from the DWARF debug info for a - file. Return NULL on failure. */ - -static struct dwarf_data * -build_dwarf_data (struct backtrace_state *state, - uintptr_t base_address, - const struct dwarf_sections *dwarf_sections, - int is_bigendian, - struct dwarf_data *altlink, - backtrace_error_callback error_callback, - void *data) -{ - struct unit_addrs_vector addrs_vec; - struct unit_addrs *addrs; - size_t addrs_count; - struct unit_vector units_vec; - struct unit **units; - size_t units_count; - struct dwarf_data *fdata; - - if (!build_address_map (state, base_address, dwarf_sections, is_bigendian, - altlink, error_callback, data, &addrs_vec, - &units_vec)) - return NULL; - - if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) - return NULL; - if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data)) - return NULL; - addrs = (struct unit_addrs *) addrs_vec.vec.base; - units = (struct unit **) units_vec.vec.base; - addrs_count = addrs_vec.count; - units_count = units_vec.count; - backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), - unit_addrs_compare); - /* No qsort for units required, already sorted. */ - - fdata = ((struct dwarf_data *) - backtrace_alloc (state, sizeof (struct dwarf_data), - error_callback, data)); - if (fdata == NULL) - return NULL; - - fdata->next = NULL; - fdata->altlink = altlink; - fdata->base_address = base_address; - fdata->addrs = addrs; - fdata->addrs_count = addrs_count; - fdata->units = units; - fdata->units_count = units_count; - fdata->dwarf_sections = *dwarf_sections; - fdata->is_bigendian = is_bigendian; - memset (&fdata->fvec, 0, sizeof fdata->fvec); - - return fdata; -} - -/* Build our data structures from the DWARF sections for a module. - Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0 - on failure. */ - -int -backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const struct dwarf_sections *dwarf_sections, - int is_bigendian, - struct dwarf_data *fileline_altlink, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, - struct dwarf_data **fileline_entry) -{ - struct dwarf_data *fdata; - - fdata = build_dwarf_data (state, base_address, dwarf_sections, is_bigendian, - fileline_altlink, error_callback, data); - if (fdata == NULL) - return 0; - - if (fileline_entry != NULL) - *fileline_entry = fdata; - - if (!state->threaded) - { - struct dwarf_data **pp; - - for (pp = (struct dwarf_data **) (void *) &state->fileline_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = fdata; - } - else - { - while (1) - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - - while (1) - { - struct dwarf_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, fdata)) - break; - } - } - - *fileline_fn = dwarf_fileline; - - return 1; -} diff --git a/3rdparty/libbacktrace/libbacktrace/elf.c b/3rdparty/libbacktrace/libbacktrace/elf.c deleted file mode 100644 index d1d257b1..00000000 --- a/3rdparty/libbacktrace/libbacktrace/elf.c +++ /dev/null @@ -1,3435 +0,0 @@ -/* elf.c -- Get debug data from an ELF file for backtraces. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DL_ITERATE_PHDR -#include -#endif - -#include "backtrace.h" -#include "internal.h" - -#ifndef S_ISLNK - #ifndef S_IFLNK - #define S_IFLNK 0120000 - #endif - #ifndef S_IFMT - #define S_IFMT 0170000 - #endif - #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif - -#ifndef __GNUC__ -#define __builtin_prefetch(p, r, l) -#define unlikely(x) (x) -#else -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN - -/* If strnlen is not declared, provide our own version. */ - -static size_t -xstrnlen (const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; ++i) - if (s[i] == '\0') - break; - return i; -} - -#define strnlen xstrnlen - -#endif - -#ifndef HAVE_LSTAT - -/* Dummy version of lstat for systems that don't have it. */ - -static int -xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED) -{ - return -1; -} - -#define lstat xlstat - -#endif - -#ifndef HAVE_READLINK - -/* Dummy version of readlink for systems that don't have it. */ - -static ssize_t -xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED, - size_t bufsz ATTRIBUTE_UNUSED) -{ - return -1; -} - -#define readlink xreadlink - -#endif - -#ifndef HAVE_DL_ITERATE_PHDR - -/* Dummy version of dl_iterate_phdr for systems that don't have it. */ - -#define dl_phdr_info x_dl_phdr_info -#define dl_iterate_phdr x_dl_iterate_phdr - -struct dl_phdr_info -{ - uintptr_t dlpi_addr; - const char *dlpi_name; -}; - -static int -dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, - size_t, void *) ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - return 0; -} - -#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */ - -/* The configure script must tell us whether we are 32-bit or 64-bit - ELF. We could make this code test and support either possibility, - but there is no point. This code only works for the currently - running executable, which means that we know the ELF mode at - configure time. */ - -#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 -#error "Unknown BACKTRACE_ELF_SIZE" -#endif - -/* might #include which might define our constants - with slightly different values. Undefine them to be safe. */ - -#undef EI_NIDENT -#undef EI_MAG0 -#undef EI_MAG1 -#undef EI_MAG2 -#undef EI_MAG3 -#undef EI_CLASS -#undef EI_DATA -#undef EI_VERSION -#undef ELF_MAG0 -#undef ELF_MAG1 -#undef ELF_MAG2 -#undef ELF_MAG3 -#undef ELFCLASS32 -#undef ELFCLASS64 -#undef ELFDATA2LSB -#undef ELFDATA2MSB -#undef EV_CURRENT -#undef ET_DYN -#undef EM_PPC64 -#undef EF_PPC64_ABI -#undef SHN_LORESERVE -#undef SHN_XINDEX -#undef SHN_UNDEF -#undef SHT_PROGBITS -#undef SHT_SYMTAB -#undef SHT_STRTAB -#undef SHT_DYNSYM -#undef SHF_COMPRESSED -#undef STT_OBJECT -#undef STT_FUNC -#undef NT_GNU_BUILD_ID -#undef ELFCOMPRESS_ZLIB - -/* Basic types. */ - -typedef uint16_t b_elf_half; /* Elf_Half. */ -typedef uint32_t b_elf_word; /* Elf_Word. */ -typedef int32_t b_elf_sword; /* Elf_Sword. */ - -#if BACKTRACE_ELF_SIZE == 32 - -typedef uint32_t b_elf_addr; /* Elf_Addr. */ -typedef uint32_t b_elf_off; /* Elf_Off. */ - -typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#else - -typedef uint64_t b_elf_addr; /* Elf_Addr. */ -typedef uint64_t b_elf_off; /* Elf_Off. */ -typedef uint64_t b_elf_xword; /* Elf_Xword. */ -typedef int64_t b_elf_sxword; /* Elf_Sxword. */ - -typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#endif - -/* Data structures and associated constants. */ - -#define EI_NIDENT 16 - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - b_elf_half e_type; /* Identifies object file type */ - b_elf_half e_machine; /* Specifies required architecture */ - b_elf_word e_version; /* Identifies object file version */ - b_elf_addr e_entry; /* Entry point virtual address */ - b_elf_off e_phoff; /* Program header table file offset */ - b_elf_off e_shoff; /* Section header table file offset */ - b_elf_word e_flags; /* Processor-specific flags */ - b_elf_half e_ehsize; /* ELF header size in bytes */ - b_elf_half e_phentsize; /* Program header table entry size */ - b_elf_half e_phnum; /* Program header table entry count */ - b_elf_half e_shentsize; /* Section header table entry size */ - b_elf_half e_shnum; /* Section header table entry count */ - b_elf_half e_shstrndx; /* Section header string table index */ -} b_elf_ehdr; /* Elf_Ehdr. */ - -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 - -#define ELFMAG0 0x7f -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' - -#define ELFCLASS32 1 -#define ELFCLASS64 2 - -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_CURRENT 1 - -#define ET_DYN 3 - -#define EM_PPC64 21 -#define EF_PPC64_ABI 3 - -typedef struct { - b_elf_word sh_name; /* Section name, index in string tbl */ - b_elf_word sh_type; /* Type of section */ - b_elf_wxword sh_flags; /* Miscellaneous section attributes */ - b_elf_addr sh_addr; /* Section virtual addr at execution */ - b_elf_off sh_offset; /* Section file offset */ - b_elf_wxword sh_size; /* Size of section in bytes */ - b_elf_word sh_link; /* Index of another section */ - b_elf_word sh_info; /* Additional section information */ - b_elf_wxword sh_addralign; /* Section alignment */ - b_elf_wxword sh_entsize; /* Entry size if section holds table */ -} b_elf_shdr; /* Elf_Shdr. */ - -#define SHN_UNDEF 0x0000 /* Undefined section */ -#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ -#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ - -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_DYNSYM 11 - -#define SHF_COMPRESSED 0x800 - -#if BACKTRACE_ELF_SIZE == 32 - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - b_elf_addr st_value; /* Symbol value */ - b_elf_word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ -} b_elf_sym; /* Elf_Sym. */ - -#else /* BACKTRACE_ELF_SIZE != 32 */ - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ - b_elf_addr st_value; /* Symbol value */ - b_elf_xword st_size; /* Symbol size */ -} b_elf_sym; /* Elf_Sym. */ - -#endif /* BACKTRACE_ELF_SIZE != 32 */ - -#define STT_OBJECT 1 -#define STT_FUNC 2 - -typedef struct -{ - uint32_t namesz; - uint32_t descsz; - uint32_t type; - char name[1]; -} b_elf_note; - -#define NT_GNU_BUILD_ID 3 - -#if BACKTRACE_ELF_SIZE == 32 - -typedef struct -{ - b_elf_word ch_type; /* Compresstion algorithm */ - b_elf_word ch_size; /* Uncompressed size */ - b_elf_word ch_addralign; /* Alignment for uncompressed data */ -} b_elf_chdr; /* Elf_Chdr */ - -#else /* BACKTRACE_ELF_SIZE != 32 */ - -typedef struct -{ - b_elf_word ch_type; /* Compression algorithm */ - b_elf_word ch_reserved; /* Reserved */ - b_elf_xword ch_size; /* Uncompressed size */ - b_elf_xword ch_addralign; /* Alignment for uncompressed data */ -} b_elf_chdr; /* Elf_Chdr */ - -#endif /* BACKTRACE_ELF_SIZE != 32 */ - -#define ELFCOMPRESS_ZLIB 1 - -/* Names of sections, indexed by enum dwarf_section in internal.h. */ - -static const char * const dwarf_section_names[DEBUG_MAX] = -{ - ".debug_info", - ".debug_line", - ".debug_abbrev", - ".debug_ranges", - ".debug_str", - ".debug_addr", - ".debug_str_offsets", - ".debug_line_str", - ".debug_rnglists" -}; - -/* Information we gather for the sections we care about. */ - -struct debug_section_info -{ - /* Section file offset. */ - off_t offset; - /* Section size. */ - size_t size; - /* Section contents, after read from file. */ - const unsigned char *data; - /* Whether the SHF_COMPRESSED flag is set for the section. */ - int compressed; -}; - -/* Information we keep for an ELF symbol. */ - -struct elf_symbol -{ - /* The name of the symbol. */ - const char *name; - /* The address of the symbol. */ - uintptr_t address; - /* The size of the symbol. */ - size_t size; -}; - -/* Information to pass to elf_syminfo. */ - -struct elf_syminfo_data -{ - /* Symbols for the next module. */ - struct elf_syminfo_data *next; - /* The ELF symbols, sorted by address. */ - struct elf_symbol *symbols; - /* The number of symbols. */ - size_t count; -}; - -/* Information about PowerPC64 ELFv1 .opd section. */ - -struct elf_ppc64_opd_data -{ - /* Address of the .opd section. */ - b_elf_addr addr; - /* Section data. */ - const char *data; - /* Size of the .opd section. */ - size_t size; - /* Corresponding section view. */ - struct backtrace_view view; -}; - -/* Compute the CRC-32 of BUF/LEN. This uses the CRC used for - .gnu_debuglink files. */ - -static uint32_t -elf_crc32 (uint32_t crc, const unsigned char *buf, size_t len) -{ - static const uint32_t crc32_table[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 - }; - const unsigned char *end; - - crc = ~crc; - for (end = buf + len; buf < end; ++ buf) - crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc; -} - -/* Return the CRC-32 of the entire file open at DESCRIPTOR. */ - -static uint32_t -elf_crc32_file (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, void *data) -{ - struct stat st; - struct backtrace_view file_view; - uint32_t ret; - - if (fstat (descriptor, &st) < 0) - { - error_callback (data, "fstat", errno); - return 0; - } - - if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback, - data, &file_view)) - return 0; - - ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size); - - backtrace_release_view (state, &file_view, error_callback, data); - - return ret; -} - -/* A dummy callback function used when we can't find any debug info. */ - -static int -elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in ELF executable", -1); - return 0; -} - -/* A dummy callback function used when we can't find a symbol - table. */ - -static void -elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in ELF executable", -1); -} - -/* Compare struct elf_symbol for qsort. */ - -static int -elf_symbol_compare (const void *v1, const void *v2) -{ - const struct elf_symbol *e1 = (const struct elf_symbol *) v1; - const struct elf_symbol *e2 = (const struct elf_symbol *) v2; - - if (e1->address < e2->address) - return -1; - else if (e1->address > e2->address) - return 1; - else - return 0; -} - -/* Compare an ADDR against an elf_symbol for bsearch. We allocate one - extra entry in the array so that this can look safely at the next - entry. */ - -static int -elf_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct elf_symbol *entry = (const struct elf_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->address) - return -1; - else if (addr >= entry->address + entry->size) - return 1; - else - return 0; -} - -/* Initialize the symbol table info for elf_syminfo. */ - -static int -elf_initialize_syminfo (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *symtab_data, size_t symtab_size, - const unsigned char *strtab, size_t strtab_size, - backtrace_error_callback error_callback, - void *data, struct elf_syminfo_data *sdata, - struct elf_ppc64_opd_data *opd) -{ - size_t sym_count; - const b_elf_sym *sym; - size_t elf_symbol_count; - size_t elf_symbol_size; - struct elf_symbol *elf_symbols; - size_t i; - unsigned int j; - - sym_count = symtab_size / sizeof (b_elf_sym); - - /* We only care about function symbols. Count them. */ - sym = (const b_elf_sym *) symtab_data; - elf_symbol_count = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if ((info == STT_FUNC || info == STT_OBJECT) - && sym->st_shndx != SHN_UNDEF) - ++elf_symbol_count; - } - - elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); - elf_symbols = ((struct elf_symbol *) - backtrace_alloc (state, elf_symbol_size, error_callback, - data)); - if (elf_symbols == NULL) - return 0; - - sym = (const b_elf_sym *) symtab_data; - j = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if (info != STT_FUNC && info != STT_OBJECT) - continue; - if (sym->st_shndx == SHN_UNDEF) - continue; - if (sym->st_name >= strtab_size) - { - error_callback (data, "symbol string index out of range", 0); - backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, - data); - return 0; - } - elf_symbols[j].name = (const char *) strtab + sym->st_name; - /* Special case PowerPC64 ELFv1 symbols in .opd section, if the symbol - is a function descriptor, read the actual code address from the - descriptor. */ - if (opd - && sym->st_value >= opd->addr - && sym->st_value < opd->addr + opd->size) - elf_symbols[j].address - = *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr)); - else - elf_symbols[j].address = sym->st_value; - elf_symbols[j].address += base_address; - elf_symbols[j].size = sym->st_size; - ++j; - } - - backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), - elf_symbol_compare); - - sdata->next = NULL; - sdata->symbols = elf_symbols; - sdata->count = elf_symbol_count; - - return 1; -} - -/* Add EDATA to the list in STATE. */ - -static void -elf_add_syminfo_data (struct backtrace_state *state, - struct elf_syminfo_data *edata) -{ - if (!state->threaded) - { - struct elf_syminfo_data **pp; - - for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = edata; - } - else - { - while (1) - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct elf_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, edata)) - break; - } - } -} - -/* Return the symbol name and value for an ADDR. */ - -static void -elf_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct elf_syminfo_data *edata; - struct elf_symbol *sym = NULL; - - if (!state->threaded) - { - for (edata = (struct elf_syminfo_data *) state->syminfo_data; - edata != NULL; - edata = edata->next) - { - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - } - } - else - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - edata = backtrace_atomic_load_pointer (pp); - if (edata == NULL) - break; - - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - - pp = &edata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->address, sym->size); -} - -/* Return whether FILENAME is a symlink. */ - -static int -elf_is_symlink (const char *filename) -{ - struct stat st; - - if (lstat (filename, &st) < 0) - return 0; - return S_ISLNK (st.st_mode); -} - -/* Return the results of reading the symlink FILENAME in a buffer - allocated by backtrace_alloc. Return the length of the buffer in - *LEN. */ - -static char * -elf_readlink (struct backtrace_state *state, const char *filename, - backtrace_error_callback error_callback, void *data, - size_t *plen) -{ - size_t len; - char *buf; - - len = 128; - while (1) - { - ssize_t rl; - - buf = backtrace_alloc (state, len, error_callback, data); - if (buf == NULL) - return NULL; - rl = readlink (filename, buf, len); - if (rl < 0) - { - backtrace_free (state, buf, len, error_callback, data); - return NULL; - } - if ((size_t) rl < len - 1) - { - buf[rl] = '\0'; - *plen = len; - return buf; - } - backtrace_free (state, buf, len, error_callback, data); - len *= 2; - } -} - -#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/" - -/* Open a separate debug info file, using the build ID to find it. - Returns an open file descriptor, or -1. - - The GDB manual says that the only place gdb looks for a debug file - when the build ID is known is in /usr/lib/debug/.build-id. */ - -static int -elf_open_debugfile_by_buildid (struct backtrace_state *state, - const char *buildid_data, size_t buildid_size, - backtrace_error_callback error_callback, - void *data) -{ - const char * const prefix = SYSTEM_BUILD_ID_DIR; - const size_t prefix_len = strlen (prefix); - const char * const suffix = ".debug"; - const size_t suffix_len = strlen (suffix); - size_t len; - char *bd_filename; - char *t; - size_t i; - int ret; - int does_not_exist; - - len = prefix_len + buildid_size * 2 + suffix_len + 2; - bd_filename = backtrace_alloc (state, len, error_callback, data); - if (bd_filename == NULL) - return -1; - - t = bd_filename; - memcpy (t, prefix, prefix_len); - t += prefix_len; - for (i = 0; i < buildid_size; i++) - { - unsigned char b; - unsigned char nib; - - b = (unsigned char) buildid_data[i]; - nib = (b & 0xf0) >> 4; - *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; - nib = b & 0x0f; - *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; - if (i == 0) - *t++ = '/'; - } - memcpy (t, suffix, suffix_len); - t[suffix_len] = '\0'; - - ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist); - - backtrace_free (state, bd_filename, len, error_callback, data); - - /* gdb checks that the debuginfo file has the same build ID note. - That seems kind of pointless to me--why would it have the right - name but not the right build ID?--so skipping the check. */ - - return ret; -} - -/* Try to open a file whose name is PREFIX (length PREFIX_LEN) - concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with - DEBUGLINK_NAME. Returns an open file descriptor, or -1. */ - -static int -elf_try_debugfile (struct backtrace_state *state, const char *prefix, - size_t prefix_len, const char *prefix2, size_t prefix2_len, - const char *debuglink_name, - backtrace_error_callback error_callback, void *data) -{ - size_t debuglink_len; - size_t try_len; - char *try; - int does_not_exist; - int ret; - - debuglink_len = strlen (debuglink_name); - try_len = prefix_len + prefix2_len + debuglink_len + 1; - try = backtrace_alloc (state, try_len, error_callback, data); - if (try == NULL) - return -1; - - memcpy (try, prefix, prefix_len); - memcpy (try + prefix_len, prefix2, prefix2_len); - memcpy (try + prefix_len + prefix2_len, debuglink_name, debuglink_len); - try[prefix_len + prefix2_len + debuglink_len] = '\0'; - - ret = backtrace_open (try, error_callback, data, &does_not_exist); - - backtrace_free (state, try, try_len, error_callback, data); - - return ret; -} - -/* Find a separate debug info file, using the debuglink section data - to find it. Returns an open file descriptor, or -1. */ - -static int -elf_find_debugfile_by_debuglink (struct backtrace_state *state, - const char *filename, - const char *debuglink_name, - backtrace_error_callback error_callback, - void *data) -{ - int ret; - char *alc; - size_t alc_len; - const char *slash; - int ddescriptor; - const char *prefix; - size_t prefix_len; - - /* Resolve symlinks in FILENAME. Since FILENAME is fairly likely to - be /proc/self/exe, symlinks are common. We don't try to resolve - the whole path name, just the base name. */ - ret = -1; - alc = NULL; - alc_len = 0; - while (elf_is_symlink (filename)) - { - char *new_buf; - size_t new_len; - - new_buf = elf_readlink (state, filename, error_callback, data, &new_len); - if (new_buf == NULL) - break; - - if (new_buf[0] == '/') - filename = new_buf; - else - { - slash = strrchr (filename, '/'); - if (slash == NULL) - filename = new_buf; - else - { - size_t clen; - char *c; - - slash++; - clen = slash - filename + strlen (new_buf) + 1; - c = backtrace_alloc (state, clen, error_callback, data); - if (c == NULL) - goto done; - - memcpy (c, filename, slash - filename); - memcpy (c + (slash - filename), new_buf, strlen (new_buf)); - c[slash - filename + strlen (new_buf)] = '\0'; - backtrace_free (state, new_buf, new_len, error_callback, data); - filename = c; - new_buf = c; - new_len = clen; - } - } - - if (alc != NULL) - backtrace_free (state, alc, alc_len, error_callback, data); - alc = new_buf; - alc_len = new_len; - } - - /* Look for DEBUGLINK_NAME in the same directory as FILENAME. */ - - slash = strrchr (filename, '/'); - if (slash == NULL) - { - prefix = ""; - prefix_len = 0; - } - else - { - slash++; - prefix = filename; - prefix_len = slash - filename; - } - - ddescriptor = elf_try_debugfile (state, prefix, prefix_len, "", 0, - debuglink_name, error_callback, data); - if (ddescriptor >= 0) - { - ret = ddescriptor; - goto done; - } - - /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME. */ - - ddescriptor = elf_try_debugfile (state, prefix, prefix_len, ".debug/", - strlen (".debug/"), debuglink_name, - error_callback, data); - if (ddescriptor >= 0) - { - ret = ddescriptor; - goto done; - } - - /* Look for DEBUGLINK_NAME in /usr/lib/debug. */ - - ddescriptor = elf_try_debugfile (state, "/usr/lib/debug/", - strlen ("/usr/lib/debug/"), prefix, - prefix_len, debuglink_name, - error_callback, data); - if (ddescriptor >= 0) - ret = ddescriptor; - - done: - if (alc != NULL && alc_len > 0) - backtrace_free (state, alc, alc_len, error_callback, data); - return ret; -} - -/* Open a separate debug info file, using the debuglink section data - to find it. Returns an open file descriptor, or -1. */ - -static int -elf_open_debugfile_by_debuglink (struct backtrace_state *state, - const char *filename, - const char *debuglink_name, - uint32_t debuglink_crc, - backtrace_error_callback error_callback, - void *data) -{ - int ddescriptor; - - ddescriptor = elf_find_debugfile_by_debuglink (state, filename, - debuglink_name, - error_callback, data); - if (ddescriptor < 0) - return -1; - - if (debuglink_crc != 0) - { - uint32_t got_crc; - - got_crc = elf_crc32_file (state, ddescriptor, error_callback, data); - if (got_crc != debuglink_crc) - { - backtrace_close (ddescriptor, error_callback, data); - return -1; - } - } - - return ddescriptor; -} - -/* A function useful for setting a breakpoint for an inflation failure - when this code is compiled with -g. */ - -static void -elf_zlib_failed(void) -{ -} - -/* *PVAL is the current value being read from the stream, and *PBITS - is the number of valid bits. Ensure that *PVAL holds at least 15 - bits by reading additional bits from *PPIN, up to PINEND, as - needed. Updates *PPIN, *PVAL and *PBITS. Returns 1 on success, 0 - on error. */ - -static int -elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend, - uint64_t *pval, unsigned int *pbits) -{ - unsigned int bits; - const unsigned char *pin; - uint64_t val; - uint32_t next; - - bits = *pbits; - if (bits >= 15) - return 1; - pin = *ppin; - val = *pval; - - if (unlikely (pinend - pin < 4)) - { - elf_zlib_failed (); - return 0; - } - -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \ - && defined(__ORDER_BIG_ENDIAN__) \ - && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ \ - || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - /* We've ensured that PIN is aligned. */ - next = *(const uint32_t *)pin; - -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - next = __builtin_bswap32 (next); -#endif -#else - next = pin[0] | (pin[1] << 8) | (pin[2] << 16) | (pin[3] << 24); -#endif - - val |= (uint64_t)next << bits; - bits += 32; - pin += 4; - - /* We will need the next four bytes soon. */ - __builtin_prefetch (pin, 0, 0); - - *ppin = pin; - *pval = val; - *pbits = bits; - return 1; -} - -/* Huffman code tables, like the rest of the zlib format, are defined - by RFC 1951. We store a Huffman code table as a series of tables - stored sequentially in memory. Each entry in a table is 16 bits. - The first, main, table has 256 entries. It is followed by a set of - secondary tables of length 2 to 128 entries. The maximum length of - a code sequence in the deflate format is 15 bits, so that is all we - need. Each secondary table has an index, which is the offset of - the table in the overall memory storage. - - The deflate format says that all codes of a given bit length are - lexicographically consecutive. Perhaps we could have 130 values - that require a 15-bit code, perhaps requiring three secondary - tables of size 128. I don't know if this is actually possible, but - it suggests that the maximum size required for secondary tables is - 3 * 128 + 3 * 64 ... == 768. The zlib enough program reports 660 - as the maximum. We permit 768, since in addition to the 256 for - the primary table, with two bytes per entry, and with the two - tables we need, that gives us a page. - - A single table entry needs to store a value or (for the main table - only) the index and size of a secondary table. Values range from 0 - to 285, inclusive. Secondary table indexes, per above, range from - 0 to 510. For a value we need to store the number of bits we need - to determine that value (one value may appear multiple times in the - table), which is 1 to 8. For a secondary table we need to store - the number of bits used to index into the table, which is 1 to 7. - And of course we need 1 bit to decide whether we have a value or a - secondary table index. So each entry needs 9 bits for value/table - index, 3 bits for size, 1 bit what it is. For simplicity we use 16 - bits per entry. */ - -/* Number of entries we allocate to for one code table. We get a page - for the two code tables we need. */ - -#define HUFFMAN_TABLE_SIZE (1024) - -/* Bit masks and shifts for the values in the table. */ - -#define HUFFMAN_VALUE_MASK 0x01ff -#define HUFFMAN_BITS_SHIFT 9 -#define HUFFMAN_BITS_MASK 0x7 -#define HUFFMAN_SECONDARY_SHIFT 12 - -/* For working memory while inflating we need two code tables, we need - an array of code lengths (max value 15, so we use unsigned char), - and an array of unsigned shorts used while building a table. The - latter two arrays must be large enough to hold the maximum number - of code lengths, which RFC 1951 defines as 286 + 30. */ - -#define ZDEBUG_TABLE_SIZE \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ - + (286 + 30) * sizeof (uint16_t) \ - + (286 + 30) * sizeof (unsigned char)) - -#define ZDEBUG_TABLE_CODELEN_OFFSET \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ - + (286 + 30) * sizeof (uint16_t)) - -#define ZDEBUG_TABLE_WORK_OFFSET \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t)) - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - -/* Used by the main function that generates the fixed table to learn - the table size. */ -static size_t final_next_secondary; - -#endif - -/* Build a Huffman code table from an array of lengths in CODES of - length CODES_LEN. The table is stored into *TABLE. ZDEBUG_TABLE - is the same as for elf_zlib_inflate, used to find some work space. - Returns 1 on success, 0 on error. */ - -static int -elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, - uint16_t *zdebug_table, uint16_t *table) -{ - uint16_t count[16]; - uint16_t start[16]; - uint16_t prev[16]; - uint16_t firstcode[7]; - uint16_t *next; - size_t i; - size_t j; - unsigned int code; - size_t next_secondary; - - /* Count the number of code of each length. Set NEXT[val] to be the - next value after VAL with the same bit length. */ - - next = (uint16_t *) (((unsigned char *) zdebug_table) - + ZDEBUG_TABLE_WORK_OFFSET); - - memset (&count[0], 0, 16 * sizeof (uint16_t)); - for (i = 0; i < codes_len; ++i) - { - if (unlikely (codes[i] >= 16)) - { - elf_zlib_failed (); - return 0; - } - - if (count[codes[i]] == 0) - { - start[codes[i]] = i; - prev[codes[i]] = i; - } - else - { - next[prev[codes[i]]] = i; - prev[codes[i]] = i; - } - - ++count[codes[i]]; - } - - /* For each length, fill in the table for the codes of that - length. */ - - memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t)); - - /* Handle the values that do not require a secondary table. */ - - code = 0; - for (j = 1; j <= 8; ++j) - { - unsigned int jcnt; - unsigned int val; - - jcnt = count[j]; - if (jcnt == 0) - continue; - - if (unlikely (jcnt > (1U << j))) - { - elf_zlib_failed (); - return 0; - } - - /* There are JCNT values that have this length, the values - starting from START[j] continuing through NEXT[VAL]. Those - values are assigned consecutive values starting at CODE. */ - - val = start[j]; - for (i = 0; i < jcnt; ++i) - { - uint16_t tval; - size_t ind; - unsigned int incr; - - /* In the compressed bit stream, the value VAL is encoded as - J bits with the value C. */ - - if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0)) - { - elf_zlib_failed (); - return 0; - } - - tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT); - - /* The table lookup uses 8 bits. If J is less than 8, we - don't know what the other bits will be. We need to fill - in all possibilities in the table. Since the Huffman - code is unambiguous, those entries can't be used for any - other code. */ - - for (ind = code; ind < 0x100; ind += 1 << j) - { - if (unlikely (table[ind] != 0)) - { - elf_zlib_failed (); - return 0; - } - table[ind] = tval; - } - - /* Advance to the next value with this length. */ - if (i + 1 < jcnt) - val = next[val]; - - /* The Huffman codes are stored in the bitstream with the - most significant bit first, as is required to make them - unambiguous. The effect is that when we read them from - the bitstream we see the bit sequence in reverse order: - the most significant bit of the Huffman code is the least - significant bit of the value we read from the bitstream. - That means that to make our table lookups work, we need - to reverse the bits of CODE. Since reversing bits is - tedious and in general requires using a table, we instead - increment CODE in reverse order. That is, if the number - of bits we are currently using, here named J, is 3, we - count as 000, 100, 010, 110, 001, 101, 011, 111, which is - to say the numbers from 0 to 7 but with the bits - reversed. Going to more bits, aka incrementing J, - effectively just adds more zero bits as the beginning, - and as such does not change the numeric value of CODE. - - To increment CODE of length J in reverse order, find the - most significant zero bit and set it to one while - clearing all higher bits. In other words, add 1 modulo - 2^J, only reversed. */ - - incr = 1U << (j - 1); - while ((code & incr) != 0) - incr >>= 1; - if (incr == 0) - code = 0; - else - { - code &= incr - 1; - code += incr; - } - } - } - - /* Handle the values that require a secondary table. */ - - /* Set FIRSTCODE, the number at which the codes start, for each - length. */ - - for (j = 9; j < 16; j++) - { - unsigned int jcnt; - unsigned int k; - - jcnt = count[j]; - if (jcnt == 0) - continue; - - /* There are JCNT values that have this length, the values - starting from START[j]. Those values are assigned - consecutive values starting at CODE. */ - - firstcode[j - 9] = code; - - /* Reverse add JCNT to CODE modulo 2^J. */ - for (k = 0; k < j; ++k) - { - if ((jcnt & (1U << k)) != 0) - { - unsigned int m; - unsigned int bit; - - bit = 1U << (j - k - 1); - for (m = 0; m < j - k; ++m, bit >>= 1) - { - if ((code & bit) == 0) - { - code += bit; - break; - } - code &= ~bit; - } - jcnt &= ~(1U << k); - } - } - if (unlikely (jcnt != 0)) - { - elf_zlib_failed (); - return 0; - } - } - - /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive - values starting at START[J] with consecutive codes starting at - FIRSTCODE[J - 9]. In the primary table we need to point to the - secondary table, and the secondary table will be indexed by J - 9 - bits. We count down from 15 so that we install the larger - secondary tables first, as the smaller ones may be embedded in - the larger ones. */ - - next_secondary = 0; /* Index of next secondary table (after primary). */ - for (j = 15; j >= 9; j--) - { - unsigned int jcnt; - unsigned int val; - size_t primary; /* Current primary index. */ - size_t secondary; /* Offset to current secondary table. */ - size_t secondary_bits; /* Bit size of current secondary table. */ - - jcnt = count[j]; - if (jcnt == 0) - continue; - - val = start[j]; - code = firstcode[j - 9]; - primary = 0x100; - secondary = 0; - secondary_bits = 0; - for (i = 0; i < jcnt; ++i) - { - uint16_t tval; - size_t ind; - unsigned int incr; - - if ((code & 0xff) != primary) - { - uint16_t tprimary; - - /* Fill in a new primary table entry. */ - - primary = code & 0xff; - - tprimary = table[primary]; - if (tprimary == 0) - { - /* Start a new secondary table. */ - - if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK) - != next_secondary)) - { - elf_zlib_failed (); - return 0; - } - - secondary = next_secondary; - secondary_bits = j - 8; - next_secondary += 1 << secondary_bits; - table[primary] = (secondary - + ((j - 8) << HUFFMAN_BITS_SHIFT) - + (1U << HUFFMAN_SECONDARY_SHIFT)); - } - else - { - /* There is an existing entry. It had better be a - secondary table with enough bits. */ - if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT)) - == 0)) - { - elf_zlib_failed (); - return 0; - } - secondary = tprimary & HUFFMAN_VALUE_MASK; - secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT) - & HUFFMAN_BITS_MASK); - if (unlikely (secondary_bits < j - 8)) - { - elf_zlib_failed (); - return 0; - } - } - } - - /* Fill in secondary table entries. */ - - tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT); - - for (ind = code >> 8; - ind < (1U << secondary_bits); - ind += 1U << (j - 8)) - { - if (unlikely (table[secondary + 0x100 + ind] != 0)) - { - elf_zlib_failed (); - return 0; - } - table[secondary + 0x100 + ind] = tval; - } - - if (i + 1 < jcnt) - val = next[val]; - - incr = 1U << (j - 1); - while ((code & incr) != 0) - incr >>= 1; - if (incr == 0) - code = 0; - else - { - code &= incr - 1; - code += incr; - } - } - } - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - final_next_secondary = next_secondary; -#endif - - return 1; -} - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - -/* Used to generate the fixed Huffman table for block type 1. */ - -#include - -static uint16_t table[ZDEBUG_TABLE_SIZE]; -static unsigned char codes[288]; - -int -main () -{ - size_t i; - - for (i = 0; i <= 143; ++i) - codes[i] = 8; - for (i = 144; i <= 255; ++i) - codes[i] = 9; - for (i = 256; i <= 279; ++i) - codes[i] = 7; - for (i = 280; i <= 287; ++i) - codes[i] = 8; - if (!elf_zlib_inflate_table (&codes[0], 288, &table[0], &table[0])) - { - fprintf (stderr, "elf_zlib_inflate_table failed\n"); - exit (EXIT_FAILURE); - } - - printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n", - final_next_secondary + 0x100); - printf ("{\n"); - for (i = 0; i < final_next_secondary + 0x100; i += 8) - { - size_t j; - - printf (" "); - for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) - printf (" %#x,", table[j]); - printf ("\n"); - } - printf ("};\n"); - printf ("\n"); - - for (i = 0; i < 32; ++i) - codes[i] = 5; - if (!elf_zlib_inflate_table (&codes[0], 32, &table[0], &table[0])) - { - fprintf (stderr, "elf_zlib_inflate_table failed\n"); - exit (EXIT_FAILURE); - } - - printf ("static const uint16_t elf_zlib_default_dist_table[%#zx] =\n", - final_next_secondary + 0x100); - printf ("{\n"); - for (i = 0; i < final_next_secondary + 0x100; i += 8) - { - size_t j; - - printf (" "); - for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) - printf (" %#x,", table[j]); - printf ("\n"); - } - printf ("};\n"); - - return 0; -} - -#endif - -/* The fixed tables generated by the #ifdef'ed out main function - above. */ - -static const uint16_t elf_zlib_default_table[0x170] = -{ - 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230, - 0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250, - 0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240, - 0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260, - 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238, - 0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258, - 0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248, - 0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268, - 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234, - 0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254, - 0xd05, 0xe5a, 0xe1a, 0x1204, 0xd15, 0xe7a, 0xe3a, 0x1244, - 0xd0d, 0xe6a, 0xe2a, 0x1224, 0xe0a, 0xe8a, 0xe4a, 0x1264, - 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123c, - 0xd0b, 0xe66, 0xe26, 0x121c, 0xe06, 0xe86, 0xe46, 0x125c, - 0xd07, 0xe5e, 0xe1e, 0x120c, 0xd17, 0xe7e, 0xe3e, 0x124c, - 0xd0f, 0xe6e, 0xe2e, 0x122c, 0xe0e, 0xe8e, 0xe4e, 0x126c, - 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1232, - 0xd08, 0xe61, 0xe21, 0x1212, 0xe01, 0xe81, 0xe41, 0x1252, - 0xd04, 0xe59, 0xe19, 0x1202, 0xd14, 0xe79, 0xe39, 0x1242, - 0xd0c, 0xe69, 0xe29, 0x1222, 0xe09, 0xe89, 0xe49, 0x1262, - 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123a, - 0xd0a, 0xe65, 0xe25, 0x121a, 0xe05, 0xe85, 0xe45, 0x125a, - 0xd06, 0xe5d, 0xe1d, 0x120a, 0xd16, 0xe7d, 0xe3d, 0x124a, - 0xd0e, 0xe6d, 0xe2d, 0x122a, 0xe0d, 0xe8d, 0xe4d, 0x126a, - 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1236, - 0xd09, 0xe63, 0xe23, 0x1216, 0xe03, 0xe83, 0xe43, 0x1256, - 0xd05, 0xe5b, 0xe1b, 0x1206, 0xd15, 0xe7b, 0xe3b, 0x1246, - 0xd0d, 0xe6b, 0xe2b, 0x1226, 0xe0b, 0xe8b, 0xe4b, 0x1266, - 0xd03, 0xe57, 0xe17, 0xf1f, 0xd13, 0xe77, 0xe37, 0x123e, - 0xd0b, 0xe67, 0xe27, 0x121e, 0xe07, 0xe87, 0xe47, 0x125e, - 0xd07, 0xe5f, 0xe1f, 0x120e, 0xd17, 0xe7f, 0xe3f, 0x124e, - 0xd0f, 0xe6f, 0xe2f, 0x122e, 0xe0f, 0xe8f, 0xe4f, 0x126e, - 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, - 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, - 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, - 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, - 0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, - 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf, - 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, - 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf, - 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, - 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, - 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, - 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, - 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, - 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff, -}; - -static const uint16_t elf_zlib_default_dist_table[0x100] = -{ - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, - 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, - 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, - 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, - 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, -}; - -/* Inflate a zlib stream from PIN/SIN to POUT/SOUT. Return 1 on - success, 0 on some error parsing the stream. */ - -static int -elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, - unsigned char *pout, size_t sout) -{ - unsigned char *porigout; - const unsigned char *pinend; - unsigned char *poutend; - - /* We can apparently see multiple zlib streams concatenated - together, so keep going as long as there is something to read. - The last 4 bytes are the checksum. */ - porigout = pout; - pinend = pin + sin; - poutend = pout + sout; - while ((pinend - pin) > 4) - { - uint64_t val; - unsigned int bits; - int last; - - /* Read the two byte zlib header. */ - - if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */ - { - /* Unknown compression method. */ - elf_zlib_failed (); - return 0; - } - if (unlikely ((pin[0] >> 4) > 7)) - { - /* Window size too large. Other than this check, we don't - care about the window size. */ - elf_zlib_failed (); - return 0; - } - if (unlikely ((pin[1] & 0x20) != 0)) - { - /* Stream expects a predefined dictionary, but we have no - dictionary. */ - elf_zlib_failed (); - return 0; - } - val = (pin[0] << 8) | pin[1]; - if (unlikely (val % 31 != 0)) - { - /* Header check failure. */ - elf_zlib_failed (); - return 0; - } - pin += 2; - - /* Align PIN to a 32-bit boundary. */ - - val = 0; - bits = 0; - while ((((uintptr_t) pin) & 3) != 0) - { - val |= (uint64_t)*pin << bits; - bits += 8; - ++pin; - } - - /* Read blocks until one is marked last. */ - - last = 0; - - while (!last) - { - unsigned int type; - const uint16_t *tlit; - const uint16_t *tdist; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - last = val & 1; - type = (val >> 1) & 3; - val >>= 3; - bits -= 3; - - if (unlikely (type == 3)) - { - /* Invalid block type. */ - elf_zlib_failed (); - return 0; - } - - if (type == 0) - { - uint16_t len; - uint16_t lenc; - - /* An uncompressed block. */ - - /* If we've read ahead more than a byte, back up. */ - while (bits > 8) - { - --pin; - bits -= 8; - } - - val = 0; - bits = 0; - if (unlikely ((pinend - pin) < 4)) - { - /* Missing length. */ - elf_zlib_failed (); - return 0; - } - len = pin[0] | (pin[1] << 8); - lenc = pin[2] | (pin[3] << 8); - pin += 4; - lenc = ~lenc; - if (unlikely (len != lenc)) - { - /* Corrupt data. */ - elf_zlib_failed (); - return 0; - } - if (unlikely (len > (unsigned int) (pinend - pin) - || len > (unsigned int) (poutend - pout))) - { - /* Not enough space in buffers. */ - elf_zlib_failed (); - return 0; - } - memcpy (pout, pin, len); - pout += len; - pin += len; - - /* Align PIN. */ - while ((((uintptr_t) pin) & 3) != 0) - { - val |= (uint64_t)*pin << bits; - bits += 8; - ++pin; - } - - /* Go around to read the next block. */ - continue; - } - - if (type == 1) - { - tlit = elf_zlib_default_table; - tdist = elf_zlib_default_dist_table; - } - else - { - unsigned int nlit; - unsigned int ndist; - unsigned int nclen; - unsigned char codebits[19]; - unsigned char *plenbase; - unsigned char *plen; - unsigned char *plenend; - - /* Read a Huffman encoding table. The various magic - numbers here are from RFC 1951. */ - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - nlit = (val & 0x1f) + 257; - val >>= 5; - ndist = (val & 0x1f) + 1; - val >>= 5; - nclen = (val & 0xf) + 4; - val >>= 4; - bits -= 14; - if (unlikely (nlit > 286 || ndist > 30)) - { - /* Values out of range. */ - elf_zlib_failed (); - return 0; - } - - /* Read and build the table used to compress the - literal, length, and distance codes. */ - - memset(&codebits[0], 0, 19); - - /* There are always at least 4 elements in the - table. */ - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[16] = val & 7; - codebits[17] = (val >> 3) & 7; - codebits[18] = (val >> 6) & 7; - codebits[0] = (val >> 9) & 7; - val >>= 12; - bits -= 12; - - if (nclen == 4) - goto codebitsdone; - - codebits[8] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 5) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[7] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 6) - goto codebitsdone; - - codebits[9] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 7) - goto codebitsdone; - - codebits[6] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 8) - goto codebitsdone; - - codebits[10] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 9) - goto codebitsdone; - - codebits[5] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 10) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[11] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 11) - goto codebitsdone; - - codebits[4] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 12) - goto codebitsdone; - - codebits[12] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 13) - goto codebitsdone; - - codebits[3] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 14) - goto codebitsdone; - - codebits[13] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 15) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[2] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 16) - goto codebitsdone; - - codebits[14] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 17) - goto codebitsdone; - - codebits[1] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 18) - goto codebitsdone; - - codebits[15] = val & 7; - val >>= 3; - bits -= 3; - - codebitsdone: - - if (!elf_zlib_inflate_table (codebits, 19, zdebug_table, - zdebug_table)) - return 0; - - /* Read the compressed bit lengths of the literal, - length, and distance codes. We have allocated space - at the end of zdebug_table to hold them. */ - - plenbase = (((unsigned char *) zdebug_table) - + ZDEBUG_TABLE_CODELEN_OFFSET); - plen = plenbase; - plenend = plen + nlit + ndist; - while (plen < plenend) - { - uint16_t t; - unsigned int b; - uint16_t v; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = zdebug_table[val & 0xff]; - - /* The compression here uses bit lengths up to 7, so - a secondary table is never necessary. */ - if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0)) - { - elf_zlib_failed (); - return 0; - } - - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - val >>= b + 1; - bits -= b + 1; - - v = t & HUFFMAN_VALUE_MASK; - if (v < 16) - *plen++ = v; - else if (v == 16) - { - unsigned int c; - unsigned int prev; - - /* Copy previous entry 3 to 6 times. */ - - if (unlikely (plen == plenbase)) - { - elf_zlib_failed (); - return 0; - } - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 3 + (val & 0x3); - val >>= 2; - bits -= 2; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - prev = plen[-1]; - switch (c) - { - case 6: - *plen++ = prev; - /* fallthrough */ - case 5: - *plen++ = prev; - /* fallthrough */ - case 4: - *plen++ = prev; - } - *plen++ = prev; - *plen++ = prev; - *plen++ = prev; - } - else if (v == 17) - { - unsigned int c; - - /* Store zero 3 to 10 times. */ - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 3 + (val & 0x7); - val >>= 3; - bits -= 3; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - switch (c) - { - case 10: - *plen++ = 0; - /* fallthrough */ - case 9: - *plen++ = 0; - /* fallthrough */ - case 8: - *plen++ = 0; - /* fallthrough */ - case 7: - *plen++ = 0; - /* fallthrough */ - case 6: - *plen++ = 0; - /* fallthrough */ - case 5: - *plen++ = 0; - /* fallthrough */ - case 4: - *plen++ = 0; - } - *plen++ = 0; - *plen++ = 0; - *plen++ = 0; - } - else if (v == 18) - { - unsigned int c; - - /* Store zero 11 to 138 times. */ - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 11 + (val & 0x7f); - val >>= 7; - bits -= 7; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - memset (plen, 0, c); - plen += c; - } - else - { - elf_zlib_failed (); - return 0; - } - } - - /* Make sure that the stop code can appear. */ - - plen = plenbase; - if (unlikely (plen[256] == 0)) - { - elf_zlib_failed (); - return 0; - } - - /* Build the decompression tables. */ - - if (!elf_zlib_inflate_table (plen, nlit, zdebug_table, - zdebug_table)) - return 0; - if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table, - zdebug_table + HUFFMAN_TABLE_SIZE)) - return 0; - tlit = zdebug_table; - tdist = zdebug_table + HUFFMAN_TABLE_SIZE; - } - - /* Inflate values until the end of the block. This is the - main loop of the inflation code. */ - - while (1) - { - uint16_t t; - unsigned int b; - uint16_t v; - unsigned int lit; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = tlit[val & 0xff]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - v = t & HUFFMAN_VALUE_MASK; - - if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) - { - lit = v; - val >>= b + 1; - bits -= b + 1; - } - else - { - t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - lit = t & HUFFMAN_VALUE_MASK; - val >>= b + 8; - bits -= b + 8; - } - - if (lit < 256) - { - if (unlikely (pout == poutend)) - { - elf_zlib_failed (); - return 0; - } - - *pout++ = lit; - - /* We will need to write the next byte soon. We ask - for high temporal locality because we will write - to the whole cache line soon. */ - __builtin_prefetch (pout, 1, 3); - } - else if (lit == 256) - { - /* The end of the block. */ - break; - } - else - { - unsigned int dist; - unsigned int len; - - /* Convert lit into a length. */ - - if (lit < 265) - len = lit - 257 + 3; - else if (lit == 285) - len = 258; - else if (unlikely (lit > 285)) - { - elf_zlib_failed (); - return 0; - } - else - { - unsigned int extra; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - /* This is an expression for the table of length - codes in RFC 1951 3.2.5. */ - lit -= 265; - extra = (lit >> 2) + 1; - len = (lit & 3) << extra; - len += 11; - len += ((1U << (extra - 1)) - 1) << 3; - len += val & ((1U << extra) - 1); - val >>= extra; - bits -= extra; - } - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = tdist[val & 0xff]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - v = t & HUFFMAN_VALUE_MASK; - - if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) - { - dist = v; - val >>= b + 1; - bits -= b + 1; - } - else - { - t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - dist = t & HUFFMAN_VALUE_MASK; - val >>= b + 8; - bits -= b + 8; - } - - /* Convert dist to a distance. */ - - if (dist == 0) - { - /* A distance of 1. A common case, meaning - repeat the last character LEN times. */ - - if (unlikely (pout == porigout)) - { - elf_zlib_failed (); - return 0; - } - - if (unlikely ((unsigned int) (poutend - pout) < len)) - { - elf_zlib_failed (); - return 0; - } - - memset (pout, pout[-1], len); - pout += len; - } - else if (unlikely (dist > 29)) - { - elf_zlib_failed (); - return 0; - } - else - { - if (dist < 4) - dist = dist + 1; - else - { - unsigned int extra; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - /* This is an expression for the table of - distance codes in RFC 1951 3.2.5. */ - dist -= 4; - extra = (dist >> 1) + 1; - dist = (dist & 1) << extra; - dist += 5; - dist += ((1U << (extra - 1)) - 1) << 2; - dist += val & ((1U << extra) - 1); - val >>= extra; - bits -= extra; - } - - /* Go back dist bytes, and copy len bytes from - there. */ - - if (unlikely ((unsigned int) (pout - porigout) < dist)) - { - elf_zlib_failed (); - return 0; - } - - if (unlikely ((unsigned int) (poutend - pout) < len)) - { - elf_zlib_failed (); - return 0; - } - - if (dist >= len) - { - memcpy (pout, pout - dist, len); - pout += len; - } - else - { - while (len > 0) - { - unsigned int copy; - - copy = len < dist ? len : dist; - memcpy (pout, pout - dist, copy); - len -= copy; - pout += copy; - } - } - } - } - } - } - } - - /* We should have filled the output buffer. */ - if (unlikely (pout != poutend)) - { - elf_zlib_failed (); - return 0; - } - - return 1; -} - -/* Verify the zlib checksum. The checksum is in the 4 bytes at - CHECKBYTES, and the uncompressed data is at UNCOMPRESSED / - UNCOMPRESSED_SIZE. Returns 1 on success, 0 on failure. */ - -static int -elf_zlib_verify_checksum (const unsigned char *checkbytes, - const unsigned char *uncompressed, - size_t uncompressed_size) -{ - unsigned int i; - unsigned int cksum; - const unsigned char *p; - uint32_t s1; - uint32_t s2; - size_t hsz; - - cksum = 0; - for (i = 0; i < 4; i++) - cksum = (cksum << 8) | checkbytes[i]; - - s1 = 1; - s2 = 0; - - /* Minimize modulo operations. */ - - p = uncompressed; - hsz = uncompressed_size; - while (hsz >= 5552) - { - for (i = 0; i < 5552; i += 16) - { - /* Manually unroll loop 16 times. */ - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - } - hsz -= 5552; - s1 %= 65521; - s2 %= 65521; - } - - while (hsz >= 16) - { - /* Manually unroll loop 16 times. */ - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - - hsz -= 16; - } - - for (i = 0; i < hsz; ++i) - { - s1 = s1 + *p++; - s2 = s2 + s1; - } - - s1 %= 65521; - s2 %= 65521; - - if (unlikely ((s2 << 16) + s1 != cksum)) - { - elf_zlib_failed (); - return 0; - } - - return 1; -} - -/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the - checksum. Return 1 on success, 0 on error. */ - -static int -elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin, - uint16_t *zdebug_table, unsigned char *pout, - size_t sout) -{ - if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout)) - return 0; - if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout)) - return 0; - return 1; -} - -/* Uncompress the old compressed debug format, the one emitted by - --compress-debug-sections=zlib-gnu. The compressed data is in - COMPRESSED / COMPRESSED_SIZE, and the function writes to - *UNCOMPRESSED / *UNCOMPRESSED_SIZE. ZDEBUG_TABLE is work space to - hold Huffman tables. Returns 0 on error, 1 on successful - decompression or if something goes wrong. In general we try to - carry on, by returning 1, even if we can't decompress. */ - -static int -elf_uncompress_zdebug (struct backtrace_state *state, - const unsigned char *compressed, size_t compressed_size, - uint16_t *zdebug_table, - backtrace_error_callback error_callback, void *data, - unsigned char **uncompressed, size_t *uncompressed_size) -{ - size_t sz; - size_t i; - unsigned char *po; - - *uncompressed = NULL; - *uncompressed_size = 0; - - /* The format starts with the four bytes ZLIB, followed by the 8 - byte length of the uncompressed data in big-endian order, - followed by a zlib stream. */ - - if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0) - return 1; - - sz = 0; - for (i = 0; i < 8; i++) - sz = (sz << 8) | compressed[i + 4]; - - if (*uncompressed != NULL && *uncompressed_size >= sz) - po = *uncompressed; - else - { - po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data); - if (po == NULL) - return 0; - } - - if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12, - zdebug_table, po, sz)) - return 1; - - *uncompressed = po; - *uncompressed_size = sz; - - return 1; -} - -/* Uncompress the new compressed debug format, the official standard - ELF approach emitted by --compress-debug-sections=zlib-gabi. The - compressed data is in COMPRESSED / COMPRESSED_SIZE, and the - function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE. - ZDEBUG_TABLE is work space as for elf_uncompress_zdebug. Returns 0 - on error, 1 on successful decompression or if something goes wrong. - In general we try to carry on, by returning 1, even if we can't - decompress. */ - -static int -elf_uncompress_chdr (struct backtrace_state *state, - const unsigned char *compressed, size_t compressed_size, - uint16_t *zdebug_table, - backtrace_error_callback error_callback, void *data, - unsigned char **uncompressed, size_t *uncompressed_size) -{ - const b_elf_chdr *chdr; - unsigned char *po; - - *uncompressed = NULL; - *uncompressed_size = 0; - - /* The format starts with an ELF compression header. */ - if (compressed_size < sizeof (b_elf_chdr)) - return 1; - - chdr = (const b_elf_chdr *) compressed; - - if (chdr->ch_type != ELFCOMPRESS_ZLIB) - { - /* Unsupported compression algorithm. */ - return 1; - } - - if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size) - po = *uncompressed; - else - { - po = (unsigned char *) backtrace_alloc (state, chdr->ch_size, - error_callback, data); - if (po == NULL) - return 0; - } - - if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr), - compressed_size - sizeof (b_elf_chdr), - zdebug_table, po, chdr->ch_size)) - return 1; - - *uncompressed = po; - *uncompressed_size = chdr->ch_size; - - return 1; -} - -/* This function is a hook for testing the zlib support. It is only - used by tests. */ - -int -backtrace_uncompress_zdebug (struct backtrace_state *state, - const unsigned char *compressed, - size_t compressed_size, - backtrace_error_callback error_callback, - void *data, unsigned char **uncompressed, - size_t *uncompressed_size) -{ - uint16_t *zdebug_table; - int ret; - - zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - return 0; - ret = elf_uncompress_zdebug (state, compressed, compressed_size, - zdebug_table, error_callback, data, - uncompressed, uncompressed_size); - backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, - error_callback, data); - return ret; -} - -/* Add the backtrace data for one ELF file. Returns 1 on success, - 0 on failure (in both cases descriptor is closed) or -1 if exe - is non-zero and the ELF file is ET_DYN, which tells the caller that - elf_add will need to be called on the descriptor again after - base_address is determined. */ - -static int -elf_add (struct backtrace_state *state, const char *filename, int descriptor, - uintptr_t base_address, backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, - struct dwarf_data **fileline_entry, int exe, int debuginfo, - const char *with_buildid_data, uint32_t with_buildid_size) -{ - struct backtrace_view ehdr_view; - b_elf_ehdr ehdr; - off_t shoff; - unsigned int shnum; - unsigned int shstrndx; - struct backtrace_view shdrs_view; - int shdrs_view_valid; - const b_elf_shdr *shdrs; - const b_elf_shdr *shstrhdr; - size_t shstr_size; - off_t shstr_off; - struct backtrace_view names_view; - int names_view_valid; - const char *names; - unsigned int symtab_shndx; - unsigned int dynsym_shndx; - unsigned int i; - struct debug_section_info sections[DEBUG_MAX]; - struct debug_section_info zsections[DEBUG_MAX]; - struct backtrace_view symtab_view; - int symtab_view_valid; - struct backtrace_view strtab_view; - int strtab_view_valid; - struct backtrace_view buildid_view; - int buildid_view_valid; - const char *buildid_data; - uint32_t buildid_size; - struct backtrace_view debuglink_view; - int debuglink_view_valid; - const char *debuglink_name; - uint32_t debuglink_crc; - struct backtrace_view debugaltlink_view; - int debugaltlink_view_valid; - const char *debugaltlink_name; - const char *debugaltlink_buildid_data; - uint32_t debugaltlink_buildid_size; - off_t min_offset; - off_t max_offset; - struct backtrace_view debug_view; - int debug_view_valid; - unsigned int using_debug_view; - uint16_t *zdebug_table; - struct elf_ppc64_opd_data opd_data, *opd; - struct dwarf_sections dwarf_sections; - - if (!debuginfo) - { - *found_sym = 0; - *found_dwarf = 0; - } - - shdrs_view_valid = 0; - names_view_valid = 0; - symtab_view_valid = 0; - strtab_view_valid = 0; - buildid_view_valid = 0; - buildid_data = NULL; - buildid_size = 0; - debuglink_view_valid = 0; - debuglink_name = NULL; - debuglink_crc = 0; - debugaltlink_view_valid = 0; - debugaltlink_name = NULL; - debugaltlink_buildid_data = NULL; - debugaltlink_buildid_size = 0; - debug_view_valid = 0; - opd = NULL; - - if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, - data, &ehdr_view)) - goto fail; - - memcpy (&ehdr, ehdr_view.data, sizeof ehdr); - - backtrace_release_view (state, &ehdr_view, error_callback, data); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0 - || ehdr.e_ident[EI_MAG1] != ELFMAG1 - || ehdr.e_ident[EI_MAG2] != ELFMAG2 - || ehdr.e_ident[EI_MAG3] != ELFMAG3) - { - error_callback (data, "executable file is not ELF", 0); - goto fail; - } - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) - { - error_callback (data, "executable file is unrecognized ELF version", 0); - goto fail; - } - -#if BACKTRACE_ELF_SIZE == 32 -#define BACKTRACE_ELFCLASS ELFCLASS32 -#else -#define BACKTRACE_ELFCLASS ELFCLASS64 -#endif - - if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) - { - error_callback (data, "executable file is unexpected ELF class", 0); - goto fail; - } - - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB - && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) - { - error_callback (data, "executable file has unknown endianness", 0); - goto fail; - } - - /* If the executable is ET_DYN, it is either a PIE, or we are running - directly a shared library with .interp. We need to wait for - dl_iterate_phdr in that case to determine the actual base_address. */ - if (exe && ehdr.e_type == ET_DYN) - return -1; - - shoff = ehdr.e_shoff; - shnum = ehdr.e_shnum; - shstrndx = ehdr.e_shstrndx; - - if ((shnum == 0 || shstrndx == SHN_XINDEX) - && shoff != 0) - { - struct backtrace_view shdr_view; - const b_elf_shdr *shdr; - - if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, - error_callback, data, &shdr_view)) - goto fail; - - shdr = (const b_elf_shdr *) shdr_view.data; - - if (shnum == 0) - shnum = shdr->sh_size; - - if (shstrndx == SHN_XINDEX) - { - shstrndx = shdr->sh_link; - - /* Versions of the GNU binutils between 2.12 and 2.18 did - not handle objects with more than SHN_LORESERVE sections - correctly. All large section indexes were offset by - 0x100. There is more information at - http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . - Fortunately these object files are easy to detect, as the - GNU binutils always put the section header string table - near the end of the list of sections. Thus if the - section header string table index is larger than the - number of sections, then we know we have to subtract - 0x100 to get the real section index. */ - if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) - shstrndx -= 0x100; - } - - backtrace_release_view (state, &shdr_view, error_callback, data); - } - - /* To translate PC to file/line when using DWARF, we need to find - the .debug_info and .debug_line sections. */ - - /* Read the section headers, skipping the first one. */ - - if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), - (shnum - 1) * sizeof (b_elf_shdr), - error_callback, data, &shdrs_view)) - goto fail; - shdrs_view_valid = 1; - shdrs = (const b_elf_shdr *) shdrs_view.data; - - /* Read the section names. */ - - shstrhdr = &shdrs[shstrndx - 1]; - shstr_size = shstrhdr->sh_size; - shstr_off = shstrhdr->sh_offset; - - if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size, - error_callback, data, &names_view)) - goto fail; - names_view_valid = 1; - names = (const char *) names_view.data; - - symtab_shndx = 0; - dynsym_shndx = 0; - - memset (sections, 0, sizeof sections); - memset (zsections, 0, sizeof zsections); - - /* Look for the symbol table. */ - for (i = 1; i < shnum; ++i) - { - const b_elf_shdr *shdr; - unsigned int sh_name; - const char *name; - int j; - - shdr = &shdrs[i - 1]; - - if (shdr->sh_type == SHT_SYMTAB) - symtab_shndx = i; - else if (shdr->sh_type == SHT_DYNSYM) - dynsym_shndx = i; - - sh_name = shdr->sh_name; - if (sh_name >= shstr_size) - { - error_callback (data, "ELF section name out of range", 0); - goto fail; - } - - name = names + sh_name; - - for (j = 0; j < (int) DEBUG_MAX; ++j) - { - if (strcmp (name, dwarf_section_names[j]) == 0) - { - sections[j].offset = shdr->sh_offset; - sections[j].size = shdr->sh_size; - sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0; - break; - } - } - - if (name[0] == '.' && name[1] == 'z') - { - for (j = 0; j < (int) DEBUG_MAX; ++j) - { - if (strcmp (name + 2, dwarf_section_names[j] + 1) == 0) - { - zsections[j].offset = shdr->sh_offset; - zsections[j].size = shdr->sh_size; - break; - } - } - } - - /* Read the build ID if present. This could check for any - SHT_NOTE section with the right note name and type, but gdb - looks for a specific section name. */ - if ((!debuginfo || with_buildid_data != NULL) - && !buildid_view_valid - && strcmp (name, ".note.gnu.build-id") == 0) - { - const b_elf_note *note; - - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &buildid_view)) - goto fail; - - buildid_view_valid = 1; - note = (const b_elf_note *) buildid_view.data; - if (note->type == NT_GNU_BUILD_ID - && note->namesz == 4 - && strncmp (note->name, "GNU", 4) == 0 - && shdr->sh_size <= 12 + ((note->namesz + 3) & ~ 3) + note->descsz) - { - buildid_data = ¬e->name[0] + ((note->namesz + 3) & ~ 3); - buildid_size = note->descsz; - } - - if (with_buildid_size != 0) - { - if (buildid_size != with_buildid_size) - goto fail; - - if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0) - goto fail; - } - } - - /* Read the debuglink file if present. */ - if (!debuginfo - && !debuglink_view_valid - && strcmp (name, ".gnu_debuglink") == 0) - { - const char *debuglink_data; - size_t crc_offset; - - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &debuglink_view)) - goto fail; - - debuglink_view_valid = 1; - debuglink_data = (const char *) debuglink_view.data; - crc_offset = strnlen (debuglink_data, shdr->sh_size); - crc_offset = (crc_offset + 3) & ~3; - if (crc_offset + 4 <= shdr->sh_size) - { - debuglink_name = debuglink_data; - debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset); - } - } - - if (!debugaltlink_view_valid - && strcmp (name, ".gnu_debugaltlink") == 0) - { - const char *debugaltlink_data; - size_t debugaltlink_name_len; - - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &debugaltlink_view)) - goto fail; - - debugaltlink_view_valid = 1; - debugaltlink_data = (const char *) debugaltlink_view.data; - debugaltlink_name = debugaltlink_data; - debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size); - if (debugaltlink_name_len < shdr->sh_size) - { - /* Include terminating zero. */ - debugaltlink_name_len += 1; - - debugaltlink_buildid_data - = debugaltlink_data + debugaltlink_name_len; - debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len; - } - } - - /* Read the .opd section on PowerPC64 ELFv1. */ - if (ehdr.e_machine == EM_PPC64 - && (ehdr.e_flags & EF_PPC64_ABI) < 2 - && shdr->sh_type == SHT_PROGBITS - && strcmp (name, ".opd") == 0) - { - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &opd_data.view)) - goto fail; - - opd = &opd_data; - opd->addr = shdr->sh_addr; - opd->data = (const char *) opd_data.view.data; - opd->size = shdr->sh_size; - } - } - - if (symtab_shndx == 0) - symtab_shndx = dynsym_shndx; - if (symtab_shndx != 0 && !debuginfo) - { - const b_elf_shdr *symtab_shdr; - unsigned int strtab_shndx; - const b_elf_shdr *strtab_shdr; - struct elf_syminfo_data *sdata; - - symtab_shdr = &shdrs[symtab_shndx - 1]; - strtab_shndx = symtab_shdr->sh_link; - if (strtab_shndx >= shnum) - { - error_callback (data, - "ELF symbol table strtab link out of range", 0); - goto fail; - } - strtab_shdr = &shdrs[strtab_shndx - 1]; - - if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, - symtab_shdr->sh_size, error_callback, data, - &symtab_view)) - goto fail; - symtab_view_valid = 1; - - if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, - strtab_shdr->sh_size, error_callback, data, - &strtab_view)) - goto fail; - strtab_view_valid = 1; - - sdata = ((struct elf_syminfo_data *) - backtrace_alloc (state, sizeof *sdata, error_callback, data)); - if (sdata == NULL) - goto fail; - - if (!elf_initialize_syminfo (state, base_address, - symtab_view.data, symtab_shdr->sh_size, - strtab_view.data, strtab_shdr->sh_size, - error_callback, data, sdata, opd)) - { - backtrace_free (state, sdata, sizeof *sdata, error_callback, data); - goto fail; - } - - /* We no longer need the symbol table, but we hold on to the - string table permanently. */ - backtrace_release_view (state, &symtab_view, error_callback, data); - symtab_view_valid = 0; - - *found_sym = 1; - - elf_add_syminfo_data (state, sdata); - } - - backtrace_release_view (state, &shdrs_view, error_callback, data); - shdrs_view_valid = 0; - backtrace_release_view (state, &names_view, error_callback, data); - names_view_valid = 0; - - /* If the debug info is in a separate file, read that one instead. */ - - if (buildid_data != NULL) - { - int d; - - d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size, - error_callback, data); - if (d >= 0) - { - int ret; - - backtrace_release_view (state, &buildid_view, error_callback, data); - if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, - data); - if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); - ret = elf_add (state, "", d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, - 0); - if (ret < 0) - backtrace_close (d, error_callback, data); - else - backtrace_close (descriptor, error_callback, data); - return ret; - } - } - - if (buildid_view_valid) - { - backtrace_release_view (state, &buildid_view, error_callback, data); - buildid_view_valid = 0; - } - - if (opd) - { - backtrace_release_view (state, &opd->view, error_callback, data); - opd = NULL; - } - - if (debuglink_name != NULL) - { - int d; - - d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name, - debuglink_crc, error_callback, - data); - if (d >= 0) - { - int ret; - - backtrace_release_view (state, &debuglink_view, error_callback, - data); - if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); - ret = elf_add (state, "", d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, - 0); - if (ret < 0) - backtrace_close (d, error_callback, data); - else - backtrace_close(descriptor, error_callback, data); - return ret; - } - } - - if (debuglink_view_valid) - { - backtrace_release_view (state, &debuglink_view, error_callback, data); - debuglink_view_valid = 0; - } - - struct dwarf_data *fileline_altlink = NULL; - if (debugaltlink_name != NULL) - { - int d; - - d = elf_open_debugfile_by_debuglink (state, filename, debugaltlink_name, - 0, error_callback, data); - if (d >= 0) - { - int ret; - - ret = elf_add (state, filename, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, &fileline_altlink, - 0, 1, debugaltlink_buildid_data, - debugaltlink_buildid_size); - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); - debugaltlink_view_valid = 0; - if (ret < 0) - { - backtrace_close (d, error_callback, data); - return ret; - } - } - } - - if (debugaltlink_view_valid) - { - backtrace_release_view (state, &debugaltlink_view, error_callback, data); - debugaltlink_view_valid = 0; - } - - /* Read all the debug sections in a single view, since they are - probably adjacent in the file. If any of sections are - uncompressed, we never release this view. */ - - min_offset = 0; - max_offset = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - off_t end; - - if (sections[i].size != 0) - { - if (min_offset == 0 || sections[i].offset < min_offset) - min_offset = sections[i].offset; - end = sections[i].offset + sections[i].size; - if (end > max_offset) - max_offset = end; - } - if (zsections[i].size != 0) - { - if (min_offset == 0 || zsections[i].offset < min_offset) - min_offset = zsections[i].offset; - end = zsections[i].offset + zsections[i].size; - if (end > max_offset) - max_offset = end; - } - } - if (min_offset == 0 || max_offset == 0) - { - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - return 1; - } - - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, &debug_view)) - goto fail; - debug_view_valid = 1; - - /* We've read all we need from the executable. */ - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - descriptor = -1; - - using_debug_view = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - if (sections[i].size == 0) - sections[i].data = NULL; - else - { - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - ++using_debug_view; - } - - if (zsections[i].size == 0) - zsections[i].data = NULL; - else - zsections[i].data = ((const unsigned char *) debug_view.data - + (zsections[i].offset - min_offset)); - } - - /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */ - - zdebug_table = NULL; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - if (sections[i].size == 0 && zsections[i].size > 0) - { - unsigned char *uncompressed_data; - size_t uncompressed_size; - - if (zdebug_table == NULL) - { - zdebug_table = ((uint16_t *) - backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - goto fail; - } - - uncompressed_data = NULL; - uncompressed_size = 0; - if (!elf_uncompress_zdebug (state, zsections[i].data, - zsections[i].size, zdebug_table, - error_callback, data, - &uncompressed_data, &uncompressed_size)) - goto fail; - sections[i].data = uncompressed_data; - sections[i].size = uncompressed_size; - sections[i].compressed = 0; - } - } - - /* Uncompress the official ELF format - (--compress-debug-sections=zlib-gabi). */ - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - unsigned char *uncompressed_data; - size_t uncompressed_size; - - if (sections[i].size == 0 || !sections[i].compressed) - continue; - - if (zdebug_table == NULL) - { - zdebug_table = ((uint16_t *) - backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - goto fail; - } - - uncompressed_data = NULL; - uncompressed_size = 0; - if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size, - zdebug_table, error_callback, data, - &uncompressed_data, &uncompressed_size)) - goto fail; - sections[i].data = uncompressed_data; - sections[i].size = uncompressed_size; - sections[i].compressed = 0; - - --using_debug_view; - } - - if (zdebug_table != NULL) - backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, - error_callback, data); - - if (debug_view_valid && using_debug_view == 0) - { - backtrace_release_view (state, &debug_view, error_callback, data); - debug_view_valid = 0; - } - - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - dwarf_sections.data[i] = sections[i].data; - dwarf_sections.size[i] = sections[i].size; - } - - if (!backtrace_dwarf_add (state, base_address, &dwarf_sections, - ehdr.e_ident[EI_DATA] == ELFDATA2MSB, - fileline_altlink, - error_callback, data, fileline_fn, - fileline_entry)) - goto fail; - - *found_dwarf = 1; - - return 1; - - fail: - if (shdrs_view_valid) - backtrace_release_view (state, &shdrs_view, error_callback, data); - if (names_view_valid) - backtrace_release_view (state, &names_view, error_callback, data); - if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); - if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); - if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, data); - if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, data); - if (buildid_view_valid) - backtrace_release_view (state, &buildid_view, error_callback, data); - if (debug_view_valid) - backtrace_release_view (state, &debug_view, error_callback, data); - if (opd) - backtrace_release_view (state, &opd->view, error_callback, data); - if (descriptor != -1) - backtrace_close (descriptor, error_callback, data); - return 0; -} - -/* Data passed to phdr_callback. */ - -struct phdr_data -{ - struct backtrace_state *state; - backtrace_error_callback error_callback; - void *data; - fileline *fileline_fn; - int *found_sym; - int *found_dwarf; - const char *exe_filename; - int exe_descriptor; -}; - -/* Callback passed to dl_iterate_phdr. Load debug info from shared - libraries. */ - -static int -#ifdef __i386__ -__attribute__ ((__force_align_arg_pointer__)) -#endif -phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, - void *pdata) -{ - struct phdr_data *pd = (struct phdr_data *) pdata; - const char *filename; - int descriptor; - int does_not_exist; - fileline elf_fileline_fn; - int found_dwarf; - - /* There is not much we can do if we don't have the module name, - unless executable is ET_DYN, where we expect the very first - phdr_callback to be for the PIE. */ - if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') - { - if (pd->exe_descriptor == -1) - return 0; - filename = pd->exe_filename; - descriptor = pd->exe_descriptor; - pd->exe_descriptor = -1; - } - else - { - if (pd->exe_descriptor != -1) - { - backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); - pd->exe_descriptor = -1; - } - - filename = info->dlpi_name; - descriptor = backtrace_open (info->dlpi_name, pd->error_callback, - pd->data, &does_not_exist); - if (descriptor < 0) - return 0; - } - - if (elf_add (pd->state, filename, descriptor, info->dlpi_addr, - pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym, - &found_dwarf, NULL, 0, 0, NULL, 0)) - { - if (found_dwarf) - { - *pd->found_dwarf = 1; - *pd->fileline_fn = elf_fileline_fn; - } - } - - return 0; -} - -/* Initialize the backtrace data we need from an ELF executable. At - the ELF level, all we need to do is find the debug info - sections. */ - -int -backtrace_initialize (struct backtrace_state *state, const char *filename, - int descriptor, backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - int found_sym; - int found_dwarf; - fileline elf_fileline_fn = elf_nodebug; - struct phdr_data pd; - - ret = elf_add (state, filename, descriptor, 0, error_callback, data, - &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL, - 0); - if (!ret) - return 0; - - pd.state = state; - pd.error_callback = error_callback; - pd.data = data; - pd.fileline_fn = &elf_fileline_fn; - pd.found_sym = &found_sym; - pd.found_dwarf = &found_dwarf; - pd.exe_filename = filename; - pd.exe_descriptor = ret < 0 ? descriptor : -1; - - dl_iterate_phdr (phdr_callback, (void *) &pd); - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = elf_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = elf_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); - else - (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, - elf_nosyms); - } - - if (!state->threaded) - *fileline_fn = state->fileline_fn; - else - *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - - if (*fileline_fn == NULL || *fileline_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - - return 1; -} diff --git a/3rdparty/libbacktrace/libbacktrace/fileline.c b/3rdparty/libbacktrace/libbacktrace/fileline.c deleted file mode 100644 index 369c9dee..00000000 --- a/3rdparty/libbacktrace/libbacktrace/fileline.c +++ /dev/null @@ -1,201 +0,0 @@ -/* fileline.c -- Get file and line number information in a backtrace. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef HAVE_GETEXECNAME -#define getexecname() NULL -#endif - -/* Initialize the fileline information from the executable. Returns 1 - on success, 0 on failure. */ - -static int -fileline_initialize (struct backtrace_state *state, - backtrace_error_callback error_callback, void *data) -{ - int failed; - fileline fileline_fn; - int pass; - int called_error_callback; - int descriptor; - const char *filename; - char buf[64]; - - if (!state->threaded) - failed = state->fileline_initialization_failed; - else - failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); - - if (failed) - { - error_callback (data, "failed to read executable information", -1); - return 0; - } - - if (!state->threaded) - fileline_fn = state->fileline_fn; - else - fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (fileline_fn != NULL) - return 1; - - /* We have not initialized the information. Do it now. */ - - descriptor = -1; - called_error_callback = 0; - for (pass = 0; pass < 5; ++pass) - { - int does_not_exist; - - switch (pass) - { - case 0: - filename = state->filename; - break; - case 1: - filename = getexecname (); - break; - case 2: - filename = "/proc/self/exe"; - break; - case 3: - filename = "/proc/curproc/file"; - break; - case 4: - snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", - (long) getpid ()); - filename = buf; - break; - default: - abort (); - } - - if (filename == NULL) - continue; - - descriptor = backtrace_open (filename, error_callback, data, - &does_not_exist); - if (descriptor < 0 && !does_not_exist) - { - called_error_callback = 1; - break; - } - if (descriptor >= 0) - break; - } - - if (descriptor < 0) - { - if (!called_error_callback) - { - if (state->filename != NULL) - error_callback (data, state->filename, ENOENT); - else - error_callback (data, - "libbacktrace could not find executable to open", - 0); - } - failed = 1; - } - - if (!failed) - { - if (!backtrace_initialize (state, filename, descriptor, error_callback, - data, &fileline_fn)) - failed = 1; - } - - if (failed) - { - if (!state->threaded) - state->fileline_initialization_failed = 1; - else - backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); - return 0; - } - - if (!state->threaded) - state->fileline_fn = fileline_fn; - else - { - backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); - - /* Note that if two threads initialize at once, one of the data - sets may be leaked. */ - } - - return 1; -} - -/* Given a PC, find the file name, line number, and function name. */ - -int -backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - return state->fileline_fn (state, pc, callback, error_callback, data); -} - -/* Given a PC, find the symbol for it, and its value. */ - -int -backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - state->syminfo_fn (state, pc, callback, error_callback, data); - return 1; -} diff --git a/3rdparty/libbacktrace/libbacktrace/internal.h b/3rdparty/libbacktrace/libbacktrace/internal.h deleted file mode 100644 index a9c66882..00000000 --- a/3rdparty/libbacktrace/libbacktrace/internal.h +++ /dev/null @@ -1,338 +0,0 @@ -/* internal.h -- Internal header file for stack backtrace library. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_INTERNAL_H -#define BACKTRACE_INTERNAL_H - -/* We assume that and "backtrace.h" have already been - included. */ - -#ifndef GCC_VERSION -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -#ifndef ATTRIBUTE_MALLOC -# if (GCC_VERSION >= 2096) -# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) -# else -# define ATTRIBUTE_MALLOC -# endif -#endif - -#ifndef HAVE_SYNC_FUNCTIONS - -/* Define out the sync functions. These should never be called if - they are not available. */ - -#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1) -#define __sync_lock_test_and_set(A, B) (abort(), 0) -#define __sync_lock_release(A) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ - -#ifdef HAVE_ATOMIC_FUNCTIONS - -/* We have the atomic builtin functions. */ - -#define backtrace_atomic_load_pointer(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_load_int(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_store_pointer(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_size_t(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_int(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) - -#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ -#ifdef HAVE_SYNC_FUNCTIONS - -/* We have the sync functions but not the atomic functions. Define - the atomic ones in terms of the sync ones. */ - -extern void *backtrace_atomic_load_pointer (void *); -extern int backtrace_atomic_load_int (int *); -extern void backtrace_atomic_store_pointer (void *, void *); -extern void backtrace_atomic_store_size_t (size_t *, size_t); -extern void backtrace_atomic_store_int (int *, int); - -#else /* !defined (HAVE_SYNC_FUNCTIONS) */ - -/* We have neither the sync nor the atomic functions. These will - never be called. */ - -#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) -#define backtrace_atomic_load_int(p) (abort(), 0) -#define backtrace_atomic_store_pointer(p, v) abort() -#define backtrace_atomic_store_size_t(p, v) abort() -#define backtrace_atomic_store_int(p, v) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ -#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ - -/* The type of the function that collects file/line information. This - is like backtrace_pcinfo. */ - -typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data); - -/* The type of the function that collects symbol information. This is - like backtrace_syminfo. */ - -typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data); - -/* What the backtrace state pointer points to. */ - -struct backtrace_state -{ - /* The name of the executable. */ - const char *filename; - /* Non-zero if threaded. */ - int threaded; - /* The master lock for fileline_fn, fileline_data, syminfo_fn, - syminfo_data, fileline_initialization_failed and everything the - data pointers point to. */ - void *lock; - /* The function that returns file/line information. */ - fileline fileline_fn; - /* The data to pass to FILELINE_FN. */ - void *fileline_data; - /* The function that returns symbol information. */ - syminfo syminfo_fn; - /* The data to pass to SYMINFO_FN. */ - void *syminfo_data; - /* Whether initializing the file/line information failed. */ - int fileline_initialization_failed; - /* The lock for the freelist. */ - int lock_alloc; - /* The freelist when using mmap. */ - struct backtrace_freelist_struct *freelist; -}; - -/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST - is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1 - if the file does not exist. If the file does not exist and - DOES_NOT_EXIST is not NULL, the function will return -1 and will - not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is - NULL, the function will call ERROR_CALLBACK before returning. */ -extern int backtrace_open (const char *filename, - backtrace_error_callback error_callback, - void *data, - int *does_not_exist); - -/* A view of the contents of a file. This supports mmap when - available. A view will remain in memory even after backtrace_close - is called on the file descriptor from which the view was - obtained. */ - -struct backtrace_view -{ - /* The data that the caller requested. */ - const void *data; - /* The base of the view. */ - void *base; - /* The total length of the view. */ - size_t len; -}; - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the - result in *VIEW. Returns 1 on success, 0 on error. */ -extern int backtrace_get_view (struct backtrace_state *state, int descriptor, - off_t offset, uint64_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view); - -/* Release a view created by backtrace_get_view. */ -extern void backtrace_release_view (struct backtrace_state *state, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data); - -/* Close a file opened by backtrace_open. Returns 1 on success, 0 on - error. */ - -extern int backtrace_close (int descriptor, - backtrace_error_callback error_callback, - void *data); - -/* Sort without using memory. */ - -extern void backtrace_qsort (void *base, size_t count, size_t size, - int (*compar) (const void *, const void *)); - -/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, - this does not report an error, it just returns NULL. */ - -extern void *backtrace_alloc (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data) ATTRIBUTE_MALLOC; - -/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is - NULL, this does not report an error. */ - -extern void backtrace_free (struct backtrace_state *state, void *mem, - size_t size, - backtrace_error_callback error_callback, - void *data); - -/* A growable vector of some struct. This is used for more efficient - allocation when we don't know the final size of some group of data - that we want to represent as an array. */ - -struct backtrace_vector -{ - /* The base of the vector. */ - void *base; - /* The number of bytes in the vector. */ - size_t size; - /* The number of bytes available at the current allocation. */ - size_t alc; -}; - -/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated - bytes. Note that this may move the entire vector to a new memory - location. Returns NULL on failure. */ - -extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data, - struct backtrace_vector *vec); - -/* Finish the current allocation on VEC. Prepare to start a new - allocation. The finished allocation will never be freed. Returns - a pointer to the base of the finished entries, or NULL on - failure. */ - -extern void* backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Release any extra space allocated for VEC. This may change - VEC->base. Returns 1 on success, 0 on failure. */ - -extern int backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Free the space managed by VEC. This will reset VEC. */ - -static inline void -backtrace_vector_free (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, void *data) -{ - vec->alc += vec->size; - vec->size = 0; - backtrace_vector_release (state, vec, error_callback, data); -} - -/* Read initial debug data from a descriptor, and set the - fileline_data, syminfo_fn, and syminfo_data fields of STATE. - Return the fileln_fn field in *FILELN_FN--this is done this way so - that the synchronization code is only implemented once. This is - called after the descriptor has first been opened. It will close - the descriptor if it is no longer needed. Returns 1 on success, 0 - on error. There will be multiple implementations of this function, - for different file formats. Each system will compile the - appropriate one. */ - -extern int backtrace_initialize (struct backtrace_state *state, - const char *filename, - int descriptor, - backtrace_error_callback error_callback, - void *data, - fileline *fileline_fn); - -/* An enum for the DWARF sections we care about. */ - -enum dwarf_section -{ - DEBUG_INFO, - DEBUG_LINE, - DEBUG_ABBREV, - DEBUG_RANGES, - DEBUG_STR, - DEBUG_ADDR, - DEBUG_STR_OFFSETS, - DEBUG_LINE_STR, - DEBUG_RNGLISTS, - - DEBUG_MAX -}; - -/* Data for the DWARF sections we care about. */ - -struct dwarf_sections -{ - const unsigned char *data[DEBUG_MAX]; - size_t size[DEBUG_MAX]; -}; - -/* DWARF data read from a file, used for .gnu_debugaltlink. */ - -struct dwarf_data; - -/* Add file/line information for a DWARF module. */ - -extern int backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const struct dwarf_sections *dwarf_sections, - int is_bigendian, - struct dwarf_data *fileline_altlink, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, - struct dwarf_data **fileline_entry); - -/* A test-only hook for elf_uncompress_zdebug. */ - -extern int backtrace_uncompress_zdebug (struct backtrace_state *, - const unsigned char *compressed, - size_t compressed_size, - backtrace_error_callback, void *data, - unsigned char **uncompressed, - size_t *uncompressed_size); - -#endif diff --git a/3rdparty/libbacktrace/libbacktrace/macho.c b/3rdparty/libbacktrace/libbacktrace/macho.c deleted file mode 100644 index b16b7710..00000000 --- a/3rdparty/libbacktrace/libbacktrace/macho.c +++ /dev/null @@ -1,1471 +0,0 @@ -/* macho.c -- Get debug data from an Mach-O file for backtraces. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by John Colanduoni. - - Pending upstream pull request: - https://github.com/ianlancetaylor/libbacktrace/pull/2 - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -/* We can't use autotools to detect the pointer width of our program because - we may be building a fat Mach-O file containing both 32-bit and 64-bit - variants. However Mach-O runs a limited set of platforms so detection - via preprocessor is not difficult. */ - -#if defined(__MACH__) -#if defined(__LP64__) -#define BACKTRACE_BITS 64 -#else -#define BACKTRACE_BITS 32 -#endif -#else -#error Attempting to build Mach-O support on incorrect platform -#endif - -#if defined(__x86_64__) -#define NATIVE_CPU_TYPE CPU_TYPE_X86_64 -#elif defined(__i386__) -#define NATIVE_CPU_TYPE CPU_TYPE_X86 -#elif defined(__aarch64__) -#define NATIVE_CPU_TYPE CPU_TYPE_ARM64 -#elif defined(__arm__) -#define NATIVE_CPU_TYPE CPU_TYPE_ARM -#else -#error Could not detect native Mach-O cpu_type_t -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -struct macho_commands_view -{ - struct backtrace_view view; - uint32_t commands_count; - uint32_t commands_total_size; - int bytes_swapped; - size_t base_offset; -}; - -static const char *const debug_section_names[DEBUG_MAX] = - { - "__debug_info", - "__debug_line", - "__debug_abbrev", - "__debug_ranges", - "__debug_str", - "", - "__debug_str_offs", - "", - "__debug_rnglists" - }; - -struct found_dwarf_section -{ - uint32_t file_offset; - uintptr_t file_size; - const unsigned char *data; -}; - -/* Mach-O symbols don't have a length. As a result we have to infer it - by sorting the symbol addresses for each image and recording the - memory range attributed to each image. */ -struct macho_symbol -{ - uintptr_t addr; - size_t size; - const char *name; -}; - -struct macho_syminfo_data -{ - struct macho_syminfo_data *next; - struct macho_symbol *symbols; - size_t symbol_count; - uintptr_t min_addr; - uintptr_t max_addr; -}; - -uint16_t -macho_file_to_host_u16 (int file_bytes_swapped, uint16_t input) -{ - if (file_bytes_swapped) - return (input >> 8) | (input << 8); - else - return input; -} - -uint32_t -macho_file_to_host_u32 (int file_bytes_swapped, uint32_t input) -{ - if (file_bytes_swapped) - { - return ((input >> 24) & 0x000000FF) - | ((input >> 8) & 0x0000FF00) - | ((input << 8) & 0x00FF0000) - | ((input << 24) & 0xFF000000); - } - else - { - return input; - } -} - -uint64_t -macho_file_to_host_u64 (int file_bytes_swapped, uint64_t input) -{ - if (file_bytes_swapped) - { - return macho_file_to_host_u32 (file_bytes_swapped, - (uint32_t) (input >> 32)) - | (((uint64_t) macho_file_to_host_u32 (file_bytes_swapped, - (uint32_t) input)) << 32); - } - else - { - return input; - } -} - -#if BACKTRACE_BITS == 64 -#define macho_file_to_host_usize macho_file_to_host_u64 -typedef struct mach_header_64 mach_header_native_t; -#define LC_SEGMENT_NATIVE LC_SEGMENT_64 -typedef struct segment_command_64 segment_command_native_t; -typedef struct nlist_64 nlist_native_t; -typedef struct section_64 section_native_t; -#else /* BACKTRACE_BITS == 32 */ -#define macho_file_to_host_usize macho_file_to_host_u32 -typedef struct mach_header mach_header_native_t; -#define LC_SEGMENT_NATIVE LC_SEGMENT -typedef struct segment_command segment_command_native_t; -typedef struct nlist nlist_native_t; -typedef struct section section_native_t; -#endif - -// Gets a view into a Mach-O image, taking any slice offset into account -int -macho_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - struct backtrace_view *view) -{ - return backtrace_get_view (state, descriptor, - commands_view->base_offset + offset, size, - error_callback, data, view); -} - -int -macho_get_commands (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - int *incompatible) -{ - int ret = 0; - int is_fat = 0; - struct backtrace_view file_header_view; - int file_header_view_valid = 0; - struct backtrace_view fat_archs_view; - int fat_archs_view_valid = 0; - const mach_header_native_t *file_header; - uint64_t commands_offset; - - *incompatible = 0; - - if (!backtrace_get_view (state, descriptor, 0, sizeof (mach_header_native_t), - error_callback, data, &file_header_view)) - goto end; - file_header_view_valid = 1; - - switch (*(uint32_t *) file_header_view.data) - { - case MH_MAGIC: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 0; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_CIGAM: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 1; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_MAGIC_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 0; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_CIGAM_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 1; - else - { - *incompatible = 1; - goto end; - } - break; - case FAT_MAGIC: - is_fat = 1; - commands_view->bytes_swapped = 0; - break; - case FAT_CIGAM: - is_fat = 1; - commands_view->bytes_swapped = 1; - break; - default: - goto end; - } - - if (is_fat) - { - uint32_t native_slice_offset; - size_t archs_total_size; - uint32_t arch_count; - const struct fat_header *fat_header; - const struct fat_arch *archs; - uint32_t i; - - fat_header = file_header_view.data; - arch_count = - macho_file_to_host_u32 (commands_view->bytes_swapped, - fat_header->nfat_arch); - - archs_total_size = arch_count * sizeof (struct fat_arch); - - if (!backtrace_get_view (state, descriptor, sizeof (struct fat_header), - archs_total_size, error_callback, - data, &fat_archs_view)) - goto end; - fat_archs_view_valid = 1; - - native_slice_offset = 0; - archs = fat_archs_view.data; - for (i = 0; i < arch_count; i++) - { - const struct fat_arch *raw_arch = archs + i; - int cpu_type = - (int) macho_file_to_host_u32 (commands_view->bytes_swapped, - (uint32_t) raw_arch->cputype); - - if (cpu_type == NATIVE_CPU_TYPE) - { - native_slice_offset = - macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_arch->offset); - - break; - } - } - - if (native_slice_offset == 0) - { - *incompatible = 1; - goto end; - } - - backtrace_release_view (state, &file_header_view, error_callback, data); - file_header_view_valid = 0; - if (!backtrace_get_view (state, descriptor, native_slice_offset, - sizeof (mach_header_native_t), error_callback, - data, &file_header_view)) - goto end; - file_header_view_valid = 1; - - // The endianess of the slice may be different than the fat image - switch (*(uint32_t *) file_header_view.data) - { - case MH_MAGIC: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 0; - else - goto end; - break; - case MH_CIGAM: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 1; - else - goto end; - break; - case MH_MAGIC_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 0; - else - goto end; - break; - case MH_CIGAM_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 1; - else - goto end; - break; - default: - goto end; - } - - commands_view->base_offset = native_slice_offset; - } - else - commands_view->base_offset = 0; - - file_header = file_header_view.data; - commands_view->commands_count = - macho_file_to_host_u32 (commands_view->bytes_swapped, - file_header->ncmds); - commands_view->commands_total_size = - macho_file_to_host_u32 (commands_view->bytes_swapped, - file_header->sizeofcmds); - commands_offset = - commands_view->base_offset + sizeof (mach_header_native_t); - - if (!backtrace_get_view (state, descriptor, commands_offset, - commands_view->commands_total_size, error_callback, - data, &commands_view->view)) - goto end; - - ret = 1; - -end: - if (file_header_view_valid) - backtrace_release_view (state, &file_header_view, error_callback, data); - if (fat_archs_view_valid) - backtrace_release_view (state, &fat_archs_view, error_callback, data); - return ret; -} - -int -macho_get_uuid (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - uuid_t *uuid) -{ - size_t offset = 0; - uint32_t i = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = - commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_UUID) - { - const struct uuid_command *uuid_command; - - if (offset + sizeof (struct uuid_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - uuid_command = - (struct uuid_command *) raw_command; - memcpy (uuid, uuid_command->uuid, sizeof (uuid_t)); - return 1; - } - - offset += command.cmdsize; - } - - error_callback (data, "executable file is missing an identifying UUID", 0); - return 0; -} - -/* Returns the base address of a Mach-O image, as encoded in the file header. - * WARNING: This does not take ASLR into account, which is ubiquitous on recent - * Darwin platforms. - */ -int -macho_get_addr_range (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - uintptr_t *base_address, uintptr_t *max_address) -{ - size_t offset = 0; - int found_text = 0; - uint32_t i = 0; - - *max_address = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SEGMENT_NATIVE) - { - const segment_command_native_t *raw_segment; - uintptr_t segment_vmaddr; - uintptr_t segment_vmsize; - uintptr_t segment_maxaddr; - uintptr_t text_fileoff; - - if (offset + sizeof (segment_command_native_t) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_segment = (segment_command_native_t *) raw_command; - - segment_vmaddr = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->vmaddr); - segment_vmsize = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->vmsize); - segment_maxaddr = segment_vmaddr + segment_vmsize; - - if (strncmp (raw_segment->segname, "__TEXT", - sizeof (raw_segment->segname)) == 0) - { - text_fileoff = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->fileoff); - *base_address = segment_vmaddr - text_fileoff; - - found_text = 1; - } - - if (segment_maxaddr > *max_address) - *max_address = segment_maxaddr; - } - - offset += command.cmdsize; - } - - if (found_text) - return 1; - else - { - error_callback (data, "executable is missing __TEXT segment", 0); - return 0; - } -} - -static int -macho_symbol_compare_addr (const void *left_raw, const void *right_raw) -{ - const struct macho_symbol *left = left_raw; - const struct macho_symbol *right = right_raw; - - if (left->addr > right->addr) - return 1; - else if (left->addr < right->addr) - return -1; - else - return 0; -} - -int -macho_symbol_type_relevant (uint8_t type) -{ - uint8_t type_field = (uint8_t) (type & N_TYPE); - - return (type_field == N_ABS || type_field == N_SECT); -} - -int -macho_add_symtab (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, int descriptor, - struct macho_commands_view *commands_view, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, int *found_sym) -{ - struct macho_syminfo_data *syminfo_data; - - int ret = 0; - size_t offset = 0; - struct backtrace_view symtab_view; - int symtab_view_valid = 0; - struct backtrace_view strtab_view; - int strtab_view_valid = 0; - size_t syminfo_index = 0; - size_t function_count = 0; - uint32_t i = 0; - uint32_t j = 0; - uint32_t symtab_index = 0; - - *found_sym = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SYMTAB) - { - const struct symtab_command *symtab_command; - uint32_t symbol_table_offset; - uint32_t symbol_count; - uint32_t string_table_offset; - uint32_t string_table_size; - - if (offset + sizeof (struct symtab_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - symtab_command = (struct symtab_command *) raw_command; - - symbol_table_offset = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->symoff); - symbol_count = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->nsyms); - string_table_offset = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->stroff); - string_table_size = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->strsize); - - - if (!macho_get_view (state, descriptor, symbol_table_offset, - symbol_count * sizeof (nlist_native_t), - error_callback, data, commands_view, - &symtab_view)) - goto end; - symtab_view_valid = 1; - - if (!macho_get_view (state, descriptor, string_table_offset, - string_table_size, error_callback, data, - commands_view, &strtab_view)) - goto end; - strtab_view_valid = 1; - - // Count functions first - for (j = 0; j < symbol_count; j++) - { - const nlist_native_t *raw_sym = - ((const nlist_native_t *) symtab_view.data) + j; - - if (macho_symbol_type_relevant (raw_sym->n_type)) - { - function_count += 1; - } - } - - // Allocate space for the: - // (a) macho_syminfo_data for this image - // (b) macho_symbol entries - syminfo_data = - backtrace_alloc (state, - sizeof (struct macho_syminfo_data), - error_callback, data); - if (syminfo_data == NULL) - goto end; - - syminfo_data->symbols = backtrace_alloc ( - state, function_count * sizeof (struct macho_symbol), - error_callback, data); - if (syminfo_data->symbols == NULL) - goto end; - - syminfo_data->symbol_count = function_count; - syminfo_data->next = NULL; - syminfo_data->min_addr = base_address; - syminfo_data->max_addr = max_image_address; - - for (symtab_index = 0; - symtab_index < symbol_count; symtab_index++) - { - const nlist_native_t *raw_sym = - ((const nlist_native_t *) symtab_view.data) + - symtab_index; - - if (macho_symbol_type_relevant (raw_sym->n_type)) - { - size_t strtab_index; - const char *name; - size_t max_len_plus_one; - - syminfo_data->symbols[syminfo_index].addr = - macho_file_to_host_usize (commands_view->bytes_swapped, - raw_sym->n_value) + vmslide; - - strtab_index = macho_file_to_host_u32 ( - commands_view->bytes_swapped, - raw_sym->n_un.n_strx); - - // Check the range of the supposed "string" we've been - // given - if (strtab_index >= string_table_size) - { - error_callback ( - data, - "dSYM file contains out of range string table index", - 0); - goto end; - } - - name = strtab_view.data + strtab_index; - max_len_plus_one = string_table_size - strtab_index; - - if (strnlen (name, max_len_plus_one) >= max_len_plus_one) - { - error_callback ( - data, - "dSYM file contains unterminated string", - 0); - goto end; - } - - // Remove underscore prefixes - if (name[0] == '_') - { - name = name + 1; - } - - syminfo_data->symbols[syminfo_index].name = name; - - syminfo_index += 1; - } - } - - backtrace_qsort (syminfo_data->symbols, - syminfo_data->symbol_count, - sizeof (struct macho_symbol), - macho_symbol_compare_addr); - - // Calculate symbol sizes - for (syminfo_index = 0; - syminfo_index < syminfo_data->symbol_count; syminfo_index++) - { - if (syminfo_index + 1 < syminfo_data->symbol_count) - { - syminfo_data->symbols[syminfo_index].size = - syminfo_data->symbols[syminfo_index + 1].addr - - syminfo_data->symbols[syminfo_index].addr; - } - else - { - syminfo_data->symbols[syminfo_index].size = - max_image_address - - syminfo_data->symbols[syminfo_index].addr; - } - } - - if (!state->threaded) - { - struct macho_syminfo_data **pp; - - for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next); - *pp = syminfo_data; - } - else - { - while (1) - { - struct macho_syminfo_data **pp; - - pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct macho_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, syminfo_data)) - break; - } - } - - strtab_view_valid = 0; // We need to keep string table around - *found_sym = 1; - ret = 1; - goto end; - } - - offset += command.cmdsize; - } - - // No symbol table here - ret = 1; - goto end; - -end: - if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); - if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); - return ret; -} - -int -macho_try_dwarf (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, uuid_t *executable_uuid, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, char *dwarf_filename, int *matched, - int *found_sym, int *found_dwarf) -{ - uuid_t dwarf_uuid; - - int ret = 0; - int dwarf_descriptor; - int dwarf_descriptor_valid = 0; - struct macho_commands_view commands_view; - int commands_view_valid = 0; - struct backtrace_view dwarf_view; - int dwarf_view_valid = 0; - size_t offset = 0; - struct found_dwarf_section sections[DEBUG_MAX]; - struct dwarf_sections dwarf_sections; - uintptr_t min_dwarf_offset = 0; - uintptr_t max_dwarf_offset = 0; - uint32_t i = 0; - uint32_t j = 0; - int k = 0; - - *matched = 0; - *found_sym = 0; - *found_dwarf = 0; - - if ((dwarf_descriptor = backtrace_open (dwarf_filename, error_callback, - data, NULL)) == 0) - goto end; - dwarf_descriptor_valid = 1; - - int incompatible; - if (!macho_get_commands (state, dwarf_descriptor, error_callback, data, - &commands_view, &incompatible)) - { - // Failing to read the header here is fine, because this dSYM may be - // for a different architecture - if (incompatible) - { - ret = 1; - } - goto end; - } - commands_view_valid = 1; - - // Get dSYM UUID and compare - if (!macho_get_uuid (state, dwarf_descriptor, error_callback, data, - &commands_view, &dwarf_uuid)) - { - error_callback (data, "dSYM file is missing an identifying uuid", 0); - goto end; - } - if (memcmp (executable_uuid, &dwarf_uuid, sizeof (uuid_t)) != 0) - { - // DWARF doesn't belong to desired executable - ret = 1; - goto end; - } - - *matched = 1; - - // Read symbol table - if (!macho_add_symtab (state, error_callback, data, dwarf_descriptor, - &commands_view, base_address, max_image_address, - vmslide, found_sym)) - goto end; - - // Get DWARF sections - - memset (sections, 0, sizeof (sections)); - offset = 0; - for (i = 0; i < commands_view.commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", 0); - goto end; - } - - raw_command = commands_view.view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view.bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view.bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SEGMENT_NATIVE) - { - uint32_t section_count; - size_t section_offset; - const segment_command_native_t *raw_segment; - - if (offset + sizeof (segment_command_native_t) - > commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", - 0); - goto end; - } - - raw_segment = (const segment_command_native_t *) raw_command; - - if (strncmp (raw_segment->segname, "__DWARF", - sizeof (raw_segment->segname)) == 0) - { - section_count = macho_file_to_host_u32 ( - commands_view.bytes_swapped, - raw_segment->nsects); - - section_offset = offset + sizeof (segment_command_native_t); - - // Search sections for relevant DWARF section names - for (j = 0; j < section_count; j++) - { - const section_native_t *raw_section; - - if (section_offset + sizeof (section_native_t) > - commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", - 0); - goto end; - } - - raw_section = commands_view.view.data + section_offset; - - for (k = 0; k < DEBUG_MAX; k++) - { - uintptr_t dwarf_section_end; - - if (debug_section_names[k][0] != '\0' && - strncmp (raw_section->sectname, - debug_section_names[k], - sizeof (raw_section->sectname)) == 0) - { - *found_dwarf = 1; - - sections[k].file_offset = - macho_file_to_host_u32 ( - commands_view.bytes_swapped, - raw_section->offset); - sections[k].file_size = - macho_file_to_host_usize ( - commands_view.bytes_swapped, - raw_section->size); - - if (min_dwarf_offset == 0 || - sections[k].file_offset < - min_dwarf_offset) - min_dwarf_offset = sections[k].file_offset; - - dwarf_section_end = - sections[k].file_offset + - sections[k].file_size; - if (dwarf_section_end > max_dwarf_offset) - max_dwarf_offset = dwarf_section_end; - - break; - } - } - - section_offset += sizeof (section_native_t); - } - - break; - } - } - - offset += command.cmdsize; - } - - if (!*found_dwarf) - { - // No DWARF in this file - ret = 1; - goto end; - } - - if (!macho_get_view (state, dwarf_descriptor, (off_t) min_dwarf_offset, - max_dwarf_offset - min_dwarf_offset, error_callback, - data, &commands_view, &dwarf_view)) - goto end; - dwarf_view_valid = 1; - - for (i = 0; i < DEBUG_MAX; i++) - { - if (sections[i].file_offset == 0) - dwarf_sections.data[i] = NULL; - else - dwarf_sections.data[i] = - dwarf_view.data + sections[i].file_offset - min_dwarf_offset; - - dwarf_sections.size[i] = sections[i].file_size; - } - - if (!backtrace_dwarf_add (state, vmslide, - &dwarf_sections, - ((__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN)^ commands_view.bytes_swapped), - NULL, /* altlink */ - error_callback, data, fileline_fn, - NULL /* returned fileline_entry */)) - goto end; - - // Don't release the DWARF view because it is still in use - dwarf_descriptor_valid = 0; - dwarf_view_valid = 0; - ret = 1; - -end: - if (dwarf_descriptor_valid) - backtrace_close (dwarf_descriptor, error_callback, data); - if (commands_view_valid) - backtrace_release_view (state, &commands_view.view, error_callback, data); - if (dwarf_view_valid) - backtrace_release_view (state, &dwarf_view, error_callback, data); - return ret; -} - -int -macho_try_dsym (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, uuid_t *executable_uuid, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, char *dsym_filename, int *matched, - int *found_sym, int *found_dwarf) -{ - int ret = 0; - char dwarf_image_dir_path[PATH_MAX]; - DIR *dwarf_image_dir; - int dwarf_image_dir_valid = 0; - struct dirent *directory_entry; - char dwarf_filename[PATH_MAX]; - int dwarf_matched; - int dwarf_had_sym; - int dwarf_had_dwarf; - - *matched = 0; - *found_sym = 0; - *found_dwarf = 0; - - strncpy (dwarf_image_dir_path, dsym_filename, PATH_MAX); - strncat (dwarf_image_dir_path, "/Contents/Resources/DWARF", PATH_MAX); - - if (!(dwarf_image_dir = opendir (dwarf_image_dir_path))) - { - error_callback (data, "could not open DWARF directory in dSYM", - 0); - goto end; - } - dwarf_image_dir_valid = 1; - - while ((directory_entry = readdir (dwarf_image_dir))) - { - if (directory_entry->d_type != DT_REG) - continue; - - strncpy (dwarf_filename, dwarf_image_dir_path, PATH_MAX); - strncat (dwarf_filename, "/", PATH_MAX); - strncat (dwarf_filename, directory_entry->d_name, PATH_MAX); - - if (!macho_try_dwarf (state, error_callback, data, fileline_fn, - executable_uuid, base_address, max_image_address, - vmslide, dwarf_filename, - &dwarf_matched, &dwarf_had_sym, &dwarf_had_dwarf)) - goto end; - - if (dwarf_matched) - { - *matched = 1; - *found_sym = dwarf_had_sym; - *found_dwarf = dwarf_had_dwarf; - ret = 1; - goto end; - } - } - - // No matching DWARF in this dSYM - ret = 1; - goto end; - -end: - if (dwarf_image_dir_valid) - closedir (dwarf_image_dir); - return ret; -} - -int -macho_add (struct backtrace_state *state, - backtrace_error_callback error_callback, void *data, int descriptor, - const char *filename, fileline *fileline_fn, intptr_t vmslide, - int *found_sym, int *found_dwarf) -{ - uuid_t image_uuid; - uintptr_t image_file_base_address; - uintptr_t image_file_max_address; - uintptr_t image_actual_base_address = 0; - uintptr_t image_actual_max_address = 0; - - int ret = 0; - struct macho_commands_view commands_view; - int commands_view_valid = 0; - char executable_dirname[PATH_MAX]; - size_t filename_len; - DIR *executable_dir = NULL; - int executable_dir_valid = 0; - struct dirent *directory_entry; - char dsym_full_path[PATH_MAX]; - static const char *extension; - size_t extension_len; - ssize_t i; - - static const char *framework = ".framework"; - size_t framework_len = strlen (framework); - char full_framework_dbsym[PATH_MAX]; - char* framework_path = 0; - - int matched; - int dsym_had_sym; - int dsym_had_dwarf; - - *found_sym = 0; - *found_dwarf = 0; - - // Find Mach-O commands list - int incompatible; - if (!macho_get_commands (state, descriptor, error_callback, data, - &commands_view, &incompatible)) - goto end; - commands_view_valid = 1; - - // First we need to get the uuid of our file so we can hunt down the correct - // dSYM - if (!macho_get_uuid (state, descriptor, error_callback, data, &commands_view, - &image_uuid)) - goto end; - - // Now we need to find the in memory base address. Step one is to find out - // what the executable thinks the base address is - if (!macho_get_addr_range (state, descriptor, error_callback, data, - &commands_view, - &image_file_base_address, - &image_file_max_address)) - goto end; - - // As we use _dyld_get_image_header the vmslide is the actual base address already - image_actual_base_address = vmslide; - image_actual_max_address = - image_file_max_address + vmslide - image_file_base_address; - - //Calculate the vmslide from the real start address - vmslide = vmslide - image_file_base_address; - - if (image_actual_base_address == 0) - { - error_callback (data, "executable file is not loaded", 0); - goto end; - } - - // Look for dSYM in our executable's directory - strncpy (executable_dirname, filename, PATH_MAX); - filename_len = strlen (executable_dirname); - for (i = filename_len - 1; i >= 0; i--) - { - if (executable_dirname[i] == '/') - { - executable_dirname[i] = '\0'; - break; - } - else if (i == 0) - { - executable_dirname[0] = '.'; - executable_dirname[1] = '\0'; - break; - } - } - - if (!(executable_dir = opendir (executable_dirname))) - { - error_callback (data, "could not open directory containing executable", - 0); - goto end; - } - executable_dir_valid = 1; - - extension = ".dSYM"; - extension_len = strlen (extension); - - //Search for a dSYM in the executable path, this includes dylibs - while ((directory_entry = readdir (executable_dir))) - { - if (directory_entry->d_namlen < extension_len) - continue; - if (strncasecmp (directory_entry->d_name + directory_entry->d_namlen - - extension_len, extension, extension_len) == 0) - { - // Found a dSYM - strncpy (dsym_full_path, executable_dirname, PATH_MAX); - strncat (dsym_full_path, "/", PATH_MAX); - strncat (dsym_full_path, directory_entry->d_name, PATH_MAX); - - if (!macho_try_dsym (state, error_callback, data, - fileline_fn, &image_uuid, - image_actual_base_address, - image_actual_max_address, vmslide, - dsym_full_path, - &matched, &dsym_had_sym, &dsym_had_dwarf)) - goto end; - - if (matched) - { - *found_sym = dsym_had_sym; - *found_dwarf = dsym_had_dwarf; - ret = 1; - goto end; - } - } - } - - // If we couldn't find a dSYM in the executable path, check whether the library is from a - // framework and search for a dSYM in the special .framework.dSYM folder - framework_path = strstr(executable_dirname, framework); - if (framework_path) { - size_t new_len = framework_path - executable_dirname + framework_len; - strncpy (full_framework_dbsym, executable_dirname, new_len); - full_framework_dbsym[new_len] = '\0'; - strncat (full_framework_dbsym, extension, extension_len); - - DIR *framework_dir = NULL; - if ((framework_dir = opendir (full_framework_dbsym))) - { - closedir (framework_dir); - - if (!macho_try_dsym (state, error_callback, data, - fileline_fn, &image_uuid, - image_actual_base_address, - image_actual_max_address, vmslide, - full_framework_dbsym, - &matched, &dsym_had_sym, &dsym_had_dwarf)) - goto end; - - if (matched) - { - *found_sym = dsym_had_sym; - *found_dwarf = dsym_had_dwarf; - ret = 1; - goto end; - } - } - } - - strncpy (executable_dirname, filename, PATH_MAX); - - // If we still don't have a DSYM file, load the DWARF data from the lib itself. Although there - // is no DWARF data in libs on macos embedded, this makes sure the symtab is loaded and we can - // try to resolve the symbols - if (!macho_try_dwarf (state, error_callback, data, fileline_fn, - &image_uuid, image_actual_base_address, image_actual_max_address, - vmslide, executable_dirname, - &matched, &dsym_had_sym, &dsym_had_dwarf)) - goto end; - - if (matched) - { - *found_sym = dsym_had_sym; - *found_dwarf = dsym_had_dwarf; - ret = 1; - goto end; - } - - // No matching dSYM - ret = 1; - goto end; - -end: - if (commands_view_valid) - backtrace_release_view (state, &commands_view.view, error_callback, - data); - if (executable_dir_valid) - closedir (executable_dir); - return ret; -} - -static int -macho_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct macho_symbol *entry = (const struct macho_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->addr) - return -1; - else if (addr >= entry->addr + entry->size) - return 1; - else - return 0; -} - -static void -macho_syminfo (struct backtrace_state *state, - uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct macho_syminfo_data *edata; - struct macho_symbol *sym = NULL; - - if (!state->threaded) - { - for (edata = (struct macho_syminfo_data *) state->syminfo_data; - edata != NULL; - edata = edata->next) - { - if (addr >= edata->min_addr && addr <= edata->max_addr) - { - sym = ((struct macho_symbol *) - bsearch (&addr, edata->symbols, edata->symbol_count, - sizeof (struct macho_symbol), macho_symbol_search)); - if (sym != NULL) - break; - } - } - } - else - { - struct macho_syminfo_data **pp; - - pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - edata = backtrace_atomic_load_pointer (pp); - if (edata == NULL) - break; - - if (addr >= edata->min_addr && addr <= edata->max_addr) - { - sym = ((struct macho_symbol *) - bsearch (&addr, edata->symbols, edata->symbol_count, - sizeof (struct macho_symbol), macho_symbol_search)); - if (sym != NULL) - break; - } - - pp = &edata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->addr, sym->size); -} - - -static int -macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in Mach-O executable", -1); - return 0; -} - -static void -macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in Mach-O executable", -1); -} - -int -backtrace_initialize (struct backtrace_state *state, - const char *filename, - int descriptor, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - fileline macho_fileline_fn = macho_nodebug; - int found_sym = 0; - int found_dwarf = 0; - uint32_t i = 0; - uint32_t loaded_image_count; - - // Add all loaded images - loaded_image_count = _dyld_image_count (); - for (i = 0; i < loaded_image_count; i++) - { - - int current_found_sym; - int current_found_dwarf; - int current_descriptor; - intptr_t current_vmslide; - intptr_t image_header; - const char *current_name; - - current_vmslide = _dyld_get_image_vmaddr_slide (i); - image_header = _dyld_get_image_header(i); - current_name = _dyld_get_image_name (i); - - if (current_name == NULL || (i != 0 && current_vmslide == 0)) - continue; - - if (!(current_descriptor = - backtrace_open (current_name, error_callback, data, NULL))) - { - continue; - } - - if (macho_add (state, error_callback, data, current_descriptor, - current_name, &macho_fileline_fn, image_header, - ¤t_found_sym, ¤t_found_dwarf)) - { - found_sym = found_sym || current_found_sym; - found_dwarf = found_dwarf || current_found_dwarf; - } - - backtrace_close (current_descriptor, error_callback, data); - } - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = macho_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = macho_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo); - else - (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, - macho_nosyms); - } - - if (!state->threaded) - { - if (state->fileline_fn == NULL || state->fileline_fn == macho_nodebug) - *fileline_fn = macho_fileline_fn; - } - else - { - fileline current_fn; - - current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (current_fn == NULL || current_fn == macho_nodebug) - *fileline_fn = macho_fileline_fn; - } - - return 1; -} - diff --git a/3rdparty/libbacktrace/libbacktrace/mmap.c b/3rdparty/libbacktrace/libbacktrace/mmap.c deleted file mode 100644 index 1b636649..00000000 --- a/3rdparty/libbacktrace/libbacktrace/mmap.c +++ /dev/null @@ -1,327 +0,0 @@ -/* mmap.c -- Memory allocation with mmap. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Memory allocation on systems that provide anonymous mmap. This - permits the backtrace functions to be invoked from a signal - handler, assuming that mmap is async-signal safe. */ - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* A list of free memory blocks. */ - -struct backtrace_freelist_struct -{ - /* Next on list. */ - struct backtrace_freelist_struct *next; - /* Size of this block, including this structure. */ - size_t size; -}; - -/* Free memory allocated by backtrace_alloc. */ - -static void -backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) -{ - /* Just leak small blocks. We don't have to be perfect. Don't put - more than 16 entries on the free list, to avoid wasting time - searching when allocating a block. If we have more than 16 - entries, leak the smallest entry. */ - - if (size >= sizeof (struct backtrace_freelist_struct)) - { - size_t c; - struct backtrace_freelist_struct **ppsmall; - struct backtrace_freelist_struct **pp; - struct backtrace_freelist_struct *p; - - c = 0; - ppsmall = NULL; - for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) - { - if (ppsmall == NULL || (*pp)->size < (*ppsmall)->size) - ppsmall = pp; - ++c; - } - if (c >= 16) - { - if (size <= (*ppsmall)->size) - return; - *ppsmall = (*ppsmall)->next; - } - - p = (struct backtrace_freelist_struct *) addr; - p->next = state->freelist; - p->size = size; - state->freelist = p; - } -} - -/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't - report an error. */ - -void * -backtrace_alloc (struct backtrace_state *state, - size_t size, backtrace_error_callback error_callback, - void *data) -{ - void *ret; - int locked; - struct backtrace_freelist_struct **pp; - size_t pagesize; - size_t asksize; - void *page; - - ret = NULL; - - /* If we can acquire the lock, then see if there is space on the - free list. If we can't acquire the lock, drop straight into - using mmap. __sync_lock_test_and_set returns the old state of - the lock, so we have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->size >= size) - { - struct backtrace_freelist_struct *p; - - p = *pp; - *pp = p->next; - - /* Round for alignment; we assume that no type we care about - is more than 8 bytes. */ - size = (size + 7) & ~ (size_t) 7; - if (size < p->size) - backtrace_free_locked (state, (char *) p + size, - p->size - size); - - ret = (void *) p; - - break; - } - } - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } - - if (ret == NULL) - { - /* Allocate a new page. */ - - pagesize = getpagesize (); - asksize = (size + pagesize - 1) & ~ (pagesize - 1); - page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (page == MAP_FAILED) - { - if (error_callback) - error_callback (data, "mmap", errno); - } - else - { - size = (size + 7) & ~ (size_t) 7; - if (size < asksize) - backtrace_free (state, (char *) page + size, asksize - size, - error_callback, data); - - ret = page; - } - } - - return ret; -} - -/* Free memory allocated by backtrace_alloc. */ - -void -backtrace_free (struct backtrace_state *state, void *addr, size_t size, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - int locked; - - /* If we are freeing a large aligned block, just release it back to - the system. This case arises when growing a vector for a large - binary with lots of debug info. Calling munmap here may cause us - to call mmap again if there is also a large shared library; we - just live with that. */ - if (size >= 16 * 4096) - { - size_t pagesize; - - pagesize = getpagesize (); - if (((uintptr_t) addr & (pagesize - 1)) == 0 - && (size & (pagesize - 1)) == 0) - { - /* If munmap fails for some reason, just add the block to - the freelist. */ - if (munmap (addr, size) == 0) - return; - } - } - - /* If we can acquire the lock, add the new space to the free list. - If we can't acquire the lock, just leak the memory. - __sync_lock_test_and_set returns the old state of the lock, so we - have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - backtrace_free_locked (state, addr, size); - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } -} - -/* Grow VEC by SIZE bytes. */ - -void * -backtrace_vector_grow (struct backtrace_state *state,size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_vector *vec) -{ - void *ret; - - if (size > vec->alc) - { - size_t pagesize; - size_t alc; - void *base; - - pagesize = getpagesize (); - alc = vec->size + size; - if (vec->size == 0) - alc = 16 * size; - else if (alc < pagesize) - { - alc *= 2; - if (alc > pagesize) - alc = pagesize; - } - else - { - alc *= 2; - alc = (alc + pagesize - 1) & ~ (pagesize - 1); - } - base = backtrace_alloc (state, alc, error_callback, data); - if (base == NULL) - return NULL; - if (vec->base != NULL) - { - memcpy (base, vec->base, vec->size); - backtrace_free (state, vec->base, vec->size + vec->alc, - error_callback, data); - } - vec->base = base; - vec->alc = alc - vec->size; - } - - ret = (char *) vec->base + vec->size; - vec->size += size; - vec->alc -= size; - return ret; -} - -/* Finish the current allocation on VEC. */ - -void * -backtrace_vector_finish ( - struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - void *ret; - - ret = vec->base; - vec->base = (char *) vec->base + vec->size; - vec->size = 0; - return ret; -} - -/* Release any extra space allocated for VEC. */ - -int -backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - size_t size; - size_t alc; - size_t aligned; - - /* Make sure that the block that we free is aligned on an 8-byte - boundary. */ - size = vec->size; - alc = vec->alc; - aligned = (size + 7) & ~ (size_t) 7; - alc -= aligned - size; - - backtrace_free (state, (char *) vec->base + aligned, alc, - error_callback, data); - vec->alc = 0; - if (vec->size == 0) - vec->base = NULL; - return 1; -} diff --git a/3rdparty/libbacktrace/libbacktrace/mmapio.c b/3rdparty/libbacktrace/libbacktrace/mmapio.c deleted file mode 100644 index b188a43a..00000000 --- a/3rdparty/libbacktrace/libbacktrace/mmapio.c +++ /dev/null @@ -1,106 +0,0 @@ -/* mmapio.c -- File views using mmap. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* This file implements file views and memory allocation when mmap is - available. */ - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ - -int -backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor, off_t offset, uint64_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view) -{ - size_t pagesize; - unsigned int inpage; - off_t pageoff; - void *map; - - if ((uint64_t) (size_t) size != size) - { - error_callback (data, "file size too large", 0); - return 0; - } - - pagesize = getpagesize (); - inpage = offset % pagesize; - pageoff = offset - inpage; - - size += inpage; - size = (size + (pagesize - 1)) & ~ (pagesize - 1); - - map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff); - if (map == MAP_FAILED) - { - error_callback (data, "mmap", errno); - return 0; - } - - view->data = (char *) map + inpage; - view->base = map; - view->len = size; - - return 1; -} - -/* Release a view read by backtrace_get_view. */ - -void -backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data) -{ - union { - const void *cv; - void *v; - } const_cast; - - const_cast.cv = view->base; - if (munmap (const_cast.v, view->len) < 0) - error_callback (data, "munmap", errno); -} diff --git a/3rdparty/libbacktrace/libbacktrace/posix.c b/3rdparty/libbacktrace/libbacktrace/posix.c deleted file mode 100644 index baffb85b..00000000 --- a/3rdparty/libbacktrace/libbacktrace/posix.c +++ /dev/null @@ -1,100 +0,0 @@ -/* posix.c -- POSIX file I/O routines for the backtrace library. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - -/* Open a file for reading. */ - -int -backtrace_open (const char *filename, backtrace_error_callback error_callback, - void *data, int *does_not_exist) -{ - int descriptor; - - if (does_not_exist != NULL) - *does_not_exist = 0; - - descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); - if (descriptor < 0) - { - if (does_not_exist != NULL && errno == ENOENT) - *does_not_exist = 1; - else - error_callback (data, filename, errno); - return -1; - } - -#ifdef HAVE_FCNTL - /* Set FD_CLOEXEC just in case the kernel does not support - O_CLOEXEC. It doesn't matter if this fails for some reason. - FIXME: At some point it should be safe to only do this if - O_CLOEXEC == 0. */ - fcntl (descriptor, F_SETFD, FD_CLOEXEC); -#endif - - return descriptor; -} - -/* Close DESCRIPTOR. */ - -int -backtrace_close (int descriptor, backtrace_error_callback error_callback, - void *data) -{ - if (close (descriptor) < 0) - { - error_callback (data, "close", errno); - return 0; - } - return 1; -} diff --git a/3rdparty/libbacktrace/libbacktrace/print.c b/3rdparty/libbacktrace/libbacktrace/print.c deleted file mode 100644 index 0767face..00000000 --- a/3rdparty/libbacktrace/libbacktrace/print.c +++ /dev/null @@ -1,92 +0,0 @@ -/* print.c -- Print the current backtrace. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Passed to callbacks. */ - -struct print_data -{ - struct backtrace_state *state; - FILE *f; -}; - -/* Print one level of a backtrace. */ - -static int -print_callback (void *data, uintptr_t pc, const char *filename, int lineno, - const char *function) -{ - struct print_data *pdata = (struct print_data *) data; - - fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", - (unsigned long) pc, - function == NULL ? "???" : function, - filename == NULL ? "???" : filename, - lineno); - return 0; -} - -/* Print errors to stderr. */ - -static void -error_callback (void *data, const char *msg, int errnum) -{ - struct print_data *pdata = (struct print_data *) data; - - if (pdata->state->filename != NULL) - fprintf (stderr, "%s: ", pdata->state->filename); - fprintf (stderr, "libbacktrace: %s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fputc ('\n', stderr); -} - -/* Print a backtrace. */ - -void __attribute__((noinline)) -backtrace_print (struct backtrace_state *state, int skip, FILE *f) -{ - struct print_data data; - - data.state = state; - data.f = f; - backtrace_full (state, skip + 1, print_callback, error_callback, - (void *) &data); -} diff --git a/3rdparty/libbacktrace/libbacktrace/simple.c b/3rdparty/libbacktrace/libbacktrace/simple.c deleted file mode 100644 index 11893639..00000000 --- a/3rdparty/libbacktrace/libbacktrace/simple.c +++ /dev/null @@ -1,108 +0,0 @@ -/* simple.c -- The backtrace_simple function. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include "unwind.h" -#include "backtrace.h" - -/* The simple_backtrace routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_simple_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_simple_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routine. */ - void *data; - /* Value to return from backtrace. */ - int ret; -}; - -/* Unwind library callback routine. This is passd to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -simple_unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - bdata->ret = bdata->callback (bdata->data, pc); - - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a simple stack backtrace. */ - -int __attribute__((noinline)) -backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_simple_data bdata; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - _Unwind_Backtrace (simple_unwind, &bdata); - return bdata.ret; -} diff --git a/3rdparty/libbacktrace/libbacktrace/sort.c b/3rdparty/libbacktrace/libbacktrace/sort.c deleted file mode 100644 index 6fe5ba24..00000000 --- a/3rdparty/libbacktrace/libbacktrace/sort.c +++ /dev/null @@ -1,108 +0,0 @@ -/* sort.c -- Sort without allocating memory - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* The GNU glibc version of qsort allocates memory, which we must not - do if we are invoked by a signal handler. So provide our own - sort. */ - -static void -swap (char *a, char *b, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++, a++, b++) - { - char t; - - t = *a; - *a = *b; - *b = t; - } -} - -void -backtrace_qsort (void *basearg, size_t count, size_t size, - int (*compar) (const void *, const void *)) -{ - char *base = (char *) basearg; - size_t i; - size_t mid; - - tail_recurse: - if (count < 2) - return; - - /* The symbol table and DWARF tables, which is all we use this - routine for, tend to be roughly sorted. Pick the middle element - in the array as our pivot point, so that we are more likely to - cut the array in half for each recursion step. */ - swap (base, base + (count / 2) * size, size); - - mid = 0; - for (i = 1; i < count; i++) - { - if ((*compar) (base, base + i * size) > 0) - { - ++mid; - if (i != mid) - swap (base + mid * size, base + i * size, size); - } - } - - if (mid > 0) - swap (base, base + mid * size, size); - - /* Recurse with the smaller array, loop with the larger one. That - ensures that our maximum stack depth is log count. */ - if (2 * mid < count) - { - backtrace_qsort (base, mid, size, compar); - base += (mid + 1) * size; - count -= mid + 1; - goto tail_recurse; - } - else - { - backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), - size, compar); - count = mid; - goto tail_recurse; - } -} diff --git a/3rdparty/libbacktrace/libbacktrace/state.c b/3rdparty/libbacktrace/libbacktrace/state.c deleted file mode 100644 index 6196c267..00000000 --- a/3rdparty/libbacktrace/libbacktrace/state.c +++ /dev/null @@ -1,72 +0,0 @@ -/* state.c -- Create the backtrace state. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" - -#include -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* Create the backtrace state. This will then be passed to all the - other routines. */ - -struct backtrace_state * -backtrace_create_state (const char *filename, int threaded, - backtrace_error_callback error_callback, - void *data) -{ - struct backtrace_state init_state; - struct backtrace_state *state; - -#ifndef HAVE_SYNC_FUNCTIONS - if (threaded) - { - error_callback (data, "backtrace library does not support threads", 0); - return NULL; - } -#endif - - memset (&init_state, 0, sizeof init_state); - init_state.filename = filename; - init_state.threaded = threaded; - - state = ((struct backtrace_state *) - backtrace_alloc (&init_state, sizeof *state, error_callback, data)); - if (state == NULL) - return NULL; - *state = init_state; - - return state; -} diff --git a/3rdparty/libbacktrace/qt_attribution.json b/3rdparty/libbacktrace/qt_attribution.json deleted file mode 100644 index e8c7bf6f..00000000 --- a/3rdparty/libbacktrace/qt_attribution.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Id": "libbacktrace", - "Name": "libbacktrace", - "QDocModule": "applicationmanager", - "QtUsage": "Automatically used in Qt ApplicationManager, if available. Configure with -config disable-libbacktrace to avoid.", - - "Description": "Standalone fork of libbacktrace - libbacktrace prints stack traces.", - "Homepage": "https://github.com/ErwanLegrand/libbacktrace", - "Version": "2016-05-18", - - "License": "BSD 3-clause \"New\" or \"Revised\" License", - "LicenseId": "BSD-3-Clause", - "LicenseFile": "LICENSE", - "Copyright": "Copyright (C) 2012-2016 Free Software Foundation, Inc." -} diff --git a/3rdparty/libyaml.pri b/3rdparty/libyaml.pri deleted file mode 100644 index bac439f0..00000000 --- a/3rdparty/libyaml.pri +++ /dev/null @@ -1,7 +0,0 @@ - -!config_libyaml|no-system-libyaml { - QMAKE_USE_PRIVATE += yaml -} else { - PKGCONFIG_PRIVATE += "'yaml-0.1 >= 0.1.6'" - CONFIG *= link_pkgconfig -} diff --git a/3rdparty/libyaml/LICENSE b/3rdparty/libyaml/LICENSE deleted file mode 100644 index 21cdd1d6..00000000 --- a/3rdparty/libyaml/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2017-2018 Ingy döt Net -Copyright (c) 2006-2016 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/3rdparty/libyaml/README b/3rdparty/libyaml/README deleted file mode 100644 index 373727e0..00000000 --- a/3rdparty/libyaml/README +++ /dev/null @@ -1,27 +0,0 @@ -LibYAML - A C library for parsing and emitting YAML. - -To build and install the library, run: -$ ./configure -$ make -# make install - -If you checked the source code from the Mercurial repository, run -$ ./bootstrap -$ ./configure -$ make -# make install - -For more information, check the LibYAML homepage: -'http://pyyaml.org/wiki/LibYAML'. - -Post your questions and opinions to the YAML-Core mailing list: -'http://lists.sourceforge.net/lists/listinfo/yaml-core'. - -Submit bug reports and feature requests to the LibYAML bug tracker: -'https://bitbucket.org/xi/libyaml/issues/new'. - -LibYAML is written by Kirill Simonov . It is released -under the MIT license. See the file LICENSE for more details. - -This project is developed for Python Software Foundation as a part of -Google Summer of Code under the mentorship of Clark Evans. diff --git a/3rdparty/libyaml/include/yaml.h b/3rdparty/libyaml/include/yaml.h deleted file mode 100644 index c225908d..00000000 --- a/3rdparty/libyaml/include/yaml.h +++ /dev/null @@ -1,1978 +0,0 @@ -/** - * @file yaml.h - * @brief Public interface for libyaml. - * - * Include the header file with the code: - * @code - * #include - * @endcode - */ - -#ifndef YAML_H -#define YAML_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/** - * @defgroup export Export Definitions - * @{ - */ - -/** The public API declaration. */ - -#if defined(__MINGW32__) -# define YAML_DECLARE(type) type -#elif defined(WIN32) -# if defined(YAML_DECLARE_STATIC) -# define YAML_DECLARE(type) type -# elif defined(YAML_DECLARE_EXPORT) -# define YAML_DECLARE(type) __declspec(dllexport) type -# else -# define YAML_DECLARE(type) __declspec(dllimport) type -# endif -#else -# define YAML_DECLARE(type) type -#endif - -/** @} */ - -/** - * @defgroup version Version Information - * @{ - */ - -/** - * Get the library version as a string. - * - * @returns The function returns the pointer to a static string of the form - * @c "X.Y.Z", where @c X is the major version number, @c Y is a minor version - * number, and @c Z is the patch version number. - */ - -YAML_DECLARE(const char *) -yaml_get_version_string(void); - -/** - * Get the library version numbers. - * - * @param[out] major Major version number. - * @param[out] minor Minor version number. - * @param[out] patch Patch version number. - */ - -YAML_DECLARE(void) -yaml_get_version(int *major, int *minor, int *patch); - -/** @} */ - -/** - * @defgroup basic Basic Types - * @{ - */ - -/** The character type (UTF-8 octet). */ -typedef unsigned char yaml_char_t; - -/** The version directive data. */ -typedef struct yaml_version_directive_s { - /** The major version number. */ - int major; - /** The minor version number. */ - int minor; -} yaml_version_directive_t; - -/** The tag directive data. */ -typedef struct yaml_tag_directive_s { - /** The tag handle. */ - yaml_char_t *handle; - /** The tag prefix. */ - yaml_char_t *prefix; -} yaml_tag_directive_t; - -/** The stream encoding. */ -typedef enum yaml_encoding_e { - /** Let the parser choose the encoding. */ - YAML_ANY_ENCODING, - /** The default UTF-8 encoding. */ - YAML_UTF8_ENCODING, - /** The UTF-16-LE encoding with BOM. */ - YAML_UTF16LE_ENCODING, - /** The UTF-16-BE encoding with BOM. */ - YAML_UTF16BE_ENCODING -} yaml_encoding_t; - -/** Line break types. */ - -typedef enum yaml_break_e { - /** Let the parser choose the break type. */ - YAML_ANY_BREAK, - /** Use CR for line breaks (Mac style). */ - YAML_CR_BREAK, - /** Use LN for line breaks (Unix style). */ - YAML_LN_BREAK, - /** Use CR LN for line breaks (DOS style). */ - YAML_CRLN_BREAK -} yaml_break_t; - -/** Many bad things could happen with the parser and emitter. */ -typedef enum yaml_error_type_e { - /** No error is produced. */ - YAML_NO_ERROR, - - /** Cannot allocate or reallocate a block of memory. */ - YAML_MEMORY_ERROR, - - /** Cannot read or decode the input stream. */ - YAML_READER_ERROR, - /** Cannot scan the input stream. */ - YAML_SCANNER_ERROR, - /** Cannot parse the input stream. */ - YAML_PARSER_ERROR, - /** Cannot compose a YAML document. */ - YAML_COMPOSER_ERROR, - - /** Cannot write to the output stream. */ - YAML_WRITER_ERROR, - /** Cannot emit a YAML stream. */ - YAML_EMITTER_ERROR -} yaml_error_type_t; - -/** The pointer position. */ -typedef struct yaml_mark_s { - /** The position index. */ - size_t index; - - /** The position line. */ - size_t line; - - /** The position column. */ - size_t column; -} yaml_mark_t; - -/** @} */ - -/** - * @defgroup styles Node Styles - * @{ - */ - -/** Scalar styles. */ -typedef enum yaml_scalar_style_e { - /** Let the emitter choose the style. */ - YAML_ANY_SCALAR_STYLE, - - /** The plain scalar style. */ - YAML_PLAIN_SCALAR_STYLE, - - /** The single-quoted scalar style. */ - YAML_SINGLE_QUOTED_SCALAR_STYLE, - /** The double-quoted scalar style. */ - YAML_DOUBLE_QUOTED_SCALAR_STYLE, - - /** The literal scalar style. */ - YAML_LITERAL_SCALAR_STYLE, - /** The folded scalar style. */ - YAML_FOLDED_SCALAR_STYLE -} yaml_scalar_style_t; - -/** Sequence styles. */ -typedef enum yaml_sequence_style_e { - /** Let the emitter choose the style. */ - YAML_ANY_SEQUENCE_STYLE, - - /** The block sequence style. */ - YAML_BLOCK_SEQUENCE_STYLE, - /** The flow sequence style. */ - YAML_FLOW_SEQUENCE_STYLE -} yaml_sequence_style_t; - -/** Mapping styles. */ -typedef enum yaml_mapping_style_e { - /** Let the emitter choose the style. */ - YAML_ANY_MAPPING_STYLE, - - /** The block mapping style. */ - YAML_BLOCK_MAPPING_STYLE, - /** The flow mapping style. */ - YAML_FLOW_MAPPING_STYLE -/* YAML_FLOW_SET_MAPPING_STYLE */ -} yaml_mapping_style_t; - -/** @} */ - -/** - * @defgroup tokens Tokens - * @{ - */ - -/** Token types. */ -typedef enum yaml_token_type_e { - /** An empty token. */ - YAML_NO_TOKEN, - - /** A STREAM-START token. */ - YAML_STREAM_START_TOKEN, - /** A STREAM-END token. */ - YAML_STREAM_END_TOKEN, - - /** A VERSION-DIRECTIVE token. */ - YAML_VERSION_DIRECTIVE_TOKEN, - /** A TAG-DIRECTIVE token. */ - YAML_TAG_DIRECTIVE_TOKEN, - /** A DOCUMENT-START token. */ - YAML_DOCUMENT_START_TOKEN, - /** A DOCUMENT-END token. */ - YAML_DOCUMENT_END_TOKEN, - - /** A BLOCK-SEQUENCE-START token. */ - YAML_BLOCK_SEQUENCE_START_TOKEN, - /** A BLOCK-MAPPING-START token. */ - YAML_BLOCK_MAPPING_START_TOKEN, - /** A BLOCK-END token. */ - YAML_BLOCK_END_TOKEN, - - /** A FLOW-SEQUENCE-START token. */ - YAML_FLOW_SEQUENCE_START_TOKEN, - /** A FLOW-SEQUENCE-END token. */ - YAML_FLOW_SEQUENCE_END_TOKEN, - /** A FLOW-MAPPING-START token. */ - YAML_FLOW_MAPPING_START_TOKEN, - /** A FLOW-MAPPING-END token. */ - YAML_FLOW_MAPPING_END_TOKEN, - - /** A BLOCK-ENTRY token. */ - YAML_BLOCK_ENTRY_TOKEN, - /** A FLOW-ENTRY token. */ - YAML_FLOW_ENTRY_TOKEN, - /** A KEY token. */ - YAML_KEY_TOKEN, - /** A VALUE token. */ - YAML_VALUE_TOKEN, - - /** An ALIAS token. */ - YAML_ALIAS_TOKEN, - /** An ANCHOR token. */ - YAML_ANCHOR_TOKEN, - /** A TAG token. */ - YAML_TAG_TOKEN, - /** A SCALAR token. */ - YAML_SCALAR_TOKEN -} yaml_token_type_t; - -/** The token structure. */ -typedef struct yaml_token_s { - - /** The token type. */ - yaml_token_type_t type; - - /** The token data. */ - union { - - /** The stream start (for @c YAML_STREAM_START_TOKEN). */ - struct { - /** The stream encoding. */ - yaml_encoding_t encoding; - } stream_start; - - /** The alias (for @c YAML_ALIAS_TOKEN). */ - struct { - /** The alias value. */ - yaml_char_t *value; - } alias; - - /** The anchor (for @c YAML_ANCHOR_TOKEN). */ - struct { - /** The anchor value. */ - yaml_char_t *value; - } anchor; - - /** The tag (for @c YAML_TAG_TOKEN). */ - struct { - /** The tag handle. */ - yaml_char_t *handle; - /** The tag suffix. */ - yaml_char_t *suffix; - } tag; - - /** The scalar value (for @c YAML_SCALAR_TOKEN). */ - struct { - /** The scalar value. */ - yaml_char_t *value; - /** The length of the scalar value. */ - size_t length; - /** The scalar style. */ - yaml_scalar_style_t style; - } scalar; - - /** The version directive (for @c YAML_VERSION_DIRECTIVE_TOKEN). */ - struct { - /** The major version number. */ - int major; - /** The minor version number. */ - int minor; - } version_directive; - - /** The tag directive (for @c YAML_TAG_DIRECTIVE_TOKEN). */ - struct { - /** The tag handle. */ - yaml_char_t *handle; - /** The tag prefix. */ - yaml_char_t *prefix; - } tag_directive; - - } data; - - /** The beginning of the token. */ - yaml_mark_t start_mark; - /** The end of the token. */ - yaml_mark_t end_mark; - -} yaml_token_t; - -/** - * Free any memory allocated for a token object. - * - * @param[in,out] token A token object. - */ - -YAML_DECLARE(void) -yaml_token_delete(yaml_token_t *token); - -/** @} */ - -/** - * @defgroup events Events - * @{ - */ - -/** Event types. */ -typedef enum yaml_event_type_e { - /** An empty event. */ - YAML_NO_EVENT, - - /** A STREAM-START event. */ - YAML_STREAM_START_EVENT, - /** A STREAM-END event. */ - YAML_STREAM_END_EVENT, - - /** A DOCUMENT-START event. */ - YAML_DOCUMENT_START_EVENT, - /** A DOCUMENT-END event. */ - YAML_DOCUMENT_END_EVENT, - - /** An ALIAS event. */ - YAML_ALIAS_EVENT, - /** A SCALAR event. */ - YAML_SCALAR_EVENT, - - /** A SEQUENCE-START event. */ - YAML_SEQUENCE_START_EVENT, - /** A SEQUENCE-END event. */ - YAML_SEQUENCE_END_EVENT, - - /** A MAPPING-START event. */ - YAML_MAPPING_START_EVENT, - /** A MAPPING-END event. */ - YAML_MAPPING_END_EVENT -} yaml_event_type_t; - -/** The event structure. */ -typedef struct yaml_event_s { - - /** The event type. */ - yaml_event_type_t type; - - /** The event data. */ - union { - - /** The stream parameters (for @c YAML_STREAM_START_EVENT). */ - struct { - /** The document encoding. */ - yaml_encoding_t encoding; - } stream_start; - - /** The document parameters (for @c YAML_DOCUMENT_START_EVENT). */ - struct { - /** The version directive. */ - yaml_version_directive_t *version_directive; - - /** The list of tag directives. */ - struct { - /** The beginning of the tag directives list. */ - yaml_tag_directive_t *start; - /** The end of the tag directives list. */ - yaml_tag_directive_t *end; - } tag_directives; - - /** Is the document indicator implicit? */ - int implicit; - } document_start; - - /** The document end parameters (for @c YAML_DOCUMENT_END_EVENT). */ - struct { - /** Is the document end indicator implicit? */ - int implicit; - } document_end; - - /** The alias parameters (for @c YAML_ALIAS_EVENT). */ - struct { - /** The anchor. */ - yaml_char_t *anchor; - } alias; - - /** The scalar parameters (for @c YAML_SCALAR_EVENT). */ - struct { - /** The anchor. */ - yaml_char_t *anchor; - /** The tag. */ - yaml_char_t *tag; - /** The scalar value. */ - yaml_char_t *value; - /** The length of the scalar value. */ - size_t length; - /** Is the tag optional for the plain style? */ - int plain_implicit; - /** Is the tag optional for any non-plain style? */ - int quoted_implicit; - /** The scalar style. */ - yaml_scalar_style_t style; - } scalar; - - /** The sequence parameters (for @c YAML_SEQUENCE_START_EVENT). */ - struct { - /** The anchor. */ - yaml_char_t *anchor; - /** The tag. */ - yaml_char_t *tag; - /** Is the tag optional? */ - int implicit; - /** The sequence style. */ - yaml_sequence_style_t style; - } sequence_start; - - /** The mapping parameters (for @c YAML_MAPPING_START_EVENT). */ - struct { - /** The anchor. */ - yaml_char_t *anchor; - /** The tag. */ - yaml_char_t *tag; - /** Is the tag optional? */ - int implicit; - /** The mapping style. */ - yaml_mapping_style_t style; - } mapping_start; - - } data; - - /** The beginning of the event. */ - yaml_mark_t start_mark; - /** The end of the event. */ - yaml_mark_t end_mark; - -} yaml_event_t; - -/** - * Create the STREAM-START event. - * - * @param[out] event An empty event object. - * @param[in] encoding The stream encoding. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_stream_start_event_initialize(yaml_event_t *event, - yaml_encoding_t encoding); - -/** - * Create the STREAM-END event. - * - * @param[out] event An empty event object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_stream_end_event_initialize(yaml_event_t *event); - -/** - * Create the DOCUMENT-START event. - * - * The @a implicit argument is considered as a stylistic parameter and may be - * ignored by the emitter. - * - * @param[out] event An empty event object. - * @param[in] version_directive The %YAML directive value or - * @c NULL. - * @param[in] tag_directives_start The beginning of the %TAG - * directives list. - * @param[in] tag_directives_end The end of the %TAG directives - * list. - * @param[in] implicit If the document start indicator is - * implicit. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_start_event_initialize(yaml_event_t *event, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int implicit); - -/** - * Create the DOCUMENT-END event. - * - * The @a implicit argument is considered as a stylistic parameter and may be - * ignored by the emitter. - * - * @param[out] event An empty event object. - * @param[in] implicit If the document end indicator is implicit. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_end_event_initialize(yaml_event_t *event, int implicit); - -/** - * Create an ALIAS event. - * - * @param[out] event An empty event object. - * @param[in] anchor The anchor value. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor); - -/** - * Create a SCALAR event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or one of the @a plain_implicit and - * @a quoted_implicit flags must be set. - * - * @param[out] event An empty event object. - * @param[in] anchor The scalar anchor or @c NULL. - * @param[in] tag The scalar tag or @c NULL. - * @param[in] value The scalar value. - * @param[in] length The length of the scalar value. - * @param[in] plain_implicit If the tag may be omitted for the plain - * style. - * @param[in] quoted_implicit If the tag may be omitted for any - * non-plain style. - * @param[in] style The scalar style. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_scalar_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, - yaml_char_t *value, int length, - int plain_implicit, int quoted_implicit, - yaml_scalar_style_t style); - -/** - * Create a SEQUENCE-START event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or the @a implicit flag must be set. - * - * @param[out] event An empty event object. - * @param[in] anchor The sequence anchor or @c NULL. - * @param[in] tag The sequence tag or @c NULL. - * @param[in] implicit If the tag may be omitted. - * @param[in] style The sequence style. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_sequence_start_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_sequence_style_t style); - -/** - * Create a SEQUENCE-END event. - * - * @param[out] event An empty event object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_sequence_end_event_initialize(yaml_event_t *event); - -/** - * Create a MAPPING-START event. - * - * The @a style argument may be ignored by the emitter. - * - * Either the @a tag attribute or the @a implicit flag must be set. - * - * @param[out] event An empty event object. - * @param[in] anchor The mapping anchor or @c NULL. - * @param[in] tag The mapping tag or @c NULL. - * @param[in] implicit If the tag may be omitted. - * @param[in] style The mapping style. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_mapping_start_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_mapping_style_t style); - -/** - * Create a MAPPING-END event. - * - * @param[out] event An empty event object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_mapping_end_event_initialize(yaml_event_t *event); - -/** - * Free any memory allocated for an event object. - * - * @param[in,out] event An event object. - */ - -YAML_DECLARE(void) -yaml_event_delete(yaml_event_t *event); - -/** @} */ - -/** - * @defgroup nodes Nodes - * @{ - */ - -/** The tag @c !!null with the only possible value: @c null. */ -#define YAML_NULL_TAG "tag:yaml.org,2002:null" -/** The tag @c !!bool with the values: @c true and @c false. */ -#define YAML_BOOL_TAG "tag:yaml.org,2002:bool" -/** The tag @c !!str for string values. */ -#define YAML_STR_TAG "tag:yaml.org,2002:str" -/** The tag @c !!int for integer values. */ -#define YAML_INT_TAG "tag:yaml.org,2002:int" -/** The tag @c !!float for float values. */ -#define YAML_FLOAT_TAG "tag:yaml.org,2002:float" -/** The tag @c !!timestamp for date and time values. */ -#define YAML_TIMESTAMP_TAG "tag:yaml.org,2002:timestamp" - -/** The tag @c !!seq is used to denote sequences. */ -#define YAML_SEQ_TAG "tag:yaml.org,2002:seq" -/** The tag @c !!map is used to denote mapping. */ -#define YAML_MAP_TAG "tag:yaml.org,2002:map" - -/** The default scalar tag is @c !!str. */ -#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG -/** The default sequence tag is @c !!seq. */ -#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG -/** The default mapping tag is @c !!map. */ -#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG - -/** Node types. */ -typedef enum yaml_node_type_e { - /** An empty node. */ - YAML_NO_NODE, - - /** A scalar node. */ - YAML_SCALAR_NODE, - /** A sequence node. */ - YAML_SEQUENCE_NODE, - /** A mapping node. */ - YAML_MAPPING_NODE -} yaml_node_type_t; - -/** The forward definition of a document node structure. */ -typedef struct yaml_node_s yaml_node_t; - -/** An element of a sequence node. */ -typedef int yaml_node_item_t; - -/** An element of a mapping node. */ -typedef struct yaml_node_pair_s { - /** The key of the element. */ - int key; - /** The value of the element. */ - int value; -} yaml_node_pair_t; - -/** The node structure. */ -struct yaml_node_s { - - /** The node type. */ - yaml_node_type_t type; - - /** The node tag. */ - yaml_char_t *tag; - - /** The node data. */ - union { - - /** The scalar parameters (for @c YAML_SCALAR_NODE). */ - struct { - /** The scalar value. */ - yaml_char_t *value; - /** The length of the scalar value. */ - size_t length; - /** The scalar style. */ - yaml_scalar_style_t style; - } scalar; - - /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */ - struct { - /** The stack of sequence items. */ - struct { - /** The beginning of the stack. */ - yaml_node_item_t *start; - /** The end of the stack. */ - yaml_node_item_t *end; - /** The top of the stack. */ - yaml_node_item_t *top; - } items; - /** The sequence style. */ - yaml_sequence_style_t style; - } sequence; - - /** The mapping parameters (for @c YAML_MAPPING_NODE). */ - struct { - /** The stack of mapping pairs (key, value). */ - struct { - /** The beginning of the stack. */ - yaml_node_pair_t *start; - /** The end of the stack. */ - yaml_node_pair_t *end; - /** The top of the stack. */ - yaml_node_pair_t *top; - } pairs; - /** The mapping style. */ - yaml_mapping_style_t style; - } mapping; - - } data; - - /** The beginning of the node. */ - yaml_mark_t start_mark; - /** The end of the node. */ - yaml_mark_t end_mark; - -}; - -/** The document structure. */ -typedef struct yaml_document_s { - - /** The document nodes. */ - struct { - /** The beginning of the stack. */ - yaml_node_t *start; - /** The end of the stack. */ - yaml_node_t *end; - /** The top of the stack. */ - yaml_node_t *top; - } nodes; - - /** The version directive. */ - yaml_version_directive_t *version_directive; - - /** The list of tag directives. */ - struct { - /** The beginning of the tag directives list. */ - yaml_tag_directive_t *start; - /** The end of the tag directives list. */ - yaml_tag_directive_t *end; - } tag_directives; - - /** Is the document start indicator implicit? */ - int start_implicit; - /** Is the document end indicator implicit? */ - int end_implicit; - - /** The beginning of the document. */ - yaml_mark_t start_mark; - /** The end of the document. */ - yaml_mark_t end_mark; - -} yaml_document_t; - -/** - * Create a YAML document. - * - * @param[out] document An empty document object. - * @param[in] version_directive The %YAML directive value or - * @c NULL. - * @param[in] tag_directives_start The beginning of the %TAG - * directives list. - * @param[in] tag_directives_end The end of the %TAG directives - * list. - * @param[in] start_implicit If the document start indicator is - * implicit. - * @param[in] end_implicit If the document end indicator is - * implicit. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_initialize(yaml_document_t *document, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int start_implicit, int end_implicit); - -/** - * Delete a YAML document and all its nodes. - * - * @param[in,out] document A document object. - */ - -YAML_DECLARE(void) -yaml_document_delete(yaml_document_t *document); - -/** - * Get a node of a YAML document. - * - * The pointer returned by this function is valid until any of the functions - * modifying the documents are called. - * - * @param[in] document A document object. - * @param[in] index The node id. - * - * @returns the node objct or @c NULL if @c node_id is out of range. - */ - -YAML_DECLARE(yaml_node_t *) -yaml_document_get_node(yaml_document_t *document, int index); - -/** - * Get the root of a YAML document node. - * - * The root object is the first object added to the document. - * - * The pointer returned by this function is valid until any of the functions - * modifying the documents are called. - * - * An empty document produced by the parser signifies the end of a YAML - * stream. - * - * @param[in] document A document object. - * - * @returns the node object or @c NULL if the document is empty. - */ - -YAML_DECLARE(yaml_node_t *) -yaml_document_get_root_node(yaml_document_t *document); - -/** - * Create a SCALAR node and attach it to the document. - * - * The @a style argument may be ignored by the emitter. - * - * @param[in,out] document A document object. - * @param[in] tag The scalar tag. - * @param[in] value The scalar value. - * @param[in] length The length of the scalar value. - * @param[in] style The scalar style. - * - * @returns the node id or @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_add_scalar(yaml_document_t *document, - yaml_char_t *tag, yaml_char_t *value, int length, - yaml_scalar_style_t style); - -/** - * Create a SEQUENCE node and attach it to the document. - * - * The @a style argument may be ignored by the emitter. - * - * @param[in,out] document A document object. - * @param[in] tag The sequence tag. - * @param[in] style The sequence style. - * - * @returns the node id or @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_add_sequence(yaml_document_t *document, - yaml_char_t *tag, yaml_sequence_style_t style); - -/** - * Create a MAPPING node and attach it to the document. - * - * The @a style argument may be ignored by the emitter. - * - * @param[in,out] document A document object. - * @param[in] tag The sequence tag. - * @param[in] style The sequence style. - * - * @returns the node id or @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_add_mapping(yaml_document_t *document, - yaml_char_t *tag, yaml_mapping_style_t style); - -/** - * Add an item to a SEQUENCE node. - * - * @param[in,out] document A document object. - * @param[in] sequence The sequence node id. - * @param[in] item The item node id. -* - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_append_sequence_item(yaml_document_t *document, - int sequence, int item); - -/** - * Add a pair of a key and a value to a MAPPING node. - * - * @param[in,out] document A document object. - * @param[in] mapping The mapping node id. - * @param[in] key The key node id. - * @param[in] value The value node id. -* - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_document_append_mapping_pair(yaml_document_t *document, - int mapping, int key, int value); - -/** @} */ - -/** - * @defgroup parser Parser Definitions - * @{ - */ - -/** - * The prototype of a read handler. - * - * The read handler is called when the parser needs to read more bytes from the - * source. The handler should write not more than @a size bytes to the @a - * buffer. The number of written bytes should be set to the @a length variable. - * - * @param[in,out] data A pointer to an application data specified by - * yaml_parser_set_input(). - * @param[out] buffer The buffer to write the data from the source. - * @param[in] size The size of the buffer. - * @param[out] size_read The actual number of bytes read from the source. - * - * @returns On success, the handler should return @c 1. If the handler failed, - * the returned value should be @c 0. On EOF, the handler should set the - * @a size_read to @c 0 and return @c 1. - */ - -typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size, - size_t *size_read); - -/** - * This structure holds information about a potential simple key. - */ - -typedef struct yaml_simple_key_s { - /** Is a simple key possible? */ - int possible; - - /** Is a simple key required? */ - int required; - - /** The number of the token. */ - size_t token_number; - - /** The position mark. */ - yaml_mark_t mark; -} yaml_simple_key_t; - -/** - * The states of the parser. - */ -typedef enum yaml_parser_state_e { - /** Expect STREAM-START. */ - YAML_PARSE_STREAM_START_STATE, - /** Expect the beginning of an implicit document. */ - YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, - /** Expect DOCUMENT-START. */ - YAML_PARSE_DOCUMENT_START_STATE, - /** Expect the content of a document. */ - YAML_PARSE_DOCUMENT_CONTENT_STATE, - /** Expect DOCUMENT-END. */ - YAML_PARSE_DOCUMENT_END_STATE, - /** Expect a block node. */ - YAML_PARSE_BLOCK_NODE_STATE, - /** Expect a block node or indentless sequence. */ - YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, - /** Expect a flow node. */ - YAML_PARSE_FLOW_NODE_STATE, - /** Expect the first entry of a block sequence. */ - YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, - /** Expect an entry of a block sequence. */ - YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, - /** Expect an entry of an indentless sequence. */ - YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, - /** Expect the first key of a block mapping. */ - YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, - /** Expect a block mapping key. */ - YAML_PARSE_BLOCK_MAPPING_KEY_STATE, - /** Expect a block mapping value. */ - YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, - /** Expect the first entry of a flow sequence. */ - YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, - /** Expect an entry of a flow sequence. */ - YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, - /** Expect a key of an ordered mapping. */ - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, - /** Expect a value of an ordered mapping. */ - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, - /** Expect the and of an ordered mapping entry. */ - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, - /** Expect the first key of a flow mapping. */ - YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, - /** Expect a key of a flow mapping. */ - YAML_PARSE_FLOW_MAPPING_KEY_STATE, - /** Expect a value of a flow mapping. */ - YAML_PARSE_FLOW_MAPPING_VALUE_STATE, - /** Expect an empty value of a flow mapping. */ - YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, - /** Expect nothing. */ - YAML_PARSE_END_STATE -} yaml_parser_state_t; - -/** - * This structure holds aliases data. - */ - -typedef struct yaml_alias_data_s { - /** The anchor. */ - yaml_char_t *anchor; - /** The node id. */ - int index; - /** The anchor mark. */ - yaml_mark_t mark; -} yaml_alias_data_t; - -/** - * The parser structure. - * - * All members are internal. Manage the structure using the @c yaml_parser_ - * family of functions. - */ - -typedef struct yaml_parser_s { - - /** - * @name Error handling - * @{ - */ - - /** Error type. */ - yaml_error_type_t error; - /** Error description. */ - const char *problem; - /** The byte about which the problem occured. */ - size_t problem_offset; - /** The problematic value (@c -1 is none). */ - int problem_value; - /** The problem position. */ - yaml_mark_t problem_mark; - /** The error context. */ - const char *context; - /** The context position. */ - yaml_mark_t context_mark; - - /** - * @} - */ - - /** - * @name Reader stuff - * @{ - */ - - /** Read handler. */ - yaml_read_handler_t *read_handler; - - /** A pointer for passing to the read handler. */ - void *read_handler_data; - - /** Standard (string or file) input data. */ - union { - /** String input data. */ - struct { - /** The string start pointer. */ - const unsigned char *start; - /** The string end pointer. */ - const unsigned char *end; - /** The string current position. */ - const unsigned char *current; - } string; - - /** File input data. */ - FILE *file; - } input; - - /** EOF flag */ - int eof; - - /** The working buffer. */ - struct { - /** The beginning of the buffer. */ - yaml_char_t *start; - /** The end of the buffer. */ - yaml_char_t *end; - /** The current position of the buffer. */ - yaml_char_t *pointer; - /** The last filled position of the buffer. */ - yaml_char_t *last; - } buffer; - - /* The number of unread characters in the buffer. */ - size_t unread; - - /** The raw buffer. */ - struct { - /** The beginning of the buffer. */ - unsigned char *start; - /** The end of the buffer. */ - unsigned char *end; - /** The current position of the buffer. */ - unsigned char *pointer; - /** The last filled position of the buffer. */ - unsigned char *last; - } raw_buffer; - - /** The input encoding. */ - yaml_encoding_t encoding; - - /** The offset of the current position (in bytes). */ - size_t offset; - - /** The mark of the current position. */ - yaml_mark_t mark; - - /** - * @} - */ - - /** - * @name Scanner stuff - * @{ - */ - - /** Have we started to scan the input stream? */ - int stream_start_produced; - - /** Have we reached the end of the input stream? */ - int stream_end_produced; - - /** The number of unclosed '[' and '{' indicators. */ - int flow_level; - - /** The tokens queue. */ - struct { - /** The beginning of the tokens queue. */ - yaml_token_t *start; - /** The end of the tokens queue. */ - yaml_token_t *end; - /** The head of the tokens queue. */ - yaml_token_t *head; - /** The tail of the tokens queue. */ - yaml_token_t *tail; - } tokens; - - /** The number of tokens fetched from the queue. */ - size_t tokens_parsed; - - /* Does the tokens queue contain a token ready for dequeueing. */ - int token_available; - - /** The indentation levels stack. */ - struct { - /** The beginning of the stack. */ - int *start; - /** The end of the stack. */ - int *end; - /** The top of the stack. */ - int *top; - } indents; - - /** The current indentation level. */ - int indent; - - /** May a simple key occur at the current position? */ - int simple_key_allowed; - - /** The stack of simple keys. */ - struct { - /** The beginning of the stack. */ - yaml_simple_key_t *start; - /** The end of the stack. */ - yaml_simple_key_t *end; - /** The top of the stack. */ - yaml_simple_key_t *top; - } simple_keys; - - /** - * @} - */ - - /** - * @name Parser stuff - * @{ - */ - - /** The parser states stack. */ - struct { - /** The beginning of the stack. */ - yaml_parser_state_t *start; - /** The end of the stack. */ - yaml_parser_state_t *end; - /** The top of the stack. */ - yaml_parser_state_t *top; - } states; - - /** The current parser state. */ - yaml_parser_state_t state; - - /** The stack of marks. */ - struct { - /** The beginning of the stack. */ - yaml_mark_t *start; - /** The end of the stack. */ - yaml_mark_t *end; - /** The top of the stack. */ - yaml_mark_t *top; - } marks; - - /** The list of TAG directives. */ - struct { - /** The beginning of the list. */ - yaml_tag_directive_t *start; - /** The end of the list. */ - yaml_tag_directive_t *end; - /** The top of the list. */ - yaml_tag_directive_t *top; - } tag_directives; - - /** - * @} - */ - - /** - * @name Dumper stuff - * @{ - */ - - /** The alias data. */ - struct { - /** The beginning of the list. */ - yaml_alias_data_t *start; - /** The end of the list. */ - yaml_alias_data_t *end; - /** The top of the list. */ - yaml_alias_data_t *top; - } aliases; - - /** The currently parsed document. */ - yaml_document_t *document; - - /** - * @} - */ - -} yaml_parser_t; - -/** - * Initialize a parser. - * - * This function creates a new parser object. An application is responsible - * for destroying the object using the yaml_parser_delete() function. - * - * @param[out] parser An empty parser object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_parser_initialize(yaml_parser_t *parser); - -/** - * Destroy a parser. - * - * @param[in,out] parser A parser object. - */ - -YAML_DECLARE(void) -yaml_parser_delete(yaml_parser_t *parser); - -/** - * Set a string input. - * - * Note that the @a input pointer must be valid while the @a parser object - * exists. The application is responsible for destroing @a input after - * destroying the @a parser. - * - * @param[in,out] parser A parser object. - * @param[in] input A source data. - * @param[in] size The length of the source data in bytes. - */ - -YAML_DECLARE(void) -yaml_parser_set_input_string(yaml_parser_t *parser, - const unsigned char *input, size_t size); - -/** - * Set a file input. - * - * @a file should be a file object open for reading. The application is - * responsible for closing the @a file. - * - * @param[in,out] parser A parser object. - * @param[in] file An open file. - */ - -YAML_DECLARE(void) -yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file); - -/** - * Set a generic input handler. - * - * @param[in,out] parser A parser object. - * @param[in] handler A read handler. - * @param[in] data Any application data for passing to the read - * handler. - */ - -YAML_DECLARE(void) -yaml_parser_set_input(yaml_parser_t *parser, - yaml_read_handler_t *handler, void *data); - -/** - * Set the source encoding. - * - * @param[in,out] parser A parser object. - * @param[in] encoding The source encoding. - */ - -YAML_DECLARE(void) -yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding); - -/** - * Scan the input stream and produce the next token. - * - * Call the function subsequently to produce a sequence of tokens corresponding - * to the input stream. The initial token has the type - * @c YAML_STREAM_START_TOKEN while the ending token has the type - * @c YAML_STREAM_END_TOKEN. - * - * An application is responsible for freeing any buffers associated with the - * produced token object using the @c yaml_token_delete function. - * - * An application must not alternate the calls of yaml_parser_scan() with the - * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break - * the parser. - * - * @param[in,out] parser A parser object. - * @param[out] token An empty token object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); - -/** - * Parse the input stream and produce the next parsing event. - * - * Call the function subsequently to produce a sequence of events corresponding - * to the input stream. The initial event has the type - * @c YAML_STREAM_START_EVENT while the ending event has the type - * @c YAML_STREAM_END_EVENT. - * - * An application is responsible for freeing any buffers associated with the - * produced event object using the yaml_event_delete() function. - * - * An application must not alternate the calls of yaml_parser_parse() with the - * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the - * parser. - * - * @param[in,out] parser A parser object. - * @param[out] event An empty event object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); - -/** - * Parse the input stream and produce the next YAML document. - * - * Call this function subsequently to produce a sequence of documents - * constituting the input stream. - * - * If the produced document has no root node, it means that the document - * end has been reached. - * - * An application is responsible for freeing any data associated with the - * produced document object using the yaml_document_delete() function. - * - * An application must not alternate the calls of yaml_parser_load() with the - * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break - * the parser. - * - * @param[in,out] parser A parser object. - * @param[out] document An empty document object. - * - * @return @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); - -/** @} */ - -/** - * @defgroup emitter Emitter Definitions - * @{ - */ - -/** - * The prototype of a write handler. - * - * The write handler is called when the emitter needs to flush the accumulated - * characters to the output. The handler should write @a size bytes of the - * @a buffer to the output. - * - * @param[in,out] data A pointer to an application data specified by - * yaml_emitter_set_output(). - * @param[in] buffer The buffer with bytes to be written. - * @param[in] size The size of the buffer. - * - * @returns On success, the handler should return @c 1. If the handler failed, - * the returned value should be @c 0. - */ - -typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size); - -/** The emitter states. */ -typedef enum yaml_emitter_state_e { - /** Expect STREAM-START. */ - YAML_EMIT_STREAM_START_STATE, - /** Expect the first DOCUMENT-START or STREAM-END. */ - YAML_EMIT_FIRST_DOCUMENT_START_STATE, - /** Expect DOCUMENT-START or STREAM-END. */ - YAML_EMIT_DOCUMENT_START_STATE, - /** Expect the content of a document. */ - YAML_EMIT_DOCUMENT_CONTENT_STATE, - /** Expect DOCUMENT-END. */ - YAML_EMIT_DOCUMENT_END_STATE, - /** Expect the first item of a flow sequence. */ - YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, - /** Expect an item of a flow sequence. */ - YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, - /** Expect the first key of a flow mapping. */ - YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, - /** Expect a key of a flow mapping. */ - YAML_EMIT_FLOW_MAPPING_KEY_STATE, - /** Expect a value for a simple key of a flow mapping. */ - YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, - /** Expect a value of a flow mapping. */ - YAML_EMIT_FLOW_MAPPING_VALUE_STATE, - /** Expect the first item of a block sequence. */ - YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, - /** Expect an item of a block sequence. */ - YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, - /** Expect the first key of a block mapping. */ - YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, - /** Expect the key of a block mapping. */ - YAML_EMIT_BLOCK_MAPPING_KEY_STATE, - /** Expect a value for a simple key of a block mapping. */ - YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, - /** Expect a value of a block mapping. */ - YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, - /** Expect nothing. */ - YAML_EMIT_END_STATE -} yaml_emitter_state_t; - - -/* This is needed for C++ */ - -typedef struct yaml_anchors_s { - /** The number of references. */ - int references; - /** The anchor id. */ - int anchor; - /** If the node has been emitted? */ - int serialized; -} yaml_anchors_t; - -/** - * The emitter structure. - * - * All members are internal. Manage the structure using the @c yaml_emitter_ - * family of functions. - */ - -typedef struct yaml_emitter_s { - - /** - * @name Error handling - * @{ - */ - - /** Error type. */ - yaml_error_type_t error; - /** Error description. */ - const char *problem; - - /** - * @} - */ - - /** - * @name Writer stuff - * @{ - */ - - /** Write handler. */ - yaml_write_handler_t *write_handler; - - /** A pointer for passing to the white handler. */ - void *write_handler_data; - - /** Standard (string or file) output data. */ - union { - /** String output data. */ - struct { - /** The buffer pointer. */ - unsigned char *buffer; - /** The buffer size. */ - size_t size; - /** The number of written bytes. */ - size_t *size_written; - } string; - - /** File output data. */ - FILE *file; - } output; - - /** The working buffer. */ - struct { - /** The beginning of the buffer. */ - yaml_char_t *start; - /** The end of the buffer. */ - yaml_char_t *end; - /** The current position of the buffer. */ - yaml_char_t *pointer; - /** The last filled position of the buffer. */ - yaml_char_t *last; - } buffer; - - /** The raw buffer. */ - struct { - /** The beginning of the buffer. */ - unsigned char *start; - /** The end of the buffer. */ - unsigned char *end; - /** The current position of the buffer. */ - unsigned char *pointer; - /** The last filled position of the buffer. */ - unsigned char *last; - } raw_buffer; - - /** The stream encoding. */ - yaml_encoding_t encoding; - - /** - * @} - */ - - /** - * @name Emitter stuff - * @{ - */ - - /** If the output is in the canonical style? */ - int canonical; - /** The number of indentation spaces. */ - int best_indent; - /** The preferred width of the output lines. */ - int best_width; - /** Allow unescaped non-ASCII characters? */ - int unicode; - /** The preferred line break. */ - yaml_break_t line_break; - - /** The stack of states. */ - struct { - /** The beginning of the stack. */ - yaml_emitter_state_t *start; - /** The end of the stack. */ - yaml_emitter_state_t *end; - /** The top of the stack. */ - yaml_emitter_state_t *top; - } states; - - /** The current emitter state. */ - yaml_emitter_state_t state; - - /** The event queue. */ - struct { - /** The beginning of the event queue. */ - yaml_event_t *start; - /** The end of the event queue. */ - yaml_event_t *end; - /** The head of the event queue. */ - yaml_event_t *head; - /** The tail of the event queue. */ - yaml_event_t *tail; - } events; - - /** The stack of indentation levels. */ - struct { - /** The beginning of the stack. */ - int *start; - /** The end of the stack. */ - int *end; - /** The top of the stack. */ - int *top; - } indents; - - /** The list of tag directives. */ - struct { - /** The beginning of the list. */ - yaml_tag_directive_t *start; - /** The end of the list. */ - yaml_tag_directive_t *end; - /** The top of the list. */ - yaml_tag_directive_t *top; - } tag_directives; - - /** The current indentation level. */ - int indent; - - /** The current flow level. */ - int flow_level; - - /** Is it the document root context? */ - int root_context; - /** Is it a sequence context? */ - int sequence_context; - /** Is it a mapping context? */ - int mapping_context; - /** Is it a simple mapping key context? */ - int simple_key_context; - - /** The current line. */ - int line; - /** The current column. */ - int column; - /** If the last character was a whitespace? */ - int whitespace; - /** If the last character was an indentation character (' ', '-', '?', ':')? */ - int indention; - /** If an explicit document end is required? */ - int open_ended; - - /** Anchor analysis. */ - struct { - /** The anchor value. */ - yaml_char_t *anchor; - /** The anchor length. */ - size_t anchor_length; - /** Is it an alias? */ - int alias; - } anchor_data; - - /** Tag analysis. */ - struct { - /** The tag handle. */ - yaml_char_t *handle; - /** The tag handle length. */ - size_t handle_length; - /** The tag suffix. */ - yaml_char_t *suffix; - /** The tag suffix length. */ - size_t suffix_length; - } tag_data; - - /** Scalar analysis. */ - struct { - /** The scalar value. */ - yaml_char_t *value; - /** The scalar length. */ - size_t length; - /** Does the scalar contain line breaks? */ - int multiline; - /** Can the scalar be expessed in the flow plain style? */ - int flow_plain_allowed; - /** Can the scalar be expressed in the block plain style? */ - int block_plain_allowed; - /** Can the scalar be expressed in the single quoted style? */ - int single_quoted_allowed; - /** Can the scalar be expressed in the literal or folded styles? */ - int block_allowed; - /** The output style. */ - yaml_scalar_style_t style; - } scalar_data; - - /** - * @} - */ - - /** - * @name Dumper stuff - * @{ - */ - - /** If the stream was already opened? */ - int opened; - /** If the stream was already closed? */ - int closed; - - /** The information associated with the document nodes. */ - yaml_anchors_t *anchors; - - /** The last assigned anchor id. */ - int last_anchor_id; - - /** The currently emitted document. */ - yaml_document_t *document; - - /** - * @} - */ - -} yaml_emitter_t; - -/** - * Initialize an emitter. - * - * This function creates a new emitter object. An application is responsible - * for destroying the object using the yaml_emitter_delete() function. - * - * @param[out] emitter An empty parser object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_initialize(yaml_emitter_t *emitter); - -/** - * Destroy an emitter. - * - * @param[in,out] emitter An emitter object. - */ - -YAML_DECLARE(void) -yaml_emitter_delete(yaml_emitter_t *emitter); - -/** - * Set a string output. - * - * The emitter will write the output characters to the @a output buffer of the - * size @a size. The emitter will set @a size_written to the number of written - * bytes. If the buffer is smaller than required, the emitter produces the - * YAML_WRITE_ERROR error. - * - * @param[in,out] emitter An emitter object. - * @param[in] output An output buffer. - * @param[in] size The buffer size. - * @param[in] size_written The pointer to save the number of written - * bytes. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output_string(yaml_emitter_t *emitter, - unsigned char *output, size_t size, size_t *size_written); - -/** - * Set a file output. - * - * @a file should be a file object open for writing. The application is - * responsible for closing the @a file. - * - * @param[in,out] emitter An emitter object. - * @param[in] file An open file. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file); - -/** - * Set a generic output handler. - * - * @param[in,out] emitter An emitter object. - * @param[in] handler A write handler. - * @param[in] data Any application data for passing to the write - * handler. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output(yaml_emitter_t *emitter, - yaml_write_handler_t *handler, void *data); - -/** - * Set the output encoding. - * - * @param[in,out] emitter An emitter object. - * @param[in] encoding The output encoding. - */ - -YAML_DECLARE(void) -yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding); - -/** - * Set if the output should be in the "canonical" format as in the YAML - * specification. - * - * @param[in,out] emitter An emitter object. - * @param[in] canonical If the output is canonical. - */ - -YAML_DECLARE(void) -yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical); - -/** - * Set the intendation increment. - * - * @param[in,out] emitter An emitter object. - * @param[in] indent The indentation increment (1 < . < 10). - */ - -YAML_DECLARE(void) -yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent); - -/** - * Set the preferred line width. @c -1 means unlimited. - * - * @param[in,out] emitter An emitter object. - * @param[in] width The preferred line width. - */ - -YAML_DECLARE(void) -yaml_emitter_set_width(yaml_emitter_t *emitter, int width); - -/** - * Set if unescaped non-ASCII characters are allowed. - * - * @param[in,out] emitter An emitter object. - * @param[in] unicode If unescaped Unicode characters are allowed. - */ - -YAML_DECLARE(void) -yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode); - -/** - * Set the preferred line break. - * - * @param[in,out] emitter An emitter object. - * @param[in] line_break The preferred line break. - */ - -YAML_DECLARE(void) -yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break); - -/** - * Emit an event. - * - * The event object may be generated using the yaml_parser_parse() function. - * The emitter takes the responsibility for the event object and destroys its - * content after it is emitted. The event object is destroyed even if the - * function fails. - * - * @param[in,out] emitter An emitter object. - * @param[in,out] event An event object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); - -/** - * Start a YAML stream. - * - * This function should be used before yaml_emitter_dump() is called. - * - * @param[in,out] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_open(yaml_emitter_t *emitter); - -/** - * Finish a YAML stream. - * - * This function should be used after yaml_emitter_dump() is called. - * - * @param[in,out] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_close(yaml_emitter_t *emitter); - -/** - * Emit a YAML document. - * - * The documen object may be generated using the yaml_parser_load() function - * or the yaml_document_initialize() function. The emitter takes the - * responsibility for the document object and destroys its content after - * it is emitted. The document object is destroyed even if the function fails. - * - * @param[in,out] emitter An emitter object. - * @param[in,out] document A document object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); - -/** - * Flush the accumulated characters to the output. - * - * @param[in,out] emitter An emitter object. - * - * @returns @c 1 if the function succeeded, @c 0 on error. - */ - -YAML_DECLARE(int) -yaml_emitter_flush(yaml_emitter_t *emitter); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* #ifndef YAML_H */ - diff --git a/3rdparty/libyaml/libyaml.pro b/3rdparty/libyaml/libyaml.pro deleted file mode 100644 index c1cabd71..00000000 --- a/3rdparty/libyaml/libyaml.pro +++ /dev/null @@ -1,40 +0,0 @@ -TEMPLATE = lib -TARGET = qtyaml - -load(am-config) - -CONFIG += \ - static \ - hide_symbols \ - exceptions_off rtti_off warn_off \ - installed - -MODULE_DEFINES *= YAML_DECLARE_STATIC -MODULE_INCLUDEPATH += $$PWD/include - -load(qt_helper_lib) - -win32-msvc* { - QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS -} -*-g++* { - QMAKE_CFLAGS += -Wno-unused -} -*-clang* { - CONFIG += warn_off - QMAKE_CFLAGS += -Wall -W -Wno-unused -} - -DEFINES *= YAML_DECLARE_STATIC HAVE_CONFIG_H - -INCLUDEPATH += $$PWD/win32 $$PWD/include - -SOURCES += \ - src/api.c \ - src/dumper.c \ - src/emitter.c \ - src/loader.c \ - src/parser.c \ - src/reader.c \ - src/scanner.c \ - src/writer.c \ diff --git a/3rdparty/libyaml/qt_attribution.json b/3rdparty/libyaml/qt_attribution.json deleted file mode 100644 index f6cf786e..00000000 --- a/3rdparty/libyaml/qt_attribution.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "Id": "libyaml", - "Name": "libyaml", - "QDocModule": "applicationmanager", - "QtUsage": "Optionally used in Qt ApplicationManager. Configure with -config force-system-libyaml to avoid.", - - "Description": "LibYAML is a YAML 1.1 parser and emitter written in C.", - "Homepage": "http://pyyaml.org/wiki/LibYAML/", - "Version": "0.2.1", - - "License": "MIT License", - "LicenseId": "MIT", - "LicenseFile": "LICENSE", - "Copyright": "Copyright (c) 2017-2018 Ingy döt Net -Copyright (c) 2006-2016 Kirill Simonov" -} diff --git a/3rdparty/libyaml/src/api.c b/3rdparty/libyaml/src/api.c deleted file mode 100644 index e793b085..00000000 --- a/3rdparty/libyaml/src/api.c +++ /dev/null @@ -1,1393 +0,0 @@ - -#include "yaml_private.h" - -/* - * Get the library version. - */ - -YAML_DECLARE(const char *) -yaml_get_version_string(void) -{ - return YAML_VERSION_STRING; -} - -/* - * Get the library version numbers. - */ - -YAML_DECLARE(void) -yaml_get_version(int *major, int *minor, int *patch) -{ - *major = YAML_VERSION_MAJOR; - *minor = YAML_VERSION_MINOR; - *patch = YAML_VERSION_PATCH; -} - -/* - * Allocate a dynamic memory block. - */ - -YAML_DECLARE(void *) -yaml_malloc(size_t size) -{ - return malloc(size ? size : 1); -} - -/* - * Reallocate a dynamic memory block. - */ - -YAML_DECLARE(void *) -yaml_realloc(void *ptr, size_t size) -{ - return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1); -} - -/* - * Free a dynamic memory block. - */ - -YAML_DECLARE(void) -yaml_free(void *ptr) -{ - if (ptr) free(ptr); -} - -/* - * Duplicate a string. - */ - -YAML_DECLARE(yaml_char_t *) -yaml_strdup(const yaml_char_t *str) -{ - if (!str) - return NULL; - - return (yaml_char_t *)strdup((char *)str); -} - -/* - * Extend a string. - */ - -YAML_DECLARE(int) -yaml_string_extend(yaml_char_t **start, - yaml_char_t **pointer, yaml_char_t **end) -{ - yaml_char_t *new_start = (yaml_char_t *)yaml_realloc((void*)*start, (*end - *start)*2); - - if (!new_start) return 0; - - memset(new_start + (*end - *start), 0, *end - *start); - - *pointer = new_start + (*pointer - *start); - *end = new_start + (*end - *start)*2; - *start = new_start; - - return 1; -} - -/* - * Append a string B to a string A. - */ - -YAML_DECLARE(int) -yaml_string_join( - yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, - yaml_char_t **b_start, yaml_char_t **b_pointer, SHIM(yaml_char_t **b_end)) -{ - UNUSED_PARAM(b_end) - if (*b_start == *b_pointer) - return 1; - - while (*a_end - *a_pointer <= *b_pointer - *b_start) { - if (!yaml_string_extend(a_start, a_pointer, a_end)) - return 0; - } - - memcpy(*a_pointer, *b_start, *b_pointer - *b_start); - *a_pointer += *b_pointer - *b_start; - - return 1; -} - -/* - * Extend a stack. - */ - -YAML_DECLARE(int) -yaml_stack_extend(void **start, void **top, void **end) -{ - void *new_start; - - if ((char *)*end - (char *)*start >= INT_MAX / 2) - return 0; - - new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2); - - if (!new_start) return 0; - - *top = (char *)new_start + ((char *)*top - (char *)*start); - *end = (char *)new_start + ((char *)*end - (char *)*start)*2; - *start = new_start; - - return 1; -} - -/* - * Extend or move a queue. - */ - -YAML_DECLARE(int) -yaml_queue_extend(void **start, void **head, void **tail, void **end) -{ - /* Check if we need to resize the queue. */ - - if (*start == *head && *tail == *end) { - void *new_start = yaml_realloc(*start, - ((char *)*end - (char *)*start)*2); - - if (!new_start) return 0; - - *head = (char *)new_start + ((char *)*head - (char *)*start); - *tail = (char *)new_start + ((char *)*tail - (char *)*start); - *end = (char *)new_start + ((char *)*end - (char *)*start)*2; - *start = new_start; - } - - /* Check if we need to move the queue at the beginning of the buffer. */ - - if (*tail == *end) { - if (*head != *tail) { - memmove(*start, *head, (char *)*tail - (char *)*head); - } - *tail = (char *)*tail - (char *)*head + (char *)*start; - *head = *start; - } - - return 1; -} - - -/* - * Create a new parser object. - */ - -YAML_DECLARE(int) -yaml_parser_initialize(yaml_parser_t *parser) -{ - assert(parser); /* Non-NULL parser object expected. */ - - memset(parser, 0, sizeof(yaml_parser_t)); - if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE)) - goto error; - if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE)) - goto error; - if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE, yaml_token_t*)) - goto error; - if (!STACK_INIT(parser, parser->indents, int*)) - goto error; - if (!STACK_INIT(parser, parser->simple_keys, yaml_simple_key_t*)) - goto error; - if (!STACK_INIT(parser, parser->states, yaml_parser_state_t*)) - goto error; - if (!STACK_INIT(parser, parser->marks, yaml_mark_t*)) - goto error; - if (!STACK_INIT(parser, parser->tag_directives, yaml_tag_directive_t*)) - goto error; - - return 1; - -error: - - BUFFER_DEL(parser, parser->raw_buffer); - BUFFER_DEL(parser, parser->buffer); - QUEUE_DEL(parser, parser->tokens); - STACK_DEL(parser, parser->indents); - STACK_DEL(parser, parser->simple_keys); - STACK_DEL(parser, parser->states); - STACK_DEL(parser, parser->marks); - STACK_DEL(parser, parser->tag_directives); - - return 0; -} - -/* - * Destroy a parser object. - */ - -YAML_DECLARE(void) -yaml_parser_delete(yaml_parser_t *parser) -{ - assert(parser); /* Non-NULL parser object expected. */ - - BUFFER_DEL(parser, parser->raw_buffer); - BUFFER_DEL(parser, parser->buffer); - while (!QUEUE_EMPTY(parser, parser->tokens)) { - yaml_token_delete(&DEQUEUE(parser, parser->tokens)); - } - QUEUE_DEL(parser, parser->tokens); - STACK_DEL(parser, parser->indents); - STACK_DEL(parser, parser->simple_keys); - STACK_DEL(parser, parser->states); - STACK_DEL(parser, parser->marks); - while (!STACK_EMPTY(parser, parser->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - STACK_DEL(parser, parser->tag_directives); - - memset(parser, 0, sizeof(yaml_parser_t)); -} - -/* - * String read handler. - */ - -static int -yaml_string_read_handler(void *data, unsigned char *buffer, size_t size, - size_t *size_read) -{ - yaml_parser_t *parser = (yaml_parser_t *)data; - - if (parser->input.string.current == parser->input.string.end) { - *size_read = 0; - return 1; - } - - if (size > (size_t)(parser->input.string.end - - parser->input.string.current)) { - size = parser->input.string.end - parser->input.string.current; - } - - memcpy(buffer, parser->input.string.current, size); - parser->input.string.current += size; - *size_read = size; - return 1; -} - -/* - * File read handler. - */ - -static int -yaml_file_read_handler(void *data, unsigned char *buffer, size_t size, - size_t *size_read) -{ - yaml_parser_t *parser = (yaml_parser_t *)data; - - *size_read = fread(buffer, 1, size, parser->input.file); - return !ferror(parser->input.file); -} - -/* - * Set a string input. - */ - -YAML_DECLARE(void) -yaml_parser_set_input_string(yaml_parser_t *parser, - const unsigned char *input, size_t size) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->read_handler); /* You can set the source only once. */ - assert(input); /* Non-NULL input string expected. */ - - parser->read_handler = yaml_string_read_handler; - parser->read_handler_data = parser; - - parser->input.string.start = input; - parser->input.string.current = input; - parser->input.string.end = input+size; -} - -/* - * Set a file input. - */ - -YAML_DECLARE(void) -yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->read_handler); /* You can set the source only once. */ - assert(file); /* Non-NULL file object expected. */ - - parser->read_handler = yaml_file_read_handler; - parser->read_handler_data = parser; - - parser->input.file = file; -} - -/* - * Set a generic input. - */ - -YAML_DECLARE(void) -yaml_parser_set_input(yaml_parser_t *parser, - yaml_read_handler_t *handler, void *data) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->read_handler); /* You can set the source only once. */ - assert(handler); /* Non-NULL read handler expected. */ - - parser->read_handler = handler; - parser->read_handler_data = data; -} - -/* - * Set the source encoding. - */ - -YAML_DECLARE(void) -yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) -{ - assert(parser); /* Non-NULL parser object expected. */ - assert(!parser->encoding); /* Encoding is already set or detected. */ - - parser->encoding = encoding; -} - -/* - * Create a new emitter object. - */ - -YAML_DECLARE(int) -yaml_emitter_initialize(yaml_emitter_t *emitter) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - memset(emitter, 0, sizeof(yaml_emitter_t)); - if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE)) - goto error; - if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE)) - goto error; - if (!STACK_INIT(emitter, emitter->states, yaml_emitter_state_t*)) - goto error; - if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE, yaml_event_t*)) - goto error; - if (!STACK_INIT(emitter, emitter->indents, int*)) - goto error; - if (!STACK_INIT(emitter, emitter->tag_directives, yaml_tag_directive_t*)) - goto error; - - return 1; - -error: - - BUFFER_DEL(emitter, emitter->buffer); - BUFFER_DEL(emitter, emitter->raw_buffer); - STACK_DEL(emitter, emitter->states); - QUEUE_DEL(emitter, emitter->events); - STACK_DEL(emitter, emitter->indents); - STACK_DEL(emitter, emitter->tag_directives); - - return 0; -} - -/* - * Destroy an emitter object. - */ - -YAML_DECLARE(void) -yaml_emitter_delete(yaml_emitter_t *emitter) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - BUFFER_DEL(emitter, emitter->buffer); - BUFFER_DEL(emitter, emitter->raw_buffer); - STACK_DEL(emitter, emitter->states); - while (!QUEUE_EMPTY(emitter, emitter->events)) { - yaml_event_delete(&DEQUEUE(emitter, emitter->events)); - } - QUEUE_DEL(emitter, emitter->events); - STACK_DEL(emitter, emitter->indents); - while (!STACK_EMPTY(empty, emitter->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - STACK_DEL(emitter, emitter->tag_directives); - yaml_free(emitter->anchors); - - memset(emitter, 0, sizeof(yaml_emitter_t)); -} - -/* - * String write handler. - */ - -static int -yaml_string_write_handler(void *data, unsigned char *buffer, size_t size) -{ - yaml_emitter_t *emitter = (yaml_emitter_t *)data; - - if (emitter->output.string.size - *emitter->output.string.size_written - < size) { - memcpy(emitter->output.string.buffer - + *emitter->output.string.size_written, - buffer, - emitter->output.string.size - - *emitter->output.string.size_written); - *emitter->output.string.size_written = emitter->output.string.size; - return 0; - } - - memcpy(emitter->output.string.buffer - + *emitter->output.string.size_written, buffer, size); - *emitter->output.string.size_written += size; - return 1; -} - -/* - * File write handler. - */ - -static int -yaml_file_write_handler(void *data, unsigned char *buffer, size_t size) -{ - yaml_emitter_t *emitter = (yaml_emitter_t *)data; - - return (fwrite(buffer, 1, size, emitter->output.file) == size); -} -/* - * Set a string output. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output_string(yaml_emitter_t *emitter, - unsigned char *output, size_t size, size_t *size_written) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->write_handler); /* You can set the output only once. */ - assert(output); /* Non-NULL output string expected. */ - - emitter->write_handler = yaml_string_write_handler; - emitter->write_handler_data = emitter; - - emitter->output.string.buffer = output; - emitter->output.string.size = size; - emitter->output.string.size_written = size_written; - *size_written = 0; -} - -/* - * Set a file output. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->write_handler); /* You can set the output only once. */ - assert(file); /* Non-NULL file object expected. */ - - emitter->write_handler = yaml_file_write_handler; - emitter->write_handler_data = emitter; - - emitter->output.file = file; -} - -/* - * Set a generic output handler. - */ - -YAML_DECLARE(void) -yaml_emitter_set_output(yaml_emitter_t *emitter, - yaml_write_handler_t *handler, void *data) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->write_handler); /* You can set the output only once. */ - assert(handler); /* Non-NULL handler object expected. */ - - emitter->write_handler = handler; - emitter->write_handler_data = data; -} - -/* - * Set the output encoding. - */ - -YAML_DECLARE(void) -yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - assert(!emitter->encoding); /* You can set encoding only once. */ - - emitter->encoding = encoding; -} - -/* - * Set the canonical output style. - */ - -YAML_DECLARE(void) -yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->canonical = (canonical != 0); -} - -/* - * Set the indentation increment. - */ - -YAML_DECLARE(void) -yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; -} - -/* - * Set the preferred line width. - */ - -YAML_DECLARE(void) -yaml_emitter_set_width(yaml_emitter_t *emitter, int width) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->best_width = (width >= 0) ? width : -1; -} - -/* - * Set if unescaped non-ASCII characters are allowed. - */ - -YAML_DECLARE(void) -yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->unicode = (unicode != 0); -} - -/* - * Set the preferred line break character. - */ - -YAML_DECLARE(void) -yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) -{ - assert(emitter); /* Non-NULL emitter object expected. */ - - emitter->line_break = line_break; -} - -/* - * Destroy a token object. - */ - -YAML_DECLARE(void) -yaml_token_delete(yaml_token_t *token) -{ - assert(token); /* Non-NULL token object expected. */ - - switch (token->type) - { - case YAML_TAG_DIRECTIVE_TOKEN: - yaml_free(token->data.tag_directive.handle); - yaml_free(token->data.tag_directive.prefix); - break; - - case YAML_ALIAS_TOKEN: - yaml_free(token->data.alias.value); - break; - - case YAML_ANCHOR_TOKEN: - yaml_free(token->data.anchor.value); - break; - - case YAML_TAG_TOKEN: - yaml_free(token->data.tag.handle); - yaml_free(token->data.tag.suffix); - break; - - case YAML_SCALAR_TOKEN: - yaml_free(token->data.scalar.value); - break; - - default: - break; - } - - memset(token, 0, sizeof(yaml_token_t)); -} - -/* - * Check if a string is a valid UTF-8 sequence. - * - * Check 'reader.c' for more details on UTF-8 encoding. - */ - -static int -yaml_check_utf8(yaml_char_t *start, size_t length) -{ - yaml_char_t *end = start+length; - yaml_char_t *pointer = start; - - while (pointer < end) { - unsigned char octet; - unsigned int width; - unsigned int value; - size_t k; - - octet = pointer[0]; - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - value = (octet & 0x80) == 0x00 ? octet & 0x7F : - (octet & 0xE0) == 0xC0 ? octet & 0x1F : - (octet & 0xF0) == 0xE0 ? octet & 0x0F : - (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; - if (!width) return 0; - if (pointer+width > end) return 0; - for (k = 1; k < width; k ++) { - octet = pointer[k]; - if ((octet & 0xC0) != 0x80) return 0; - value = (value << 6) + (octet & 0x3F); - } - if (!((width == 1) || - (width == 2 && value >= 0x80) || - (width == 3 && value >= 0x800) || - (width == 4 && value >= 0x10000))) return 0; - - pointer += width; - } - - return 1; -} - -/* - * Create STREAM-START. - */ - -YAML_DECLARE(int) -yaml_stream_start_event_initialize(yaml_event_t *event, - yaml_encoding_t encoding) -{ - yaml_mark_t mark = { 0, 0, 0 }; - - assert(event); /* Non-NULL event object is expected. */ - - STREAM_START_EVENT_INIT(*event, encoding, mark, mark); - - return 1; -} - -/* - * Create STREAM-END. - */ - -YAML_DECLARE(int) -yaml_stream_end_event_initialize(yaml_event_t *event) -{ - yaml_mark_t mark = { 0, 0, 0 }; - - assert(event); /* Non-NULL event object is expected. */ - - STREAM_END_EVENT_INIT(*event, mark, mark); - - return 1; -} - -/* - * Create DOCUMENT-START. - */ - -YAML_DECLARE(int) -yaml_document_start_event_initialize(yaml_event_t *event, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int implicit) -{ - struct { - yaml_error_type_t error; - } context; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_version_directive_t *version_directive_copy = NULL; - struct { - yaml_tag_directive_t *start; - yaml_tag_directive_t *end; - yaml_tag_directive_t *top; - } tag_directives_copy = { NULL, NULL, NULL }; - yaml_tag_directive_t value = { NULL, NULL }; - - assert(event); /* Non-NULL event object is expected. */ - assert((tag_directives_start && tag_directives_end) || - (tag_directives_start == tag_directives_end)); - /* Valid tag directives are expected. */ - - if (version_directive) { - version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); - if (!version_directive_copy) goto error; - version_directive_copy->major = version_directive->major; - version_directive_copy->minor = version_directive->minor; - } - - if (tag_directives_start != tag_directives_end) { - yaml_tag_directive_t *tag_directive; - if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) - goto error; - for (tag_directive = tag_directives_start; - tag_directive != tag_directives_end; tag_directive ++) { - assert(tag_directive->handle); - assert(tag_directive->prefix); - if (!yaml_check_utf8(tag_directive->handle, - strlen((char *)tag_directive->handle))) - goto error; - if (!yaml_check_utf8(tag_directive->prefix, - strlen((char *)tag_directive->prefix))) - goto error; - value.handle = yaml_strdup(tag_directive->handle); - value.prefix = yaml_strdup(tag_directive->prefix); - if (!value.handle || !value.prefix) goto error; - if (!PUSH(&context, tag_directives_copy, value)) - goto error; - value.handle = NULL; - value.prefix = NULL; - } - } - - DOCUMENT_START_EVENT_INIT(*event, version_directive_copy, - tag_directives_copy.start, tag_directives_copy.top, - implicit, mark, mark); - - return 1; - -error: - yaml_free(version_directive_copy); - while (!STACK_EMPTY(context, tag_directives_copy)) { - yaml_tag_directive_t value = POP(context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); - } - STACK_DEL(context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); - - return 0; -} - -/* - * Create DOCUMENT-END. - */ - -YAML_DECLARE(int) -yaml_document_end_event_initialize(yaml_event_t *event, int implicit) -{ - yaml_mark_t mark = { 0, 0, 0 }; - - assert(event); /* Non-NULL emitter object is expected. */ - - DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); - - return 1; -} - -/* - * Create ALIAS. - */ - -YAML_DECLARE(int) -yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor) -{ - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - - assert(event); /* Non-NULL event object is expected. */ - assert(anchor); /* Non-NULL anchor is expected. */ - - if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; - - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) - return 0; - - ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); - - return 1; -} - -/* - * Create SCALAR. - */ - -YAML_DECLARE(int) -yaml_scalar_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, - yaml_char_t *value, int length, - int plain_implicit, int quoted_implicit, - yaml_scalar_style_t style) -{ - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - yaml_char_t *value_copy = NULL; - - assert(event); /* Non-NULL event object is expected. */ - assert(value); /* Non-NULL anchor is expected. */ - - if (anchor) { - if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) goto error; - } - - if (tag) { - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - } - - if (length < 0) { - length = strlen((char *)value); - } - - if (!yaml_check_utf8(value, length)) goto error; - value_copy = YAML_MALLOC(length+1); - if (!value_copy) goto error; - memcpy(value_copy, value, length); - value_copy[length] = '\0'; - - SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, - plain_implicit, quoted_implicit, style, mark, mark); - - return 1; - -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); - yaml_free(value_copy); - - return 0; -} - -/* - * Create SEQUENCE-START. - */ - -YAML_DECLARE(int) -yaml_sequence_start_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_sequence_style_t style) -{ - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - - assert(event); /* Non-NULL event object is expected. */ - - if (anchor) { - if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) goto error; - } - - if (tag) { - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - } - - SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, - implicit, style, mark, mark); - - return 1; - -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); - - return 0; -} - -/* - * Create SEQUENCE-END. - */ - -YAML_DECLARE(int) -yaml_sequence_end_event_initialize(yaml_event_t *event) -{ - yaml_mark_t mark = { 0, 0, 0 }; - - assert(event); /* Non-NULL event object is expected. */ - - SEQUENCE_END_EVENT_INIT(*event, mark, mark); - - return 1; -} - -/* - * Create MAPPING-START. - */ - -YAML_DECLARE(int) -yaml_mapping_start_event_initialize(yaml_event_t *event, - yaml_char_t *anchor, yaml_char_t *tag, int implicit, - yaml_mapping_style_t style) -{ - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *anchor_copy = NULL; - yaml_char_t *tag_copy = NULL; - - assert(event); /* Non-NULL event object is expected. */ - - if (anchor) { - if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; - anchor_copy = yaml_strdup(anchor); - if (!anchor_copy) goto error; - } - - if (tag) { - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - } - - MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, - implicit, style, mark, mark); - - return 1; - -error: - yaml_free(anchor_copy); - yaml_free(tag_copy); - - return 0; -} - -/* - * Create MAPPING-END. - */ - -YAML_DECLARE(int) -yaml_mapping_end_event_initialize(yaml_event_t *event) -{ - yaml_mark_t mark = { 0, 0, 0 }; - - assert(event); /* Non-NULL event object is expected. */ - - MAPPING_END_EVENT_INIT(*event, mark, mark); - - return 1; -} - -/* - * Destroy an event object. - */ - -YAML_DECLARE(void) -yaml_event_delete(yaml_event_t *event) -{ - yaml_tag_directive_t *tag_directive; - - assert(event); /* Non-NULL event object expected. */ - - switch (event->type) - { - case YAML_DOCUMENT_START_EVENT: - yaml_free(event->data.document_start.version_directive); - for (tag_directive = event->data.document_start.tag_directives.start; - tag_directive != event->data.document_start.tag_directives.end; - tag_directive++) { - yaml_free(tag_directive->handle); - yaml_free(tag_directive->prefix); - } - yaml_free(event->data.document_start.tag_directives.start); - break; - - case YAML_ALIAS_EVENT: - yaml_free(event->data.alias.anchor); - break; - - case YAML_SCALAR_EVENT: - yaml_free(event->data.scalar.anchor); - yaml_free(event->data.scalar.tag); - yaml_free(event->data.scalar.value); - break; - - case YAML_SEQUENCE_START_EVENT: - yaml_free(event->data.sequence_start.anchor); - yaml_free(event->data.sequence_start.tag); - break; - - case YAML_MAPPING_START_EVENT: - yaml_free(event->data.mapping_start.anchor); - yaml_free(event->data.mapping_start.tag); - break; - - default: - break; - } - - memset(event, 0, sizeof(yaml_event_t)); -} - -/* - * Create a document object. - */ - -YAML_DECLARE(int) -yaml_document_initialize(yaml_document_t *document, - yaml_version_directive_t *version_directive, - yaml_tag_directive_t *tag_directives_start, - yaml_tag_directive_t *tag_directives_end, - int start_implicit, int end_implicit) -{ - struct { - yaml_error_type_t error; - } context; - struct { - yaml_node_t *start; - yaml_node_t *end; - yaml_node_t *top; - } nodes = { NULL, NULL, NULL }; - yaml_version_directive_t *version_directive_copy = NULL; - struct { - yaml_tag_directive_t *start; - yaml_tag_directive_t *end; - yaml_tag_directive_t *top; - } tag_directives_copy = { NULL, NULL, NULL }; - yaml_tag_directive_t value = { NULL, NULL }; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(document); /* Non-NULL document object is expected. */ - assert((tag_directives_start && tag_directives_end) || - (tag_directives_start == tag_directives_end)); - /* Valid tag directives are expected. */ - - if (!STACK_INIT(&context, nodes, yaml_node_t*)) goto error; - - if (version_directive) { - version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); - if (!version_directive_copy) goto error; - version_directive_copy->major = version_directive->major; - version_directive_copy->minor = version_directive->minor; - } - - if (tag_directives_start != tag_directives_end) { - yaml_tag_directive_t *tag_directive; - if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) - goto error; - for (tag_directive = tag_directives_start; - tag_directive != tag_directives_end; tag_directive ++) { - assert(tag_directive->handle); - assert(tag_directive->prefix); - if (!yaml_check_utf8(tag_directive->handle, - strlen((char *)tag_directive->handle))) - goto error; - if (!yaml_check_utf8(tag_directive->prefix, - strlen((char *)tag_directive->prefix))) - goto error; - value.handle = yaml_strdup(tag_directive->handle); - value.prefix = yaml_strdup(tag_directive->prefix); - if (!value.handle || !value.prefix) goto error; - if (!PUSH(&context, tag_directives_copy, value)) - goto error; - value.handle = NULL; - value.prefix = NULL; - } - } - - DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, - tag_directives_copy.start, tag_directives_copy.top, - start_implicit, end_implicit, mark, mark); - - return 1; - -error: - STACK_DEL(&context, nodes); - yaml_free(version_directive_copy); - while (!STACK_EMPTY(&context, tag_directives_copy)) { - yaml_tag_directive_t value = POP(&context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); - } - STACK_DEL(&context, tag_directives_copy); - yaml_free(value.handle); - yaml_free(value.prefix); - - return 0; -} - -/* - * Destroy a document object. - */ - -YAML_DECLARE(void) -yaml_document_delete(yaml_document_t *document) -{ - yaml_tag_directive_t *tag_directive; - - assert(document); /* Non-NULL document object is expected. */ - - while (!STACK_EMPTY(&context, document->nodes)) { - yaml_node_t node = POP(&context, document->nodes); - yaml_free(node.tag); - switch (node.type) { - case YAML_SCALAR_NODE: - yaml_free(node.data.scalar.value); - break; - case YAML_SEQUENCE_NODE: - STACK_DEL(&context, node.data.sequence.items); - break; - case YAML_MAPPING_NODE: - STACK_DEL(&context, node.data.mapping.pairs); - break; - default: - assert(0); /* Should not happen. */ - } - } - STACK_DEL(&context, document->nodes); - - yaml_free(document->version_directive); - for (tag_directive = document->tag_directives.start; - tag_directive != document->tag_directives.end; - tag_directive++) { - yaml_free(tag_directive->handle); - yaml_free(tag_directive->prefix); - } - yaml_free(document->tag_directives.start); - - memset(document, 0, sizeof(yaml_document_t)); -} - -/** - * Get a document node. - */ - -YAML_DECLARE(yaml_node_t *) -yaml_document_get_node(yaml_document_t *document, int index) -{ - assert(document); /* Non-NULL document object is expected. */ - - if (index > 0 && document->nodes.start + index <= document->nodes.top) { - return document->nodes.start + index - 1; - } - return NULL; -} - -/** - * Get the root object. - */ - -YAML_DECLARE(yaml_node_t *) -yaml_document_get_root_node(yaml_document_t *document) -{ - assert(document); /* Non-NULL document object is expected. */ - - if (document->nodes.top != document->nodes.start) { - return document->nodes.start; - } - return NULL; -} - -/* - * Add a scalar node to a document. - */ - -YAML_DECLARE(int) -yaml_document_add_scalar(yaml_document_t *document, - yaml_char_t *tag, yaml_char_t *value, int length, - yaml_scalar_style_t style) -{ - struct { - yaml_error_type_t error; - } context; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *tag_copy = NULL; - yaml_char_t *value_copy = NULL; - yaml_node_t node; - - assert(document); /* Non-NULL document object is expected. */ - assert(value); /* Non-NULL value is expected. */ - - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; - } - - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - - if (length < 0) { - length = strlen((char *)value); - } - - if (!yaml_check_utf8(value, length)) goto error; - value_copy = YAML_MALLOC(length+1); - if (!value_copy) goto error; - memcpy(value_copy, value, length); - value_copy[length] = '\0'; - - SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; - - return document->nodes.top - document->nodes.start; - -error: - yaml_free(tag_copy); - yaml_free(value_copy); - - return 0; -} - -/* - * Add a sequence node to a document. - */ - -YAML_DECLARE(int) -yaml_document_add_sequence(yaml_document_t *document, - yaml_char_t *tag, yaml_sequence_style_t style) -{ - struct { - yaml_error_type_t error; - } context; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *tag_copy = NULL; - struct { - yaml_node_item_t *start; - yaml_node_item_t *end; - yaml_node_item_t *top; - } items = { NULL, NULL, NULL }; - yaml_node_t node; - - assert(document); /* Non-NULL document object is expected. */ - - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; - } - - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - - if (!STACK_INIT(&context, items, yaml_node_item_t*)) goto error; - - SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, - style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; - - return document->nodes.top - document->nodes.start; - -error: - STACK_DEL(&context, items); - yaml_free(tag_copy); - - return 0; -} - -/* - * Add a mapping node to a document. - */ - -YAML_DECLARE(int) -yaml_document_add_mapping(yaml_document_t *document, - yaml_char_t *tag, yaml_mapping_style_t style) -{ - struct { - yaml_error_type_t error; - } context; - yaml_mark_t mark = { 0, 0, 0 }; - yaml_char_t *tag_copy = NULL; - struct { - yaml_node_pair_t *start; - yaml_node_pair_t *end; - yaml_node_pair_t *top; - } pairs = { NULL, NULL, NULL }; - yaml_node_t node; - - assert(document); /* Non-NULL document object is expected. */ - - if (!tag) { - tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; - } - - if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; - tag_copy = yaml_strdup(tag); - if (!tag_copy) goto error; - - if (!STACK_INIT(&context, pairs, yaml_node_pair_t*)) goto error; - - MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, - style, mark, mark); - if (!PUSH(&context, document->nodes, node)) goto error; - - return document->nodes.top - document->nodes.start; - -error: - STACK_DEL(&context, pairs); - yaml_free(tag_copy); - - return 0; -} - -/* - * Append an item to a sequence node. - */ - -YAML_DECLARE(int) -yaml_document_append_sequence_item(yaml_document_t *document, - int sequence, int item) -{ - struct { - yaml_error_type_t error; - } context; - - assert(document); /* Non-NULL document is required. */ - assert(sequence > 0 - && document->nodes.start + sequence <= document->nodes.top); - /* Valid sequence id is required. */ - assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); - /* A sequence node is required. */ - assert(item > 0 && document->nodes.start + item <= document->nodes.top); - /* Valid item id is required. */ - - if (!PUSH(&context, - document->nodes.start[sequence-1].data.sequence.items, item)) - return 0; - - return 1; -} - -/* - * Append a pair of a key and a value to a mapping node. - */ - -YAML_DECLARE(int) -yaml_document_append_mapping_pair(yaml_document_t *document, - int mapping, int key, int value) -{ - struct { - yaml_error_type_t error; - } context; - - yaml_node_pair_t pair; - - assert(document); /* Non-NULL document is required. */ - assert(mapping > 0 - && document->nodes.start + mapping <= document->nodes.top); - /* Valid mapping id is required. */ - assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); - /* A mapping node is required. */ - assert(key > 0 && document->nodes.start + key <= document->nodes.top); - /* Valid key id is required. */ - assert(value > 0 && document->nodes.start + value <= document->nodes.top); - /* Valid value id is required. */ - - pair.key = key; - pair.value = value; - - if (!PUSH(&context, - document->nodes.start[mapping-1].data.mapping.pairs, pair)) - return 0; - - return 1; -} - - diff --git a/3rdparty/libyaml/src/dumper.c b/3rdparty/libyaml/src/dumper.c deleted file mode 100644 index 1fe940b6..00000000 --- a/3rdparty/libyaml/src/dumper.c +++ /dev/null @@ -1,394 +0,0 @@ - -#include "yaml_private.h" - -/* - * API functions. - */ - -YAML_DECLARE(int) -yaml_emitter_open(yaml_emitter_t *emitter); - -YAML_DECLARE(int) -yaml_emitter_close(yaml_emitter_t *emitter); - -YAML_DECLARE(int) -yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); - -/* - * Clean up functions. - */ - -static void -yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter); - -/* - * Anchor functions. - */ - -static void -yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index); - -static yaml_char_t * -yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id); - - -/* - * Serialize functions. - */ - -static int -yaml_emitter_dump_node(yaml_emitter_t *emitter, int index); - -static int -yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); - -static int -yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor); - -static int -yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor); - -static int -yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor); - -/* - * Issue a STREAM-START event. - */ - -YAML_DECLARE(int) -yaml_emitter_open(yaml_emitter_t *emitter) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(emitter); /* Non-NULL emitter object is required. */ - assert(!emitter->opened); /* Emitter should not be opened yet. */ - - STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark); - - if (!yaml_emitter_emit(emitter, &event)) { - return 0; - } - - emitter->opened = 1; - - return 1; -} - -/* - * Issue a STREAM-END event. - */ - -YAML_DECLARE(int) -yaml_emitter_close(yaml_emitter_t *emitter) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(emitter); /* Non-NULL emitter object is required. */ - assert(emitter->opened); /* Emitter should be opened. */ - - if (emitter->closed) return 1; - - STREAM_END_EVENT_INIT(event, mark, mark); - - if (!yaml_emitter_emit(emitter, &event)) { - return 0; - } - - emitter->closed = 1; - - return 1; -} - -/* - * Dump a YAML document. - */ - -YAML_DECLARE(int) -yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - assert(emitter); /* Non-NULL emitter object is required. */ - assert(document); /* Non-NULL emitter object is expected. */ - - emitter->document = document; - - if (!emitter->opened) { - if (!yaml_emitter_open(emitter)) goto error; - } - - if (STACK_EMPTY(emitter, document->nodes)) { - if (!yaml_emitter_close(emitter)) goto error; - yaml_emitter_delete_document_and_anchors(emitter); - return 1; - } - - assert(emitter->opened); /* Emitter should be opened. */ - - emitter->anchors = (yaml_anchors_t*)yaml_malloc(sizeof(*(emitter->anchors)) - * (document->nodes.top - document->nodes.start)); - if (!emitter->anchors) goto error; - memset(emitter->anchors, 0, sizeof(*(emitter->anchors)) - * (document->nodes.top - document->nodes.start)); - - DOCUMENT_START_EVENT_INIT(event, document->version_directive, - document->tag_directives.start, document->tag_directives.end, - document->start_implicit, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) goto error; - - yaml_emitter_anchor_node(emitter, 1); - if (!yaml_emitter_dump_node(emitter, 1)) goto error; - - DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) goto error; - - yaml_emitter_delete_document_and_anchors(emitter); - - return 1; - -error: - - yaml_emitter_delete_document_and_anchors(emitter); - - return 0; -} - -/* - * Clean up the emitter object after a document is dumped. - */ - -static void -yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter) -{ - int index; - - if (!emitter->anchors) { - yaml_document_delete(emitter->document); - emitter->document = NULL; - return; - } - - for (index = 0; emitter->document->nodes.start + index - < emitter->document->nodes.top; index ++) { - yaml_node_t node = emitter->document->nodes.start[index]; - if (!emitter->anchors[index].serialized) { - yaml_free(node.tag); - if (node.type == YAML_SCALAR_NODE) { - yaml_free(node.data.scalar.value); - } - } - if (node.type == YAML_SEQUENCE_NODE) { - STACK_DEL(emitter, node.data.sequence.items); - } - if (node.type == YAML_MAPPING_NODE) { - STACK_DEL(emitter, node.data.mapping.pairs); - } - } - - STACK_DEL(emitter, emitter->document->nodes); - yaml_free(emitter->anchors); - - emitter->anchors = NULL; - emitter->last_anchor_id = 0; - emitter->document = NULL; -} - -/* - * Check the references of a node and assign the anchor id if needed. - */ - -static void -yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index) -{ - yaml_node_t *node = emitter->document->nodes.start + index - 1; - yaml_node_item_t *item; - yaml_node_pair_t *pair; - - emitter->anchors[index-1].references ++; - - if (emitter->anchors[index-1].references == 1) { - switch (node->type) { - case YAML_SEQUENCE_NODE: - for (item = node->data.sequence.items.start; - item < node->data.sequence.items.top; item ++) { - yaml_emitter_anchor_node(emitter, *item); - } - break; - case YAML_MAPPING_NODE: - for (pair = node->data.mapping.pairs.start; - pair < node->data.mapping.pairs.top; pair ++) { - yaml_emitter_anchor_node(emitter, pair->key); - yaml_emitter_anchor_node(emitter, pair->value); - } - break; - default: - break; - } - } - - else if (emitter->anchors[index-1].references == 2) { - emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id); - } -} - -/* - * Generate a textual representation for an anchor. - */ - -#define ANCHOR_TEMPLATE "id%03d" -#define ANCHOR_TEMPLATE_LENGTH 16 - -static yaml_char_t * -yaml_emitter_generate_anchor(SHIM(yaml_emitter_t *emitter), int anchor_id) -{ - yaml_char_t *anchor = YAML_MALLOC(ANCHOR_TEMPLATE_LENGTH); - - if (!anchor) return NULL; - - sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id); - - return anchor; -} - -/* - * Serialize a node. - */ - -static int -yaml_emitter_dump_node(yaml_emitter_t *emitter, int index) -{ - yaml_node_t *node = emitter->document->nodes.start + index - 1; - int anchor_id = emitter->anchors[index-1].anchor; - yaml_char_t *anchor = NULL; - - if (anchor_id) { - anchor = yaml_emitter_generate_anchor(emitter, anchor_id); - if (!anchor) return 0; - } - - if (emitter->anchors[index-1].serialized) { - return yaml_emitter_dump_alias(emitter, anchor); - } - - emitter->anchors[index-1].serialized = 1; - - switch (node->type) { - case YAML_SCALAR_NODE: - return yaml_emitter_dump_scalar(emitter, node, anchor); - case YAML_SEQUENCE_NODE: - return yaml_emitter_dump_sequence(emitter, node, anchor); - case YAML_MAPPING_NODE: - return yaml_emitter_dump_mapping(emitter, node, anchor); - default: - assert(0); /* Could not happen. */ - break; - } - - return 0; /* Could not happen. */ -} - -/* - * Serialize an alias. - */ - -static int -yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - ALIAS_EVENT_INIT(event, anchor, mark, mark); - - return yaml_emitter_emit(emitter, &event); -} - -/* - * Serialize a scalar. - */ - -static int -yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - int plain_implicit = (strcmp((char *)node->tag, - YAML_DEFAULT_SCALAR_TAG) == 0); - int quoted_implicit = (strcmp((char *)node->tag, - YAML_DEFAULT_SCALAR_TAG) == 0); - - SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value, - node->data.scalar.length, plain_implicit, quoted_implicit, - node->data.scalar.style, mark, mark); - - return yaml_emitter_emit(emitter, &event); -} - -/* - * Serialize a sequence. - */ - -static int -yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0); - - yaml_node_item_t *item; - - SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit, - node->data.sequence.style, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) return 0; - - for (item = node->data.sequence.items.start; - item < node->data.sequence.items.top; item ++) { - if (!yaml_emitter_dump_node(emitter, *item)) return 0; - } - - SEQUENCE_END_EVENT_INIT(event, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) return 0; - - return 1; -} - -/* - * Serialize a mapping. - */ - -static int -yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, - yaml_char_t *anchor) -{ - yaml_event_t event; - yaml_mark_t mark = { 0, 0, 0 }; - - int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0); - - yaml_node_pair_t *pair; - - MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit, - node->data.mapping.style, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) return 0; - - for (pair = node->data.mapping.pairs.start; - pair < node->data.mapping.pairs.top; pair ++) { - if (!yaml_emitter_dump_node(emitter, pair->key)) return 0; - if (!yaml_emitter_dump_node(emitter, pair->value)) return 0; - } - - MAPPING_END_EVENT_INIT(event, mark, mark); - if (!yaml_emitter_emit(emitter, &event)) return 0; - - return 1; -} - diff --git a/3rdparty/libyaml/src/emitter.c b/3rdparty/libyaml/src/emitter.c deleted file mode 100644 index b9392e40..00000000 --- a/3rdparty/libyaml/src/emitter.c +++ /dev/null @@ -1,2324 +0,0 @@ - -#include "yaml_private.h" - -/* - * Flush the buffer if needed. - */ - -#define FLUSH(emitter) \ - ((emitter->buffer.pointer+5 < emitter->buffer.end) \ - || yaml_emitter_flush(emitter)) - -/* - * Put a character to the output buffer. - */ - -#define PUT(emitter,value) \ - (FLUSH(emitter) \ - && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \ - emitter->column++, \ - 1)) - -/* - * Put a line break to the output buffer. - */ - -#define PUT_BREAK(emitter) \ - (FLUSH(emitter) \ - && ((emitter->line_break == YAML_CR_BREAK ? \ - (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \ - emitter->line_break == YAML_LN_BREAK ? \ - (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \ - emitter->line_break == YAML_CRLN_BREAK ? \ - (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \ - *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \ - emitter->column = 0, \ - emitter->line ++, \ - 1)) - -/* - * Copy a character from a string into buffer. - */ - -#define WRITE(emitter,string) \ - (FLUSH(emitter) \ - && (COPY(emitter->buffer,string), \ - emitter->column ++, \ - 1)) - -/* - * Copy a line break character from a string into buffer. - */ - -#define WRITE_BREAK(emitter,string) \ - (FLUSH(emitter) \ - && (CHECK(string,'\n') ? \ - (PUT_BREAK(emitter), \ - string.pointer ++, \ - 1) : \ - (COPY(emitter->buffer,string), \ - emitter->column = 0, \ - emitter->line ++, \ - 1))) - -/* - * API functions. - */ - -YAML_DECLARE(int) -yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); - -/* - * Utility functions. - */ - -static int -yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem); - -static int -yaml_emitter_need_more_events(yaml_emitter_t *emitter); - -static int -yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, - yaml_tag_directive_t value, int allow_duplicates); - -static int -yaml_emitter_increase_indent(yaml_emitter_t *emitter, - int flow, int indentless); - -/* - * State functions. - */ - -static int -yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event); - -static int -yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, - yaml_event_t *event); - -static int -yaml_emitter_emit_document_start(yaml_emitter_t *emitter, - yaml_event_t *event, int first); - -static int -yaml_emitter_emit_document_content(yaml_emitter_t *emitter, - yaml_event_t *event); - -static int -yaml_emitter_emit_document_end(yaml_emitter_t *emitter, - yaml_event_t *event); - -static int -yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, - yaml_event_t *event, int first); - -static int -yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, - yaml_event_t *event, int first); - -static int -yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, - yaml_event_t *event, int simple); - -static int -yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, - yaml_event_t *event, int first); - -static int -yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, - yaml_event_t *event, int first); - -static int -yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, - yaml_event_t *event, int simple); - -static int -yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, - int root, int sequence, int mapping, int simple_key); - -static int -yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event); - -static int -yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event); - -static int -yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event); - -static int -yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event); - -/* - * Checkers. - */ - -static int -yaml_emitter_check_empty_document(yaml_emitter_t *emitter); - -static int -yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter); - -static int -yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter); - -static int -yaml_emitter_check_simple_key(yaml_emitter_t *emitter); - -static int -yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event); - -/* - * Processors. - */ - -static int -yaml_emitter_process_anchor(yaml_emitter_t *emitter); - -static int -yaml_emitter_process_tag(yaml_emitter_t *emitter); - -static int -yaml_emitter_process_scalar(yaml_emitter_t *emitter); - -/* - * Analyzers. - */ - -static int -yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, - yaml_version_directive_t version_directive); - -static int -yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, - yaml_tag_directive_t tag_directive); - -static int -yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, - yaml_char_t *anchor, int alias); - -static int -yaml_emitter_analyze_tag(yaml_emitter_t *emitter, - yaml_char_t *tag); - -static int -yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length); - -static int -yaml_emitter_analyze_event(yaml_emitter_t *emitter, - yaml_event_t *event); - -/* - * Writers. - */ - -static int -yaml_emitter_write_bom(yaml_emitter_t *emitter); - -static int -yaml_emitter_write_indent(yaml_emitter_t *emitter); - -static int -yaml_emitter_write_indicator(yaml_emitter_t *emitter, - const char *indicator, int need_whitespace, - int is_whitespace, int is_indention); - -static int -yaml_emitter_write_anchor(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length); - -static int -yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length); - -static int -yaml_emitter_write_tag_content(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int need_whitespace); - -static int -yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks); - -static int -yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks); - -static int -yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks); - -static int -yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, - yaml_string_t string); - -static int -yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length); - -static int -yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length); - -/* - * Set an emitter error and return 0. - */ - -static int -yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem) -{ - emitter->error = YAML_EMITTER_ERROR; - emitter->problem = problem; - - return 0; -} - -/* - * Emit an event. - */ - -YAML_DECLARE(int) -yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) -{ - if (!ENQUEUE(emitter, emitter->events, *event)) { - yaml_event_delete(event); - return 0; - } - - while (!yaml_emitter_need_more_events(emitter)) { - if (!yaml_emitter_analyze_event(emitter, emitter->events.head)) - return 0; - if (!yaml_emitter_state_machine(emitter, emitter->events.head)) - return 0; - yaml_event_delete(&DEQUEUE(emitter, emitter->events)); - } - - return 1; -} - -/* - * Check if we need to accumulate more events before emitting. - * - * We accumulate extra - * - 1 event for DOCUMENT-START - * - 2 events for SEQUENCE-START - * - 3 events for MAPPING-START - */ - -static int -yaml_emitter_need_more_events(yaml_emitter_t *emitter) -{ - int level = 0; - int accumulate = 0; - yaml_event_t *event; - - if (QUEUE_EMPTY(emitter, emitter->events)) - return 1; - - switch (emitter->events.head->type) { - case YAML_DOCUMENT_START_EVENT: - accumulate = 1; - break; - case YAML_SEQUENCE_START_EVENT: - accumulate = 2; - break; - case YAML_MAPPING_START_EVENT: - accumulate = 3; - break; - default: - return 0; - } - - if (emitter->events.tail - emitter->events.head > accumulate) - return 0; - - for (event = emitter->events.head; event != emitter->events.tail; event ++) { - switch (event->type) { - case YAML_STREAM_START_EVENT: - case YAML_DOCUMENT_START_EVENT: - case YAML_SEQUENCE_START_EVENT: - case YAML_MAPPING_START_EVENT: - level += 1; - break; - case YAML_STREAM_END_EVENT: - case YAML_DOCUMENT_END_EVENT: - case YAML_SEQUENCE_END_EVENT: - case YAML_MAPPING_END_EVENT: - level -= 1; - break; - default: - break; - } - if (!level) - return 0; - } - - return 1; -} - -/* - * Append a directive to the directives stack. - */ - -static int -yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, - yaml_tag_directive_t value, int allow_duplicates) -{ - yaml_tag_directive_t *tag_directive; - yaml_tag_directive_t copy = { NULL, NULL }; - - for (tag_directive = emitter->tag_directives.start; - tag_directive != emitter->tag_directives.top; tag_directive ++) { - if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { - if (allow_duplicates) - return 1; - return yaml_emitter_set_emitter_error(emitter, - "duplicate %TAG directive"); - } - } - - copy.handle = yaml_strdup(value.handle); - copy.prefix = yaml_strdup(value.prefix); - if (!copy.handle || !copy.prefix) { - emitter->error = YAML_MEMORY_ERROR; - goto error; - } - - if (!PUSH(emitter, emitter->tag_directives, copy)) - goto error; - - return 1; - -error: - yaml_free(copy.handle); - yaml_free(copy.prefix); - return 0; -} - -/* - * Increase the indentation level. - */ - -static int -yaml_emitter_increase_indent(yaml_emitter_t *emitter, - int flow, int indentless) -{ - if (!PUSH(emitter, emitter->indents, emitter->indent)) - return 0; - - if (emitter->indent < 0) { - emitter->indent = flow ? emitter->best_indent : 0; - } - else if (!indentless) { - emitter->indent += emitter->best_indent; - } - - return 1; -} - -/* - * State dispatcher. - */ - -static int -yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event) -{ - switch (emitter->state) - { - case YAML_EMIT_STREAM_START_STATE: - return yaml_emitter_emit_stream_start(emitter, event); - - case YAML_EMIT_FIRST_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, 1); - - case YAML_EMIT_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, 0); - - case YAML_EMIT_DOCUMENT_CONTENT_STATE: - return yaml_emitter_emit_document_content(emitter, event); - - case YAML_EMIT_DOCUMENT_END_STATE: - return yaml_emitter_emit_document_end(emitter, event); - - case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, 1); - - case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, 0); - - case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, 1); - - case YAML_EMIT_FLOW_MAPPING_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, 0); - - case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, 1); - - case YAML_EMIT_FLOW_MAPPING_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, 0); - - case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, 1); - - case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, 0); - - case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, 1); - - case YAML_EMIT_BLOCK_MAPPING_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, 0); - - case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, 1); - - case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, 0); - - case YAML_EMIT_END_STATE: - return yaml_emitter_set_emitter_error(emitter, - "expected nothing after STREAM-END"); - - default: - assert(1); /* Invalid state. */ - } - - return 0; -} - -/* - * Expect STREAM-START. - */ - -static int -yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, - yaml_event_t *event) -{ - if (event->type == YAML_STREAM_START_EVENT) - { - if (!emitter->encoding) { - emitter->encoding = event->data.stream_start.encoding; - } - - if (!emitter->encoding) { - emitter->encoding = YAML_UTF8_ENCODING; - } - - if (emitter->best_indent < 2 || emitter->best_indent > 9) { - emitter->best_indent = 2; - } - - if (emitter->best_width >= 0 - && emitter->best_width <= emitter->best_indent*2) { - emitter->best_width = 80; - } - - if (emitter->best_width < 0) { - emitter->best_width = INT_MAX; - } - - if (!emitter->line_break) { - emitter->line_break = YAML_LN_BREAK; - } - - emitter->indent = -1; - - emitter->line = 0; - emitter->column = 0; - emitter->whitespace = 1; - emitter->indention = 1; - - if (emitter->encoding != YAML_UTF8_ENCODING) { - if (!yaml_emitter_write_bom(emitter)) - return 0; - } - - emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE; - - return 1; - } - - return yaml_emitter_set_emitter_error(emitter, - "expected STREAM-START"); -} - -/* - * Expect DOCUMENT-START or STREAM-END. - */ - -static int -yaml_emitter_emit_document_start(yaml_emitter_t *emitter, - yaml_event_t *event, int first) -{ - if (event->type == YAML_DOCUMENT_START_EVENT) - { - yaml_tag_directive_t default_tag_directives[] = { - {(yaml_char_t *)"!", (yaml_char_t *)"!"}, - {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, - {NULL, NULL} - }; - yaml_tag_directive_t *tag_directive; - int implicit; - - if (event->data.document_start.version_directive) { - if (!yaml_emitter_analyze_version_directive(emitter, - *event->data.document_start.version_directive)) - return 0; - } - - for (tag_directive = event->data.document_start.tag_directives.start; - tag_directive != event->data.document_start.tag_directives.end; - tag_directive ++) { - if (!yaml_emitter_analyze_tag_directive(emitter, *tag_directive)) - return 0; - if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0)) - return 0; - } - - for (tag_directive = default_tag_directives; - tag_directive->handle; tag_directive ++) { - if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1)) - return 0; - } - - implicit = event->data.document_start.implicit; - if (!first || emitter->canonical) { - implicit = 0; - } - - if ((event->data.document_start.version_directive || - (event->data.document_start.tag_directives.start - != event->data.document_start.tag_directives.end)) && - emitter->open_ended) - { - if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - - if (event->data.document_start.version_directive) { - implicit = 0; - if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - - if (event->data.document_start.tag_directives.start - != event->data.document_start.tag_directives.end) { - implicit = 0; - for (tag_directive = event->data.document_start.tag_directives.start; - tag_directive != event->data.document_start.tag_directives.end; - tag_directive ++) { - if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle, - strlen((char *)tag_directive->handle))) - return 0; - if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix, - strlen((char *)tag_directive->prefix), 1)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - } - - if (yaml_emitter_check_empty_document(emitter)) { - implicit = 0; - } - - if (!implicit) { - if (!yaml_emitter_write_indent(emitter)) - return 0; - if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0)) - return 0; - if (emitter->canonical) { - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - } - - emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE; - - return 1; - } - - else if (event->type == YAML_STREAM_END_EVENT) - { - - if (!yaml_emitter_flush(emitter)) - return 0; - - emitter->state = YAML_EMIT_END_STATE; - - return 1; - } - - return yaml_emitter_set_emitter_error(emitter, - "expected DOCUMENT-START or STREAM-END"); -} - -/* - * Expect the root node. - */ - -static int -yaml_emitter_emit_document_content(yaml_emitter_t *emitter, - yaml_event_t *event) -{ - if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0); -} - -/* - * Expect DOCUMENT-END. - */ - -static int -yaml_emitter_emit_document_end(yaml_emitter_t *emitter, - yaml_event_t *event) -{ - if (event->type == YAML_DOCUMENT_END_EVENT) - { - if (!yaml_emitter_write_indent(emitter)) - return 0; - if (!event->data.document_end.implicit) { - if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - if (!yaml_emitter_flush(emitter)) - return 0; - - emitter->state = YAML_EMIT_DOCUMENT_START_STATE; - - while (!STACK_EMPTY(emitter, emitter->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(emitter, - emitter->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - - return 1; - } - - return yaml_emitter_set_emitter_error(emitter, - "expected DOCUMENT-END"); -} - -/* - * - * Expect a flow item node. - */ - -static int -yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, - yaml_event_t *event, int first) -{ - if (first) - { - if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0)) - return 0; - if (!yaml_emitter_increase_indent(emitter, 1, 0)) - return 0; - emitter->flow_level ++; - } - - if (event->type == YAML_SEQUENCE_END_EVENT) - { - emitter->flow_level --; - emitter->indent = POP(emitter, emitter->indents); - if (emitter->canonical && !first) { - if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0)) - return 0; - emitter->state = POP(emitter, emitter->states); - - return 1; - } - - if (!first) { - if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) - return 0; - } - - if (emitter->canonical || emitter->column > emitter->best_width) { - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); -} - -/* - * Expect a flow key node. - */ - -static int -yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, - yaml_event_t *event, int first) -{ - if (first) - { - if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0)) - return 0; - if (!yaml_emitter_increase_indent(emitter, 1, 0)) - return 0; - emitter->flow_level ++; - } - - if (event->type == YAML_MAPPING_END_EVENT) - { - emitter->flow_level --; - emitter->indent = POP(emitter, emitter->indents); - if (emitter->canonical && !first) { - if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) - return 0; - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0)) - return 0; - emitter->state = POP(emitter, emitter->states); - - return 1; - } - - if (!first) { - if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) - return 0; - } - if (emitter->canonical || emitter->column > emitter->best_width) { - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - - if (!emitter->canonical && yaml_emitter_check_simple_key(emitter)) - { - if (!PUSH(emitter, emitter->states, - YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); - } - else - { - if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0)) - return 0; - if (!PUSH(emitter, emitter->states, - YAML_EMIT_FLOW_MAPPING_VALUE_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); - } -} - -/* - * Expect a flow value node. - */ - -static int -yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, - yaml_event_t *event, int simple) -{ - if (simple) { - if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) - return 0; - } - else { - if (emitter->canonical || emitter->column > emitter->best_width) { - if (!yaml_emitter_write_indent(emitter)) - return 0; - } - if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0)) - return 0; - } - if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE)) - return 0; - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); -} - -/* - * Expect a block item node. - */ - -static int -yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, - yaml_event_t *event, int first) -{ - if (first) - { - if (!yaml_emitter_increase_indent(emitter, 0, - (emitter->mapping_context && !emitter->indention))) - return 0; - } - - if (event->type == YAML_SEQUENCE_END_EVENT) - { - emitter->indent = POP(emitter, emitter->indents); - emitter->state = POP(emitter, emitter->states); - - return 1; - } - - if (!yaml_emitter_write_indent(emitter)) - return 0; - if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1)) - return 0; - if (!PUSH(emitter, emitter->states, - YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); -} - -/* - * Expect a block key node. - */ - -static int -yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, - yaml_event_t *event, int first) -{ - if (first) - { - if (!yaml_emitter_increase_indent(emitter, 0, 0)) - return 0; - } - - if (event->type == YAML_MAPPING_END_EVENT) - { - emitter->indent = POP(emitter, emitter->indents); - emitter->state = POP(emitter, emitter->states); - - return 1; - } - - if (!yaml_emitter_write_indent(emitter)) - return 0; - - if (yaml_emitter_check_simple_key(emitter)) - { - if (!PUSH(emitter, emitter->states, - YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); - } - else - { - if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1)) - return 0; - if (!PUSH(emitter, emitter->states, - YAML_EMIT_BLOCK_MAPPING_VALUE_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); - } -} - -/* - * Expect a block value node. - */ - -static int -yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, - yaml_event_t *event, int simple) -{ - if (simple) { - if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) - return 0; - } - else { - if (!yaml_emitter_write_indent(emitter)) - return 0; - if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1)) - return 0; - } - if (!PUSH(emitter, emitter->states, - YAML_EMIT_BLOCK_MAPPING_KEY_STATE)) - return 0; - - return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); -} - -/* - * Expect a node. - */ - -static int -yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, - int root, int sequence, int mapping, int simple_key) -{ - emitter->root_context = root; - emitter->sequence_context = sequence; - emitter->mapping_context = mapping; - emitter->simple_key_context = simple_key; - - switch (event->type) - { - case YAML_ALIAS_EVENT: - return yaml_emitter_emit_alias(emitter, event); - - case YAML_SCALAR_EVENT: - return yaml_emitter_emit_scalar(emitter, event); - - case YAML_SEQUENCE_START_EVENT: - return yaml_emitter_emit_sequence_start(emitter, event); - - case YAML_MAPPING_START_EVENT: - return yaml_emitter_emit_mapping_start(emitter, event); - - default: - return yaml_emitter_set_emitter_error(emitter, - "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS"); - } - - return 0; -} - -/* - * Expect ALIAS. - */ - -static int -yaml_emitter_emit_alias(yaml_emitter_t *emitter, SHIM(yaml_event_t *event)) -{ - if (!yaml_emitter_process_anchor(emitter)) - return 0; - emitter->state = POP(emitter, emitter->states); - - return 1; -} - -/* - * Expect SCALAR. - */ - -static int -yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event) -{ - if (!yaml_emitter_select_scalar_style(emitter, event)) - return 0; - if (!yaml_emitter_process_anchor(emitter)) - return 0; - if (!yaml_emitter_process_tag(emitter)) - return 0; - if (!yaml_emitter_increase_indent(emitter, 1, 0)) - return 0; - if (!yaml_emitter_process_scalar(emitter)) - return 0; - emitter->indent = POP(emitter, emitter->indents); - emitter->state = POP(emitter, emitter->states); - - return 1; -} - -/* - * Expect SEQUENCE-START. - */ - -static int -yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event) -{ - if (!yaml_emitter_process_anchor(emitter)) - return 0; - if (!yaml_emitter_process_tag(emitter)) - return 0; - - if (emitter->flow_level || emitter->canonical - || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE - || yaml_emitter_check_empty_sequence(emitter)) { - emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; - } - else { - emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; - } - - return 1; -} - -/* - * Expect MAPPING-START. - */ - -static int -yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event) -{ - if (!yaml_emitter_process_anchor(emitter)) - return 0; - if (!yaml_emitter_process_tag(emitter)) - return 0; - - if (emitter->flow_level || emitter->canonical - || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE - || yaml_emitter_check_empty_mapping(emitter)) { - emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; - } - else { - emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; - } - - return 1; -} - -/* - * Check if the document content is an empty scalar. - */ - -static int -yaml_emitter_check_empty_document(SHIM(yaml_emitter_t *emitter)) -{ - return 0; -} - -/* - * Check if the next events represent an empty sequence. - */ - -static int -yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter) -{ - if (emitter->events.tail - emitter->events.head < 2) - return 0; - - return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT - && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT); -} - -/* - * Check if the next events represent an empty mapping. - */ - -static int -yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter) -{ - if (emitter->events.tail - emitter->events.head < 2) - return 0; - - return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT - && emitter->events.head[1].type == YAML_MAPPING_END_EVENT); -} - -/* - * Check if the next node can be expressed as a simple key. - */ - -static int -yaml_emitter_check_simple_key(yaml_emitter_t *emitter) -{ - yaml_event_t *event = emitter->events.head; - size_t length = 0; - - switch (event->type) - { - case YAML_ALIAS_EVENT: - length += emitter->anchor_data.anchor_length; - break; - - case YAML_SCALAR_EVENT: - if (emitter->scalar_data.multiline) - return 0; - length += emitter->anchor_data.anchor_length - + emitter->tag_data.handle_length - + emitter->tag_data.suffix_length - + emitter->scalar_data.length; - break; - - case YAML_SEQUENCE_START_EVENT: - if (!yaml_emitter_check_empty_sequence(emitter)) - return 0; - length += emitter->anchor_data.anchor_length - + emitter->tag_data.handle_length - + emitter->tag_data.suffix_length; - break; - - case YAML_MAPPING_START_EVENT: - if (!yaml_emitter_check_empty_mapping(emitter)) - return 0; - length += emitter->anchor_data.anchor_length - + emitter->tag_data.handle_length - + emitter->tag_data.suffix_length; - break; - - default: - return 0; - } - - if (length > 128) - return 0; - - return 1; -} - -/* - * Determine an acceptable scalar style. - */ - -static int -yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) -{ - yaml_scalar_style_t style = event->data.scalar.style; - int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix); - - if (no_tag && !event->data.scalar.plain_implicit - && !event->data.scalar.quoted_implicit) { - return yaml_emitter_set_emitter_error(emitter, - "neither tag nor implicit flags are specified"); - } - - if (style == YAML_ANY_SCALAR_STYLE) - style = YAML_PLAIN_SCALAR_STYLE; - - if (emitter->canonical) - style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; - - if (emitter->simple_key_context && emitter->scalar_data.multiline) - style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; - - if (style == YAML_PLAIN_SCALAR_STYLE) - { - if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed) - || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed)) - style = YAML_SINGLE_QUOTED_SCALAR_STYLE; - if (!emitter->scalar_data.length - && (emitter->flow_level || emitter->simple_key_context)) - style = YAML_SINGLE_QUOTED_SCALAR_STYLE; - if (no_tag && !event->data.scalar.plain_implicit) - style = YAML_SINGLE_QUOTED_SCALAR_STYLE; - } - - if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE) - { - if (!emitter->scalar_data.single_quoted_allowed) - style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; - } - - if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE) - { - if (!emitter->scalar_data.block_allowed - || emitter->flow_level || emitter->simple_key_context) - style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; - } - - if (no_tag && !event->data.scalar.quoted_implicit - && style != YAML_PLAIN_SCALAR_STYLE) - { - emitter->tag_data.handle = (yaml_char_t *)"!"; - emitter->tag_data.handle_length = 1; - } - - emitter->scalar_data.style = style; - - return 1; -} - -/* - * Write an achor. - */ - -static int -yaml_emitter_process_anchor(yaml_emitter_t *emitter) -{ - if (!emitter->anchor_data.anchor) - return 1; - - if (!yaml_emitter_write_indicator(emitter, - (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0)) - return 0; - - return yaml_emitter_write_anchor(emitter, - emitter->anchor_data.anchor, emitter->anchor_data.anchor_length); -} - -/* - * Write a tag. - */ - -static int -yaml_emitter_process_tag(yaml_emitter_t *emitter) -{ - if (!emitter->tag_data.handle && !emitter->tag_data.suffix) - return 1; - - if (emitter->tag_data.handle) - { - if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle, - emitter->tag_data.handle_length)) - return 0; - if (emitter->tag_data.suffix) { - if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, - emitter->tag_data.suffix_length, 0)) - return 0; - } - } - else - { - if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, - emitter->tag_data.suffix_length, 0)) - return 0; - if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0)) - return 0; - } - - return 1; -} - -/* - * Write a scalar. - */ - -static int -yaml_emitter_process_scalar(yaml_emitter_t *emitter) -{ - switch (emitter->scalar_data.style) - { - case YAML_PLAIN_SCALAR_STYLE: - return yaml_emitter_write_plain_scalar(emitter, - emitter->scalar_data.value, emitter->scalar_data.length, - !emitter->simple_key_context); - - case YAML_SINGLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_single_quoted_scalar(emitter, - emitter->scalar_data.value, emitter->scalar_data.length, - !emitter->simple_key_context); - - case YAML_DOUBLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_double_quoted_scalar(emitter, - emitter->scalar_data.value, emitter->scalar_data.length, - !emitter->simple_key_context); - - case YAML_LITERAL_SCALAR_STYLE: - return yaml_emitter_write_literal_scalar(emitter, - emitter->scalar_data.value, emitter->scalar_data.length); - - case YAML_FOLDED_SCALAR_STYLE: - return yaml_emitter_write_folded_scalar(emitter, - emitter->scalar_data.value, emitter->scalar_data.length); - - default: - assert(1); /* Impossible. */ - } - - return 0; -} - -/* - * Check if a %YAML directive is valid. - */ - -static int -yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, - yaml_version_directive_t version_directive) -{ - if (version_directive.major != 1 || version_directive.minor != 1) { - return yaml_emitter_set_emitter_error(emitter, - "incompatible %YAML directive"); - } - - return 1; -} - -/* - * Check if a %TAG directive is valid. - */ - -static int -yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, - yaml_tag_directive_t tag_directive) -{ - yaml_string_t handle; - yaml_string_t prefix; - size_t handle_length; - size_t prefix_length; - - handle_length = strlen((char *)tag_directive.handle); - prefix_length = strlen((char *)tag_directive.prefix); - STRING_ASSIGN(handle, tag_directive.handle, handle_length); - STRING_ASSIGN(prefix, tag_directive.prefix, prefix_length); - - if (handle.start == handle.end) { - return yaml_emitter_set_emitter_error(emitter, - "tag handle must not be empty"); - } - - if (handle.start[0] != '!') { - return yaml_emitter_set_emitter_error(emitter, - "tag handle must start with '!'"); - } - - if (handle.end[-1] != '!') { - return yaml_emitter_set_emitter_error(emitter, - "tag handle must end with '!'"); - } - - handle.pointer ++; - - while (handle.pointer < handle.end-1) { - if (!IS_ALPHA(handle)) { - return yaml_emitter_set_emitter_error(emitter, - "tag handle must contain alphanumerical characters only"); - } - MOVE(handle); - } - - if (prefix.start == prefix.end) { - return yaml_emitter_set_emitter_error(emitter, - "tag prefix must not be empty"); - } - - return 1; -} - -/* - * Check if an anchor is valid. - */ - -static int -yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, - yaml_char_t *anchor, int alias) -{ - size_t anchor_length; - yaml_string_t string; - - anchor_length = strlen((char *)anchor); - STRING_ASSIGN(string, anchor, anchor_length); - - if (string.start == string.end) { - return yaml_emitter_set_emitter_error(emitter, alias ? - "alias value must not be empty" : - "anchor value must not be empty"); - } - - while (string.pointer != string.end) { - if (!IS_ALPHA(string)) { - return yaml_emitter_set_emitter_error(emitter, alias ? - "alias value must contain alphanumerical characters only" : - "anchor value must contain alphanumerical characters only"); - } - MOVE(string); - } - - emitter->anchor_data.anchor = string.start; - emitter->anchor_data.anchor_length = string.end - string.start; - emitter->anchor_data.alias = alias; - - return 1; -} - -/* - * Check if a tag is valid. - */ - -static int -yaml_emitter_analyze_tag(yaml_emitter_t *emitter, - yaml_char_t *tag) -{ - size_t tag_length; - yaml_string_t string; - yaml_tag_directive_t *tag_directive; - - tag_length = strlen((char *)tag); - STRING_ASSIGN(string, tag, tag_length); - - if (string.start == string.end) { - return yaml_emitter_set_emitter_error(emitter, - "tag value must not be empty"); - } - - for (tag_directive = emitter->tag_directives.start; - tag_directive != emitter->tag_directives.top; tag_directive ++) { - size_t prefix_length = strlen((char *)tag_directive->prefix); - if (prefix_length < (size_t)(string.end - string.start) - && strncmp((char *)tag_directive->prefix, (char *)string.start, - prefix_length) == 0) - { - emitter->tag_data.handle = tag_directive->handle; - emitter->tag_data.handle_length = - strlen((char *)tag_directive->handle); - emitter->tag_data.suffix = string.start + prefix_length; - emitter->tag_data.suffix_length = - (string.end - string.start) - prefix_length; - return 1; - } - } - - emitter->tag_data.suffix = string.start; - emitter->tag_data.suffix_length = string.end - string.start; - - return 1; -} - -/* - * Check if a scalar is valid. - */ - -static int -yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length) -{ - yaml_string_t string; - - int block_indicators = 0; - int flow_indicators = 0; - int line_breaks = 0; - int special_characters = 0; - - int leading_space = 0; - int leading_break = 0; - int trailing_space = 0; - int trailing_break = 0; - int break_space = 0; - int space_break = 0; - - int preceded_by_whitespace = 0; - int followed_by_whitespace = 0; - int previous_space = 0; - int previous_break = 0; - - STRING_ASSIGN(string, value, length); - - emitter->scalar_data.value = value; - emitter->scalar_data.length = length; - - if (string.start == string.end) - { - emitter->scalar_data.multiline = 0; - emitter->scalar_data.flow_plain_allowed = 0; - emitter->scalar_data.block_plain_allowed = 1; - emitter->scalar_data.single_quoted_allowed = 1; - emitter->scalar_data.block_allowed = 0; - - return 1; - } - - if ((CHECK_AT(string, '-', 0) - && CHECK_AT(string, '-', 1) - && CHECK_AT(string, '-', 2)) - || (CHECK_AT(string, '.', 0) - && CHECK_AT(string, '.', 1) - && CHECK_AT(string, '.', 2))) { - block_indicators = 1; - flow_indicators = 1; - } - - preceded_by_whitespace = 1; - followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); - - while (string.pointer != string.end) - { - if (string.start == string.pointer) - { - if (CHECK(string, '#') || CHECK(string, ',') - || CHECK(string, '[') || CHECK(string, ']') - || CHECK(string, '{') || CHECK(string, '}') - || CHECK(string, '&') || CHECK(string, '*') - || CHECK(string, '!') || CHECK(string, '|') - || CHECK(string, '>') || CHECK(string, '\'') - || CHECK(string, '"') || CHECK(string, '%') - || CHECK(string, '@') || CHECK(string, '`')) { - flow_indicators = 1; - block_indicators = 1; - } - - if (CHECK(string, '?') || CHECK(string, ':')) { - flow_indicators = 1; - if (followed_by_whitespace) { - block_indicators = 1; - } - } - - if (CHECK(string, '-') && followed_by_whitespace) { - flow_indicators = 1; - block_indicators = 1; - } - } - else - { - if (CHECK(string, ',') || CHECK(string, '?') - || CHECK(string, '[') || CHECK(string, ']') - || CHECK(string, '{') || CHECK(string, '}')) { - flow_indicators = 1; - } - - if (CHECK(string, ':')) { - flow_indicators = 1; - if (followed_by_whitespace) { - block_indicators = 1; - } - } - - if (CHECK(string, '#') && preceded_by_whitespace) { - flow_indicators = 1; - block_indicators = 1; - } - } - - if (!IS_PRINTABLE(string) - || (!IS_ASCII(string) && !emitter->unicode)) { - special_characters = 1; - } - - if (IS_BREAK(string)) { - line_breaks = 1; - } - - if (IS_SPACE(string)) - { - if (string.start == string.pointer) { - leading_space = 1; - } - if (string.pointer+WIDTH(string) == string.end) { - trailing_space = 1; - } - if (previous_break) { - break_space = 1; - } - previous_space = 1; - previous_break = 0; - } - else if (IS_BREAK(string)) - { - if (string.start == string.pointer) { - leading_break = 1; - } - if (string.pointer+WIDTH(string) == string.end) { - trailing_break = 1; - } - if (previous_space) { - space_break = 1; - } - previous_space = 0; - previous_break = 1; - } - else - { - previous_space = 0; - previous_break = 0; - } - - preceded_by_whitespace = IS_BLANKZ(string); - MOVE(string); - if (string.pointer != string.end) { - followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); - } - } - - emitter->scalar_data.multiline = line_breaks; - - emitter->scalar_data.flow_plain_allowed = 1; - emitter->scalar_data.block_plain_allowed = 1; - emitter->scalar_data.single_quoted_allowed = 1; - emitter->scalar_data.block_allowed = 1; - - if (leading_space || leading_break || trailing_space || trailing_break) { - emitter->scalar_data.flow_plain_allowed = 0; - emitter->scalar_data.block_plain_allowed = 0; - } - - if (trailing_space) { - emitter->scalar_data.block_allowed = 0; - } - - if (break_space) { - emitter->scalar_data.flow_plain_allowed = 0; - emitter->scalar_data.block_plain_allowed = 0; - emitter->scalar_data.single_quoted_allowed = 0; - } - - if (space_break || special_characters) { - emitter->scalar_data.flow_plain_allowed = 0; - emitter->scalar_data.block_plain_allowed = 0; - emitter->scalar_data.single_quoted_allowed = 0; - emitter->scalar_data.block_allowed = 0; - } - - if (line_breaks) { - emitter->scalar_data.flow_plain_allowed = 0; - emitter->scalar_data.block_plain_allowed = 0; - } - - if (flow_indicators) { - emitter->scalar_data.flow_plain_allowed = 0; - } - - if (block_indicators) { - emitter->scalar_data.block_plain_allowed = 0; - } - - return 1; -} - -/* - * Check if the event data is valid. - */ - -static int -yaml_emitter_analyze_event(yaml_emitter_t *emitter, - yaml_event_t *event) -{ - emitter->anchor_data.anchor = NULL; - emitter->anchor_data.anchor_length = 0; - emitter->tag_data.handle = NULL; - emitter->tag_data.handle_length = 0; - emitter->tag_data.suffix = NULL; - emitter->tag_data.suffix_length = 0; - emitter->scalar_data.value = NULL; - emitter->scalar_data.length = 0; - - switch (event->type) - { - case YAML_ALIAS_EVENT: - if (!yaml_emitter_analyze_anchor(emitter, - event->data.alias.anchor, 1)) - return 0; - return 1; - - case YAML_SCALAR_EVENT: - if (event->data.scalar.anchor) { - if (!yaml_emitter_analyze_anchor(emitter, - event->data.scalar.anchor, 0)) - return 0; - } - if (event->data.scalar.tag && (emitter->canonical || - (!event->data.scalar.plain_implicit - && !event->data.scalar.quoted_implicit))) { - if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag)) - return 0; - } - if (!yaml_emitter_analyze_scalar(emitter, - event->data.scalar.value, event->data.scalar.length)) - return 0; - return 1; - - case YAML_SEQUENCE_START_EVENT: - if (event->data.sequence_start.anchor) { - if (!yaml_emitter_analyze_anchor(emitter, - event->data.sequence_start.anchor, 0)) - return 0; - } - if (event->data.sequence_start.tag && (emitter->canonical || - !event->data.sequence_start.implicit)) { - if (!yaml_emitter_analyze_tag(emitter, - event->data.sequence_start.tag)) - return 0; - } - return 1; - - case YAML_MAPPING_START_EVENT: - if (event->data.mapping_start.anchor) { - if (!yaml_emitter_analyze_anchor(emitter, - event->data.mapping_start.anchor, 0)) - return 0; - } - if (event->data.mapping_start.tag && (emitter->canonical || - !event->data.mapping_start.implicit)) { - if (!yaml_emitter_analyze_tag(emitter, - event->data.mapping_start.tag)) - return 0; - } - return 1; - - default: - return 1; - } -} - -/* - * Write the BOM character. - */ - -static int -yaml_emitter_write_bom(yaml_emitter_t *emitter) -{ - if (!FLUSH(emitter)) return 0; - - *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF'; - *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB'; - *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF'; - - return 1; -} - -static int -yaml_emitter_write_indent(yaml_emitter_t *emitter) -{ - int indent = (emitter->indent >= 0) ? emitter->indent : 0; - - if (!emitter->indention || emitter->column > indent - || (emitter->column == indent && !emitter->whitespace)) { - if (!PUT_BREAK(emitter)) return 0; - } - - while (emitter->column < indent) { - if (!PUT(emitter, ' ')) return 0; - } - - emitter->whitespace = 1; - emitter->indention = 1; - - return 1; -} - -static int -yaml_emitter_write_indicator(yaml_emitter_t *emitter, - const char *indicator, int need_whitespace, - int is_whitespace, int is_indention) -{ - size_t indicator_length; - yaml_string_t string; - - indicator_length = strlen(indicator); - STRING_ASSIGN(string, (yaml_char_t *)indicator, indicator_length); - - if (need_whitespace && !emitter->whitespace) { - if (!PUT(emitter, ' ')) return 0; - } - - while (string.pointer != string.end) { - if (!WRITE(emitter, string)) return 0; - } - - emitter->whitespace = is_whitespace; - emitter->indention = (emitter->indention && is_indention); - emitter->open_ended = 0; - - return 1; -} - -static int -yaml_emitter_write_anchor(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length) -{ - yaml_string_t string; - STRING_ASSIGN(string, value, length); - - while (string.pointer != string.end) { - if (!WRITE(emitter, string)) return 0; - } - - emitter->whitespace = 0; - emitter->indention = 0; - - return 1; -} - -static int -yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length) -{ - yaml_string_t string; - STRING_ASSIGN(string, value, length); - - if (!emitter->whitespace) { - if (!PUT(emitter, ' ')) return 0; - } - - while (string.pointer != string.end) { - if (!WRITE(emitter, string)) return 0; - } - - emitter->whitespace = 0; - emitter->indention = 0; - - return 1; -} - -static int -yaml_emitter_write_tag_content(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, - int need_whitespace) -{ - yaml_string_t string; - STRING_ASSIGN(string, value, length); - - if (need_whitespace && !emitter->whitespace) { - if (!PUT(emitter, ' ')) return 0; - } - - while (string.pointer != string.end) { - if (IS_ALPHA(string) - || CHECK(string, ';') || CHECK(string, '/') - || CHECK(string, '?') || CHECK(string, ':') - || CHECK(string, '@') || CHECK(string, '&') - || CHECK(string, '=') || CHECK(string, '+') - || CHECK(string, '$') || CHECK(string, ',') - || CHECK(string, '_') || CHECK(string, '.') - || CHECK(string, '~') || CHECK(string, '*') - || CHECK(string, '\'') || CHECK(string, '(') - || CHECK(string, ')') || CHECK(string, '[') - || CHECK(string, ']')) { - if (!WRITE(emitter, string)) return 0; - } - else { - int width = WIDTH(string); - unsigned int value; - while (width --) { - value = *(string.pointer++); - if (!PUT(emitter, '%')) return 0; - if (!PUT(emitter, (value >> 4) - + ((value >> 4) < 10 ? '0' : 'A' - 10))) - return 0; - if (!PUT(emitter, (value & 0x0F) - + ((value & 0x0F) < 10 ? '0' : 'A' - 10))) - return 0; - } - } - } - - emitter->whitespace = 0; - emitter->indention = 0; - - return 1; -} - -static int -yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks) -{ - yaml_string_t string; - int spaces = 0; - int breaks = 0; - - STRING_ASSIGN(string, value, length); - - if (!emitter->whitespace) { - if (!PUT(emitter, ' ')) return 0; - } - - while (string.pointer != string.end) - { - if (IS_SPACE(string)) - { - if (allow_breaks && !spaces - && emitter->column > emitter->best_width - && !IS_SPACE_AT(string, 1)) { - if (!yaml_emitter_write_indent(emitter)) return 0; - MOVE(string); - } - else { - if (!WRITE(emitter, string)) return 0; - } - spaces = 1; - } - else if (IS_BREAK(string)) - { - if (!breaks && CHECK(string, '\n')) { - if (!PUT_BREAK(emitter)) return 0; - } - if (!WRITE_BREAK(emitter, string)) return 0; - emitter->indention = 1; - breaks = 1; - } - else - { - if (breaks) { - if (!yaml_emitter_write_indent(emitter)) return 0; - } - if (!WRITE(emitter, string)) return 0; - emitter->indention = 0; - spaces = 0; - breaks = 0; - } - } - - emitter->whitespace = 0; - emitter->indention = 0; - if (emitter->root_context) - { - emitter->open_ended = 1; - } - - return 1; -} - -static int -yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks) -{ - yaml_string_t string; - int spaces = 0; - int breaks = 0; - - STRING_ASSIGN(string, value, length); - - if (!yaml_emitter_write_indicator(emitter, "'", 1, 0, 0)) - return 0; - - while (string.pointer != string.end) - { - if (IS_SPACE(string)) - { - if (allow_breaks && !spaces - && emitter->column > emitter->best_width - && string.pointer != string.start - && string.pointer != string.end - 1 - && !IS_SPACE_AT(string, 1)) { - if (!yaml_emitter_write_indent(emitter)) return 0; - MOVE(string); - } - else { - if (!WRITE(emitter, string)) return 0; - } - spaces = 1; - } - else if (IS_BREAK(string)) - { - if (!breaks && CHECK(string, '\n')) { - if (!PUT_BREAK(emitter)) return 0; - } - if (!WRITE_BREAK(emitter, string)) return 0; - emitter->indention = 1; - breaks = 1; - } - else - { - if (breaks) { - if (!yaml_emitter_write_indent(emitter)) return 0; - } - if (CHECK(string, '\'')) { - if (!PUT(emitter, '\'')) return 0; - } - if (!WRITE(emitter, string)) return 0; - emitter->indention = 0; - spaces = 0; - breaks = 0; - } - } - - if (breaks) - if (!yaml_emitter_write_indent(emitter)) return 0; - - if (!yaml_emitter_write_indicator(emitter, "'", 0, 0, 0)) - return 0; - - emitter->whitespace = 0; - emitter->indention = 0; - - return 1; -} - -static int -yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length, int allow_breaks) -{ - yaml_string_t string; - int spaces = 0; - - STRING_ASSIGN(string, value, length); - - if (!yaml_emitter_write_indicator(emitter, "\"", 1, 0, 0)) - return 0; - - while (string.pointer != string.end) - { - if (!IS_PRINTABLE(string) || (!emitter->unicode && !IS_ASCII(string)) - || IS_BOM(string) || IS_BREAK(string) - || CHECK(string, '"') || CHECK(string, '\\')) - { - unsigned char octet; - unsigned int width; - unsigned int value; - int k; - - octet = string.pointer[0]; - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - value = (octet & 0x80) == 0x00 ? octet & 0x7F : - (octet & 0xE0) == 0xC0 ? octet & 0x1F : - (octet & 0xF0) == 0xE0 ? octet & 0x0F : - (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; - for (k = 1; k < (int)width; k ++) { - octet = string.pointer[k]; - value = (value << 6) + (octet & 0x3F); - } - string.pointer += width; - - if (!PUT(emitter, '\\')) return 0; - - switch (value) - { - case 0x00: - if (!PUT(emitter, '0')) return 0; - break; - - case 0x07: - if (!PUT(emitter, 'a')) return 0; - break; - - case 0x08: - if (!PUT(emitter, 'b')) return 0; - break; - - case 0x09: - if (!PUT(emitter, 't')) return 0; - break; - - case 0x0A: - if (!PUT(emitter, 'n')) return 0; - break; - - case 0x0B: - if (!PUT(emitter, 'v')) return 0; - break; - - case 0x0C: - if (!PUT(emitter, 'f')) return 0; - break; - - case 0x0D: - if (!PUT(emitter, 'r')) return 0; - break; - - case 0x1B: - if (!PUT(emitter, 'e')) return 0; - break; - - case 0x22: - if (!PUT(emitter, '\"')) return 0; - break; - - case 0x5C: - if (!PUT(emitter, '\\')) return 0; - break; - - case 0x85: - if (!PUT(emitter, 'N')) return 0; - break; - - case 0xA0: - if (!PUT(emitter, '_')) return 0; - break; - - case 0x2028: - if (!PUT(emitter, 'L')) return 0; - break; - - case 0x2029: - if (!PUT(emitter, 'P')) return 0; - break; - - default: - if (value <= 0xFF) { - if (!PUT(emitter, 'x')) return 0; - width = 2; - } - else if (value <= 0xFFFF) { - if (!PUT(emitter, 'u')) return 0; - width = 4; - } - else { - if (!PUT(emitter, 'U')) return 0; - width = 8; - } - for (k = (width-1)*4; k >= 0; k -= 4) { - int digit = (value >> k) & 0x0F; - if (!PUT(emitter, digit + (digit < 10 ? '0' : 'A'-10))) - return 0; - } - } - spaces = 0; - } - else if (IS_SPACE(string)) - { - if (allow_breaks && !spaces - && emitter->column > emitter->best_width - && string.pointer != string.start - && string.pointer != string.end - 1) { - if (!yaml_emitter_write_indent(emitter)) return 0; - if (IS_SPACE_AT(string, 1)) { - if (!PUT(emitter, '\\')) return 0; - } - MOVE(string); - } - else { - if (!WRITE(emitter, string)) return 0; - } - spaces = 1; - } - else - { - if (!WRITE(emitter, string)) return 0; - spaces = 0; - } - } - - if (!yaml_emitter_write_indicator(emitter, "\"", 0, 0, 0)) - return 0; - - emitter->whitespace = 0; - emitter->indention = 0; - - return 1; -} - -static int -yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, - yaml_string_t string) -{ - char indent_hint[2]; - const char *chomp_hint = NULL; - - if (IS_SPACE(string) || IS_BREAK(string)) - { - indent_hint[0] = '0' + (char)emitter->best_indent; - indent_hint[1] = '\0'; - if (!yaml_emitter_write_indicator(emitter, indent_hint, 0, 0, 0)) - return 0; - } - - emitter->open_ended = 0; - - string.pointer = string.end; - if (string.start == string.pointer) - { - chomp_hint = "-"; - } - else - { - do { - string.pointer --; - } while ((*string.pointer & 0xC0) == 0x80); - if (!IS_BREAK(string)) - { - chomp_hint = "-"; - } - else if (string.start == string.pointer) - { - chomp_hint = "+"; - emitter->open_ended = 1; - } - else - { - do { - string.pointer --; - } while ((*string.pointer & 0xC0) == 0x80); - if (IS_BREAK(string)) - { - chomp_hint = "+"; - emitter->open_ended = 1; - } - } - } - - if (chomp_hint) - { - if (!yaml_emitter_write_indicator(emitter, chomp_hint, 0, 0, 0)) - return 0; - } - - return 1; -} - -static int -yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length) -{ - yaml_string_t string; - int breaks = 1; - - STRING_ASSIGN(string, value, length); - - if (!yaml_emitter_write_indicator(emitter, "|", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_block_scalar_hints(emitter, string)) - return 0; - if (!PUT_BREAK(emitter)) return 0; - emitter->indention = 1; - emitter->whitespace = 1; - - while (string.pointer != string.end) - { - if (IS_BREAK(string)) - { - if (!WRITE_BREAK(emitter, string)) return 0; - emitter->indention = 1; - breaks = 1; - } - else - { - if (breaks) { - if (!yaml_emitter_write_indent(emitter)) return 0; - } - if (!WRITE(emitter, string)) return 0; - emitter->indention = 0; - breaks = 0; - } - } - - return 1; -} - -static int -yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, - yaml_char_t *value, size_t length) -{ - yaml_string_t string; - int breaks = 1; - int leading_spaces = 1; - - STRING_ASSIGN(string, value, length); - - if (!yaml_emitter_write_indicator(emitter, ">", 1, 0, 0)) - return 0; - if (!yaml_emitter_write_block_scalar_hints(emitter, string)) - return 0; - if (!PUT_BREAK(emitter)) return 0; - emitter->indention = 1; - emitter->whitespace = 1; - - while (string.pointer != string.end) - { - if (IS_BREAK(string)) - { - if (!breaks && !leading_spaces && CHECK(string, '\n')) { - int k = 0; - while (IS_BREAK_AT(string, k)) { - k += WIDTH_AT(string, k); - } - if (!IS_BLANKZ_AT(string, k)) { - if (!PUT_BREAK(emitter)) return 0; - } - } - if (!WRITE_BREAK(emitter, string)) return 0; - emitter->indention = 1; - breaks = 1; - } - else - { - if (breaks) { - if (!yaml_emitter_write_indent(emitter)) return 0; - leading_spaces = IS_BLANK(string); - } - if (!breaks && IS_SPACE(string) && !IS_SPACE_AT(string, 1) - && emitter->column > emitter->best_width) { - if (!yaml_emitter_write_indent(emitter)) return 0; - MOVE(string); - } - else { - if (!WRITE(emitter, string)) return 0; - } - emitter->indention = 0; - breaks = 0; - } - } - - return 1; -} diff --git a/3rdparty/libyaml/src/loader.c b/3rdparty/libyaml/src/loader.c deleted file mode 100644 index db8501ac..00000000 --- a/3rdparty/libyaml/src/loader.c +++ /dev/null @@ -1,444 +0,0 @@ - -#include "yaml_private.h" - -/* - * API functions. - */ - -YAML_DECLARE(int) -yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); - -/* - * Error handling. - */ - -static int -yaml_parser_set_composer_error(yaml_parser_t *parser, - const char *problem, yaml_mark_t problem_mark); - -static int -yaml_parser_set_composer_error_context(yaml_parser_t *parser, - const char *context, yaml_mark_t context_mark, - const char *problem, yaml_mark_t problem_mark); - - -/* - * Alias handling. - */ - -static int -yaml_parser_register_anchor(yaml_parser_t *parser, - int index, yaml_char_t *anchor); - -/* - * Clean up functions. - */ - -static void -yaml_parser_delete_aliases(yaml_parser_t *parser); - -/* - * Composer functions. - */ - -static int -yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event); - -static int -yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event); - -static int -yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event); - -static int -yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event); - -static int -yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event); - -static int -yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event); - -/* - * Load the next document of the stream. - */ - -YAML_DECLARE(int) -yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document) -{ - yaml_event_t event; - - assert(parser); /* Non-NULL parser object is expected. */ - assert(document); /* Non-NULL document object is expected. */ - - memset(document, 0, sizeof(yaml_document_t)); - if (!STACK_INIT(parser, document->nodes, yaml_node_t*)) - goto error; - - if (!parser->stream_start_produced) { - if (!yaml_parser_parse(parser, &event)) goto error; - assert(event.type == YAML_STREAM_START_EVENT); - /* STREAM-START is expected. */ - } - - if (parser->stream_end_produced) { - return 1; - } - - if (!yaml_parser_parse(parser, &event)) goto error; - if (event.type == YAML_STREAM_END_EVENT) { - return 1; - } - - if (!STACK_INIT(parser, parser->aliases, yaml_alias_data_t*)) - goto error; - - parser->document = document; - - if (!yaml_parser_load_document(parser, &event)) goto error; - - yaml_parser_delete_aliases(parser); - parser->document = NULL; - - return 1; - -error: - - yaml_parser_delete_aliases(parser); - yaml_document_delete(document); - parser->document = NULL; - - return 0; -} - -/* - * Set composer error. - */ - -static int -yaml_parser_set_composer_error(yaml_parser_t *parser, - const char *problem, yaml_mark_t problem_mark) -{ - parser->error = YAML_COMPOSER_ERROR; - parser->problem = problem; - parser->problem_mark = problem_mark; - - return 0; -} - -/* - * Set composer error with context. - */ - -static int -yaml_parser_set_composer_error_context(yaml_parser_t *parser, - const char *context, yaml_mark_t context_mark, - const char *problem, yaml_mark_t problem_mark) -{ - parser->error = YAML_COMPOSER_ERROR; - parser->context = context; - parser->context_mark = context_mark; - parser->problem = problem; - parser->problem_mark = problem_mark; - - return 0; -} - -/* - * Delete the stack of aliases. - */ - -static void -yaml_parser_delete_aliases(yaml_parser_t *parser) -{ - while (!STACK_EMPTY(parser, parser->aliases)) { - yaml_free(POP(parser, parser->aliases).anchor); - } - STACK_DEL(parser, parser->aliases); -} - -/* - * Compose a document object. - */ - -static int -yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event) -{ - yaml_event_t event; - - assert(first_event->type == YAML_DOCUMENT_START_EVENT); - /* DOCUMENT-START is expected. */ - - parser->document->version_directive - = first_event->data.document_start.version_directive; - parser->document->tag_directives.start - = first_event->data.document_start.tag_directives.start; - parser->document->tag_directives.end - = first_event->data.document_start.tag_directives.end; - parser->document->start_implicit - = first_event->data.document_start.implicit; - parser->document->start_mark = first_event->start_mark; - - if (!yaml_parser_parse(parser, &event)) return 0; - - if (!yaml_parser_load_node(parser, &event)) return 0; - - if (!yaml_parser_parse(parser, &event)) return 0; - assert(event.type == YAML_DOCUMENT_END_EVENT); - /* DOCUMENT-END is expected. */ - - parser->document->end_implicit = event.data.document_end.implicit; - parser->document->end_mark = event.end_mark; - - return 1; -} - -/* - * Compose a node. - */ - -static int -yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event) -{ - switch (first_event->type) { - case YAML_ALIAS_EVENT: - return yaml_parser_load_alias(parser, first_event); - case YAML_SCALAR_EVENT: - return yaml_parser_load_scalar(parser, first_event); - case YAML_SEQUENCE_START_EVENT: - return yaml_parser_load_sequence(parser, first_event); - case YAML_MAPPING_START_EVENT: - return yaml_parser_load_mapping(parser, first_event); - default: - assert(0); /* Could not happen. */ - return 0; - } - - return 0; -} - -/* - * Add an anchor. - */ - -static int -yaml_parser_register_anchor(yaml_parser_t *parser, - int index, yaml_char_t *anchor) -{ - yaml_alias_data_t data; - yaml_alias_data_t *alias_data; - - if (!anchor) return 1; - - data.anchor = anchor; - data.index = index; - data.mark = parser->document->nodes.start[index-1].start_mark; - - for (alias_data = parser->aliases.start; - alias_data != parser->aliases.top; alias_data ++) { - if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { - yaml_free(anchor); - return yaml_parser_set_composer_error_context(parser, - "found duplicate anchor; first occurrence", - alias_data->mark, "second occurrence", data.mark); - } - } - - if (!PUSH(parser, parser->aliases, data)) { - yaml_free(anchor); - return 0; - } - - return 1; -} - -/* - * Compose a node corresponding to an alias. - */ - -static int -yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event) -{ - yaml_char_t *anchor = first_event->data.alias.anchor; - yaml_alias_data_t *alias_data; - - for (alias_data = parser->aliases.start; - alias_data != parser->aliases.top; alias_data ++) { - if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { - yaml_free(anchor); - return alias_data->index; - } - } - - yaml_free(anchor); - return yaml_parser_set_composer_error(parser, "found undefined alias", - first_event->start_mark); -} - -/* - * Compose a scalar node. - */ - -static int -yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event) -{ - yaml_node_t node; - int index; - yaml_char_t *tag = first_event->data.scalar.tag; - - if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; - - if (!tag || strcmp((char *)tag, "!") == 0) { - yaml_free(tag); - tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG); - if (!tag) goto error; - } - - SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value, - first_event->data.scalar.length, first_event->data.scalar.style, - first_event->start_mark, first_event->end_mark); - - if (!PUSH(parser, parser->document->nodes, node)) goto error; - - index = parser->document->nodes.top - parser->document->nodes.start; - - if (!yaml_parser_register_anchor(parser, index, - first_event->data.scalar.anchor)) return 0; - - return index; - -error: - yaml_free(tag); - yaml_free(first_event->data.scalar.anchor); - yaml_free(first_event->data.scalar.value); - return 0; -} - -/* - * Compose a sequence node. - */ - -static int -yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event) -{ - yaml_event_t event; - yaml_node_t node; - struct { - yaml_node_item_t *start; - yaml_node_item_t *end; - yaml_node_item_t *top; - } items = { NULL, NULL, NULL }; - int index, item_index; - yaml_char_t *tag = first_event->data.sequence_start.tag; - - if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; - - if (!tag || strcmp((char *)tag, "!") == 0) { - yaml_free(tag); - tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG); - if (!tag) goto error; - } - - if (!STACK_INIT(parser, items, yaml_node_item_t*)) goto error; - - SEQUENCE_NODE_INIT(node, tag, items.start, items.end, - first_event->data.sequence_start.style, - first_event->start_mark, first_event->end_mark); - - if (!PUSH(parser, parser->document->nodes, node)) goto error; - - index = parser->document->nodes.top - parser->document->nodes.start; - - if (!yaml_parser_register_anchor(parser, index, - first_event->data.sequence_start.anchor)) return 0; - - if (!yaml_parser_parse(parser, &event)) return 0; - - while (event.type != YAML_SEQUENCE_END_EVENT) { - if (!STACK_LIMIT(parser, - parser->document->nodes.start[index-1].data.sequence.items, - INT_MAX-1)) return 0; - item_index = yaml_parser_load_node(parser, &event); - if (!item_index) return 0; - if (!PUSH(parser, - parser->document->nodes.start[index-1].data.sequence.items, - item_index)) return 0; - if (!yaml_parser_parse(parser, &event)) return 0; - } - - parser->document->nodes.start[index-1].end_mark = event.end_mark; - - return index; - -error: - yaml_free(tag); - yaml_free(first_event->data.sequence_start.anchor); - return 0; -} - -/* - * Compose a mapping node. - */ - -static int -yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event) -{ - yaml_event_t event; - yaml_node_t node; - struct { - yaml_node_pair_t *start; - yaml_node_pair_t *end; - yaml_node_pair_t *top; - } pairs = { NULL, NULL, NULL }; - int index; - yaml_node_pair_t pair; - yaml_char_t *tag = first_event->data.mapping_start.tag; - - if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; - - if (!tag || strcmp((char *)tag, "!") == 0) { - yaml_free(tag); - tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG); - if (!tag) goto error; - } - - if (!STACK_INIT(parser, pairs, yaml_node_pair_t*)) goto error; - - MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end, - first_event->data.mapping_start.style, - first_event->start_mark, first_event->end_mark); - - if (!PUSH(parser, parser->document->nodes, node)) goto error; - - index = parser->document->nodes.top - parser->document->nodes.start; - - if (!yaml_parser_register_anchor(parser, index, - first_event->data.mapping_start.anchor)) return 0; - - if (!yaml_parser_parse(parser, &event)) return 0; - - while (event.type != YAML_MAPPING_END_EVENT) { - if (!STACK_LIMIT(parser, - parser->document->nodes.start[index-1].data.mapping.pairs, - INT_MAX-1)) return 0; - pair.key = yaml_parser_load_node(parser, &event); - if (!pair.key) return 0; - if (!yaml_parser_parse(parser, &event)) return 0; - pair.value = yaml_parser_load_node(parser, &event); - if (!pair.value) return 0; - if (!PUSH(parser, - parser->document->nodes.start[index-1].data.mapping.pairs, - pair)) return 0; - if (!yaml_parser_parse(parser, &event)) return 0; - } - - parser->document->nodes.start[index-1].end_mark = event.end_mark; - - return index; - -error: - yaml_free(tag); - yaml_free(first_event->data.mapping_start.anchor); - return 0; -} - diff --git a/3rdparty/libyaml/src/parser.c b/3rdparty/libyaml/src/parser.c deleted file mode 100644 index 1198c737..00000000 --- a/3rdparty/libyaml/src/parser.c +++ /dev/null @@ -1,1372 +0,0 @@ - -/* - * The parser implements the following grammar: - * - * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END - * implicit_document ::= block_node DOCUMENT-END* - * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* - * block_node_or_indentless_sequence ::= - * ALIAS - * | properties (block_content | indentless_block_sequence)? - * | block_content - * | indentless_block_sequence - * block_node ::= ALIAS - * | properties block_content? - * | block_content - * flow_node ::= ALIAS - * | properties flow_content? - * | flow_content - * properties ::= TAG ANCHOR? | ANCHOR TAG? - * block_content ::= block_collection | flow_collection | SCALAR - * flow_content ::= flow_collection | SCALAR - * block_collection ::= block_sequence | block_mapping - * flow_collection ::= flow_sequence | flow_mapping - * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END - * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ - * block_mapping ::= BLOCK-MAPPING_START - * ((KEY block_node_or_indentless_sequence?)? - * (VALUE block_node_or_indentless_sequence?)?)* - * BLOCK-END - * flow_sequence ::= FLOW-SEQUENCE-START - * (flow_sequence_entry FLOW-ENTRY)* - * flow_sequence_entry? - * FLOW-SEQUENCE-END - * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * flow_mapping ::= FLOW-MAPPING-START - * (flow_mapping_entry FLOW-ENTRY)* - * flow_mapping_entry? - * FLOW-MAPPING-END - * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - */ - -#include "yaml_private.h" - -/* - * Peek the next token in the token queue. - */ - -#define PEEK_TOKEN(parser) \ - ((parser->token_available || yaml_parser_fetch_more_tokens(parser)) ? \ - parser->tokens.head : NULL) - -/* - * Remove the next token from the queue (must be called after PEEK_TOKEN). - */ - -#define SKIP_TOKEN(parser) \ - (parser->token_available = 0, \ - parser->tokens_parsed ++, \ - parser->stream_end_produced = \ - (parser->tokens.head->type == YAML_STREAM_END_TOKEN), \ - parser->tokens.head ++) - -/* - * Public API declarations. - */ - -YAML_DECLARE(int) -yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); - -/* - * Error handling. - */ - -static int -yaml_parser_set_parser_error(yaml_parser_t *parser, - const char *problem, yaml_mark_t problem_mark); - -static int -yaml_parser_set_parser_error_context(yaml_parser_t *parser, - const char *context, yaml_mark_t context_mark, - const char *problem, yaml_mark_t problem_mark); - -/* - * State functions. - */ - -static int -yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event); - -static int -yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event); - -static int -yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, - int implicit); - -static int -yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event); - -static int -yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event); - -static int -yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, - int block, int indentless_sequence); - -static int -yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event, int first); - -static int -yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event); - -static int -yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, - yaml_event_t *event, int first); - -static int -yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, - yaml_event_t *event); - -static int -yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event, int first); - -static int -yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, - yaml_event_t *event); - -static int -yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, - yaml_event_t *event); - -static int -yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, - yaml_event_t *event); - -static int -yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, - yaml_event_t *event, int first); - -static int -yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, - yaml_event_t *event, int empty); - -/* - * Utility functions. - */ - -static int -yaml_parser_process_empty_scalar(yaml_parser_t *parser, - yaml_event_t *event, yaml_mark_t mark); - -static int -yaml_parser_process_directives(yaml_parser_t *parser, - yaml_version_directive_t **version_directive_ref, - yaml_tag_directive_t **tag_directives_start_ref, - yaml_tag_directive_t **tag_directives_end_ref); - -static int -yaml_parser_append_tag_directive(yaml_parser_t *parser, - yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark); - -/* - * Get the next event. - */ - -YAML_DECLARE(int) -yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event) -{ - assert(parser); /* Non-NULL parser object is expected. */ - assert(event); /* Non-NULL event object is expected. */ - - /* Erase the event object. */ - - memset(event, 0, sizeof(yaml_event_t)); - - /* No events after the end of the stream or error. */ - - if (parser->stream_end_produced || parser->error || - parser->state == YAML_PARSE_END_STATE) { - return 1; - } - - /* Generate the next event. */ - - return yaml_parser_state_machine(parser, event); -} - -/* - * Set parser error. - */ - -static int -yaml_parser_set_parser_error(yaml_parser_t *parser, - const char *problem, yaml_mark_t problem_mark) -{ - parser->error = YAML_PARSER_ERROR; - parser->problem = problem; - parser->problem_mark = problem_mark; - - return 0; -} - -static int -yaml_parser_set_parser_error_context(yaml_parser_t *parser, - const char *context, yaml_mark_t context_mark, - const char *problem, yaml_mark_t problem_mark) -{ - parser->error = YAML_PARSER_ERROR; - parser->context = context; - parser->context_mark = context_mark; - parser->problem = problem; - parser->problem_mark = problem_mark; - - return 0; -} - - -/* - * State dispatcher. - */ - -static int -yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event) -{ - switch (parser->state) - { - case YAML_PARSE_STREAM_START_STATE: - return yaml_parser_parse_stream_start(parser, event); - - case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, 1); - - case YAML_PARSE_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, 0); - - case YAML_PARSE_DOCUMENT_CONTENT_STATE: - return yaml_parser_parse_document_content(parser, event); - - case YAML_PARSE_DOCUMENT_END_STATE: - return yaml_parser_parse_document_end(parser, event); - - case YAML_PARSE_BLOCK_NODE_STATE: - return yaml_parser_parse_node(parser, event, 1, 0); - - case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return yaml_parser_parse_node(parser, event, 1, 1); - - case YAML_PARSE_FLOW_NODE_STATE: - return yaml_parser_parse_node(parser, event, 0, 0); - - case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, 1); - - case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, 0); - - case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_indentless_sequence_entry(parser, event); - - case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, 1); - - case YAML_PARSE_BLOCK_MAPPING_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, 0); - - case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE: - return yaml_parser_parse_block_mapping_value(parser, event); - - case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, 1); - - case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, 0); - - case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event); - - case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event); - - case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event); - - case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, 1); - - case YAML_PARSE_FLOW_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, 0); - - case YAML_PARSE_FLOW_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, 0); - - case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, 1); - - default: - assert(1); /* Invalid state. */ - } - - return 0; -} - -/* - * Parse the production: - * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END - * ************ - */ - -static int -yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type != YAML_STREAM_START_TOKEN) { - return yaml_parser_set_parser_error(parser, - "did not find expected ", token->start_mark); - } - - parser->state = YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE; - STREAM_START_EVENT_INIT(*event, token->data.stream_start.encoding, - token->start_mark, token->start_mark); - SKIP_TOKEN(parser); - - return 1; -} - -/* - * Parse the productions: - * implicit_document ::= block_node DOCUMENT-END* - * * - * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* - * ************************* - */ - -static int -yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, - int implicit) -{ - yaml_token_t *token; - yaml_version_directive_t *version_directive = NULL; - struct { - yaml_tag_directive_t *start; - yaml_tag_directive_t *end; - } tag_directives = { NULL, NULL }; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - /* Parse extra document end indicators. */ - - if (!implicit) - { - while (token->type == YAML_DOCUMENT_END_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - } - } - - /* Parse an implicit document. */ - - if (implicit && token->type != YAML_VERSION_DIRECTIVE_TOKEN && - token->type != YAML_TAG_DIRECTIVE_TOKEN && - token->type != YAML_DOCUMENT_START_TOKEN && - token->type != YAML_STREAM_END_TOKEN) - { - if (!yaml_parser_process_directives(parser, NULL, NULL, NULL)) - return 0; - if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) - return 0; - parser->state = YAML_PARSE_BLOCK_NODE_STATE; - DOCUMENT_START_EVENT_INIT(*event, NULL, NULL, NULL, 1, - token->start_mark, token->start_mark); - return 1; - } - - /* Parse an explicit document. */ - - else if (token->type != YAML_STREAM_END_TOKEN) - { - yaml_mark_t start_mark, end_mark; - start_mark = token->start_mark; - if (!yaml_parser_process_directives(parser, &version_directive, - &tag_directives.start, &tag_directives.end)) - return 0; - token = PEEK_TOKEN(parser); - if (!token) goto error; - if (token->type != YAML_DOCUMENT_START_TOKEN) { - yaml_parser_set_parser_error(parser, - "did not find expected ", token->start_mark); - goto error; - } - if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) - goto error; - parser->state = YAML_PARSE_DOCUMENT_CONTENT_STATE; - end_mark = token->end_mark; - DOCUMENT_START_EVENT_INIT(*event, version_directive, - tag_directives.start, tag_directives.end, 0, - start_mark, end_mark); - SKIP_TOKEN(parser); - version_directive = NULL; - tag_directives.start = tag_directives.end = NULL; - return 1; - } - - /* Parse the stream end. */ - - else - { - parser->state = YAML_PARSE_END_STATE; - STREAM_END_EVENT_INIT(*event, token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; - } - -error: - yaml_free(version_directive); - while (tag_directives.start != tag_directives.end) { - yaml_free(tag_directives.end[-1].handle); - yaml_free(tag_directives.end[-1].prefix); - tag_directives.end --; - } - yaml_free(tag_directives.start); - return 0; -} - -/* - * Parse the productions: - * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* - * *********** - */ - -static int -yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_VERSION_DIRECTIVE_TOKEN || - token->type == YAML_TAG_DIRECTIVE_TOKEN || - token->type == YAML_DOCUMENT_START_TOKEN || - token->type == YAML_DOCUMENT_END_TOKEN || - token->type == YAML_STREAM_END_TOKEN) { - parser->state = POP(parser, parser->states); - return yaml_parser_process_empty_scalar(parser, event, - token->start_mark); - } - else { - return yaml_parser_parse_node(parser, event, 1, 0); - } -} - -/* - * Parse the productions: - * implicit_document ::= block_node DOCUMENT-END* - * ************* - * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* - * ************* - */ - -static int -yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event) -{ - yaml_token_t *token; - yaml_mark_t start_mark, end_mark; - int implicit = 1; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - start_mark = end_mark = token->start_mark; - - if (token->type == YAML_DOCUMENT_END_TOKEN) { - end_mark = token->end_mark; - SKIP_TOKEN(parser); - implicit = 0; - } - - while (!STACK_EMPTY(parser, parser->tag_directives)) { - yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - - parser->state = YAML_PARSE_DOCUMENT_START_STATE; - DOCUMENT_END_EVENT_INIT(*event, implicit, start_mark, end_mark); - - return 1; -} - -/* - * Parse the productions: - * block_node_or_indentless_sequence ::= - * ALIAS - * ***** - * | properties (block_content | indentless_block_sequence)? - * ********** * - * | block_content | indentless_block_sequence - * * - * block_node ::= ALIAS - * ***** - * | properties block_content? - * ********** * - * | block_content - * * - * flow_node ::= ALIAS - * ***** - * | properties flow_content? - * ********** * - * | flow_content - * * - * properties ::= TAG ANCHOR? | ANCHOR TAG? - * ************************* - * block_content ::= block_collection | flow_collection | SCALAR - * ****** - * flow_content ::= flow_collection | SCALAR - * ****** - */ - -static int -yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, - int block, int indentless_sequence) -{ - yaml_token_t *token; - yaml_char_t *anchor = NULL; - yaml_char_t *tag_handle = NULL; - yaml_char_t *tag_suffix = NULL; - yaml_char_t *tag = NULL; - yaml_mark_t start_mark, end_mark, tag_mark; - int implicit; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_ALIAS_TOKEN) - { - parser->state = POP(parser, parser->states); - ALIAS_EVENT_INIT(*event, token->data.alias.value, - token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; - } - - else - { - start_mark = end_mark = token->start_mark; - - if (token->type == YAML_ANCHOR_TOKEN) - { - anchor = token->data.anchor.value; - start_mark = token->start_mark; - end_mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) goto error; - if (token->type == YAML_TAG_TOKEN) - { - tag_handle = token->data.tag.handle; - tag_suffix = token->data.tag.suffix; - tag_mark = token->start_mark; - end_mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) goto error; - } - } - else if (token->type == YAML_TAG_TOKEN) - { - tag_handle = token->data.tag.handle; - tag_suffix = token->data.tag.suffix; - start_mark = tag_mark = token->start_mark; - end_mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) goto error; - if (token->type == YAML_ANCHOR_TOKEN) - { - anchor = token->data.anchor.value; - end_mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) goto error; - } - } - - if (tag_handle) { - if (!*tag_handle) { - tag = tag_suffix; - yaml_free(tag_handle); - tag_handle = tag_suffix = NULL; - } - else { - yaml_tag_directive_t *tag_directive; - for (tag_directive = parser->tag_directives.start; - tag_directive != parser->tag_directives.top; - tag_directive ++) { - if (strcmp((char *)tag_directive->handle, (char *)tag_handle) == 0) { - size_t prefix_len = strlen((char *)tag_directive->prefix); - size_t suffix_len = strlen((char *)tag_suffix); - tag = YAML_MALLOC(prefix_len+suffix_len+1); - if (!tag) { - parser->error = YAML_MEMORY_ERROR; - goto error; - } - memcpy(tag, tag_directive->prefix, prefix_len); - memcpy(tag+prefix_len, tag_suffix, suffix_len); - tag[prefix_len+suffix_len] = '\0'; - yaml_free(tag_handle); - yaml_free(tag_suffix); - tag_handle = tag_suffix = NULL; - break; - } - } - if (!tag) { - yaml_parser_set_parser_error_context(parser, - "while parsing a node", start_mark, - "found undefined tag handle", tag_mark); - goto error; - } - } - } - - implicit = (!tag || !*tag); - if (indentless_sequence && token->type == YAML_BLOCK_ENTRY_TOKEN) { - end_mark = token->end_mark; - parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; - SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, - YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); - return 1; - } - else { - if (token->type == YAML_SCALAR_TOKEN) { - int plain_implicit = 0; - int quoted_implicit = 0; - end_mark = token->end_mark; - if ((token->data.scalar.style == YAML_PLAIN_SCALAR_STYLE && !tag) - || (tag && strcmp((char *)tag, "!") == 0)) { - plain_implicit = 1; - } - else if (!tag) { - quoted_implicit = 1; - } - parser->state = POP(parser, parser->states); - SCALAR_EVENT_INIT(*event, anchor, tag, - token->data.scalar.value, token->data.scalar.length, - plain_implicit, quoted_implicit, - token->data.scalar.style, start_mark, end_mark); - SKIP_TOKEN(parser); - return 1; - } - else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) { - end_mark = token->end_mark; - parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE; - SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, - YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark); - return 1; - } - else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) { - end_mark = token->end_mark; - parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE; - MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, - YAML_FLOW_MAPPING_STYLE, start_mark, end_mark); - return 1; - } - else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) { - end_mark = token->end_mark; - parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE; - SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, - YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); - return 1; - } - else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) { - end_mark = token->end_mark; - parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE; - MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, - YAML_BLOCK_MAPPING_STYLE, start_mark, end_mark); - return 1; - } - else if (anchor || tag) { - yaml_char_t *value = YAML_MALLOC(1); - if (!value) { - parser->error = YAML_MEMORY_ERROR; - goto error; - } - value[0] = '\0'; - parser->state = POP(parser, parser->states); - SCALAR_EVENT_INIT(*event, anchor, tag, value, 0, - implicit, 0, YAML_PLAIN_SCALAR_STYLE, - start_mark, end_mark); - return 1; - } - else { - yaml_parser_set_parser_error_context(parser, - (block ? "while parsing a block node" - : "while parsing a flow node"), start_mark, - "did not find expected node content", token->start_mark); - goto error; - } - } - } - -error: - yaml_free(anchor); - yaml_free(tag_handle); - yaml_free(tag_suffix); - yaml_free(tag); - - return 0; -} - -/* - * Parse the productions: - * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END - * ******************** *********** * ********* - */ - -static int -yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event, int first) -{ - yaml_token_t *token; - - if (first) { - token = PEEK_TOKEN(parser); - if (!PUSH(parser, parser->marks, token->start_mark)) - return 0; - SKIP_TOKEN(parser); - } - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_BLOCK_ENTRY_TOKEN) - { - yaml_mark_t mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_BLOCK_ENTRY_TOKEN && - token->type != YAML_BLOCK_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 1, 0); - } - else { - parser->state = YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE; - return yaml_parser_process_empty_scalar(parser, event, mark); - } - } - - else if (token->type == YAML_BLOCK_END_TOKEN) - { - parser->state = POP(parser, parser->states); - (void)POP(parser, parser->marks); - SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; - } - - else - { - return yaml_parser_set_parser_error_context(parser, - "while parsing a block collection", POP(parser, parser->marks), - "did not find expected '-' indicator", token->start_mark); - } -} - -/* - * Parse the productions: - * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ - * *********** * - */ - -static int -yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_BLOCK_ENTRY_TOKEN) - { - yaml_mark_t mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_BLOCK_ENTRY_TOKEN && - token->type != YAML_KEY_TOKEN && - token->type != YAML_VALUE_TOKEN && - token->type != YAML_BLOCK_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 1, 0); - } - else { - parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; - return yaml_parser_process_empty_scalar(parser, event, mark); - } - } - - else - { - parser->state = POP(parser, parser->states); - SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->start_mark); - return 1; - } -} - -/* - * Parse the productions: - * block_mapping ::= BLOCK-MAPPING_START - * ******************* - * ((KEY block_node_or_indentless_sequence?)? - * *** * - * (VALUE block_node_or_indentless_sequence?)?)* - * - * BLOCK-END - * ********* - */ - -static int -yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, - yaml_event_t *event, int first) -{ - yaml_token_t *token; - - if (first) { - token = PEEK_TOKEN(parser); - if (!PUSH(parser, parser->marks, token->start_mark)) - return 0; - SKIP_TOKEN(parser); - } - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_KEY_TOKEN) - { - yaml_mark_t mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_KEY_TOKEN && - token->type != YAML_VALUE_TOKEN && - token->type != YAML_BLOCK_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_BLOCK_MAPPING_VALUE_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 1, 1); - } - else { - parser->state = YAML_PARSE_BLOCK_MAPPING_VALUE_STATE; - return yaml_parser_process_empty_scalar(parser, event, mark); - } - } - - else if (token->type == YAML_BLOCK_END_TOKEN) - { - parser->state = POP(parser, parser->states); - (void)POP(parser, parser->marks); - MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; - } - - else - { - return yaml_parser_set_parser_error_context(parser, - "while parsing a block mapping", POP(parser, parser->marks), - "did not find expected key", token->start_mark); - } -} - -/* - * Parse the productions: - * block_mapping ::= BLOCK-MAPPING_START - * - * ((KEY block_node_or_indentless_sequence?)? - * - * (VALUE block_node_or_indentless_sequence?)?)* - * ***** * - * BLOCK-END - * - */ - -static int -yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, - yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_VALUE_TOKEN) - { - yaml_mark_t mark = token->end_mark; - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_KEY_TOKEN && - token->type != YAML_VALUE_TOKEN && - token->type != YAML_BLOCK_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_BLOCK_MAPPING_KEY_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 1, 1); - } - else { - parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; - return yaml_parser_process_empty_scalar(parser, event, mark); - } - } - - else - { - parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; - return yaml_parser_process_empty_scalar(parser, event, token->start_mark); - } -} - -/* - * Parse the productions: - * flow_sequence ::= FLOW-SEQUENCE-START - * ******************* - * (flow_sequence_entry FLOW-ENTRY)* - * * ********** - * flow_sequence_entry? - * * - * FLOW-SEQUENCE-END - * ***************** - * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * * - */ - -static int -yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, - yaml_event_t *event, int first) -{ - yaml_token_t *token; - - if (first) { - token = PEEK_TOKEN(parser); - if (!PUSH(parser, parser->marks, token->start_mark)) - return 0; - SKIP_TOKEN(parser); - } - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) - { - if (!first) { - if (token->type == YAML_FLOW_ENTRY_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - } - else { - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow sequence", POP(parser, parser->marks), - "did not find expected ',' or ']'", token->start_mark); - } - } - - if (token->type == YAML_KEY_TOKEN) { - parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE; - MAPPING_START_EVENT_INIT(*event, NULL, NULL, - 1, YAML_FLOW_MAPPING_STYLE, - token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; - } - - else if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - } - - parser->state = POP(parser, parser->states); - (void)POP(parser, parser->marks); - SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; -} - -/* - * Parse the productions: - * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * *** * - */ - -static int -yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, - yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type != YAML_VALUE_TOKEN && token->type != YAML_FLOW_ENTRY_TOKEN - && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - else { - yaml_mark_t mark = token->end_mark; - SKIP_TOKEN(parser); - parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE; - return yaml_parser_process_empty_scalar(parser, event, mark); - } -} - -/* - * Parse the productions: - * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * ***** * - */ - -static int -yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, - yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type == YAML_VALUE_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_FLOW_ENTRY_TOKEN - && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - } - parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE; - return yaml_parser_process_empty_scalar(parser, event, token->start_mark); -} - -/* - * Parse the productions: - * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * * - */ - -static int -yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, - yaml_event_t *event) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE; - - MAPPING_END_EVENT_INIT(*event, token->start_mark, token->start_mark); - return 1; -} - -/* - * Parse the productions: - * flow_mapping ::= FLOW-MAPPING-START - * ****************** - * (flow_mapping_entry FLOW-ENTRY)* - * * ********** - * flow_mapping_entry? - * ****************** - * FLOW-MAPPING-END - * **************** - * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * * *** * - */ - -static int -yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, - yaml_event_t *event, int first) -{ - yaml_token_t *token; - - if (first) { - token = PEEK_TOKEN(parser); - if (!PUSH(parser, parser->marks, token->start_mark)) - return 0; - SKIP_TOKEN(parser); - } - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (token->type != YAML_FLOW_MAPPING_END_TOKEN) - { - if (!first) { - if (token->type == YAML_FLOW_ENTRY_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - } - else { - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow mapping", POP(parser, parser->marks), - "did not find expected ',' or '}'", token->start_mark); - } - } - - if (token->type == YAML_KEY_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_VALUE_TOKEN - && token->type != YAML_FLOW_ENTRY_TOKEN - && token->type != YAML_FLOW_MAPPING_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_MAPPING_VALUE_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - else { - parser->state = YAML_PARSE_FLOW_MAPPING_VALUE_STATE; - return yaml_parser_process_empty_scalar(parser, event, - token->start_mark); - } - } - else if (token->type != YAML_FLOW_MAPPING_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - } - - parser->state = POP(parser, parser->states); - (void)POP(parser, parser->marks); - MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); - SKIP_TOKEN(parser); - return 1; -} - -/* - * Parse the productions: - * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - * * ***** * - */ - -static int -yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, - yaml_event_t *event, int empty) -{ - yaml_token_t *token; - - token = PEEK_TOKEN(parser); - if (!token) return 0; - - if (empty) { - parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; - return yaml_parser_process_empty_scalar(parser, event, - token->start_mark); - } - - if (token->type == YAML_VALUE_TOKEN) { - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) return 0; - if (token->type != YAML_FLOW_ENTRY_TOKEN - && token->type != YAML_FLOW_MAPPING_END_TOKEN) { - if (!PUSH(parser, parser->states, - YAML_PARSE_FLOW_MAPPING_KEY_STATE)) - return 0; - return yaml_parser_parse_node(parser, event, 0, 0); - } - } - - parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; - return yaml_parser_process_empty_scalar(parser, event, token->start_mark); -} - -/* - * Generate an empty scalar event. - */ - -static int -yaml_parser_process_empty_scalar(yaml_parser_t *parser, yaml_event_t *event, - yaml_mark_t mark) -{ - yaml_char_t *value; - - value = YAML_MALLOC(1); - if (!value) { - parser->error = YAML_MEMORY_ERROR; - return 0; - } - value[0] = '\0'; - - SCALAR_EVENT_INIT(*event, NULL, NULL, value, 0, - 1, 0, YAML_PLAIN_SCALAR_STYLE, mark, mark); - - return 1; -} - -/* - * Parse directives. - */ - -static int -yaml_parser_process_directives(yaml_parser_t *parser, - yaml_version_directive_t **version_directive_ref, - yaml_tag_directive_t **tag_directives_start_ref, - yaml_tag_directive_t **tag_directives_end_ref) -{ - yaml_tag_directive_t default_tag_directives[] = { - {(yaml_char_t *)"!", (yaml_char_t *)"!"}, - {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, - {NULL, NULL} - }; - yaml_tag_directive_t *default_tag_directive; - yaml_version_directive_t *version_directive = NULL; - struct { - yaml_tag_directive_t *start; - yaml_tag_directive_t *end; - yaml_tag_directive_t *top; - } tag_directives = { NULL, NULL, NULL }; - yaml_token_t *token; - - if (!STACK_INIT(parser, tag_directives, yaml_tag_directive_t*)) - goto error; - - token = PEEK_TOKEN(parser); - if (!token) goto error; - - while (token->type == YAML_VERSION_DIRECTIVE_TOKEN || - token->type == YAML_TAG_DIRECTIVE_TOKEN) - { - if (token->type == YAML_VERSION_DIRECTIVE_TOKEN) { - if (version_directive) { - yaml_parser_set_parser_error(parser, - "found duplicate %YAML directive", token->start_mark); - goto error; - } - if (token->data.version_directive.major != 1 - || token->data.version_directive.minor != 1) { - yaml_parser_set_parser_error(parser, - "found incompatible YAML document", token->start_mark); - goto error; - } - version_directive = YAML_MALLOC_STATIC(yaml_version_directive_t); - if (!version_directive) { - parser->error = YAML_MEMORY_ERROR; - goto error; - } - version_directive->major = token->data.version_directive.major; - version_directive->minor = token->data.version_directive.minor; - } - - else if (token->type == YAML_TAG_DIRECTIVE_TOKEN) { - yaml_tag_directive_t value; - value.handle = token->data.tag_directive.handle; - value.prefix = token->data.tag_directive.prefix; - - if (!yaml_parser_append_tag_directive(parser, value, 0, - token->start_mark)) - goto error; - if (!PUSH(parser, tag_directives, value)) - goto error; - } - - SKIP_TOKEN(parser); - token = PEEK_TOKEN(parser); - if (!token) goto error; - } - - for (default_tag_directive = default_tag_directives; - default_tag_directive->handle; default_tag_directive++) { - if (!yaml_parser_append_tag_directive(parser, *default_tag_directive, 1, - token->start_mark)) - goto error; - } - - if (version_directive_ref) { - *version_directive_ref = version_directive; - } - if (tag_directives_start_ref) { - if (STACK_EMPTY(parser, tag_directives)) { - *tag_directives_start_ref = *tag_directives_end_ref = NULL; - STACK_DEL(parser, tag_directives); - } - else { - *tag_directives_start_ref = tag_directives.start; - *tag_directives_end_ref = tag_directives.top; - } - } - else { - STACK_DEL(parser, tag_directives); - } - - if (!version_directive_ref) - yaml_free(version_directive); - return 1; - -error: - yaml_free(version_directive); - while (!STACK_EMPTY(parser, tag_directives)) { - yaml_tag_directive_t tag_directive = POP(parser, tag_directives); - yaml_free(tag_directive.handle); - yaml_free(tag_directive.prefix); - } - STACK_DEL(parser, tag_directives); - return 0; -} - -/* - * Append a tag directive to the directives stack. - */ - -static int -yaml_parser_append_tag_directive(yaml_parser_t *parser, - yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark) -{ - yaml_tag_directive_t *tag_directive; - yaml_tag_directive_t copy = { NULL, NULL }; - - for (tag_directive = parser->tag_directives.start; - tag_directive != parser->tag_directives.top; tag_directive ++) { - if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { - if (allow_duplicates) - return 1; - return yaml_parser_set_parser_error(parser, - "found duplicate %TAG directive", mark); - } - } - - copy.handle = yaml_strdup(value.handle); - copy.prefix = yaml_strdup(value.prefix); - if (!copy.handle || !copy.prefix) { - parser->error = YAML_MEMORY_ERROR; - goto error; - } - - if (!PUSH(parser, parser->tag_directives, copy)) - goto error; - - return 1; - -error: - yaml_free(copy.handle); - yaml_free(copy.prefix); - return 0; -} - diff --git a/3rdparty/libyaml/src/reader.c b/3rdparty/libyaml/src/reader.c deleted file mode 100644 index f3ac54c2..00000000 --- a/3rdparty/libyaml/src/reader.c +++ /dev/null @@ -1,469 +0,0 @@ - -#include "yaml_private.h" - -/* - * Declarations. - */ - -static int -yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, - size_t offset, int value); - -static int -yaml_parser_update_raw_buffer(yaml_parser_t *parser); - -static int -yaml_parser_determine_encoding(yaml_parser_t *parser); - -YAML_DECLARE(int) -yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); - -/* - * Set the reader error and return 0. - */ - -static int -yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, - size_t offset, int value) -{ - parser->error = YAML_READER_ERROR; - parser->problem = problem; - parser->problem_offset = offset; - parser->problem_value = value; - - return 0; -} - -/* - * Byte order marks. - */ - -#define BOM_UTF8 "\xef\xbb\xbf" -#define BOM_UTF16LE "\xff\xfe" -#define BOM_UTF16BE "\xfe\xff" - -/* - * Determine the input stream encoding by checking the BOM symbol. If no BOM is - * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. - */ - -static int -yaml_parser_determine_encoding(yaml_parser_t *parser) -{ - /* Ensure that we had enough bytes in the raw buffer. */ - - while (!parser->eof - && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { - if (!yaml_parser_update_raw_buffer(parser)) { - return 0; - } - } - - /* Determine the encoding. */ - - if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 - && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { - parser->encoding = YAML_UTF16LE_ENCODING; - parser->raw_buffer.pointer += 2; - parser->offset += 2; - } - else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 - && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { - parser->encoding = YAML_UTF16BE_ENCODING; - parser->raw_buffer.pointer += 2; - parser->offset += 2; - } - else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 - && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { - parser->encoding = YAML_UTF8_ENCODING; - parser->raw_buffer.pointer += 3; - parser->offset += 3; - } - else { - parser->encoding = YAML_UTF8_ENCODING; - } - - return 1; -} - -/* - * Update the raw buffer. - */ - -static int -yaml_parser_update_raw_buffer(yaml_parser_t *parser) -{ - size_t size_read = 0; - - /* Return if the raw buffer is full. */ - - if (parser->raw_buffer.start == parser->raw_buffer.pointer - && parser->raw_buffer.last == parser->raw_buffer.end) - return 1; - - /* Return on EOF. */ - - if (parser->eof) return 1; - - /* Move the remaining bytes in the raw buffer to the beginning. */ - - if (parser->raw_buffer.start < parser->raw_buffer.pointer - && parser->raw_buffer.pointer < parser->raw_buffer.last) { - memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, - parser->raw_buffer.last - parser->raw_buffer.pointer); - } - parser->raw_buffer.last -= - parser->raw_buffer.pointer - parser->raw_buffer.start; - parser->raw_buffer.pointer = parser->raw_buffer.start; - - /* Call the read handler to fill the buffer. */ - - if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, - parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { - return yaml_parser_set_reader_error(parser, "input error", - parser->offset, -1); - } - parser->raw_buffer.last += size_read; - if (!size_read) { - parser->eof = 1; - } - - return 1; -} - -/* - * Ensure that the buffer contains at least `length` characters. - * Return 1 on success, 0 on failure. - * - * The length is supposed to be significantly less that the buffer size. - */ - -YAML_DECLARE(int) -yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) -{ - int first = 1; - - assert(parser->read_handler); /* Read handler must be set. */ - - /* If the EOF flag is set and the raw buffer is empty, do nothing. */ - - if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) - return 1; - - /* Return if the buffer contains enough characters. */ - - if (parser->unread >= length) - return 1; - - /* Determine the input encoding if it is not known yet. */ - - if (!parser->encoding) { - if (!yaml_parser_determine_encoding(parser)) - return 0; - } - - /* Move the unread characters to the beginning of the buffer. */ - - if (parser->buffer.start < parser->buffer.pointer - && parser->buffer.pointer < parser->buffer.last) { - size_t size = parser->buffer.last - parser->buffer.pointer; - memmove(parser->buffer.start, parser->buffer.pointer, size); - parser->buffer.pointer = parser->buffer.start; - parser->buffer.last = parser->buffer.start + size; - } - else if (parser->buffer.pointer == parser->buffer.last) { - parser->buffer.pointer = parser->buffer.start; - parser->buffer.last = parser->buffer.start; - } - - /* Fill the buffer until it has enough characters. */ - - while (parser->unread < length) - { - /* Fill the raw buffer if necessary. */ - - if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { - if (!yaml_parser_update_raw_buffer(parser)) return 0; - } - first = 0; - - /* Decode the raw buffer. */ - - while (parser->raw_buffer.pointer != parser->raw_buffer.last) - { - unsigned int value = 0, value2 = 0; - int incomplete = 0; - unsigned char octet; - unsigned int width = 0; - int low, high; - size_t k; - size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; - - /* Decode the next character. */ - - switch (parser->encoding) - { - case YAML_UTF8_ENCODING: - - /* - * Decode a UTF-8 character. Check RFC 3629 - * (http://www.ietf.org/rfc/rfc3629.txt) for more details. - * - * The following table (taken from the RFC) is used for - * decoding. - * - * Char. number range | UTF-8 octet sequence - * (hexadecimal) | (binary) - * --------------------+------------------------------------ - * 0000 0000-0000 007F | 0xxxxxxx - * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * - * Additionally, the characters in the range 0xD800-0xDFFF - * are prohibited as they are reserved for use with UTF-16 - * surrogate pairs. - */ - - /* Determine the length of the UTF-8 sequence. */ - - octet = parser->raw_buffer.pointer[0]; - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - - /* Check if the leading octet is valid. */ - - if (!width) - return yaml_parser_set_reader_error(parser, - "invalid leading UTF-8 octet", - parser->offset, octet); - - /* Check if the raw buffer contains an incomplete character. */ - - if (width > raw_unread) { - if (parser->eof) { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-8 octet sequence", - parser->offset, -1); - } - incomplete = 1; - break; - } - - /* Decode the leading octet. */ - - value = (octet & 0x80) == 0x00 ? octet & 0x7F : - (octet & 0xE0) == 0xC0 ? octet & 0x1F : - (octet & 0xF0) == 0xE0 ? octet & 0x0F : - (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; - - /* Check and decode the trailing octets. */ - - for (k = 1; k < width; k ++) - { - octet = parser->raw_buffer.pointer[k]; - - /* Check if the octet is valid. */ - - if ((octet & 0xC0) != 0x80) - return yaml_parser_set_reader_error(parser, - "invalid trailing UTF-8 octet", - parser->offset+k, octet); - - /* Decode the octet. */ - - value = (value << 6) + (octet & 0x3F); - } - - /* Check the length of the sequence against the value. */ - - if (!((width == 1) || - (width == 2 && value >= 0x80) || - (width == 3 && value >= 0x800) || - (width == 4 && value >= 0x10000))) - return yaml_parser_set_reader_error(parser, - "invalid length of a UTF-8 sequence", - parser->offset, -1); - - /* Check the range of the value. */ - - if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) - return yaml_parser_set_reader_error(parser, - "invalid Unicode character", - parser->offset, value); - - break; - - case YAML_UTF16LE_ENCODING: - case YAML_UTF16BE_ENCODING: - - low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); - high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); - - /* - * The UTF-16 encoding is not as simple as one might - * naively think. Check RFC 2781 - * (http://www.ietf.org/rfc/rfc2781.txt). - * - * Normally, two subsequent bytes describe a Unicode - * character. However a special technique (called a - * surrogate pair) is used for specifying character - * values larger than 0xFFFF. - * - * A surrogate pair consists of two pseudo-characters: - * high surrogate area (0xD800-0xDBFF) - * low surrogate area (0xDC00-0xDFFF) - * - * The following formulas are used for decoding - * and encoding characters using surrogate pairs: - * - * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) - * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) - * W1 = 110110yyyyyyyyyy - * W2 = 110111xxxxxxxxxx - * - * where U is the character value, W1 is the high surrogate - * area, W2 is the low surrogate area. - */ - - /* Check for incomplete UTF-16 character. */ - - if (raw_unread < 2) { - if (parser->eof) { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 character", - parser->offset, -1); - } - incomplete = 1; - break; - } - - /* Get the character. */ - - value = parser->raw_buffer.pointer[low] - + (parser->raw_buffer.pointer[high] << 8); - - /* Check for unexpected low surrogate area. */ - - if ((value & 0xFC00) == 0xDC00) - return yaml_parser_set_reader_error(parser, - "unexpected low surrogate area", - parser->offset, value); - - /* Check for a high surrogate area. */ - - if ((value & 0xFC00) == 0xD800) { - - width = 4; - - /* Check for incomplete surrogate pair. */ - - if (raw_unread < 4) { - if (parser->eof) { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 surrogate pair", - parser->offset, -1); - } - incomplete = 1; - break; - } - - /* Get the next character. */ - - value2 = parser->raw_buffer.pointer[low+2] - + (parser->raw_buffer.pointer[high+2] << 8); - - /* Check for a low surrogate area. */ - - if ((value2 & 0xFC00) != 0xDC00) - return yaml_parser_set_reader_error(parser, - "expected low surrogate area", - parser->offset+2, value2); - - /* Generate the value of the surrogate pair. */ - - value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); - } - - else { - width = 2; - } - - break; - - default: - assert(1); /* Impossible. */ - } - - /* Check if the raw buffer contains enough bytes to form a character. */ - - if (incomplete) break; - - /* - * Check if the character is in the allowed range: - * #x9 | #xA | #xD | [#x20-#x7E] (8 bit) - * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) - * | [#x10000-#x10FFFF] (32 bit) - */ - - if (! (value == 0x09 || value == 0x0A || value == 0x0D - || (value >= 0x20 && value <= 0x7E) - || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) - || (value >= 0xE000 && value <= 0xFFFD) - || (value >= 0x10000 && value <= 0x10FFFF))) - return yaml_parser_set_reader_error(parser, - "control characters are not allowed", - parser->offset, value); - - /* Move the raw pointers. */ - - parser->raw_buffer.pointer += width; - parser->offset += width; - - /* Finally put the character into the buffer. */ - - /* 0000 0000-0000 007F -> 0xxxxxxx */ - if (value <= 0x7F) { - *(parser->buffer.last++) = value; - } - /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ - else if (value <= 0x7FF) { - *(parser->buffer.last++) = 0xC0 + (value >> 6); - *(parser->buffer.last++) = 0x80 + (value & 0x3F); - } - /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ - else if (value <= 0xFFFF) { - *(parser->buffer.last++) = 0xE0 + (value >> 12); - *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); - *(parser->buffer.last++) = 0x80 + (value & 0x3F); - } - /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - else { - *(parser->buffer.last++) = 0xF0 + (value >> 18); - *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); - *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); - *(parser->buffer.last++) = 0x80 + (value & 0x3F); - } - - parser->unread ++; - } - - /* On EOF, put NUL into the buffer and return. */ - - if (parser->eof) { - *(parser->buffer.last++) = '\0'; - parser->unread ++; - return 1; - } - - } - - if (parser->offset >= MAX_FILE_SIZE) { - return yaml_parser_set_reader_error(parser, "input is too long", - parser->offset, -1); - } - - return 1; -} diff --git a/3rdparty/libyaml/src/scanner.c b/3rdparty/libyaml/src/scanner.c deleted file mode 100644 index ceee7496..00000000 --- a/3rdparty/libyaml/src/scanner.c +++ /dev/null @@ -1,3589 +0,0 @@ - -/* - * Introduction - * ************ - * - * The following notes assume that you are familiar with the YAML specification - * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in - * some cases we are less restrictive that it requires. - * - * The process of transforming a YAML stream into a sequence of events is - * divided on two steps: Scanning and Parsing. - * - * The Scanner transforms the input stream into a sequence of tokens, while the - * parser transform the sequence of tokens produced by the Scanner into a - * sequence of parsing events. - * - * The Scanner is rather clever and complicated. The Parser, on the contrary, - * is a straightforward implementation of a recursive-descendant parser (or, - * LL(1) parser, as it is usually called). - * - * Actually there are two issues of Scanning that might be called "clever", the - * rest is quite straightforward. The issues are "block collection start" and - * "simple keys". Both issues are explained below in details. - * - * Here the Scanning step is explained and implemented. We start with the list - * of all the tokens produced by the Scanner together with short descriptions. - * - * Now, tokens: - * - * STREAM-START(encoding) # The stream start. - * STREAM-END # The stream end. - * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. - * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. - * DOCUMENT-START # '---' - * DOCUMENT-END # '...' - * BLOCK-SEQUENCE-START # Indentation increase denoting a block - * BLOCK-MAPPING-START # sequence or a block mapping. - * BLOCK-END # Indentation decrease. - * FLOW-SEQUENCE-START # '[' - * FLOW-SEQUENCE-END # ']' - * FLOW-MAPPING-START # '{' - * FLOW-MAPPING-END # '}' - * BLOCK-ENTRY # '-' - * FLOW-ENTRY # ',' - * KEY # '?' or nothing (simple keys). - * VALUE # ':' - * ALIAS(anchor) # '*anchor' - * ANCHOR(anchor) # '&anchor' - * TAG(handle,suffix) # '!handle!suffix' - * SCALAR(value,style) # A scalar. - * - * The following two tokens are "virtual" tokens denoting the beginning and the - * end of the stream: - * - * STREAM-START(encoding) - * STREAM-END - * - * We pass the information about the input stream encoding with the - * STREAM-START token. - * - * The next two tokens are responsible for tags: - * - * VERSION-DIRECTIVE(major,minor) - * TAG-DIRECTIVE(handle,prefix) - * - * Example: - * - * %YAML 1.1 - * %TAG ! !foo - * %TAG !yaml! tag:yaml.org,2002: - * --- - * - * The corresponding sequence of tokens: - * - * STREAM-START(utf-8) - * VERSION-DIRECTIVE(1,1) - * TAG-DIRECTIVE("!","!foo") - * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") - * DOCUMENT-START - * STREAM-END - * - * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole - * line. - * - * The document start and end indicators are represented by: - * - * DOCUMENT-START - * DOCUMENT-END - * - * Note that if a YAML stream contains an implicit document (without '---' - * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be - * produced. - * - * In the following examples, we present whole documents together with the - * produced tokens. - * - * 1. An implicit document: - * - * 'a scalar' - * - * Tokens: - * - * STREAM-START(utf-8) - * SCALAR("a scalar",single-quoted) - * STREAM-END - * - * 2. An explicit document: - * - * --- - * 'a scalar' - * ... - * - * Tokens: - * - * STREAM-START(utf-8) - * DOCUMENT-START - * SCALAR("a scalar",single-quoted) - * DOCUMENT-END - * STREAM-END - * - * 3. Several documents in a stream: - * - * 'a scalar' - * --- - * 'another scalar' - * --- - * 'yet another scalar' - * - * Tokens: - * - * STREAM-START(utf-8) - * SCALAR("a scalar",single-quoted) - * DOCUMENT-START - * SCALAR("another scalar",single-quoted) - * DOCUMENT-START - * SCALAR("yet another scalar",single-quoted) - * STREAM-END - * - * We have already introduced the SCALAR token above. The following tokens are - * used to describe aliases, anchors, tag, and scalars: - * - * ALIAS(anchor) - * ANCHOR(anchor) - * TAG(handle,suffix) - * SCALAR(value,style) - * - * The following series of examples illustrate the usage of these tokens: - * - * 1. A recursive sequence: - * - * &A [ *A ] - * - * Tokens: - * - * STREAM-START(utf-8) - * ANCHOR("A") - * FLOW-SEQUENCE-START - * ALIAS("A") - * FLOW-SEQUENCE-END - * STREAM-END - * - * 2. A tagged scalar: - * - * !!float "3.14" # A good approximation. - * - * Tokens: - * - * STREAM-START(utf-8) - * TAG("!!","float") - * SCALAR("3.14",double-quoted) - * STREAM-END - * - * 3. Various scalar styles: - * - * --- # Implicit empty plain scalars do not produce tokens. - * --- a plain scalar - * --- 'a single-quoted scalar' - * --- "a double-quoted scalar" - * --- |- - * a literal scalar - * --- >- - * a folded - * scalar - * - * Tokens: - * - * STREAM-START(utf-8) - * DOCUMENT-START - * DOCUMENT-START - * SCALAR("a plain scalar",plain) - * DOCUMENT-START - * SCALAR("a single-quoted scalar",single-quoted) - * DOCUMENT-START - * SCALAR("a double-quoted scalar",double-quoted) - * DOCUMENT-START - * SCALAR("a literal scalar",literal) - * DOCUMENT-START - * SCALAR("a folded scalar",folded) - * STREAM-END - * - * Now it's time to review collection-related tokens. We will start with - * flow collections: - * - * FLOW-SEQUENCE-START - * FLOW-SEQUENCE-END - * FLOW-MAPPING-START - * FLOW-MAPPING-END - * FLOW-ENTRY - * KEY - * VALUE - * - * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and - * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' - * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the - * indicators '?' and ':', which are used for denoting mapping keys and values, - * are represented by the KEY and VALUE tokens. - * - * The following examples show flow collections: - * - * 1. A flow sequence: - * - * [item 1, item 2, item 3] - * - * Tokens: - * - * STREAM-START(utf-8) - * FLOW-SEQUENCE-START - * SCALAR("item 1",plain) - * FLOW-ENTRY - * SCALAR("item 2",plain) - * FLOW-ENTRY - * SCALAR("item 3",plain) - * FLOW-SEQUENCE-END - * STREAM-END - * - * 2. A flow mapping: - * - * { - * a simple key: a value, # Note that the KEY token is produced. - * ? a complex key: another value, - * } - * - * Tokens: - * - * STREAM-START(utf-8) - * FLOW-MAPPING-START - * KEY - * SCALAR("a simple key",plain) - * VALUE - * SCALAR("a value",plain) - * FLOW-ENTRY - * KEY - * SCALAR("a complex key",plain) - * VALUE - * SCALAR("another value",plain) - * FLOW-ENTRY - * FLOW-MAPPING-END - * STREAM-END - * - * A simple key is a key which is not denoted by the '?' indicator. Note that - * the Scanner still produce the KEY token whenever it encounters a simple key. - * - * For scanning block collections, the following tokens are used (note that we - * repeat KEY and VALUE here): - * - * BLOCK-SEQUENCE-START - * BLOCK-MAPPING-START - * BLOCK-END - * BLOCK-ENTRY - * KEY - * VALUE - * - * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation - * increase that precedes a block collection (cf. the INDENT token in Python). - * The token BLOCK-END denote indentation decrease that ends a block collection - * (cf. the DEDENT token in Python). However YAML has some syntax pecularities - * that makes detections of these tokens more complex. - * - * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators - * '-', '?', and ':' correspondingly. - * - * The following examples show how the tokens BLOCK-SEQUENCE-START, - * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: - * - * 1. Block sequences: - * - * - item 1 - * - item 2 - * - - * - item 3.1 - * - item 3.2 - * - - * key 1: value 1 - * key 2: value 2 - * - * Tokens: - * - * STREAM-START(utf-8) - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * SCALAR("item 1",plain) - * BLOCK-ENTRY - * SCALAR("item 2",plain) - * BLOCK-ENTRY - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * SCALAR("item 3.1",plain) - * BLOCK-ENTRY - * SCALAR("item 3.2",plain) - * BLOCK-END - * BLOCK-ENTRY - * BLOCK-MAPPING-START - * KEY - * SCALAR("key 1",plain) - * VALUE - * SCALAR("value 1",plain) - * KEY - * SCALAR("key 2",plain) - * VALUE - * SCALAR("value 2",plain) - * BLOCK-END - * BLOCK-END - * STREAM-END - * - * 2. Block mappings: - * - * a simple key: a value # The KEY token is produced here. - * ? a complex key - * : another value - * a mapping: - * key 1: value 1 - * key 2: value 2 - * a sequence: - * - item 1 - * - item 2 - * - * Tokens: - * - * STREAM-START(utf-8) - * BLOCK-MAPPING-START - * KEY - * SCALAR("a simple key",plain) - * VALUE - * SCALAR("a value",plain) - * KEY - * SCALAR("a complex key",plain) - * VALUE - * SCALAR("another value",plain) - * KEY - * SCALAR("a mapping",plain) - * BLOCK-MAPPING-START - * KEY - * SCALAR("key 1",plain) - * VALUE - * SCALAR("value 1",plain) - * KEY - * SCALAR("key 2",plain) - * VALUE - * SCALAR("value 2",plain) - * BLOCK-END - * KEY - * SCALAR("a sequence",plain) - * VALUE - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * SCALAR("item 1",plain) - * BLOCK-ENTRY - * SCALAR("item 2",plain) - * BLOCK-END - * BLOCK-END - * STREAM-END - * - * YAML does not always require to start a new block collection from a new - * line. If the current line contains only '-', '?', and ':' indicators, a new - * block collection may start at the current line. The following examples - * illustrate this case: - * - * 1. Collections in a sequence: - * - * - - item 1 - * - item 2 - * - key 1: value 1 - * key 2: value 2 - * - ? complex key - * : complex value - * - * Tokens: - * - * STREAM-START(utf-8) - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * SCALAR("item 1",plain) - * BLOCK-ENTRY - * SCALAR("item 2",plain) - * BLOCK-END - * BLOCK-ENTRY - * BLOCK-MAPPING-START - * KEY - * SCALAR("key 1",plain) - * VALUE - * SCALAR("value 1",plain) - * KEY - * SCALAR("key 2",plain) - * VALUE - * SCALAR("value 2",plain) - * BLOCK-END - * BLOCK-ENTRY - * BLOCK-MAPPING-START - * KEY - * SCALAR("complex key") - * VALUE - * SCALAR("complex value") - * BLOCK-END - * BLOCK-END - * STREAM-END - * - * 2. Collections in a mapping: - * - * ? a sequence - * : - item 1 - * - item 2 - * ? a mapping - * : key 1: value 1 - * key 2: value 2 - * - * Tokens: - * - * STREAM-START(utf-8) - * BLOCK-MAPPING-START - * KEY - * SCALAR("a sequence",plain) - * VALUE - * BLOCK-SEQUENCE-START - * BLOCK-ENTRY - * SCALAR("item 1",plain) - * BLOCK-ENTRY - * SCALAR("item 2",plain) - * BLOCK-END - * KEY - * SCALAR("a mapping",plain) - * VALUE - * BLOCK-MAPPING-START - * KEY - * SCALAR("key 1",plain) - * VALUE - * SCALAR("value 1",plain) - * KEY - * SCALAR("key 2",plain) - * VALUE - * SCALAR("value 2",plain) - * BLOCK-END - * BLOCK-END - * STREAM-END - * - * YAML also permits non-indented sequences if they are included into a block - * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: - * - * key: - * - item 1 # BLOCK-SEQUENCE-START is NOT produced here. - * - item 2 - * - * Tokens: - * - * STREAM-START(utf-8) - * BLOCK-MAPPING-START - * KEY - * SCALAR("key",plain) - * VALUE - * BLOCK-ENTRY - * SCALAR("item 1",plain) - * BLOCK-ENTRY - * SCALAR("item 2",plain) - * BLOCK-END - */ - -#include "yaml_private.h" - -/* - * Ensure that the buffer contains the required number of characters. - * Return 1 on success, 0 on failure (reader error or memory error). - */ - -#define CACHE(parser,length) \ - (parser->unread >= (length) \ - ? 1 \ - : yaml_parser_update_buffer(parser, (length))) - -/* - * Advance the buffer pointer. - */ - -#define SKIP(parser) \ - (parser->mark.index ++, \ - parser->mark.column ++, \ - parser->unread --, \ - parser->buffer.pointer += WIDTH(parser->buffer)) - -#define SKIP_LINE(parser) \ - (IS_CRLF(parser->buffer) ? \ - (parser->mark.index += 2, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread -= 2, \ - parser->buffer.pointer += 2) : \ - IS_BREAK(parser->buffer) ? \ - (parser->mark.index ++, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread --, \ - parser->buffer.pointer += WIDTH(parser->buffer)) : 0) - -/* - * Copy a character to a string buffer and advance pointers. - */ - -#define READ(parser,string) \ - (STRING_EXTEND(parser,string) ? \ - (COPY(string,parser->buffer), \ - parser->mark.index ++, \ - parser->mark.column ++, \ - parser->unread --, \ - 1) : 0) - -/* - * Copy a line break character to a string buffer and advance pointers. - */ - -#define READ_LINE(parser,string) \ - (STRING_EXTEND(parser,string) ? \ - (((CHECK_AT(parser->buffer,'\r',0) \ - && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \ - (*((string).pointer++) = (yaml_char_t) '\n', \ - parser->buffer.pointer += 2, \ - parser->mark.index += 2, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread -= 2) : \ - (CHECK_AT(parser->buffer,'\r',0) \ - || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \ - (*((string).pointer++) = (yaml_char_t) '\n', \ - parser->buffer.pointer ++, \ - parser->mark.index ++, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread --) : \ - (CHECK_AT(parser->buffer,'\xC2',0) \ - && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \ - (*((string).pointer++) = (yaml_char_t) '\n', \ - parser->buffer.pointer += 2, \ - parser->mark.index ++, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread --) : \ - (CHECK_AT(parser->buffer,'\xE2',0) && \ - CHECK_AT(parser->buffer,'\x80',1) && \ - (CHECK_AT(parser->buffer,'\xA8',2) || \ - CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \ - (*((string).pointer++) = *(parser->buffer.pointer++), \ - *((string).pointer++) = *(parser->buffer.pointer++), \ - *((string).pointer++) = *(parser->buffer.pointer++), \ - parser->mark.index ++, \ - parser->mark.column = 0, \ - parser->mark.line ++, \ - parser->unread --) : 0), \ - 1) : 0) - -/* - * Public API declarations. - */ - -YAML_DECLARE(int) -yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); - -/* - * Error handling. - */ - -static int -yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, - yaml_mark_t context_mark, const char *problem); - -/* - * High-level token API. - */ - -YAML_DECLARE(int) -yaml_parser_fetch_more_tokens(yaml_parser_t *parser); - -static int -yaml_parser_fetch_next_token(yaml_parser_t *parser); - -/* - * Potential simple keys. - */ - -static int -yaml_parser_stale_simple_keys(yaml_parser_t *parser); - -static int -yaml_parser_save_simple_key(yaml_parser_t *parser); - -static int -yaml_parser_remove_simple_key(yaml_parser_t *parser); - -static int -yaml_parser_increase_flow_level(yaml_parser_t *parser); - -static int -yaml_parser_decrease_flow_level(yaml_parser_t *parser); - -/* - * Indentation treatment. - */ - -static int -yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, - ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark); - -static int -yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column); - -/* - * Token fetchers. - */ - -static int -yaml_parser_fetch_stream_start(yaml_parser_t *parser); - -static int -yaml_parser_fetch_stream_end(yaml_parser_t *parser); - -static int -yaml_parser_fetch_directive(yaml_parser_t *parser); - -static int -yaml_parser_fetch_document_indicator(yaml_parser_t *parser, - yaml_token_type_t type); - -static int -yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, - yaml_token_type_t type); - -static int -yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, - yaml_token_type_t type); - -static int -yaml_parser_fetch_flow_entry(yaml_parser_t *parser); - -static int -yaml_parser_fetch_block_entry(yaml_parser_t *parser); - -static int -yaml_parser_fetch_key(yaml_parser_t *parser); - -static int -yaml_parser_fetch_value(yaml_parser_t *parser); - -static int -yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type); - -static int -yaml_parser_fetch_tag(yaml_parser_t *parser); - -static int -yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal); - -static int -yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single); - -static int -yaml_parser_fetch_plain_scalar(yaml_parser_t *parser); - -/* - * Token scanners. - */ - -static int -yaml_parser_scan_to_next_token(yaml_parser_t *parser); - -static int -yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token); - -static int -yaml_parser_scan_directive_name(yaml_parser_t *parser, - yaml_mark_t start_mark, yaml_char_t **name); - -static int -yaml_parser_scan_version_directive_value(yaml_parser_t *parser, - yaml_mark_t start_mark, int *major, int *minor); - -static int -yaml_parser_scan_version_directive_number(yaml_parser_t *parser, - yaml_mark_t start_mark, int *number); - -static int -yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, - yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix); - -static int -yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, - yaml_token_type_t type); - -static int -yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token); - -static int -yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, - yaml_mark_t start_mark, yaml_char_t **handle); - -static int -yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, - yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri); - -static int -yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, - yaml_mark_t start_mark, yaml_string_t *string); - -static int -yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, - int literal); - -static int -yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, - int *indent, yaml_string_t *breaks, - yaml_mark_t start_mark, yaml_mark_t *end_mark); - -static int -yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, - int single); - -static int -yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token); - -/* - * Get the next token. - */ - -YAML_DECLARE(int) -yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token) -{ - assert(parser); /* Non-NULL parser object is expected. */ - assert(token); /* Non-NULL token object is expected. */ - - /* Erase the token object. */ - - memset(token, 0, sizeof(yaml_token_t)); - - /* No tokens after STREAM-END or error. */ - - if (parser->stream_end_produced || parser->error) { - return 1; - } - - /* Ensure that the tokens queue contains enough tokens. */ - - if (!parser->token_available) { - if (!yaml_parser_fetch_more_tokens(parser)) - return 0; - } - - /* Fetch the next token from the queue. */ - - *token = DEQUEUE(parser, parser->tokens); - parser->token_available = 0; - parser->tokens_parsed ++; - - if (token->type == YAML_STREAM_END_TOKEN) { - parser->stream_end_produced = 1; - } - - return 1; -} - -/* - * Set the scanner error and return 0. - */ - -static int -yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, - yaml_mark_t context_mark, const char *problem) -{ - parser->error = YAML_SCANNER_ERROR; - parser->context = context; - parser->context_mark = context_mark; - parser->problem = problem; - parser->problem_mark = parser->mark; - - return 0; -} - -/* - * Ensure that the tokens queue contains at least one token which can be - * returned to the Parser. - */ - -YAML_DECLARE(int) -yaml_parser_fetch_more_tokens(yaml_parser_t *parser) -{ - int need_more_tokens; - - /* While we need more tokens to fetch, do it. */ - - while (1) - { - /* - * Check if we really need to fetch more tokens. - */ - - need_more_tokens = 0; - - if (parser->tokens.head == parser->tokens.tail) - { - /* Queue is empty. */ - - need_more_tokens = 1; - } - else - { - yaml_simple_key_t *simple_key; - - /* Check if any potential simple key may occupy the head position. */ - - if (!yaml_parser_stale_simple_keys(parser)) - return 0; - - for (simple_key = parser->simple_keys.start; - simple_key != parser->simple_keys.top; simple_key++) { - if (simple_key->possible - && simple_key->token_number == parser->tokens_parsed) { - need_more_tokens = 1; - break; - } - } - } - - /* We are finished. */ - - if (!need_more_tokens) - break; - - /* Fetch the next token. */ - - if (!yaml_parser_fetch_next_token(parser)) - return 0; - } - - parser->token_available = 1; - - return 1; -} - -/* - * The dispatcher for token fetchers. - */ - -static int -yaml_parser_fetch_next_token(yaml_parser_t *parser) -{ - /* Ensure that the buffer is initialized. */ - - if (!CACHE(parser, 1)) - return 0; - - /* Check if we just started scanning. Fetch STREAM-START then. */ - - if (!parser->stream_start_produced) - return yaml_parser_fetch_stream_start(parser); - - /* Eat whitespaces and comments until we reach the next token. */ - - if (!yaml_parser_scan_to_next_token(parser)) - return 0; - - /* Remove obsolete potential simple keys. */ - - if (!yaml_parser_stale_simple_keys(parser)) - return 0; - - /* Check the indentation level against the current column. */ - - if (!yaml_parser_unroll_indent(parser, parser->mark.column)) - return 0; - - /* - * Ensure that the buffer contains at least 4 characters. 4 is the length - * of the longest indicators ('--- ' and '... '). - */ - - if (!CACHE(parser, 4)) - return 0; - - /* Is it the end of the stream? */ - - if (IS_Z(parser->buffer)) - return yaml_parser_fetch_stream_end(parser); - - /* Is it a directive? */ - - if (parser->mark.column == 0 && CHECK(parser->buffer, '%')) - return yaml_parser_fetch_directive(parser); - - /* Is it the document start indicator? */ - - if (parser->mark.column == 0 - && CHECK_AT(parser->buffer, '-', 0) - && CHECK_AT(parser->buffer, '-', 1) - && CHECK_AT(parser->buffer, '-', 2) - && IS_BLANKZ_AT(parser->buffer, 3)) - return yaml_parser_fetch_document_indicator(parser, - YAML_DOCUMENT_START_TOKEN); - - /* Is it the document end indicator? */ - - if (parser->mark.column == 0 - && CHECK_AT(parser->buffer, '.', 0) - && CHECK_AT(parser->buffer, '.', 1) - && CHECK_AT(parser->buffer, '.', 2) - && IS_BLANKZ_AT(parser->buffer, 3)) - return yaml_parser_fetch_document_indicator(parser, - YAML_DOCUMENT_END_TOKEN); - - /* Is it the flow sequence start indicator? */ - - if (CHECK(parser->buffer, '[')) - return yaml_parser_fetch_flow_collection_start(parser, - YAML_FLOW_SEQUENCE_START_TOKEN); - - /* Is it the flow mapping start indicator? */ - - if (CHECK(parser->buffer, '{')) - return yaml_parser_fetch_flow_collection_start(parser, - YAML_FLOW_MAPPING_START_TOKEN); - - /* Is it the flow sequence end indicator? */ - - if (CHECK(parser->buffer, ']')) - return yaml_parser_fetch_flow_collection_end(parser, - YAML_FLOW_SEQUENCE_END_TOKEN); - - /* Is it the flow mapping end indicator? */ - - if (CHECK(parser->buffer, '}')) - return yaml_parser_fetch_flow_collection_end(parser, - YAML_FLOW_MAPPING_END_TOKEN); - - /* Is it the flow entry indicator? */ - - if (CHECK(parser->buffer, ',')) - return yaml_parser_fetch_flow_entry(parser); - - /* Is it the block entry indicator? */ - - if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1)) - return yaml_parser_fetch_block_entry(parser); - - /* Is it the key indicator? */ - - if (CHECK(parser->buffer, '?') - && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) - return yaml_parser_fetch_key(parser); - - /* Is it the value indicator? */ - - if (CHECK(parser->buffer, ':') - && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) - return yaml_parser_fetch_value(parser); - - /* Is it an alias? */ - - if (CHECK(parser->buffer, '*')) - return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN); - - /* Is it an anchor? */ - - if (CHECK(parser->buffer, '&')) - return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN); - - /* Is it a tag? */ - - if (CHECK(parser->buffer, '!')) - return yaml_parser_fetch_tag(parser); - - /* Is it a literal scalar? */ - - if (CHECK(parser->buffer, '|') && !parser->flow_level) - return yaml_parser_fetch_block_scalar(parser, 1); - - /* Is it a folded scalar? */ - - if (CHECK(parser->buffer, '>') && !parser->flow_level) - return yaml_parser_fetch_block_scalar(parser, 0); - - /* Is it a single-quoted scalar? */ - - if (CHECK(parser->buffer, '\'')) - return yaml_parser_fetch_flow_scalar(parser, 1); - - /* Is it a double-quoted scalar? */ - - if (CHECK(parser->buffer, '"')) - return yaml_parser_fetch_flow_scalar(parser, 0); - - /* - * Is it a plain scalar? - * - * A plain scalar may start with any non-blank characters except - * - * '-', '?', ':', ',', '[', ']', '{', '}', - * '#', '&', '*', '!', '|', '>', '\'', '\"', - * '%', '@', '`'. - * - * In the block context (and, for the '-' indicator, in the flow context - * too), it may also start with the characters - * - * '-', '?', ':' - * - * if it is followed by a non-space character. - * - * The last rule is more restrictive than the specification requires. - */ - - if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-') - || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':') - || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[') - || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') - || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#') - || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*') - || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|') - || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'') - || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%') - || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) || - (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) || - (!parser->flow_level && - (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')) - && !IS_BLANKZ_AT(parser->buffer, 1))) - return yaml_parser_fetch_plain_scalar(parser); - - /* - * If we don't determine the token type so far, it is an error. - */ - - return yaml_parser_set_scanner_error(parser, - "while scanning for the next token", parser->mark, - "found character that cannot start any token"); -} - -/* - * Check the list of potential simple keys and remove the positions that - * cannot contain simple keys anymore. - */ - -static int -yaml_parser_stale_simple_keys(yaml_parser_t *parser) -{ - yaml_simple_key_t *simple_key; - - /* Check for a potential simple key for each flow level. */ - - for (simple_key = parser->simple_keys.start; - simple_key != parser->simple_keys.top; simple_key ++) - { - /* - * The specification requires that a simple key - * - * - is limited to a single line, - * - is shorter than 1024 characters. - */ - - if (simple_key->possible - && (simple_key->mark.line < parser->mark.line - || simple_key->mark.index+1024 < parser->mark.index)) { - - /* Check if the potential simple key to be removed is required. */ - - if (simple_key->required) { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key->mark, - "could not find expected ':'"); - } - - simple_key->possible = 0; - } - } - - return 1; -} - -/* - * Check if a simple key may start at the current position and add it if - * needed. - */ - -static int -yaml_parser_save_simple_key(yaml_parser_t *parser) -{ - /* - * A simple key is required at the current position if the scanner is in - * the block context and the current column coincides with the indentation - * level. - */ - - int required = (!parser->flow_level - && parser->indent == (ptrdiff_t)parser->mark.column); - - /* - * If the current position may start a simple key, save it. - */ - - if (parser->simple_key_allowed) - { - yaml_simple_key_t simple_key; - simple_key.possible = 1; - simple_key.required = required; - simple_key.token_number = - parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head); - simple_key.mark = parser->mark; - - if (!yaml_parser_remove_simple_key(parser)) return 0; - - *(parser->simple_keys.top-1) = simple_key; - } - - return 1; -} - -/* - * Remove a potential simple key at the current flow level. - */ - -static int -yaml_parser_remove_simple_key(yaml_parser_t *parser) -{ - yaml_simple_key_t *simple_key = parser->simple_keys.top-1; - - if (simple_key->possible) - { - /* If the key is required, it is an error. */ - - if (simple_key->required) { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key->mark, - "could not find expected ':'"); - } - } - - /* Remove the key from the stack. */ - - simple_key->possible = 0; - - return 1; -} - -/* - * Increase the flow level and resize the simple key list if needed. - */ - -static int -yaml_parser_increase_flow_level(yaml_parser_t *parser) -{ - yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } }; - - /* Reset the simple key on the next level. */ - - if (!PUSH(parser, parser->simple_keys, empty_simple_key)) - return 0; - - /* Increase the flow level. */ - - if (parser->flow_level == INT_MAX) { - parser->error = YAML_MEMORY_ERROR; - return 0; - } - - parser->flow_level++; - - return 1; -} - -/* - * Decrease the flow level. - */ - -static int -yaml_parser_decrease_flow_level(yaml_parser_t *parser) -{ - if (parser->flow_level) { - parser->flow_level --; - (void)POP(parser, parser->simple_keys); - } - - return 1; -} - -/* - * Push the current indentation level to the stack and set the new level - * the current column is greater than the indentation level. In this case, - * append or insert the specified token into the token queue. - * - */ - -static int -yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, - ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark) -{ - yaml_token_t token; - - /* In the flow context, do nothing. */ - - if (parser->flow_level) - return 1; - - if (parser->indent < column) - { - /* - * Push the current indentation level to the stack and set the new - * indentation level. - */ - - if (!PUSH(parser, parser->indents, parser->indent)) - return 0; - - if (column > INT_MAX) { - parser->error = YAML_MEMORY_ERROR; - return 0; - } - - parser->indent = column; - - /* Create a token and insert it into the queue. */ - - TOKEN_INIT(token, type, mark, mark); - - if (number == -1) { - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - } - else { - if (!QUEUE_INSERT(parser, - parser->tokens, number - parser->tokens_parsed, token)) - return 0; - } - } - - return 1; -} - -/* - * Pop indentation levels from the indents stack until the current level - * becomes less or equal to the column. For each indentation level, append - * the BLOCK-END token. - */ - - -static int -yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column) -{ - yaml_token_t token; - - /* In the flow context, do nothing. */ - - if (parser->flow_level) - return 1; - - /* Loop through the indentation levels in the stack. */ - - while (parser->indent > column) - { - /* Create a token and append it to the queue. */ - - TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - /* Pop the indentation level. */ - - parser->indent = POP(parser, parser->indents); - } - - return 1; -} - -/* - * Initialize the scanner and produce the STREAM-START token. - */ - -static int -yaml_parser_fetch_stream_start(yaml_parser_t *parser) -{ - yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } }; - yaml_token_t token; - - /* Set the initial indentation. */ - - parser->indent = -1; - - /* Initialize the simple key stack. */ - - if (!PUSH(parser, parser->simple_keys, simple_key)) - return 0; - - /* A simple key is allowed at the beginning of the stream. */ - - parser->simple_key_allowed = 1; - - /* We have started. */ - - parser->stream_start_produced = 1; - - /* Create the STREAM-START token and append it to the queue. */ - - STREAM_START_TOKEN_INIT(token, parser->encoding, - parser->mark, parser->mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the STREAM-END token and shut down the scanner. - */ - -static int -yaml_parser_fetch_stream_end(yaml_parser_t *parser) -{ - yaml_token_t token; - - /* Force new line. */ - - if (parser->mark.column != 0) { - parser->mark.column = 0; - parser->mark.line ++; - } - - /* Reset the indentation level. */ - - if (!yaml_parser_unroll_indent(parser, -1)) - return 0; - - /* Reset simple keys. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - parser->simple_key_allowed = 0; - - /* Create the STREAM-END token and append it to the queue. */ - - STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. - */ - -static int -yaml_parser_fetch_directive(yaml_parser_t *parser) -{ - yaml_token_t token; - - /* Reset the indentation level. */ - - if (!yaml_parser_unroll_indent(parser, -1)) - return 0; - - /* Reset simple keys. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - parser->simple_key_allowed = 0; - - /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */ - - if (!yaml_parser_scan_directive(parser, &token)) - return 0; - - /* Append the token to the queue. */ - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - - return 1; -} - -/* - * Produce the DOCUMENT-START or DOCUMENT-END token. - */ - -static int -yaml_parser_fetch_document_indicator(yaml_parser_t *parser, - yaml_token_type_t type) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* Reset the indentation level. */ - - if (!yaml_parser_unroll_indent(parser, -1)) - return 0; - - /* Reset simple keys. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - parser->simple_key_allowed = 0; - - /* Consume the token. */ - - start_mark = parser->mark; - - SKIP(parser); - SKIP(parser); - SKIP(parser); - - end_mark = parser->mark; - - /* Create the DOCUMENT-START or DOCUMENT-END token. */ - - TOKEN_INIT(token, type, start_mark, end_mark); - - /* Append the token to the queue. */ - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. - */ - -static int -yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, - yaml_token_type_t type) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* The indicators '[' and '{' may start a simple key. */ - - if (!yaml_parser_save_simple_key(parser)) - return 0; - - /* Increase the flow level. */ - - if (!yaml_parser_increase_flow_level(parser)) - return 0; - - /* A simple key may follow the indicators '[' and '{'. */ - - parser->simple_key_allowed = 1; - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */ - - TOKEN_INIT(token, type, start_mark, end_mark); - - /* Append the token to the queue. */ - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. - */ - -static int -yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, - yaml_token_type_t type) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* Reset any potential simple key on the current flow level. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - /* Decrease the flow level. */ - - if (!yaml_parser_decrease_flow_level(parser)) - return 0; - - /* No simple keys after the indicators ']' and '}'. */ - - parser->simple_key_allowed = 0; - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */ - - TOKEN_INIT(token, type, start_mark, end_mark); - - /* Append the token to the queue. */ - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the FLOW-ENTRY token. - */ - -static int -yaml_parser_fetch_flow_entry(yaml_parser_t *parser) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* Reset any potential simple keys on the current flow level. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - /* Simple keys are allowed after ','. */ - - parser->simple_key_allowed = 1; - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the FLOW-ENTRY token and append it to the queue. */ - - TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the BLOCK-ENTRY token. - */ - -static int -yaml_parser_fetch_block_entry(yaml_parser_t *parser) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* Check if the scanner is in the block context. */ - - if (!parser->flow_level) - { - /* Check if we are allowed to start a new entry. */ - - if (!parser->simple_key_allowed) { - return yaml_parser_set_scanner_error(parser, NULL, parser->mark, - "block sequence entries are not allowed in this context"); - } - - /* Add the BLOCK-SEQUENCE-START token if needed. */ - - if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, - YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark)) - return 0; - } - else - { - /* - * It is an error for the '-' indicator to occur in the flow context, - * but we let the Parser detect and report about it because the Parser - * is able to point to the context. - */ - } - - /* Reset any potential simple keys on the current flow level. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - /* Simple keys are allowed after '-'. */ - - parser->simple_key_allowed = 1; - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the BLOCK-ENTRY token and append it to the queue. */ - - TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the KEY token. - */ - -static int -yaml_parser_fetch_key(yaml_parser_t *parser) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - - /* In the block context, additional checks are required. */ - - if (!parser->flow_level) - { - /* Check if we are allowed to start a new key (not necessary simple). */ - - if (!parser->simple_key_allowed) { - return yaml_parser_set_scanner_error(parser, NULL, parser->mark, - "mapping keys are not allowed in this context"); - } - - /* Add the BLOCK-MAPPING-START token if needed. */ - - if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, - YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) - return 0; - } - - /* Reset any potential simple keys on the current flow level. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - /* Simple keys are allowed after '?' in the block context. */ - - parser->simple_key_allowed = (!parser->flow_level); - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the KEY token and append it to the queue. */ - - TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the VALUE token. - */ - -static int -yaml_parser_fetch_value(yaml_parser_t *parser) -{ - yaml_mark_t start_mark, end_mark; - yaml_token_t token; - yaml_simple_key_t *simple_key = parser->simple_keys.top-1; - - /* Have we found a simple key? */ - - if (simple_key->possible) - { - - /* Create the KEY token and insert it into the queue. */ - - TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark); - - if (!QUEUE_INSERT(parser, parser->tokens, - simple_key->token_number - parser->tokens_parsed, token)) - return 0; - - /* In the block context, we may need to add the BLOCK-MAPPING-START token. */ - - if (!yaml_parser_roll_indent(parser, simple_key->mark.column, - simple_key->token_number, - YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark)) - return 0; - - /* Remove the simple key. */ - - simple_key->possible = 0; - - /* A simple key cannot follow another simple key. */ - - parser->simple_key_allowed = 0; - } - else - { - /* The ':' indicator follows a complex key. */ - - /* In the block context, extra checks are required. */ - - if (!parser->flow_level) - { - /* Check if we are allowed to start a complex value. */ - - if (!parser->simple_key_allowed) { - return yaml_parser_set_scanner_error(parser, NULL, parser->mark, - "mapping values are not allowed in this context"); - } - - /* Add the BLOCK-MAPPING-START token if needed. */ - - if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, - YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) - return 0; - } - - /* Simple keys after ':' are allowed in the block context. */ - - parser->simple_key_allowed = (!parser->flow_level); - } - - /* Consume the token. */ - - start_mark = parser->mark; - SKIP(parser); - end_mark = parser->mark; - - /* Create the VALUE token and append it to the queue. */ - - TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark); - - if (!ENQUEUE(parser, parser->tokens, token)) - return 0; - - return 1; -} - -/* - * Produce the ALIAS or ANCHOR token. - */ - -static int -yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type) -{ - yaml_token_t token; - - /* An anchor or an alias could be a simple key. */ - - if (!yaml_parser_save_simple_key(parser)) - return 0; - - /* A simple key cannot follow an anchor or an alias. */ - - parser->simple_key_allowed = 0; - - /* Create the ALIAS or ANCHOR token and append it to the queue. */ - - if (!yaml_parser_scan_anchor(parser, &token, type)) - return 0; - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - return 1; -} - -/* - * Produce the TAG token. - */ - -static int -yaml_parser_fetch_tag(yaml_parser_t *parser) -{ - yaml_token_t token; - - /* A tag could be a simple key. */ - - if (!yaml_parser_save_simple_key(parser)) - return 0; - - /* A simple key cannot follow a tag. */ - - parser->simple_key_allowed = 0; - - /* Create the TAG token and append it to the queue. */ - - if (!yaml_parser_scan_tag(parser, &token)) - return 0; - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - - return 1; -} - -/* - * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. - */ - -static int -yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal) -{ - yaml_token_t token; - - /* Remove any potential simple keys. */ - - if (!yaml_parser_remove_simple_key(parser)) - return 0; - - /* A simple key may follow a block scalar. */ - - parser->simple_key_allowed = 1; - - /* Create the SCALAR token and append it to the queue. */ - - if (!yaml_parser_scan_block_scalar(parser, &token, literal)) - return 0; - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - - return 1; -} - -/* - * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. - */ - -static int -yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single) -{ - yaml_token_t token; - - /* A plain scalar could be a simple key. */ - - if (!yaml_parser_save_simple_key(parser)) - return 0; - - /* A simple key cannot follow a flow scalar. */ - - parser->simple_key_allowed = 0; - - /* Create the SCALAR token and append it to the queue. */ - - if (!yaml_parser_scan_flow_scalar(parser, &token, single)) - return 0; - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - - return 1; -} - -/* - * Produce the SCALAR(...,plain) token. - */ - -static int -yaml_parser_fetch_plain_scalar(yaml_parser_t *parser) -{ - yaml_token_t token; - - /* A plain scalar could be a simple key. */ - - if (!yaml_parser_save_simple_key(parser)) - return 0; - - /* A simple key cannot follow a flow scalar. */ - - parser->simple_key_allowed = 0; - - /* Create the SCALAR token and append it to the queue. */ - - if (!yaml_parser_scan_plain_scalar(parser, &token)) - return 0; - - if (!ENQUEUE(parser, parser->tokens, token)) { - yaml_token_delete(&token); - return 0; - } - - return 1; -} - -/* - * Eat whitespaces and comments until the next token is found. - */ - -static int -yaml_parser_scan_to_next_token(yaml_parser_t *parser) -{ - /* Until the next token is not found. */ - - while (1) - { - /* Allow the BOM mark to start a line. */ - - if (!CACHE(parser, 1)) return 0; - - if (parser->mark.column == 0 && IS_BOM(parser->buffer)) - SKIP(parser); - - /* - * Eat whitespaces. - * - * Tabs are allowed: - * - * - in the flow context; - * - in the block context, but not at the beginning of the line or - * after '-', '?', or ':' (complex value). - */ - - if (!CACHE(parser, 1)) return 0; - - while (CHECK(parser->buffer,' ') || - ((parser->flow_level || !parser->simple_key_allowed) && - CHECK(parser->buffer, '\t'))) { - SKIP(parser); - if (!CACHE(parser, 1)) return 0; - } - - /* Eat a comment until a line break. */ - - if (CHECK(parser->buffer, '#')) { - while (!IS_BREAKZ(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) return 0; - } - } - - /* If it is a line break, eat it. */ - - if (IS_BREAK(parser->buffer)) - { - if (!CACHE(parser, 2)) return 0; - SKIP_LINE(parser); - - /* In the block context, a new line may start a simple key. */ - - if (!parser->flow_level) { - parser->simple_key_allowed = 1; - } - } - else - { - /* We have found a token. */ - - break; - } - } - - return 1; -} - -/* - * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. - * - * Scope: - * %YAML 1.1 # a comment \n - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * %TAG !yaml! tag:yaml.org,2002: \n - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - */ - -int -yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token) -{ - yaml_mark_t start_mark, end_mark; - yaml_char_t *name = NULL; - int major, minor; - yaml_char_t *handle = NULL, *prefix = NULL; - - /* Eat '%'. */ - - start_mark = parser->mark; - - SKIP(parser); - - /* Scan the directive name. */ - - if (!yaml_parser_scan_directive_name(parser, start_mark, &name)) - goto error; - - /* Is it a YAML directive? */ - - if (strcmp((char *)name, "YAML") == 0) - { - /* Scan the VERSION directive value. */ - - if (!yaml_parser_scan_version_directive_value(parser, start_mark, - &major, &minor)) - goto error; - - end_mark = parser->mark; - - /* Create a VERSION-DIRECTIVE token. */ - - VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor, - start_mark, end_mark); - } - - /* Is it a TAG directive? */ - - else if (strcmp((char *)name, "TAG") == 0) - { - /* Scan the TAG directive value. */ - - if (!yaml_parser_scan_tag_directive_value(parser, start_mark, - &handle, &prefix)) - goto error; - - end_mark = parser->mark; - - /* Create a TAG-DIRECTIVE token. */ - - TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix, - start_mark, end_mark); - } - - /* Unknown directive. */ - - else - { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unknown directive name"); - goto error; - } - - /* Eat the rest of the line including any comments. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_BLANK(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - - if (CHECK(parser->buffer, '#')) { - while (!IS_BREAKZ(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - } - - /* Check if we are at the end of the line. */ - - if (!IS_BREAKZ(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "did not find expected comment or line break"); - goto error; - } - - /* Eat a line break. */ - - if (IS_BREAK(parser->buffer)) { - if (!CACHE(parser, 2)) goto error; - SKIP_LINE(parser); - } - - yaml_free(name); - - return 1; - -error: - yaml_free(prefix); - yaml_free(handle); - yaml_free(name); - return 0; -} - -/* - * Scan the directive name. - * - * Scope: - * %YAML 1.1 # a comment \n - * ^^^^ - * %TAG !yaml! tag:yaml.org,2002: \n - * ^^^ - */ - -static int -yaml_parser_scan_directive_name(yaml_parser_t *parser, - yaml_mark_t start_mark, yaml_char_t **name) -{ - yaml_string_t string = NULL_STRING; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - - /* Consume the directive name. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_ALPHA(parser->buffer)) - { - if (!READ(parser, string)) goto error; - if (!CACHE(parser, 1)) goto error; - } - - /* Check if the name is empty. */ - - if (string.start == string.pointer) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "could not find expected directive name"); - goto error; - } - - /* Check for an blank character after the name. */ - - if (!IS_BLANKZ(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unexpected non-alphabetical character"); - goto error; - } - - *name = string.start; - - return 1; - -error: - STRING_DEL(parser, string); - return 0; -} - -/* - * Scan the value of VERSION-DIRECTIVE. - * - * Scope: - * %YAML 1.1 # a comment \n - * ^^^^^^ - */ - -static int -yaml_parser_scan_version_directive_value(yaml_parser_t *parser, - yaml_mark_t start_mark, int *major, int *minor) -{ - /* Eat whitespaces. */ - - if (!CACHE(parser, 1)) return 0; - - while (IS_BLANK(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) return 0; - } - - /* Consume the major version number. */ - - if (!yaml_parser_scan_version_directive_number(parser, start_mark, major)) - return 0; - - /* Eat '.'. */ - - if (!CHECK(parser->buffer, '.')) { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected digit or '.' character"); - } - - SKIP(parser); - - /* Consume the minor version number. */ - - if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor)) - return 0; - - return 1; -} - -#define MAX_NUMBER_LENGTH 9 - -/* - * Scan the version number of VERSION-DIRECTIVE. - * - * Scope: - * %YAML 1.1 # a comment \n - * ^ - * %YAML 1.1 # a comment \n - * ^ - */ - -static int -yaml_parser_scan_version_directive_number(yaml_parser_t *parser, - yaml_mark_t start_mark, int *number) -{ - int value = 0; - size_t length = 0; - - /* Repeat while the next character is digit. */ - - if (!CACHE(parser, 1)) return 0; - - while (IS_DIGIT(parser->buffer)) - { - /* Check if the number is too long. */ - - if (++length > MAX_NUMBER_LENGTH) { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "found extremely long version number"); - } - - value = value*10 + AS_DIGIT(parser->buffer); - - SKIP(parser); - - if (!CACHE(parser, 1)) return 0; - } - - /* Check if the number was present. */ - - if (!length) { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected version number"); - } - - *number = value; - - return 1; -} - -/* - * Scan the value of a TAG-DIRECTIVE token. - * - * Scope: - * %TAG !yaml! tag:yaml.org,2002: \n - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - */ - -static int -yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, - yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix) -{ - yaml_char_t *handle_value = NULL; - yaml_char_t *prefix_value = NULL; - - /* Eat whitespaces. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_BLANK(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - - /* Scan a handle. */ - - if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value)) - goto error; - - /* Expect a whitespace. */ - - if (!CACHE(parser, 1)) goto error; - - if (!IS_BLANK(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace"); - goto error; - } - - /* Eat whitespaces. */ - - while (IS_BLANK(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - - /* Scan a prefix. */ - - if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value)) - goto error; - - /* Expect a whitespace or line break. */ - - if (!CACHE(parser, 1)) goto error; - - if (!IS_BLANKZ(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace or line break"); - goto error; - } - - *handle = handle_value; - *prefix = prefix_value; - - return 1; - -error: - yaml_free(handle_value); - yaml_free(prefix_value); - return 0; -} - -static int -yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, - yaml_token_type_t type) -{ - int length = 0; - yaml_mark_t start_mark, end_mark; - yaml_string_t string = NULL_STRING; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - - /* Eat the indicator character. */ - - start_mark = parser->mark; - - SKIP(parser); - - /* Consume the value. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_ALPHA(parser->buffer)) { - if (!READ(parser, string)) goto error; - if (!CACHE(parser, 1)) goto error; - length ++; - } - - end_mark = parser->mark; - - /* - * Check if length of the anchor is greater than 0 and it is followed by - * a whitespace character or one of the indicators: - * - * '?', ':', ',', ']', '}', '%', '@', '`'. - */ - - if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?') - || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',') - || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}') - || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@') - || CHECK(parser->buffer, '`'))) { - yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ? - "while scanning an anchor" : "while scanning an alias", start_mark, - "did not find expected alphabetic or numeric character"); - goto error; - } - - /* Create a token. */ - - if (type == YAML_ANCHOR_TOKEN) { - ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark); - } - else { - ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark); - } - - return 1; - -error: - STRING_DEL(parser, string); - return 0; -} - -/* - * Scan a TAG token. - */ - -static int -yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token) -{ - yaml_char_t *handle = NULL; - yaml_char_t *suffix = NULL; - yaml_mark_t start_mark, end_mark; - - start_mark = parser->mark; - - /* Check if the tag is in the canonical form. */ - - if (!CACHE(parser, 2)) goto error; - - if (CHECK_AT(parser->buffer, '<', 1)) - { - /* Set the handle to '' */ - - handle = YAML_MALLOC(1); - if (!handle) goto error; - handle[0] = '\0'; - - /* Eat '!<' */ - - SKIP(parser); - SKIP(parser); - - /* Consume the tag value. */ - - if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) - goto error; - - /* Check for '>' and eat it. */ - - if (!CHECK(parser->buffer, '>')) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find the expected '>'"); - goto error; - } - - SKIP(parser); - } - else - { - /* The tag has either the '!suffix' or the '!handle!suffix' form. */ - - /* First, try to scan a handle. */ - - if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle)) - goto error; - - /* Check if it is, indeed, handle. */ - - if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!') - { - /* Scan the suffix now. */ - - if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) - goto error; - } - else - { - /* It wasn't a handle after all. Scan the rest of the tag. */ - - if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix)) - goto error; - - /* Set the handle to '!'. */ - - yaml_free(handle); - handle = YAML_MALLOC(2); - if (!handle) goto error; - handle[0] = '!'; - handle[1] = '\0'; - - /* - * A special case: the '!' tag. Set the handle to '' and the - * suffix to '!'. - */ - - if (suffix[0] == '\0') { - yaml_char_t *tmp = handle; - handle = suffix; - suffix = tmp; - } - } - } - - /* Check the character which ends the tag. */ - - if (!CACHE(parser, 1)) goto error; - - if (!IS_BLANKZ(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find expected whitespace or line break"); - goto error; - } - - end_mark = parser->mark; - - /* Create a token. */ - - TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark); - - return 1; - -error: - yaml_free(handle); - yaml_free(suffix); - return 0; -} - -/* - * Scan a tag handle. - */ - -static int -yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, - yaml_mark_t start_mark, yaml_char_t **handle) -{ - yaml_string_t string = NULL_STRING; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - - /* Check the initial '!' character. */ - - if (!CACHE(parser, 1)) goto error; - - if (!CHECK(parser->buffer, '!')) { - yaml_parser_set_scanner_error(parser, directive ? - "while scanning a tag directive" : "while scanning a tag", - start_mark, "did not find expected '!'"); - goto error; - } - - /* Copy the '!' character. */ - - if (!READ(parser, string)) goto error; - - /* Copy all subsequent alphabetical and numerical characters. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_ALPHA(parser->buffer)) - { - if (!READ(parser, string)) goto error; - if (!CACHE(parser, 1)) goto error; - } - - /* Check if the trailing character is '!' and copy it. */ - - if (CHECK(parser->buffer, '!')) - { - if (!READ(parser, string)) goto error; - } - else - { - /* - * It's either the '!' tag or not really a tag handle. If it's a %TAG - * directive, it's an error. If it's a tag token, it must be a part of - * URI. - */ - - if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) { - yaml_parser_set_scanner_error(parser, "while parsing a tag directive", - start_mark, "did not find expected '!'"); - goto error; - } - } - - *handle = string.start; - - return 1; - -error: - STRING_DEL(parser, string); - return 0; -} - -/* - * Scan a tag. - */ - -static int -yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, - yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri) -{ - size_t length = head ? strlen((char *)head) : 0; - yaml_string_t string = NULL_STRING; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - - /* Resize the string to include the head. */ - - while ((size_t)(string.end - string.start) <= length) { - if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) { - parser->error = YAML_MEMORY_ERROR; - goto error; - } - } - - /* - * Copy the head if needed. - * - * Note that we don't copy the leading '!' character. - */ - - if (length > 1) { - memcpy(string.start, head+1, length-1); - string.pointer += length-1; - } - - /* Scan the tag. */ - - if (!CACHE(parser, 1)) goto error; - - /* - * The set of characters that may appear in URI is as follows: - * - * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', - * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', - * '%'. - */ - - while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';') - || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?') - || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@') - || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=') - || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$') - || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.') - || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~') - || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'') - || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')') - || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']') - || CHECK(parser->buffer, '%')) - { - /* Check if it is a URI-escape sequence. */ - - if (CHECK(parser->buffer, '%')) { - if (!STRING_EXTEND(parser, string)) - goto error; - - if (!yaml_parser_scan_uri_escapes(parser, - directive, start_mark, &string)) goto error; - } - else { - if (!READ(parser, string)) goto error; - } - - length ++; - if (!CACHE(parser, 1)) goto error; - } - - /* Check if the tag is non-empty. */ - - if (!length) { - if (!STRING_EXTEND(parser, string)) - goto error; - - yaml_parser_set_scanner_error(parser, directive ? - "while parsing a %TAG directive" : "while parsing a tag", - start_mark, "did not find expected tag URI"); - goto error; - } - - *uri = string.start; - - return 1; - -error: - STRING_DEL(parser, string); - return 0; -} - -/* - * Decode an URI-escape sequence corresponding to a single UTF-8 character. - */ - -static int -yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, - yaml_mark_t start_mark, yaml_string_t *string) -{ - int width = 0; - - /* Decode the required number of characters. */ - - do { - - unsigned char octet = 0; - - /* Check for a URI-escaped octet. */ - - if (!CACHE(parser, 3)) return 0; - - if (!(CHECK(parser->buffer, '%') - && IS_HEX_AT(parser->buffer, 1) - && IS_HEX_AT(parser->buffer, 2))) { - return yaml_parser_set_scanner_error(parser, directive ? - "while parsing a %TAG directive" : "while parsing a tag", - start_mark, "did not find URI escaped octet"); - } - - /* Get the octet. */ - - octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2); - - /* If it is the leading octet, determine the length of the UTF-8 sequence. */ - - if (!width) - { - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - if (!width) { - return yaml_parser_set_scanner_error(parser, directive ? - "while parsing a %TAG directive" : "while parsing a tag", - start_mark, "found an incorrect leading UTF-8 octet"); - } - } - else - { - /* Check if the trailing octet is correct. */ - - if ((octet & 0xC0) != 0x80) { - return yaml_parser_set_scanner_error(parser, directive ? - "while parsing a %TAG directive" : "while parsing a tag", - start_mark, "found an incorrect trailing UTF-8 octet"); - } - } - - /* Copy the octet and move the pointers. */ - - *(string->pointer++) = octet; - SKIP(parser); - SKIP(parser); - SKIP(parser); - - } while (--width); - - return 1; -} - -/* - * Scan a block scalar. - */ - -static int -yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, - int literal) -{ - yaml_mark_t start_mark; - yaml_mark_t end_mark; - yaml_string_t string = NULL_STRING; - yaml_string_t leading_break = NULL_STRING; - yaml_string_t trailing_breaks = NULL_STRING; - int chomping = 0; - int increment = 0; - int indent = 0; - int leading_blank = 0; - int trailing_blank = 0; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; - - /* Eat the indicator '|' or '>'. */ - - start_mark = parser->mark; - - SKIP(parser); - - /* Scan the additional block scalar indicators. */ - - if (!CACHE(parser, 1)) goto error; - - /* Check for a chomping indicator. */ - - if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) - { - /* Set the chomping method and eat the indicator. */ - - chomping = CHECK(parser->buffer, '+') ? +1 : -1; - - SKIP(parser); - - /* Check for an indentation indicator. */ - - if (!CACHE(parser, 1)) goto error; - - if (IS_DIGIT(parser->buffer)) - { - /* Check that the indentation is greater than 0. */ - - if (CHECK(parser->buffer, '0')) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0"); - goto error; - } - - /* Get the indentation level and eat the indicator. */ - - increment = AS_DIGIT(parser->buffer); - - SKIP(parser); - } - } - - /* Do the same as above, but in the opposite order. */ - - else if (IS_DIGIT(parser->buffer)) - { - if (CHECK(parser->buffer, '0')) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0"); - goto error; - } - - increment = AS_DIGIT(parser->buffer); - - SKIP(parser); - - if (!CACHE(parser, 1)) goto error; - - if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) { - chomping = CHECK(parser->buffer, '+') ? +1 : -1; - - SKIP(parser); - } - } - - /* Eat whitespaces and comments to the end of the line. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_BLANK(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - - if (CHECK(parser->buffer, '#')) { - while (!IS_BREAKZ(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) goto error; - } - } - - /* Check if we are at the end of the line. */ - - if (!IS_BREAKZ(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "did not find expected comment or line break"); - goto error; - } - - /* Eat a line break. */ - - if (IS_BREAK(parser->buffer)) { - if (!CACHE(parser, 2)) goto error; - SKIP_LINE(parser); - } - - end_mark = parser->mark; - - /* Set the indentation level if it was specified. */ - - if (increment) { - indent = parser->indent >= 0 ? parser->indent+increment : increment; - } - - /* Scan the leading line breaks and determine the indentation level if needed. */ - - if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, - start_mark, &end_mark)) goto error; - - /* Scan the block scalar content. */ - - if (!CACHE(parser, 1)) goto error; - - while ((int)parser->mark.column == indent && !(IS_Z(parser->buffer))) - { - /* - * We are at the beginning of a non-empty line. - */ - - /* Is it a trailing whitespace? */ - - trailing_blank = IS_BLANK(parser->buffer); - - /* Check if we need to fold the leading line break. */ - - if (!literal && (*leading_break.start == '\n') - && !leading_blank && !trailing_blank) - { - /* Do we need to join the lines by space? */ - - if (*trailing_breaks.start == '\0') { - if (!STRING_EXTEND(parser, string)) goto error; - *(string.pointer ++) = ' '; - } - - CLEAR(parser, leading_break); - } - else { - if (!JOIN(parser, string, leading_break)) goto error; - CLEAR(parser, leading_break); - } - - /* Append the remaining line breaks. */ - - if (!JOIN(parser, string, trailing_breaks)) goto error; - CLEAR(parser, trailing_breaks); - - /* Is it a leading whitespace? */ - - leading_blank = IS_BLANK(parser->buffer); - - /* Consume the current line. */ - - while (!IS_BREAKZ(parser->buffer)) { - if (!READ(parser, string)) goto error; - if (!CACHE(parser, 1)) goto error; - } - - /* Consume the line break. */ - - if (!CACHE(parser, 2)) goto error; - - if (!READ_LINE(parser, leading_break)) goto error; - - /* Eat the following indentation spaces and line breaks. */ - - if (!yaml_parser_scan_block_scalar_breaks(parser, - &indent, &trailing_breaks, start_mark, &end_mark)) goto error; - } - - /* Chomp the tail. */ - - if (chomping != -1) { - if (!JOIN(parser, string, leading_break)) goto error; - } - if (chomping == 1) { - if (!JOIN(parser, string, trailing_breaks)) goto error; - } - - /* Create a token. */ - - SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, - literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE, - start_mark, end_mark); - - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - - return 1; - -error: - STRING_DEL(parser, string); - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - - return 0; -} - -/* - * Scan indentation spaces and line breaks for a block scalar. Determine the - * indentation level if needed. - */ - -static int -yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, - int *indent, yaml_string_t *breaks, - yaml_mark_t start_mark, yaml_mark_t *end_mark) -{ - int max_indent = 0; - - *end_mark = parser->mark; - - /* Eat the indentation spaces and line breaks. */ - - while (1) - { - /* Eat the indentation spaces. */ - - if (!CACHE(parser, 1)) return 0; - - while ((!*indent || (int)parser->mark.column < *indent) - && IS_SPACE(parser->buffer)) { - SKIP(parser); - if (!CACHE(parser, 1)) return 0; - } - - if ((int)parser->mark.column > max_indent) - max_indent = (int)parser->mark.column; - - /* Check for a tab character messing the indentation. */ - - if ((!*indent || (int)parser->mark.column < *indent) - && IS_TAB(parser->buffer)) { - return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found a tab character where an indentation space is expected"); - } - - /* Have we found a non-empty line? */ - - if (!IS_BREAK(parser->buffer)) break; - - /* Consume the line break. */ - - if (!CACHE(parser, 2)) return 0; - if (!READ_LINE(parser, *breaks)) return 0; - *end_mark = parser->mark; - } - - /* Determine the indentation level if needed. */ - - if (!*indent) { - *indent = max_indent; - if (*indent < parser->indent + 1) - *indent = parser->indent + 1; - if (*indent < 1) - *indent = 1; - } - - return 1; -} - -/* - * Scan a quoted scalar. - */ - -static int -yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, - int single) -{ - yaml_mark_t start_mark; - yaml_mark_t end_mark; - yaml_string_t string = NULL_STRING; - yaml_string_t leading_break = NULL_STRING; - yaml_string_t trailing_breaks = NULL_STRING; - yaml_string_t whitespaces = NULL_STRING; - int leading_blanks; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; - - /* Eat the left quote. */ - - start_mark = parser->mark; - - SKIP(parser); - - /* Consume the content of the quoted scalar. */ - - while (1) - { - /* Check that there are no document indicators at the beginning of the line. */ - - if (!CACHE(parser, 4)) goto error; - - if (parser->mark.column == 0 && - ((CHECK_AT(parser->buffer, '-', 0) && - CHECK_AT(parser->buffer, '-', 1) && - CHECK_AT(parser->buffer, '-', 2)) || - (CHECK_AT(parser->buffer, '.', 0) && - CHECK_AT(parser->buffer, '.', 1) && - CHECK_AT(parser->buffer, '.', 2))) && - IS_BLANKZ_AT(parser->buffer, 3)) - { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected document indicator"); - goto error; - } - - /* Check for EOF. */ - - if (IS_Z(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected end of stream"); - goto error; - } - - /* Consume non-blank characters. */ - - if (!CACHE(parser, 2)) goto error; - - leading_blanks = 0; - - while (!IS_BLANKZ(parser->buffer)) - { - /* Check for an escaped single quote. */ - - if (single && CHECK_AT(parser->buffer, '\'', 0) - && CHECK_AT(parser->buffer, '\'', 1)) - { - if (!STRING_EXTEND(parser, string)) goto error; - *(string.pointer++) = '\''; - SKIP(parser); - SKIP(parser); - } - - /* Check for the right quote. */ - - else if (CHECK(parser->buffer, single ? '\'' : '"')) - { - break; - } - - /* Check for an escaped line break. */ - - else if (!single && CHECK(parser->buffer, '\\') - && IS_BREAK_AT(parser->buffer, 1)) - { - if (!CACHE(parser, 3)) goto error; - SKIP(parser); - SKIP_LINE(parser); - leading_blanks = 1; - break; - } - - /* Check for an escape sequence. */ - - else if (!single && CHECK(parser->buffer, '\\')) - { - size_t code_length = 0; - - if (!STRING_EXTEND(parser, string)) goto error; - - /* Check the escape character. */ - - switch (parser->buffer.pointer[1]) - { - case '0': - *(string.pointer++) = '\0'; - break; - - case 'a': - *(string.pointer++) = '\x07'; - break; - - case 'b': - *(string.pointer++) = '\x08'; - break; - - case 't': - case '\t': - *(string.pointer++) = '\x09'; - break; - - case 'n': - *(string.pointer++) = '\x0A'; - break; - - case 'v': - *(string.pointer++) = '\x0B'; - break; - - case 'f': - *(string.pointer++) = '\x0C'; - break; - - case 'r': - *(string.pointer++) = '\x0D'; - break; - - case 'e': - *(string.pointer++) = '\x1B'; - break; - - case ' ': - *(string.pointer++) = '\x20'; - break; - - case '"': - *(string.pointer++) = '"'; - break; - - case '/': - *(string.pointer++) = '/'; - break; - - case '\\': - *(string.pointer++) = '\\'; - break; - - case 'N': /* NEL (#x85) */ - *(string.pointer++) = '\xC2'; - *(string.pointer++) = '\x85'; - break; - - case '_': /* #xA0 */ - *(string.pointer++) = '\xC2'; - *(string.pointer++) = '\xA0'; - break; - - case 'L': /* LS (#x2028) */ - *(string.pointer++) = '\xE2'; - *(string.pointer++) = '\x80'; - *(string.pointer++) = '\xA8'; - break; - - case 'P': /* PS (#x2029) */ - *(string.pointer++) = '\xE2'; - *(string.pointer++) = '\x80'; - *(string.pointer++) = '\xA9'; - break; - - case 'x': - code_length = 2; - break; - - case 'u': - code_length = 4; - break; - - case 'U': - code_length = 8; - break; - - default: - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found unknown escape character"); - goto error; - } - - SKIP(parser); - SKIP(parser); - - /* Consume an arbitrary escape code. */ - - if (code_length) - { - unsigned int value = 0; - size_t k; - - /* Scan the character value. */ - - if (!CACHE(parser, code_length)) goto error; - - for (k = 0; k < code_length; k ++) { - if (!IS_HEX_AT(parser->buffer, k)) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "did not find expected hexdecimal number"); - goto error; - } - value = (value << 4) + AS_HEX_AT(parser->buffer, k); - } - - /* Check the value and write the character. */ - - if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found invalid Unicode character escape code"); - goto error; - } - - if (value <= 0x7F) { - *(string.pointer++) = value; - } - else if (value <= 0x7FF) { - *(string.pointer++) = 0xC0 + (value >> 6); - *(string.pointer++) = 0x80 + (value & 0x3F); - } - else if (value <= 0xFFFF) { - *(string.pointer++) = 0xE0 + (value >> 12); - *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); - *(string.pointer++) = 0x80 + (value & 0x3F); - } - else { - *(string.pointer++) = 0xF0 + (value >> 18); - *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F); - *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); - *(string.pointer++) = 0x80 + (value & 0x3F); - } - - /* Advance the pointer. */ - - for (k = 0; k < code_length; k ++) { - SKIP(parser); - } - } - } - - else - { - /* It is a non-escaped non-blank character. */ - - if (!READ(parser, string)) goto error; - } - - if (!CACHE(parser, 2)) goto error; - } - - /* Check if we are at the end of the scalar. */ - - /* Fix for crash unitialized value crash - * Credit for the bug and input is to OSS Fuzz - * Credit for the fix to Alex Gaynor - */ - if (!CACHE(parser, 1)) goto error; - if (CHECK(parser->buffer, single ? '\'' : '"')) - break; - - /* Consume blank characters. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) - { - if (IS_BLANK(parser->buffer)) - { - /* Consume a space or a tab character. */ - - if (!leading_blanks) { - if (!READ(parser, whitespaces)) goto error; - } - else { - SKIP(parser); - } - } - else - { - if (!CACHE(parser, 2)) goto error; - - /* Check if it is a first line break. */ - - if (!leading_blanks) - { - CLEAR(parser, whitespaces); - if (!READ_LINE(parser, leading_break)) goto error; - leading_blanks = 1; - } - else - { - if (!READ_LINE(parser, trailing_breaks)) goto error; - } - } - if (!CACHE(parser, 1)) goto error; - } - - /* Join the whitespaces or fold line breaks. */ - - if (leading_blanks) - { - /* Do we need to fold line breaks? */ - - if (leading_break.start[0] == '\n') { - if (trailing_breaks.start[0] == '\0') { - if (!STRING_EXTEND(parser, string)) goto error; - *(string.pointer++) = ' '; - } - else { - if (!JOIN(parser, string, trailing_breaks)) goto error; - CLEAR(parser, trailing_breaks); - } - CLEAR(parser, leading_break); - } - else { - if (!JOIN(parser, string, leading_break)) goto error; - if (!JOIN(parser, string, trailing_breaks)) goto error; - CLEAR(parser, leading_break); - CLEAR(parser, trailing_breaks); - } - } - else - { - if (!JOIN(parser, string, whitespaces)) goto error; - CLEAR(parser, whitespaces); - } - } - - /* Eat the right quote. */ - - SKIP(parser); - - end_mark = parser->mark; - - /* Create a token. */ - - SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, - single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE, - start_mark, end_mark); - - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - STRING_DEL(parser, whitespaces); - - return 1; - -error: - STRING_DEL(parser, string); - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - STRING_DEL(parser, whitespaces); - - return 0; -} - -/* - * Scan a plain scalar. - */ - -static int -yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token) -{ - yaml_mark_t start_mark; - yaml_mark_t end_mark; - yaml_string_t string = NULL_STRING; - yaml_string_t leading_break = NULL_STRING; - yaml_string_t trailing_breaks = NULL_STRING; - yaml_string_t whitespaces = NULL_STRING; - int leading_blanks = 0; - int indent = parser->indent+1; - - if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; - if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; - - start_mark = end_mark = parser->mark; - - /* Consume the content of the plain scalar. */ - - while (1) - { - /* Check for a document indicator. */ - - if (!CACHE(parser, 4)) goto error; - - if (parser->mark.column == 0 && - ((CHECK_AT(parser->buffer, '-', 0) && - CHECK_AT(parser->buffer, '-', 1) && - CHECK_AT(parser->buffer, '-', 2)) || - (CHECK_AT(parser->buffer, '.', 0) && - CHECK_AT(parser->buffer, '.', 1) && - CHECK_AT(parser->buffer, '.', 2))) && - IS_BLANKZ_AT(parser->buffer, 3)) break; - - /* Check for a comment. */ - - if (CHECK(parser->buffer, '#')) - break; - - /* Consume non-blank characters. */ - - while (!IS_BLANKZ(parser->buffer)) - { - /* Check for "x:" + one of ',?[]{}' in the flow context. TODO: Fix the test "spec-08-13". - * This is not completely according to the spec - * See http://yaml.org/spec/1.1/#id907281 9.1.3. Plain - */ - - if (parser->flow_level - && CHECK(parser->buffer, ':') - && ( - CHECK_AT(parser->buffer, ',', 1) - || CHECK_AT(parser->buffer, '?', 1) - || CHECK_AT(parser->buffer, '[', 1) - || CHECK_AT(parser->buffer, ']', 1) - || CHECK_AT(parser->buffer, '{', 1) - || CHECK_AT(parser->buffer, '}', 1) - ) - ) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found unexpected ':'"); - goto error; - } - - /* Check for indicators that may end a plain scalar. */ - - if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1)) - || (parser->flow_level && - (CHECK(parser->buffer, ',') - || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[') - || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') - || CHECK(parser->buffer, '}')))) - break; - - /* Check if we need to join whitespaces and breaks. */ - - if (leading_blanks || whitespaces.start != whitespaces.pointer) - { - if (leading_blanks) - { - /* Do we need to fold line breaks? */ - - if (leading_break.start[0] == '\n') { - if (trailing_breaks.start[0] == '\0') { - if (!STRING_EXTEND(parser, string)) goto error; - *(string.pointer++) = ' '; - } - else { - if (!JOIN(parser, string, trailing_breaks)) goto error; - CLEAR(parser, trailing_breaks); - } - CLEAR(parser, leading_break); - } - else { - if (!JOIN(parser, string, leading_break)) goto error; - if (!JOIN(parser, string, trailing_breaks)) goto error; - CLEAR(parser, leading_break); - CLEAR(parser, trailing_breaks); - } - - leading_blanks = 0; - } - else - { - if (!JOIN(parser, string, whitespaces)) goto error; - CLEAR(parser, whitespaces); - } - } - - /* Copy the character. */ - - if (!READ(parser, string)) goto error; - - end_mark = parser->mark; - - if (!CACHE(parser, 2)) goto error; - } - - /* Is it the end? */ - - if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))) - break; - - /* Consume blank characters. */ - - if (!CACHE(parser, 1)) goto error; - - while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) - { - if (IS_BLANK(parser->buffer)) - { - /* Check for tab character that abuse indentation. */ - - if (leading_blanks && (int)parser->mark.column < indent - && IS_TAB(parser->buffer)) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found a tab character that violate indentation"); - goto error; - } - - /* Consume a space or a tab character. */ - - if (!leading_blanks) { - if (!READ(parser, whitespaces)) goto error; - } - else { - SKIP(parser); - } - } - else - { - if (!CACHE(parser, 2)) goto error; - - /* Check if it is a first line break. */ - - if (!leading_blanks) - { - CLEAR(parser, whitespaces); - if (!READ_LINE(parser, leading_break)) goto error; - leading_blanks = 1; - } - else - { - if (!READ_LINE(parser, trailing_breaks)) goto error; - } - } - if (!CACHE(parser, 1)) goto error; - } - - /* Check indentation level. */ - - if (!parser->flow_level && (int)parser->mark.column < indent) - break; - } - - /* Create a token. */ - - SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, - YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark); - - /* Note that we change the 'simple_key_allowed' flag. */ - - if (leading_blanks) { - parser->simple_key_allowed = 1; - } - - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - STRING_DEL(parser, whitespaces); - - return 1; - -error: - STRING_DEL(parser, string); - STRING_DEL(parser, leading_break); - STRING_DEL(parser, trailing_breaks); - STRING_DEL(parser, whitespaces); - - return 0; -} diff --git a/3rdparty/libyaml/src/writer.c b/3rdparty/libyaml/src/writer.c deleted file mode 100644 index 5d57f392..00000000 --- a/3rdparty/libyaml/src/writer.c +++ /dev/null @@ -1,141 +0,0 @@ - -#include "yaml_private.h" - -/* - * Declarations. - */ - -static int -yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); - -YAML_DECLARE(int) -yaml_emitter_flush(yaml_emitter_t *emitter); - -/* - * Set the writer error and return 0. - */ - -static int -yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) -{ - emitter->error = YAML_WRITER_ERROR; - emitter->problem = problem; - - return 0; -} - -/* - * Flush the output buffer. - */ - -YAML_DECLARE(int) -yaml_emitter_flush(yaml_emitter_t *emitter) -{ - int low, high; - - assert(emitter); /* Non-NULL emitter object is expected. */ - assert(emitter->write_handler); /* Write handler must be set. */ - assert(emitter->encoding); /* Output encoding must be set. */ - - emitter->buffer.last = emitter->buffer.pointer; - emitter->buffer.pointer = emitter->buffer.start; - - /* Check if the buffer is empty. */ - - if (emitter->buffer.start == emitter->buffer.last) { - return 1; - } - - /* If the output encoding is UTF-8, we don't need to recode the buffer. */ - - if (emitter->encoding == YAML_UTF8_ENCODING) - { - if (emitter->write_handler(emitter->write_handler_data, - emitter->buffer.start, - emitter->buffer.last - emitter->buffer.start)) { - emitter->buffer.last = emitter->buffer.start; - emitter->buffer.pointer = emitter->buffer.start; - return 1; - } - else { - return yaml_emitter_set_writer_error(emitter, "write error"); - } - } - - /* Recode the buffer into the raw buffer. */ - - low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); - high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); - - while (emitter->buffer.pointer != emitter->buffer.last) - { - unsigned char octet; - unsigned int width; - unsigned int value; - size_t k; - - /* - * See the "reader.c" code for more details on UTF-8 encoding. Note - * that we assume that the buffer contains a valid UTF-8 sequence. - */ - - /* Read the next UTF-8 character. */ - - octet = emitter->buffer.pointer[0]; - - width = (octet & 0x80) == 0x00 ? 1 : - (octet & 0xE0) == 0xC0 ? 2 : - (octet & 0xF0) == 0xE0 ? 3 : - (octet & 0xF8) == 0xF0 ? 4 : 0; - - value = (octet & 0x80) == 0x00 ? octet & 0x7F : - (octet & 0xE0) == 0xC0 ? octet & 0x1F : - (octet & 0xF0) == 0xE0 ? octet & 0x0F : - (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; - - for (k = 1; k < width; k ++) { - octet = emitter->buffer.pointer[k]; - value = (value << 6) + (octet & 0x3F); - } - - emitter->buffer.pointer += width; - - /* Write the character. */ - - if (value < 0x10000) - { - emitter->raw_buffer.last[high] = value >> 8; - emitter->raw_buffer.last[low] = value & 0xFF; - - emitter->raw_buffer.last += 2; - } - else - { - /* Write the character using a surrogate pair (check "reader.c"). */ - - value -= 0x10000; - emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); - emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; - emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); - emitter->raw_buffer.last[low+2] = value & 0xFF; - - emitter->raw_buffer.last += 4; - } - } - - /* Write the raw buffer. */ - - if (emitter->write_handler(emitter->write_handler_data, - emitter->raw_buffer.start, - emitter->raw_buffer.last - emitter->raw_buffer.start)) { - emitter->buffer.last = emitter->buffer.start; - emitter->buffer.pointer = emitter->buffer.start; - emitter->raw_buffer.last = emitter->raw_buffer.start; - emitter->raw_buffer.pointer = emitter->raw_buffer.start; - return 1; - } - else { - return yaml_emitter_set_writer_error(emitter, "write error"); - } -} - diff --git a/3rdparty/libyaml/src/yaml_private.h b/3rdparty/libyaml/src/yaml_private.h deleted file mode 100644 index b3351c41..00000000 --- a/3rdparty/libyaml/src/yaml_private.h +++ /dev/null @@ -1,684 +0,0 @@ -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include - -/* - * Memory management. - */ - -YAML_DECLARE(void *) -yaml_malloc(size_t size); - -YAML_DECLARE(void *) -yaml_realloc(void *ptr, size_t size); - -YAML_DECLARE(void) -yaml_free(void *ptr); - -YAML_DECLARE(yaml_char_t *) -yaml_strdup(const yaml_char_t *); - -/* - * Reader: Ensure that the buffer contains at least `length` characters. - */ - -YAML_DECLARE(int) -yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); - -/* - * Scanner: Ensure that the token stack contains at least one token ready. - */ - -YAML_DECLARE(int) -yaml_parser_fetch_more_tokens(yaml_parser_t *parser); - -/* - * The size of the input raw buffer. - */ - -#define INPUT_RAW_BUFFER_SIZE 16384 - -/* - * The size of the input buffer. - * - * It should be possible to decode the whole raw buffer. - */ - -#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3) - -/* - * The size of the output buffer. - */ - -#define OUTPUT_BUFFER_SIZE 16384 - -/* - * The size of the output raw buffer. - * - * It should be possible to encode the whole output buffer. - */ - -#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2) - -/* - * The maximum size of a YAML input file. - * This used to be PTRDIFF_MAX, but that's not entirely portable - * because stdint.h isn't available on all platforms. - * It is not entirely clear why this isn't the maximum value - * that can fit into the parser->offset field. - */ - -#define MAX_FILE_SIZE (~(size_t)0 / 2) - - -/* - * The size of other stacks and queues. - */ - -#define INITIAL_STACK_SIZE 16 -#define INITIAL_QUEUE_SIZE 16 -#define INITIAL_STRING_SIZE 16 - -/* - * Buffer management. - */ - -#define BUFFER_INIT(context,buffer,size) \ - (((buffer).start = (yaml_char_t *)yaml_malloc(size)) ? \ - ((buffer).last = (buffer).pointer = (buffer).start, \ - (buffer).end = (buffer).start+(size), \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define BUFFER_DEL(context,buffer) \ - (yaml_free((buffer).start), \ - (buffer).start = (buffer).pointer = (buffer).end = 0) - -/* - * String management. - */ - -typedef struct { - yaml_char_t *start; - yaml_char_t *end; - yaml_char_t *pointer; -} yaml_string_t; - -YAML_DECLARE(int) -yaml_string_extend(yaml_char_t **start, - yaml_char_t **pointer, yaml_char_t **end); - -YAML_DECLARE(int) -yaml_string_join( - yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, - yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end); - -#define NULL_STRING { NULL, NULL, NULL } - -#define STRING(string,length) { (string), (string)+(length), (string) } - -#define STRING_ASSIGN(value,string,length) \ - ((value).start = (string), \ - (value).end = (string)+(length), \ - (value).pointer = (string)) - -#define STRING_INIT(context,string,size) \ - (((string).start = YAML_MALLOC(size)) ? \ - ((string).pointer = (string).start, \ - (string).end = (string).start+(size), \ - memset((string).start, 0, (size)), \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define STRING_DEL(context,string) \ - (yaml_free((string).start), \ - (string).start = (string).pointer = (string).end = 0) - -#define STRING_EXTEND(context,string) \ - ((((string).pointer+5 < (string).end) \ - || yaml_string_extend(&(string).start, \ - &(string).pointer, &(string).end)) ? \ - 1 : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define CLEAR(context,string) \ - ((string).pointer = (string).start, \ - memset((string).start, 0, (string).end-(string).start)) - -#define JOIN(context,string_a,string_b) \ - ((yaml_string_join(&(string_a).start, &(string_a).pointer, \ - &(string_a).end, &(string_b).start, \ - &(string_b).pointer, &(string_b).end)) ? \ - ((string_b).pointer = (string_b).start, \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -/* - * String check operations. - */ - -/* - * Check the octet at the specified position. - */ - -#define CHECK_AT(string,octet,offset) \ - ((string).pointer[offset] == (yaml_char_t)(octet)) - -/* - * Check the current octet in the buffer. - */ - -#define CHECK(string,octet) (CHECK_AT((string),(octet),0)) - -/* - * Check if the character at the specified position is an alphabetical - * character, a digit, '_', or '-'. - */ - -#define IS_ALPHA_AT(string,offset) \ - (((string).pointer[offset] >= (yaml_char_t) '0' && \ - (string).pointer[offset] <= (yaml_char_t) '9') || \ - ((string).pointer[offset] >= (yaml_char_t) 'A' && \ - (string).pointer[offset] <= (yaml_char_t) 'Z') || \ - ((string).pointer[offset] >= (yaml_char_t) 'a' && \ - (string).pointer[offset] <= (yaml_char_t) 'z') || \ - (string).pointer[offset] == '_' || \ - (string).pointer[offset] == '-') - -#define IS_ALPHA(string) IS_ALPHA_AT((string),0) - -/* - * Check if the character at the specified position is a digit. - */ - -#define IS_DIGIT_AT(string,offset) \ - (((string).pointer[offset] >= (yaml_char_t) '0' && \ - (string).pointer[offset] <= (yaml_char_t) '9')) - -#define IS_DIGIT(string) IS_DIGIT_AT((string),0) - -/* - * Get the value of a digit. - */ - -#define AS_DIGIT_AT(string,offset) \ - ((string).pointer[offset] - (yaml_char_t) '0') - -#define AS_DIGIT(string) AS_DIGIT_AT((string),0) - -/* - * Check if the character at the specified position is a hex-digit. - */ - -#define IS_HEX_AT(string,offset) \ - (((string).pointer[offset] >= (yaml_char_t) '0' && \ - (string).pointer[offset] <= (yaml_char_t) '9') || \ - ((string).pointer[offset] >= (yaml_char_t) 'A' && \ - (string).pointer[offset] <= (yaml_char_t) 'F') || \ - ((string).pointer[offset] >= (yaml_char_t) 'a' && \ - (string).pointer[offset] <= (yaml_char_t) 'f')) - -#define IS_HEX(string) IS_HEX_AT((string),0) - -/* - * Get the value of a hex-digit. - */ - -#define AS_HEX_AT(string,offset) \ - (((string).pointer[offset] >= (yaml_char_t) 'A' && \ - (string).pointer[offset] <= (yaml_char_t) 'F') ? \ - ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \ - ((string).pointer[offset] >= (yaml_char_t) 'a' && \ - (string).pointer[offset] <= (yaml_char_t) 'f') ? \ - ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \ - ((string).pointer[offset] - (yaml_char_t) '0')) - -#define AS_HEX(string) AS_HEX_AT((string),0) - -/* - * Check if the character is ASCII. - */ - -#define IS_ASCII_AT(string,offset) \ - ((string).pointer[offset] <= (yaml_char_t) '\x7F') - -#define IS_ASCII(string) IS_ASCII_AT((string),0) - -/* - * Check if the character can be printed unescaped. - */ - -#define IS_PRINTABLE_AT(string,offset) \ - (((string).pointer[offset] == 0x0A) /* . == #x0A */ \ - || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \ - && (string).pointer[offset] <= 0x7E) \ - || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \ - && (string).pointer[offset+1] >= 0xA0) \ - || ((string).pointer[offset] > 0xC2 \ - && (string).pointer[offset] < 0xED) \ - || ((string).pointer[offset] == 0xED \ - && (string).pointer[offset+1] < 0xA0) \ - || ((string).pointer[offset] == 0xEE) \ - || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \ - && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \ - && (string).pointer[offset+2] == 0xBF) \ - && !((string).pointer[offset+1] == 0xBF \ - && ((string).pointer[offset+2] == 0xBE \ - || (string).pointer[offset+2] == 0xBF)))) - -#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0) - -/* - * Check if the character at the specified position is NUL. - */ - -#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset)) - -#define IS_Z(string) IS_Z_AT((string),0) - -/* - * Check if the character at the specified position is BOM. - */ - -#define IS_BOM_AT(string,offset) \ - (CHECK_AT((string),'\xEF',(offset)) \ - && CHECK_AT((string),'\xBB',(offset)+1) \ - && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */ - -#define IS_BOM(string) IS_BOM_AT(string,0) - -/* - * Check if the character at the specified position is space. - */ - -#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset)) - -#define IS_SPACE(string) IS_SPACE_AT((string),0) - -/* - * Check if the character at the specified position is tab. - */ - -#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset)) - -#define IS_TAB(string) IS_TAB_AT((string),0) - -/* - * Check if the character at the specified position is blank (space or tab). - */ - -#define IS_BLANK_AT(string,offset) \ - (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset))) - -#define IS_BLANK(string) IS_BLANK_AT((string),0) - -/* - * Check if the character at the specified position is a line break. - */ - -#define IS_BREAK_AT(string,offset) \ - (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \ - || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \ - || (CHECK_AT((string),'\xC2',(offset)) \ - && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \ - || (CHECK_AT((string),'\xE2',(offset)) \ - && CHECK_AT((string),'\x80',(offset)+1) \ - && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \ - || (CHECK_AT((string),'\xE2',(offset)) \ - && CHECK_AT((string),'\x80',(offset)+1) \ - && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */ - -#define IS_BREAK(string) IS_BREAK_AT((string),0) - -#define IS_CRLF_AT(string,offset) \ - (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1)) - -#define IS_CRLF(string) IS_CRLF_AT((string),0) - -/* - * Check if the character is a line break or NUL. - */ - -#define IS_BREAKZ_AT(string,offset) \ - (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset))) - -#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0) - -/* - * Check if the character is a line break, space, or NUL. - */ - -#define IS_SPACEZ_AT(string,offset) \ - (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) - -#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0) - -/* - * Check if the character is a line break, space, tab, or NUL. - */ - -#define IS_BLANKZ_AT(string,offset) \ - (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) - -#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0) - -/* - * Determine the width of the character. - */ - -#define WIDTH_AT(string,offset) \ - (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \ - ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \ - ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \ - ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0) - -#define WIDTH(string) WIDTH_AT((string),0) - -/* - * Move the string pointer to the next character. - */ - -#define MOVE(string) ((string).pointer += WIDTH((string))) - -/* - * Copy a character and move the pointers of both strings. - */ - -#define COPY(string_a,string_b) \ - ((*(string_b).pointer & 0x80) == 0x00 ? \ - (*((string_a).pointer++) = *((string_b).pointer++)) : \ - (*(string_b).pointer & 0xE0) == 0xC0 ? \ - (*((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++)) : \ - (*(string_b).pointer & 0xF0) == 0xE0 ? \ - (*((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++)) : \ - (*(string_b).pointer & 0xF8) == 0xF0 ? \ - (*((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++), \ - *((string_a).pointer++) = *((string_b).pointer++)) : 0) - -/* - * Stack and queue management. - */ - -YAML_DECLARE(int) -yaml_stack_extend(void **start, void **top, void **end); - -YAML_DECLARE(int) -yaml_queue_extend(void **start, void **head, void **tail, void **end); - -#define STACK_INIT(context,stack,type) \ - (((stack).start = (type)yaml_malloc(INITIAL_STACK_SIZE*sizeof(*(stack).start))) ? \ - ((stack).top = (stack).start, \ - (stack).end = (stack).start+INITIAL_STACK_SIZE, \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define STACK_DEL(context,stack) \ - (yaml_free((stack).start), \ - (stack).start = (stack).top = (stack).end = 0) - -#define STACK_EMPTY(context,stack) \ - ((stack).start == (stack).top) - -#define STACK_LIMIT(context,stack,size) \ - ((stack).top - (stack).start < (size) ? \ - 1 : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define PUSH(context,stack,value) \ - (((stack).top != (stack).end \ - || yaml_stack_extend((void **)&(stack).start, \ - (void **)&(stack).top, (void **)&(stack).end)) ? \ - (*((stack).top++) = value, \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define POP(context,stack) \ - (*(--(stack).top)) - -#define QUEUE_INIT(context,queue,size,type) \ - (((queue).start = (type)yaml_malloc((size)*sizeof(*(queue).start))) ? \ - ((queue).head = (queue).tail = (queue).start, \ - (queue).end = (queue).start+(size), \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define QUEUE_DEL(context,queue) \ - (yaml_free((queue).start), \ - (queue).start = (queue).head = (queue).tail = (queue).end = 0) - -#define QUEUE_EMPTY(context,queue) \ - ((queue).head == (queue).tail) - -#define ENQUEUE(context,queue,value) \ - (((queue).tail != (queue).end \ - || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ - (void **)&(queue).tail, (void **)&(queue).end)) ? \ - (*((queue).tail++) = value, \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -#define DEQUEUE(context,queue) \ - (*((queue).head++)) - -#define QUEUE_INSERT(context,queue,index,value) \ - (((queue).tail != (queue).end \ - || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ - (void **)&(queue).tail, (void **)&(queue).end)) ? \ - (memmove((queue).head+(index)+1,(queue).head+(index), \ - ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \ - *((queue).head+(index)) = value, \ - (queue).tail++, \ - 1) : \ - ((context)->error = YAML_MEMORY_ERROR, \ - 0)) - -/* - * Token initializers. - */ - -#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \ - (memset(&(token), 0, sizeof(yaml_token_t)), \ - (token).type = (token_type), \ - (token).start_mark = (token_start_mark), \ - (token).end_mark = (token_end_mark)) - -#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \ - (token).data.stream_start.encoding = (token_encoding)) - -#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark))) - -#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \ - (token).data.alias.value = (token_value)) - -#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \ - (token).data.anchor.value = (token_value)) - -#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \ - (token).data.tag.handle = (token_handle), \ - (token).data.tag.suffix = (token_suffix)) - -#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \ - (token).data.scalar.value = (token_value), \ - (token).data.scalar.length = (token_length), \ - (token).data.scalar.style = (token_style)) - -#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ - (token).data.version_directive.major = (token_major), \ - (token).data.version_directive.minor = (token_minor)) - -#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \ - (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ - (token).data.tag_directive.handle = (token_handle), \ - (token).data.tag_directive.prefix = (token_prefix)) - -/* - * Event initializers. - */ - -#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \ - (memset(&(event), 0, sizeof(yaml_event_t)), \ - (event).type = (event_type), \ - (event).start_mark = (event_start_mark), \ - (event).end_mark = (event_end_mark)) - -#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \ - (event).data.stream_start.encoding = (event_encoding)) - -#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark))) - -#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \ - event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \ - (event).data.document_start.version_directive = (event_version_directive), \ - (event).data.document_start.tag_directives.start = (event_tag_directives_start), \ - (event).data.document_start.tag_directives.end = (event_tag_directives_end), \ - (event).data.document_start.implicit = (event_implicit)) - -#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \ - (event).data.document_end.implicit = (event_implicit)) - -#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \ - (event).data.alias.anchor = (event_anchor)) - -#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \ - event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \ - (event).data.scalar.anchor = (event_anchor), \ - (event).data.scalar.tag = (event_tag), \ - (event).data.scalar.value = (event_value), \ - (event).data.scalar.length = (event_length), \ - (event).data.scalar.plain_implicit = (event_plain_implicit), \ - (event).data.scalar.quoted_implicit = (event_quoted_implicit), \ - (event).data.scalar.style = (event_style)) - -#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \ - event_implicit,event_style,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \ - (event).data.sequence_start.anchor = (event_anchor), \ - (event).data.sequence_start.tag = (event_tag), \ - (event).data.sequence_start.implicit = (event_implicit), \ - (event).data.sequence_start.style = (event_style)) - -#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark))) - -#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \ - event_implicit,event_style,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \ - (event).data.mapping_start.anchor = (event_anchor), \ - (event).data.mapping_start.tag = (event_tag), \ - (event).data.mapping_start.implicit = (event_implicit), \ - (event).data.mapping_start.style = (event_style)) - -#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \ - (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark))) - -/* - * Document initializer. - */ - -#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ - document_version_directive,document_tag_directives_start, \ - document_tag_directives_end,document_start_implicit, \ - document_end_implicit,document_start_mark,document_end_mark) \ - (memset(&(document), 0, sizeof(yaml_document_t)), \ - (document).nodes.start = (document_nodes_start), \ - (document).nodes.end = (document_nodes_end), \ - (document).nodes.top = (document_nodes_start), \ - (document).version_directive = (document_version_directive), \ - (document).tag_directives.start = (document_tag_directives_start), \ - (document).tag_directives.end = (document_tag_directives_end), \ - (document).start_implicit = (document_start_implicit), \ - (document).end_implicit = (document_end_implicit), \ - (document).start_mark = (document_start_mark), \ - (document).end_mark = (document_end_mark)) - -/* - * Node initializers. - */ - -#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ - (memset(&(node), 0, sizeof(yaml_node_t)), \ - (node).type = (node_type), \ - (node).tag = (node_tag), \ - (node).start_mark = (node_start_mark), \ - (node).end_mark = (node_end_mark)) - -#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.scalar.value = (node_value), \ - (node).data.scalar.length = (node_length), \ - (node).data.scalar.style = (node_style)) - -#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.sequence.items.start = (node_items_start), \ - (node).data.sequence.items.end = (node_items_end), \ - (node).data.sequence.items.top = (node_items_start), \ - (node).data.sequence.style = (node_style)) - -#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ - node_style,start_mark,end_mark) \ - (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ - (node).data.mapping.pairs.start = (node_pairs_start), \ - (node).data.mapping.pairs.end = (node_pairs_end), \ - (node).data.mapping.pairs.top = (node_pairs_start), \ - (node).data.mapping.style = (node_style)) - -/* Strict C compiler warning helpers */ - -#if defined(__clang__) || defined(__GNUC__) -# define HASATTRIBUTE_UNUSED -#endif -#ifdef HASATTRIBUTE_UNUSED -# define __attribute__unused__ __attribute__((__unused__)) -#else -# define __attribute__unused__ -#endif - -/* Shim arguments are arguments that must be included in your function, - * but serve no purpose inside. Silence compiler warnings. */ -#define SHIM(a) /*@unused@*/ a __attribute__unused__ - -/* UNUSED_PARAM() marks a shim argument in the body to silence compiler warnings */ -#ifdef __clang__ -# define UNUSED_PARAM(a) (void)(a); -#else -# define UNUSED_PARAM(a) /*@-noeffect*/if (0) (void)(a)/*@=noeffect*/; -#endif - -#define YAML_MALLOC_STATIC(type) (type*)yaml_malloc(sizeof(type)) -#define YAML_MALLOC(size) (yaml_char_t *)yaml_malloc(size) diff --git a/3rdparty/libyaml/win32/config.h b/3rdparty/libyaml/win32/config.h deleted file mode 100644 index 405d3e75..00000000 --- a/3rdparty/libyaml/win32/config.h +++ /dev/null @@ -1,4 +0,0 @@ -#define YAML_VERSION_MAJOR 0 -#define YAML_VERSION_MINOR 2 -#define YAML_VERSION_PATCH 1 -#define YAML_VERSION_STRING "0.2.1" diff --git a/3rdparty/libz.pri b/3rdparty/libz.pri deleted file mode 100644 index 682bf410..00000000 --- a/3rdparty/libz.pri +++ /dev/null @@ -1,8 +0,0 @@ -# zlib dependency satisfied by bundled 3rd party zlib or system zlib -CONFIG *= qt - -qtConfig(system-zlib) { - QMAKE_USE_PRIVATE *= zlib -} else { - QT_PRIVATE *= core zlib-private -} diff --git a/3rdparty/stackwalker.pri b/3rdparty/stackwalker.pri deleted file mode 100644 index c77951b2..00000000 --- a/3rdparty/stackwalker.pri +++ /dev/null @@ -1,2 +0,0 @@ - -QMAKE_USE_PRIVATE += stackwalker diff --git a/3rdparty/stackwalker/LICENSE b/3rdparty/stackwalker/LICENSE deleted file mode 100644 index 43fd8dba..00000000 --- a/3rdparty/stackwalker/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -BSD-2-Clause - -Copyright (c) 2005 - 2019, Jochen Kalmbach -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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. diff --git a/3rdparty/stackwalker/qt_attribution.json b/3rdparty/stackwalker/qt_attribution.json deleted file mode 100644 index 8a4adba4..00000000 --- a/3rdparty/stackwalker/qt_attribution.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Id": "stackwalker", - "Name": "StackWalker", - "QDocModule": "applicationmanager", - "QtUsage": "Automatically used in Qt ApplicationManager, if available. Configure with -config disable-stackwalker to avoid.", - - "Description": "Walking the callstack in windows applications.", - "Homepage": "https://github.com/JochenKalmbach/StackWalker", - "Version": "2020-02-06", - - "License": "BSD 2-clause \"Simplified\" License", - "LicenseId": "BSD-2-Clause", - "LicenseFile": "LICENSE", - "Copyright": "Copyright (C) 2005-2019 Jochen Kalmbach" -} diff --git a/3rdparty/stackwalker/stackwalker.cpp b/3rdparty/stackwalker/stackwalker.cpp deleted file mode 100644 index 7008ac67..00000000 --- a/3rdparty/stackwalker/stackwalker.cpp +++ /dev/null @@ -1,1469 +0,0 @@ -/********************************************************************** - * - * StackWalker.cpp - * https://github.com/JochenKalmbach/StackWalker - * - * Old location: http://stackwalker.codeplex.com/ - * - * - * History: - * 2005-07-27 v1 - First public release on http://www.codeproject.com/ - * http://www.codeproject.com/threads/StackWalker.asp - * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack - * (to simplify the usage) - * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL - * (should also be enough) - * - Changed to compile correctly with the PSDK of VC7.0 - * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: - * it uses LPSTR instead of LPCSTR as first parameter) - * - Added declarations to support VC5/6 without using 'dbghelp.h' - * - Added a 'pUserData' member to the ShowCallstack function and the - * PReadProcessMemoryRoutine declaration (to pass some user-defined data, - * which can be used in the readMemoryFunction-callback) - * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default - * - Added example for doing an exception-callstack-walking in main.cpp - * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) - * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! - * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx - * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx - * Fixed Bug: Compiling with "/Wall" - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx - * Fixed Bug: Now checking SymUseSymSrv - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx - * Fixed Bug: Support for recursive function calls - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx - * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx - * Fixed Bug: SymDia is number 7, not 9! - * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! - * Thanks to Teajay which reported the bug... - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx - * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory - * Thanks to Luiz Salamon which reported this "bug"... - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx - * 2009-04-10 v9 License slightly corrected ( replaced) - * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ - * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available - * 2010-04-15 v12 Added support for VS2010 RTM - * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx - * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed: - * http://stackwalker.codeplex.com/workitem/10511 - * - * - * LICENSE (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2005-2013, Jochen Kalmbach - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 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. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - **********************************************************************/ - -#include "StackWalker.h" - -#include -#include -#include -#include -#pragma comment(lib, "version.lib") // for "VerQueryValue" -#pragma warning(disable : 4826) - - -// If VC7 and later, then use the shipped 'dbghelp.h'-file -#pragma pack(push, 8) -#if _MSC_VER >= 1300 -#include -#else -// inline the important dbghelp.h-declarations... -typedef enum -{ - SymNone = 0, - SymCoff, - SymCv, - SymPdb, - SymExport, - SymDeferred, - SymSym, - SymDia, - SymVirtual, - NumSymTypes -} SYM_TYPE; -typedef struct _IMAGEHLP_LINE64 -{ - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - PVOID Key; // internal - DWORD LineNumber; // line number in file - PCHAR FileName; // full filename - DWORD64 Address; // first instruction of line -} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; -typedef struct _IMAGEHLP_MODULE64 -{ - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name -} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; -typedef struct _IMAGEHLP_SYMBOL64 -{ - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) - DWORD64 Address; // virtual address including dll base address - DWORD Size; // estimated size of symbol, can be zero - DWORD Flags; // info about the symbols, see the SYMF defines - DWORD MaxNameLength; // maximum size of symbol name in 'Name' - CHAR Name[1]; // symbol name (null terminated string) -} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; -typedef enum -{ - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat -} ADDRESS_MODE; -typedef struct _tagADDRESS64 -{ - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; -} ADDRESS64, *LPADDRESS64; -typedef struct _KDHELP64 -{ - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 Reserved[8]; -} KDHELP64, *PKDHELP64; -typedef struct _tagSTACKFRAME64 -{ - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - PVOID FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; -} STACKFRAME64, *LPSTACKFRAME64; -typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead); -typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess, DWORD64 AddrBase); -typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); -typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, - HANDLE hThread, - LPADDRESS64 lpaddr); - -// clang-format off -#define SYMOPT_CASE_INSENSITIVE 0x00000001 -#define SYMOPT_UNDNAME 0x00000002 -#define SYMOPT_DEFERRED_LOADS 0x00000004 -#define SYMOPT_NO_CPP 0x00000008 -#define SYMOPT_LOAD_LINES 0x00000010 -#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 -#define SYMOPT_LOAD_ANYTHING 0x00000040 -#define SYMOPT_IGNORE_CVREC 0x00000080 -#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 -#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 -#define SYMOPT_EXACT_SYMBOLS 0x00000400 -#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 -#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 -#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 -#define SYMOPT_PUBLICS_ONLY 0x00004000 -#define SYMOPT_NO_PUBLICS 0x00008000 -#define SYMOPT_AUTO_PUBLICS 0x00010000 -#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 -#define SYMOPT_SECURE 0x00040000 -#define SYMOPT_DEBUG 0x80000000 -#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration -#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; -// clang-format on - -#endif // _MSC_VER < 1300 -#pragma pack(pop) - -// Some missing defines (for VC5/6): -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - -// secure-CRT_functions are only available starting with VC8 -#if _MSC_VER < 1400 -#define strcpy_s(dst, len, src) strcpy(dst, src) -#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src) -#define strcat_s(dst, len, src) strcat(dst, src) -#define _snprintf_s _snprintf -#define _tcscat_s _tcscat -#endif - -static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) -{ - if (nMaxDestSize <= 0) - return; - strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE); - // INFO: _TRUNCATE will ensure that it is null-terminated; - // but with older compilers (<1400) it uses "strncpy" and this does not!) - szDest[nMaxDestSize - 1] = 0; -} // MyStrCpy - -// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') -#define USED_CONTEXT_FLAGS CONTEXT_FULL - -class StackWalkerInternal -{ -public: - StackWalkerInternal(StackWalker* parent, HANDLE hProcess) - { - m_parent = parent; - m_hDbhHelp = NULL; - pSC = NULL; - m_hProcess = hProcess; - m_szSymPath = NULL; - pSFTA = NULL; - pSGLFA = NULL; - pSGMB = NULL; - pSGMI = NULL; - pSGO = NULL; - pSGSFA = NULL; - pSI = NULL; - pSLM = NULL; - pSSO = NULL; - pSW = NULL; - pUDSN = NULL; - pSGSP = NULL; - } - ~StackWalkerInternal() - { - if (pSC != NULL) - pSC(m_hProcess); // SymCleanup - if (m_hDbhHelp != NULL) - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - m_parent = NULL; - if (m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - } - BOOL Init(LPCSTR szSymPath) - { - if (m_parent == NULL) - return FALSE; - // Dynamically load the Entry-Points for dbghelp.dll: - // First try to load the newest one from - TCHAR szTemp[4096]; - // But before we do this, we first check if the ".local" file exists - if (GetModuleFileName(NULL, szTemp, 4096) > 0) - { - _tcscat_s(szTemp, _T(".local")); - if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) - { - // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" - // Ok, first try the new path according to the architecture: -#ifdef _M_IX86 - if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#elif _M_X64 - if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#elif _M_IA64 - if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#endif - // If still not found, try the old directories... - if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#if defined _M_X64 || defined _M_IA64 - // Still not found? Then try to load the (old) 64-Bit version: - if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#endif - } - } - if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one - m_hDbhHelp = LoadLibrary(_T("dbghelp.dll")); - if (m_hDbhHelp == NULL) - return FALSE; - pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize"); - pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup"); - - pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64"); - pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions"); - pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions"); - - pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64"); - pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64"); - pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64"); - pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64"); - pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64"); - pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName"); - pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64"); - pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath"); - - if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL || - pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL || - pSLM == NULL) - { - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - pSC = NULL; - return FALSE; - } - - // SymInitialize - if (szSymPath != NULL) - m_szSymPath = _strdup(szSymPath); - if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) - this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); - - DWORD symOptions = this->pSGO(); // SymGetOptions - symOptions |= SYMOPT_LOAD_LINES; - symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; - //symOptions |= SYMOPT_NO_PROMPTS; - // SymSetOptions - symOptions = this->pSSO(symOptions); - - char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; - if (this->pSGSP != NULL) - { - if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) - this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); - } - char szUserName[1024] = {0}; - DWORD dwSize = 1024; - GetUserNameA(szUserName, &dwSize); - this->m_parent->OnSymInit(buf, symOptions, szUserName); - - return TRUE; - } - - StackWalker* m_parent; - - HMODULE m_hDbhHelp; - HANDLE m_hProcess; - LPSTR m_szSymPath; - -#pragma pack(push, 8) - typedef struct IMAGEHLP_MODULE64_V3 - { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name - // new elements: 07-Jun-2002 - CHAR LoadedPdbName[256]; // pdb file name - DWORD CVSig; // Signature of the CV record in the debug directories - CHAR CVData[MAX_PATH * 3]; // Contents of the CV record - DWORD PdbSig; // Signature of PDB - GUID PdbSig70; // Signature of PDB (VC 7 and up) - DWORD PdbAge; // DBI age of pdb - BOOL PdbUnmatched; // loaded an unmatched pdb - BOOL DbgUnmatched; // loaded an unmatched dbg - BOOL LineNumbers; // we have line number information - BOOL GlobalSymbols; // we have internal symbol information - BOOL TypeInfo; // we have type information - // new elements: 17-Dec-2003 - BOOL SourceIndexed; // pdb supports source server - BOOL Publics; // contains public symbols - }; - - typedef struct IMAGEHLP_MODULE64_V2 - { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name - }; -#pragma pack(pop) - - // SymCleanup() - typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess); - tSC pSC; - - // SymFunctionTableAccess64() - typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase); - tSFTA pSFTA; - - // SymGetLineFromAddr64() - typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess, - IN DWORD64 dwAddr, - OUT PDWORD pdwDisplacement, - OUT PIMAGEHLP_LINE64 Line); - tSGLFA pSGLFA; - - // SymGetModuleBase64() - typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr); - tSGMB pSGMB; - - // SymGetModuleInfo64() - typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess, - IN DWORD64 dwAddr, - OUT IMAGEHLP_MODULE64_V3* ModuleInfo); - tSGMI pSGMI; - - // SymGetOptions() - typedef DWORD(__stdcall* tSGO)(VOID); - tSGO pSGO; - - // SymGetSymFromAddr64() - typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess, - IN DWORD64 dwAddr, - OUT PDWORD64 pdwDisplacement, - OUT PIMAGEHLP_SYMBOL64 Symbol); - tSGSFA pSGSFA; - - // SymInitialize() - typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess); - tSI pSI; - - // SymLoadModule64() - typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess, - IN HANDLE hFile, - IN PSTR ImageName, - IN PSTR ModuleName, - IN DWORD64 BaseOfDll, - IN DWORD SizeOfDll); - tSLM pSLM; - - // SymSetOptions() - typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions); - tSSO pSSO; - - // StackWalk64() - typedef BOOL(__stdcall* tSW)(DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); - tSW pSW; - - // UnDecorateSymbolName() - typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName, - PSTR UnDecoratedName, - DWORD UndecoratedLength, - DWORD Flags); - tUDSN pUDSN; - - typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); - tSGSP pSGSP; - -private: -// **************************************** ToolHelp32 ************************ -#define MAX_MODULE_NAME32 255 -#define TH32CS_SNAPMODULE 0x00000008 -#pragma pack(push, 8) - typedef struct tagMODULEENTRY32 - { - DWORD dwSize; - DWORD th32ModuleID; // This module - DWORD th32ProcessID; // owning process - DWORD GlblcntUsage; // Global usage count on the module - DWORD ProccntUsage; // Module usage count in th32ProcessID's context - BYTE* modBaseAddr; // Base address of module in th32ProcessID's context - DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr - HMODULE hModule; // The hModule of this module in th32ProcessID's context - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; - } MODULEENTRY32; - typedef MODULEENTRY32* PMODULEENTRY32; - typedef MODULEENTRY32* LPMODULEENTRY32; -#pragma pack(pop) - - BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) - { - // CreateToolhelp32Snapshot() - typedef HANDLE(__stdcall * tCT32S)(DWORD dwFlags, DWORD th32ProcessID); - // Module32First() - typedef BOOL(__stdcall * tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - // Module32Next() - typedef BOOL(__stdcall * tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - - // try both dlls... - const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")}; - HINSTANCE hToolhelp = NULL; - tCT32S pCT32S = NULL; - tM32F pM32F = NULL; - tM32N pM32N = NULL; - - HANDLE hSnap; - MODULEENTRY32 me; - me.dwSize = sizeof(me); - BOOL keepGoing; - size_t i; - - for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++) - { - hToolhelp = LoadLibrary(dllname[i]); - if (hToolhelp == NULL) - continue; - pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); - pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First"); - pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next"); - if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL)) - break; // found the functions! - FreeLibrary(hToolhelp); - hToolhelp = NULL; - } - - if (hToolhelp == NULL) - return FALSE; - - hSnap = pCT32S(TH32CS_SNAPMODULE, pid); - if (hSnap == (HANDLE)-1) - { - FreeLibrary(hToolhelp); - return FALSE; - } - - keepGoing = !!pM32F(hSnap, &me); - int cnt = 0; - while (keepGoing) - { - this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr, - me.modBaseSize); - cnt++; - keepGoing = !!pM32N(hSnap, &me); - } - CloseHandle(hSnap); - FreeLibrary(hToolhelp); - if (cnt <= 0) - return FALSE; - return TRUE; - } // GetModuleListTH32 - - // **************************************** PSAPI ************************ - typedef struct _MODULEINFO - { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; - } MODULEINFO, *LPMODULEINFO; - - BOOL GetModuleListPSAPI(HANDLE hProcess) - { - // EnumProcessModules() - typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, - LPDWORD lpcbNeeded); - // GetModuleFileNameEx() - typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, - DWORD nSize); - // GetModuleBaseName() - typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, - DWORD nSize); - // GetModuleInformation() - typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize); - - HINSTANCE hPsapi; - tEPM pEPM; - tGMFNE pGMFNE; - tGMBN pGMBN; - tGMI pGMI; - - DWORD i; - //ModuleEntry e; - DWORD cbNeeded; - MODULEINFO mi; - HMODULE* hMods = 0; - char* tt = NULL; - char* tt2 = NULL; - const SIZE_T TTBUFLEN = 8096; - int cnt = 0; - - hPsapi = LoadLibrary(_T("psapi.dll")); - if (hPsapi == NULL) - return FALSE; - - pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules"); - pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA"); - pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA"); - pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation"); - if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL)) - { - // we couldn't find all functions - FreeLibrary(hPsapi); - return FALSE; - } - - hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE))); - tt = (char*)malloc(sizeof(char) * TTBUFLEN); - tt2 = (char*)malloc(sizeof(char) * TTBUFLEN); - if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL)) - goto cleanup; - - if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded)) - { - //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); - goto cleanup; - } - - if (cbNeeded > TTBUFLEN) - { - //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); - goto cleanup; - } - - for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++) - { - // base address, size - pGMI(hProcess, hMods[i], &mi, sizeof(mi)); - // image file name - tt[0] = 0; - pGMFNE(hProcess, hMods[i], tt, TTBUFLEN); - // module name - tt2[0] = 0; - pGMBN(hProcess, hMods[i], tt2, TTBUFLEN); - - DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage); - if (dwRes != ERROR_SUCCESS) - this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); - cnt++; - } - - cleanup: - if (hPsapi != NULL) - FreeLibrary(hPsapi); - if (tt2 != NULL) - free(tt2); - if (tt != NULL) - free(tt); - if (hMods != NULL) - free(hMods); - - return cnt != 0; - } // GetModuleListPSAPI - - DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) - { - CHAR* szImg = _strdup(img); - CHAR* szMod = _strdup(mod); - DWORD result = ERROR_SUCCESS; - if ((szImg == NULL) || (szMod == NULL)) - result = ERROR_NOT_ENOUGH_MEMORY; - else - { - if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) - result = GetLastError(); - } - ULONGLONG fileVersion = 0; - if ((m_parent != NULL) && (szImg != NULL)) - { - // try to retrieve the file-version: - if ((this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) - { - VS_FIXEDFILEINFO* fInfo = NULL; - DWORD dwHandle; - DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); - if (dwSize > 0) - { - LPVOID vData = malloc(dwSize); - if (vData != NULL) - { - if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) - { - UINT len; - TCHAR szSubBlock[] = _T("\\"); - if (VerQueryValue(vData, szSubBlock, (LPVOID*)&fInfo, &len) == 0) - fInfo = NULL; - else - { - fileVersion = - ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); - } - } - free(vData); - } - } - } - - // Retrieve some additional-infos about the module - IMAGEHLP_MODULE64_V3 Module; - const char* szSymType = "-unknown-"; - if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) - { - switch (Module.SymType) - { - case SymNone: - szSymType = "-nosymbols-"; - break; - case SymCoff: // 1 - szSymType = "COFF"; - break; - case SymCv: // 2 - szSymType = "CV"; - break; - case SymPdb: // 3 - szSymType = "PDB"; - break; - case SymExport: // 4 - szSymType = "-exported-"; - break; - case SymDeferred: // 5 - szSymType = "-deferred-"; - break; - case SymSym: // 6 - szSymType = "SYM"; - break; - case 7: // SymDia: - szSymType = "DIA"; - break; - case 8: //SymVirtual: - szSymType = "Virtual"; - break; - } - } - LPCSTR pdbName = Module.LoadedImageName; - if (Module.LoadedPdbName[0] != 0) - pdbName = Module.LoadedPdbName; - this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, - fileVersion); - } - if (szImg != NULL) - free(szImg); - if (szMod != NULL) - free(szMod); - return result; - } - -public: - BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) - { - // first try toolhelp32 - if (GetModuleListTH32(hProcess, dwProcessId)) - return true; - // then try psapi - return GetModuleListPSAPI(hProcess); - } - - BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo) - { - memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); - if (this->pSGMI == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - // First try to use the larger ModuleInfo-Structure - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); - void* pData = malloc( - 4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... - if (pData == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); - static bool s_useV3Version = true; - if (s_useV3Version) - { - if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE) - { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); - free(pData); - return TRUE; - } - s_useV3Version = false; // to prevent unnecessary calls with the larger struct... - } - - // could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)... - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); - if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE) - { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - free(pData); - return TRUE; - } - free(pData); - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } -}; - -// ############################################################# -StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) -{ - this->m_options = OptionsAll; - this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - this->m_szSymPath = NULL; - this->m_MaxRecursionCount = 1000; -} -StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) -{ - this->m_options = options; - this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - if (szSymPath != NULL) - { - this->m_szSymPath = _strdup(szSymPath); - this->m_options |= SymBuildPath; - } - else - this->m_szSymPath = NULL; - this->m_MaxRecursionCount = 1000; -} - -StackWalker::~StackWalker() -{ - if (m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - if (this->m_sw != NULL) - delete this->m_sw; - this->m_sw = NULL; -} - -BOOL StackWalker::LoadModules() -{ - if (this->m_sw == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - if (m_modulesLoaded != FALSE) - return TRUE; - - // Build the sym-path: - char* szSymPath = NULL; - if ((this->m_options & SymBuildPath) != 0) - { - const size_t nSymPathLen = 4096; - szSymPath = (char*)malloc(nSymPathLen); - if (szSymPath == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - szSymPath[0] = 0; - // Now first add the (optional) provided sympath: - if (this->m_szSymPath != NULL) - { - strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - strcat_s(szSymPath, nSymPathLen, ".;"); - - const size_t nTempLen = 1024; - char szTemp[nTempLen]; - // Now add the current directory: - if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - // Now add the path for the main-module: - if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p) - { - // locate the rightmost path separator - if ((*p == '\\') || (*p == '/') || (*p == ':')) - { - *p = 0; - break; - } - } // for (search for path separator...) - if (strlen(szTemp) > 0) - { - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - } - if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - // also add the "system32"-directory: - strcat_s(szTemp, nTempLen, "\\system32"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - if ((this->m_options & SymUseSymSrv) != 0) - { - if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(szSymPath, nSymPathLen, "SRV*"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, "\\websymbols"); - strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); - } - else - strcat_s(szSymPath, nSymPathLen, - "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); - } - } // if SymBuildPath - - // First Init the whole stuff... - BOOL bRet = this->m_sw->Init(szSymPath); - if (szSymPath != NULL) - free(szSymPath); - szSymPath = NULL; - if (bRet == FALSE) - { - this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); - if (bRet != FALSE) - m_modulesLoaded = TRUE; - return bRet; -} - -// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction -// This has to be done due to a problem with the "hProcess"-parameter in x64... -// Because this class is in no case multi-threading-enabled (because of the limitations -// of dbghelp.dll) it is "safe" to use a static-variable -static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; -static LPVOID s_readMemoryFunction_UserData = NULL; - -BOOL StackWalker::ShowCallstack(HANDLE hThread, - const CONTEXT* context, - PReadProcessMemoryRoutine readMemoryFunction, - LPVOID pUserData) -{ - CONTEXT c; - CallstackEntry csEntry; - IMAGEHLP_SYMBOL64* pSym = NULL; - StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; - IMAGEHLP_LINE64 Line; - int frameNum; - bool bLastEntryCalled = true; - int curRecursionCount = 0; - - if (m_modulesLoaded == FALSE) - this->LoadModules(); // ignore the result... - - if (this->m_sw->m_hDbhHelp == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - s_readMemoryFunction = readMemoryFunction; - s_readMemoryFunction_UserData = pUserData; - - if (context == NULL) - { - // If no context is provided, capture the context - // See: https://stackwalker.codeplex.com/discussions/446958 -#if _WIN32_WINNT <= 0x0501 - // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available! - if (hThread == GetCurrentThread()) -#else - if (GetThreadId(hThread) == GetCurrentThreadId()) -#endif - { - GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); - } - else - { - SuspendThread(hThread); - memset(&c, 0, sizeof(CONTEXT)); - c.ContextFlags = USED_CONTEXT_FLAGS; - - // TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture... - // This does only work if we are x64 and the target process is x64 or x86; - // It cannot work, if this process is x64 and the target process is x64... this is not supported... - // See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html - if (GetThreadContext(hThread, &c) == FALSE) - { - ResumeThread(hThread); - return FALSE; - } - } - } - else - c = *context; - - // init STACKFRAME for first call - STACKFRAME64 s; // in/out stackframe - memset(&s, 0, sizeof(s)); - DWORD imageType; -#ifdef _M_IX86 - // normally, call ImageNtHeader() and use machine info from PE header - imageType = IMAGE_FILE_MACHINE_I386; - s.AddrPC.Offset = c.Eip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Ebp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Esp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_X64 - imageType = IMAGE_FILE_MACHINE_AMD64; - s.AddrPC.Offset = c.Rip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Rsp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Rsp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_IA64 - imageType = IMAGE_FILE_MACHINE_IA64; - s.AddrPC.Offset = c.StIIP; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.IntSp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrBStore.Offset = c.RsBSP; - s.AddrBStore.Mode = AddrModeFlat; - s.AddrStack.Offset = c.IntSp; - s.AddrStack.Mode = AddrModeFlat; -#else -#error "Platform not supported!" -#endif - - pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - if (!pSym) - goto cleanup; // not enough memory... - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; - - memset(&Line, 0, sizeof(Line)); - Line.SizeOfStruct = sizeof(Line); - - memset(&Module, 0, sizeof(Module)); - Module.SizeOfStruct = sizeof(Module); - - for (frameNum = 0;; ++frameNum) - { - // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) - // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can - // assume that either you are done, or that the stack is so hosed that the next - // deeper frame could not be found. - // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386! - if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, - this->m_sw->pSFTA, this->m_sw->pSGMB, NULL)) - { - // INFO: "StackWalk64" does not set "GetLastError"... - this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); - break; - } - - csEntry.offset = s.AddrPC.Offset; - csEntry.name[0] = 0; - csEntry.undName[0] = 0; - csEntry.undFullName[0] = 0; - csEntry.offsetFromSmybol = 0; - csEntry.offsetFromLine = 0; - csEntry.lineFileName[0] = 0; - csEntry.lineNumber = 0; - csEntry.loadedImageName[0] = 0; - csEntry.moduleName[0] = 0; - if (s.AddrPC.Offset == s.AddrReturn.Offset) - { - if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount)) - { - this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); - break; - } - curRecursionCount++; - } - else - curRecursionCount = 0; - if (s.AddrPC.Offset != 0) - { - // we seem to have a valid PC - // show procedure info (SymGetSymFromAddr64()) - if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), - pSym) != FALSE) - { - MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); - // UnDecorateSymbolName() - this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY); - this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE); - } - else - { - this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); - } - - // show line number info, NT5.0-method (SymGetLineFromAddr64()) - if (this->m_sw->pSGLFA != NULL) - { // yes, we have SymGetLineFromAddr64() - if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), - &Line) != FALSE) - { - csEntry.lineNumber = Line.LineNumber; - MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); - } - else - { - this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); - } - } // yes, we have SymGetLineFromAddr64() - - // show module info (SymGetModuleInfo64()) - if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module) != FALSE) - { // got module info OK - switch (Module.SymType) - { - case SymNone: - csEntry.symTypeString = "-nosymbols-"; - break; - case SymCoff: - csEntry.symTypeString = "COFF"; - break; - case SymCv: - csEntry.symTypeString = "CV"; - break; - case SymPdb: - csEntry.symTypeString = "PDB"; - break; - case SymExport: - csEntry.symTypeString = "-exported-"; - break; - case SymDeferred: - csEntry.symTypeString = "-deferred-"; - break; - case SymSym: - csEntry.symTypeString = "SYM"; - break; -#if API_VERSION_NUMBER >= 9 - case SymDia: - csEntry.symTypeString = "DIA"; - break; -#endif - case 8: //SymVirtual: - csEntry.symTypeString = "Virtual"; - break; - default: - //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType ); - csEntry.symTypeString = NULL; - break; - } - - MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); - csEntry.baseOfImage = Module.BaseOfImage; - MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); - } // got module info OK - else - { - this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); - } - } // we seem to have a valid PC - - CallstackEntryType et = nextEntry; - if (frameNum == 0) - et = firstEntry; - bLastEntryCalled = false; - this->OnCallstackEntry(et, csEntry); - - if (s.AddrReturn.Offset == 0) - { - bLastEntryCalled = true; - this->OnCallstackEntry(lastEntry, csEntry); - SetLastError(ERROR_SUCCESS); - break; - } - } // for ( frameNum ) - -cleanup: - if (pSym) - free(pSym); - - if (bLastEntryCalled == false) - this->OnCallstackEntry(lastEntry, csEntry); - - if (context == NULL) - ResumeThread(hThread); - - return TRUE; -} - -BOOL StackWalker::ShowObject(LPVOID pObject) -{ - // Load modules if not done yet - if (m_modulesLoaded == FALSE) - this->LoadModules(); // ignore the result... - - // Verify that the DebugHelp.dll was actually found - if (this->m_sw->m_hDbhHelp == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - // SymGetSymFromAddr64() is required - if (this->m_sw->pSGSFA == NULL) - return FALSE; - - // Show object info (SymGetSymFromAddr64()) - DWORD64 dwAddress = DWORD64(pObject); - DWORD64 dwDisplacement = 0; - IMAGEHLP_SYMBOL64* pSym = - (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; - if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE) - { - this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress); - return FALSE; - } - // Object name output - this->OnOutput(pSym->Name); - - free(pSym); - return TRUE; -}; - -BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead) -{ - if (s_readMemoryFunction == NULL) - { - SIZE_T st; - BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st); - *lpNumberOfBytesRead = (DWORD)st; - //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); - return bRet; - } - else - { - return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, - s_readMemoryFunction_UserData); - } -} - -void StackWalker::OnLoadModule(LPCSTR img, - LPCSTR mod, - DWORD64 baseAddr, - DWORD size, - DWORD result, - LPCSTR symType, - LPCSTR pdbName, - ULONGLONG fileVersion) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - size_t maxLen = STACKWALK_MAX_NAMELEN; -#if _MSC_VER >= 1400 - maxLen = _TRUNCATE; -#endif - if (fileVersion == 0) - _snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", - img, mod, (LPVOID)baseAddr, size, result, symType, pdbName); - else - { - DWORD v4 = (DWORD)(fileVersion & 0xFFFF); - DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF); - DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF); - DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF); - _snprintf_s( - buffer, maxLen, - "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", - img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); - } - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated - OnOutput(buffer); -} - -void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - size_t maxLen = STACKWALK_MAX_NAMELEN; -#if _MSC_VER >= 1400 - maxLen = _TRUNCATE; -#endif - if ((eType != lastEntry) && (entry.offset != 0)) - { - if (entry.name[0] == 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); - if (entry.undName[0] != 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); - if (entry.undFullName[0] != 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); - if (entry.lineFileName[0] == 0) - { - MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); - if (entry.moduleName[0] == 0) - MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); - _snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName, - entry.lineFileName, entry.name); - } - else - _snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, - entry.name); - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; - OnOutput(buffer); - } -} - -void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - size_t maxLen = STACKWALK_MAX_NAMELEN; -#if _MSC_VER >= 1400 - maxLen = _TRUNCATE; -#endif - _snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, - (LPVOID)addr); - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; - OnOutput(buffer); -} - -void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - size_t maxLen = STACKWALK_MAX_NAMELEN; -#if _MSC_VER >= 1400 - maxLen = _TRUNCATE; -#endif - _snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", - szSearchPath, symOptions, szUserName); - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; - OnOutput(buffer); - // Also display the OS-version -#if _MSC_VER <= 1200 - OSVERSIONINFOA ver; - ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); - ver.dwOSVersionInfoSize = sizeof(ver); - if (GetVersionExA(&ver) != FALSE) - { - _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, - ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; - OnOutput(buffer); - } -#else - OSVERSIONINFOEXA ver; - ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); - ver.dwOSVersionInfoSize = sizeof(ver); -#if _MSC_VER >= 1900 -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE) - { - _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, - ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, - ver.wProductType); - buffer[STACKWALK_MAX_NAMELEN - 1] = 0; - OnOutput(buffer); - } -#if _MSC_VER >= 1900 -#pragma warning(pop) -#endif -#endif -} - -void StackWalker::OnOutput(LPCSTR buffer) -{ - OutputDebugStringA(buffer); -} diff --git a/3rdparty/stackwalker/stackwalker.h b/3rdparty/stackwalker/stackwalker.h deleted file mode 100644 index 0a004d96..00000000 --- a/3rdparty/stackwalker/stackwalker.h +++ /dev/null @@ -1,255 +0,0 @@ -#ifndef __STACKWALKER_H__ -#define __STACKWALKER_H__ - -#if defined(_MSC_VER) - -/********************************************************************** - * - * StackWalker.h - * - * - * - * LICENSE (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2005-2009, Jochen Kalmbach - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 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. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - * - * **********************************************************************/ -// #pragma once is supported starting with _MSC_VER 1000, -// so we need not to check the version (because we only support _MSC_VER >= 1100)! -#pragma once - -#include - -#if _MSC_VER >= 1900 -#pragma warning(disable : 4091) -#endif - -// special defines for VC5/6 (if no actual PSDK is installed): -#if _MSC_VER < 1300 -typedef unsigned __int64 DWORD64, *PDWORD64; -#if defined(_WIN64) -typedef unsigned __int64 SIZE_T, *PSIZE_T; -#else -typedef unsigned long SIZE_T, *PSIZE_T; -#endif -#endif // _MSC_VER < 1300 - -class StackWalkerInternal; // forward -class StackWalker -{ -public: - typedef enum StackWalkOptions - { - // No addition info will be retrieved - // (only the address is available) - RetrieveNone = 0, - - // Try to get the symbol-name - RetrieveSymbol = 1, - - // Try to get the line for this symbol - RetrieveLine = 2, - - // Try to retrieve the module-infos - RetrieveModuleInfo = 4, - - // Also retrieve the version for the DLL/EXE - RetrieveFileVersion = 8, - - // Contains all the above - RetrieveVerbose = 0xF, - - // Generate a "good" symbol-search-path - SymBuildPath = 0x10, - - // Also use the public Microsoft-Symbol-Server - SymUseSymSrv = 0x20, - - // Contains all the above "Sym"-options - SymAll = 0x30, - - // Contains all options (default) - OptionsAll = 0x3F - } StackWalkOptions; - - StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, - DWORD dwProcessId = GetCurrentProcessId(), - HANDLE hProcess = GetCurrentProcess()); - StackWalker(DWORD dwProcessId, HANDLE hProcess); - virtual ~StackWalker(); - - typedef BOOL(__stdcall* PReadProcessMemoryRoutine)( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead, - LPVOID pUserData // optional data, which was passed in "ShowCallstack" - ); - - BOOL LoadModules(); - - BOOL ShowCallstack( - HANDLE hThread = GetCurrentThread(), - const CONTEXT* context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, - LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback - ); - - BOOL ShowObject(LPVOID pObject); - -#if _MSC_VER >= 1300 - // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" - // in older compilers in order to use it... starting with VC7 we can declare it as "protected" -protected: -#endif - enum - { - STACKWALK_MAX_NAMELEN = 1024 - }; // max name length for found symbols - -protected: - // Entry for each Callstack-Entry - typedef struct CallstackEntry - { - DWORD64 offset; // if 0, we have no valid entry - CHAR name[STACKWALK_MAX_NAMELEN]; - CHAR undName[STACKWALK_MAX_NAMELEN]; - CHAR undFullName[STACKWALK_MAX_NAMELEN]; - DWORD64 offsetFromSmybol; - DWORD offsetFromLine; - DWORD lineNumber; - CHAR lineFileName[STACKWALK_MAX_NAMELEN]; - DWORD symType; - LPCSTR symTypeString; - CHAR moduleName[STACKWALK_MAX_NAMELEN]; - DWORD64 baseOfImage; - CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; - } CallstackEntry; - - typedef enum CallstackEntryType - { - firstEntry, - nextEntry, - lastEntry - } CallstackEntryType; - - virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); - virtual void OnLoadModule(LPCSTR img, - LPCSTR mod, - DWORD64 baseAddr, - DWORD size, - DWORD result, - LPCSTR symType, - LPCSTR pdbName, - ULONGLONG fileVersion); - virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry); - virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); - virtual void OnOutput(LPCSTR szText); - - StackWalkerInternal* m_sw; - HANDLE m_hProcess; - DWORD m_dwProcessId; - BOOL m_modulesLoaded; - LPSTR m_szSymPath; - - int m_options; - int m_MaxRecursionCount; - - static BOOL __stdcall myReadProcMem(HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead); - - friend StackWalkerInternal; -}; // class StackWalker - -// The "ugly" assembler-implementation is needed for systems before XP -// If you have a new PSDK and you only compile for XP and later, then you can use -// the "RtlCaptureContext" -// Currently there is no define which determines the PSDK-Version... -// So we just use the compiler-version (and assumes that the PSDK is -// the one which was installed by the VS-IDE) - -// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... -// But I currently use it in x64/IA64 environments... -//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) - -#if defined(_M_IX86) -#ifdef CURRENT_THREAD_VIA_EXCEPTION -// TODO: The following is not a "good" implementation, -// because the callstack is only valid in the "__except" block... -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do \ - { \ - memset(&c, 0, sizeof(CONTEXT)); \ - EXCEPTION_POINTERS* pExp = NULL; \ - __try \ - { \ - throw 0; \ - } \ - __except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \ - : EXCEPTION_EXECUTE_HANDLER)) \ - { \ - } \ - if (pExp != NULL) \ - memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - } while (0); -#else -// clang-format off -// The following should be enough for walking the callstack... -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do \ - { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - __asm call x \ - __asm x: pop eax \ - __asm mov c.Eip, eax \ - __asm mov c.Ebp, ebp \ - __asm mov c.Esp, esp \ - } while (0) -// clang-format on -#endif - -#else - -// The following is defined for x86 (XP and higher), x64 and IA64: -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do \ - { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - RtlCaptureContext(&c); \ - } while (0); -#endif - -#endif //defined(_MSC_VER) - -#endif // __STACKWALKER_H__ diff --git a/3rdparty/stackwalker/stackwalker.pro b/3rdparty/stackwalker/stackwalker.pro deleted file mode 100644 index 19e68949..00000000 --- a/3rdparty/stackwalker/stackwalker.pro +++ /dev/null @@ -1,26 +0,0 @@ -requires(windows:msvc) - -TEMPLATE = lib -TARGET = stackwalker - -load(am-config) - -CONFIG += \ - static \ - hide_symbols \ - warn_off \ - installed - -MODULE_INCLUDEPATH += $$PWD - -load(qt_helper_lib) - -QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS - -INCLUDEPATH += $$PWD - -HEADERS += \ - stackwalker.h - -SOURCES += \ - stackwalker.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..9d84b673 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +# Generated from application-manager.pro. + +cmake_minimum_required(VERSION 3.16) + +include(.cmake.conf) +project(QtApplicationManager # special case + VERSION "${QT_REPO_MODULE_VERSION}" + DESCRIPTION "QtAplicationManager Tools and Libraries" # special case + HOMEPAGE_URL "https://qt.io/" + LANGUAGES CXX C +) + +set(QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS TRUE) + +# populate the platform check variables +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals) + +if(NOT (ANDROID OR IOS OR LINUX OR MACOS OR (WIN32 AND NOT WINRT))) + message(NOTICE "Skipping the build as building is only supported on Windows, macOS, Linux, Android and iOS.") + return() +endif() + +# find the all modules (Gui isn't really optional, but we have to deal with a no-gui CI configuration) +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Concurrent) +find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS + Gui + Qml + Quick + QuickTest + DBus + WaylandClient + WaylandCompositor + QuickTest + Widgets + ZlibPrivate + GeniviExtras +) + +if(NOT TARGET Qt::Gui OR NOT TARGET Qt::Quick) + message(NOTICE "Skipping the build as QtGui and/or QtQuick are not available.") + return() +endif() + +qt_build_repo() diff --git a/benchmarks/appman-bench/README b/benchmarks/appman-bench/README deleted file mode 100644 index 0af954ee..00000000 --- a/benchmarks/appman-bench/README +++ /dev/null @@ -1,21 +0,0 @@ -The appman-bench is a tool using a known, minimal System UI -environment to benchmark the application manager itself and -apps started by it. - -The benchmark tests the following: -* cpu load -* gpu load -* memory consumption -* fps - -The bench provides a collection of small qml test files. -These qml test files are loaded in a System UI, as well -as in every app which is started. -The System UI waits for all apps to be started and starts -measuring while keeping them running for some time. - -The bench provides a way to change what runtime is used -for testing and enables us to see differences between the -appman-launcher-qml and qmlscene binaries. -New tests can be added by writing a qml file and putting it into -the test folder. diff --git a/benchmarks/appman-bench/am-config.yaml b/benchmarks/appman-bench/am-config.yaml deleted file mode 100644 index 21d47daf..00000000 --- a/benchmarks/appman-bench/am-config.yaml +++ /dev/null @@ -1,24 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -runtimes: - qml: - quitTime: 2000 - -logging: - rules: - - "*=false" - - "*.critical=true" - - "am.bench*=true" - -ui: - fullscreen: no - mainQml: "${CONFIG_PWD}/system-ui/main.qml" - -# development setup: -flags: - noSecurity: yes - noUiWatchdog: yes diff --git a/benchmarks/appman-bench/appman-bench.pro b/benchmarks/appman-bench/appman-bench.pro deleted file mode 100644 index 2baae5e2..00000000 --- a/benchmarks/appman-bench/appman-bench.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = aux - -OTHER_FILES = \ - README \ - run.sh \ - am-config.yaml \ - tests/* \ - system-ui/*.qml \ - templates/appman-qml/* \ - templates/qmlscene/* \ diff --git a/benchmarks/appman-bench/run.sh b/benchmarks/appman-bench/run.sh deleted file mode 100644 index d6a3242c..00000000 --- a/benchmarks/appman-bench/run.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/bash -############################################################################# -## -## Copyright (C) 2021 The Qt Company Ltd. -## Copyright (C) 2019 Luxoft Sweden AB -## Copyright (C) 2018 Pelagicore AG -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the QtApplicationManager module of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:BSD$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## BSD License Usage -## Alternatively, you may use this file under the terms of the BSD license -## as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * 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. -## * Neither the name of The Qt Company Ltd nor the names of its -## contributors may be used to endorse or promote products derived -## from this software without specific prior written permission. -## -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -## OWNER 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." -## -## $QT_END_LICENSE$ -## -############################################################################# - - -SCRIPT=$(dirname $0) -usage() -{ - echo "$0 [-n ][-r ][-q ][-t ] " - echo "" - echo "This script will execute a benchmark using the appman binary provided by ." - echo "It uses templates for defining the runtime used and also templates for the test to be executed." - echo "" - echo "The following options are accepted:" - echo "-n : Defines how many applications are executed at the same time." - echo "-r : Defines which runtime template is used. Possible values are:" - echo " 'appman-qml' : Starts a normal appman qml runtime using appman-launcher-qml" - echo " 'qmlscene' : Starts a native runtime using qmlscene for interpreting the qml code" - echo "-q : Defines which Qt is used. This is required by the qmlscene runtime-template." - echo "-t : Only executes this given single test. If not provided all tests in the 'tests' folder are executed" - echo "" - exit 1 -} - - -TEMPLATE=appman-qml -APPS=4 -QT_FOLDER= -TEST= - -while getopts ":n:r:q:t:" option -do -case "${option}" -in -n) APPS=${OPTARG};; -r) TEMPLATE=${OPTARG};; -q) QT_FOLDER="${OPTARG}/bin/";; -t) TEST=${OPTARG};; -*) usage;; -esac -done - -[ "$#" -lt 1 ] && usage -APPMAN="${@: -1}" -[ ! -e "$APPMAN" ] && usage - -trap exit INT QUIT 0 -run_test() -{ - temp_folder=$(mktemp -d) - temp_app_folder="$temp_folder/apps" - mkdir -p $temp_folder - - cp -a system-ui $temp_folder/ - cp -a am-config.yaml $temp_folder/ - - mkdir -p $temp_app_folder - - for (( i=1; i<=$APPS; i++ )) - do - appid="app$i" - mkdir -p $temp_app_folder/$appid - cp -a templates/$TEMPLATE/* $temp_app_folder/$appid/ - sed -i -e "s/TEST_ID/$appid/g" $temp_app_folder/$appid/info.yaml - sed -i -e "s|QT_FOLDER/|$QT_FOLDER|g" $temp_app_folder/$appid/info.yaml - done - - echo "Running $test_qml in $temp_folder" - cp $test_qml $temp_folder/test.qml - (cd $temp_folder && $APPMAN -c am-config.yaml --clear-cache --no-dlt-logging) -} - -if [ -n "$TEST" ] -then - echo "RUNNING SINGLE TEST" - if [ ! -e "tests/$TEST" ]; then - echo "Test doesn't exist" - exit 1 - fi - test_qml="tests/$TEST" - run_test -else - echo "RUNNING ALL TESTS" - for test_qml in tests/* - do - run_test - done -fi - - diff --git a/benchmarks/appman-bench/system-ui/main.qml b/benchmarks/appman-bench/system-ui/main.qml deleted file mode 100644 index 20843986..00000000 --- a/benchmarks/appman-bench/system-ui/main.qml +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.8 -import QtQuick.Window 2.2 -import QtApplicationManager 2.0 -import QtApplicationManager.SystemUI 2.0 - -Window { - id: root - width: 1024 - height: 640 - - LoggingCategory { - id: benchCategory - name: "am.bench" - } - - Loader { - anchors.fill: parent - source: "../test.qml" - } - - Rectangle { - width: 10 - height: 10 - color: "red" - NumberAnimation on rotation { - loops: Animation.Infinite - from: 0 - to: 360 - } - } - - Grid { - id: grid - anchors.fill: parent - - columns: Math.ceil(Math.sqrt(ApplicationManager.count)) - - Repeater { - id: windows - model: WindowManager - - Item { - property alias processMonitor: appProcessMonitor - property alias frameTimer: appFrameTimer - - width: root.width / grid.columns; - height: root.height / Math.ceil(ApplicationManager.count / grid.columns) - - WindowItem { - anchors.fill: parent - anchors.margins: 3 - anchors.topMargin: 25 - window: model.window - } - - MonitorModel { - id: appProcessMonitor - maximumCount: 100 - running: true - interval: 100 - - ProcessStatus { - applicationId: model.window.application.id - } - - FrameTimer { - id: appFrameTimer - window: model.window - } - } - } - } - } - - Connections { - target: WindowManager - function onWindowAdded(window) { - console.log("System UI: onWindowAdded: " + window); - if (WindowManager.count >= ApplicationManager.count) - statsTimer.start(); - } - } - - MonitorModel { - id: systemUiMonitor - maximumCount: 100 - running: true - interval: 100 - - ProcessStatus { - applicationId: "" - } - - FrameTimer { - id: systemFrameTimer - window: root - } - - GpuStatus {} - } - - Timer { - id: statsTimer - interval: 2000 - onTriggered: { - systemUiMonitor.running = false; - var load = avg(systemUiMonitor, systemUiMonitor.count, "cpuLoad"); - var rss = "System UI RSS Max: " + format((max(systemUiMonitor, systemUiMonitor.count, "memoryRss.total") - / 1e6).toFixed(0)) + " MB"; - var pss = "System UI PSS Max: " + format((max(systemUiMonitor, systemUiMonitor.count, "memoryPss.total") - / 1e6).toFixed(0)) + " MB"; - var fps = "System UI FPS Avg: " + format(systemFrameTimer.averageFps.toFixed(1)) + " fps"; - var cpuLoad = "System UI CPU Load Avg: " + format((load * 100).toFixed(1)) + " %"; - var gpuLoad = "System GPU Load Avg: " + format((avg(systemUiMonitor, systemUiMonitor.count, "gpuLoad") - * 100).toFixed(0)) + " %"; - - var totalAppRSS = 0; - var totalAppPSS = 0; - var totalAppFPS = 0; - var totalCPULoad = load; - for (var i = 0; i < windows.count; i++) { - var chrome = windows.itemAt(i); - chrome.processMonitor.running = false; - totalAppRSS += max(chrome.processMonitor, chrome.processMonitor.count, "memoryRss.total"); - totalAppPSS += max(chrome.processMonitor, chrome.processMonitor.count, "memoryPss.total"); - totalAppFPS += chrome.processMonitor.get(chrome.processMonitor.count - 1).averageFps ; - totalCPULoad += avg(chrome.processMonitor, chrome.processMonitor.count, "cpuLoad"); - ApplicationManager.stopApplication(ApplicationManager.application(i).id); - } - - var appRSS = "App RSS Max: " + format((totalAppRSS / ApplicationManager.count / 1e6).toFixed(0)) + " MB"; - var appPSS = "App PSS Max: " + format((totalAppPSS / ApplicationManager.count / 1e6).toFixed(0)) + " MB"; - var appFPS = "App FPS Avg: " + format((totalAppFPS / ApplicationManager.count ).toFixed(1)) + " fps"; - - var accCpuLoad = "Acc. CPU Load Avg: " + format((totalCPULoad * 100).toFixed(1)) + " %"; - - console.log(benchCategory, "System UI Resolution: " + root.width + "x" + root.height + " | App Resolution: " - + windows.itemAt(0).width + "x" + windows.itemAt(0).height); - console.log(benchCategory, cpuLoad + " | " + accCpuLoad + " | " + gpuLoad + " | " + fps + " | " + rss - + " | " + pss + " | " + appFPS + " | " + appRSS + " | " + appPSS); - Qt.quit(); - } - } - - function max(monitor, size, key) { - var value = 0; - for (var i = 0; i < size; i++) { - var val = eval("monitor.get(i)." + key); - if (val) - value = Math.max(val, value); - } - return value; - } - - function avg(monitor, size, key) { - var sum = 0; - for (var i = 0; i < size; i++) { - var val = eval("monitor.get(i)." + key) - if (val == undefined) - break; - sum += val; - } - return sum / size; - } - - function format(n) { - return String(" " + n).slice(-6); - } - - Connections { - target: ApplicationManager - function onWindowManagerCompositorReadyChanged() { - for (var i = 0; i < ApplicationManager.count; i++) - ApplicationManager.application(i).start(); - } - } -} diff --git a/benchmarks/appman-bench/templates/appman-qml/icon.png b/benchmarks/appman-bench/templates/appman-qml/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/benchmarks/appman-bench/templates/appman-qml/icon.png and /dev/null differ diff --git a/benchmarks/appman-bench/templates/appman-qml/info.yaml b/benchmarks/appman-bench/templates/appman-qml/info.yaml deleted file mode 100644 index 6d82c3d0..00000000 --- a/benchmarks/appman-bench/templates/appman-qml/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'TEST_ID' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'ApplicationManagerBench Test' diff --git a/benchmarks/appman-bench/templates/appman-qml/main.qml b/benchmarks/appman-bench/templates/appman-qml/main.qml deleted file mode 100644 index 07cc3de5..00000000 --- a/benchmarks/appman-bench/templates/appman-qml/main.qml +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - Loader { - anchors.fill: parent - source: "../../test.qml" - } - Rectangle { - width: 10 - height: 10 - color: "red" - NumberAnimation on rotation { - loops: Animation.Infinite - from: 0 - to: 360 - } - } - - Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } - } -} diff --git a/benchmarks/appman-bench/templates/qmlscene/icon.png b/benchmarks/appman-bench/templates/qmlscene/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/benchmarks/appman-bench/templates/qmlscene/icon.png and /dev/null differ diff --git a/benchmarks/appman-bench/templates/qmlscene/info.yaml b/benchmarks/appman-bench/templates/qmlscene/info.yaml deleted file mode 100644 index 3ecadf30..00000000 --- a/benchmarks/appman-bench/templates/qmlscene/info.yaml +++ /dev/null @@ -1,13 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'TEST_ID' -icon: 'icon.png' -code: 'QT_FOLDER/qmlscene' -runtimeParameters: - arguments: ['main.qml'] - environmentVariables: - QT_LOGGING_RULES: "*=false;*.critical=true" -runtime: 'native' -name: - en: 'ApplicationManagerBench Test' diff --git a/benchmarks/appman-bench/templates/qmlscene/main.qml b/benchmarks/appman-bench/templates/qmlscene/main.qml deleted file mode 100644 index 6b7c0f27..00000000 --- a/benchmarks/appman-bench/templates/qmlscene/main.qml +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtQuick.Window 2.0 - -Window { - id: root - Loader { - anchors.fill: parent - source: "../../test.qml" - } - Rectangle { - width: 10 - height: 10 - color: "red" - NumberAnimation on rotation { - loops: Animation.Infinite - from: 0 - to: 360 - } - } -} diff --git a/benchmarks/appman-bench/tests/controls2.qml b/benchmarks/appman-bench/tests/controls2.qml deleted file mode 100644 index b0f3bff6..00000000 --- a/benchmarks/appman-bench/tests/controls2.qml +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick.Controls 2.0 - -Button { - text: "Button " + Math.random() -} diff --git a/benchmarks/appman-bench/tests/rect.qml b/benchmarks/appman-bench/tests/rect.qml deleted file mode 100644 index 39f9cd10..00000000 --- a/benchmarks/appman-bench/tests/rect.qml +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 - -Rectangle { - color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); -} diff --git a/benchmarks/appman-bench/tests/repeater.qml b/benchmarks/appman-bench/tests/repeater.qml deleted file mode 100644 index 35a57980..00000000 --- a/benchmarks/appman-bench/tests/repeater.qml +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 - -Grid { - id: grid - property int count: 10000 - columns: Math.ceil(Math.sqrt(count)) - - Repeater { - model: grid.count - - Rectangle { - width: grid.width / grid.columns; - height: grid.height / Math.ceil(grid.count / grid.columns) - - color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); - } - } -} diff --git a/benchmarks/appman-bench/tests/shader.qml b/benchmarks/appman-bench/tests/shader.qml deleted file mode 100644 index 6ea1aabe..00000000 --- a/benchmarks/appman-bench/tests/shader.qml +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtGraphicalEffects 1.0 - -Item { - Grid { - id: grid - - anchors.fill: parent - - property int count: 10000 - columns: Math.ceil(Math.sqrt(count)) - - Repeater { - model: grid.count - - Rectangle { - width: grid.width / grid.columns; - height: grid.height / Math.ceil(grid.count / grid.columns) - - color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); - - NumberAnimation on rotation { - loops: Animation.Infinite - from: 0 - to: 360 - } - } - } - } - - GaussianBlur { - anchors.fill: grid - source: grid - radius: 100 - samples: 100 - } -} diff --git a/benchmarks/benchmarks.pro b/benchmarks/benchmarks.pro deleted file mode 100644 index ca7d4f1f..00000000 --- a/benchmarks/benchmarks.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = \ - appman-bench \ - diff --git a/cmake/FindWrapLibArchive.cmake b/cmake/FindWrapLibArchive.cmake new file mode 100644 index 00000000..67e4ce0b --- /dev/null +++ b/cmake/FindWrapLibArchive.cmake @@ -0,0 +1,18 @@ +# We can't create the same interface imported target multiple times, CMake will complain if we do +# that. This can happen if the find_package call is done in multiple different subdirectories. +if(TARGET WrapLibArchive::WrapLibArchive) + set(WrapLibArchive_FOUND TRUE) + return() +endif() + +find_package(LibArchive) + +if (NOT LibArchive_FOUND) + set(WrapLibArchive_FOUND FALSE) + return() +endif() + +add_library(WrapLibArchive::WrapLibArchive INTERFACE IMPORTED) +target_link_libraries(WrapLibArchive::WrapLibArchive INTERFACE ${LibArchive_LIBRARIES}) +target_include_directories(WrapLibArchive::WrapLibArchive INTERFACE ${LibArchive_INCLUDE_DIRS}) +set(WrapLibArchive_FOUND TRUE) diff --git a/cmake/FindWrapLibYaml.cmake b/cmake/FindWrapLibYaml.cmake new file mode 100644 index 00000000..1dab9126 --- /dev/null +++ b/cmake/FindWrapLibYaml.cmake @@ -0,0 +1,19 @@ +# We can't create the same interface imported target multiple times, CMake will complain if we do +# that. This can happen if the find_package call is done in multiple different subdirectories. +if(TARGET WrapLibYaml::WrapLibYaml) + set(WrapLibYaml_FOUND TRUE) + return() +endif() + +find_package(PkgConfig) +pkg_check_modules(pc_libyaml yaml-0.1 IMPORTED_TARGET) + + +if (NOT pc_libyaml_FOUND) + set(WrapLibYaml_FOUND FALSE) + return() +endif() + +add_library(WrapLibYaml::WrapLibYaml INTERFACE IMPORTED) +target_link_libraries(WrapLibYaml::WrapLibYaml INTERFACE ${pc_libyaml_LIBRARIES}) +set(WrapLibYaml_FOUND TRUE) diff --git a/cmake/QtAppManHelpers.cmake b/cmake/QtAppManHelpers.cmake new file mode 100644 index 00000000..d19120a8 --- /dev/null +++ b/cmake/QtAppManHelpers.cmake @@ -0,0 +1,21 @@ +# This function is a hack to make generating DBus adaptors without custom cpp files possible +function(qtam_internal_add_dbus_adaptor target) + if (NOT TARGET "${target}") + message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") + endif() + + cmake_parse_arguments(arg "" "" "DBUS_ADAPTOR_SOURCES;DBUS_ADAPTOR_FLAGS" ${ARGN}) + + foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES}) + qt_internal_extend_target(${target} + DBUS_ADAPTOR_SOURCES ${adaptor} + DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS} + ) + + # hack to remove the .cpp file, which we implement ourselves + get_target_property(srcs ${target} SOURCES) + list(REMOVE_AT srcs -1) + set_target_properties(${target} PROPERTIES SOURCES "${srcs}") + + endforeach() +endfunction() diff --git a/coin/module_config.yaml b/coin/module_config.yaml new file mode 100644 index 00000000..47a5f070 --- /dev/null +++ b/coin/module_config.yaml @@ -0,0 +1,23 @@ +version: 2 +accept_configuration: + condition: property + property: features + not_contains_value: Disable + +instructions: + Build: + - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" + + Test: + - type: Group + instructions: + - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" + disable_if: + condition: or + conditions: + - condition: property + property: host.os + in_values: ["Windows", "MacOS"] + - condition: property + property: target.os + in_values: ["IOS", "Android", "WebAssembly"] diff --git a/config.tests/libarchive/libarchive.pro b/config.tests/libarchive/libarchive.pro deleted file mode 100644 index 7f4224e0..00000000 --- a/config.tests/libarchive/libarchive.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = libarchive -CONFIG -= qt -CONFIG += console - -SOURCES += main.cpp - -PKGCONFIG += "'libarchive >= 3.1.2'" -CONFIG += link_pkgconfig diff --git a/config.tests/libarchive/main.cpp b/config.tests/libarchive/main.cpp deleted file mode 100644 index 2a532461..00000000 --- a/config.tests/libarchive/main.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -int main() -{ - struct archive *ar = archive_write_new(); - - return 0; -} diff --git a/config.tests/libyaml/libyaml.pro b/config.tests/libyaml/libyaml.pro deleted file mode 100644 index eaf0665c..00000000 --- a/config.tests/libyaml/libyaml.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = libyaml -CONFIG -= qt -CONFIG += console - -SOURCES += main.cpp - -PKGCONFIG += "'yaml-0.1 >= 0.1.6'" -CONFIG += link_pkgconfig diff --git a/config.tests/libyaml/main.cpp b/config.tests/libyaml/main.cpp deleted file mode 100644 index c1f7c70d..00000000 --- a/config.tests/libyaml/main.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -int main() -{ - yaml_parser_t p; - yaml_parser_initialize(&p); - - return 0; -} diff --git a/config.tests/touchemulation/main.cpp b/config.tests/touchemulation/main.cpp deleted file mode 100644 index 41d73613..00000000 --- a/config.tests/touchemulation/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -int main() -{ - return 0; -} diff --git a/config.tests/touchemulation/touchemulation.pro b/config.tests/touchemulation/touchemulation.pro deleted file mode 100644 index 6a88ef05..00000000 --- a/config.tests/touchemulation/touchemulation.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = touchemulation -CONFIG -= qt -CONFIG += console - -SOURCES += main.cpp - -PKGCONFIG += xcb x11 xi -CONFIG += link_pkgconfig diff --git a/configure.cmake b/configure.cmake new file mode 100644 index 00000000..53e3f110 --- /dev/null +++ b/configure.cmake @@ -0,0 +1,21 @@ + + +#### Inputs + + + +#### Libraries + + + +#### Tests + + + +#### Features + + +qt_extra_definition("QT_VERSION_STR" "\"${PROJECT_VERSION}\"" PUBLIC) +qt_extra_definition("QT_VERSION_MAJOR" ${PROJECT_VERSION_MAJOR} PUBLIC) +qt_extra_definition("QT_VERSION_MINOR" ${PROJECT_VERSION_MINOR} PUBLIC) +qt_extra_definition("QT_VERSION_PATCH" ${PROJECT_VERSION_PATCH} PUBLIC) diff --git a/dependencies.yaml b/dependencies.yaml index 8b34b97e..6f104f88 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -1,10 +1,13 @@ dependencies: ../qtbase: - ref: befa3729db0d1010694bd1bb4cbadd36ff5c49fb + ref: f380c87731472eb59495b7823b7c6243b3aa11f4 required: true + shared: true ../qtdeclarative: - ref: 7e3f5f2224ba0e57a9dffa6251bb002cde564f56 + ref: 249db12b6020cc3a8f04841b1e28cd529f4929d9 required: true + shared: true ../qtwayland: - ref: 3cbd627b9fbbef36394de4cb297e88eb34d436da + ref: 0c93bfd8679319cc906544141287c0e973b8555d required: false + shared: true diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 00000000..21a0ea14 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from doc.pro. + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..90d9a2a9 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,7 @@ +# Generated from examples.pro. + +qt_examples_build_begin() + +add_subdirectory(applicationmanager) + +qt_examples_build_end() diff --git a/examples/applicationmanager/CMakeLists.txt b/examples/applicationmanager/CMakeLists.txt new file mode 100644 index 00000000..c19b0f84 --- /dev/null +++ b/examples/applicationmanager/CMakeLists.txt @@ -0,0 +1,15 @@ + +#add_subdirectory(animated-windows) +#add_subdirectory(frame-timer) +#add_subdirectory(hello-world) +#add_subdirectory(launch-intents) +#add_subdirectory(minidesk) +#add_subdirectory(application-features) +#add_subdirectory(multi-views) +#add_subdirectory(process-status) +add_subdirectory(startup-plugin) +#add_subdirectory(intents) +add_subdirectory(custom-appman) +if(LINUX) + add_subdirectory(softwarecontainer-plugin) +endif() diff --git a/examples/applicationmanager/animated-windows/CMakeLists.txt b/examples/applicationmanager/animated-windows/CMakeLists.txt new file mode 100644 index 00000000..31a2a51e --- /dev/null +++ b/examples/applicationmanager/animated-windows/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from animated-windows.pro. + +cmake_minimum_required(VERSION 3.14) +project(animated-windows LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/animated-windows") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + + +set_target_properties(animated-windows PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(animated-windows PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS animated-windows + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/application-features/CMakeLists.txt b/examples/applicationmanager/application-features/CMakeLists.txt new file mode 100644 index 00000000..4df08997 --- /dev/null +++ b/examples/applicationmanager/application-features/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated from application-features.pro. + +cmake_minimum_required(VERSION 3.14) +project(ui LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/application-features") + +) +set_target_properties(ui PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +install(TARGETS ui + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) +add_subdirectory(imports) +add_subdirectory(native) diff --git a/examples/applicationmanager/application-features/imports/CMakeLists.txt b/examples/applicationmanager/application-features/imports/CMakeLists.txt new file mode 100644 index 00000000..cb913a12 --- /dev/null +++ b/examples/applicationmanager/application-features/imports/CMakeLists.txt @@ -0,0 +1,3 @@ +# Generated from imports.pro. + +add_subdirectory(terminator2) diff --git a/examples/applicationmanager/application-features/imports/terminator2/CMakeLists.txt b/examples/applicationmanager/application-features/imports/terminator2/CMakeLists.txt new file mode 100644 index 00000000..945ad301 --- /dev/null +++ b/examples/applicationmanager/application-features/imports/terminator2/CMakeLists.txt @@ -0,0 +1,48 @@ +# Generated from terminator2.pro. + +cmake_minimum_required(VERSION 3.14) +project(terminator2plugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/application-features/apps/crash/Terminator") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Qml) +find_package(Qt6 COMPONENTS Quick) + +qt6_add_qml_module(terminator2plugin + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CURRENT_BINARY_DIR}/../../apps/crash/Terminator" + VERSION 1.0 + URI "Terminator" + INSTALL_LOCATION ${INSTALL_EXAMPLEDIR} +) + +target_sources(terminator2plugin PRIVATE + qmlterminator2.cpp qmlterminator2.h +) +set_target_properties(terminator2plugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(terminator2plugin PUBLIC + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick +) + +install(TARGETS terminator2plugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/application-features/native/CMakeLists.txt b/examples/applicationmanager/application-features/native/CMakeLists.txt new file mode 100644 index 00000000..0d1c9b10 --- /dev/null +++ b/examples/applicationmanager/application-features/native/CMakeLists.txt @@ -0,0 +1,5 @@ +# Generated from native.pro. + +if(TARGET Qt::WaylandClient AND TARGET Qt::Widgets) + add_subdirectory(widgets) +endif() diff --git a/examples/applicationmanager/application-features/native/widgets/CMakeLists.txt b/examples/applicationmanager/application-features/native/widgets/CMakeLists.txt new file mode 100644 index 00000000..11f79f20 --- /dev/null +++ b/examples/applicationmanager/application-features/native/widgets/CMakeLists.txt @@ -0,0 +1,41 @@ +# Generated from widgets.pro. + +cmake_minimum_required(VERSION 3.14) +project(widgets LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/application-features/apps/widgets") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(widgets + main.cpp +) +set_target_properties(widgets PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(widgets PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets + appman_commonPrivate + appman_launcherPrivate +) + +install(TARGETS widgets + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/applicationmanager.pro b/examples/applicationmanager/applicationmanager.pro index 462ef585..c3469aac 100644 --- a/examples/applicationmanager/applicationmanager.pro +++ b/examples/applicationmanager/applicationmanager.pro @@ -1,3 +1,5 @@ +requires(false) + load(am-config) requires(!disable-installer) diff --git a/examples/applicationmanager/custom-appman/CMakeLists.txt b/examples/applicationmanager/custom-appman/CMakeLists.txt new file mode 100644 index 00000000..69b70411 --- /dev/null +++ b/examples/applicationmanager/custom-appman/CMakeLists.txt @@ -0,0 +1,40 @@ +# Generated from custom-appman.pro. + +cmake_minimum_required(VERSION 3.14) +project(custom-appman LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/custom-appman") + +find_package(Qt6 COMPONENTS AppManMainPrivate) + + +qt_add_executable(custom-appman + custom-appman.cpp +) +set_target_properties(custom-appman PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) +target_compile_definitions(custom-appman PUBLIC + QT_MESSAGELOGCONTEXT +) + +target_link_libraries(custom-appman PUBLIC + Qt::AppManMainPrivate +) + +install(TARGETS custom-appman + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/frame-timer/CMakeLists.txt b/examples/applicationmanager/frame-timer/CMakeLists.txt new file mode 100644 index 00000000..bb6e0a97 --- /dev/null +++ b/examples/applicationmanager/frame-timer/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from frame-timer.pro. + +cmake_minimum_required(VERSION 3.14) +project(frame-timer LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/frame-timer") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(frame-timer PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(frame-timer PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS frame-timer + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/hello-world/CMakeLists.txt b/examples/applicationmanager/hello-world/CMakeLists.txt new file mode 100644 index 00000000..d58f0387 --- /dev/null +++ b/examples/applicationmanager/hello-world/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from hello-world.pro. + +cmake_minimum_required(VERSION 3.14) +project(hello-world LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/hello-world") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(hello-world PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(hello-world PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS hello-world + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/launch-intents/CMakeLists.txt b/examples/applicationmanager/launch-intents/CMakeLists.txt new file mode 100644 index 00000000..82b069d1 --- /dev/null +++ b/examples/applicationmanager/launch-intents/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from launch-intents.pro. + +cmake_minimum_required(VERSION 3.14) +project(launch-intents LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/launch-intents") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(launch-intents PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(launch-intents PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS launch-intents + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/minidesk/CMakeLists.txt b/examples/applicationmanager/minidesk/CMakeLists.txt new file mode 100644 index 00000000..014486e1 --- /dev/null +++ b/examples/applicationmanager/minidesk/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from minidesk.pro. + +cmake_minimum_required(VERSION 3.14) +project(minidesk LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/minidesk") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(minidesk PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(minidesk PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS minidesk + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/multi-views/CMakeLists.txt b/examples/applicationmanager/multi-views/CMakeLists.txt new file mode 100644 index 00000000..92b681c8 --- /dev/null +++ b/examples/applicationmanager/multi-views/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from multi-views.pro. + +cmake_minimum_required(VERSION 3.14) +project(multi-views LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/multi-views") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(multi-views PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(multi-views PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS multi-views + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/process-status/CMakeLists.txt b/examples/applicationmanager/process-status/CMakeLists.txt new file mode 100644 index 00000000..2cb18fbf --- /dev/null +++ b/examples/applicationmanager/process-status/CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from process-status.pro. + +cmake_minimum_required(VERSION 3.14) +project(process-status LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/process-status") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) + +) +set_target_properties(process-status PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(process-status PUBLIC + Qt::Core + Qt::Gui +) + +install(TARGETS process-status + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/softwarecontainer-plugin/CMakeLists.txt b/examples/applicationmanager/softwarecontainer-plugin/CMakeLists.txt new file mode 100644 index 00000000..1e7f7e7c --- /dev/null +++ b/examples/applicationmanager/softwarecontainer-plugin/CMakeLists.txt @@ -0,0 +1,39 @@ +# Generated from softwarecontainer-plugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(softwarecontainer-plugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/softwarecontainer-plugin") + +find_package(Qt6 COMPONENTS Core DBus AppManCommonPrivate AppManPluginInterfacesPrivate) + +qt_add_plugin(softwarecontainer-plugin) +target_sources(softwarecontainer-plugin PRIVATE + softwarecontainer.cpp softwarecontainer.h +) +set_target_properties(softwarecontainer-plugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(softwarecontainer-plugin PUBLIC + Qt::Core + Qt::DBus + Qt::AppManCommonPrivate + Qt::AppManPluginInterfacesPrivate +) + +install(TARGETS softwarecontainer-plugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/applicationmanager/startup-plugin/CMakeLists.txt b/examples/applicationmanager/startup-plugin/CMakeLists.txt new file mode 100644 index 00000000..5cf87297 --- /dev/null +++ b/examples/applicationmanager/startup-plugin/CMakeLists.txt @@ -0,0 +1,37 @@ +# Generated from startup-plugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(startup-plugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/applicationmanager/startup-plugin") + +find_package(Qt6 COMPONENTS Core AppManPluginInterfacesPrivate) + +qt_add_plugin(startup-plugin) +target_sources(startup-plugin PRIVATE + startup-plugin.cpp startup-plugin.h +) +set_target_properties(startup-plugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(startup-plugin PUBLIC + Qt::Core + Qt::AppManPluginInterfacesPrivate +) + +install(TARGETS startup-plugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/qmake-features/CMakeLists.txt b/qmake-features/CMakeLists.txt new file mode 100644 index 00000000..c58ce690 --- /dev/null +++ b/qmake-features/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from qmake-features.pro. + diff --git a/qt_cmdline.cmake b/qt_cmdline.cmake new file mode 100644 index 00000000..81d85ac2 --- /dev/null +++ b/qt_cmdline.cmake @@ -0,0 +1,2 @@ +qt_commandline_subconfig(src/common-lib) +qt_commandline_subconfig(src/package-lib) diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt new file mode 100644 index 00000000..c9b444f5 --- /dev/null +++ b/src/3rdparty/CMakeLists.txt @@ -0,0 +1,15 @@ +if(NOT QT_FEATURE_system_libarchive) + add_subdirectory(libarchive) +endif() + +if(NOT QT_FEATURE_system_libyaml) + add_subdirectory(libyaml) +endif() + +if(QT_FEATURE_libbacktrace) + add_subdirectory(libbacktrace) +endif() + +if(QT_FEATURE_stackwalker) + add_subdirectory(stackwalker) +endif() diff --git a/src/3rdparty/README.md b/src/3rdparty/README.md new file mode 100644 index 00000000..26baa958 --- /dev/null +++ b/src/3rdparty/README.md @@ -0,0 +1,73 @@ +## How to recreate the qmake base buildsystem for the 3rd-party stuff + +## openssl + +### Linux + +* `./config no-asm no-idea` +* `make` +* `cp crypto/buildinf.h libcrypto-include-unix` +* `cp include/openssl/opensslconf.h libcrypto-include-unix/openssl` + +### Mac OS X + +* `./Configure darwin64-x86_64-cc no-asm no-idea` +* `make depend` +* `make` +* `cp crypto/buildinf.h libcrypto-include-osx` +* `cp include/openssl/opensslconf.h libcrypto-include-osx/openssl` + +### Windows +* `perl Configure VC-WIN32 no-asm no-idea` +* `ms\do_ms.bat` +* `nmake -f ms\nt.mak` +* `copy /Y crypto\buildinf.h libarchive-include-win32` +* `copy /Y inc32\openssl\*.h libarchive-include-win32\openssl` + + +## xz + +### Linux +* ` ./configure --disable-shared --enable-threads=no --disable-assembler --disable-xz --disable-xzdec + --disable-lzmadec --disable-lzmainfo --disable-lzma-links --disable-scripts --disable-doc` +* `cp config.h config-unix.h` +* `echo "#include PLATFORM_CONFIG_H" >config.h` + +### Mac OS X +* ` ./configure --disable-shared --enable-threads=no --disable-assembler --disable-xz --disable-xzdec + --disable-lzmadec --disable-lzmainfo --disable-lzma-links --disable-scripts --disable-doc` +* `cp config.h config-osx.h` +* `echo "#include PLATFORM_CONFIG_H" >config.h` + +### Windows +* `copy /Y windows\config.h config-windows.h` +* `echo #include PLATFORM_CONFIG_H >config.h` + + +## libarchive + +### Linux +* `./configure --disable-shared --disable-bsdtar --disable-bsdcpio --disable-xattr --disable-acl + --without-bz2lib --without-lzmadec --without-lzo2 --without-nettle --without-openssl + --without-xml2 --without-expat` +* `cp config.h config-unix.h` +* `rm -rf CMakeLists.txt Makefile.* aclocal.m4 config.h.in configure* build/ contrib doc examples cpio libarchive_fe/ tar test_utils libarchive/CMakeLists.txt libarchive/test libarchive/*.5 libarchive/*.3` + +### Mac OS X +* `./configure --disable-shared --disable-bsdtar --disable-bsdcpio --disable-xattr --disable-acl + --without-bz2lib --without-lzmadec --without-lzo2 --without-nettle --without-openssl + --without-xml2 --without-expat` +* `cp config.h config-osx.h` + +### Windows +Prerequisite: build zlib 1.2.8 + +* `mkdir cbuild` +* `cd cbuild` +* `cmake -DENABLE_TAR=OFF -DENABLE_CPIO=OFF -DENABLE_XATTR=OFF -DENABLE_ACL=OFF -DENABLE_TEST=OFF + -DENABLE_OPENSSL=OFF -DZLIB_LIBRARY=..\..\zlib-1.2.8\release\z.lib -DZLIB_INCLUDE_DIR=..\..\zlib-1.2.8` +* `copy /Y config.h config-windows.h` + +## libyaml + +* `rm -rf CMakeLists.txt Makefile.* aclocal.m4 config* doc tests win32 yaml-0.1.pc.in include/Makefile.* src/Makefile.*` diff --git a/src/3rdparty/libarchive/CMakeLists.txt b/src/3rdparty/libarchive/CMakeLists.txt new file mode 100644 index 00000000..ed6a19be --- /dev/null +++ b/src/3rdparty/libarchive/CMakeLists.txt @@ -0,0 +1,158 @@ +# Generated from libarchive.pro. + +##################################################################### +## BundledArchive Generic Library: +##################################################################### + +if (APPLE) + find_package(Iconv) +endif() + +qt_internal_add_3rdparty_library(BundledLibArchive + QMAKE_LIB_NAME archive + STATIC + INSTALL + SOURCES + libarchive/archive_acl.c + libarchive/archive_check_magic.c + libarchive/archive_cmdline.c + libarchive/archive_entry.c + libarchive/archive_entry_copy_stat.c + libarchive/archive_entry_link_resolver.c + libarchive/archive_entry_sparse.c + libarchive/archive_entry_stat.c + libarchive/archive_entry_strmode.c + libarchive/archive_entry_xattr.c + libarchive/archive_getdate.c + libarchive/archive_match.c + libarchive/archive_options.c + libarchive/archive_pathmatch.c + libarchive/archive_ppmd7.c + libarchive/archive_random.c + libarchive/archive_rb.c + libarchive/archive_read.c + libarchive/archive_read_append_filter.c + libarchive/archive_read_data_into_fd.c + libarchive/archive_read_disk_entry_from_file.c + libarchive/archive_read_disk_set_standard_lookup.c + libarchive/archive_read_extract.c + libarchive/archive_read_open_fd.c + libarchive/archive_read_open_file.c + libarchive/archive_read_open_filename.c + libarchive/archive_read_open_memory.c + libarchive/archive_read_set_format.c + libarchive/archive_read_set_options.c + libarchive/archive_read_support_filter_bzip2.c + libarchive/archive_read_support_filter_gzip.c + libarchive/archive_read_support_filter_none.c + libarchive/archive_read_support_filter_program.c + libarchive/archive_read_support_filter_xz.c + libarchive/archive_read_support_format_by_code.c + libarchive/archive_read_support_format_empty.c + libarchive/archive_read_support_format_tar.c + libarchive/archive_string.c + libarchive/archive_string_sprintf.c + libarchive/archive_util.c + libarchive/archive_virtual.c + libarchive/archive_write.c + libarchive/archive_write_add_filter.c + libarchive/archive_write_add_filter_b64encode.c + libarchive/archive_write_add_filter_by_name.c + libarchive/archive_write_add_filter_bzip2.c + libarchive/archive_write_add_filter_gzip.c + libarchive/archive_write_add_filter_none.c + libarchive/archive_write_add_filter_program.c + libarchive/archive_write_add_filter_xz.c + libarchive/archive_write_disk_set_standard_lookup.c + libarchive/archive_write_open_fd.c + libarchive/archive_write_open_file.c + libarchive/archive_write_open_filename.c + libarchive/archive_write_open_memory.c + libarchive/archive_write_set_format.c + libarchive/archive_write_set_format_by_name.c + libarchive/archive_write_set_format_gnutar.c + libarchive/archive_write_set_format_ustar.c + libarchive/archive_write_set_options.c + INCLUDE_DIRECTORIES + libarchive + . + PUBLIC_INCLUDE_DIRECTORIES + $ +) +qt_disable_warnings(BundledLibArchive) +qt_set_symbol_visibility_hidden(BundledLibArchive) + +qt_internal_extend_target(BundledLibArchive CONDITION MACOS + DEFINES + PLATFORM_CONFIG_H=\\\"config-macos.h\\\" + PUBLIC_LIBRARIES + ${FWCoreServices} + Iconv::Iconv +) + +qt_internal_extend_target(BundledLibArchive CONDITION IOS + PUBLIC_LIBRARIES + Iconv::Iconv +) + +qt_internal_extend_target(BundledLibArchive CONDITION WIN32 + SOURCES + libarchive/archive_entry_copy_bhfi.c + libarchive/archive_read_disk_windows.c + libarchive/archive_windows.c + libarchive/archive_write_disk_windows.c + libarchive/filter_fork_windows.c + DEFINES + PLATFORM_CONFIG_H=\\\"config-windows.h\\\" + PUBLIC_DEFINES + LIBARCHIVE_STATIC + PUBLIC_LIBRARIES + advapi32 + crypt32 +) + +#### Keys ignored in scope 6:.:.:libarchive.pro:win32-msvc_x_: +# QMAKE_CFLAGS = "/wd4146" "/wd4133" "/D_CRT_SECURE_NO_WARNINGS" + +#### Keys ignored in scope 7:.:.:libarchive.pro:GCC: +# QMAKE_CFLAGS = "-Wno-unused" "-Wno-sign-compare" "-Wno-old-style-declaration" + +#### Keys ignored in scope 8:.:.:libarchive.pro:CLANG: +# QMAKE_CFLAGS = "-Wall" "-W" "-Wno-unused" "-Wno-sign-compare" + +qt_internal_extend_target(BundledLibArchive CONDITION ANDROID + DEFINES + PLATFORM_CONFIG_H=\\\"config-android.h\\\" +) + +qt_internal_extend_target(BundledLibArchive CONDITION IOS AND NOT MACOS + DEFINES + PLATFORM_CONFIG_H=\\\"config-ios.h\\\" +) + +qt_internal_extend_target(BundledLibArchive CONDITION UNIX AND NOT ANDROID AND NOT IOS AND NOT MACOS + DEFINES + PLATFORM_CONFIG_H=\\\"config-unix.h\\\" +) + +qt_internal_extend_target(BundledLibArchive CONDITION UNIX + SOURCES + libarchive/archive_read_disk_posix.c + libarchive/archive_write_disk_posix.c + libarchive/filter_fork_posix.c +) + +if (QT_FEATURE_system_zlib) + find_package(ZLIB) + + qt_internal_extend_target(BundledLibArchive + LIBRARIES + ZLIB::ZLIB + ) +else() + qt_internal_extend_target(BundledLibArchive + LIBRARIES + Qt::Core + Qt::ZlibPrivate + ) +endif() diff --git a/src/3rdparty/libarchive/COPYING b/src/3rdparty/libarchive/COPYING new file mode 100644 index 00000000..93952b77 --- /dev/null +++ b/src/3rdparty/libarchive/COPYING @@ -0,0 +1,59 @@ +The libarchive distribution as a whole is Copyright by Tim Kientzle +and is subject to the copyright notice reproduced at the bottom of +this file. + +Each individual file in this distribution should have a clear +copyright/licensing statement at the beginning of the file. If any do +not, please let me know and I will rectify it. The following is +intended to summarize the copyright status of the individual files; +the actual statements in the files are controlling. + +* Except as listed below, all C sources (including .c and .h files) + and documentation files are subject to the copyright notice reproduced + at the bottom of this file. + +* The following source files are also subject in whole or in part to + a 3-clause UC Regents copyright; please read the individual source + files for details: + libarchive/archive_entry.c + libarchive/archive_read_support_filter_compress.c + libarchive/archive_write_add_filter_compress.c + libarchive/mtree.5 + +* The following source files are in the public domain: + libarchive/archive_getdate.c + +* The build files---including Makefiles, configure scripts, + and auxiliary scripts used as part of the compile process---have + widely varying licensing terms. Please check individual files before + distributing them to see if those restrictions apply to you. + +I intend for all new source code to use the license below and hope over +time to replace code with other licenses with new implementations that +do use the license below. The varying licensing of the build scripts +seems to be an unavoidable mess. + + +Copyright (c) 2003-2009 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer + in this position and unchanged. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/3rdparty/libarchive/INSTALL b/src/3rdparty/libarchive/INSTALL new file mode 100644 index 00000000..2fafbd50 --- /dev/null +++ b/src/3rdparty/libarchive/INSTALL @@ -0,0 +1,35 @@ +More complete build documentation is available on the libarchive +Wiki: https://github.com/libarchive/libarchive/wiki + +On most Unix-like systems, you should be able to install libarchive, +bsdtar, and bsdcpio using the following common steps: + ./configure + make + make install + +If you need to customize the target directories or otherwise adjust +the build setting, use + ./configure --help +to list the configure options. + +If you are developing libarchive and need to update the +configure script and other build files: + /bin/sh build/autogen.sh + +To create a distribution, please use the 'distcheck' target: + /bin/sh build/autogen.sh && ./configure && make distcheck + +On Unix-like and non-Unix-like systems, use the "cmake" utility (available from +http://cmake.org/) to generate suitable build files for your platform. +Cmake requires the name of the directory containing CmakeLists.txt and +the "generator" to use for your build environment. For example, to +build with Xcode on Mac OS, you can use the following command: + cmake -G "Xcode" ~/libarchive-download-dir/ +The result will be appropriate makefiles, solution files, or project +files that can be used with the corresponding development tool. +The default on Unix-like systems is to generate Makefiles, so you +can also use cmake instead of the configure script: + cmake ~/libarchive-download-dir/ + make + make install +See the libarchive Wiki or the cmake site for further documentation. diff --git a/src/3rdparty/libarchive/NEWS b/src/3rdparty/libarchive/NEWS new file mode 100644 index 00000000..9527e662 --- /dev/null +++ b/src/3rdparty/libarchive/NEWS @@ -0,0 +1,687 @@ +Jul 09, 2017: libarchive 3.3.2 released + +Mar 16, 2017: NFSv4 ACL support for Linux (librichacl) + +Feb 26, 2017: libarchive 3.3.1 released + Security & Feature release + +Feb 19, 2017: libarchive 3.3.0 released + Security & Feature release + +Jan 29, 2017: Limited NFSv4 ACL support for Mac OS (Darwin) + +Jan 10, 2017: POSIX.1e and NFSv4 ACL support for Solaris and derivates + +Dec 27, 2016: NFSv4 ACL read and write support for pax + Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w() + +Nov, 2016: libarchive is now being tested by the OSS-Fuzz project + +Oct 26, 2016: Remove liblzmadec support + +Oct 23, 2016: libarchive 3.2.2 released + Security release + +Jun 20, 2016: libarchive 3.2.1 released + This fixes a handful of security and other critical issues with 3.2.0 + +May 01, 2016: libarchive 3.2.0 released + +Apr 09, 2016: libarchive 3.1.901a released + Another test release in preparation for 3.2.0 + +Feb 13, 2016: libarchive 3.1.900a released + This is a test release in preparation for 3.2.0 + +Oct 21, 2015: Preliminary port to OSF + +Apr 11, 2015: libarchive's issue tracker is now hosted at GitHub. + https://github.com/libarchive/libarchive/issues + +Early 2015: Many fixes to crash and overflow bugs thanks to Hanno Boeck + +Oct 13, 2014: Zip encryption and decryption support + +Aug 13, 2014: Add support for lz4 compression. + +Jun 10, 2014: Add warc format support + +May 3, 2014: Add experimental Zip streaming extension + +Apr 6, 2014: Add bsdcat command-line tool + +Jan 12, 2014: Add Zip64 support + +Dec 1, 2013: Rewrite Zip write logic + +Jul 1, 2013: Add ability to detect encrypted entries for many formats + (This does not add the ability to *decrypt* those entries, however) + +Feb 23, 2013: "raw" write support added + +Feb 09, 2013: libarchive 3.1.2 released + +Jan 28, 2013: libarchive's new website moved to http://www.libarchive.org. + +Jan 13, 2013: libarchive 3.1.1 released + +Jan 13, 2013: libarchive 3.1.0 released + +Dec 07, 2012: Implement functions to manually set the format and filters used. + +Nov 11, 2012: Add support for __MACOSX directory in Zip archives, which resource + forks are stored in. + +Oct 20, 2012: Add support for writing v7 tar format. + +Oct 09, 2012: Add support for grzip compression. + +Oct 07, 2012: Introduce b64encode filter. +Oct 07, 2012: Introduce uuencode filter. + +Oct 06, 2012: Add support for lzop. + +Sep 27, 2012: Implement function used to seek within data blocks. + (Currently only supported for uncompressed RAR archives). + +Apr 22, 2012: Add basic archive read and write filter support for lrzip. + +Mar 27, 2012: libarchive 3.0.4 released + +Feb 05, 2012: libarchive development now hosted at GitHub. + http://libarchive.github.com/ +Feb 05, 2012: libarchive's issue tracker remains at Google Code. + http://code.google.com/p/libarchive/issues/list +Feb 05, 2012: libarchive's mailing lists remain at Google Groups. + +Dec 24, 2011: libarchive 3.0.2 released +Dec 23, 2011: Various fixes merged from FreeBSD +Dec 23, 2011: Symlink support in Zip reader and writer +Dec 23, 2011: Robustness fixes to 7Zip reader + +Nov 27, 2011: libarchive 3.0.1b released + +Nov 26, 2011: 7Zip reader +Nov 26, 2011: Small fixes to ISO and Zip to improve robustness with corrupted input +Nov 24, 2011: Improve streaming Zip reader's support for uncompressed entries +Nov 20, 2011: New seeking Zip reader supports SFX Zip archives +Nov 20, 2011: Build fixes on Windows + +Nov 13, 2011: libarchive 3.0.0a released + +Nov 06, 2011: Update shared-library version calculations for libarchive 3.x +Sep 04, 2011: Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions +Aug 18, 2011: Fix reading ISO images built by NetBSD's mkisofs +Aug 15, 2011: Old archive_read_support_compression_XXX functions are deprecated and + will disappear in libarchive 4.0. +Jun 26, 2011: RAR reader +Jun 16, 2011: Add tar:compat-2x option to emulate broken libarchive 2.x + handling of pax UTF-8 headers +Apr 25, 2011: Refactor read_open() into a collection of single-item setters; + support the old interfaces as wrappers +Apr 12, 2011: Split disk writer into separate POSIX and Windows implementations +Apr 10, 2011: Improvements to character translations on Windows. +Mar 30, 2011: More work to return errors instead of calling abort() +Mar 23, 2011: Add charset option to many writers to control MBCS filenames +Mar 17, 2011: Overhauled support for per-format extension options +Mar 17, 2011: Track character set used for mbcs strings, support + translating to/from user-specified locale +Mar 09, 2011: Recognize mtree files without requiring a signature +Mar 06, 2011: Use iconv to convert to/from Unicode instead of making bad + assumptions about the C90 character set translation functions +Feb 17, 2011: Fixes for AIX, TRU64, and other platforms +Dec 22, 2010: CAB reader +Dec 20, 2010: LHA/LZH reader +Jul 03, 2010: minitar example demonstrates archive_read_disk directory traversal +Jun 29, 2010: Many improvements to ISO reader compatibility +Jun 26, 2010: Use larger buffers when copy files into an archive +Jun 18, 2010: Reimplement Mac OS extensions in libarchive +Jun 09, 2010: archive_read_disk now supports traversals +May 28, 2010: XAR writer +May 16, 2010: Fix ^T handling; don't exit on interrupted reads and writes +May 09, 2010: Improved detection of platform-specific crypto support +May 04, 2010: lzip read and write filters +May 01, 2010: New options: tar --gid --gname --uid --uname +Apr 28, 2010: Use Red-black tree for ISO reader/writer to improve performance +Apr 17, 2010: Minimal writer for legacy GNU tar format +Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs. +Mar 06, 2010: Fix build when an older libarchive is already installed +Feb 28, 2010: Relax handling of state failures; misuse by clients now generally + results in a sticky ARCHIVE_FATAL rather than a visit to abort() +Feb 25, 2010: ISO writer +Feb 21, 2010: Split many man pages into smaller chunks. +Feb 21, 2010: Performance: Cheat on block sizes when reading archives from disk. +Feb 21, 2010: Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t +Feb 20, 2010: Document new ACL functions. +Feb 19, 2010: Support multiple write filters +Feb 07, 2010: Remove some legacy libarchive 1.x APIs +Feb 04, 2010: Read afio headers +Feb 02, 2010: Archive sparse files compatibly with GNU tar +Feb 01, 2010: Integrate Apple extensions for Mac OS extended attributes into bsdtar +Jan 31, 2010: Support cpio -V + +Feb 04, 2010: libarchive 2.8.0 released +Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o' +Jan 17, 2010: Don't use futimes() on Cygwin + +Jan 02, 2010: libarchive 2.7.902a released (test release for 2.8) +Jan 02, 2010: Fix tar/test/test_windows on MinGW +Jan 02, 2010: Fix memory leaks in libarchive tests +Jan 01, 2010: Fix memory leak when filter startup fails + +Dec 27, 2009: libarchive 2.7.901a released (test release for 2.8) + +Aug 04, 2009: libarchive 2.7.1 released +Jul 20, 2009: Suppress bogus warning about unxz +Jul 19, 2009: Support Cygwin 1.7 +Jun 11, 2009: Support lzma/xz files compressed with larger buffer sizes. +May 24, 2009: Handle gzip files signed with OpenBSD "gzsig" program. +May 07, 2009: Avoid false failures when reading from pipe. + +Apr 16, 2009: libarchive 2.7.0 released + +Apr 10, 2009: libarchive 2.6.992a released +Apr 09, 2009: Fix SIGPIPE issue building with MSVC. +Apr 09, 2009: Fix several minor memory leaks in libarchive and libarchive_test + +Apr 08, 2009: libarchive 2.6.991a released +Apr 07, 2009: Additional tests added to bsdcpio_test + +Apr 01, 2009: libarchive 2.6.990a released +Apr 01, 2009: Use command-line gunzip, bunzip2, unxz, unlzma for + decompression if the library is built without suitable + libraries. The setup functions return ARCHIVE_WARN + in this case so clients can adapt if necessary. +Apr 01, 2009: Use getpw*_r and getgr*_r functions for thread-safety. +Mar 24, 2009: Add archive_read_next_header2(), which is up to 25% + more efficient for some clients; from Brian Harring. +Mar 22, 2009: PDF versions of manpages are now included in the distribution. +Mar, 2009: Major work to improve Cygwin build by Charles Wilson. +Feb/Mar, 2009: Major work on cmake build support, mostly by Michihiro NAKAJIMA. +Feb/Mar, 2009: Major work on Visual Studio support by Michihiro NAKAJIMA. + All tests now pass. +Feb 25, 2009: Fix Debian Bug #516577 +Feb 21, 2009: Yacc is no longer needed to build; date parser rewritten in C. +Jan/Feb, 2009: Mtree work by Michihiro. +Feb, 2009: Joliet support by Andreas Henriksson. +Jan/Feb, 2009: New options framework by Michihiro. +Feb, 2009: High-res timestamps on Tru64, AIX, and GNU Hurd, by Björn Jacke. +Jan 18, 2009: Extended attributes work on FreeBSD and Linux now with pax format. +Jan 07, 2009: New archive_read_disk_entry_from_file() knows about ACLs, + extended attributes, etc so that bsdtar and bsdcpio don't require + such system-specific knowledge. +Jan 03, 2009: Read filter system extensively refactored. In particular, + read filter pipelines are now built out automatically and individual + filters should be much easier to implement. Documentation on the + Googlecode Wiki explains how to implement new filters. +Dec 28, 2008: Many Windows/Visual Studio fixes from Michihiro NAKAJIMA. + +Dec 28, 2008: Main libarchive development moved from FreeBSD Perforce + server to Google Code. This should make it easier for more + people to participate in libarchive development. + +Dec 28, 2008: libarchive 2.6.0 released +Dec 25, 2008: libarchive 2.5.905a released +Dec 10, 2008: libarchive 2.5.904a released +Dec 04, 2008: libarchive 2.5.903a released +Nov 09, 2008: libarchive 2.5.902a released +Nov 08, 2008: libarchive 2.5.901a released +Nov 08, 2008: Start of pre-release testing for libarchive 2.6 + +Nov 07, 2008: Read filter refactor: The decompression routines just + consume and produce arbitrarily-sized blocks. The reblocking + from read_support_compression_none() has been pulled into the + read core. Also, the decompression bid now makes multiple + passes and stacks read filters. +Oct 21, 2008: bsdcpio: New command-line parser. +Oct 19, 2008: Internal read_ahead change: short reads are now an error +Oct 06, 2008: bsdtar: option parser no longer uses getopt_long(), + gives consistent option parsing on all platforms. +Sep 19, 2008: Jaakko Heinonen: shar utility built on libarchive +Sep 17, 2008: Pedro Giffuni: birthtime support +Sep 17, 2008: Miklos Vajna: lzma reader and test. Note: I still have + some concerns about the auto-detection (LZMA file format + doesn't support auto-detection well), so this is not yet + enabled under archive_read_support_compression_all(). For + now, you must call archive_read_support_compression_lzma() if + you want LZMA read support. +Sep 11, 2008: Ivailo Petrov: Many fixes to Windows build, new solution files +Jul 26, 2008: archive_entry now tracks which values have not been set. + This helps zip extraction (file size is often "unknown") and + time restores (tar usually doesn't know atime). +Jul 26, 2008: Joerg Sonnenberger: Performance improvements to shar writer +Jul 25, 2008: Joerg Sonnenberger: mtree write support + +Jul 02, 2008: libarchive 2.5.5 released + +Jul 02, 2008: libarchive 2.5.5b released +Jul 01, 2008: bsdcpio is being used by enough people, we can call it 1.0.0 now +Jun 20, 2008: bsdcpio: If a -l link fails with EXDEV, copy the file instead +Jun 19, 2008: bsdcpio: additional long options for better GNU cpio compat +Jun 15, 2008: Many small portability and bugfixes since 2.5.4b. + +May 25, 2008: libarchive 2.5.4b released +May 21, 2008: Joerg Sonnenberger: fix bsdtar hardlink handling for newc format + +May 21, 2008: More progress on Windows building. Thanks to "Scott" + for the Windows makefiles, thanks to Kees Zeelenberg for + code contributions. + +May 21, 2008: Fix a number of non-exploitable integer and buffer overflows, + thanks to David Remahl at Apple for pointing these out. + +May 21, 2008: Colin Percival: SIGINFO or SIGUSR1 to bsdtar prints progress info + +May 16, 2008: bsdtar's test harness no longer depends on file ordering. + This was causing spurious test failures on a lot of systems. + Thanks to Bernhard R. Link for the diagnosis. + +May 14, 2008: Joerg Sonnenberger: -s substitution support for bsdtar + +May 13, 2008: Joerg Sonnenberger: Many mtree improvements + +May 11, 2008: Joerg Sonnenberger: fix hardlink extraction when + hardlinks have different permissions from original file + +April 30, 2008: Primary libarchive work has been moved into the FreeBSD + project's Perforce repository: http://perforce.freebsd.org/ + The libarchive project can be browsed at + //depot/user/kientzle/libarchive-portable + Direct link: http://preview.tinyurl.com/46mdgr + +May 04, 2008: libarchive 2.5.3b released + * libarchive: Several fixes to link resolver to address bsdcpio crashes + * bsdcpio: -p hardlink handling fixes + * tar/pax: Ensure ustar dirnames end in '/'; be more careful about + measuring filenames when deciding what pathname fields to use + * libarchive: Mark which entry strings are set; be accurate about + distinguishing empty strings ("") from unset ones (NULL) + * tar: Don't crash reading entries with empty filenames + * libarchive_test, bsdtar_test, bsdcpio_test: Better defaults: + run all tests, delete temp dirs, summarize repeated failures + * -no-undefined to libtool for Cygwin + * libarchive_test: Skip large file tests on systems with 32-bit off_t + * iso9660: Don't bother trying to find the body of an empty file; + this works around strange behavior from some ISO9660 writers + * tar: allow -r -T to be used together + * tar: allow --format with -r or -u + * libarchive: Don't build archive.h + +May 04, 2008: Simplified building: archive.h is no longer constructed + This may require additional #if conditionals on some platforms. + +Mar 30, 2008: libarchive 2.5.1b released + +Mar 15, 2008: libarchive 2.5.0b released +Mar 15, 2008: bsdcpio now seems to correctly write hardlinks into newc, + ustar, and old cpio archives. Just a little more testing before + bsdcpio 1.0 becomes a reality. +Mar 15, 2008: I think the new linkify() interface is finally handling + all known hardlink strategies. +Mar 15, 2008: Mtree read fixes from Joerg Sonnenberger. +Mar 15, 2008: Many new bsdtar and bsdcpio options from Joerg Sonnenberger. +Mar 15, 2008: test harnesses no longer require uudecode; they + now have built-in decoding logic that decodes the reference + files as they are needed. + +Mar 14, 2008: libarchive 2.4.14 released; identical to 2.4.13 except for + a point fix for gname/uname mixup in pax format that was introduced + with the UTF-8 fixes. + +Feb 26, 2008: libarchive 2.4.13 released +Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted + to/from UTF-8. Implement "hdrcharset" attribute from SUS-2008. +Feb 25, 2008: Fix name clash on NetBSD. +Feb 18, 2008: Fix writing empty 'ar' archives, per Kai Wang +Feb 18, 2008: [bsdtar] Permit appending on block devices. +Feb 09, 2008: New "linkify" resolver to help with newc hardlink writing; + bsdcpio still needs to be converted to use this. +Feb 02, 2008: Windows compatibility fixes from Ivailo Petrov, Kees Zeelenberg +Jan 30, 2008: Ignore hardlink size for non-POSIX tar archives. + +Jan 22, 2008: libarchive 2.4.12 released +Jan 22, 2008: Fix bad padding when writing symlinks to newc cpio archives. +Jan 22, 2008: Verify bsdcpio_test by getting it to work against GNU cpio 2.9. + bsdcpio_test complains about missing options (-y and -z), format + of informational messages (--version, --help), and a minor formatting + issue in odc format output. After this update, bsdcpio_test uncovered + several more cosmetic issues in bsdcpio, all now fixed. +Jan 22, 2008: Experimental support for self-extracting Zip archives. +Jan 22, 2008: Extend hardlink restore strategy to work correctly with + hardlinks extracted from newc cpio files. (Which store the body + only with the last occurrence of a link.) + +Dec 30, 2007: libarchive 2.4.11 released +Dec 30, 2007: Fixed a compile error in bsdcpio on some systems. + +Dec 29, 2007: libarchive 2.4.10 released +Dec 29, 2007: bsdcpio 0.9.0 is ready for wider use. +Dec 29, 2007: Completed initial test harness for bsdcpio. + +Dec 22, 2007: libarchive 2.4.9 released +Dec 22, 2007: Implement the remaining options for bsdcpio: -a, -q, -L, -f, + pattern selection for -i and -it. + +Dec 13, 2007: libarchive 2.4.8 released +Dec 13, 2007: gzip and bzip2 compression now handle zero-byte writes correctly, + Thanks to Damien Golding for bringing this to my attention. + +Dec 12, 2007: libarchive 2.4.7 released + +Dec 10, 2007: libarchive 2.4.6 released +Dec 09, 2007: tar/test/test_copy.c verifies "tar -c | tar -x" copy pipeline +Dec 07, 2007: Fix a couple of minor memory leaks. + +Dec 04, 2007: libarchive 2.4.5 released +Dec 04, 2007: Fix cpio/test/test_write_odc by setting the umask first. + +Dec 03, 2007: libarchive 2.4.4 released +Dec 03, 2007: New configure options --disable-xattr and --disable-acl, + thanks to Samuli Suominen. + +Dec 03, 2007: libarchive 2.4.3 released +Dec 03, 2007: Thanks to Lapo Luchini for sending me a ZIP file that + libarchive couldn't handle. Fixed a bug in handling of + "length at end" flags in ZIP files. +Dec 03, 2007: Fixed bsdcpio -help, bsdtar -help tests. +Dec 02, 2007: First cut at real bsdtar test harness. + +Dec 02, 2007: libarchive 2.4.2 released + +Dec 02, 2007: libarchive 2.4.1 released +Dec 02, 2007: Minor fixes, rough cut of mdoc-to-man conversion for + man pages. + +Oct 30, 2007: libarchive 2.4.0 released +Oct 30, 2007: Minor compile fix thanks to Joerg Schilling. +Oct 30, 2007: Only run the format auction once at the beginning of the + archive. This is simpler and supports better error recovery. +Oct 29, 2007: Test support for very large entries in tar archives: + libarchive_test now exercises entries from 2GB up to 1TB. + +Oct 27, 2007: libarchive 2.3.5 released +Oct 27, 2007: Correct some unnecessary internal data copying in the + "compression none" reader and writer; this reduces user time + by up to 2/3 in some tests. (Thanks to Jan Psota for + publishing his performance test results to GNU tar's bug-tar + mailing list; those results pointed me towards this problem.) +Oct 27, 2007: Fix for skipping archive entries that are exactly + a multiple of 4G on 32-bit platforms. +Oct 25, 2007: Fix for reading very large (>8G) tar archives; this was + broken when I put in support for new GNU tar sparse formats. +Oct 20, 2007: Initial work on new pattern-matching code for cpio; I + hope this eventually replaces the code currently in bsdtar. + +Oct 08, 2007: libarchive 2.3.4 released +Oct 05, 2007: Continuing work on bsdcpio test suite. +Oct 05, 2007: New cpio.5 manpage, updates to "History" of bsdcpio.1 and + bsdtar.1 manpages. +Oct 05, 2007: Fix zip reader to immediately return EOF if you try + to read body of non-regular file. In particular, this fixes + bsdtar extraction of zip archives. + +Sep 30, 2007: libarchive 2.3.3 released +Sep 26, 2007: Rework Makefile.am so that the enable/disable options + actually do the right things. +Sep 26, 2007: cpio-odc and cpio-newc archives no longer write bodies + for non-regular files. +Sep 26, 2007: Test harness for bsdcpio is in place, needs more tests written. + This is much nicer than the ragtag collection of test scripts + that bsdtar has. + +Sep 20, 2007: libarchive 2.3.2 released +Sep 20, 2007: libarchive 2.3.1 broke bsdtar because the archive_write_data() + fix was implemented incorrectly. + +Sep 16, 2007: libarchive 2.3.1 released +Sep 16, 2007: Many fixes to bsdcpio 0.3: handle hardlinks with -p, recognize + block size on writing, fix a couple of segfaults. +Sep 16, 2007: Fixed return value from archive_write_data() when used + with archive_write_disk() to match the documentation and other + instances of this same function. +Sep 15, 2007: Add archive_entry_link_resolver, archive_entry_strmode + +Sep 11, 2007: libarchive 2.2.8 released +Sep 09, 2007: bsdcpio 0.2 supports most (not yet all) of the old POSIX spec. + +Sep 01, 2007: libarchive 2.2.7 released +Aug 31, 2007: Support for reading mtree files, including an mtree.5 manpage + (A little experimental still.) +Aug 18, 2007: Read gtar 1.17 --posix --sparse entries. +Aug 13, 2007: Refined suid/sgid restore handling; it is no longer + an error if suid/sgid bits are dropped when you request + perm restore but don't request owner restore. +Aug 06, 2007: Use --enable-bsdcpio if you want to try bsdcpio + +Aug 05, 2007: libarchive 2.2.6 released +Aug 05, 2007: New configure option --disable-bsdtar, thanks to Joerg + Sonnenberger. +Aug 05, 2007: Several bug fixes from FreeBSD CVS repo. + +Jul 13, 2007: libarchive 2.2.5 released + +Jul 12, 2007: libarchive 2.2.4 released +Jul 12, 2007: Thanks to Colin Percival's help in diagnosing and + fixing several critical security bugs. Details available at + http://security.freebsd.org/advisories/FreeBSD-SA-07:05.libarchive.asc + +May 26, 2007: libarchive 2.2.3 released +May 26, 2007: Fix memory leaks in ZIP reader and shar writer, add some + missing system headers to archive_entry.h, dead code cleanup + from Colin Percival, more tests for gzip/bzip2, fix an + EOF anomaly in bzip2 decompression. + +May 12, 2007: libarchive 2.2.2 released +May 12, 2007: Fix archive_write_disk permission restore by cloning + entry passed into write_header so that permission info is + still available at finish_entry time. (archive_read_extract() + worked okay because it held onto the passed-in entry, but + direct consumers of archive_write_disk would break). This + required fixing archive_entry_clone(), which now works and has + a reasonably complete test case. +May 10, 2007: Skeletal cpio implementation. + +May 06, 2007: libarchive 2.2.1 released +May 06, 2007: Flesh out a lot more of test_entry.c so as to catch + problems such as the device node breakage before releasing . +May 05, 2007: Fix a bad bug introduced in 2.1.9 that broke device + node entries in tar archives. +May 03, 2007: Move 'struct stat' out of archive_entry core as well. + This removes some portability headaches and fixes a bunch + of corner cases that arise when manipulating archives on + dissimilar systems. + +Apr 30, 2007: libarchive 2.1.10 released +Apr 31, 2007: Minor code cleanup. + +Apr 24, 2007: libarchive 2.1.9 released +Apr 24, 2007: Fix some recently-introduced problems with libraries + (Just let automake handle it and it all works much better.) + Finish isolating major()/minor()/makedev() in archive_entry.c. + +Apr 23, 2007: libarchive 2.1.8 released +Apr 23, 2007: Minor fixes found from building on MacOS X + +Apr 22, 2007: libarchive 2.1.7 released +Apr 22, 2007: Eliminated all uses of 'struct stat' from the + format readers/writers. This should improve portability; + 'struct stat' is now only used in archive_entry and in + code that actually touches the disk. + +Apr 17, 2007: libarchive 2.1.6 released + Libarchive now compiles and passes all tests on Interix. + +Apr 16, 2007: libarchive 2.1.5 released + +Apr 15, 2007: libarchive 2.1b2 released +Apr 15, 2007: New libarchive_internals.3 documentation of internal APIs. + Not complete, but should prove helpful. +Apr 15, 2007: Experimental "read_compress_program" and "write_compress_program" + for using libarchive with external compression. Not yet + well tested, and likely has portability issues. Feedback + appreciated. + +Apr 14, 2007: libarchive 2.0.31 released +Apr 14, 2007: More fixes for Interix, more 'ar' work + +Apr 14, 2007: libarchive 2.0.30 released +Apr 13, 2007: libarchive now enforces trailing '/' on dirs + written to tar archives + +Apr 11, 2007: libarchive 2.0.29 released +Apr 11, 2007: Make it easier to statically configure for different platforms. +Apr 11, 2007: Updated config.guess, config.sub, libtool + +Apr 06, 2007: libarchive 2.0.28 released +Apr 06, 2007: 'ar' format read/write support thanks to Kai Wang. + +Apr 01, 2007: libarchive 2.0.27 released +Mar 31, 2007: Several minor fixes from Colin Percival and Joerg Sonnenberger. + +Mar 12, 2007: libarchive 2.0.25 released +Mar 12, 2007: Fix broken --unlink flag. + +Mar 11, 2007: libarchive 2.0.24 released +Mar 10, 2007: Correct an ACL blunder that causes any ACL with an entry + that refers to a non-existent user or group to not be restored correctly. + The fix both makes the parser more tolerant (so that archives created + with the buggy ACLs can be read now) and corrects the ACL formatter. +Mar 10, 2007: More work on test portability to Linux. + +Mar 10, 2007: libarchive 2.0.22 released +Mar 10, 2007: Header cleanups; added linux/fs.h, removed + some unnecessary headers, added #include guards in bsdtar. + If you see any obvious compile failures from this, let me know. +Mar 10, 2007: Work on bsdtar test scripts: not yet robust enough + to enable as part of "make check", but getting better. +Mar 10, 2007: libarchive now returns ARCHIVE_FAILED when + a header write fails in a way that only affects this item. + Less bad than ARCHIVE_FATAL, but worse than ARCHIVE_WARN. + +Mar 07, 2007: libarchive 2.0.21 released +Mar 07, 2007: Add some ACL tests (only for the system-independent + portion of the ACL support for now). +Mar 07, 2007: tar's ability to read ACLs off disk got + turned off for FreeBSD; re-enable it. (ACL restores and + libarchive support for storing/reading ACLs from pax + archives was unaffected.) + +Mar 02, 2007: libarchive 2.0.20 released +Mar 2, 2007: It's not perfect, but it's pretty good. + Libarchive 2.0 is officially out of beta. + +Feb 28, 2007: libarchive 2.0b17 released +Feb 27, 2007: Make the GID restore checks more robust by checking + whether the current user has too few or too many privileges. + +Feb 26, 2007: libarchive 2.0b15 released +Feb 26, 2007: Don't lose symlinks when extracting from ISOs. + Thanks to Diego "Flameeyes" Pettenò for telling me about the + broken testcase on Gentoo that (finally!) led me to the cause + of this long-standing bug. + +Feb 26, 2007: libarchive 2.0b14 released +Feb 26, 2007: Fix a broken test on platforms that lack lchmod(). + +Feb 25, 2007: libarchive 2.0b13 released +Feb 25, 2007: Empty archives were being written as empty files, + without a proper end-of-archive marker. Fixed. + +Feb 23, 2007: libarchive 2.0b12 released +Feb 22, 2007: Basic security checks added: _EXTRACT_SECURE_NODOTDOT + and _EXTRACT_SECURE_SYMLINK. These checks used to be in bsdtar, + but they belong down in libarchive where they can be used by + other tools and where they can be better optimized. + +Feb 11, 2007: libarchive 2.0b11 released +Feb 10, 2007: Fixed a bunch of errors in libarchive's handling + of EXTRACT_PERM and EXTRACT_OWNER, especially relating + to SUID and SGID bits. + +Jan 31, 2007: libarchive 2.0b9 released +Jan 31, 2007: Added read support for "empty" archives as a + distinct archive format. Bsdtar uses this to handle, e.g., + "touch foo.tar; tar -rf foo.tar" + +Jan 22, 2007: libarchive 2.0b6 released +Jan 22, 2007: archive_write_disk API is now in place. It provides + a finer-grained interface than archive_read_extract. In particular, + you can use it to create objects on disk without having an archive + around (just feed it archive_entry objects describing what you + want to create), you can override the uname/gname-to-uid/gid lookups + (minitar uses this to avoid getpwXXX() and getgrXXX() bloat). + +Jan 09, 2007: libarchive 2.0a3 released +Jan 9, 2007: archive_extract is now much better; it handles the + most common cases with a minimal number of system calls. + Some features still need a lot of testing, especially corner + cases involving objects that already exist on disk. I expect + the next round of API overhaul will simplify building test cases. +Jan 9, 2007: a number of fixes thanks to Colin Percival, especially + corrections to the skip() framework and handling of large files. +Jan 9, 2007: Fixes for large ISOs. The code should correctly handle + very large ISOs with entries up to 4G. Thanks to Robert Sciuk + for pointing out these issues. + +Sep 05, 2006: libarchive 1.3.1 released +Sep 5, 2006: Bump version to 1.3 for new I/O wrappers. +Sep 4, 2006: New memory and FILE read/write wrappers. +Sep 4, 2006: libarchive test harness is now minimally functional; + it's located a few minor bugs in error-handling logic + +Aug 17, 2006: libarchive 1.2.54 released +Aug 17, 2006: Outline ABI changes for libarchive 2.0; these + are protected behind #ifdef's until I think I've found everything + that needs to change. +Aug 17, 2006: Fix error-handling in archive_read/write_close() + They weren't returning any errors before. +Aug 17, 2006: Fix recursive-add logic to not trigger if it's not set + Fixes a bug adding files when writing archive to pipe or when + using archive_write_open() directly. +Jul 2006: New "skip" handling improves performance extracting + single files from large uncompressed archives. + +Mar 21, 2006: 1.2.52 released +Mar 21, 2006: Fix -p on platforms that don't have platform-specific + extended attribute code. +Mar 20, 2006: Add NEWS file; fill in some older history from other + files. I'll try to keep this file up-to-date from now on. + +OLDER NEWS SUMMARIES + +Mar 19, 2006: libarchive 1.2.51 released +Mar 18, 2006: Many fixes to extended attribute support, including a redesign + of the storage format to simplify debugging. +Mar 12, 2006: Remove 'tp' support; it was a fun idea, but not worth + spending much time on. +Mar 11, 2006: Incorporated Jaakko Heinonen's still-experimental support + for extended attributes (Currently Linux-only.). +Mar 11, 2006: Reorganized distribution package: There is now one tar.gz + file that builds both libarchive and bsdtar. +Feb 13, 2006: Minor bug fixes: correctly read cpio device entries, write + Pax attribute entry names. +Nov 7, 2005: Experimental 'tp' format support in libarchive. Feedback + appreciated; this is not enabled by archive_read_support_format_all() + yet as I'm not quite content with the format detection heuristics. +Nov 7, 2005: Some more portability improvements thanks to Darin Broady, + minor bugfixes. +Oct 12, 2005: Use GNU libtool to build shared libraries on many systems. +Aug 9, 2005: Correctly detect that MacOS X does not have POSIX ACLs. +Apr 17, 2005: Kees Zeelenberg has ported libarchive and bsdtar to Windows: + http://gnuwin32.sourceforge.net/ +Apr 11, 2005: Extended Zip/Zip64 support thanks to Dan Nelson. -L/-h + fix from Jaakko Heinonen. +Mar 12, 2005: archive_read_extract can now handle very long + pathnames (I've tested with pathnames up to 1MB). +Mar 12, 2005: Marcus Geiger has written an article about libarchive + http://xsnil.antbear.org/2005/02/05/archive-mit-libarchive-verarbeiten/ + including examples of using it from Objective-C. His MoinX + http://moinx.antbear.org/ desktop Wiki uses + libarchive for archiving and restoring Wiki pages. +Jan 22, 2005: Preliminary ZIP extraction support, + new directory-walking code for bsdtar. +Jan 16, 2005: ISO9660 extraction code added; manpage corrections. +May 22, 2004: Many gtar-compatible long options have been added; almost + all FreeBSD ports extract correctly with bsdtar. +May 18, 2004: bsdtar can read Solaris, HP-UX, Unixware, star, gtar, + and pdtar archives. diff --git a/src/3rdparty/libarchive/README.md b/src/3rdparty/libarchive/README.md new file mode 100644 index 00000000..be6c13b3 --- /dev/null +++ b/src/3rdparty/libarchive/README.md @@ -0,0 +1,222 @@ +# Welcome to libarchive! + +The libarchive project develops a portable, efficient C library that +can read and write streaming archives in a variety of formats. It +also includes implementations of the common `tar`, `cpio`, and `zcat` +command-line tools that use the libarchive library. + +## Questions? Issues? + +* http://www.libarchive.org is the home for ongoing + libarchive development, including documentation, + and links to the libarchive mailing lists. +* To report an issue, use the issue tracker at + https://github.com/libarchive/libarchive/issues +* To submit an enhancement to libarchive, please + submit a pull request via GitHub: https://github.com/libarchive/libarchive/pulls + +## Contents of the Distribution + +This distribution bundle includes the following major components: + +* **libarchive**: a library for reading and writing streaming archives +* **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built on libarchive +* **cpio**: the 'bsdcpio' program is a different interface to essentially the same functionality +* **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, xzcat, and such +* **examples**: Some small example programs that you may find useful. +* **examples/minitar**: a compact sample demonstrating use of libarchive. +* **contrib**: Various items sent to me by third parties; please contact the authors with any questions. + +The top-level directory contains the following information files: + +* **NEWS** - highlights of recent changes +* **COPYING** - what you can do with this +* **INSTALL** - installation instructions +* **README** - this file +* **CMakeLists.txt** - input for "cmake" build tool, see INSTALL +* **configure** - configuration script, see INSTALL for details. If your copy of the source lacks a `configure` script, you can try to construct it by running the script in `build/autogen.sh` (or use `cmake`). + +The following files in the top-level directory are used by the 'configure' script: +* `Makefile.am`, `aclocal.m4`, `configure.ac` - used to build this distribution, only needed by maintainers +* `Makefile.in`, `config.h.in` - templates used by configure script + +## Documentation + +In addition to the informational articles and documentation +in the online [libarchive Wiki](https://github.com/libarchive/libarchive/wiki), +the distribution also includes a number of manual pages: + + * bsdtar.1 explains the use of the bsdtar program + * bsdcpio.1 explains the use of the bsdcpio program + * bsdcat.1 explains the use of the bsdcat program + * libarchive.3 gives an overview of the library as a whole + * archive_read.3, archive_write.3, archive_write_disk.3, and + archive_read_disk.3 provide detailed calling sequences for the read + and write APIs + * archive_entry.3 details the "struct archive_entry" utility class + * archive_internals.3 provides some insight into libarchive's + internal structure and operation. + * libarchive-formats.5 documents the file formats supported by the library + * cpio.5, mtree.5, and tar.5 provide detailed information about these + popular archive formats, including hard-to-find details about + modern cpio and tar variants. + +The manual pages above are provided in the 'doc' directory in +a number of different formats. + +You should also read the copious comments in `archive.h` and the +source code for the sample programs for more details. Please let us +know about any errors or omissions you find. + +## Supported Formats + +Currently, the library automatically detects and reads the following fomats: + * Old V7 tar archives + * POSIX ustar + * GNU tar format (including GNU long filenames, long link names, and sparse files) + * Solaris 9 extended tar format (including ACLs) + * POSIX pax interchange format + * POSIX octet-oriented cpio + * SVR4 ASCII cpio + * POSIX octet-oriented cpio + * Binary cpio (big-endian or little-endian) + * ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions) + * ZIP archives (with uncompressed or "deflate" compressed entries, including support for encrypted Zip archives) + * GNU and BSD 'ar' archives + * 'mtree' format + * 7-Zip archives + * Microsoft CAB format + * LHA and LZH archives + * RAR archives (with some limitations due to RAR's proprietary status) + * XAR archives + +The library also detects and handles any of the following before evaluating the archive: + * uuencoded files + * files with RPM wrapper + * gzip compression + * bzip2 compression + * compress/LZW compression + * lzma, lzip, and xz compression + * lz4 compression + * lzop compression + +The library can create archives in any of the following formats: + * POSIX ustar + * POSIX pax interchange format + * "restricted" pax format, which will create ustar archives except for + entries that require pax extensions (for long filenames, ACLs, etc). + * Old GNU tar format + * Old V7 tar format + * POSIX octet-oriented cpio + * SVR4 "newc" cpio + * shar archives + * ZIP archives (with uncompressed or "deflate" compressed entries) + * GNU and BSD 'ar' archives + * 'mtree' format + * ISO9660 format + * 7-Zip archives + * XAR archives + +When creating archives, the result can be filtered with any of the following: + * uuencode + * gzip compression + * bzip2 compression + * compress/LZW compression + * lzma, lzip, and xz compression + * lz4 compression + * lzop compression + +## Notes about the Library Design + +The following notes address many of the most common +questions we are asked about libarchive: + +* This is a heavily stream-oriented system. That means that + it is optimized to read or write the archive in a single + pass from beginning to end. For example, this allows + libarchive to process archives too large to store on disk + by processing them on-the-fly as they are read from or + written to a network or tape drive. This also makes + libarchive useful for tools that need to produce + archives on-the-fly (such as webservers that provide + archived contents of a users account). + +* In-place modification and random access to the contents + of an archive are not directly supported. For some formats, + this is not an issue: For example, tar.gz archives are not + designed for random access. In some other cases, libarchive + can re-open an archive and scan it from the beginning quickly + enough to provide the needed abilities even without true + random access. Of course, some applications do require true + random access; those applications should consider alternatives + to libarchive. + +* The library is designed to be extended with new compression and + archive formats. The only requirement is that the format be + readable or writable as a stream and that each archive entry be + independent. There are articles on the libarchive Wiki explaining + how to extend libarchive. + +* On read, compression and format are always detected automatically. + +* The same API is used for all formats; in particular, it's very + easy for software using libarchive to transparently handle + any of libarchive's archiving formats. + +* Libarchive's automatic support for decompression can be used + without archiving by explicitly selecting the "raw" and "empty" + formats. + +* I've attempted to minimize static link pollution. If you don't + explicitly invoke a particular feature (such as support for a + particular compression or format), it won't get pulled in to + statically-linked programs. In particular, if you don't explicitly + enable a particular compression or decompression support, you won't + need to link against the corresponding compression or decompression + libraries. This also reduces the size of statically-linked + binaries in environments where that matters. + +* The library is generally _thread safe_ depending on the platform: + it does not define any global variables of its own. However, some + platforms do not provide fully thread-safe versions of key C library + functions. On those platforms, libarchive will use the non-thread-safe + functions. Patches to improve this are of great interest to us. + +* In particular, libarchive's modules to read or write a directory + tree do use `chdir()` to optimize the directory traversals. This + can cause problems for programs that expect to do disk access from + multiple threads. Of course, those modules are completely + optional and you can use the rest of libarchive without them. + +* The library is _not_ thread aware, however. It does no locking + or thread management of any kind. If you create a libarchive + object and need to access it from multiple threads, you will + need to provide your own locking. + +* On read, the library accepts whatever blocks you hand it. + Your read callback is free to pass the library a byte at a time + or mmap the entire archive and give it to the library at once. + On write, the library always produces correctly-blocked output. + +* The object-style approach allows you to have multiple archive streams + open at once. bsdtar uses this in its "@archive" extension. + +* The archive itself is read/written using callback functions. + You can read an archive directly from an in-memory buffer or + write it to a socket, if you wish. There are some utility + functions to provide easy-to-use "open file," etc, capabilities. + +* The read/write APIs are designed to allow individual entries + to be read or written to any data source: You can create + a block of data in memory and add it to a tar archive without + first writing a temporary file. You can also read an entry from + an archive and write the data directly to a socket. If you want + to read/write entries to disk, there are convenience functions to + make this especially easy. + +* Note: The "pax interchange format" is a POSIX standard extended tar + format that should be used when the older _ustar_ format is not + appropriate. It has many advantages over other tar formats + (including the legacy GNU tar format) and is widely supported by + current tar implementations. + diff --git a/src/3rdparty/libarchive/config-android.h b/src/3rdparty/libarchive/config-android.h new file mode 100644 index 00000000..037f1b60 --- /dev/null +++ b/src/3rdparty/libarchive/config-android.h @@ -0,0 +1,153 @@ +// hand-crafted until it compiled ;) + +#define HAVE_CHOWN 1 +#define HAVE_CHROOT 1 +#define HAVE_CTIME_R 1 +#define HAVE_CTYPE_H 1 +#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0 +#define HAVE_DECL_INT64_MAX 1 +#define HAVE_DECL_INT64_MIN 1 +#define HAVE_DECL_INT32_MAX 1 +#define HAVE_DECL_INT32_MIN 1 +#define HAVE_DECL_INTMAX_MAX 1 +#define HAVE_DECL_INTMAX_MIN 1 +#define HAVE_DECL_SIZE_MAX 1 +#define HAVE_DECL_SSIZE_MAX 1 +#define HAVE_DECL_STRERROR_R 1 +#define HAVE_DECL_UINT32_MAX 1 +#define HAVE_DECL_UINT64_MAX 1 +#define HAVE_DECL_UINTMAX_MAX 1 +#define HAVE_DIRENT_H 1 +#define HAVE_DIRFD 1 +#define HAVE_DLFCN_H 1 +#define HAVE_EILSEQ 1 +#define HAVE_ERRNO_H 1 +#define HAVE_FCHDIR 1 +#define HAVE_FCHMOD 1 +#define HAVE_FCHOWN 1 +#define HAVE_FCNTL 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FDOPENDIR 1 +#define HAVE_FGETXATTR 1 +#define HAVE_FLISTXATTR 1 +#define HAVE_FORK 1 +#define HAVE_FSEEKO 1 +#define HAVE_FSETXATTR 1 +#define HAVE_FSTAT 1 +#define HAVE_FSTATAT 1 +//#define HAVE_FSTATFS 1 +//#define HAVE_FSTATVFS 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_GETEUID 1 +#define HAVE_GETPID 1 +#define HAVE_GETPWNAM_R 1 +#define HAVE_GETPWUID_R 1 +#define HAVE_GETXATTR 1 +#define HAVE_GMTIME_R 1 +#define HAVE_GRP_H 1 +#define HAVE_INTMAX_T 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LCHOWN 1 +#define HAVE_LGETXATTR 1 +#define HAVE_LIBLZMA 1 +#define HAVE_LIBZ 1 +#define HAVE_LIMITS_H 1 +#define HAVE_LINK 1 +//#define HAVE_LINUX_FIEMAP_H 1 +#define HAVE_LINUX_FS_H 1 +#define HAVE_LINUX_MAGIC_H 1 +#define HAVE_LINUX_TYPES_H 1 +#define HAVE_LISTXATTR 1 +#define HAVE_LLISTXATTR 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LOCALTIME_R 1 +#define HAVE_LONG_LONG_INT 1 +#define HAVE_LSETXATTR 1 +#define HAVE_LSTAT 1 +#define HAVE_MBRTOWC 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MEMSET 1 +#define HAVE_MKDIR 1 +#define HAVE_MKFIFO 1 +#define HAVE_MKNOD 1 +#define HAVE_MKSTEMP 1 +#define HAVE_OPENAT 1 +#define HAVE_PATHS_H 1 +#define HAVE_PIPE 1 +#define HAVE_POLL 1 +#define HAVE_POLL_H 1 +#define HAVE_PTHREAD_H 1 +#define HAVE_PWD_H 1 +#define HAVE_READDIR_R 1 +#define HAVE_READLINK 1 +#define HAVE_READLINKAT 1 +#define HAVE_REGEX_H 1 +#define HAVE_SELECT 1 +#define HAVE_SETENV 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SIGACTION 1 +#define HAVE_SIGNAL_H 1 +//#define HAVE_STATFS 1 +//#define HAVE_STATVFS 1 +#define HAVE_STDARG_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRCHR 1 +#define HAVE_STRDUP 1 +#define HAVE_STRERROR 1 +#define HAVE_STRERROR_R 1 +#define HAVE_STRFTIME 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRRCHR 1 +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +//#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 +#define HAVE_STRUCT_TM_TM_GMTOFF 1 +#define HAVE_SYMLINK 1 +#define HAVE_SYS_CDEFS_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_POLL_H 1 +#define HAVE_SYS_SELECT_H 1 +//#define HAVE_SYS_STATFS_H 1 +//#define HAVE_SYS_STATVFS_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_VFS_H 1 +#define HAVE_SYS_WAIT_H 1 +//#define HAVE_SYS_XATTR_H 1 +#define HAVE_TIMEGM 1 +#define HAVE_TIME_H 1 +#define HAVE_TZSET 1 +#define HAVE_UINTMAX_T 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UNSETENV 1 +#define HAVE_UNSIGNED_LONG_LONG 1 +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#define HAVE_UTIME 1 +#define HAVE_UTIMENSAT 1 +#define HAVE_UTIMES 1 +#define HAVE_UTIME_H 1 +#define HAVE_VFORK 1 +#define HAVE_VPRINTF 1 +#define HAVE_WCHAR_H 1 +#define HAVE_WCHAR_T 1 +#define HAVE_WCRTOMB 1 +#define HAVE_WCSCMP 1 +#define HAVE_WCSCPY 1 +#define HAVE_WCSLEN 1 +#define HAVE_WCTOMB 1 +#define HAVE_WCTYPE_H 1 +#define HAVE_WMEMCMP 1 +#define HAVE_WMEMCPY 1 +#define HAVE_ARC4RANDOM_BUF 1 +#define HAVE_ZLIB_H 1 +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +#define SIZEOF_WCHAR_T 4 +#define STDC_HEADERS 1 +#define STRERROR_R_CHAR_P 1 +#define TIME_WITH_SYS_TIME 1 diff --git a/src/3rdparty/libarchive/config-ios.h b/src/3rdparty/libarchive/config-ios.h new file mode 100644 index 00000000..2664e699 --- /dev/null +++ b/src/3rdparty/libarchive/config-ios.h @@ -0,0 +1,1098 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1 + +/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_WIN */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1 + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1 + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1 + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1 + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ + +/* Version number of bsdcpio */ +#define BSDCPIO_VERSION_STRING "3.1.2" + +/* Version number of bsdtar */ +#define BSDTAR_VERSION_STRING "3.1.2" + +/* Define to 1 if you have the `acl_create_entry' function. */ +/* #undef HAVE_ACL_CREATE_ENTRY */ + +/* Define to 1 if you have the `acl_get_link' function. */ +/* #undef HAVE_ACL_GET_LINK */ + +/* Define to 1 if you have the `acl_get_link_np' function. */ +/* #undef HAVE_ACL_GET_LINK_NP */ + +/* Define to 1 if you have the `acl_get_perm' function. */ +/* #undef HAVE_ACL_GET_PERM */ + +/* Define to 1 if you have the `acl_get_perm_np' function. */ +/* #undef HAVE_ACL_GET_PERM_NP */ + +/* Define to 1 if you have the `acl_init' function. */ +/* #undef HAVE_ACL_INIT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ACL_LIBACL_H */ + +/* Define to 1 if the system has the type `acl_permset_t'. */ +/* #undef HAVE_ACL_PERMSET_T */ + +/* Define to 1 if you have the `acl_set_fd' function. */ +/* #undef HAVE_ACL_SET_FD */ + +/* Define to 1 if you have the `acl_set_fd_np' function. */ +/* #undef HAVE_ACL_SET_FD_NP */ + +/* Define to 1 if you have the `acl_set_file' function. */ +/* #undef HAVE_ACL_SET_FILE */ + +/* True for systems with POSIX ACL support */ +/* #undef HAVE_ACL_USER */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ATTR_XATTR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BZLIB_H */ + +/* Define to 1 if you have the `chflags' function. */ +#define HAVE_CHFLAGS 1 + +/* Define to 1 if you have the `chown' function. */ +#define HAVE_CHOWN 1 + +/* Define to 1 if you have the `chroot' function. */ +#define HAVE_CHROOT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_COPYFILE_H 1 + +/* Define to 1 if you have the `ctime_r' function. */ +#define HAVE_CTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `cygwin_conv_path' function. */ +/* #undef HAVE_CYGWIN_CONV_PATH */ + +/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to + 0 if you don't. */ +/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ + +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MAX 1 + +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MIN 1 + +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SIZE_MAX 1 + +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SSIZE_MAX 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT32_MAX 1 + +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT64_MAX 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the `dirfd' function. */ +#define HAVE_DIRFD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if nl_langinfo supports D_MD_ORDER */ +#define HAVE_D_MD_ORDER 1 + +/* A possible errno value for invalid file format errors */ +#define HAVE_EFTYPE 1 + +/* A possible errno value for invalid file format errors */ +#define HAVE_EILSEQ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXPAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXT2FS_EXT2_FS_H */ + +/* Define to 1 if you have the `extattr_get_file' function. */ +/* #undef HAVE_EXTATTR_GET_FILE */ + +/* Define to 1 if you have the `extattr_list_file' function. */ +/* #undef HAVE_EXTATTR_LIST_FILE */ + +/* Define to 1 if you have the `extattr_set_fd' function. */ +/* #undef HAVE_EXTATTR_SET_FD */ + +/* Define to 1 if you have the `extattr_set_file' function. */ +/* #undef HAVE_EXTATTR_SET_FILE */ + +/* Define to 1 if you have the `fchdir' function. */ +#define HAVE_FCHDIR 1 + +/* Define to 1 if you have the `fchflags' function. */ +#define HAVE_FCHFLAGS 1 + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the `fchown' function. */ +#define HAVE_FCHOWN 1 + +/* Define to 1 if you have the `fcntl' function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopendir' function. */ +/* #undef HAVE_FDOPENDIR */ + +/* Define to 1 if you have the `fgetea' function. */ +/* #undef HAVE_FGETEA */ + +/* Define to 1 if you have the `fgetxattr' function. */ +/* #undef HAVE_FGETXATTR */ + +/* Define to 1 if you have the `flistea' function. */ +/* #undef HAVE_FLISTEA */ + +/* Define to 1 if you have the `flistxattr' function. */ +/* #undef HAVE_FLISTXATTR */ + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fsetea' function. */ +/* #undef HAVE_FSETEA */ + +/* Define to 1 if you have the `fsetxattr' function. */ +/* #undef HAVE_FSETXATTR */ + +/* Define to 1 if you have the `fstat' function. */ +#define HAVE_FSTAT 1 + +/* Define to 1 if you have the `fstatat' function. */ +/* #undef HAVE_FSTATAT */ + +/* Define to 1 if you have the `fstatfs' function. */ +#define HAVE_FSTATFS 1 + +/* Define to 1 if you have the `fstatvfs' function. */ +#define HAVE_FSTATVFS 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `futimens' function. */ +/* #undef HAVE_FUTIMENS */ + +/* Define to 1 if you have the `futimes' function. */ +#define HAVE_FUTIMES 1 + +/* Define to 1 if you have the `futimesat' function. */ +/* #undef HAVE_FUTIMESAT */ + +/* Define to 1 if you have the `getea' function. */ +/* #undef HAVE_GETEA */ + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the `getgrgid_r' function. */ +#define HAVE_GETGRGID_R 1 + +/* Define to 1 if you have the `getgrnam_r' function. */ +#define HAVE_GETGRNAM_R 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpwnam_r' function. */ +#define HAVE_GETPWNAM_R 1 + +/* Define to 1 if you have the `getpwuid_r' function. */ +#define HAVE_GETPWUID_R 1 + +/* Define to 1 if you have the `getvfsbyname' function. */ +#define HAVE_GETVFSBYNAME 1 + +/* Define to 1 if you have the `getxattr' function. */ +/* #undef HAVE_GETXATTR */ + +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the iconv() function and it works. */ +#define HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ICONV_H 1 + +/* Define to 1 if the system has the type `intmax_t'. */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have the `lchflags' function. */ +#define HAVE_LCHFLAGS 1 + +/* Define to 1 if you have the `lchmod' function. */ +#define HAVE_LCHMOD 1 + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `lgetea' function. */ +/* #undef HAVE_LGETEA */ + +/* Define to 1 if you have the `lgetxattr' function. */ +/* #undef HAVE_LGETXATTR */ + +/* Define to 1 if you have the `acl' library (-lacl). */ +/* #undef HAVE_LIBACL */ + +/* Define to 1 if you have the `attr' library (-lattr). */ +/* #undef HAVE_LIBATTR */ + +/* Define to 1 if you have the `bz2' library (-lbz2). */ +/* #undef HAVE_LIBBZ2 */ + +/* Define to 1 if you have the `charset' library (-lcharset). */ +/* #undef HAVE_LIBCHARSET */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `eay32' library (-leay32). */ +/* #undef HAVE_LIBEAY32 */ + +/* Define to 1 if you have the `eay64' library (-leay64). */ +/* #undef HAVE_LIBEAY64 */ + +/* Define to 1 if you have the `expat' library (-lexpat). */ +/* #undef HAVE_LIBEXPAT */ + +/* Define to 1 if you have the `lzma' library (-llzma). */ +/* #undef HAVE_LIBLZMA */ + +/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ +/* #undef HAVE_LIBLZMADEC */ + +/* Define to 1 if you have the `lzo2' library (-llzo2). */ +/* #undef HAVE_LIBLZO2 */ + +/* Define to 1 if you have the `md' library (-lmd). */ +/* #undef HAVE_LIBMD */ + +/* Define to 1 if you have the `nettle' library (-lnettle). */ +/* #undef HAVE_LIBNETTLE */ + +/* Define to 1 if you have the `pcre' library (-lpcre). */ +/* #undef HAVE_LIBPCRE */ + +/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ +/* #undef HAVE_LIBPCREPOSIX */ + +/* Define to 1 if you have the `regex' library (-lregex). */ +/* #undef HAVE_LIBREGEX */ + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +/* #undef HAVE_LIBXML2 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLREADER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLWRITER_H */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `link' function. */ +#define HAVE_LINK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FIEMAP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_MAGIC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_TYPES_H */ + +/* Define to 1 if you have the `listea' function. */ +/* #undef HAVE_LISTEA */ + +/* Define to 1 if you have the `listxattr' function. */ +/* #undef HAVE_LISTXATTR */ + +/* Define to 1 if you have the `llistea' function. */ +/* #undef HAVE_LLISTEA */ + +/* Define to 1 if you have the `llistxattr' function. */ +/* #undef HAVE_LLISTXATTR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LOCALCHARSET_H */ + +/* Define to 1 if you have the `locale_charset' function. */ +#define HAVE_LOCALE_CHARSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the `lsetea' function. */ +/* #undef HAVE_LSETEA */ + +/* Define to 1 if you have the `lsetxattr' function. */ +/* #undef HAVE_LSETXATTR */ + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if `lstat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the `lutimes' function. */ +#define HAVE_LUTIMES 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMADEC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZO1X_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZOCONF_H */ + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MD5_H */ + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mknod' function. */ +#define HAVE_MKNOD 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_MD5_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_RIPEMD160_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_SHA_H */ + +/* Define to 1 if you have the `nl_langinfo' function. */ +#define HAVE_NL_LANGINFO 1 + +/* Define to 1 if you have the `openat' function. */ +/* #undef HAVE_OPENAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_OPENSSL_EVP_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PCREPOSIX_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `poll' function. */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the `posix_spawnp' function. */ +#define HAVE_POSIX_SPAWNP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have a POSIX compatible readdir_r */ +#define HAVE_READDIR_R 1 + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `readlinkat' function. */ +/* #undef HAVE_READLINKAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RIPEMD_H */ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA256_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA512_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA_H */ + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SPAWN_H 1 + +/* Define to 1 if you have the `statfs' function. */ +#define HAVE_STATFS 1 + +/* Define to 1 if you have the `statvfs' function. */ +#define HAVE_STATVFS 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncpy_s' function. */ +/* #undef HAVE_STRNCPY_S */ + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ + +/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ + +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 + +/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_flags' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_FLAGS 1 + +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 + +/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ + +/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ + +/* Define to 1 if `st_umtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ + +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_GMTOFF 1 + +/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ + +/* Define to 1 if you have the `symlink' function. */ +#define HAVE_SYMLINK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_ACL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_CDEFS_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EXTATTR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UTIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the `timegm' function. */ +#define HAVE_TIMEGM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the `tzset' function. */ +#define HAVE_TZSET 1 + +/* Define to 1 if the system has the type `uintmax_t'. */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +/* #undef HAVE_UTIMENSAT */ + +/* Define to 1 if you have the `utimes' function. */ +#define HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if the system has the type `wchar_t'. */ +#define HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the `wcscmp' function. */ +#define HAVE_WCSCMP 1 + +/* Define to 1 if you have the `wcscpy' function. */ +#define HAVE_WCSCPY 1 + +/* Define to 1 if you have the `wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the `wctomb' function. */ +#define HAVE_WCTOMB 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCTYPE_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINCRYPT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINIOCTL_H */ + +/* Define to 1 if you have the `wmemcmp' function. */ +#define HAVE_WMEMCMP 1 + +/* Define to 1 if you have the `wmemcpy' function. */ +#define HAVE_WMEMCPY 1 + +/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ +/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H 1 + +/* Define to 1 if you have the `_ctime64_s' function. */ +/* #undef HAVE__CTIME64_S */ + +/* Define to 1 if you have the `_fseeki64' function. */ +/* #undef HAVE__FSEEKI64 */ + +/* Define to 1 if you have the `_get_timezone' function. */ +/* #undef HAVE__GET_TIMEZONE */ + +/* Define to 1 if you have the `_localtime64_s' function. */ +/* #undef HAVE__LOCALTIME64_S */ + +/* Define to 1 if you have the `_mkgmtime64' function. */ +/* #undef HAVE__MKGMTIME64 */ + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Version number of libarchive as a single integer */ +#define LIBARCHIVE_VERSION_NUMBER "3001002" + +/* Version number of libarchive */ +#define LIBARCHIVE_VERSION_STRING "3.1.2" + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libarchive" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libarchive" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libarchive 3.1.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libarchive" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.1.2" + +/* Define to 1 if PCRE_STATIC needs to be defined. */ +/* #undef PCRE_STATIC */ + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +/* #undef STRERROR_R_CHAR_P */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "3.1.2" + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef WINVER */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef _WIN32_WINNT */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to match typeof st_gid field of struct stat if doesn't + define. */ +/* #undef gid_t */ + +/* Define to `unsigned long' if does not define. */ +/* #undef id_t */ + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int16_t */ + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to the widest signed integer type if and do + not define. */ +/* #undef intmax_t */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long long' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to match typeof st_uid field of struct stat if doesn't + define. */ +/* #undef uid_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +/* Define to the widest unsigned integer type if and + do not define. */ +/* #undef uintmax_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef uintptr_t */ + +#define HAVE_ARC4RANDOM_BUF 1 diff --git a/src/3rdparty/libarchive/config-macos.h b/src/3rdparty/libarchive/config-macos.h new file mode 100644 index 00000000..85294b2e --- /dev/null +++ b/src/3rdparty/libarchive/config-macos.h @@ -0,0 +1,1098 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1 + +/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_WIN */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1 + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1 + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1 + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ +#define ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1 + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ + +/* Version number of bsdcpio */ +#define BSDCPIO_VERSION_STRING "3.1.2" + +/* Version number of bsdtar */ +#define BSDTAR_VERSION_STRING "3.1.2" + +/* Define to 1 if you have the `acl_create_entry' function. */ +/* #undef HAVE_ACL_CREATE_ENTRY */ + +/* Define to 1 if you have the `acl_get_link' function. */ +/* #undef HAVE_ACL_GET_LINK */ + +/* Define to 1 if you have the `acl_get_link_np' function. */ +/* #undef HAVE_ACL_GET_LINK_NP */ + +/* Define to 1 if you have the `acl_get_perm' function. */ +/* #undef HAVE_ACL_GET_PERM */ + +/* Define to 1 if you have the `acl_get_perm_np' function. */ +/* #undef HAVE_ACL_GET_PERM_NP */ + +/* Define to 1 if you have the `acl_init' function. */ +/* #undef HAVE_ACL_INIT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ACL_LIBACL_H */ + +/* Define to 1 if the system has the type `acl_permset_t'. */ +/* #undef HAVE_ACL_PERMSET_T */ + +/* Define to 1 if you have the `acl_set_fd' function. */ +/* #undef HAVE_ACL_SET_FD */ + +/* Define to 1 if you have the `acl_set_fd_np' function. */ +/* #undef HAVE_ACL_SET_FD_NP */ + +/* Define to 1 if you have the `acl_set_file' function. */ +/* #undef HAVE_ACL_SET_FILE */ + +/* True for systems with POSIX ACL support */ +/* #undef HAVE_ACL_USER */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ATTR_XATTR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BZLIB_H */ + +/* Define to 1 if you have the `chflags' function. */ +#define HAVE_CHFLAGS 1 + +/* Define to 1 if you have the `chown' function. */ +#define HAVE_CHOWN 1 + +/* Define to 1 if you have the `chroot' function. */ +#define HAVE_CHROOT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_COPYFILE_H 1 + +/* Define to 1 if you have the `ctime_r' function. */ +#define HAVE_CTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `cygwin_conv_path' function. */ +/* #undef HAVE_CYGWIN_CONV_PATH */ + +/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to + 0 if you don't. */ +/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ + +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MAX 1 + +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MIN 1 + +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SIZE_MAX 1 + +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SSIZE_MAX 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT32_MAX 1 + +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT64_MAX 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the `dirfd' function. */ +#define HAVE_DIRFD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if nl_langinfo supports D_MD_ORDER */ +#define HAVE_D_MD_ORDER 1 + +/* A possible errno value for invalid file format errors */ +#define HAVE_EFTYPE 1 + +/* A possible errno value for invalid file format errors */ +#define HAVE_EILSEQ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXPAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXT2FS_EXT2_FS_H */ + +/* Define to 1 if you have the `extattr_get_file' function. */ +/* #undef HAVE_EXTATTR_GET_FILE */ + +/* Define to 1 if you have the `extattr_list_file' function. */ +/* #undef HAVE_EXTATTR_LIST_FILE */ + +/* Define to 1 if you have the `extattr_set_fd' function. */ +/* #undef HAVE_EXTATTR_SET_FD */ + +/* Define to 1 if you have the `extattr_set_file' function. */ +/* #undef HAVE_EXTATTR_SET_FILE */ + +/* Define to 1 if you have the `fchdir' function. */ +#define HAVE_FCHDIR 1 + +/* Define to 1 if you have the `fchflags' function. */ +#define HAVE_FCHFLAGS 1 + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the `fchown' function. */ +#define HAVE_FCHOWN 1 + +/* Define to 1 if you have the `fcntl' function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopendir' function. */ +/* #undef HAVE_FDOPENDIR */ + +/* Define to 1 if you have the `fgetea' function. */ +/* #undef HAVE_FGETEA */ + +/* Define to 1 if you have the `fgetxattr' function. */ +/* #undef HAVE_FGETXATTR */ + +/* Define to 1 if you have the `flistea' function. */ +/* #undef HAVE_FLISTEA */ + +/* Define to 1 if you have the `flistxattr' function. */ +/* #undef HAVE_FLISTXATTR */ + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fsetea' function. */ +/* #undef HAVE_FSETEA */ + +/* Define to 1 if you have the `fsetxattr' function. */ +/* #undef HAVE_FSETXATTR */ + +/* Define to 1 if you have the `fstat' function. */ +#define HAVE_FSTAT 1 + +/* Define to 1 if you have the `fstatat' function. */ +/* #undef HAVE_FSTATAT */ + +/* Define to 1 if you have the `fstatfs' function. */ +#define HAVE_FSTATFS 1 + +/* Define to 1 if you have the `fstatvfs' function. */ +#define HAVE_FSTATVFS 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `futimens' function. */ +/* #undef HAVE_FUTIMENS */ + +/* Define to 1 if you have the `futimes' function. */ +#define HAVE_FUTIMES 1 + +/* Define to 1 if you have the `futimesat' function. */ +/* #undef HAVE_FUTIMESAT */ + +/* Define to 1 if you have the `getea' function. */ +/* #undef HAVE_GETEA */ + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the `getgrgid_r' function. */ +#define HAVE_GETGRGID_R 1 + +/* Define to 1 if you have the `getgrnam_r' function. */ +#define HAVE_GETGRNAM_R 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpwnam_r' function. */ +#define HAVE_GETPWNAM_R 1 + +/* Define to 1 if you have the `getpwuid_r' function. */ +#define HAVE_GETPWUID_R 1 + +/* Define to 1 if you have the `getvfsbyname' function. */ +#define HAVE_GETVFSBYNAME 1 + +/* Define to 1 if you have the `getxattr' function. */ +/* #undef HAVE_GETXATTR */ + +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the iconv() function and it works. */ +#define HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ICONV_H 1 + +/* Define to 1 if the system has the type `intmax_t'. */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have the `lchflags' function. */ +#define HAVE_LCHFLAGS 1 + +/* Define to 1 if you have the `lchmod' function. */ +#define HAVE_LCHMOD 1 + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `lgetea' function. */ +/* #undef HAVE_LGETEA */ + +/* Define to 1 if you have the `lgetxattr' function. */ +/* #undef HAVE_LGETXATTR */ + +/* Define to 1 if you have the `acl' library (-lacl). */ +/* #undef HAVE_LIBACL */ + +/* Define to 1 if you have the `attr' library (-lattr). */ +/* #undef HAVE_LIBATTR */ + +/* Define to 1 if you have the `bz2' library (-lbz2). */ +/* #undef HAVE_LIBBZ2 */ + +/* Define to 1 if you have the `charset' library (-lcharset). */ +/* #undef HAVE_LIBCHARSET */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `eay32' library (-leay32). */ +/* #undef HAVE_LIBEAY32 */ + +/* Define to 1 if you have the `eay64' library (-leay64). */ +/* #undef HAVE_LIBEAY64 */ + +/* Define to 1 if you have the `expat' library (-lexpat). */ +/* #undef HAVE_LIBEXPAT */ + +/* Define to 1 if you have the `lzma' library (-llzma). */ +/* #undef HAVE_LIBLZMA */ + +/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ +/* #undef HAVE_LIBLZMADEC */ + +/* Define to 1 if you have the `lzo2' library (-llzo2). */ +/* #undef HAVE_LIBLZO2 */ + +/* Define to 1 if you have the `md' library (-lmd). */ +/* #undef HAVE_LIBMD */ + +/* Define to 1 if you have the `nettle' library (-lnettle). */ +/* #undef HAVE_LIBNETTLE */ + +/* Define to 1 if you have the `pcre' library (-lpcre). */ +/* #undef HAVE_LIBPCRE */ + +/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ +/* #undef HAVE_LIBPCREPOSIX */ + +/* Define to 1 if you have the `regex' library (-lregex). */ +/* #undef HAVE_LIBREGEX */ + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +/* #undef HAVE_LIBXML2 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLREADER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLWRITER_H */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `link' function. */ +#define HAVE_LINK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FIEMAP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_MAGIC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_TYPES_H */ + +/* Define to 1 if you have the `listea' function. */ +/* #undef HAVE_LISTEA */ + +/* Define to 1 if you have the `listxattr' function. */ +/* #undef HAVE_LISTXATTR */ + +/* Define to 1 if you have the `llistea' function. */ +/* #undef HAVE_LLISTEA */ + +/* Define to 1 if you have the `llistxattr' function. */ +/* #undef HAVE_LLISTXATTR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALCHARSET_H 1 + +/* Define to 1 if you have the `locale_charset' function. */ +#define HAVE_LOCALE_CHARSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the `lsetea' function. */ +/* #undef HAVE_LSETEA */ + +/* Define to 1 if you have the `lsetxattr' function. */ +/* #undef HAVE_LSETXATTR */ + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if `lstat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the `lutimes' function. */ +#define HAVE_LUTIMES 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMADEC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZO1X_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZOCONF_H */ + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MD5_H */ + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mknod' function. */ +#define HAVE_MKNOD 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_MD5_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_RIPEMD160_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_SHA_H */ + +/* Define to 1 if you have the `nl_langinfo' function. */ +#define HAVE_NL_LANGINFO 1 + +/* Define to 1 if you have the `openat' function. */ +/* #undef HAVE_OPENAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_OPENSSL_EVP_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PCREPOSIX_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `poll' function. */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the `posix_spawnp' function. */ +#define HAVE_POSIX_SPAWNP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have a POSIX compatible readdir_r */ +#define HAVE_READDIR_R 1 + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `readlinkat' function. */ +/* #undef HAVE_READLINKAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RIPEMD_H */ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA256_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA512_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA_H */ + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SPAWN_H 1 + +/* Define to 1 if you have the `statfs' function. */ +#define HAVE_STATFS 1 + +/* Define to 1 if you have the `statvfs' function. */ +#define HAVE_STATVFS 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncpy_s' function. */ +/* #undef HAVE_STRNCPY_S */ + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ + +/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ + +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 + +/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_flags' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_FLAGS 1 + +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 + +/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ + +/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ + +/* Define to 1 if `st_umtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ + +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_GMTOFF 1 + +/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ + +/* Define to 1 if you have the `symlink' function. */ +#define HAVE_SYMLINK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_ACL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_CDEFS_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EXTATTR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UTIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the `timegm' function. */ +#define HAVE_TIMEGM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the `tzset' function. */ +#define HAVE_TZSET 1 + +/* Define to 1 if the system has the type `uintmax_t'. */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +/* #undef HAVE_UTIMENSAT */ + +/* Define to 1 if you have the `utimes' function. */ +#define HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if the system has the type `wchar_t'. */ +#define HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the `wcscmp' function. */ +#define HAVE_WCSCMP 1 + +/* Define to 1 if you have the `wcscpy' function. */ +#define HAVE_WCSCPY 1 + +/* Define to 1 if you have the `wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the `wctomb' function. */ +#define HAVE_WCTOMB 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCTYPE_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINCRYPT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINIOCTL_H */ + +/* Define to 1 if you have the `wmemcmp' function. */ +#define HAVE_WMEMCMP 1 + +/* Define to 1 if you have the `wmemcpy' function. */ +#define HAVE_WMEMCPY 1 + +/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ +/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H 1 + +/* Define to 1 if you have the `_ctime64_s' function. */ +/* #undef HAVE__CTIME64_S */ + +/* Define to 1 if you have the `_fseeki64' function. */ +/* #undef HAVE__FSEEKI64 */ + +/* Define to 1 if you have the `_get_timezone' function. */ +/* #undef HAVE__GET_TIMEZONE */ + +/* Define to 1 if you have the `_localtime64_s' function. */ +/* #undef HAVE__LOCALTIME64_S */ + +/* Define to 1 if you have the `_mkgmtime64' function. */ +/* #undef HAVE__MKGMTIME64 */ + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Version number of libarchive as a single integer */ +#define LIBARCHIVE_VERSION_NUMBER "3001002" + +/* Version number of libarchive */ +#define LIBARCHIVE_VERSION_STRING "3.1.2" + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libarchive" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libarchive" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libarchive 3.1.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libarchive" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.1.2" + +/* Define to 1 if PCRE_STATIC needs to be defined. */ +/* #undef PCRE_STATIC */ + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +/* #undef STRERROR_R_CHAR_P */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "3.1.2" + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef WINVER */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef _WIN32_WINNT */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to match typeof st_gid field of struct stat if doesn't + define. */ +/* #undef gid_t */ + +/* Define to `unsigned long' if does not define. */ +/* #undef id_t */ + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int16_t */ + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to the widest signed integer type if and do + not define. */ +/* #undef intmax_t */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long long' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to match typeof st_uid field of struct stat if doesn't + define. */ +/* #undef uid_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +/* Define to the widest unsigned integer type if and + do not define. */ +/* #undef uintmax_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef uintptr_t */ + +#define HAVE_ARC4RANDOM_BUF 1 diff --git a/src/3rdparty/libarchive/config-unix.h b/src/3rdparty/libarchive/config-unix.h new file mode 100644 index 00000000..b82ec002 --- /dev/null +++ b/src/3rdparty/libarchive/config-unix.h @@ -0,0 +1,1096 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_WIN */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_WIN */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ + +/* Version number of bsdcpio */ +#define BSDCPIO_VERSION_STRING "3.1.2" + +/* Version number of bsdtar */ +#define BSDTAR_VERSION_STRING "3.1.2" + +/* Define to 1 if you have the `acl_create_entry' function. */ +/* #undef HAVE_ACL_CREATE_ENTRY */ + +/* Define to 1 if you have the `acl_get_link' function. */ +/* #undef HAVE_ACL_GET_LINK */ + +/* Define to 1 if you have the `acl_get_link_np' function. */ +/* #undef HAVE_ACL_GET_LINK_NP */ + +/* Define to 1 if you have the `acl_get_perm' function. */ +/* #undef HAVE_ACL_GET_PERM */ + +/* Define to 1 if you have the `acl_get_perm_np' function. */ +/* #undef HAVE_ACL_GET_PERM_NP */ + +/* Define to 1 if you have the `acl_init' function. */ +/* #undef HAVE_ACL_INIT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ACL_LIBACL_H */ + +/* Define to 1 if the system has the type `acl_permset_t'. */ +/* #undef HAVE_ACL_PERMSET_T */ + +/* Define to 1 if you have the `acl_set_fd' function. */ +/* #undef HAVE_ACL_SET_FD */ + +/* Define to 1 if you have the `acl_set_fd_np' function. */ +/* #undef HAVE_ACL_SET_FD_NP */ + +/* Define to 1 if you have the `acl_set_file' function. */ +/* #undef HAVE_ACL_SET_FILE */ + +/* True for systems with POSIX ACL support */ +/* #undef HAVE_ACL_USER */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ATTR_XATTR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BZLIB_H */ + +/* Define to 1 if you have the `chflags' function. */ +/* #undef HAVE_CHFLAGS */ + +/* Define to 1 if you have the `chown' function. */ +#define HAVE_CHOWN 1 + +/* Define to 1 if you have the `chroot' function. */ +#define HAVE_CHROOT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_COPYFILE_H */ + +/* Define to 1 if you have the `ctime_r' function. */ +#define HAVE_CTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `cygwin_conv_path' function. */ +/* #undef HAVE_CYGWIN_CONV_PATH */ + +/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to + 0 if you don't. */ +/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ + +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MAX 1 + +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MIN 1 + +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SIZE_MAX 1 + +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SSIZE_MAX 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT32_MAX 1 + +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT64_MAX 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the `dirfd' function. */ +#define HAVE_DIRFD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if nl_langinfo supports D_MD_ORDER */ +/* #undef HAVE_D_MD_ORDER */ + +/* A possible errno value for invalid file format errors */ +/* #undef HAVE_EFTYPE */ + +/* A possible errno value for invalid file format errors */ +#define HAVE_EILSEQ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXPAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXT2FS_EXT2_FS_H */ + +/* Define to 1 if you have the `extattr_get_file' function. */ +/* #undef HAVE_EXTATTR_GET_FILE */ + +/* Define to 1 if you have the `extattr_list_file' function. */ +/* #undef HAVE_EXTATTR_LIST_FILE */ + +/* Define to 1 if you have the `extattr_set_fd' function. */ +/* #undef HAVE_EXTATTR_SET_FD */ + +/* Define to 1 if you have the `extattr_set_file' function. */ +/* #undef HAVE_EXTATTR_SET_FILE */ + +/* Define to 1 if you have the `fchdir' function. */ +#define HAVE_FCHDIR 1 + +/* Define to 1 if you have the `fchflags' function. */ +/* #undef HAVE_FCHFLAGS */ + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the `fchown' function. */ +#define HAVE_FCHOWN 1 + +/* Define to 1 if you have the `fcntl' function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopendir' function. */ +#define HAVE_FDOPENDIR 1 + +/* Define to 1 if you have the `fgetea' function. */ +/* #undef HAVE_FGETEA */ + +/* Define to 1 if you have the `fgetxattr' function. */ +/* #undef HAVE_FGETXATTR */ + +/* Define to 1 if you have the `flistea' function. */ +/* #undef HAVE_FLISTEA */ + +/* Define to 1 if you have the `flistxattr' function. */ +/* #undef HAVE_FLISTXATTR */ + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fsetea' function. */ +/* #undef HAVE_FSETEA */ + +/* Define to 1 if you have the `fsetxattr' function. */ +/* #undef HAVE_FSETXATTR */ + +/* Define to 1 if you have the `fstat' function. */ +#define HAVE_FSTAT 1 + +/* Define to 1 if you have the `fstatat' function. */ +#define HAVE_FSTATAT 1 + +/* Define to 1 if you have the `fstatfs' function. */ +#define HAVE_FSTATFS 1 + +/* Define to 1 if you have the `fstatvfs' function. */ +#define HAVE_FSTATVFS 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `futimens' function. */ +#define HAVE_FUTIMENS 1 + +/* Define to 1 if you have the `futimes' function. */ +#define HAVE_FUTIMES 1 + +/* Define to 1 if you have the `futimesat' function. */ +#define HAVE_FUTIMESAT 1 + +/* Define to 1 if you have the `getea' function. */ +/* #undef HAVE_GETEA */ + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the `getgrgid_r' function. */ +#define HAVE_GETGRGID_R 1 + +/* Define to 1 if you have the `getgrnam_r' function. */ +#define HAVE_GETGRNAM_R 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpwnam_r' function. */ +#define HAVE_GETPWNAM_R 1 + +/* Define to 1 if you have the `getpwuid_r' function. */ +#define HAVE_GETPWUID_R 1 + +/* Define to 1 if you have the `getvfsbyname' function. */ +/* #undef HAVE_GETVFSBYNAME */ + +/* Define to 1 if you have the `getxattr' function. */ +/* #undef HAVE_GETXATTR */ + +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the iconv() function and it works. */ +#define HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ICONV_H 1 + +/* Define to 1 if the system has the type `intmax_t'. */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have the `lchflags' function. */ +/* #undef HAVE_LCHFLAGS */ + +/* Define to 1 if you have the `lchmod' function. */ +/* #undef HAVE_LCHMOD */ + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `lgetea' function. */ +/* #undef HAVE_LGETEA */ + +/* Define to 1 if you have the `lgetxattr' function. */ +/* #undef HAVE_LGETXATTR */ + +/* Define to 1 if you have the `acl' library (-lacl). */ +/* #undef HAVE_LIBACL */ + +/* Define to 1 if you have the `attr' library (-lattr). */ +/* #undef HAVE_LIBATTR */ + +/* Define to 1 if you have the `bz2' library (-lbz2). */ +/* #undef HAVE_LIBBZ2 */ + +/* Define to 1 if you have the `charset' library (-lcharset). */ +/* #undef HAVE_LIBCHARSET */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +/* #undef HAVE_LIBCRYPTO */ + +/* Define to 1 if you have the `eay32' library (-leay32). */ +/* #undef HAVE_LIBEAY32 */ + +/* Define to 1 if you have the `eay64' library (-leay64). */ +/* #undef HAVE_LIBEAY64 */ + +/* Define to 1 if you have the `expat' library (-lexpat). */ +/* #undef HAVE_LIBEXPAT */ + +/* Define to 1 if you have the `lzma' library (-llzma). */ +/* #undef HAVE_LIBLZMA */ + +/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ +/* #undef HAVE_LIBLZMADEC */ + +/* Define to 1 if you have the `lzo2' library (-llzo2). */ +/* #undef HAVE_LIBLZO2 */ + +/* Define to 1 if you have the `md' library (-lmd). */ +/* #undef HAVE_LIBMD */ + +/* Define to 1 if you have the `nettle' library (-lnettle). */ +/* #undef HAVE_LIBNETTLE */ + +/* Define to 1 if you have the `pcre' library (-lpcre). */ +/* #undef HAVE_LIBPCRE */ + +/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ +/* #undef HAVE_LIBPCREPOSIX */ + +/* Define to 1 if you have the `regex' library (-lregex). */ +/* #undef HAVE_LIBREGEX */ + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +/* #undef HAVE_LIBXML2 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLREADER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLWRITER_H */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `link' function. */ +#define HAVE_LINK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_FIEMAP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_FS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_MAGIC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_TYPES_H 1 + +/* Define to 1 if you have the `listea' function. */ +/* #undef HAVE_LISTEA */ + +/* Define to 1 if you have the `listxattr' function. */ +/* #undef HAVE_LISTXATTR */ + +/* Define to 1 if you have the `llistea' function. */ +/* #undef HAVE_LLISTEA */ + +/* Define to 1 if you have the `llistxattr' function. */ +/* #undef HAVE_LLISTXATTR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LOCALCHARSET_H */ + +/* Define to 1 if you have the `locale_charset' function. */ +/* #undef HAVE_LOCALE_CHARSET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the `lsetea' function. */ +/* #undef HAVE_LSETEA */ + +/* Define to 1 if you have the `lsetxattr' function. */ +/* #undef HAVE_LSETXATTR */ + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if `lstat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the `lutimes' function. */ +#define HAVE_LUTIMES 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMADEC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZO1X_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZOCONF_H */ + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MD5_H */ + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mknod' function. */ +#define HAVE_MKNOD 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_MD5_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_RIPEMD160_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_SHA_H */ + +/* Define to 1 if you have the `nl_langinfo' function. */ +#define HAVE_NL_LANGINFO 1 + +/* Define to 1 if you have the `openat' function. */ +#define HAVE_OPENAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_OPENSSL_EVP_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PCREPOSIX_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `poll' function. */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the `posix_spawnp' function. */ +#define HAVE_POSIX_SPAWNP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have a POSIX compatible readdir_r */ +#define HAVE_READDIR_R 1 + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `readlinkat' function. */ +#define HAVE_READLINKAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RIPEMD_H */ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA256_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA512_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA_H */ + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SPAWN_H 1 + +/* Define to 1 if you have the `statfs' function. */ +#define HAVE_STATFS 1 + +/* Define to 1 if you have the `statvfs' function. */ +#define HAVE_STATVFS 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncpy_s' function. */ +/* #undef HAVE_STRNCPY_S */ + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ + +/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ + +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ + +/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */ + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_flags' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ + +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */ + +/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ + +/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 + +/* Define to 1 if `st_umtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ + +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_GMTOFF 1 + +/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ + +/* Define to 1 if you have the `symlink' function. */ +#define HAVE_SYMLINK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ACL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_CDEFS_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EXTATTR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UTIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_VFS_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the `timegm' function. */ +#define HAVE_TIMEGM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the `tzset' function. */ +#define HAVE_TZSET 1 + +/* Define to 1 if the system has the type `uintmax_t'. */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +#define HAVE_UTIMENSAT 1 + +/* Define to 1 if you have the `utimes' function. */ +#define HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if the system has the type `wchar_t'. */ +#define HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the `wcscmp' function. */ +#define HAVE_WCSCMP 1 + +/* Define to 1 if you have the `wcscpy' function. */ +#define HAVE_WCSCPY 1 + +/* Define to 1 if you have the `wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the `wctomb' function. */ +#define HAVE_WCTOMB 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCTYPE_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINCRYPT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINIOCTL_H */ + +/* Define to 1 if you have the `wmemcmp' function. */ +#define HAVE_WMEMCMP 1 + +/* Define to 1 if you have the `wmemcpy' function. */ +#define HAVE_WMEMCPY 1 + +/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ +#define HAVE_WORKING_EXT2_IOC_GETFLAGS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H 1 + +/* Define to 1 if you have the `_ctime64_s' function. */ +/* #undef HAVE__CTIME64_S */ + +/* Define to 1 if you have the `_fseeki64' function. */ +/* #undef HAVE__FSEEKI64 */ + +/* Define to 1 if you have the `_get_timezone' function. */ +/* #undef HAVE__GET_TIMEZONE */ + +/* Define to 1 if you have the `_localtime64_s' function. */ +/* #undef HAVE__LOCALTIME64_S */ + +/* Define to 1 if you have the `_mkgmtime64' function. */ +/* #undef HAVE__MKGMTIME64 */ + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Version number of libarchive as a single integer */ +#define LIBARCHIVE_VERSION_NUMBER "3001002" + +/* Version number of libarchive */ +#define LIBARCHIVE_VERSION_STRING "3.1.2" + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libarchive" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libarchive" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libarchive 3.1.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libarchive" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.1.2" + +/* Define to 1 if PCRE_STATIC needs to be defined. */ +/* #undef PCRE_STATIC */ + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +#define STRERROR_R_CHAR_P 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "3.1.2" + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef WINVER */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to '0x0500' for Windows 2000 APIs. */ +/* #undef _WIN32_WINNT */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to match typeof st_gid field of struct stat if doesn't + define. */ +/* #undef gid_t */ + +/* Define to `unsigned long' if does not define. */ +/* #undef id_t */ + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int16_t */ + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to the widest signed integer type if and do + not define. */ +/* #undef intmax_t */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long long' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to match typeof st_uid field of struct stat if doesn't + define. */ +/* #undef uid_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +/* Define to the widest unsigned integer type if and + do not define. */ +/* #undef uintmax_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef uintptr_t */ diff --git a/src/3rdparty/libarchive/config-windows.h b/src/3rdparty/libarchive/config-windows.h new file mode 100644 index 00000000..6019e58c --- /dev/null +++ b/src/3rdparty/libarchive/config-windows.h @@ -0,0 +1,1149 @@ +/* config.h. Generated from build/cmake/config.h.in by cmake configure */ + +/* + * Ensure we have C99-style int64_t, etc, all defined. + */ + +/* First, we need to know if the system has already defined them. */ +#define HAVE_INT16_T +#define HAVE_INT32_T +#define HAVE_INT64_T +#define HAVE_INTMAX_T + +#define HAVE_UINT8_T +#define HAVE_UINT16_T +#define HAVE_UINT32_T +#define HAVE_UINT64_T +#define HAVE_UINTMAX_T + +/* We might have the types we want under other spellings. */ +#define HAVE___INT64 +/* #undef HAVE_U_INT64_T */ +#define HAVE_UNSIGNED___INT64 + +/* The sizes of various standard integer types. */ +#define SIZE_OF_SHORT 2 +#define SIZE_OF_INT 4 +#define SIZE_OF_LONG 4 +#define SIZE_OF_LONG_LONG 8 +#define SIZE_OF_UNSIGNED_SHORT 2 +#define SIZE_OF_UNSIGNED 4 +#define SIZE_OF_UNSIGNED_LONG 4 +#define SIZE_OF_UNSIGNED_LONG_LONG 8 + +/* + * If we lack int64_t, define it to the first of __int64, int, long, and long long + * that exists and is the right size. + */ +#if !defined(HAVE_INT64_T) && defined(HAVE___INT64) +typedef __int64 int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_INT == 8 +typedef int int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG == 8 +typedef long int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG_LONG == 8 +typedef long long int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) +#error No 64-bit integer type was found. +#endif + +/* + * Similarly for int32_t + */ +#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4 +typedef long int32_t; +#define HAVE_INT32_T +#endif + +#if !defined(HAVE_INT32_T) && SIZE_OF_LONG == 4 +typedef long int32_t; +#define HAVE_INT32_T +#endif + +#if !defined(HAVE_INT32_T) +#error No 32-bit integer type was found. +#endif + +/* + * Similarly for int16_t + */ +#if !defined(HAVE_INT16_T) && SIZE_OF_INT == 2 +typedef int int16_t; +#define HAVE_INT16_T +#endif + +#if !defined(HAVE_INT16_T) && SIZE_OF_SHORT == 2 +typedef short int16_t; +#define HAVE_INT16_T +#endif + +#if !defined(HAVE_INT16_T) +#error No 16-bit integer type was found. +#endif + +/* + * Similarly for uint64_t + */ +#if !defined(HAVE_UINT64_T) && defined(HAVE_UNSIGNED___INT64) +typedef unsigned __int64 uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED == 8 +typedef unsigned uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG == 8 +typedef unsigned long uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG_LONG == 8 +typedef unsigned long long uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) +#error No 64-bit unsigned integer type was found. +#endif + + +/* + * Similarly for uint32_t + */ +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED == 4 +typedef unsigned uint32_t; +#define HAVE_UINT32_T +#endif + +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED_LONG == 4 +typedef unsigned long uint32_t; +#define HAVE_UINT32_T +#endif + +#if !defined(HAVE_UINT32_T) +#error No 32-bit unsigned integer type was found. +#endif + +/* + * Similarly for uint16_t + */ +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED == 2 +typedef unsigned uint16_t; +#define HAVE_UINT16_T +#endif + +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED_SHORT == 2 +typedef unsigned short uint16_t; +#define HAVE_UINT16_T +#endif + +#if !defined(HAVE_UINT16_T) +#error No 16-bit unsigned integer type was found. +#endif + +/* + * Similarly for uint8_t + */ +#if !defined(HAVE_UINT8_T) +typedef unsigned char uint8_t; +#define HAVE_UINT8_T +#endif + +#if !defined(HAVE_UINT16_T) +#error No 8-bit unsigned integer type was found. +#endif + +/* Define intmax_t and uintmax_t if they are not already defined. */ +#if !defined(HAVE_INTMAX_T) +typedef int64_t intmax_t; +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#endif + +#if !defined(HAVE_UINTMAX_T) +typedef uint64_t uintmax_t; +#endif + +/* Define ZLIB_WINAPI if zlib was built on Visual Studio. */ +/* #undef ZLIB_WINAPI */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBC */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */ + +/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */ +#define ARCHIVE_CRYPTO_MD5_WIN 1 + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */ + +/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */ + +/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */ +#define ARCHIVE_CRYPTO_SHA1_WIN 1 + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */ + +/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA256_WIN */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */ + +/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA384_WIN */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */ + +/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ +/* #undef ARCHIVE_CRYPTO_SHA512_WIN */ + +/* Version number of bsdcpio */ +#define BSDCPIO_VERSION_STRING "3.1.2" + +/* Version number of bsdtar */ +#define BSDTAR_VERSION_STRING "3.1.2" + +/* Define to 1 if you have the `acl_create_entry' function. */ +/* #undef HAVE_ACL_CREATE_ENTRY */ + +/* Define to 1 if you have the `acl_get_link' function. */ +/* #undef HAVE_ACL_GET_LINK */ + +/* Define to 1 if you have the `acl_get_link_np' function. */ +/* #undef HAVE_ACL_GET_LINK_NP */ + +/* Define to 1 if you have the `acl_get_perm' function. */ +/* #undef HAVE_ACL_GET_PERM */ + +/* Define to 1 if you have the `acl_get_perm_np' function. */ +/* #undef HAVE_ACL_GET_PERM_NP */ + +/* Define to 1 if you have the `acl_init' function. */ +/* #undef HAVE_ACL_INIT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ACL_LIBACL_H */ + +/* Define to 1 if the system has the type `acl_permset_t'. */ +/* #undef HAVE_ACL_PERMSET_T */ + +/* Define to 1 if you have the `acl_set_fd' function. */ +/* #undef HAVE_ACL_SET_FD */ + +/* Define to 1 if you have the `acl_set_fd_np' function. */ +/* #undef HAVE_ACL_SET_FD_NP */ + +/* Define to 1 if you have the `acl_set_file' function. */ +/* #undef HAVE_ACL_SET_FILE */ + +/* True for systems with POSIX ACL support */ +/* #undef HAVE_ACL_USER */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ATTR_XATTR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BSDXML_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BZLIB_H */ + +/* Define to 1 if you have the `chflags' function. */ +/* #undef HAVE_CHFLAGS */ + +/* Define to 1 if you have the `chown' function. */ +/* #undef HAVE_CHOWN */ + +/* Define to 1 if you have the `chroot' function. */ +/* #undef HAVE_CHROOT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_COPYFILE_H */ + +/* Define to 1 if you have the `ctime_r' function. */ +/* #undef HAVE_CTIME_R */ + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `cygwin_conv_path' function. */ +/* #undef HAVE_CYGWIN_CONV_PATH */ + +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MAX 1 + +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you + don't. */ +#define HAVE_DECL_INT64_MIN 1 + +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_SIZE_MAX 1 + +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you + don't. */ +/* #undef HAVE_DECL_SSIZE_MAX */ + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +/* #undef HAVE_DECL_STRERROR_R */ + +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT32_MAX 1 + +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you + don't. */ +#define HAVE_DECL_UINT64_MAX 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRECT_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_DIRENT_H */ + +/* Define to 1 if you have the `dirfd' function. */ +/* #undef HAVE_DIRFD */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if nl_langinfo supports D_MD_ORDER */ +/* #undef HAVE_D_MD_ORDER */ + +/* A possible errno value for invalid file format errors */ +/* #undef HAVE_EFTYPE */ + +/* A possible errno value for invalid file format errors */ +#define HAVE_EILSEQ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXPAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXT2FS_EXT2_FS_H */ + +/* Define to 1 if you have the `extattr_get_file' function. */ +/* #undef HAVE_EXTATTR_GET_FILE */ + +/* Define to 1 if you have the `extattr_list_file' function. */ +/* #undef HAVE_EXTATTR_LIST_FILE */ + +/* Define to 1 if you have the `extattr_set_fd' function. */ +/* #undef HAVE_EXTATTR_SET_FD */ + +/* Define to 1 if you have the `extattr_set_file' function. */ +/* #undef HAVE_EXTATTR_SET_FILE */ + +/* Define to 1 if EXTATTR_NAMESPACE_USER is defined in sys/extattr.h. */ +/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */ + +/* Define to 1 if you have the `fchdir' function. */ +/* #undef HAVE_FCHDIR */ + +/* Define to 1 if you have the `fchflags' function. */ +/* #undef HAVE_FCHFLAGS */ + +/* Define to 1 if you have the `fchmod' function. */ +/* #undef HAVE_FCHMOD */ + +/* Define to 1 if you have the `fchown' function. */ +/* #undef HAVE_FCHOWN */ + +/* Define to 1 if you have the `fcntl' function. */ +/* #undef HAVE_FCNTL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopendir' function. */ +/* #undef HAVE_FDOPENDIR */ + +/* Define to 1 if you have the `fgetea' function. */ +/* #undef HAVE_FGETEA */ + +/* Define to 1 if you have the `fgetxattr' function. */ +/* #undef HAVE_FGETXATTR */ + +/* Define to 1 if you have the `flistea' function. */ +/* #undef HAVE_FLISTEA */ + +/* Define to 1 if you have the `flistxattr' function. */ +/* #undef HAVE_FLISTXATTR */ + +/* Define to 1 if you have the `fork' function. */ +/* #undef HAVE_FORK */ + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +/* #undef HAVE_FSEEKO */ + +/* Define to 1 if you have the `fsetea' function. */ +/* #undef HAVE_FSETEA */ + +/* Define to 1 if you have the `fsetxattr' function. */ +/* #undef HAVE_FSETXATTR */ + +/* Define to 1 if you have the `fstat' function. */ +#define HAVE_FSTAT 1 + +/* Define to 1 if you have the `fstatat' function. */ +/* #undef HAVE_FSTATAT */ + +/* Define to 1 if you have the `fstatfs' function. */ +/* #undef HAVE_FSTATFS */ + +/* Define to 1 if you have the `fstatvfs' function. */ +/* #undef HAVE_FSTATVFS */ + +/* Define to 1 if you have the `ftruncate' function. */ +/* #undef HAVE_FTRUNCATE */ + +/* Define to 1 if you have the `futimens' function. */ +/* #undef HAVE_FUTIMENS */ + +/* Define to 1 if you have the `futimes' function. */ +/* #undef HAVE_FUTIMES */ + +/* Define to 1 if you have the `futimesat' function. */ +/* #undef HAVE_FUTIMESAT */ + +/* Define to 1 if you have the `getea' function. */ +/* #undef HAVE_GETEA */ + +/* Define to 1 if you have the `geteuid' function. */ +/* #undef HAVE_GETEUID */ + +/* Define to 1 if you have the `getgrgid_r' function. */ +/* #undef HAVE_GETGRGID_R */ + +/* Define to 1 if you have the `getgrnam_r' function. */ +/* #undef HAVE_GETGRNAM_R */ + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpwnam_r' function. */ +/* #undef HAVE_GETPWNAM_R */ + +/* Define to 1 if you have the `getpwuid_r' function. */ +/* #undef HAVE_GETPWUID_R */ + +/* Define to 1 if you have the `getvfsbyname' function. */ +/* #undef HAVE_GETVFSBYNAME */ + +/* Define to 1 if you have the `getxattr' function. */ +/* #undef HAVE_GETXATTR */ + +/* Define to 1 if you have the `gmtime_r' function. */ +/* #undef HAVE_GMTIME_R */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GRP_H */ + +/* Define to 1 if you have the `iconv' function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ICONV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LANGINFO_H */ + +/* Define to 1 if you have the `lchflags' function. */ +/* #undef HAVE_LCHFLAGS */ + +/* Define to 1 if you have the `lchmod' function. */ +/* #undef HAVE_LCHMOD */ + +/* Define to 1 if you have the `lchown' function. */ +/* #undef HAVE_LCHOWN */ + +/* Define to 1 if you have the `lgetea' function. */ +/* #undef HAVE_LGETEA */ + +/* Define to 1 if you have the `lgetxattr' function. */ +/* #undef HAVE_LGETXATTR */ + +/* Define to 1 if you have the `acl' library (-lacl). */ +/* #undef HAVE_LIBACL */ + +/* Define to 1 if you have the `attr' library (-lattr). */ +/* #undef HAVE_LIBATTR */ + +/* Define to 1 if you have the `bsdxml' library (-lbsdxml). */ +/* #undef HAVE_LIBBSDXML */ + +/* Define to 1 if you have the `bz2' library (-lbz2). */ +/* #undef HAVE_LIBBZ2 */ + +/* Define to 1 if you have the `expat' library (-lexpat). */ +/* #undef HAVE_LIBEXPAT */ + +/* Define to 1 if you have the `gcc' library (-lgcc). */ +/* #undef HAVE_LIBGCC */ + +/* Define to 1 if you have the `lzma' library (-llzma). */ +/* #undef HAVE_LIBLZMA */ + +/* Define to 1 if you have the `lzmadec' library (-llzmadec). */ +/* #undef HAVE_LIBLZMADEC */ + +/* Define to 1 if you have the `lzo2' library (-llzo2). */ +/* #undef HAVE_LIBLZO2 */ + +/* Define to 1 if you have the `nettle' library (-lnettle). */ +/* #undef HAVE_LIBNETTLE */ + +/* Define to 1 if you have the `pcre' library (-lpcre). */ +/* #undef HAVE_LIBPCRE */ + +/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ +/* #undef HAVE_LIBPCREPOSIX */ + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +/* #undef HAVE_LIBXML2 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLREADER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBXML_XMLWRITER_H */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `link' function. */ +/* #undef HAVE_LINK */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FIEMAP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_MAGIC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_TYPES_H */ + +/* Define to 1 if you have the `listea' function. */ +/* #undef HAVE_LISTEA */ + +/* Define to 1 if you have the `listxattr' function. */ +/* #undef HAVE_LISTXATTR */ + +/* Define to 1 if you have the `llistea' function. */ +/* #undef HAVE_LLISTEA */ + +/* Define to 1 if you have the `llistxattr' function. */ +/* #undef HAVE_LLISTXATTR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LOCALCHARSET_H */ + +/* Define to 1 if you have the `locale_charset' function. */ +/* #undef HAVE_LOCALE_CHARSET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +/* #undef HAVE_LOCALTIME_R */ + +/* Define to 1 if the system has the type `long long int'. */ +/* #undef HAVE_LONG_LONG_INT */ + +/* Define to 1 if you have the `lsetea' function. */ +/* #undef HAVE_LSETEA */ + +/* Define to 1 if you have the `lsetxattr' function. */ +/* #undef HAVE_LSETXATTR */ + +/* Define to 1 if you have the `lstat' function. */ +/* #undef HAVE_LSTAT */ + +/* Define to 1 if `lstat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the `lutimes' function. */ +/* #undef HAVE_LUTIMES */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMADEC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZO1X_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZO_LZOCONF_H */ + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mkfifo' function. */ +/* #undef HAVE_MKFIFO */ + +/* Define to 1 if you have the `mknod' function. */ +/* #undef HAVE_MKNOD */ + +/* Define to 1 if you have the `mkstemp' function. */ +/* #undef HAVE_MKSTEMP */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_MD5_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_RIPEMD160_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETTLE_SHA_H */ + +/* Define to 1 if you have the `nl_langinfo' function. */ +/* #undef HAVE_NL_LANGINFO */ + +/* Define to 1 if you have the `openat' function. */ +/* #undef HAVE_OPENAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PATHS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PCREPOSIX_H */ + +/* Define to 1 if you have the `pipe' function. */ +/* #undef HAVE_PIPE */ + +/* Define to 1 if you have the `poll' function. */ +/* #undef HAVE_POLL */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_POLL_H */ + +/* Define to 1 if you have the `posix_spawnp' function. */ +/* #undef HAVE_POSIX_SPAWNP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PROCESS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PWD_H */ + +/* Define to 1 if you have the `readdir_r' function. */ +/* #undef HAVE_READDIR_R */ + +/* Define to 1 if you have the `readlink' function. */ +/* #undef HAVE_READLINK */ + +/* Define to 1 if you have the `readlinkat' function. */ +/* #undef HAVE_READLINKAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_REGEX_H */ + +/* Define to 1 if you have the `select' function. */ +/* #undef HAVE_SELECT */ + +/* Define to 1 if you have the `setenv' function. */ +/* #undef HAVE_SETENV */ + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `sigaction' function. */ +/* #undef HAVE_SIGACTION */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SPAWN_H */ + +/* Define to 1 if you have the `statfs' function. */ +/* #undef HAVE_STATFS */ + +/* Define to 1 if you have the `statvfs' function. */ +/* #undef HAVE_STATVFS */ + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +/* #undef HAVE_STRERROR_R */ + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if `f_namemax' is a member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ + +/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */ + +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ + +/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */ + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ + +/* Define to 1 if `st_flags' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ + +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */ + +/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */ + +/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */ + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ + +/* Define to 1 if `st_umtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_UMTIME */ + +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM_TM_GMTOFF */ + +/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM___TM_GMTOFF */ + +/* Define to 1 if you have the `symlink' function. */ +/* #undef HAVE_SYMLINK */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ACL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_CDEFS_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EXTATTR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MOUNT_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_POLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STATVFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTIME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UTSNAME_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the `timegm' function. */ +/* #undef HAVE_TIMEGM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the `tzset' function. */ +#define HAVE_TZSET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if you have the `unsetenv' function. */ +/* #undef HAVE_UNSETENV */ + +/* Define to 1 if the system has the type `unsigned long long'. */ +/* #undef HAVE_UNSIGNED_LONG_LONG */ + +/* Define to 1 if the system has the type `unsigned long long int'. */ +/* #undef HAVE_UNSIGNED_LONG_LONG_INT */ + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +/* #undef HAVE_UTIMENSAT */ + +/* Define to 1 if you have the `utimes' function. */ +/* #undef HAVE_UTIMES */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTIME_H */ + +/* Define to 1 if you have the `vfork' function. */ +/* #undef HAVE_VFORK */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if the system has the type `wchar_t'. */ +#define HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the `wcscmp' function. */ +#define HAVE_WCSCMP 1 + +/* Define to 1 if you have the `wcscpy' function. */ +#define HAVE_WCSCPY 1 + +/* Define to 1 if you have the `wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the `wctomb' function. */ +#define HAVE_WCTOMB 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCTYPE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WINCRYPT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WINDOWS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WINIOCTL_H 1 + +/* Define to 1 if you have _CrtSetReportMode in */ +#define HAVE__CrtSetReportMode 1 + +/* Define to 1 if you have the `wmemcmp' function. */ +/* #undef HAVE_WMEMCMP */ + +/* Define to 1 if you have the `wmemcpy' function. */ +/* #undef HAVE_WMEMCPY */ + +/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */ +/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H 1 + +/* Define to 1 if you have the `_ctime64_s' function. */ +#define HAVE__CTIME64_S 1 + +/* Define to 1 if you have the `_fseeki64' function. */ +#define HAVE__FSEEKI64 1 + +/* Define to 1 if you have the `_get_timezone' function. */ +#define HAVE__GET_TIMEZONE 1 + +/* Define to 1 if you have the `_localtime64_s' function. */ +#define HAVE__LOCALTIME64_S 1 + +/* Define to 1 if you have the `_mkgmtime64' function. */ +#define HAVE__MKGMTIME64 1 + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Version number of libarchive as a single integer */ +#define LIBARCHIVE_VERSION_NUMBER "3001002" + +/* Version number of libarchive */ +#define LIBARCHIVE_VERSION_STRING "3.1.2" + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 2 + +/* Define to 1 if strerror_r returns char *. */ +/* #undef STRERROR_R_CHAR_P */ + +/* Define to 1 if you can safely include both and . */ +/* #undef TIME_WITH_SYS_TIME */ + +/* + * Some platform requires a macro to use extension functions. + */ +#define SAFE_TO_DEFINE_EXTENSIONS 1 +#ifdef SAFE_TO_DEFINE_EXTENSIONS +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +#endif /* SAFE_TO_DEFINE_EXTENSIONS */ + +/* Version number of package */ +#define VERSION "3.1.2" + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define for Windows to use Windows 2000+ APIs. */ +#define _WIN32_WINNT 0x0500 +#define WINVER 0x0500 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +#define gid_t short + +/* Define to `unsigned long' if does not define. */ +#define id_t short + +/* Define to `int' if does not define. */ +#ifndef __MINGW32__ +# define mode_t unsigned short +#endif + +/* Define to `long long' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +#define pid_t int + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +#if defined(_WIN64) +# define ssize_t __int64 +#else +# define ssize_t long +#endif + +/* Define to `int' if doesn't define. */ +#define uid_t short + +/* Define to `int' if does not define. */ +/* #undef intptr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef uintptr_t */ diff --git a/src/3rdparty/libarchive/libarchive.pro b/src/3rdparty/libarchive/libarchive.pro new file mode 100644 index 00000000..4ec7eaaa --- /dev/null +++ b/src/3rdparty/libarchive/libarchive.pro @@ -0,0 +1,126 @@ +TEMPLATE = lib +TARGET = qtarchive + +load(am-config) + +CONFIG += \ + static \ + hide_symbols \ + exceptions_off rtti_off warn_off \ + installed + +macos:LIBS += -framework CoreServices -liconv +ios:LIBS += -liconv +win32:LIBS += -lcrypt32 -ladvapi32 +win32:MODULE_DEFINES += LIBARCHIVE_STATIC +MODULE_INCLUDEPATH += $$PWD/libarchive + +load(qt_helper_lib) + +win32-msvc* { + QMAKE_CFLAGS += /wd4146 /wd4133 /D_CRT_SECURE_NO_WARNINGS +} +*-g++* { + QMAKE_CFLAGS += -Wno-unused -Wno-sign-compare -Wno-old-style-declaration +} +*-clang* { + CONFIG *= warn_off + QMAKE_CFLAGS += -Wall -W -Wno-unused -Wno-sign-compare +} + +android:DEFINES += PLATFORM_CONFIG_H=\\\"config-android.h\\\" +else:win32:DEFINES += PLATFORM_CONFIG_H=\\\"config-windows.h\\\" +else:macos:DEFINES += PLATFORM_CONFIG_H=\\\"config-macos.h\\\" +else:ios:DEFINES += PLATFORM_CONFIG_H=\\\"config-ios.h\\\" +else:DEFINES += PLATFORM_CONFIG_H=\\\"config-unix.h\\\" + +OTHER_FILES += \ + config-android.h \ + config-windows.h \ + config-macos.h \ + config-ios.h \ + config-unix.h \ + android_lf.h \ + +INCLUDEPATH *= $$PWD/libarchive + +include(../libz.pri) + +# disabled for now, since we have 2 problems: +# 1) the python/django appstore is based on python 2.7 which does not support it via tarfile +# 2) we get a weird error on macOS when creating XZ'ed packages from libarchive +# include(../liblzma.pri) + +SOURCES += \ + libarchive/archive_acl.c \ + libarchive/archive_check_magic.c \ + libarchive/archive_cmdline.c \ + libarchive/archive_entry.c \ + libarchive/archive_entry_copy_stat.c \ + libarchive/archive_entry_link_resolver.c \ + libarchive/archive_entry_sparse.c \ + libarchive/archive_entry_stat.c \ + libarchive/archive_entry_strmode.c \ + libarchive/archive_entry_xattr.c \ + libarchive/archive_getdate.c \ + libarchive/archive_match.c \ + libarchive/archive_options.c \ + libarchive/archive_pathmatch.c \ + libarchive/archive_ppmd7.c \ + libarchive/archive_random.c \ + libarchive/archive_rb.c \ + libarchive/archive_read_append_filter.c \ + libarchive/archive_read.c \ + libarchive/archive_read_data_into_fd.c \ + libarchive/archive_read_disk_entry_from_file.c \ + libarchive/archive_read_disk_set_standard_lookup.c \ + libarchive/archive_read_extract.c \ + libarchive/archive_read_open_fd.c \ + libarchive/archive_read_open_file.c \ + libarchive/archive_read_open_filename.c \ + libarchive/archive_read_open_memory.c \ + libarchive/archive_read_set_format.c \ + libarchive/archive_read_set_options.c \ + libarchive/archive_read_support_filter_bzip2.c \ + libarchive/archive_read_support_filter_gzip.c \ + libarchive/archive_read_support_filter_none.c \ + libarchive/archive_read_support_filter_program.c \ + libarchive/archive_read_support_filter_xz.c \ + libarchive/archive_read_support_format_by_code.c \ + libarchive/archive_read_support_format_empty.c \ + libarchive/archive_read_support_format_tar.c \ + libarchive/archive_string.c \ + libarchive/archive_string_sprintf.c \ + libarchive/archive_util.c \ + libarchive/archive_virtual.c \ + libarchive/archive_write_add_filter_b64encode.c \ + libarchive/archive_write_add_filter_by_name.c \ + libarchive/archive_write_add_filter_bzip2.c \ + libarchive/archive_write_add_filter.c \ + libarchive/archive_write_add_filter_gzip.c \ + libarchive/archive_write_add_filter_none.c \ + libarchive/archive_write_add_filter_program.c \ + libarchive/archive_write_add_filter_xz.c \ + libarchive/archive_write.c \ + libarchive/archive_write_disk_set_standard_lookup.c \ + libarchive/archive_write_open_fd.c \ + libarchive/archive_write_open_file.c \ + libarchive/archive_write_open_filename.c \ + libarchive/archive_write_open_memory.c \ + libarchive/archive_write_set_format_by_name.c \ + libarchive/archive_write_set_format.c \ + libarchive/archive_write_set_format_gnutar.c \ + libarchive/archive_write_set_format_ustar.c \ + libarchive/archive_write_set_options.c \ + +!win32:SOURCES += \ + libarchive/archive_read_disk_posix.c \ + libarchive/archive_write_disk_posix.c \ + libarchive/filter_fork_posix.c \ + +win32:SOURCES += \ + libarchive/archive_entry_copy_bhfi.c \ + libarchive/archive_read_disk_windows.c \ + libarchive/archive_windows.c \ + libarchive/archive_write_disk_windows.c \ + libarchive/filter_fork_windows.c \ diff --git a/src/3rdparty/libarchive/libarchive/android_lf.h b/src/3rdparty/libarchive/libarchive/android_lf.h new file mode 100644 index 00000000..2a18f514 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/android_lf.h @@ -0,0 +1,47 @@ +/* + * Macros for file64 functions + * + * Android does not support the macro _FILE_OFFSET_BITS=64 + * As of android-21 it does however support many file64 functions +*/ + +#ifndef ARCHIVE_ANDROID_LF_H_INCLUDED +#define ARCHIVE_ANDROID_LF_H_INCLUDED + +#if __ANDROID_API__ > 20 + +#include +#include +#include +#include +#include +#include +#include + +//dirent.h +#define readdir_r readdir64_r +#define readdir readdir64 +#define dirent dirent64 +//fcntl.h +#define openat openat64 +#define open open64 +#define mkstemp mkstemp64 +//unistd.h +#define lseek lseek64 +#define ftruncate ftruncate64 +//sys/stat.h +#define fstatat fstatat64 +#define fstat fstat64 +#define lstat lstat64 +#define stat stat64 +//sys/statvfs.h +#define fstatvfs fstatvfs64 +#define statvfs statvfs64 +//sys/types.h +#define off_t off64_t +//sys/vfs.h +#define fstatfs fstatfs64 +#define statfs statfs64 +#endif + +#endif /* ARCHIVE_ANDROID_LF_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive.h b/src/3rdparty/libarchive/libarchive/archive.h new file mode 100644 index 00000000..316a68a6 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive.h @@ -0,0 +1,1187 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $ + */ + +#ifndef ARCHIVE_H_INCLUDED +#define ARCHIVE_H_INCLUDED + +/* + * The version number is expressed as a single integer that makes it + * easy to compare versions at build time: for version a.b.c, the + * version number is printf("%d%03d%03d",a,b,c). For example, if you + * know your application requires version 2.12.108 or later, you can + * assert that ARCHIVE_VERSION_NUMBER >= 2012108. + */ +/* Note: Compiler will complain if this does not match archive_entry.h! */ +#define ARCHIVE_VERSION_NUMBER 3003002 + +#include +#include /* for wchar_t */ +#include /* For FILE * */ +#include /* For time_t */ + +/* + * Note: archive.h is for use outside of libarchive; the configuration + * headers (config.h, archive_platform.h, etc.) are purely internal. + * Do NOT use HAVE_XXX configuration macros to control the behavior of + * this header! If you must conditionalize, use predefined compiler and/or + * platform macros. + */ +#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 +# include +#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__) +# include +#endif + +/* Get appropriate definitions of 64-bit integer */ +#if !defined(__LA_INT64_T_DEFINED) +/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */ +# if ARCHIVE_VERSION_NUMBER < 4000000 +#define __LA_INT64_T la_int64_t +# endif +#define __LA_INT64_T_DEFINED +# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) +typedef __int64 la_int64_t; +# else +# include /* ssize_t */ +# if defined(_SCO_DS) || defined(__osf__) +typedef long long la_int64_t; +# else +typedef int64_t la_int64_t; +# endif +# endif +#endif + +/* The la_ssize_t should match the type used in 'struct stat' */ +#if !defined(__LA_SSIZE_T_DEFINED) +/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */ +# if ARCHIVE_VERSION_NUMBER < 4000000 +#define __LA_SSIZE_T la_ssize_t +# endif +#define __LA_SSIZE_T_DEFINED +# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) +# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_) +typedef ssize_t la_ssize_t; +# elif defined(_WIN64) +typedef __int64 la_ssize_t; +# else +typedef long la_ssize_t; +# endif +# else +# include /* ssize_t */ +typedef ssize_t la_ssize_t; +# endif +#endif + +/* Large file support for Android */ +#ifdef __ANDROID__ +#include "android_lf.h" +#endif + +/* + * On Windows, define LIBARCHIVE_STATIC if you're building or using a + * .lib. The default here assumes you're building a DLL. Only + * libarchive source should ever define __LIBARCHIVE_BUILD. + */ +#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) +# ifdef __LIBARCHIVE_BUILD +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllexport)) extern +# else +# define __LA_DECL __declspec(dllexport) +# endif +# else +# ifdef __GNUC__ +# define __LA_DECL +# else +# define __LA_DECL __declspec(dllimport) +# endif +# endif +#else +/* Static libraries or non-Windows needs no special declaration. */ +# define __LA_DECL +#endif + +#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__) +#define __LA_PRINTF(fmtarg, firstvararg) \ + __attribute__((__format__ (__printf__, fmtarg, firstvararg))) +#else +#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */ +#endif + +#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 +# define __LA_DEPRECATED __attribute__((deprecated)) +#else +# define __LA_DEPRECATED +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The version number is provided as both a macro and a function. + * The macro identifies the installed header; the function identifies + * the library version (which may not be the same if you're using a + * dynamically-linked version of the library). Of course, if the + * header and library are very different, you should expect some + * strangeness. Don't do that. + */ +__LA_DECL int archive_version_number(void); + +/* + * Textual name/version of the library, useful for version displays. + */ +#define ARCHIVE_VERSION_ONLY_STRING "3.3.2" +#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING +__LA_DECL const char * archive_version_string(void); + +/* + * Detailed textual name/version of the library and its dependencies. + * This has the form: + * "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..." + * the list of libraries described here will vary depending on how + * libarchive was compiled. + */ +__LA_DECL const char * archive_version_details(void); + +/* + * Returns NULL if libarchive was compiled without the associated library. + * Otherwise, returns the version number that libarchive was compiled + * against. + */ +__LA_DECL const char * archive_zlib_version(void); +__LA_DECL const char * archive_liblzma_version(void); +__LA_DECL const char * archive_bzlib_version(void); +__LA_DECL const char * archive_liblz4_version(void); + +/* Declare our basic types. */ +struct archive; +struct archive_entry; + +/* + * Error codes: Use archive_errno() and archive_error_string() + * to retrieve details. Unless specified otherwise, all functions + * that return 'int' use these codes. + */ +#define ARCHIVE_EOF 1 /* Found end of archive. */ +#define ARCHIVE_OK 0 /* Operation was successful. */ +#define ARCHIVE_RETRY (-10) /* Retry might succeed. */ +#define ARCHIVE_WARN (-20) /* Partial success. */ +/* For example, if write_header "fails", then you can't push data. */ +#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */ +/* But if write_header is "fatal," then this archive is dead and useless. */ +#define ARCHIVE_FATAL (-30) /* No more operations are possible. */ + +/* + * As far as possible, archive_errno returns standard platform errno codes. + * Of course, the details vary by platform, so the actual definitions + * here are stored in "archive_platform.h". The symbols are listed here + * for reference; as a rule, clients should not need to know the exact + * platform-dependent error code. + */ +/* Unrecognized or invalid file format. */ +/* #define ARCHIVE_ERRNO_FILE_FORMAT */ +/* Illegal usage of the library. */ +/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */ +/* Unknown or unclassified error. */ +/* #define ARCHIVE_ERRNO_MISC */ + +/* + * Callbacks are invoked to automatically read/skip/write/open/close the + * archive. You can provide your own for complex tasks (like breaking + * archives across multiple tapes) or use standard ones built into the + * library. + */ + +/* Returns pointer and size of next block of data from archive. */ +typedef la_ssize_t archive_read_callback(struct archive *, + void *_client_data, const void **_buffer); + +/* Skips at most request bytes from archive and returns the skipped amount. + * This may skip fewer bytes than requested; it may even skip zero bytes. + * If you do skip fewer bytes than requested, libarchive will invoke your + * read callback and discard data as necessary to make up the full skip. + */ +typedef la_int64_t archive_skip_callback(struct archive *, + void *_client_data, la_int64_t request); + +/* Seeks to specified location in the file and returns the position. + * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h. + * Return ARCHIVE_FATAL if the seek fails for any reason. + */ +typedef la_int64_t archive_seek_callback(struct archive *, + void *_client_data, la_int64_t offset, int whence); + +/* Returns size actually written, zero on EOF, -1 on error. */ +typedef la_ssize_t archive_write_callback(struct archive *, + void *_client_data, + const void *_buffer, size_t _length); + +typedef int archive_open_callback(struct archive *, void *_client_data); + +typedef int archive_close_callback(struct archive *, void *_client_data); + +/* Switches from one client data object to the next/prev client data object. + * This is useful for reading from different data blocks such as a set of files + * that make up one large file. + */ +typedef int archive_switch_callback(struct archive *, void *_client_data1, + void *_client_data2); + +/* + * Returns a passphrase used for encryption or decryption, NULL on nothing + * to do and give it up. + */ +typedef const char *archive_passphrase_callback(struct archive *, + void *_client_data); + +/* + * Codes to identify various stream filters. + */ +#define ARCHIVE_FILTER_NONE 0 +#define ARCHIVE_FILTER_GZIP 1 +#define ARCHIVE_FILTER_BZIP2 2 +#define ARCHIVE_FILTER_COMPRESS 3 +#define ARCHIVE_FILTER_PROGRAM 4 +#define ARCHIVE_FILTER_LZMA 5 +#define ARCHIVE_FILTER_XZ 6 +#define ARCHIVE_FILTER_UU 7 +#define ARCHIVE_FILTER_RPM 8 +#define ARCHIVE_FILTER_LZIP 9 +#define ARCHIVE_FILTER_LRZIP 10 +#define ARCHIVE_FILTER_LZOP 11 +#define ARCHIVE_FILTER_GRZIP 12 +#define ARCHIVE_FILTER_LZ4 13 + +#if ARCHIVE_VERSION_NUMBER < 4000000 +#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE +#define ARCHIVE_COMPRESSION_GZIP ARCHIVE_FILTER_GZIP +#define ARCHIVE_COMPRESSION_BZIP2 ARCHIVE_FILTER_BZIP2 +#define ARCHIVE_COMPRESSION_COMPRESS ARCHIVE_FILTER_COMPRESS +#define ARCHIVE_COMPRESSION_PROGRAM ARCHIVE_FILTER_PROGRAM +#define ARCHIVE_COMPRESSION_LZMA ARCHIVE_FILTER_LZMA +#define ARCHIVE_COMPRESSION_XZ ARCHIVE_FILTER_XZ +#define ARCHIVE_COMPRESSION_UU ARCHIVE_FILTER_UU +#define ARCHIVE_COMPRESSION_RPM ARCHIVE_FILTER_RPM +#define ARCHIVE_COMPRESSION_LZIP ARCHIVE_FILTER_LZIP +#define ARCHIVE_COMPRESSION_LRZIP ARCHIVE_FILTER_LRZIP +#endif + +/* + * Codes returned by archive_format. + * + * Top 16 bits identifies the format family (e.g., "tar"); lower + * 16 bits indicate the variant. This is updated by read_next_header. + * Note that the lower 16 bits will often vary from entry to entry. + * In some cases, this variation occurs as libarchive learns more about + * the archive (for example, later entries might utilize extensions that + * weren't necessary earlier in the archive; in this case, libarchive + * will change the format code to indicate the extended format that + * was used). In other cases, it's because different tools have + * modified the archive and so different parts of the archive + * actually have slightly different formats. (Both tar and cpio store + * format codes in each entry, so it is quite possible for each + * entry to be in a different format.) + */ +#define ARCHIVE_FORMAT_BASE_MASK 0xff0000 +#define ARCHIVE_FORMAT_CPIO 0x10000 +#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1) +#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2) +#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3) +#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) +#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) +#define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6) +#define ARCHIVE_FORMAT_SHAR 0x20000 +#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) +#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) +#define ARCHIVE_FORMAT_TAR 0x30000 +#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1) +#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2) +#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3) +#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4) +#define ARCHIVE_FORMAT_ISO9660 0x40000 +#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1) +#define ARCHIVE_FORMAT_ZIP 0x50000 +#define ARCHIVE_FORMAT_EMPTY 0x60000 +#define ARCHIVE_FORMAT_AR 0x70000 +#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1) +#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2) +#define ARCHIVE_FORMAT_MTREE 0x80000 +#define ARCHIVE_FORMAT_RAW 0x90000 +#define ARCHIVE_FORMAT_XAR 0xA0000 +#define ARCHIVE_FORMAT_LHA 0xB0000 +#define ARCHIVE_FORMAT_CAB 0xC0000 +#define ARCHIVE_FORMAT_RAR 0xD0000 +#define ARCHIVE_FORMAT_7ZIP 0xE0000 +#define ARCHIVE_FORMAT_WARC 0xF0000 + +/* + * Codes returned by archive_read_format_capabilities(). + * + * This list can be extended with values between 0 and 0xffff. + * The original purpose of this list was to let different archive + * format readers expose their general capabilities in terms of + * encryption. + */ +#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */ +#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */ +#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */ + +/* + * Codes returned by archive_read_has_encrypted_entries(). + * + * In case the archive does not support encryption detection at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader + * for some other reason (e.g. not enough bytes read) cannot say if + * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW + * is returned. + */ +#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2 +#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1 + +/*- + * Basic outline for reading an archive: + * 1) Ask archive_read_new for an archive reader object. + * 2) Update any global properties as appropriate. + * In particular, you'll certainly want to call appropriate + * archive_read_support_XXX functions. + * 3) Call archive_read_open_XXX to open the archive + * 4) Repeatedly call archive_read_next_header to get information about + * successive archive entries. Call archive_read_data to extract + * data for entries of interest. + * 5) Call archive_read_free to end processing. + */ +__LA_DECL struct archive *archive_read_new(void); + +/* + * The archive_read_support_XXX calls enable auto-detect for this + * archive handle. They also link in the necessary support code. + * For example, if you don't want bzlib linked in, don't invoke + * support_compression_bzip2(). The "all" functions provide the + * obvious shorthand. + */ + +#if ARCHIVE_VERSION_NUMBER < 4000000 +__LA_DECL int archive_read_support_compression_all(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_bzip2(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_compress(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_gzip(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_lzip(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_lzma(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_none(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_program(struct archive *, + const char *command) __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_program_signature + (struct archive *, const char *, + const void * /* match */, size_t) __LA_DEPRECATED; + +__LA_DECL int archive_read_support_compression_rpm(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_uu(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_read_support_compression_xz(struct archive *) + __LA_DEPRECATED; +#endif + +__LA_DECL int archive_read_support_filter_all(struct archive *); +__LA_DECL int archive_read_support_filter_bzip2(struct archive *); +__LA_DECL int archive_read_support_filter_compress(struct archive *); +__LA_DECL int archive_read_support_filter_gzip(struct archive *); +__LA_DECL int archive_read_support_filter_grzip(struct archive *); +__LA_DECL int archive_read_support_filter_lrzip(struct archive *); +__LA_DECL int archive_read_support_filter_lz4(struct archive *); +__LA_DECL int archive_read_support_filter_lzip(struct archive *); +__LA_DECL int archive_read_support_filter_lzma(struct archive *); +__LA_DECL int archive_read_support_filter_lzop(struct archive *); +__LA_DECL int archive_read_support_filter_none(struct archive *); +__LA_DECL int archive_read_support_filter_program(struct archive *, + const char *command); +__LA_DECL int archive_read_support_filter_program_signature + (struct archive *, const char * /* cmd */, + const void * /* match */, size_t); +__LA_DECL int archive_read_support_filter_rpm(struct archive *); +__LA_DECL int archive_read_support_filter_uu(struct archive *); +__LA_DECL int archive_read_support_filter_xz(struct archive *); + +__LA_DECL int archive_read_support_format_7zip(struct archive *); +__LA_DECL int archive_read_support_format_all(struct archive *); +__LA_DECL int archive_read_support_format_ar(struct archive *); +__LA_DECL int archive_read_support_format_by_code(struct archive *, int); +__LA_DECL int archive_read_support_format_cab(struct archive *); +__LA_DECL int archive_read_support_format_cpio(struct archive *); +__LA_DECL int archive_read_support_format_empty(struct archive *); +__LA_DECL int archive_read_support_format_gnutar(struct archive *); +__LA_DECL int archive_read_support_format_iso9660(struct archive *); +__LA_DECL int archive_read_support_format_lha(struct archive *); +__LA_DECL int archive_read_support_format_mtree(struct archive *); +__LA_DECL int archive_read_support_format_rar(struct archive *); +__LA_DECL int archive_read_support_format_raw(struct archive *); +__LA_DECL int archive_read_support_format_tar(struct archive *); +__LA_DECL int archive_read_support_format_warc(struct archive *); +__LA_DECL int archive_read_support_format_xar(struct archive *); +/* archive_read_support_format_zip() enables both streamable and seekable + * zip readers. */ +__LA_DECL int archive_read_support_format_zip(struct archive *); +/* Reads Zip archives as stream from beginning to end. Doesn't + * correctly handle SFX ZIP files or ZIP archives that have been modified + * in-place. */ +__LA_DECL int archive_read_support_format_zip_streamable(struct archive *); +/* Reads starting from central directory; requires seekable input. */ +__LA_DECL int archive_read_support_format_zip_seekable(struct archive *); + +/* Functions to manually set the format and filters to be used. This is + * useful to bypass the bidding process when the format and filters to use + * is known in advance. + */ +__LA_DECL int archive_read_set_format(struct archive *, int); +__LA_DECL int archive_read_append_filter(struct archive *, int); +__LA_DECL int archive_read_append_filter_program(struct archive *, + const char *); +__LA_DECL int archive_read_append_filter_program_signature + (struct archive *, const char *, const void * /* match */, size_t); + +/* Set various callbacks. */ +__LA_DECL int archive_read_set_open_callback(struct archive *, + archive_open_callback *); +__LA_DECL int archive_read_set_read_callback(struct archive *, + archive_read_callback *); +__LA_DECL int archive_read_set_seek_callback(struct archive *, + archive_seek_callback *); +__LA_DECL int archive_read_set_skip_callback(struct archive *, + archive_skip_callback *); +__LA_DECL int archive_read_set_close_callback(struct archive *, + archive_close_callback *); +/* Callback used to switch between one data object to the next */ +__LA_DECL int archive_read_set_switch_callback(struct archive *, + archive_switch_callback *); + +/* This sets the first data object. */ +__LA_DECL int archive_read_set_callback_data(struct archive *, void *); +/* This sets data object at specified index */ +__LA_DECL int archive_read_set_callback_data2(struct archive *, void *, + unsigned int); +/* This adds a data object at the specified index. */ +__LA_DECL int archive_read_add_callback_data(struct archive *, void *, + unsigned int); +/* This appends a data object to the end of list */ +__LA_DECL int archive_read_append_callback_data(struct archive *, void *); +/* This prepends a data object to the beginning of list */ +__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *); + +/* Opening freezes the callbacks. */ +__LA_DECL int archive_read_open1(struct archive *); + +/* Convenience wrappers around the above. */ +__LA_DECL int archive_read_open(struct archive *, void *_client_data, + archive_open_callback *, archive_read_callback *, + archive_close_callback *); +__LA_DECL int archive_read_open2(struct archive *, void *_client_data, + archive_open_callback *, archive_read_callback *, + archive_skip_callback *, archive_close_callback *); + +/* + * A variety of shortcuts that invoke archive_read_open() with + * canned callbacks suitable for common situations. The ones that + * accept a block size handle tape blocking correctly. + */ +/* Use this if you know the filename. Note: NULL indicates stdin. */ +__LA_DECL int archive_read_open_filename(struct archive *, + const char *_filename, size_t _block_size); +/* Use this for reading multivolume files by filenames. + * NOTE: Must be NULL terminated. Sorting is NOT done. */ +__LA_DECL int archive_read_open_filenames(struct archive *, + const char **_filenames, size_t _block_size); +__LA_DECL int archive_read_open_filename_w(struct archive *, + const wchar_t *_filename, size_t _block_size); +/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */ +__LA_DECL int archive_read_open_file(struct archive *, + const char *_filename, size_t _block_size) __LA_DEPRECATED; +/* Read an archive that's stored in memory. */ +__LA_DECL int archive_read_open_memory(struct archive *, + const void * buff, size_t size); +/* A more involved version that is only used for internal testing. */ +__LA_DECL int archive_read_open_memory2(struct archive *a, const void *buff, + size_t size, size_t read_size); +/* Read an archive that's already open, using the file descriptor. */ +__LA_DECL int archive_read_open_fd(struct archive *, int _fd, + size_t _block_size); +/* Read an archive that's already open, using a FILE *. */ +/* Note: DO NOT use this with tape drives. */ +__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file); + +/* Parses and returns next entry header. */ +__LA_DECL int archive_read_next_header(struct archive *, + struct archive_entry **); + +/* Parses and returns next entry header using the archive_entry passed in */ +__LA_DECL int archive_read_next_header2(struct archive *, + struct archive_entry *); + +/* + * Retrieve the byte offset in UNCOMPRESSED data where last-read + * header started. + */ +__LA_DECL la_int64_t archive_read_header_position(struct archive *); + +/* + * Returns 1 if the archive contains at least one encrypted entry. + * If the archive format not support encryption at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. + * If for any other reason (e.g. not enough data read so far) + * we cannot say whether there are encrypted entries, then + * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. + * In general, this function will return values below zero when the + * reader is uncertain or totally incapable of encryption support. + * When this function returns 0 you can be sure that the reader + * supports encryption detection but no encrypted entries have + * been found yet. + * + * NOTE: If the metadata/header of an archive is also encrypted, you + * cannot rely on the number of encrypted entries. That is why this + * function does not return the number of encrypted entries but# + * just shows that there are some. + */ +__LA_DECL int archive_read_has_encrypted_entries(struct archive *); + +/* + * Returns a bitmask of capabilities that are supported by the archive format reader. + * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. + */ +__LA_DECL int archive_read_format_capabilities(struct archive *); + +/* Read data from the body of an entry. Similar to read(2). */ +__LA_DECL la_ssize_t archive_read_data(struct archive *, + void *, size_t); + +/* Seek within the body of an entry. Similar to lseek(2). */ +__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int); + +/* + * A zero-copy version of archive_read_data that also exposes the file offset + * of each returned block. Note that the client has no way to specify + * the desired size of the block. The API does guarantee that offsets will + * be strictly increasing and that returned blocks will not overlap. + */ +__LA_DECL int archive_read_data_block(struct archive *a, + const void **buff, size_t *size, la_int64_t *offset); + +/*- + * Some convenience functions that are built on archive_read_data: + * 'skip': skips entire entry + * 'into_buffer': writes data into memory buffer that you provide + * 'into_fd': writes data to specified filedes + */ +__LA_DECL int archive_read_data_skip(struct archive *); +__LA_DECL int archive_read_data_into_fd(struct archive *, int fd); + +/* + * Set read options. + */ +/* Apply option to the format only. */ +__LA_DECL int archive_read_set_format_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option to the filter only. */ +__LA_DECL int archive_read_set_filter_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option to both the format and the filter. */ +__LA_DECL int archive_read_set_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option string to both the format and the filter. */ +__LA_DECL int archive_read_set_options(struct archive *_a, + const char *opts); + +/* + * Add a decryption passphrase. + */ +__LA_DECL int archive_read_add_passphrase(struct archive *, const char *); +__LA_DECL int archive_read_set_passphrase_callback(struct archive *, + void *client_data, archive_passphrase_callback *); + + +/*- + * Convenience function to recreate the current entry (whose header + * has just been read) on disk. + * + * This does quite a bit more than just copy data to disk. It also: + * - Creates intermediate directories as required. + * - Manages directory permissions: non-writable directories will + * be initially created with write permission enabled; when the + * archive is closed, dir permissions are edited to the values specified + * in the archive. + * - Checks hardlinks: hardlinks will not be extracted unless the + * linked-to file was also extracted within the same session. (TODO) + */ + +/* The "flags" argument selects optional behavior, 'OR' the flags you want. */ + +/* Default: Do not try to set owner/group. */ +#define ARCHIVE_EXTRACT_OWNER (0x0001) +/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ +#define ARCHIVE_EXTRACT_PERM (0x0002) +/* Default: Do not restore mtime/atime. */ +#define ARCHIVE_EXTRACT_TIME (0x0004) +/* Default: Replace existing files. */ +#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008) +/* Default: Try create first, unlink only if create fails with EEXIST. */ +#define ARCHIVE_EXTRACT_UNLINK (0x0010) +/* Default: Do not restore ACLs. */ +#define ARCHIVE_EXTRACT_ACL (0x0020) +/* Default: Do not restore fflags. */ +#define ARCHIVE_EXTRACT_FFLAGS (0x0040) +/* Default: Do not restore xattrs. */ +#define ARCHIVE_EXTRACT_XATTR (0x0080) +/* Default: Do not try to guard against extracts redirected by symlinks. */ +/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */ +#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100) +/* Default: Do not reject entries with '..' as path elements. */ +#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200) +/* Default: Create parent directories as needed. */ +#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400) +/* Default: Overwrite files, even if one on disk is newer. */ +#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) +/* Detect blocks of 0 and write holes instead. */ +#define ARCHIVE_EXTRACT_SPARSE (0x1000) +/* Default: Do not restore Mac extended metadata. */ +/* This has no effect except on Mac OS. */ +#define ARCHIVE_EXTRACT_MAC_METADATA (0x2000) +/* Default: Use HFS+ compression if it was compressed. */ +/* This has no effect except on Mac OS v10.6 or later. */ +#define ARCHIVE_EXTRACT_NO_HFS_COMPRESSION (0x4000) +/* Default: Do not use HFS+ compression if it was not compressed. */ +/* This has no effect except on Mac OS v10.6 or later. */ +#define ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED (0x8000) +/* Default: Do not reject entries with absolute paths */ +#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000) +/* Default: Do not clear no-change flags when unlinking object */ +#define ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS (0x20000) + +__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *, + int flags); +__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *, + struct archive * /* dest */); +__LA_DECL void archive_read_extract_set_progress_callback(struct archive *, + void (*_progress_func)(void *), void *_user_data); + +/* Record the dev/ino of a file that will not be written. This is + * generally set to the dev/ino of the archive being read. */ +__LA_DECL void archive_read_extract_set_skip_file(struct archive *, + la_int64_t, la_int64_t); + +/* Close the file and release most resources. */ +__LA_DECL int archive_read_close(struct archive *); +/* Release all resources and destroy the object. */ +/* Note that archive_read_free will call archive_read_close for you. */ +__LA_DECL int archive_read_free(struct archive *); +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Synonym for archive_read_free() for backwards compatibility. */ +__LA_DECL int archive_read_finish(struct archive *) __LA_DEPRECATED; +#endif + +/*- + * To create an archive: + * 1) Ask archive_write_new for an archive writer object. + * 2) Set any global properties. In particular, you should set + * the compression and format to use. + * 3) Call archive_write_open to open the file (most people + * will use archive_write_open_file or archive_write_open_fd, + * which provide convenient canned I/O callbacks for you). + * 4) For each entry: + * - construct an appropriate struct archive_entry structure + * - archive_write_header to write the header + * - archive_write_data to write the entry data + * 5) archive_write_close to close the output + * 6) archive_write_free to cleanup the writer and release resources + */ +__LA_DECL struct archive *archive_write_new(void); +__LA_DECL int archive_write_set_bytes_per_block(struct archive *, + int bytes_per_block); +__LA_DECL int archive_write_get_bytes_per_block(struct archive *); +/* XXX This is badly misnamed; suggestions appreciated. XXX */ +__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *, + int bytes_in_last_block); +__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *); + +/* The dev/ino of a file that won't be archived. This is used + * to avoid recursively adding an archive to itself. */ +__LA_DECL int archive_write_set_skip_file(struct archive *, + la_int64_t, la_int64_t); + +#if ARCHIVE_VERSION_NUMBER < 4000000 +__LA_DECL int archive_write_set_compression_bzip2(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_compress(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_gzip(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_lzip(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_lzma(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_none(struct archive *) + __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_program(struct archive *, + const char *cmd) __LA_DEPRECATED; +__LA_DECL int archive_write_set_compression_xz(struct archive *) + __LA_DEPRECATED; +#endif + +/* A convenience function to set the filter based on the code. */ +__LA_DECL int archive_write_add_filter(struct archive *, int filter_code); +__LA_DECL int archive_write_add_filter_by_name(struct archive *, + const char *name); +__LA_DECL int archive_write_add_filter_b64encode(struct archive *); +__LA_DECL int archive_write_add_filter_bzip2(struct archive *); +__LA_DECL int archive_write_add_filter_compress(struct archive *); +__LA_DECL int archive_write_add_filter_grzip(struct archive *); +__LA_DECL int archive_write_add_filter_gzip(struct archive *); +__LA_DECL int archive_write_add_filter_lrzip(struct archive *); +__LA_DECL int archive_write_add_filter_lz4(struct archive *); +__LA_DECL int archive_write_add_filter_lzip(struct archive *); +__LA_DECL int archive_write_add_filter_lzma(struct archive *); +__LA_DECL int archive_write_add_filter_lzop(struct archive *); +__LA_DECL int archive_write_add_filter_none(struct archive *); +__LA_DECL int archive_write_add_filter_program(struct archive *, + const char *cmd); +__LA_DECL int archive_write_add_filter_uuencode(struct archive *); +__LA_DECL int archive_write_add_filter_xz(struct archive *); + + +/* A convenience function to set the format based on the code or name. */ +__LA_DECL int archive_write_set_format(struct archive *, int format_code); +__LA_DECL int archive_write_set_format_by_name(struct archive *, + const char *name); +/* To minimize link pollution, use one or more of the following. */ +__LA_DECL int archive_write_set_format_7zip(struct archive *); +__LA_DECL int archive_write_set_format_ar_bsd(struct archive *); +__LA_DECL int archive_write_set_format_ar_svr4(struct archive *); +__LA_DECL int archive_write_set_format_cpio(struct archive *); +__LA_DECL int archive_write_set_format_cpio_newc(struct archive *); +__LA_DECL int archive_write_set_format_gnutar(struct archive *); +__LA_DECL int archive_write_set_format_iso9660(struct archive *); +__LA_DECL int archive_write_set_format_mtree(struct archive *); +__LA_DECL int archive_write_set_format_mtree_classic(struct archive *); +/* TODO: int archive_write_set_format_old_tar(struct archive *); */ +__LA_DECL int archive_write_set_format_pax(struct archive *); +__LA_DECL int archive_write_set_format_pax_restricted(struct archive *); +__LA_DECL int archive_write_set_format_raw(struct archive *); +__LA_DECL int archive_write_set_format_shar(struct archive *); +__LA_DECL int archive_write_set_format_shar_dump(struct archive *); +__LA_DECL int archive_write_set_format_ustar(struct archive *); +__LA_DECL int archive_write_set_format_v7tar(struct archive *); +__LA_DECL int archive_write_set_format_warc(struct archive *); +__LA_DECL int archive_write_set_format_xar(struct archive *); +__LA_DECL int archive_write_set_format_zip(struct archive *); +__LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const char *filename); +__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext); +__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *); +__LA_DECL int archive_write_zip_set_compression_store(struct archive *); +__LA_DECL int archive_write_open(struct archive *, void *, + archive_open_callback *, archive_write_callback *, + archive_close_callback *); +__LA_DECL int archive_write_open_fd(struct archive *, int _fd); +__LA_DECL int archive_write_open_filename(struct archive *, const char *_file); +__LA_DECL int archive_write_open_filename_w(struct archive *, + const wchar_t *_file); +/* A deprecated synonym for archive_write_open_filename() */ +__LA_DECL int archive_write_open_file(struct archive *, const char *_file) + __LA_DEPRECATED; +__LA_DECL int archive_write_open_FILE(struct archive *, FILE *); +/* _buffSize is the size of the buffer, _used refers to a variable that + * will be updated after each write into the buffer. */ +__LA_DECL int archive_write_open_memory(struct archive *, + void *_buffer, size_t _buffSize, size_t *_used); + +/* + * Note that the library will truncate writes beyond the size provided + * to archive_write_header or pad if the provided data is short. + */ +__LA_DECL int archive_write_header(struct archive *, + struct archive_entry *); +__LA_DECL la_ssize_t archive_write_data(struct archive *, + const void *, size_t); + +/* This interface is currently only available for archive_write_disk handles. */ +__LA_DECL la_ssize_t archive_write_data_block(struct archive *, + const void *, size_t, la_int64_t); + +__LA_DECL int archive_write_finish_entry(struct archive *); +__LA_DECL int archive_write_close(struct archive *); +/* Marks the archive as FATAL so that a subsequent free() operation + * won't try to close() cleanly. Provides a fast abort capability + * when the client discovers that things have gone wrong. */ +__LA_DECL int archive_write_fail(struct archive *); +/* This can fail if the archive wasn't already closed, in which case + * archive_write_free() will implicitly call archive_write_close(). */ +__LA_DECL int archive_write_free(struct archive *); +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Synonym for archive_write_free() for backwards compatibility. */ +__LA_DECL int archive_write_finish(struct archive *) __LA_DEPRECATED; +#endif + +/* + * Set write options. + */ +/* Apply option to the format only. */ +__LA_DECL int archive_write_set_format_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option to the filter only. */ +__LA_DECL int archive_write_set_filter_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option to both the format and the filter. */ +__LA_DECL int archive_write_set_option(struct archive *_a, + const char *m, const char *o, + const char *v); +/* Apply option string to both the format and the filter. */ +__LA_DECL int archive_write_set_options(struct archive *_a, + const char *opts); + +/* + * Set a encryption passphrase. + */ +__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p); +__LA_DECL int archive_write_set_passphrase_callback(struct archive *, + void *client_data, archive_passphrase_callback *); + +/*- + * ARCHIVE_WRITE_DISK API + * + * To create objects on disk: + * 1) Ask archive_write_disk_new for a new archive_write_disk object. + * 2) Set any global properties. In particular, you probably + * want to set the options. + * 3) For each entry: + * - construct an appropriate struct archive_entry structure + * - archive_write_header to create the file/dir/etc on disk + * - archive_write_data to write the entry data + * 4) archive_write_free to cleanup the writer and release resources + * + * In particular, you can use this in conjunction with archive_read() + * to pull entries out of an archive and create them on disk. + */ +__LA_DECL struct archive *archive_write_disk_new(void); +/* This file will not be overwritten. */ +__LA_DECL int archive_write_disk_set_skip_file(struct archive *, + la_int64_t, la_int64_t); +/* Set flags to control how the next item gets created. + * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */ +__LA_DECL int archive_write_disk_set_options(struct archive *, + int flags); +/* + * The lookup functions are given uname/uid (or gname/gid) pairs and + * return a uid (gid) suitable for this system. These are used for + * restoring ownership and for setting ACLs. The default functions + * are naive, they just return the uid/gid. These are small, so reasonable + * for applications that don't need to preserve ownership; they + * are probably also appropriate for applications that are doing + * same-system backup and restore. + */ +/* + * The "standard" lookup functions use common system calls to lookup + * the uname/gname, falling back to the uid/gid if the names can't be + * found. They cache lookups and are reasonably fast, but can be very + * large, so they are not used unless you ask for them. In + * particular, these match the specifications of POSIX "pax" and old + * POSIX "tar". + */ +__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *); +/* + * If neither the default (naive) nor the standard (big) functions suit + * your needs, you can write your own and register them. Be sure to + * include a cleanup function if you have allocated private data. + */ +__LA_DECL int archive_write_disk_set_group_lookup(struct archive *, + void * /* private_data */, + la_int64_t (*)(void *, const char *, la_int64_t), + void (* /* cleanup */)(void *)); +__LA_DECL int archive_write_disk_set_user_lookup(struct archive *, + void * /* private_data */, + la_int64_t (*)(void *, const char *, la_int64_t), + void (* /* cleanup */)(void *)); +__LA_DECL la_int64_t archive_write_disk_gid(struct archive *, const char *, la_int64_t); +__LA_DECL la_int64_t archive_write_disk_uid(struct archive *, const char *, la_int64_t); + +/* + * ARCHIVE_READ_DISK API + * + * This is still evolving and somewhat experimental. + */ +__LA_DECL struct archive *archive_read_disk_new(void); +/* The names for symlink modes here correspond to an old BSD + * command-line argument convention: -L, -P, -H */ +/* Follow all symlinks. */ +__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *); +/* Follow no symlinks. */ +__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *); +/* Follow symlink initially, then not. */ +__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *); +/* TODO: Handle Linux stat32/stat64 ugliness. */ +__LA_DECL int archive_read_disk_entry_from_file(struct archive *, + struct archive_entry *, int /* fd */, const struct stat *); +/* Look up gname for gid or uname for uid. */ +/* Default implementations are very, very stupid. */ +__LA_DECL const char *archive_read_disk_gname(struct archive *, la_int64_t); +__LA_DECL const char *archive_read_disk_uname(struct archive *, la_int64_t); +/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the + * results for performance. */ +__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *); +/* You can install your own lookups if you like. */ +__LA_DECL int archive_read_disk_set_gname_lookup(struct archive *, + void * /* private_data */, + const char *(* /* lookup_fn */)(void *, la_int64_t), + void (* /* cleanup_fn */)(void *)); +__LA_DECL int archive_read_disk_set_uname_lookup(struct archive *, + void * /* private_data */, + const char *(* /* lookup_fn */)(void *, la_int64_t), + void (* /* cleanup_fn */)(void *)); +/* Start traversal. */ +__LA_DECL int archive_read_disk_open(struct archive *, const char *); +__LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *); +/* + * Request that current entry be visited. If you invoke it on every + * directory, you'll get a physical traversal. This is ignored if the + * current entry isn't a directory or a link to a directory. So, if + * you invoke this on every returned path, you'll get a full logical + * traversal. + */ +__LA_DECL int archive_read_disk_descend(struct archive *); +__LA_DECL int archive_read_disk_can_descend(struct archive *); +__LA_DECL int archive_read_disk_current_filesystem(struct archive *); +__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *); +__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *); +/* Request that the access time of the entry visited by traversal be restored. */ +__LA_DECL int archive_read_disk_set_atime_restored(struct archive *); +/* + * Set behavior. The "flags" argument selects optional behavior. + */ +/* Request that the access time of the entry visited by traversal be restored. + * This is the same as archive_read_disk_set_atime_restored. */ +#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001) +/* Default: Do not skip an entry which has nodump flags. */ +#define ARCHIVE_READDISK_HONOR_NODUMP (0x0002) +/* Default: Skip a mac resource fork file whose prefix is "._" because of + * using copyfile. */ +#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004) +/* Default: Traverse mount points. */ +#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008) +/* Default: Xattrs are read from disk. */ +#define ARCHIVE_READDISK_NO_XATTR (0x0010) +/* Default: ACLs are read from disk. */ +#define ARCHIVE_READDISK_NO_ACL (0x0020) +/* Default: File flags are read from disk. */ +#define ARCHIVE_READDISK_NO_FFLAGS (0x0040) + +__LA_DECL int archive_read_disk_set_behavior(struct archive *, + int flags); + +/* + * Set archive_match object that will be used in archive_read_disk to + * know whether an entry should be skipped. The callback function + * _excluded_func will be invoked when an entry is skipped by the result + * of archive_match. + */ +__LA_DECL int archive_read_disk_set_matching(struct archive *, + struct archive *_matching, void (*_excluded_func) + (struct archive *, void *, struct archive_entry *), + void *_client_data); +__LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *, + int (*_metadata_filter_func)(struct archive *, void *, + struct archive_entry *), void *_client_data); + +/* Simplified cleanup interface; + * This calls archive_read_free() or archive_write_free() as needed. */ +__LA_DECL int archive_free(struct archive *); + +/* + * Accessor functions to read/set various information in + * the struct archive object: + */ + +/* Number of filters in the current filter pipeline. */ +/* Filter #0 is the one closest to the format, -1 is a synonym for the + * last filter, which is always the pseudo-filter that wraps the + * client callbacks. */ +__LA_DECL int archive_filter_count(struct archive *); +__LA_DECL la_int64_t archive_filter_bytes(struct archive *, int); +__LA_DECL int archive_filter_code(struct archive *, int); +__LA_DECL const char * archive_filter_name(struct archive *, int); + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* These don't properly handle multiple filters, so are deprecated and + * will eventually be removed. */ +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */ +__LA_DECL la_int64_t archive_position_compressed(struct archive *) + __LA_DEPRECATED; +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */ +__LA_DECL la_int64_t archive_position_uncompressed(struct archive *) + __LA_DEPRECATED; +/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */ +__LA_DECL const char *archive_compression_name(struct archive *) + __LA_DEPRECATED; +/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */ +__LA_DECL int archive_compression(struct archive *) + __LA_DEPRECATED; +#endif + +__LA_DECL int archive_errno(struct archive *); +__LA_DECL const char *archive_error_string(struct archive *); +__LA_DECL const char *archive_format_name(struct archive *); +__LA_DECL int archive_format(struct archive *); +__LA_DECL void archive_clear_error(struct archive *); +__LA_DECL void archive_set_error(struct archive *, int _err, + const char *fmt, ...) __LA_PRINTF(3, 4); +__LA_DECL void archive_copy_error(struct archive *dest, + struct archive *src); +__LA_DECL int archive_file_count(struct archive *); + +/* + * ARCHIVE_MATCH API + */ +__LA_DECL struct archive *archive_match_new(void); +__LA_DECL int archive_match_free(struct archive *); + +/* + * Test if archive_entry is excluded. + * This is a convenience function. This is the same as calling all + * archive_match_path_excluded, archive_match_time_excluded + * and archive_match_owner_excluded. + */ +__LA_DECL int archive_match_excluded(struct archive *, + struct archive_entry *); + +/* + * Test if pathname is excluded. The conditions are set by following functions. + */ +__LA_DECL int archive_match_path_excluded(struct archive *, + struct archive_entry *); +/* Add exclusion pathname pattern. */ +__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *); +__LA_DECL int archive_match_exclude_pattern_w(struct archive *, + const wchar_t *); +/* Add exclusion pathname pattern from file. */ +__LA_DECL int archive_match_exclude_pattern_from_file(struct archive *, + const char *, int _nullSeparator); +__LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *, + const wchar_t *, int _nullSeparator); +/* Add inclusion pathname pattern. */ +__LA_DECL int archive_match_include_pattern(struct archive *, const char *); +__LA_DECL int archive_match_include_pattern_w(struct archive *, + const wchar_t *); +/* Add inclusion pathname pattern from file. */ +__LA_DECL int archive_match_include_pattern_from_file(struct archive *, + const char *, int _nullSeparator); +__LA_DECL int archive_match_include_pattern_from_file_w(struct archive *, + const wchar_t *, int _nullSeparator); +/* + * How to get statistic information for inclusion patterns. + */ +/* Return the amount number of unmatched inclusion patterns. */ +__LA_DECL int archive_match_path_unmatched_inclusions(struct archive *); +/* Return the pattern of unmatched inclusion with ARCHIVE_OK. + * Return ARCHIVE_EOF if there is no inclusion pattern. */ +__LA_DECL int archive_match_path_unmatched_inclusions_next( + struct archive *, const char **); +__LA_DECL int archive_match_path_unmatched_inclusions_next_w( + struct archive *, const wchar_t **); + +/* + * Test if a file is excluded by its time stamp. + * The conditions are set by following functions. + */ +__LA_DECL int archive_match_time_excluded(struct archive *, + struct archive_entry *); + +/* + * Flags to tell a matching type of time stamps. These are used for + * following functions. + */ +/* Time flag: mtime to be tested. */ +#define ARCHIVE_MATCH_MTIME (0x0100) +/* Time flag: ctime to be tested. */ +#define ARCHIVE_MATCH_CTIME (0x0200) +/* Comparison flag: Match the time if it is newer than. */ +#define ARCHIVE_MATCH_NEWER (0x0001) +/* Comparison flag: Match the time if it is older than. */ +#define ARCHIVE_MATCH_OLDER (0x0002) +/* Comparison flag: Match the time if it is equal to. */ +#define ARCHIVE_MATCH_EQUAL (0x0010) +/* Set inclusion time. */ +__LA_DECL int archive_match_include_time(struct archive *, int _flag, + time_t _sec, long _nsec); +/* Set inclusion time by a date string. */ +__LA_DECL int archive_match_include_date(struct archive *, int _flag, + const char *_datestr); +__LA_DECL int archive_match_include_date_w(struct archive *, int _flag, + const wchar_t *_datestr); +/* Set inclusion time by a particular file. */ +__LA_DECL int archive_match_include_file_time(struct archive *, + int _flag, const char *_pathname); +__LA_DECL int archive_match_include_file_time_w(struct archive *, + int _flag, const wchar_t *_pathname); +/* Add exclusion entry. */ +__LA_DECL int archive_match_exclude_entry(struct archive *, + int _flag, struct archive_entry *); + +/* + * Test if a file is excluded by its uid ,gid, uname or gname. + * The conditions are set by following functions. + */ +__LA_DECL int archive_match_owner_excluded(struct archive *, + struct archive_entry *); +/* Add inclusion uid, gid, uname and gname. */ +__LA_DECL int archive_match_include_uid(struct archive *, la_int64_t); +__LA_DECL int archive_match_include_gid(struct archive *, la_int64_t); +__LA_DECL int archive_match_include_uname(struct archive *, const char *); +__LA_DECL int archive_match_include_uname_w(struct archive *, + const wchar_t *); +__LA_DECL int archive_match_include_gname(struct archive *, const char *); +__LA_DECL int archive_match_include_gname_w(struct archive *, + const wchar_t *); + +/* Utility functions */ +/* Convenience function to sort a NULL terminated list of strings */ +__LA_DECL int archive_utility_string_sort(char **); + +#ifdef __cplusplus +} +#endif + +/* These are meaningless outside of this header. */ +#undef __LA_DECL + +#endif /* !ARCHIVE_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_acl.c b/src/3rdparty/libarchive/libarchive/archive_acl.c new file mode 100644 index 00000000..b8b6b636 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_acl.c @@ -0,0 +1,2069 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#include "archive_acl_private.h" +#include "archive_entry.h" +#include "archive_private.h" + +#undef max +#define max(a, b) ((a)>(b)?(a):(b)) + +#ifndef HAVE_WMEMCMP +/* Good enough for simple equality testing, but not for sorting. */ +#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) +#endif + +static int acl_special(struct archive_acl *acl, + int type, int permset, int tag); +static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, + int type, int permset, int tag, int id); +static int archive_acl_add_entry_len_l(struct archive_acl *acl, + int type, int permset, int tag, int id, const char *name, + size_t len, struct archive_string_conv *sc); +static int archive_acl_text_want_type(struct archive_acl *acl, int flags); +static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type, + int flags, int wide, struct archive *a, + struct archive_string_conv *sc); +static int isint_w(const wchar_t *start, const wchar_t *end, int *result); +static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); +static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, + int *result); +static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, + int *result); +static void next_field_w(const wchar_t **wp, const wchar_t **start, + const wchar_t **end, wchar_t *sep); +static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, + int tag, int flags, const wchar_t *wname, int perm, int id); +static void append_id_w(wchar_t **wp, int id); +static int isint(const char *start, const char *end, int *result); +static int ismode(const char *start, const char *end, int *result); +static int is_nfs4_flags(const char *start, const char *end, + int *result); +static int is_nfs4_perms(const char *start, const char *end, + int *result); +static void next_field(const char **p, const char **start, + const char **end, char *sep); +static void append_entry(char **p, const char *prefix, int type, + int tag, int flags, const char *name, int perm, int id); +static void append_id(char **p, int id); + +static const struct { + const int perm; + const char c; + const wchar_t wc; +} nfsv4_acl_perm_map[] = { + { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', + L'r' }, + { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', + L'w' }, + { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, + { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, + 'p', L'p' }, + { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, + { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, + { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, + { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, + { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, + { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, + { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, + { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, + { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, + { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } +}; + +static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / + sizeof(nfsv4_acl_perm_map[0])); + +static const struct { + const int perm; + const char c; + const wchar_t wc; +} nfsv4_acl_flag_map[] = { + { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, + { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, + { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, + { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, + { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, + { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, + { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } +}; + +static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / + sizeof(nfsv4_acl_flag_map[0])); + +void +archive_acl_clear(struct archive_acl *acl) +{ + struct archive_acl_entry *ap; + + while (acl->acl_head != NULL) { + ap = acl->acl_head->next; + archive_mstring_clean(&acl->acl_head->name); + free(acl->acl_head); + acl->acl_head = ap; + } + if (acl->acl_text_w != NULL) { + free(acl->acl_text_w); + acl->acl_text_w = NULL; + } + if (acl->acl_text != NULL) { + free(acl->acl_text); + acl->acl_text = NULL; + } + acl->acl_p = NULL; + acl->acl_types = 0; + acl->acl_state = 0; /* Not counting. */ +} + +void +archive_acl_copy(struct archive_acl *dest, struct archive_acl *src) +{ + struct archive_acl_entry *ap, *ap2; + + archive_acl_clear(dest); + + dest->mode = src->mode; + ap = src->acl_head; + while (ap != NULL) { + ap2 = acl_new_entry(dest, + ap->type, ap->permset, ap->tag, ap->id); + if (ap2 != NULL) + archive_mstring_copy(&ap2->name, &ap->name); + ap = ap->next; + } +} + +int +archive_acl_add_entry(struct archive_acl *acl, + int type, int permset, int tag, int id, const char *name) +{ + struct archive_acl_entry *ap; + + if (acl_special(acl, type, permset, tag) == 0) + return ARCHIVE_OK; + ap = acl_new_entry(acl, type, permset, tag, id); + if (ap == NULL) { + /* XXX Error XXX */ + return ARCHIVE_FAILED; + } + if (name != NULL && *name != '\0') + archive_mstring_copy_mbs(&ap->name, name); + else + archive_mstring_clean(&ap->name); + return ARCHIVE_OK; +} + +int +archive_acl_add_entry_w_len(struct archive_acl *acl, + int type, int permset, int tag, int id, const wchar_t *name, size_t len) +{ + struct archive_acl_entry *ap; + + if (acl_special(acl, type, permset, tag) == 0) + return ARCHIVE_OK; + ap = acl_new_entry(acl, type, permset, tag, id); + if (ap == NULL) { + /* XXX Error XXX */ + return ARCHIVE_FAILED; + } + if (name != NULL && *name != L'\0' && len > 0) + archive_mstring_copy_wcs_len(&ap->name, name, len); + else + archive_mstring_clean(&ap->name); + return ARCHIVE_OK; +} + +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) +{ + struct archive_acl_entry *ap; + int r; + + if (acl_special(acl, type, permset, tag) == 0) + return ARCHIVE_OK; + ap = acl_new_entry(acl, type, permset, tag, id); + if (ap == NULL) { + /* XXX Error XXX */ + return ARCHIVE_FAILED; + } + if (name != NULL && *name != '\0' && len > 0) { + r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc); + } else { + r = 0; + archive_mstring_clean(&ap->name); + } + if (r == 0) + return (ARCHIVE_OK); + else if (errno == ENOMEM) + return (ARCHIVE_FATAL); + else + return (ARCHIVE_WARN); +} + +/* + * If this ACL entry is part of the standard POSIX permissions set, + * store the permissions in the stat structure and return zero. + */ +static int +acl_special(struct archive_acl *acl, int type, int permset, int tag) +{ + if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS + && ((permset & ~007) == 0)) { + switch (tag) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + acl->mode &= ~0700; + acl->mode |= (permset & 7) << 6; + return (0); + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + acl->mode &= ~0070; + acl->mode |= (permset & 7) << 3; + return (0); + case ARCHIVE_ENTRY_ACL_OTHER: + acl->mode &= ~0007; + acl->mode |= permset & 7; + return (0); + } + } + return (1); +} + +/* + * Allocate and populate a new ACL entry with everything but the + * name. + */ +static struct archive_acl_entry * +acl_new_entry(struct archive_acl *acl, + int type, int permset, int tag, int id) +{ + struct archive_acl_entry *ap, *aq; + + /* Type argument must be a valid NFS4 or POSIX.1e type. + * The type must agree with anything already set and + * the permset must be compatible. */ + if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + return (NULL); + } + if (permset & + ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4 + | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) { + return (NULL); + } + } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { + if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { + return (NULL); + } + if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) { + return (NULL); + } + } else { + return (NULL); + } + + /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */ + switch (tag) { + case ARCHIVE_ENTRY_ACL_USER: + case ARCHIVE_ENTRY_ACL_USER_OBJ: + case ARCHIVE_ENTRY_ACL_GROUP: + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + /* Tags valid in both NFS4 and POSIX.1e */ + break; + case ARCHIVE_ENTRY_ACL_MASK: + case ARCHIVE_ENTRY_ACL_OTHER: + /* Tags valid only in POSIX.1e. */ + if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) { + return (NULL); + } + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + /* Tags valid only in NFS4. */ + if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + return (NULL); + } + break; + default: + /* No other values are valid. */ + return (NULL); + } + + if (acl->acl_text_w != NULL) { + free(acl->acl_text_w); + acl->acl_text_w = NULL; + } + if (acl->acl_text != NULL) { + free(acl->acl_text); + acl->acl_text = NULL; + } + + /* + * If there's a matching entry already in the list, overwrite it. + * NFSv4 entries may be repeated and are not overwritten. + * + * TODO: compare names of no id is provided (needs more rework) + */ + ap = acl->acl_head; + aq = NULL; + while (ap != NULL) { + if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && + ap->type == type && ap->tag == tag && ap->id == id) { + if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && + tag != ARCHIVE_ENTRY_ACL_GROUP)) { + ap->permset = permset; + return (ap); + } + } + aq = ap; + ap = ap->next; + } + + /* Add a new entry to the end of the list. */ + ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); + if (ap == NULL) + return (NULL); + if (aq == NULL) + acl->acl_head = ap; + else + aq->next = ap; + ap->type = type; + ap->tag = tag; + ap->id = id; + ap->permset = permset; + acl->acl_types |= type; + return (ap); +} + +/* + * Return a count of entries matching "want_type". + */ +int +archive_acl_count(struct archive_acl *acl, int want_type) +{ + int count; + struct archive_acl_entry *ap; + + count = 0; + ap = acl->acl_head; + while (ap != NULL) { + if ((ap->type & want_type) != 0) + count++; + ap = ap->next; + } + + if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) + count += 3; + return (count); +} + +/* + * Return a bitmask of stored ACL types in an ACL list + */ +int +archive_acl_types(struct archive_acl *acl) +{ + return (acl->acl_types); +} + +/* + * Prepare for reading entries from the ACL data. Returns a count + * of entries matching "want_type", or zero if there are no + * non-extended ACL entries of that type. + */ +int +archive_acl_reset(struct archive_acl *acl, int want_type) +{ + int count, cutoff; + + count = archive_acl_count(acl, want_type); + + /* + * If the only entries are the three standard ones, + * then don't return any ACL data. (In this case, + * client can just use chmod(2) to set permissions.) + */ + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) + cutoff = 3; + else + cutoff = 0; + + if (count > cutoff) + acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; + else + acl->acl_state = 0; + acl->acl_p = acl->acl_head; + return (count); +} + + +/* + * Return the next ACL entry in the list. Fake entries for the + * standard permissions and include them in the returned list. + */ +int +archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, + int *type, int *permset, int *tag, int *id, const char **name) +{ + *name = NULL; + *id = -1; + + /* + * The acl_state is either zero (no entries available), -1 + * (reading from list), or an entry type (retrieve that type + * from ae_stat.aest_mode). + */ + if (acl->acl_state == 0) + return (ARCHIVE_WARN); + + /* The first three access entries are special. */ + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + switch (acl->acl_state) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + *permset = (acl->mode >> 6) & 7; + *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + *tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + return (ARCHIVE_OK); + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + *permset = (acl->mode >> 3) & 7; + *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER; + return (ARCHIVE_OK); + case ARCHIVE_ENTRY_ACL_OTHER: + *permset = acl->mode & 7; + *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + *tag = ARCHIVE_ENTRY_ACL_OTHER; + acl->acl_state = -1; + acl->acl_p = acl->acl_head; + return (ARCHIVE_OK); + default: + break; + } + } + + while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0) + acl->acl_p = acl->acl_p->next; + if (acl->acl_p == NULL) { + acl->acl_state = 0; + *type = 0; + *permset = 0; + *tag = 0; + *id = -1; + *name = NULL; + return (ARCHIVE_EOF); /* End of ACL entries. */ + } + *type = acl->acl_p->type; + *permset = acl->acl_p->permset; + *tag = acl->acl_p->tag; + *id = acl->acl_p->id; + if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) { + if (errno == ENOMEM) + return (ARCHIVE_FATAL); + *name = NULL; + } + acl->acl_p = acl->acl_p->next; + return (ARCHIVE_OK); +} + +/* + * Determine what type of ACL do we want + */ +static int +archive_acl_text_want_type(struct archive_acl *acl, int flags) +{ + int want_type; + + /* Check if ACL is NFSv4 */ + if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + /* NFSv4 should never mix with POSIX.1e */ + if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) + return (0); + else + return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); + } + + /* Now deal with POSIX.1e ACLs */ + + want_type = 0; + if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) + want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + + /* By default we want both access and default ACLs */ + if (want_type == 0) + return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); + + return (want_type); +} + +/* + * Calculate ACL text string length + */ +static ssize_t +archive_acl_text_len(struct archive_acl *acl, int want_type, int flags, + int wide, struct archive *a, struct archive_string_conv *sc) { + struct archive_acl_entry *ap; + const char *name; + const wchar_t *wname; + int count, idlen, tmp, r; + ssize_t length; + size_t len; + + count = 0; + length = 0; + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + count++; + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 + && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + length += 8; /* "default:" */ + switch (ap->tag) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + length += 6; /* "owner@" */ + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_USER: + case ARCHIVE_ENTRY_ACL_MASK: + length += 4; /* "user", "mask" */ + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + length += 6; /* "group@" */ + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_GROUP: + case ARCHIVE_ENTRY_ACL_OTHER: + length += 5; /* "group", "other" */ + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + length += 9; /* "everyone@" */ + break; + } + length += 1; /* colon after tag */ + if (ap->tag == ARCHIVE_ENTRY_ACL_USER || + ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { + if (wide) { + r = archive_mstring_get_wcs(a, &ap->name, + &wname); + if (r == 0 && wname != NULL) + length += wcslen(wname); + else if (r < 0 && errno == ENOMEM) + return (0); + else + length += sizeof(uid_t) * 3 + 1; + } else { + r = archive_mstring_get_mbs_l(&ap->name, &name, + &len, sc); + if (r != 0) + return (0); + if (len > 0 && name != NULL) + length += len; + else + length += sizeof(uid_t) * 3 + 1; + } + length += 1; /* colon after user or group name */ + } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) + length += 1; /* 2nd colon empty user,group or other */ + + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) + && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) + && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER + || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { + /* Solaris has no colon after other: and mask: */ + length = length - 1; + } + + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* rwxpdDaARWcCos:fdinSFI:deny */ + length += 27; + if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) + length += 1; /* allow, alarm, audit */ + } else + length += 3; /* rwx */ + + if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || + ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && + (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { + length += 1; /* colon */ + /* 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); +} + +/* + * Generate a wide text version of the ACL. The flags parameter controls + * the type and style of the generated ACL. + */ +wchar_t * +archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, + struct archive *a) +{ + int count; + ssize_t length; + size_t len; + const wchar_t *wname; + const wchar_t *prefix; + wchar_t separator; + struct archive_acl_entry *ap; + int id, r, want_type; + wchar_t *wp, *ws; + + want_type = archive_acl_text_want_type(acl, flags); + + /* Both NFSv4 and POSIX.1 types found */ + if (want_type == 0) + return (NULL); + + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) + flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; + + length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); + + if (length == 0) + return (NULL); + + if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) + separator = L','; + else + separator = L'\n'; + + /* Now, allocate the string and actually populate it. */ + wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); + if (wp == NULL) { + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); + } + count = 0; + + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, + acl->mode & 0700, -1); + *wp++ = separator; + append_entry_w(&wp, 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_ENTRY_ACL_OTHER, flags, NULL, + acl->mode & 0007, -1); + count += 3; + } + + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && + (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) + prefix = L"default:"; + else + prefix = NULL; + r = archive_mstring_get_wcs(a, &ap->name, &wname); + if (r == 0) { + if (count > 0) + *wp++ = separator; + if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) + id = ap->id; + else + id = -1; + append_entry_w(&wp, prefix, ap->type, ap->tag, flags, + wname, ap->permset, id); + count++; + } else if (r < 0 && errno == ENOMEM) + return (NULL); + } + + /* Add terminating character */ + *wp++ = L'\0'; + + len = wcslen(ws); + + if ((ssize_t)len > (length - 1)) + __archive_errx(1, "Buffer overrun"); + + if (text_len != NULL) + *text_len = len; + + return (ws); +} + +static void +append_id_w(wchar_t **wp, int id) +{ + if (id < 0) + id = 0; + if (id > 9) + append_id_w(wp, id / 10); + *(*wp)++ = L"0123456789"[id % 10]; +} + +static void +append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, + int tag, int flags, const wchar_t *wname, int perm, int id) +{ + int i; + + if (prefix != NULL) { + wcscpy(*wp, prefix); + *wp += wcslen(*wp); + } + switch (tag) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + wname = NULL; + id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + wcscpy(*wp, L"owner@"); + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_USER: + wcscpy(*wp, L"user"); + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + wname = NULL; + id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + wcscpy(*wp, L"group@"); + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_GROUP: + wcscpy(*wp, L"group"); + break; + case ARCHIVE_ENTRY_ACL_MASK: + wcscpy(*wp, L"mask"); + wname = NULL; + id = -1; + break; + case ARCHIVE_ENTRY_ACL_OTHER: + wcscpy(*wp, L"other"); + wname = NULL; + id = -1; + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + wcscpy(*wp, L"everyone@"); + wname = NULL; + id = -1; + break; + } + *wp += wcslen(*wp); + *(*wp)++ = 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); + } else if (tag == ARCHIVE_ENTRY_ACL_USER + || tag == ARCHIVE_ENTRY_ACL_GROUP) { + append_id_w(wp, id); + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) + id = -1; + } + /* Solaris style has no second colon after other and mask */ + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) + || (tag != ARCHIVE_ENTRY_ACL_OTHER + && tag != ARCHIVE_ENTRY_ACL_MASK)) + *(*wp)++ = L':'; + } + if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + /* POSIX.1e ACL perms */ + *(*wp)++ = (perm & 0444) ? L'r' : L'-'; + *(*wp)++ = (perm & 0222) ? L'w' : L'-'; + *(*wp)++ = (perm & 0111) ? L'x' : L'-'; + } else { + /* NFSv4 ACL perms */ + for (i = 0; i < nfsv4_acl_perm_map_size; i++) { + if (perm & nfsv4_acl_perm_map[i].perm) + *(*wp)++ = nfsv4_acl_perm_map[i].wc; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*wp)++ = L'-'; + } + *(*wp)++ = L':'; + for (i = 0; i < nfsv4_acl_flag_map_size; i++) { + if (perm & nfsv4_acl_flag_map[i].perm) + *(*wp)++ = nfsv4_acl_flag_map[i].wc; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*wp)++ = L'-'; + } + *(*wp)++ = L':'; + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + wcscpy(*wp, L"allow"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + wcscpy(*wp, L"deny"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + wcscpy(*wp, L"audit"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + wcscpy(*wp, L"alarm"); + break; + default: + break; + } + *wp += wcslen(*wp); + } + if (id != -1) { + *(*wp)++ = L':'; + append_id_w(wp, id); + } +} + +/* + * Generate a text version of the ACL. The flags parameter controls + * the type and style of the generated ACL. + */ +char * +archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, + struct archive_string_conv *sc) +{ + int count; + ssize_t length; + size_t len; + const char *name; + const char *prefix; + char separator; + struct archive_acl_entry *ap; + int id, r, want_type; + char *p, *s; + + want_type = archive_acl_text_want_type(acl, flags); + + /* Both NFSv4 and POSIX.1 types found */ + if (want_type == 0) + return (NULL); + + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) + flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; + + length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); + + if (length == 0) + return (NULL); + + if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) + separator = ','; + else + separator = '\n'; + + /* Now, allocate the string and actually populate it. */ + p = s = (char *)malloc(length * sizeof(char)); + if (p == NULL) { + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); + } + count = 0; + + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, + acl->mode & 0700, -1); + *p++ = separator; + append_entry(&p, 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_ENTRY_ACL_OTHER, flags, NULL, + acl->mode & 0007, -1); + count += 3; + } + + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && + (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) + prefix = "default:"; + else + prefix = NULL; + r = archive_mstring_get_mbs_l( + &ap->name, &name, &len, sc); + if (r != 0) + return (NULL); + if (count > 0) + *p++ = separator; + if (name == NULL || + (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { + id = ap->id; + } else { + id = -1; + } + append_entry(&p, prefix, ap->type, ap->tag, flags, name, + ap->permset, id); + count++; + } + + /* Add terminating character */ + *p++ = '\0'; + + len = strlen(s); + + if ((ssize_t)len > (length - 1)) + __archive_errx(1, "Buffer overrun"); + + if (text_len != NULL) + *text_len = len; + + return (s); +} + +static void +append_id(char **p, int id) +{ + if (id < 0) + id = 0; + if (id > 9) + append_id(p, id / 10); + *(*p)++ = "0123456789"[id % 10]; +} + +static void +append_entry(char **p, const char *prefix, int type, + int tag, int flags, const char *name, int perm, int id) +{ + int i; + + if (prefix != NULL) { + strcpy(*p, prefix); + *p += strlen(*p); + } + switch (tag) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + name = NULL; + id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + strcpy(*p, "owner@"); + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_USER: + strcpy(*p, "user"); + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + name = NULL; + id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + strcpy(*p, "group@"); + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_GROUP: + strcpy(*p, "group"); + break; + case ARCHIVE_ENTRY_ACL_MASK: + strcpy(*p, "mask"); + name = NULL; + id = -1; + break; + case ARCHIVE_ENTRY_ACL_OTHER: + strcpy(*p, "other"); + name = NULL; + id = -1; + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + strcpy(*p, "everyone@"); + name = NULL; + id = -1; + break; + } + *p += strlen(*p); + *(*p)++ = ':'; + if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || + tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + if (name != NULL) { + strcpy(*p, name); + *p += strlen(*p); + } else if (tag == ARCHIVE_ENTRY_ACL_USER + || tag == ARCHIVE_ENTRY_ACL_GROUP) { + append_id(p, id); + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) + id = -1; + } + /* Solaris style has no second colon after other and mask */ + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) + || (tag != ARCHIVE_ENTRY_ACL_OTHER + && tag != ARCHIVE_ENTRY_ACL_MASK)) + *(*p)++ = ':'; + } + if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + /* POSIX.1e ACL perms */ + *(*p)++ = (perm & 0444) ? 'r' : '-'; + *(*p)++ = (perm & 0222) ? 'w' : '-'; + *(*p)++ = (perm & 0111) ? 'x' : '-'; + } else { + /* NFSv4 ACL perms */ + for (i = 0; i < nfsv4_acl_perm_map_size; i++) { + if (perm & nfsv4_acl_perm_map[i].perm) + *(*p)++ = nfsv4_acl_perm_map[i].c; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*p)++ = '-'; + } + *(*p)++ = ':'; + for (i = 0; i < nfsv4_acl_flag_map_size; i++) { + if (perm & nfsv4_acl_flag_map[i].perm) + *(*p)++ = nfsv4_acl_flag_map[i].c; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*p)++ = '-'; + } + *(*p)++ = ':'; + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + strcpy(*p, "allow"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + strcpy(*p, "deny"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + strcpy(*p, "audit"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + strcpy(*p, "alarm"); + break; + } + *p += strlen(*p); + } + if (id != -1) { + *(*p)++ = ':'; + append_id(p, id); + } +} + +/* + * Parse a wide ACL text string. + * + * The want_type argument may be one of the following: + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT + * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL + * + * POSIX.1e ACL entries prefixed with "default:" are treated as + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 + */ +int +archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, + int want_type) +{ + struct { + const wchar_t *start; + const wchar_t *end; + } field[6], name; + + const wchar_t *s, *st; + + int numfields, fields, n, r, sol, ret; + int type, types, tag, permset, id; + size_t len; + wchar_t sep; + + ret = ARCHIVE_OK; + types = 0; + + switch (want_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + numfields = 5; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + numfields = 6; + break; + default: + return (ARCHIVE_FATAL); + } + + while (text != NULL && *text != L'\0') { + /* + * Parse the fields out of the next entry, + * advance 'text' to start of next entry. + */ + fields = 0; + do { + const wchar_t *start, *end; + next_field_w(&text, &start, &end, &sep); + if (fields < numfields) { + field[fields].start = start; + field[fields].end = end; + } + ++fields; + } while (sep == L':'); + + /* Set remaining fields to blank. */ + for (n = fields; n < numfields; ++n) + field[n].start = field[n].end = NULL; + + if (field[0].start != NULL && *(field[0].start) == L'#') { + /* Comment, skip entry */ + continue; + } + + n = 0; + sol = 0; + id = -1; + permset = 0; + name.start = name.end = NULL; + + if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* POSIX.1e ACLs */ + /* + * Default keyword "default:user::rwx" + * if found, we have one more field + * + * We also support old Solaris extension: + * "defaultuser::rwx" is the default ACL corresponding + * to "user::rwx", etc. valid only for first field + */ + s = field[0].start; + len = field[0].end - field[0].start; + if (*s == L'd' && (len == 1 || (len >= 7 + && wmemcmp((s + 1), L"efault", 6) == 0))) { + type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + if (len > 7) + field[0].start += 7; + else + n = 1; + } else + type = want_type; + + /* Check for a numeric ID in field n+1 or n+3. */ + isint_w(field[n + 1].start, field[n + 1].end, &id); + /* Field n+3 is optional. */ + if (id == -1 && fields > n+3) + isint_w(field[n + 3].start, field[n + 3].end, + &id); + + tag = 0; + s = field[n].start; + st = field[n].start + 1; + len = field[n].end - field[n].start; + + switch (*s) { + case L'u': + if (len == 1 || (len == 4 + && wmemcmp(st, L"ser", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case L'g': + if (len == 1 || (len == 5 + && wmemcmp(st, L"roup", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case L'o': + if (len == 1 || (len == 5 + && wmemcmp(st, L"ther", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + case L'm': + if (len == 1 || (len == 4 + && wmemcmp(st, L"ask", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_MASK; + break; + default: + break; + } + + switch (tag) { + case ARCHIVE_ENTRY_ACL_OTHER: + case ARCHIVE_ENTRY_ACL_MASK: + if (fields == (n + 2) + && field[n + 1].start < field[n + 1].end + && ismode_w(field[n + 1].start, + field[n + 1].end, &permset)) { + /* This is Solaris-style "other:rwx" */ + sol = 1; + } else if (fields == (n + 3) && + field[n + 1].start < field[n + 1].end) { + /* Invalid mask or other field */ + ret = ARCHIVE_WARN; + continue; + } + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (id != -1 || + field[n + 1].start < field[n + 1].end) { + name = field[n + 1]; + if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) + tag = ARCHIVE_ENTRY_ACL_USER; + else + tag = ARCHIVE_ENTRY_ACL_GROUP; + } + break; + default: + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + + /* + * Without "default:" we expect mode in field 2 + * Exception: Solaris other and mask fields + */ + if (permset == 0 && !ismode_w(field[n + 2 - sol].start, + field[n + 2 - sol].end, &permset)) { + /* Invalid mode, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + } else { + /* NFS4 ACLs */ + s = field[0].start; + len = field[0].end - field[0].start; + tag = 0; + + switch (len) { + case 4: + if (wmemcmp(s, L"user", 4) == 0) + tag = ARCHIVE_ENTRY_ACL_USER; + break; + case 5: + if (wmemcmp(s, L"group", 5) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case 6: + if (wmemcmp(s, L"owner@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if (wmemcmp(s, L"group@", len) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 9: + if (wmemcmp(s, L"everyone@", 9) == 0) + tag = ARCHIVE_ENTRY_ACL_EVERYONE; + default: + break; + } + + if (tag == 0) { + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } else if (tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + n = 1; + name = field[1]; + isint_w(name.start, name.end, &id); + } else + n = 0; + + if (!is_nfs4_perms_w(field[1 + n].start, + field[1 + n].end, &permset)) { + /* Invalid NFSv4 perms, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + if (!is_nfs4_flags_w(field[2 + n].start, + field[2 + n].end, &permset)) { + /* Invalid NFSv4 flags, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + s = field[3 + n].start; + len = field[3 + n].end - field[3 + n].start; + type = 0; + if (len == 4) { + if (wmemcmp(s, L"deny", 4) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + } else if (len == 5) { + if (wmemcmp(s, L"allow", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + else if (wmemcmp(s, L"audit", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; + else if (wmemcmp(s, L"alarm", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + } + if (type == 0) { + /* Invalid entry type, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + isint_w(field[4 + n].start, field[4 + n].end, &id); + } + + /* Add entry to the internal list. */ + r = archive_acl_add_entry_w_len(acl, type, permset, + tag, id, name.start, name.end - name.start); + if (r < ARCHIVE_WARN) + return (r); + if (r != ARCHIVE_OK) + ret = ARCHIVE_WARN; + types |= type; + } + + /* Reset ACL */ + archive_acl_reset(acl, types); + + return (ret); +} + +/* + * Parse a string to a positive decimal integer. Returns true if + * the string is non-empty and consists only of decimal digits, + * false otherwise. + */ +static int +isint_w(const wchar_t *start, const wchar_t *end, int *result) +{ + int n = 0; + if (start >= end) + return (0); + while (start < end) { + if (*start < '0' || *start > '9') + return (0); + if (n > (INT_MAX / 10) || + (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { + n = INT_MAX; + } else { + n *= 10; + n += *start - '0'; + } + start++; + } + *result = n; + return (1); +} + +/* + * Parse a string as a mode field. Returns true if + * the string is non-empty and consists only of mode characters, + * false otherwise. + */ +static int +ismode_w(const wchar_t *start, const wchar_t *end, int *permset) +{ + const wchar_t *p; + + if (start >= end) + return (0); + p = start; + *permset = 0; + while (p < end) { + switch (*p++) { + case L'r': case L'R': + *permset |= ARCHIVE_ENTRY_ACL_READ; + break; + case L'w': case L'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE; + break; + case L'x': case L'X': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case L'-': + break; + default: + return (0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL permission field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * permission characters, false otherwise + */ +static int +is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) +{ + const wchar_t *p = start; + + while (p < end) { + switch (*p++) { + case L'r': + *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; + break; + case L'w': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; + break; + case L'x': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case L'p': + *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; + break; + case L'D': + *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; + break; + case L'd': + *permset |= ARCHIVE_ENTRY_ACL_DELETE; + break; + case L'a': + *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; + break; + case L'A': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; + break; + case L'R': + *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; + break; + case L'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; + break; + case L'c': + *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; + break; + case L'C': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; + break; + case L'o': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; + break; + case L's': + *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + break; + case L'-': + break; + default: + return(0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL flags field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * flag characters, false otherwise + */ +static int +is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) +{ + const wchar_t *p = start; + + while (p < end) { + switch(*p++) { + case L'f': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; + break; + case L'd': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; + break; + case L'i': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; + break; + case L'n': + *permset |= + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; + break; + case L'S': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; + break; + case L'F': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; + break; + case L'I': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; + break; + case L'-': + break; + default: + return (0); + } + } + return (1); +} + +/* + * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated + * to point to just after the separator. *start points to the first + * character of the matched text and *end just after the last + * character of the matched identifier. In particular *end - *start + * is the length of the field body, not including leading or trailing + * whitespace. + */ +static void +next_field_w(const wchar_t **wp, const wchar_t **start, + const wchar_t **end, wchar_t *sep) +{ + /* Skip leading whitespace to find start of field. */ + while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') { + (*wp)++; + } + *start = *wp; + + /* Scan for the separator. */ + while (**wp != L'\0' && **wp != L',' && **wp != L':' && + **wp != L'\n') { + (*wp)++; + } + *sep = **wp; + + /* Trim trailing whitespace to locate end of field. */ + *end = *wp - 1; + while (**end == L' ' || **end == L'\t' || **end == L'\n') { + (*end)--; + } + (*end)++; + + /* Adjust scanner location. */ + if (**wp != L'\0') + (*wp)++; +} + +/* + * Parse an ACL text string. + * + * The want_type argument may be one of the following: + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT + * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL + * + * POSIX.1e ACL entries prefixed with "default:" are treated as + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 + */ +int +archive_acl_from_text_l(struct archive_acl *acl, const char *text, + int want_type, struct archive_string_conv *sc) +{ + struct { + const char *start; + const char *end; + } field[6], name; + + const char *s, *st; + int numfields, fields, n, r, sol, ret; + int type, types, tag, permset, id; + size_t len; + char sep; + + switch (want_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + numfields = 5; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + numfields = 6; + break; + default: + return (ARCHIVE_FATAL); + } + + ret = ARCHIVE_OK; + types = 0; + + while (text != NULL && *text != '\0') { + /* + * Parse the fields out of the next entry, + * advance 'text' to start of next entry. + */ + fields = 0; + do { + const char *start, *end; + next_field(&text, &start, &end, &sep); + if (fields < numfields) { + field[fields].start = start; + field[fields].end = end; + } + ++fields; + } while (sep == ':'); + + /* Set remaining fields to blank. */ + for (n = fields; n < numfields; ++n) + field[n].start = field[n].end = NULL; + + if (field[0].start != NULL && *(field[0].start) == '#') { + /* Comment, skip entry */ + continue; + } + + n = 0; + sol = 0; + id = -1; + permset = 0; + name.start = name.end = NULL; + + if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* POSIX.1e ACLs */ + /* + * Default keyword "default:user::rwx" + * if found, we have one more field + * + * We also support old Solaris extension: + * "defaultuser::rwx" is the default ACL corresponding + * to "user::rwx", etc. valid only for first field + */ + s = field[0].start; + len = field[0].end - field[0].start; + if (*s == 'd' && (len == 1 || (len >= 7 + && memcmp((s + 1), "efault", 6) == 0))) { + type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + if (len > 7) + field[0].start += 7; + else + n = 1; + } else + type = want_type; + + /* Check for a numeric ID in field n+1 or n+3. */ + isint(field[n + 1].start, field[n + 1].end, &id); + /* Field n+3 is optional. */ + if (id == -1 && fields > (n + 3)) + isint(field[n + 3].start, field[n + 3].end, + &id); + + tag = 0; + s = field[n].start; + st = field[n].start + 1; + len = field[n].end - field[n].start; + + switch (*s) { + case 'u': + if (len == 1 || (len == 4 + && memcmp(st, "ser", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case 'g': + if (len == 1 || (len == 5 + && memcmp(st, "roup", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 'o': + if (len == 1 || (len == 5 + && memcmp(st, "ther", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + case 'm': + if (len == 1 || (len == 4 + && memcmp(st, "ask", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_MASK; + break; + default: + break; + } + + switch (tag) { + case ARCHIVE_ENTRY_ACL_OTHER: + case ARCHIVE_ENTRY_ACL_MASK: + if (fields == (n + 2) + && field[n + 1].start < field[n + 1].end + && ismode(field[n + 1].start, + field[n + 1].end, &permset)) { + /* This is Solaris-style "other:rwx" */ + sol = 1; + } else if (fields == (n + 3) && + field[n + 1].start < field[n + 1].end) { + /* Invalid mask or other field */ + ret = ARCHIVE_WARN; + continue; + } + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (id != -1 || + field[n + 1].start < field[n + 1].end) { + name = field[n + 1]; + if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) + tag = ARCHIVE_ENTRY_ACL_USER; + else + tag = ARCHIVE_ENTRY_ACL_GROUP; + } + break; + default: + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + + /* + * Without "default:" we expect mode in field 3 + * Exception: Solaris other and mask fields + */ + if (permset == 0 && !ismode(field[n + 2 - sol].start, + field[n + 2 - sol].end, &permset)) { + /* Invalid mode, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + } else { + /* NFS4 ACLs */ + s = field[0].start; + len = field[0].end - field[0].start; + tag = 0; + + switch (len) { + case 4: + if (memcmp(s, "user", 4) == 0) + tag = ARCHIVE_ENTRY_ACL_USER; + break; + case 5: + if (memcmp(s, "group", 5) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case 6: + if (memcmp(s, "owner@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if (memcmp(s, "group@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 9: + if (memcmp(s, "everyone@", 9) == 0) + tag = ARCHIVE_ENTRY_ACL_EVERYONE; + break; + default: + break; + } + + if (tag == 0) { + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } else if (tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + n = 1; + name = field[1]; + isint(name.start, name.end, &id); + } else + n = 0; + + if (!is_nfs4_perms(field[1 + n].start, + field[1 + n].end, &permset)) { + /* Invalid NFSv4 perms, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + if (!is_nfs4_flags(field[2 + n].start, + field[2 + n].end, &permset)) { + /* Invalid NFSv4 flags, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + s = field[3 + n].start; + len = field[3 + n].end - field[3 + n].start; + type = 0; + if (len == 4) { + if (memcmp(s, "deny", 4) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + } else if (len == 5) { + if (memcmp(s, "allow", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + else if (memcmp(s, "audit", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; + else if (memcmp(s, "alarm", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + } + if (type == 0) { + /* Invalid entry type, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + isint(field[4 + n].start, field[4 + n].end, + &id); + } + + /* Add entry to the internal list. */ + r = archive_acl_add_entry_len_l(acl, type, permset, + tag, id, name.start, name.end - name.start, sc); + if (r < ARCHIVE_WARN) + return (r); + if (r != ARCHIVE_OK) + ret = ARCHIVE_WARN; + types |= type; + } + + /* Reset ACL */ + archive_acl_reset(acl, types); + + return (ret); +} + +/* + * Parse a string to a positive decimal integer. Returns true if + * the string is non-empty and consists only of decimal digits, + * false otherwise. + */ +static int +isint(const char *start, const char *end, int *result) +{ + int n = 0; + if (start >= end) + return (0); + while (start < end) { + if (*start < '0' || *start > '9') + return (0); + if (n > (INT_MAX / 10) || + (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) { + n = INT_MAX; + } else { + n *= 10; + n += *start - '0'; + } + start++; + } + *result = n; + return (1); +} + +/* + * Parse a string as a mode field. Returns true if + * the string is non-empty and consists only of mode characters, + * false otherwise. + */ +static int +ismode(const char *start, const char *end, int *permset) +{ + const char *p; + + if (start >= end) + return (0); + p = start; + *permset = 0; + while (p < end) { + switch (*p++) { + case 'r': case 'R': + *permset |= ARCHIVE_ENTRY_ACL_READ; + break; + case 'w': case 'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE; + break; + case 'x': case 'X': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case '-': + break; + default: + return (0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL permission field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * permission characters, false otherwise + */ +static int +is_nfs4_perms(const char *start, const char *end, int *permset) +{ + const char *p = start; + + while (p < end) { + switch (*p++) { + case 'r': + *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; + break; + case 'w': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; + break; + case 'x': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case 'p': + *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; + break; + case 'D': + *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; + break; + case 'd': + *permset |= ARCHIVE_ENTRY_ACL_DELETE; + break; + case 'a': + *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; + break; + case 'A': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; + break; + case 'R': + *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; + break; + case 'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; + break; + case 'c': + *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; + break; + case 'C': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; + break; + case 'o': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; + break; + case 's': + *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + break; + case '-': + break; + default: + return(0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL flags field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * flag characters, false otherwise + */ +static int +is_nfs4_flags(const char *start, const char *end, int *permset) +{ + const char *p = start; + + while (p < end) { + switch(*p++) { + case 'f': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; + break; + case 'd': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; + break; + case 'i': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; + break; + case 'n': + *permset |= + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; + break; + case 'S': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; + break; + case 'F': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; + break; + case 'I': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; + break; + case '-': + break; + default: + return (0); + } + } + return (1); +} + +/* + * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated + * to point to just after the separator. *start points to the first + * character of the matched text and *end just after the last + * character of the matched identifier. In particular *end - *start + * is the length of the field body, not including leading or trailing + * whitespace. + */ +static void +next_field(const char **p, const char **start, + const char **end, char *sep) +{ + /* Skip leading whitespace to find start of field. */ + while (**p == ' ' || **p == '\t' || **p == '\n') { + (*p)++; + } + *start = *p; + + /* Scan for the separator. */ + while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') { + (*p)++; + } + *sep = **p; + + /* Trim trailing whitespace to locate end of field. */ + *end = *p - 1; + while (**end == ' ' || **end == '\t' || **end == '\n') { + (*end)--; + } + (*end)++; + + /* Adjust scanner location. */ + if (**p != '\0') + (*p)++; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_acl_private.h b/src/3rdparty/libarchive/libarchive/archive_acl_private.h new file mode 100644 index 00000000..ef0b0234 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_acl_private.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED +#define ARCHIVE_ACL_PRIVATE_H_INCLUDED + +#include "archive_string.h" + +struct archive_acl_entry { + struct archive_acl_entry *next; + int type; /* E.g., access or default */ + int tag; /* E.g., user/group/other/mask */ + int permset; /* r/w/x bits */ + int id; /* uid/gid for user/group */ + struct archive_mstring name; /* uname/gname */ +}; + +struct archive_acl { + mode_t mode; + struct archive_acl_entry *acl_head; + struct archive_acl_entry *acl_p; + int acl_state; /* See acl_next for details. */ + wchar_t *acl_text_w; + char *acl_text; + int acl_types; +}; + +void archive_acl_clear(struct archive_acl *); +void archive_acl_copy(struct archive_acl *, struct archive_acl *); +int archive_acl_count(struct archive_acl *, int); +int archive_acl_types(struct archive_acl *); +int archive_acl_reset(struct archive_acl *, int); +int archive_acl_next(struct archive *, struct archive_acl *, int, + int *, int *, int *, int *, const char **); + +int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *); +int archive_acl_add_entry_w_len(struct archive_acl *, + int, int, int, int, const wchar_t *, size_t); +int archive_acl_add_entry_len(struct archive_acl *, + int, int, int, int, const char *, size_t); + +wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int, + struct archive *); +char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int, + struct archive_string_conv *); + +/* + * ACL text parser. + */ +int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */, + int /* type */); +int archive_acl_from_text_l(struct archive_acl *, const char * /* text */, + int /* type */, struct archive_string_conv *); + +#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_check_magic.c b/src/3rdparty/libarchive/libarchive/archive_check_magic.c new file mode 100644 index 00000000..288ce233 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_check_magic.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_check_magic.c 201089 2009-12-28 02:20:23Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#endif + +#include "archive_private.h" + +static void +errmsg(const char *m) +{ + size_t s = strlen(m); + ssize_t written; + + while (s > 0) { + written = write(2, m, strlen(m)); + if (written <= 0) + return; + m += written; + s -= written; + } +} + +static __LA_DEAD void +diediedie(void) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) + /* Cause a breakpoint exception */ + DebugBreak(); +#endif + abort(); /* Terminate the program abnormally. */ +} + +static const char * +state_name(unsigned s) +{ + switch (s) { + case ARCHIVE_STATE_NEW: return ("new"); + case ARCHIVE_STATE_HEADER: return ("header"); + case ARCHIVE_STATE_DATA: return ("data"); + case ARCHIVE_STATE_EOF: return ("eof"); + case ARCHIVE_STATE_CLOSED: return ("closed"); + case ARCHIVE_STATE_FATAL: return ("fatal"); + default: return ("??"); + } +} + +static const char * +archive_handle_type_name(unsigned m) +{ + switch (m) { + case ARCHIVE_WRITE_MAGIC: return ("archive_write"); + case ARCHIVE_READ_MAGIC: return ("archive_read"); + case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk"); + case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk"); + case ARCHIVE_MATCH_MAGIC: return ("archive_match"); + default: return NULL; + } +} + + +static char * +write_all_states(char *buff, unsigned int states) +{ + unsigned int lowbit; + + buff[0] = '\0'; + + /* A trick for computing the lowest set bit. */ + while ((lowbit = states & (1 + ~states)) != 0) { + states &= ~lowbit; /* Clear the low bit. */ + strcat(buff, state_name(lowbit)); + if (states != 0) + strcat(buff, "/"); + } + return buff; +} + +/* + * Check magic value and current state. + * Magic value mismatches are fatal and result in calls to abort(). + * State mismatches return ARCHIVE_FATAL. + * Otherwise, returns ARCHIVE_OK. + * + * This is designed to catch serious programming errors that violate + * the libarchive API. + */ +int +__archive_check_magic(struct archive *a, unsigned int magic, + unsigned int state, const char *function) +{ + char states1[64]; + char states2[64]; + const char *handle_type; + + /* + * If this isn't some form of archive handle, + * then the library user has screwed up so bad that + * we don't even have a reliable way to report an error. + */ + handle_type = archive_handle_type_name(a->magic); + + if (!handle_type) { + errmsg("PROGRAMMER ERROR: Function "); + errmsg(function); + errmsg(" invoked with invalid archive handle.\n"); + diediedie(); + } + + if (a->magic != magic) { + archive_set_error(a, -1, + "PROGRAMMER ERROR: Function '%s' invoked" + " on '%s' archive object, which is not supported.", + function, + handle_type); + a->state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + + if ((a->state & state) == 0) { + /* If we're already FATAL, don't overwrite the error. */ + if (a->state != ARCHIVE_STATE_FATAL) + archive_set_error(a, -1, + "INTERNAL ERROR: Function '%s' invoked with" + " archive structure in state '%s'," + " should be in state '%s'", + function, + write_all_states(states1, a->state), + write_all_states(states2, state)); + a->state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + return ARCHIVE_OK; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_cmdline.c b/src/3rdparty/libarchive/libarchive/archive_cmdline.c new file mode 100644 index 00000000..7d3bac53 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_cmdline.c @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif + +#include "archive.h" +#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 +extract_quotation(struct archive_string *as, const char *p) +{ + const char *s; + + for (s = p + 1; *s;) { + if (*s == '\\') { + if (s[1] != '\0') { + archive_strappend_char(as, s[1]); + s += 2; + } else + s++; + } else if (*s == '"') + break; + else { + archive_strappend_char(as, s[0]); + s++; + } + } + if (*s != '"') + return (ARCHIVE_FAILED);/* Invalid sequence. */ + return ((ssize_t)(s + 1 - p)); +} + +static ssize_t +get_argument(struct archive_string *as, const char *p) +{ + const char *s = p; + + archive_string_empty(as); + + /* Skip beginning space characters. */ + while (*s != '\0' && *s == ' ') + s++; + /* Copy non-space characters. */ + while (*s != '\0' && *s != ' ') { + if (*s == '\\') { + if (s[1] != '\0') { + archive_strappend_char(as, s[1]); + s += 2; + } else { + s++;/* Ignore this character.*/ + break; + } + } else if (*s == '"') { + ssize_t q = extract_quotation(as, s); + if (q < 0) + return (ARCHIVE_FAILED);/* Invalid sequence. */ + s += q; + } else { + archive_strappend_char(as, s[0]); + s++; + } + } + return ((ssize_t)(s - p)); +} + +/* + * Set up command line arguments. + * Returns ARChIVE_OK if everything okey. + * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an + * empty command line. + * Returns ARChIVE_FATAL if no memory. + */ +int +__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd) +{ + struct archive_string as; + const char *p; + ssize_t al; + int r; + + archive_string_init(&as); + + /* Get first argument as a command path. */ + al = get_argument(&as, cmd); + if (al < 0) { + r = ARCHIVE_FAILED;/* Invalid sequence. */ + goto exit_function; + } + if (archive_strlen(&as) == 0) { + r = ARCHIVE_FAILED;/* An empty command path. */ + goto exit_function; + } + r = cmdline_set_path(data, as.s); + if (r != ARCHIVE_OK) + goto exit_function; + p = strrchr(as.s, '/'); + if (p == NULL) + p = as.s; + else + p++; + r = cmdline_add_arg(data, p); + if (r != ARCHIVE_OK) + goto exit_function; + cmd += al; + + for (;;) { + al = get_argument(&as, cmd); + if (al < 0) { + r = ARCHIVE_FAILED;/* Invalid sequence. */ + goto exit_function; + } + if (al == 0) + break; + cmd += al; + if (archive_strlen(&as) == 0 && *cmd == '\0') + break; + r = cmdline_add_arg(data, as.s); + if (r != ARCHIVE_OK) + goto exit_function; + } + r = ARCHIVE_OK; +exit_function: + archive_string_free(&as); + return (r); +} + +/* + * 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. + */ +static int +cmdline_add_arg(struct archive_cmdline *data, const char *arg) +{ + char **newargv; + + if (data->path == NULL) + return (ARCHIVE_FAILED); + + newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *)); + if (newargv == NULL) + return (ARCHIVE_FATAL); + data->argv = newargv; + data->argv[data->argc] = strdup(arg); + if (data->argv[data->argc] == NULL) + return (ARCHIVE_FATAL); + /* Set the terminator of argv. */ + data->argv[++data->argc] = NULL; + return (ARCHIVE_OK); +} + +struct archive_cmdline * +__archive_cmdline_allocate(void) +{ + return (struct archive_cmdline *) + calloc(1, sizeof(struct archive_cmdline)); +} + +/* + * Release the resources. + */ +int +__archive_cmdline_free(struct archive_cmdline *data) +{ + + if (data) { + free(data->path); + if (data->argv != NULL) { + int i; + for (i = 0; data->argv[i] != NULL; i++) + free(data->argv[i]); + free(data->argv); + } + free(data); + } + return (ARCHIVE_OK); +} + diff --git a/src/3rdparty/libarchive/libarchive/archive_cmdline_private.h b/src/3rdparty/libarchive/libarchive/archive_cmdline_private.h new file mode 100644 index 00000000..4e409e81 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_cmdline_private.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_CMDLINE_PRIVATE_H +#define ARCHIVE_CMDLINE_PRIVATE_H + +struct archive_cmdline { + char *path; + char **argv; + int argc; +}; + +struct archive_cmdline *__archive_cmdline_allocate(void); +int __archive_cmdline_parse(struct archive_cmdline *, const char *); +int __archive_cmdline_free(struct archive_cmdline *); + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_crc32.h b/src/3rdparty/libarchive/libarchive/archive_crc32.h new file mode 100644 index 00000000..cd633af8 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_crc32.h @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2009 Joerg Sonnenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_crc32.h 201102 2009-12-28 03:11:36Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +/* + * When zlib is unavailable, we should still be able to validate + * uncompressed zip archives. That requires us to be able to compute + * the CRC32 check value. This is a drop-in compatible replacement + * for crc32() from zlib. It's slower than the zlib implementation, + * but still pretty fast: This runs about 300MB/s on my 3GHz P4 + * compared to about 800MB/s for the zlib implementation. + */ +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]; + + 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. */ + for (;len >= 8; len -= 8) { + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + } + while (len--) + crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); + return (crc ^ 0xffffffffUL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_endian.h b/src/3rdparty/libarchive/libarchive/archive_endian.h new file mode 100644 index 00000000..1c48563b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_endian.h @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 2002 Thomas Moestl + * 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. + * + * $FreeBSD: head/lib/libarchive/archive_endian.h 201085 2009-12-28 02:17:15Z kientzle $ + * + * Borrowed from FreeBSD's + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +/* Note: This is a purely internal header! */ +/* Do not use this outside of libarchive internal code! */ + +#ifndef ARCHIVE_ENDIAN_H_INCLUDED +#define ARCHIVE_ENDIAN_H_INCLUDED + + +/* + * 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 + +/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ + +static inline uint16_t +archive_be16dec(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 p1 = p[1]; + unsigned int p0 = p[0]; + + return ((p0 << 8) | p1); +} + +static inline uint32_t +archive_be32dec(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 p3 = p[3]; + unsigned int p2 = p[2]; + unsigned int p1 = p[1]; + unsigned int p0 = p[0]; + + return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3); +} + +static inline uint64_t +archive_be64dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4)); +} + +static inline uint16_t +archive_le16dec(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 p1 = p[1]; + unsigned int p0 = p[0]; + + return ((p1 << 8) | p0); +} + +static inline uint32_t +archive_le32dec(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 p3 = p[3]; + unsigned int p2 = p[2]; + unsigned int p1 = p[1]; + unsigned int p0 = p[0]; + + return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0); +} + +static inline uint64_t +archive_le64dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p)); +} + +static inline void +archive_be16enc(void *pp, uint16_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = (u >> 8) & 0xff; + p[1] = u & 0xff; +} + +static inline void +archive_be32enc(void *pp, uint32_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = (u >> 24) & 0xff; + p[1] = (u >> 16) & 0xff; + p[2] = (u >> 8) & 0xff; + p[3] = u & 0xff; +} + +static inline void +archive_be64enc(void *pp, uint64_t u) +{ + unsigned char *p = (unsigned char *)pp; + + archive_be32enc(p, (uint32_t)(u >> 32)); + archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff)); +} + +static inline void +archive_le16enc(void *pp, uint16_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; +} + +static inline void +archive_le32enc(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; + p[3] = (u >> 24) & 0xff; +} + +static inline void +archive_le64enc(void *pp, uint64_t u) +{ + unsigned char *p = (unsigned char *)pp; + + archive_le32enc(p, (uint32_t)(u & 0xffffffff)); + archive_le32enc(p + 4, (uint32_t)(u >> 32)); +} + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_entry.c b/src/3rdparty/libarchive/libarchive/archive_entry.c new file mode 100644 index 00000000..30fb4566 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry.c @@ -0,0 +1,2038 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:27Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#if MAJOR_IN_MKDEV +#include +#define HAVE_MAJOR +#elif MAJOR_IN_SYSMACROS +#include +#define HAVE_MAJOR +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include /* for Linux file flags */ +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include /* for Linux file flags */ +#endif +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#include "archive.h" +#include "archive_acl_private.h" +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_entry_private.h" + +#if !defined(HAVE_MAJOR) && !defined(major) +/* Replacement for major/minor/makedev. */ +#define major(x) ((int)(0x00ff & ((x) >> 8))) +#define minor(x) ((int)(0xffff00ff & (x))) +#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) +#endif + +/* Play games to come up with a suitable makedev() definition. */ +#ifdef __QNXNTO__ +/* QNX. */ +#include +#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) +#elif defined makedev +/* There's a "makedev" macro. */ +#define ae_makedev(maj, min) makedev((maj), (min)) +#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) +/* Windows. */ +#define ae_makedev(maj, min) mkdev((maj), (min)) +#else +/* There's a "makedev" function. */ +#define ae_makedev(maj, min) makedev((maj), (min)) +#endif + +/* + * This adjustment is needed to support the following idiom for adding + * 1000ns to the stored time: + * archive_entry_set_atime(archive_entry_atime(), + * archive_entry_atime_nsec() + 1000) + * The additional if() here compensates for ambiguity in the C standard, + * which permits two possible interpretations of a % b when a is negative. + */ +#define FIX_NS(t,ns) \ + do { \ + t += ns / 1000000000; \ + ns %= 1000000000; \ + if (ns < 0) { --t; ns += 1000000000; } \ + } while (0) + +static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); +static const wchar_t *ae_wcstofflags(const wchar_t *stringp, + unsigned long *setp, unsigned long *clrp); +static const char *ae_strtofflags(const char *stringp, + unsigned long *setp, unsigned long *clrp); + +#ifndef HAVE_WCSCPY +static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2) +{ + wchar_t *dest = s1; + while ((*s1 = *s2) != L'\0') + ++s1, ++s2; + return dest; +} +#endif +#ifndef HAVE_WCSLEN +static size_t wcslen(const wchar_t *s) +{ + const wchar_t *p = s; + while (*p != L'\0') + ++p; + return p - s; +} +#endif +#ifndef HAVE_WMEMCMP +/* Good enough for simple equality testing, but not for sorting. */ +#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t)) +#endif + +/**************************************************************************** + * + * Public Interface + * + ****************************************************************************/ + +struct archive_entry * +archive_entry_clear(struct archive_entry *entry) +{ + if (entry == NULL) + return (NULL); + archive_mstring_clean(&entry->ae_fflags_text); + archive_mstring_clean(&entry->ae_gname); + archive_mstring_clean(&entry->ae_hardlink); + archive_mstring_clean(&entry->ae_pathname); + archive_mstring_clean(&entry->ae_sourcepath); + archive_mstring_clean(&entry->ae_symlink); + archive_mstring_clean(&entry->ae_uname); + archive_entry_copy_mac_metadata(entry, NULL, 0); + archive_acl_clear(&entry->acl); + archive_entry_xattr_clear(entry); + archive_entry_sparse_clear(entry); + free(entry->stat); + memset(entry, 0, sizeof(*entry)); + return entry; +} + +struct archive_entry * +archive_entry_clone(struct archive_entry *entry) +{ + struct archive_entry *entry2; + struct ae_xattr *xp; + struct ae_sparse *sp; + size_t s; + const void *p; + + /* Allocate new structure and copy over all of the fields. */ + /* TODO: Should we copy the archive over? Or require a new archive + * as an argument? */ + entry2 = archive_entry_new2(entry->archive); + if (entry2 == NULL) + return (NULL); + entry2->ae_stat = entry->ae_stat; + entry2->ae_fflags_set = entry->ae_fflags_set; + entry2->ae_fflags_clear = entry->ae_fflags_clear; + + /* TODO: XXX If clone can have a different archive, what do we do here if + * character sets are different? XXX */ + archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); + archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname); + archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink); + archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname); + archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); + archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink); + entry2->ae_set = entry->ae_set; + archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname); + + /* Copy encryption status */ + entry2->encryption = entry->encryption; + + /* Copy ACL data over. */ + archive_acl_copy(&entry2->acl, &entry->acl); + + /* Copy Mac OS metadata. */ + p = archive_entry_mac_metadata(entry, &s); + archive_entry_copy_mac_metadata(entry2, p, s); + + /* Copy xattr data over. */ + xp = entry->xattr_head; + while (xp != NULL) { + archive_entry_xattr_add_entry(entry2, + xp->name, xp->value, xp->size); + xp = xp->next; + } + + /* Copy sparse data over. */ + sp = entry->sparse_head; + while (sp != NULL) { + archive_entry_sparse_add_entry(entry2, + sp->offset, sp->length); + sp = sp->next; + } + + return (entry2); +} + +void +archive_entry_free(struct archive_entry *entry) +{ + archive_entry_clear(entry); + free(entry); +} + +struct archive_entry * +archive_entry_new(void) +{ + return archive_entry_new2(NULL); +} + +struct archive_entry * +archive_entry_new2(struct archive *a) +{ + struct archive_entry *entry; + + entry = (struct archive_entry *)calloc(1, sizeof(*entry)); + if (entry == NULL) + return (NULL); + entry->archive = a; + return (entry); +} + +/* + * Functions for reading fields from an archive_entry. + */ + +time_t +archive_entry_atime(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_atime); +} + +long +archive_entry_atime_nsec(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_atime_nsec); +} + +int +archive_entry_atime_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_ATIME); +} + +time_t +archive_entry_birthtime(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_birthtime); +} + +long +archive_entry_birthtime_nsec(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_birthtime_nsec); +} + +int +archive_entry_birthtime_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_BIRTHTIME); +} + +time_t +archive_entry_ctime(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_ctime); +} + +int +archive_entry_ctime_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_CTIME); +} + +long +archive_entry_ctime_nsec(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_ctime_nsec); +} + +dev_t +archive_entry_dev(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_dev_is_broken_down) + return ae_makedev(entry->ae_stat.aest_devmajor, + entry->ae_stat.aest_devminor); + else + return (entry->ae_stat.aest_dev); +} + +int +archive_entry_dev_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_DEV); +} + +dev_t +archive_entry_devmajor(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_dev_is_broken_down) + return (entry->ae_stat.aest_devmajor); + else + return major(entry->ae_stat.aest_dev); +} + +dev_t +archive_entry_devminor(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_dev_is_broken_down) + return (entry->ae_stat.aest_devminor); + else + return minor(entry->ae_stat.aest_dev); +} + +mode_t +archive_entry_filetype(struct archive_entry *entry) +{ + return (AE_IFMT & entry->acl.mode); +} + +void +archive_entry_fflags(struct archive_entry *entry, + unsigned long *set, unsigned long *clear) +{ + *set = entry->ae_fflags_set; + *clear = entry->ae_fflags_clear; +} + +/* + * Note: if text was provided, this just returns that text. If you + * really need the text to be rebuilt in a canonical form, set the + * text, ask for the bitmaps, then set the bitmaps. (Setting the + * bitmaps clears any stored text.) This design is deliberate: if + * we're editing archives, we don't want to discard flags just because + * they aren't supported on the current system. The bitmap<->text + * conversions are platform-specific (see below). + */ +const char * +archive_entry_fflags_text(struct archive_entry *entry) +{ + const char *f; + char *p; + + if (archive_mstring_get_mbs(entry->archive, + &entry->ae_fflags_text, &f) == 0) { + if (f != NULL) + return (f); + } else if (errno == ENOMEM) + __archive_errx(1, "No memory"); + + if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0) + return (NULL); + + p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear); + if (p == NULL) + return (NULL); + + archive_mstring_copy_mbs(&entry->ae_fflags_text, p); + free(p); + if (archive_mstring_get_mbs(entry->archive, + &entry->ae_fflags_text, &f) == 0) + return (f); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +la_int64_t +archive_entry_gid(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_gid); +} + +const char * +archive_entry_gname(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const char * +archive_entry_gname_utf8(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + + +const wchar_t * +archive_entry_gname_w(struct archive_entry *entry) +{ + const wchar_t *p; + if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +int +_archive_entry_gname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc)); +} + +const char * +archive_entry_hardlink(struct archive_entry *entry) +{ + const char *p; + if ((entry->ae_set & AE_SET_HARDLINK) == 0) + return (NULL); + if (archive_mstring_get_mbs( + entry->archive, &entry->ae_hardlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const char * +archive_entry_hardlink_utf8(struct archive_entry *entry) +{ + const char *p; + if ((entry->ae_set & AE_SET_HARDLINK) == 0) + return (NULL); + if (archive_mstring_get_utf8( + entry->archive, &entry->ae_hardlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const wchar_t * +archive_entry_hardlink_w(struct archive_entry *entry) +{ + const wchar_t *p; + if ((entry->ae_set & AE_SET_HARDLINK) == 0) + return (NULL); + if (archive_mstring_get_wcs( + entry->archive, &entry->ae_hardlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +int +_archive_entry_hardlink_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + if ((entry->ae_set & AE_SET_HARDLINK) == 0) { + *p = NULL; + *len = 0; + return (0); + } + return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc)); +} + +la_int64_t +archive_entry_ino(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_ino); +} + +int +archive_entry_ino_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_INO); +} + +la_int64_t +archive_entry_ino64(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_ino); +} + +mode_t +archive_entry_mode(struct archive_entry *entry) +{ + return (entry->acl.mode); +} + +time_t +archive_entry_mtime(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_mtime); +} + +long +archive_entry_mtime_nsec(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_mtime_nsec); +} + +int +archive_entry_mtime_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_MTIME); +} + +unsigned int +archive_entry_nlink(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_nlink); +} + +const char * +archive_entry_pathname(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_mbs( + entry->archive, &entry->ae_pathname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const char * +archive_entry_pathname_utf8(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_utf8( + entry->archive, &entry->ae_pathname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const wchar_t * +archive_entry_pathname_w(struct archive_entry *entry) +{ + const wchar_t *p; + if (archive_mstring_get_wcs( + entry->archive, &entry->ae_pathname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +int +_archive_entry_pathname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc)); +} + +mode_t +archive_entry_perm(struct archive_entry *entry) +{ + return (~AE_IFMT & entry->acl.mode); +} + +dev_t +archive_entry_rdev(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_rdev_is_broken_down) + return ae_makedev(entry->ae_stat.aest_rdevmajor, + entry->ae_stat.aest_rdevminor); + else + return (entry->ae_stat.aest_rdev); +} + +dev_t +archive_entry_rdevmajor(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_rdev_is_broken_down) + return (entry->ae_stat.aest_rdevmajor); + else + return major(entry->ae_stat.aest_rdev); +} + +dev_t +archive_entry_rdevminor(struct archive_entry *entry) +{ + if (entry->ae_stat.aest_rdev_is_broken_down) + return (entry->ae_stat.aest_rdevminor); + else + return minor(entry->ae_stat.aest_rdev); +} + +la_int64_t +archive_entry_size(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_size); +} + +int +archive_entry_size_is_set(struct archive_entry *entry) +{ + return (entry->ae_set & AE_SET_SIZE); +} + +const char * +archive_entry_sourcepath(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_mbs( + entry->archive, &entry->ae_sourcepath, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const wchar_t * +archive_entry_sourcepath_w(struct archive_entry *entry) +{ + const wchar_t *p; + if (archive_mstring_get_wcs( + entry->archive, &entry->ae_sourcepath, &p) == 0) + return (p); + return (NULL); +} + +const char * +archive_entry_symlink(struct archive_entry *entry) +{ + const char *p; + if ((entry->ae_set & AE_SET_SYMLINK) == 0) + return (NULL); + if (archive_mstring_get_mbs( + entry->archive, &entry->ae_symlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const char * +archive_entry_symlink_utf8(struct archive_entry *entry) +{ + const char *p; + if ((entry->ae_set & AE_SET_SYMLINK) == 0) + return (NULL); + if (archive_mstring_get_utf8( + entry->archive, &entry->ae_symlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const wchar_t * +archive_entry_symlink_w(struct archive_entry *entry) +{ + const wchar_t *p; + if ((entry->ae_set & AE_SET_SYMLINK) == 0) + return (NULL); + if (archive_mstring_get_wcs( + entry->archive, &entry->ae_symlink, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +int +_archive_entry_symlink_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + if ((entry->ae_set & AE_SET_SYMLINK) == 0) { + *p = NULL; + *len = 0; + return (0); + } + return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc)); +} + +la_int64_t +archive_entry_uid(struct archive_entry *entry) +{ + return (entry->ae_stat.aest_uid); +} + +const char * +archive_entry_uname(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const char * +archive_entry_uname_utf8(struct archive_entry *entry) +{ + const char *p; + if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +const wchar_t * +archive_entry_uname_w(struct archive_entry *entry) +{ + const wchar_t *p; + if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0) + return (p); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); +} + +int +_archive_entry_uname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc)); +} + +int +archive_entry_is_data_encrypted(struct archive_entry *entry) +{ + return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA); +} + +int +archive_entry_is_metadata_encrypted(struct archive_entry *entry) +{ + return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA); +} + +int +archive_entry_is_encrypted(struct archive_entry *entry) +{ + return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA)); +} + +/* + * Functions to set archive_entry properties. + */ + +void +archive_entry_set_filetype(struct archive_entry *entry, unsigned int type) +{ + entry->stat_valid = 0; + entry->acl.mode &= ~AE_IFMT; + entry->acl.mode |= AE_IFMT & type; +} + +void +archive_entry_set_fflags(struct archive_entry *entry, + unsigned long set, unsigned long clear) +{ + archive_mstring_clean(&entry->ae_fflags_text); + entry->ae_fflags_set = set; + entry->ae_fflags_clear = clear; +} + +const char * +archive_entry_copy_fflags_text(struct archive_entry *entry, + const char *flags) +{ + archive_mstring_copy_mbs(&entry->ae_fflags_text, flags); + return (ae_strtofflags(flags, + &entry->ae_fflags_set, &entry->ae_fflags_clear)); +} + +const wchar_t * +archive_entry_copy_fflags_text_w(struct archive_entry *entry, + const wchar_t *flags) +{ + archive_mstring_copy_wcs(&entry->ae_fflags_text, flags); + return (ae_wcstofflags(flags, + &entry->ae_fflags_set, &entry->ae_fflags_clear)); +} + +void +archive_entry_set_gid(struct archive_entry *entry, la_int64_t g) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_gid = g; +} + +void +archive_entry_set_gname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_gname, name); +} + +void +archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_utf8(&entry->ae_gname, name); +} + +void +archive_entry_copy_gname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_gname, name); +} + +void +archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) +{ + archive_mstring_copy_wcs(&entry->ae_gname, name); +} + +int +archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) +{ + if (archive_mstring_update_utf8(entry->archive, + &entry->ae_gname, name) == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +int +_archive_entry_copy_gname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc)); +} + +void +archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino) +{ + entry->stat_valid = 0; + entry->ae_set |= AE_SET_INO; + entry->ae_stat.aest_ino = ino; +} + +void +archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino) +{ + entry->stat_valid = 0; + entry->ae_set |= AE_SET_INO; + entry->ae_stat.aest_ino = ino; +} + +void +archive_entry_set_hardlink(struct archive_entry *entry, const char *target) +{ + archive_mstring_copy_mbs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; +} + +void +archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target) +{ + archive_mstring_copy_utf8(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; +} + +void +archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) +{ + archive_mstring_copy_mbs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; +} + +void +archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) +{ + archive_mstring_copy_wcs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; +} + +int +archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target) +{ + if (target != NULL) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; + if (archive_mstring_update_utf8(entry->archive, + &entry->ae_hardlink, target) == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +int +_archive_entry_copy_hardlink_l(struct archive_entry *entry, + const char *target, size_t len, struct archive_string_conv *sc) +{ + int r; + + r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, + target, len, sc); + if (target != NULL && r == 0) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; + return (r); +} + +void +archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) +{ + FIX_NS(t, ns); + entry->stat_valid = 0; + entry->ae_set |= AE_SET_ATIME; + entry->ae_stat.aest_atime = t; + entry->ae_stat.aest_atime_nsec = ns; +} + +void +archive_entry_unset_atime(struct archive_entry *entry) +{ + archive_entry_set_atime(entry, 0, 0); + entry->ae_set &= ~AE_SET_ATIME; +} + +void +archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns) +{ + FIX_NS(t, ns); + entry->stat_valid = 0; + entry->ae_set |= AE_SET_BIRTHTIME; + entry->ae_stat.aest_birthtime = t; + entry->ae_stat.aest_birthtime_nsec = ns; +} + +void +archive_entry_unset_birthtime(struct archive_entry *entry) +{ + archive_entry_set_birthtime(entry, 0, 0); + entry->ae_set &= ~AE_SET_BIRTHTIME; +} + +void +archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) +{ + FIX_NS(t, ns); + entry->stat_valid = 0; + entry->ae_set |= AE_SET_CTIME; + entry->ae_stat.aest_ctime = t; + entry->ae_stat.aest_ctime_nsec = ns; +} + +void +archive_entry_unset_ctime(struct archive_entry *entry) +{ + archive_entry_set_ctime(entry, 0, 0); + entry->ae_set &= ~AE_SET_CTIME; +} + +void +archive_entry_set_dev(struct archive_entry *entry, dev_t d) +{ + entry->stat_valid = 0; + entry->ae_set |= AE_SET_DEV; + entry->ae_stat.aest_dev_is_broken_down = 0; + entry->ae_stat.aest_dev = d; +} + +void +archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) +{ + entry->stat_valid = 0; + entry->ae_set |= AE_SET_DEV; + entry->ae_stat.aest_dev_is_broken_down = 1; + entry->ae_stat.aest_devmajor = m; +} + +void +archive_entry_set_devminor(struct archive_entry *entry, dev_t m) +{ + entry->stat_valid = 0; + entry->ae_set |= AE_SET_DEV; + entry->ae_stat.aest_dev_is_broken_down = 1; + entry->ae_stat.aest_devminor = m; +} + +/* Set symlink if symlink is already set, else set hardlink. */ +void +archive_entry_set_link(struct archive_entry *entry, const char *target) +{ + if (entry->ae_set & AE_SET_SYMLINK) + archive_mstring_copy_mbs(&entry->ae_symlink, target); + else + archive_mstring_copy_mbs(&entry->ae_hardlink, target); +} + +void +archive_entry_set_link_utf8(struct archive_entry *entry, const char *target) +{ + if (entry->ae_set & AE_SET_SYMLINK) + archive_mstring_copy_utf8(&entry->ae_symlink, target); + else + archive_mstring_copy_utf8(&entry->ae_hardlink, target); +} + +/* Set symlink if symlink is already set, else set hardlink. */ +void +archive_entry_copy_link(struct archive_entry *entry, const char *target) +{ + if (entry->ae_set & AE_SET_SYMLINK) + archive_mstring_copy_mbs(&entry->ae_symlink, target); + else + archive_mstring_copy_mbs(&entry->ae_hardlink, target); +} + +/* Set symlink if symlink is already set, else set hardlink. */ +void +archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) +{ + if (entry->ae_set & AE_SET_SYMLINK) + archive_mstring_copy_wcs(&entry->ae_symlink, target); + else + archive_mstring_copy_wcs(&entry->ae_hardlink, target); +} + +int +archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) +{ + int r; + if (entry->ae_set & AE_SET_SYMLINK) + r = archive_mstring_update_utf8(entry->archive, + &entry->ae_symlink, target); + else + r = archive_mstring_update_utf8(entry->archive, + &entry->ae_hardlink, target); + if (r == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +int +_archive_entry_copy_link_l(struct archive_entry *entry, + const char *target, size_t len, struct archive_string_conv *sc) +{ + int r; + + if (entry->ae_set & AE_SET_SYMLINK) + r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, + target, len, sc); + else + r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, + target, len, sc); + return (r); +} + +void +archive_entry_set_mode(struct archive_entry *entry, mode_t m) +{ + entry->stat_valid = 0; + entry->acl.mode = m; +} + +void +archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns) +{ + FIX_NS(t, ns); + entry->stat_valid = 0; + entry->ae_set |= AE_SET_MTIME; + entry->ae_stat.aest_mtime = t; + entry->ae_stat.aest_mtime_nsec = ns; +} + +void +archive_entry_unset_mtime(struct archive_entry *entry) +{ + archive_entry_set_mtime(entry, 0, 0); + entry->ae_set &= ~AE_SET_MTIME; +} + +void +archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_nlink = nlink; +} + +void +archive_entry_set_pathname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_pathname, name); +} + +void +archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_utf8(&entry->ae_pathname, name); +} + +void +archive_entry_copy_pathname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_pathname, name); +} + +void +archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) +{ + archive_mstring_copy_wcs(&entry->ae_pathname, name); +} + +int +archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) +{ + if (archive_mstring_update_utf8(entry->archive, + &entry->ae_pathname, name) == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +int +_archive_entry_copy_pathname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname, + name, len, sc)); +} + +void +archive_entry_set_perm(struct archive_entry *entry, mode_t p) +{ + entry->stat_valid = 0; + entry->acl.mode &= AE_IFMT; + entry->acl.mode |= ~AE_IFMT & p; +} + +void +archive_entry_set_rdev(struct archive_entry *entry, dev_t m) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_rdev = m; + entry->ae_stat.aest_rdev_is_broken_down = 0; +} + +void +archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_rdev_is_broken_down = 1; + entry->ae_stat.aest_rdevmajor = m; +} + +void +archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_rdev_is_broken_down = 1; + entry->ae_stat.aest_rdevminor = m; +} + +void +archive_entry_set_size(struct archive_entry *entry, la_int64_t s) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_size = s; + entry->ae_set |= AE_SET_SIZE; +} + +void +archive_entry_unset_size(struct archive_entry *entry) +{ + archive_entry_set_size(entry, 0); + entry->ae_set &= ~AE_SET_SIZE; +} + +void +archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) +{ + archive_mstring_copy_mbs(&entry->ae_sourcepath, path); +} + +void +archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path) +{ + archive_mstring_copy_wcs(&entry->ae_sourcepath, path); +} + +void +archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) +{ + archive_mstring_copy_mbs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; +} + +void +archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname) +{ + archive_mstring_copy_utf8(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; +} + +void +archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) +{ + archive_mstring_copy_mbs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; +} + +void +archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) +{ + archive_mstring_copy_wcs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; +} + +int +archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname) +{ + if (linkname != NULL) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; + if (archive_mstring_update_utf8(entry->archive, + &entry->ae_symlink, linkname) == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +int +_archive_entry_copy_symlink_l(struct archive_entry *entry, + const char *linkname, size_t len, struct archive_string_conv *sc) +{ + int r; + + r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, + linkname, len, sc); + if (linkname != NULL && r == 0) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; + return (r); +} + +void +archive_entry_set_uid(struct archive_entry *entry, la_int64_t u) +{ + entry->stat_valid = 0; + entry->ae_stat.aest_uid = u; +} + +void +archive_entry_set_uname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_uname, name); +} + +void +archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_utf8(&entry->ae_uname, name); +} + +void +archive_entry_copy_uname(struct archive_entry *entry, const char *name) +{ + archive_mstring_copy_mbs(&entry->ae_uname, name); +} + +void +archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) +{ + archive_mstring_copy_wcs(&entry->ae_uname, name); +} + +int +archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) +{ + if (archive_mstring_update_utf8(entry->archive, + &entry->ae_uname, name) == 0) + return (1); + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (0); +} + +void +archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted) +{ + if (is_encrypted) { + entry->encryption |= AE_ENCRYPTION_DATA; + } else { + entry->encryption &= ~AE_ENCRYPTION_DATA; + } +} + +void +archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted) +{ + if (is_encrypted) { + entry->encryption |= AE_ENCRYPTION_METADATA; + } else { + entry->encryption &= ~AE_ENCRYPTION_METADATA; + } +} + +int +_archive_entry_copy_uname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_uname, + name, len, sc)); +} + +const void * +archive_entry_mac_metadata(struct archive_entry *entry, size_t *s) +{ + *s = entry->mac_metadata_size; + return entry->mac_metadata; +} + +void +archive_entry_copy_mac_metadata(struct archive_entry *entry, + const void *p, size_t s) +{ + free(entry->mac_metadata); + if (p == NULL || s == 0) { + entry->mac_metadata = NULL; + entry->mac_metadata_size = 0; + } else { + entry->mac_metadata_size = s; + entry->mac_metadata = malloc(s); + if (entry->mac_metadata == NULL) + abort(); + memcpy(entry->mac_metadata, p, s); + } +} + +/* + * ACL management. The following would, of course, be a lot simpler + * if: 1) the last draft of POSIX.1e were a really thorough and + * complete standard that addressed the needs of ACL archiving and 2) + * everyone followed it faithfully. Alas, neither is true, so the + * following is a lot more complex than might seem necessary to the + * uninitiated. + */ + +struct archive_acl * +archive_entry_acl(struct archive_entry *entry) +{ + return &entry->acl; +} + +void +archive_entry_acl_clear(struct archive_entry *entry) +{ + archive_acl_clear(&entry->acl); +} + +/* + * Add a single ACL entry to the internal list of ACL data. + */ +int +archive_entry_acl_add_entry(struct archive_entry *entry, + int type, int permset, int tag, int id, const char *name) +{ + return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name); +} + +/* + * As above, but with a wide-character name. + */ +int +archive_entry_acl_add_entry_w(struct archive_entry *entry, + int type, int permset, int tag, int id, const wchar_t *name) +{ + return archive_acl_add_entry_w_len(&entry->acl, + type, permset, tag, id, name, wcslen(name)); +} + +/* + * Return a bitmask of ACL types in an archive entry ACL list + */ +int +archive_entry_acl_types(struct archive_entry *entry) +{ + return (archive_acl_types(&entry->acl)); +} + +/* + * Return a count of entries matching "want_type". + */ +int +archive_entry_acl_count(struct archive_entry *entry, int want_type) +{ + return archive_acl_count(&entry->acl, want_type); +} + +/* + * Prepare for reading entries from the ACL data. Returns a count + * of entries matching "want_type", or zero if there are no + * non-extended ACL entries of that type. + */ +int +archive_entry_acl_reset(struct archive_entry *entry, int want_type) +{ + return archive_acl_reset(&entry->acl, want_type); +} + +/* + * Return the next ACL entry in the list. Fake entries for the + * standard permissions and include them in the returned list. + */ +int +archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, + int *permset, int *tag, int *id, const char **name) +{ + int r; + r = archive_acl_next(entry->archive, &entry->acl, want_type, type, + permset, tag, id, name); + if (r == ARCHIVE_FATAL && errno == ENOMEM) + __archive_errx(1, "No memory"); + return (r); +} + +/* + * Generate a text version of the ACL. The flags parameter controls + * the style of the generated ACL. + */ +wchar_t * +archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len, + int flags) +{ + return (archive_acl_to_text_w(&entry->acl, len, flags, + entry->archive)); +} + +char * +archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len, + int flags) +{ + return (archive_acl_to_text_l(&entry->acl, len, flags, NULL)); +} + +char * +_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len, + int flags, struct archive_string_conv *sc) +{ + return (archive_acl_to_text_l(&entry->acl, len, flags, sc)); +} + +/* + * ACL text parser. + */ +int +archive_entry_acl_from_text_w(struct archive_entry *entry, + const wchar_t *wtext, int type) +{ + return (archive_acl_from_text_w(&entry->acl, wtext, type)); +} + +int +archive_entry_acl_from_text(struct archive_entry *entry, + const char *text, int type) +{ + return (archive_acl_from_text_l(&entry->acl, text, type, NULL)); +} + +int +_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text, + int type, struct archive_string_conv *sc) +{ + return (archive_acl_from_text_l(&entry->acl, text, type, sc)); +} + +/* Deprecated */ +static int +archive_entry_acl_text_compat(int *flags) +{ + if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0) + return (1); + + /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */ + if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) + *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID; + + /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */ + if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) + *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; + + *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA; + + return (0); +} + +/* Deprecated */ +const wchar_t * +archive_entry_acl_text_w(struct archive_entry *entry, int flags) +{ + if (entry->acl.acl_text_w != NULL) { + free(entry->acl.acl_text_w); + entry->acl.acl_text_w = NULL; + } + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl, + NULL, flags, entry->archive); + return (entry->acl.acl_text_w); +} + +/* Deprecated */ +const char * +archive_entry_acl_text(struct archive_entry *entry, int flags) +{ + if (entry->acl.acl_text != NULL) { + free(entry->acl.acl_text); + entry->acl.acl_text = NULL; + } + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL, + flags, NULL); + + return (entry->acl.acl_text); +} + +/* Deprecated */ +int +_archive_entry_acl_text_l(struct archive_entry *entry, int flags, + const char **acl_text, size_t *len, struct archive_string_conv *sc) +{ + if (entry->acl.acl_text != NULL) { + free(entry->acl.acl_text); + entry->acl.acl_text = NULL; + } + + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, + (ssize_t *)len, flags, sc); + + *acl_text = entry->acl.acl_text; + + return (0); +} + +/* + * Following code is modified from UC Berkeley sources, and + * is subject to the following copyright notice. + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static const struct flag { + const char *name; + const wchar_t *wname; + unsigned long set; + unsigned long clear; +} flags[] = { + /* Preferred (shorter) names per flag first, all prefixed by "no" */ +#ifdef SF_APPEND + { "nosappnd", L"nosappnd", SF_APPEND, 0 }, + { "nosappend", L"nosappend", SF_APPEND, 0 }, +#endif +#if defined(FS_APPEND_FL) /* 'a' */ + { "nosappnd", L"nosappnd", FS_APPEND_FL, 0 }, + { "nosappend", L"nosappend", FS_APPEND_FL, 0 }, +#elif defined(EXT2_APPEND_FL) /* 'a' */ + { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 }, + { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 }, +#endif +#ifdef SF_ARCHIVED + { "noarch", L"noarch", SF_ARCHIVED, 0 }, + { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, +#endif +#ifdef SF_IMMUTABLE + { "noschg", L"noschg", SF_IMMUTABLE, 0 }, + { "noschange", L"noschange", SF_IMMUTABLE, 0 }, + { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 }, +#endif +#if defined(FS_IMMUTABLE_FL) /* 'i' */ + { "noschg", L"noschg", FS_IMMUTABLE_FL, 0 }, + { "noschange", L"noschange", FS_IMMUTABLE_FL, 0 }, + { "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0 }, +#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */ + { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 }, + { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 }, + { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 }, +#endif +#ifdef SF_NOUNLINK + { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 }, + { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 }, +#endif +#ifdef SF_SNAPSHOT + { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 }, +#endif +#ifdef UF_APPEND + { "nouappnd", L"nouappnd", UF_APPEND, 0 }, + { "nouappend", L"nouappend", UF_APPEND, 0 }, +#endif +#ifdef UF_IMMUTABLE + { "nouchg", L"nouchg", UF_IMMUTABLE, 0 }, + { "nouchange", L"nouchange", UF_IMMUTABLE, 0 }, + { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 }, +#endif +#ifdef UF_NODUMP + { "nodump", L"nodump", 0, UF_NODUMP}, +#endif +#if defined(FS_NODUMP_FL) /* 'd' */ + { "nodump", L"nodump", 0, FS_NODUMP_FL}, +#elif defined(EXT2_NODUMP_FL) /* 'd' */ + { "nodump", L"nodump", 0, EXT2_NODUMP_FL}, +#endif +#ifdef UF_OPAQUE + { "noopaque", L"noopaque", UF_OPAQUE, 0 }, +#endif +#ifdef UF_NOUNLINK + { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 }, + { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 }, +#endif +#ifdef UF_COMPRESSED + { "nocompressed",L"nocompressed", UF_COMPRESSED, 0 }, +#endif +#ifdef UF_HIDDEN + { "nohidden", L"nohidden", UF_HIDDEN, 0 }, +#endif +#if defined(FS_UNRM_FL) + { "nouunlink", L"nouunlink", FS_UNRM_FL, 0}, +#elif defined(EXT2_UNRM_FL) + { "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0}, +#endif + +#if defined(FS_BTREE_FL) + { "nobtree", L"nobtree", FS_BTREE_FL, 0 }, +#elif defined(EXT2_BTREE_FL) + { "nobtree", L"nobtree", EXT2_BTREE_FL, 0 }, +#endif + +#if defined(FS_ECOMPR_FL) + { "nocomperr", L"nocomperr", FS_ECOMPR_FL, 0 }, +#elif defined(EXT2_ECOMPR_FL) + { "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 }, +#endif + +#if defined(FS_COMPR_FL) /* 'c' */ + { "nocompress", L"nocompress", FS_COMPR_FL, 0 }, +#elif defined(EXT2_COMPR_FL) /* 'c' */ + { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 }, +#endif + +#if defined(FS_NOATIME_FL) /* 'A' */ + { "noatime", L"noatime", 0, FS_NOATIME_FL}, +#elif defined(EXT2_NOATIME_FL) /* 'A' */ + { "noatime", L"noatime", 0, EXT2_NOATIME_FL}, +#endif + +#if defined(FS_DIRTY_FL) + { "nocompdirty",L"nocompdirty", FS_DIRTY_FL, 0}, +#elif defined(EXT2_DIRTY_FL) + { "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0}, +#endif + +#if defined(FS_COMPRBLK_FL) +#if defined(FS_NOCOMPR_FL) + { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, FS_NOCOMPR_FL}, +#else + { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, 0}, +#endif +#elif defined(EXT2_COMPRBLK_FL) +#if defined(EXT2_NOCOMPR_FL) + { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL}, +#else + { "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0}, +#endif +#endif +#if defined(FS_DIRSYNC_FL) + { "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0}, +#elif defined(EXT2_DIRSYNC_FL) + { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0}, +#endif +#if defined(FS_INDEX_FL) + { "nohashidx", L"nohashidx", FS_INDEX_FL, 0}, +#elif defined(EXT2_INDEX_FL) + { "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0}, +#endif +#if defined(FS_IMAGIC_FL) + { "noimagic", L"noimagic", FS_IMAGIC_FL, 0}, +#elif defined(EXT2_IMAGIC_FL) + { "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0}, +#endif +#if defined(FS_JOURNAL_DATA_FL) + { "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0}, +#elif defined(EXT3_JOURNAL_DATA_FL) + { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0}, +#endif +#if defined(FS_SECRM_FL) + { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0}, +#elif defined(EXT2_SECRM_FL) + { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0}, +#endif +#if defined(FS_SYNC_FL) + { "nosync", L"nosync", FS_SYNC_FL, 0}, +#elif defined(EXT2_SYNC_FL) + { "nosync", L"nosync", EXT2_SYNC_FL, 0}, +#endif +#if defined(FS_NOTAIL_FL) + { "notail", L"notail", 0, FS_NOTAIL_FL}, +#elif defined(EXT2_NOTAIL_FL) + { "notail", L"notail", 0, EXT2_NOTAIL_FL}, +#endif +#if defined(FS_TOPDIR_FL) + { "notopdir", L"notopdir", FS_TOPDIR_FL, 0}, +#elif defined(EXT2_TOPDIR_FL) + { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0}, +#endif +#ifdef FS_ENCRYPT_FL + { "noencrypt", L"noencrypt", FS_ENCRYPT_FL, 0}, +#endif +#ifdef FS_HUGE_FILE_FL + { "nohugefile", L"nohugefile", FS_HUGE_FILE_FL, 0}, +#endif +#ifdef FS_EXTENT_FL + { "noextent", L"noextent", FS_EXTENT_FL, 0}, +#endif +#ifdef FS_EA_INODE_FL + { "noeainode", L"noeainode", FS_EA_INODE_FL, 0}, +#endif +#ifdef FS_EOFBLOCKS_FL + { "noeofblocks",L"noeofblocks", FS_EOFBLOCKS_FL, 0}, +#endif +#ifdef FS_NOCOW_FL + { "nocow", L"nocow", FS_NOCOW_FL, 0}, +#endif +#ifdef FS_INLINE_DATA_FL + { "noinlinedata",L"noinlinedata", FS_INLINE_DATA_FL, 0}, +#endif +#ifdef FS_PROJINHERIT_FL + { "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0}, +#endif +#if defined(FS_RESERVED_FL) + { "noreserved", L"noreserved", FS_RESERVED_FL, 0}, +#elif defined(EXT2_RESERVED_FL) + { "noreserved", L"noreserved", EXT2_RESERVED_FL, 0}, +#endif + { NULL, NULL, 0, 0 } +}; + +/* + * fflagstostr -- + * Convert file flags to a comma-separated string. If no flags + * are set, return the empty string. + */ +static char * +ae_fflagstostr(unsigned long bitset, unsigned long bitclear) +{ + char *string, *dp; + const char *sp; + unsigned long bits; + const struct flag *flag; + size_t length; + + bits = bitset | bitclear; + length = 0; + for (flag = flags; flag->name != NULL; flag++) + if (bits & (flag->set | flag->clear)) { + length += strlen(flag->name) + 1; + bits &= ~(flag->set | flag->clear); + } + + if (length == 0) + return (NULL); + string = (char *)malloc(length); + if (string == NULL) + return (NULL); + + dp = string; + for (flag = flags; flag->name != NULL; flag++) { + if (bitset & flag->set || bitclear & flag->clear) { + sp = flag->name + 2; + } else if (bitset & flag->clear || bitclear & flag->set) { + sp = flag->name; + } else + continue; + bitset &= ~(flag->set | flag->clear); + bitclear &= ~(flag->set | flag->clear); + if (dp > string) + *dp++ = ','; + while ((*dp++ = *sp++) != '\0') + ; + dp--; + } + + *dp = '\0'; + return (string); +} + +/* + * strtofflags -- + * Take string of arguments and return file flags. This + * version works a little differently than strtofflags(3). + * In particular, it always tests every token, skipping any + * unrecognized tokens. It returns a pointer to the first + * unrecognized token, or NULL if every token was recognized. + * This version is also const-correct and does not modify the + * provided string. + */ +static const char * +ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) +{ + const char *start, *end; + const struct flag *flag; + unsigned long set, clear; + const char *failed; + + set = clear = 0; + start = s; + failed = NULL; + /* Find start of first token. */ + while (*start == '\t' || *start == ' ' || *start == ',') + start++; + while (*start != '\0') { + size_t length; + /* Locate end of token. */ + end = start; + while (*end != '\0' && *end != '\t' && + *end != ' ' && *end != ',') + end++; + length = end - start; + for (flag = flags; flag->name != NULL; flag++) { + size_t flag_length = strlen(flag->name); + if (length == flag_length + && memcmp(start, flag->name, length) == 0) { + /* Matched "noXXXX", so reverse the sense. */ + clear |= flag->set; + set |= flag->clear; + break; + } else if (length == flag_length - 2 + && memcmp(start, flag->name + 2, length) == 0) { + /* Matched "XXXX", so don't reverse. */ + set |= flag->set; + clear |= flag->clear; + break; + } + } + /* Ignore unknown flag names. */ + if (flag->name == NULL && failed == NULL) + failed = start; + + /* Find start of next token. */ + start = end; + while (*start == '\t' || *start == ' ' || *start == ',') + start++; + + } + + if (setp) + *setp = set; + if (clrp) + *clrp = clear; + + /* Return location of first failure. */ + return (failed); +} + +/* + * wcstofflags -- + * Take string of arguments and return file flags. This + * version works a little differently than strtofflags(3). + * In particular, it always tests every token, skipping any + * unrecognized tokens. It returns a pointer to the first + * unrecognized token, or NULL if every token was recognized. + * This version is also const-correct and does not modify the + * provided string. + */ +static const wchar_t * +ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) +{ + const wchar_t *start, *end; + const struct flag *flag; + unsigned long set, clear; + const wchar_t *failed; + + set = clear = 0; + start = s; + failed = NULL; + /* Find start of first token. */ + while (*start == L'\t' || *start == L' ' || *start == L',') + start++; + while (*start != L'\0') { + size_t length; + /* Locate end of token. */ + end = start; + while (*end != L'\0' && *end != L'\t' && + *end != L' ' && *end != L',') + end++; + length = end - start; + for (flag = flags; flag->wname != NULL; flag++) { + size_t flag_length = wcslen(flag->wname); + if (length == flag_length + && wmemcmp(start, flag->wname, length) == 0) { + /* Matched "noXXXX", so reverse the sense. */ + clear |= flag->set; + set |= flag->clear; + break; + } else if (length == flag_length - 2 + && wmemcmp(start, flag->wname + 2, length) == 0) { + /* Matched "XXXX", so don't reverse. */ + set |= flag->set; + clear |= flag->clear; + break; + } + } + /* Ignore unknown flag names. */ + if (flag->wname == NULL && failed == NULL) + failed = start; + + /* Find start of next token. */ + start = end; + while (*start == L'\t' || *start == L' ' || *start == L',') + start++; + + } + + if (setp) + *setp = set; + if (clrp) + *clrp = clear; + + /* Return location of first failure. */ + return (failed); +} + + +#ifdef TEST +#include +int +main(int argc, char **argv) +{ + struct archive_entry *entry = archive_entry_new(); + unsigned long set, clear; + const wchar_t *remainder; + + remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,"); + archive_entry_fflags(entry, &set, &clear); + + wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder); + + wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry)); + return (0); +} +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_entry.h b/src/3rdparty/libarchive/libarchive/archive_entry.h new file mode 100644 index 00000000..bcc2962b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry.h @@ -0,0 +1,702 @@ +/*- + * Copyright (c) 2003-2008 Tim Kientzle + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $ + */ + +#ifndef ARCHIVE_ENTRY_H_INCLUDED +#define ARCHIVE_ENTRY_H_INCLUDED + +/* Note: Compiler will complain if this does not match archive.h! */ +#define ARCHIVE_VERSION_NUMBER 3003002 + +/* + * Note: archive_entry.h is for use outside of libarchive; the + * configuration headers (config.h, archive_platform.h, etc.) are + * purely internal. Do NOT use HAVE_XXX configuration macros to + * control the behavior of this header! If you must conditionalize, + * use predefined compiler and/or platform macros. + */ + +#include +#include /* for wchar_t */ +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#endif + +/* Get a suitable 64-bit integer type. */ +#if !defined(__LA_INT64_T_DEFINED) +# if ARCHIVE_VERSION_NUMBER < 4000000 +#define __LA_INT64_T la_int64_t +# endif +#define __LA_INT64_T_DEFINED +# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) +typedef __int64 la_int64_t; +# else +#include +# if defined(_SCO_DS) || defined(__osf__) +typedef long long la_int64_t; +# else +typedef int64_t la_int64_t; +# endif +# endif +#endif + +/* The la_ssize_t should match the type used in 'struct stat' */ +#if !defined(__LA_SSIZE_T_DEFINED) +/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */ +# if ARCHIVE_VERSION_NUMBER < 4000000 +#define __LA_SSIZE_T la_ssize_t +# endif +#define __LA_SSIZE_T_DEFINED +# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) +# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_) +typedef ssize_t la_ssize_t; +# elif defined(_WIN64) +typedef __int64 la_ssize_t; +# else +typedef long la_ssize_t; +# endif +# else +# include /* ssize_t */ +typedef ssize_t la_ssize_t; +# endif +#endif + +/* Get a suitable definition for mode_t */ +#if ARCHIVE_VERSION_NUMBER >= 3999000 +/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */ +# define __LA_MODE_T int +#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__) +# define __LA_MODE_T unsigned short +#else +# define __LA_MODE_T mode_t +#endif + +/* Large file support for Android */ +#ifdef __ANDROID__ +#include "android_lf.h" +#endif + +/* + * On Windows, define LIBARCHIVE_STATIC if you're building or using a + * .lib. The default here assumes you're building a DLL. Only + * libarchive source should ever define __LIBARCHIVE_BUILD. + */ +#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) +# ifdef __LIBARCHIVE_BUILD +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllexport)) extern +# else +# define __LA_DECL __declspec(dllexport) +# endif +# else +# ifdef __GNUC__ +# define __LA_DECL +# else +# define __LA_DECL __declspec(dllimport) +# endif +# endif +#else +/* Static libraries on all platforms and shared libraries on non-Windows. */ +# define __LA_DECL +#endif + +#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 +# define __LA_DEPRECATED __attribute__((deprecated)) +#else +# define __LA_DEPRECATED +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Description of an archive entry. + * + * You can think of this as "struct stat" with some text fields added in. + * + * TODO: Add "comment", "charset", and possibly other entries that are + * supported by "pax interchange" format. However, GNU, ustar, cpio, + * and other variants don't support these features, so they're not an + * excruciatingly high priority right now. + * + * TODO: "pax interchange" format allows essentially arbitrary + * key/value attributes to be attached to any entry. Supporting + * such extensions may make this library useful for special + * applications (e.g., a package manager could attach special + * package-management attributes to each entry). + */ +struct archive; +struct archive_entry; + +/* + * File-type constants. These are returned from archive_entry_filetype() + * and passed to archive_entry_set_filetype(). + * + * These values match S_XXX defines on every platform I've checked, + * including Windows, AIX, Linux, Solaris, and BSD. They're + * (re)defined here because platforms generally don't define the ones + * they don't support. For example, Windows doesn't define S_IFLNK or + * S_IFBLK. Instead of having a mass of conditional logic and system + * checks to define any S_XXX values that aren't supported locally, + * I've just defined a new set of such constants so that + * libarchive-based applications can manipulate and identify archive + * entries properly even if the hosting platform can't store them on + * disk. + * + * These values are also used directly within some portable formats, + * such as cpio. If you find a platform that varies from these, the + * correct solution is to leave these alone and translate from these + * portable values to platform-native values when entries are read from + * or written to disk. + */ +/* + * In libarchive 4.0, we can drop the casts here. + * They're needed to work around Borland C's broken mode_t. + */ +#define AE_IFMT ((__LA_MODE_T)0170000) +#define AE_IFREG ((__LA_MODE_T)0100000) +#define AE_IFLNK ((__LA_MODE_T)0120000) +#define AE_IFSOCK ((__LA_MODE_T)0140000) +#define AE_IFCHR ((__LA_MODE_T)0020000) +#define AE_IFBLK ((__LA_MODE_T)0060000) +#define AE_IFDIR ((__LA_MODE_T)0040000) +#define AE_IFIFO ((__LA_MODE_T)0010000) + +/* + * Basic object manipulation + */ + +__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *); +/* The 'clone' function does a deep copy; all of the strings are copied too. */ +__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *); +__LA_DECL void archive_entry_free(struct archive_entry *); +__LA_DECL struct archive_entry *archive_entry_new(void); + +/* + * This form of archive_entry_new2() will pull character-set + * conversion information from the specified archive handle. The + * older archive_entry_new(void) form is equivalent to calling + * archive_entry_new2(NULL) and will result in the use of an internal + * default character-set conversion. + */ +__LA_DECL struct archive_entry *archive_entry_new2(struct archive *); + +/* + * Retrieve fields from an archive_entry. + * + * There are a number of implicit conversions among these fields. For + * example, if a regular string field is set and you read the _w wide + * character field, the entry will implicitly convert narrow-to-wide + * using the current locale. Similarly, dev values are automatically + * updated when you write devmajor or devminor and vice versa. + * + * In addition, fields can be "set" or "unset." Unset string fields + * return NULL, non-string fields have _is_set() functions to test + * whether they've been set. You can "unset" a string field by + * assigning NULL; non-string fields have _unset() functions to + * unset them. + * + * Note: There is one ambiguity in the above; string fields will + * also return NULL when implicit character set conversions fail. + * This is usually what you want. + */ +__LA_DECL time_t archive_entry_atime(struct archive_entry *); +__LA_DECL long archive_entry_atime_nsec(struct archive_entry *); +__LA_DECL int archive_entry_atime_is_set(struct archive_entry *); +__LA_DECL time_t archive_entry_birthtime(struct archive_entry *); +__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *); +__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *); +__LA_DECL time_t archive_entry_ctime(struct archive_entry *); +__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); +__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *); +__LA_DECL dev_t archive_entry_dev(struct archive_entry *); +__LA_DECL int archive_entry_dev_is_set(struct archive_entry *); +__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); +__LA_DECL dev_t archive_entry_devminor(struct archive_entry *); +__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); +__LA_DECL void archive_entry_fflags(struct archive_entry *, + unsigned long * /* set */, + unsigned long * /* clear */); +__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *); +__LA_DECL la_int64_t archive_entry_gid(struct archive_entry *); +__LA_DECL const char *archive_entry_gname(struct archive_entry *); +__LA_DECL const char *archive_entry_gname_utf8(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *); +__LA_DECL const char *archive_entry_hardlink(struct archive_entry *); +__LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *); +__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *); +__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *); +__LA_DECL int archive_entry_ino_is_set(struct archive_entry *); +__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); +__LA_DECL time_t archive_entry_mtime(struct archive_entry *); +__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *); +__LA_DECL int archive_entry_mtime_is_set(struct archive_entry *); +__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *); +__LA_DECL const char *archive_entry_pathname(struct archive_entry *); +__LA_DECL const char *archive_entry_pathname_utf8(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *); +__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdev(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); +__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *); +__LA_DECL la_int64_t archive_entry_size(struct archive_entry *); +__LA_DECL int archive_entry_size_is_set(struct archive_entry *); +__LA_DECL const char *archive_entry_strmode(struct archive_entry *); +__LA_DECL const char *archive_entry_symlink(struct archive_entry *); +__LA_DECL const char *archive_entry_symlink_utf8(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *); +__LA_DECL la_int64_t archive_entry_uid(struct archive_entry *); +__LA_DECL const char *archive_entry_uname(struct archive_entry *); +__LA_DECL const char *archive_entry_uname_utf8(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); +__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *); +__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *); +__LA_DECL int archive_entry_is_encrypted(struct archive_entry *); + +/* + * Set fields in an archive_entry. + * + * Note: Before libarchive 2.4, there were 'set' and 'copy' versions + * of the string setters. 'copy' copied the actual string, 'set' just + * stored the pointer. In libarchive 2.4 and later, strings are + * always copied. + */ + +__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_unset_atime(struct archive_entry *); +#if defined(_WIN32) && !defined(__CYGWIN__) +__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *); +#endif +__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); +__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_unset_ctime(struct archive_entry *); +__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int); +__LA_DECL void archive_entry_set_fflags(struct archive_entry *, + unsigned long /* set */, unsigned long /* clear */); +/* Returns pointer to start of first invalid token, or NULL if none. */ +/* Note that all recognized tokens are processed, regardless. */ +__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *, + const char *); +__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, + const wchar_t *); +__LA_DECL void archive_entry_set_gid(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_gname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_set_ino64(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T); +__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_unset_mtime(struct archive_entry *); +__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int); +__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_pathname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T); +__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_unset_size(struct archive_entry *); +__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *); +__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_symlink_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_uid(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_uname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted); +__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted); +/* + * Routines to bulk copy fields to/from a platform-native "struct + * stat." Libarchive used to just store a struct stat inside of each + * archive_entry object, but this created issues when trying to + * manipulate archives on systems different than the ones they were + * created on. + * + * TODO: On Linux and other LFS systems, provide both stat32 and + * stat64 versions of these functions and all of the macro glue so + * that archive_entry_stat is magically defined to + * archive_entry_stat32 or archive_entry_stat64 as appropriate. + */ +__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); +__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); + +/* + * Storage for Mac OS-specific AppleDouble metadata information. + * Apple-format tar files store a separate binary blob containing + * encoded metadata with ACL, extended attributes, etc. + * This provides a place to store that blob. + */ + +__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *); +__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t); + +/* + * ACL routines. This used to simply store and return text-format ACL + * strings, but that proved insufficient for a number of reasons: + * = clients need control over uname/uid and gname/gid mappings + * = there are many different ACL text formats + * = would like to be able to read/convert archives containing ACLs + * on platforms that lack ACL libraries + * + * This last point, in particular, forces me to implement a reasonably + * complete set of ACL support routines. + */ + +/* + * Permission bits. + */ +#define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001 +#define ARCHIVE_ENTRY_ACL_WRITE 0x00000002 +#define ARCHIVE_ENTRY_ACL_READ 0x00000004 +#define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008 +#define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008 +#define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010 +#define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010 +#define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020 +#define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020 +#define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040 +#define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080 +#define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100 +#define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200 +#define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400 +#define ARCHIVE_ENTRY_ACL_DELETE 0x00000800 +#define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000 +#define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000 +#define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000 +#define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000 + +#define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \ + (ARCHIVE_ENTRY_ACL_EXECUTE \ + | ARCHIVE_ENTRY_ACL_WRITE \ + | ARCHIVE_ENTRY_ACL_READ) + +#define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \ + (ARCHIVE_ENTRY_ACL_EXECUTE \ + | ARCHIVE_ENTRY_ACL_READ_DATA \ + | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \ + | ARCHIVE_ENTRY_ACL_WRITE_DATA \ + | ARCHIVE_ENTRY_ACL_ADD_FILE \ + | ARCHIVE_ENTRY_ACL_APPEND_DATA \ + | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \ + | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \ + | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \ + | ARCHIVE_ENTRY_ACL_DELETE_CHILD \ + | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \ + | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \ + | ARCHIVE_ENTRY_ACL_DELETE \ + | ARCHIVE_ENTRY_ACL_READ_ACL \ + | ARCHIVE_ENTRY_ACL_WRITE_ACL \ + | ARCHIVE_ENTRY_ACL_WRITE_OWNER \ + | ARCHIVE_ENTRY_ACL_SYNCHRONIZE) + +/* + * Inheritance values (NFS4 ACLs only); included in permset. + */ +#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000 +#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000 + +#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \ + (ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \ + | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \ + | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \ + | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \ + | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \ + | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \ + | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) + +/* We need to be able to specify combinations of these. */ +#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */ +#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */ +#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \ + | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) +#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \ + | ARCHIVE_ENTRY_ACL_TYPE_DENY \ + | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \ + | ARCHIVE_ENTRY_ACL_TYPE_ALARM) + +/* Tag values mimic POSIX.1e */ +#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */ +#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */ +#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */ +#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */ +#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */ +#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */ +#define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */ + +/* + * Set the ACL by clearing it and adding entries one at a time. + * Unlike the POSIX.1e ACL routines, you must specify the type + * (access/default) for each entry. Internally, the ACL data is just + * a soup of entries. API calls here allow you to retrieve just the + * entries of interest. This design (which goes against the spirit of + * POSIX.1e) is useful for handling archive formats that combine + * default and access information in a single ACL list. + */ +__LA_DECL void archive_entry_acl_clear(struct archive_entry *); +__LA_DECL int archive_entry_acl_add_entry(struct archive_entry *, + int /* type */, int /* permset */, int /* tag */, + int /* qual */, const char * /* name */); +__LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *, + int /* type */, int /* permset */, int /* tag */, + int /* qual */, const wchar_t * /* name */); + +/* + * To retrieve the ACL, first "reset", then repeatedly ask for the + * "next" entry. The want_type parameter allows you to request only + * certain types of entries. + */ +__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); +__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */, + int * /* type */, int * /* permset */, int * /* tag */, + int * /* qual */, const char ** /* name */); +__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, + int * /* type */, int * /* permset */, int * /* tag */, + int * /* qual */, const wchar_t ** /* name */); + +/* + * Construct a text-format ACL. The flags argument is a bitmask that + * can include any of the following: + * + * Flags only for archive entries with POSIX.1e ACL: + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries. + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries. + * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each + * default ACL entry. + * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and + * "mask" entries. + * + * Flags only for archive entries with NFSv4 ACL: + * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for + * unset permissions and flags in NFSv4 ACL permission and flag fields + * + * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL: + * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in + * each ACL entry. + * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma + * instead of newline. + */ +#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001 +#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002 +#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004 +#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008 +#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010 + +__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *, + la_ssize_t * /* len */, int /* flags */); +__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *, + la_ssize_t * /* len */, int /* flags */); +__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *, + const wchar_t * /* wtext */, int /* type */); +__LA_DECL int archive_entry_acl_from_text(struct archive_entry *, + const char * /* text */, int /* type */); + +/* Deprecated constants */ +#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 +#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 + +/* Deprecated functions */ +__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, + int /* flags */) __LA_DEPRECATED; +__LA_DECL const char *archive_entry_acl_text(struct archive_entry *, + int /* flags */) __LA_DEPRECATED; + +/* Return bitmask of ACL types in an archive entry */ +__LA_DECL int archive_entry_acl_types(struct archive_entry *); + +/* Return a count of entries matching 'want_type' */ +__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); + +/* Return an opaque ACL object. */ +/* There's not yet anything clients can actually do with this... */ +struct archive_acl; +__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *); + +/* + * extended attributes + */ + +__LA_DECL void archive_entry_xattr_clear(struct archive_entry *); +__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *, + const char * /* name */, const void * /* value */, + size_t /* size */); + +/* + * To retrieve the xattr list, first "reset", then repeatedly ask for the + * "next" entry. + */ + +__LA_DECL int archive_entry_xattr_count(struct archive_entry *); +__LA_DECL int archive_entry_xattr_reset(struct archive_entry *); +__LA_DECL int archive_entry_xattr_next(struct archive_entry *, + const char ** /* name */, const void ** /* value */, size_t *); + +/* + * sparse + */ + +__LA_DECL void archive_entry_sparse_clear(struct archive_entry *); +__LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *, + la_int64_t /* offset */, la_int64_t /* length */); + +/* + * To retrieve the xattr list, first "reset", then repeatedly ask for the + * "next" entry. + */ + +__LA_DECL int archive_entry_sparse_count(struct archive_entry *); +__LA_DECL int archive_entry_sparse_reset(struct archive_entry *); +__LA_DECL int archive_entry_sparse_next(struct archive_entry *, + la_int64_t * /* offset */, la_int64_t * /* length */); + +/* + * Utility to match up hardlinks. + * + * The 'struct archive_entry_linkresolver' is a cache of archive entries + * for files with multiple links. Here's how to use it: + * 1. Create a lookup object with archive_entry_linkresolver_new() + * 2. Tell it the archive format you're using. + * 3. Hand each archive_entry to archive_entry_linkify(). + * That function will return 0, 1, or 2 entries that should + * be written. + * 4. Call archive_entry_linkify(resolver, NULL) until + * no more entries are returned. + * 5. Call archive_entry_linkresolver_free(resolver) to free resources. + * + * The entries returned have their hardlink and size fields updated + * appropriately. If an entry is passed in that does not refer to + * a file with multiple links, it is returned unchanged. The intention + * is that you should be able to simply filter all entries through + * this machine. + * + * To make things more efficient, be sure that each entry has a valid + * nlinks value. The hardlink cache uses this to track when all links + * have been found. If the nlinks value is zero, it will keep every + * name in the cache indefinitely, which can use a lot of memory. + * + * Note that archive_entry_size() is reset to zero if the file + * body should not be written to the archive. Pay attention! + */ +struct archive_entry_linkresolver; + +/* + * There are three different strategies for marking hardlinks. + * The descriptions below name them after the best-known + * formats that rely on each strategy: + * + * "Old cpio" is the simplest, it always returns any entry unmodified. + * As far as I know, only cpio formats use this. Old cpio archives + * store every link with the full body; the onus is on the dearchiver + * to detect and properly link the files as they are restored. + * "tar" is also pretty simple; it caches a copy the first time it sees + * any link. Subsequent appearances are modified to be hardlink + * references to the first one without any body. Used by all tar + * formats, although the newest tar formats permit the "old cpio" strategy + * as well. This strategy is very simple for the dearchiver, + * and reasonably straightforward for the archiver. + * "new cpio" is trickier. It stores the body only with the last + * occurrence. The complication is that we might not + * see every link to a particular file in a single session, so + * there's no easy way to know when we've seen the last occurrence. + * The solution here is to queue one link until we see the next. + * At the end of the session, you can enumerate any remaining + * entries by calling archive_entry_linkify(NULL) and store those + * bodies. If you have a file with three links l1, l2, and l3, + * you'll get the following behavior if you see all three links: + * linkify(l1) => NULL (the resolver stores l1 internally) + * linkify(l2) => l1 (resolver stores l2, you write l1) + * linkify(l3) => l2, l3 (all links seen, you can write both). + * If you only see l1 and l2, you'll get this behavior: + * linkify(l1) => NULL + * linkify(l2) => l1 + * linkify(NULL) => l2 (at end, you retrieve remaining links) + * As the name suggests, this strategy is used by newer cpio variants. + * It's noticeably more complex for the archiver, slightly more complex + * for the dearchiver than the tar strategy, but makes it straightforward + * to restore a file using any link by simply continuing to scan until + * you see a link that is stored with a body. In contrast, the tar + * strategy requires you to rescan the archive from the beginning to + * correctly extract an arbitrary link. + */ + +__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); +__LA_DECL void archive_entry_linkresolver_set_strategy( + struct archive_entry_linkresolver *, int /* format_code */); +__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); +__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *, + struct archive_entry **, struct archive_entry **); +__LA_DECL struct archive_entry *archive_entry_partial_links( + struct archive_entry_linkresolver *res, unsigned int *links); + +#ifdef __cplusplus +} +#endif + +/* This is meaningless outside of this header. */ +#undef __LA_DECL + +#endif /* !ARCHIVE_ENTRY_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c b/src/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c new file mode 100644 index 00000000..77bf38e4 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_copy_bhfi.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive_private.h" +#include "archive_entry.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) + +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) + +__inline static void +fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ + } else { + *t = 0; + *ns = 0; + } +} + +void +archive_entry_copy_bhfi(struct archive_entry *entry, + BY_HANDLE_FILE_INFORMATION *bhfi) +{ + time_t secs; + long nsecs; + + fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); + archive_entry_set_atime(entry, secs, nsecs); + fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); + archive_entry_set_mtime(entry, secs, nsecs); + fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); + archive_entry_set_birthtime(entry, secs, nsecs); + archive_entry_set_ctime(entry, secs, nsecs); + archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber); + archive_entry_set_ino64(entry, (((int64_t)bhfi->nFileIndexHigh) << 32) + + bhfi->nFileIndexLow); + archive_entry_set_nlink(entry, bhfi->nNumberOfLinks); + archive_entry_set_size(entry, (((int64_t)bhfi->nFileSizeHigh) << 32) + + bhfi->nFileSizeLow); + /* archive_entry_set_mode(entry, st->st_mode); */ +} +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c b/src/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c new file mode 100644 index 00000000..ac83868e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_copy_stat.c 189466 2009-03-07 00:52:02Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" + +void +archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st) +{ +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec); + archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec); + archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec); +#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec); + archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec); + archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec); +#elif HAVE_STRUCT_STAT_ST_MTIME_NSEC + archive_entry_set_atime(entry, st->st_atime, st->st_atime_nsec); + archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_nsec); + archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_nsec); +#elif HAVE_STRUCT_STAT_ST_MTIME_N + archive_entry_set_atime(entry, st->st_atime, st->st_atime_n); + archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n); + archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n); +#elif HAVE_STRUCT_STAT_ST_UMTIME + archive_entry_set_atime(entry, st->st_atime, st->st_uatime * 1000); + archive_entry_set_ctime(entry, st->st_ctime, st->st_uctime * 1000); + archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime * 1000); +#elif HAVE_STRUCT_STAT_ST_MTIME_USEC + archive_entry_set_atime(entry, st->st_atime, st->st_atime_usec * 1000); + archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_usec * 1000); + archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec * 1000); +#else + archive_entry_set_atime(entry, st->st_atime, 0); + archive_entry_set_ctime(entry, st->st_ctime, 0); + archive_entry_set_mtime(entry, st->st_mtime, 0); +#endif +#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC + archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec); +#elif HAVE_STRUCT_STAT_ST_BIRTHTIME + archive_entry_set_birthtime(entry, st->st_birthtime, 0); +#else + archive_entry_unset_birthtime(entry); +#endif + archive_entry_set_dev(entry, st->st_dev); + archive_entry_set_gid(entry, st->st_gid); + archive_entry_set_uid(entry, st->st_uid); + archive_entry_set_ino(entry, st->st_ino); + archive_entry_set_nlink(entry, st->st_nlink); + archive_entry_set_rdev(entry, st->st_rdev); + archive_entry_set_size(entry, st->st_size); + archive_entry_set_mode(entry, st->st_mode); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c b/src/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c new file mode 100644 index 00000000..c7d59497 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_link_resolver.c @@ -0,0 +1,447 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_link_resolver.c 201100 2009-12-28 03:05:31Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" + +/* + * This is mostly a pretty straightforward hash table implementation. + * The only interesting bit is the different strategies used to + * match up links. These strategies match those used by various + * archiving formats: + * tar - content stored with first link, remainder refer back to it. + * This requires us to match each subsequent link up with the + * first appearance. + * cpio - Old cpio just stored body with each link, match-ups were + * implicit. This is trivial. + * new cpio - New cpio only stores body with last link, match-ups + * are implicit. This is actually quite tricky; see the notes + * below. + */ + +/* Users pass us a format code, we translate that into a strategy here. */ +#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE 1 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 2 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 3 + +/* Initial size of link cache. */ +#define links_cache_initial_size 1024 + +struct links_entry { + struct links_entry *next; + struct links_entry *previous; + struct archive_entry *canonical; + struct archive_entry *entry; + size_t hash; + unsigned int links; /* # links not yet seen */ +}; + +struct archive_entry_linkresolver { + struct links_entry **buckets; + struct links_entry *spare; + unsigned long number_entries; + size_t number_buckets; + int strategy; +}; + +#define NEXT_ENTRY_DEFERRED 1 +#define NEXT_ENTRY_PARTIAL 2 +#define NEXT_ENTRY_ALL (NEXT_ENTRY_DEFERRED | NEXT_ENTRY_PARTIAL) + +static struct links_entry *find_entry(struct archive_entry_linkresolver *, + struct archive_entry *); +static void grow_hash(struct archive_entry_linkresolver *); +static struct links_entry *insert_entry(struct archive_entry_linkresolver *, + struct archive_entry *); +static struct links_entry *next_entry(struct archive_entry_linkresolver *, + int); + +struct archive_entry_linkresolver * +archive_entry_linkresolver_new(void) +{ + struct archive_entry_linkresolver *res; + + /* Check for positive power-of-two */ + if (links_cache_initial_size == 0 || + (links_cache_initial_size & (links_cache_initial_size - 1)) != 0) + return (NULL); + + res = calloc(1, sizeof(struct archive_entry_linkresolver)); + if (res == NULL) + return (NULL); + res->number_buckets = links_cache_initial_size; + res->buckets = calloc(res->number_buckets, sizeof(res->buckets[0])); + if (res->buckets == NULL) { + free(res); + return (NULL); + } + return (res); +} + +void +archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res, + int fmt) +{ + int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK; + + switch (fmtbase) { + case ARCHIVE_FORMAT_7ZIP: + case ARCHIVE_FORMAT_AR: + case ARCHIVE_FORMAT_ZIP: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; + break; + case ARCHIVE_FORMAT_CPIO: + switch (fmt) { + case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC: + case ARCHIVE_FORMAT_CPIO_SVR4_CRC: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO; + break; + default: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; + break; + } + break; + case ARCHIVE_FORMAT_MTREE: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE; + break; + case ARCHIVE_FORMAT_ISO9660: + case ARCHIVE_FORMAT_SHAR: + case ARCHIVE_FORMAT_TAR: + case ARCHIVE_FORMAT_XAR: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; + break; + default: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; + break; + } +} + +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); + free(res->buckets); + free(res); +} + +void +archive_entry_linkify(struct archive_entry_linkresolver *res, + struct archive_entry **e, struct archive_entry **f) +{ + struct links_entry *le; + struct archive_entry *t; + + *f = NULL; /* Default: Don't return a second entry. */ + + if (*e == NULL) { + le = next_entry(res, NEXT_ENTRY_DEFERRED); + if (le != NULL) { + *e = le->entry; + le->entry = NULL; + } + return; + } + + /* If it has only one link, then we're done. */ + if (archive_entry_nlink(*e) == 1) + return; + /* Directories, devices never have hardlinks. */ + if (archive_entry_filetype(*e) == AE_IFDIR + || archive_entry_filetype(*e) == AE_IFBLK + || archive_entry_filetype(*e) == AE_IFCHR) + return; + + switch (res->strategy) { + case ARCHIVE_ENTRY_LINKIFY_LIKE_TAR: + le = find_entry(res, *e); + if (le != NULL) { + archive_entry_unset_size(*e); + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); + } else + insert_entry(res, *e); + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE: + le = find_entry(res, *e); + if (le != NULL) { + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); + } else + insert_entry(res, *e); + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO: + /* This one is trivial. */ + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO: + le = find_entry(res, *e); + if (le != NULL) { + /* + * Put the new entry in le, return the + * old entry from le. + */ + t = *e; + *e = le->entry; + le->entry = t; + /* Make the old entry into a hardlink. */ + archive_entry_unset_size(*e); + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); + /* If we ran out of links, return the + * final entry as well. */ + if (le->links == 0) { + *f = le->entry; + le->entry = NULL; + } + } else { + /* + * If we haven't seen it, tuck it away + * for future use. + */ + le = insert_entry(res, *e); + if (le == NULL) + /* XXX We should return an error code XXX */ + return; + le->entry = *e; + *e = NULL; + } + return; + default: + break; + } + return; +} + +static struct links_entry * +find_entry(struct archive_entry_linkresolver *res, + struct archive_entry *entry) +{ + struct links_entry *le; + size_t hash, bucket; + dev_t dev; + int64_t ino; + + /* Free a held entry. */ + if (res->spare != NULL) { + archive_entry_free(res->spare->canonical); + archive_entry_free(res->spare->entry); + free(res->spare); + res->spare = NULL; + } + + dev = archive_entry_dev(entry); + ino = archive_entry_ino64(entry); + hash = (size_t)(dev ^ ino); + + /* Try to locate this entry in the links cache. */ + bucket = hash & (res->number_buckets - 1); + for (le = res->buckets[bucket]; le != NULL; le = le->next) { + if (le->hash == hash + && dev == archive_entry_dev(le->canonical) + && ino == archive_entry_ino64(le->canonical)) { + /* + * Decrement link count each time and release + * the entry if it hits zero. This saves + * memory and is necessary for detecting + * missed links. + */ + --le->links; + if (le->links > 0) + return (le); + /* Remove it from this hash bucket. */ + if (le->previous != NULL) + le->previous->next = le->next; + if (le->next != NULL) + le->next->previous = le->previous; + if (res->buckets[bucket] == le) + res->buckets[bucket] = le->next; + res->number_entries--; + /* Defer freeing this entry. */ + res->spare = le; + return (le); + } + } + return (NULL); +} + +static struct links_entry * +next_entry(struct archive_entry_linkresolver *res, int mode) +{ + struct links_entry *le; + size_t bucket; + + /* Free a held entry. */ + if (res->spare != NULL) { + archive_entry_free(res->spare->canonical); + archive_entry_free(res->spare->entry); + free(res->spare); + res->spare = NULL; + } + + /* Look for next non-empty bucket in the links cache. */ + for (bucket = 0; bucket < res->number_buckets; bucket++) { + for (le = res->buckets[bucket]; le != NULL; le = le->next) { + if (le->entry != NULL && + (mode & NEXT_ENTRY_DEFERRED) == 0) + continue; + if (le->entry == NULL && + (mode & NEXT_ENTRY_PARTIAL) == 0) + continue; + /* Remove it from this hash bucket. */ + if (le->next != NULL) + le->next->previous = le->previous; + if (le->previous != NULL) + le->previous->next = le->next; + else + res->buckets[bucket] = le->next; + res->number_entries--; + /* Defer freeing this entry. */ + res->spare = le; + return (le); + } + } + return (NULL); +} + +static struct links_entry * +insert_entry(struct archive_entry_linkresolver *res, + struct archive_entry *entry) +{ + struct links_entry *le; + size_t hash, bucket; + + /* Add this entry to the links cache. */ + le = calloc(1, sizeof(struct links_entry)); + if (le == NULL) + return (NULL); + le->canonical = archive_entry_clone(entry); + + /* If the links cache is getting too full, enlarge the hash table. */ + if (res->number_entries > res->number_buckets * 2) + grow_hash(res); + + hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry)); + bucket = hash & (res->number_buckets - 1); + + /* If we could allocate the entry, record it. */ + if (res->buckets[bucket] != NULL) + res->buckets[bucket]->previous = le; + res->number_entries++; + le->next = res->buckets[bucket]; + le->previous = NULL; + res->buckets[bucket] = le; + le->hash = hash; + le->links = archive_entry_nlink(entry) - 1; + return (le); +} + +static void +grow_hash(struct archive_entry_linkresolver *res) +{ + struct links_entry *le, **new_buckets; + size_t new_size; + size_t i, bucket; + + /* Try to enlarge the bucket list. */ + new_size = res->number_buckets * 2; + if (new_size < res->number_buckets) + return; + new_buckets = calloc(new_size, sizeof(struct links_entry *)); + + if (new_buckets == NULL) + return; + + for (i = 0; i < res->number_buckets; i++) { + while (res->buckets[i] != NULL) { + /* Remove entry from old bucket. */ + le = res->buckets[i]; + res->buckets[i] = le->next; + + /* Add entry to new bucket. */ + bucket = le->hash & (new_size - 1); + + if (new_buckets[bucket] != NULL) + new_buckets[bucket]->previous = le; + le->next = new_buckets[bucket]; + le->previous = NULL; + new_buckets[bucket] = le; + } + } + free(res->buckets); + res->buckets = new_buckets; + res->number_buckets = new_size; +} + +struct archive_entry * +archive_entry_partial_links(struct archive_entry_linkresolver *res, + unsigned int *links) +{ + struct archive_entry *e; + struct links_entry *le; + + /* Free a held entry. */ + if (res->spare != NULL) { + archive_entry_free(res->spare->canonical); + archive_entry_free(res->spare->entry); + free(res->spare); + res->spare = NULL; + } + + le = next_entry(res, NEXT_ENTRY_PARTIAL); + if (le != NULL) { + e = le->canonical; + if (links != NULL) + *links = le->links; + le->canonical = NULL; + } else { + e = NULL; + if (links != NULL) + *links = 0; + } + return (e); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_locale.h b/src/3rdparty/libarchive/libarchive/archive_entry_locale.h new file mode 100644 index 00000000..44550c51 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_locale.h @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2011 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED +#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED + +struct archive_entry; +struct archive_string_conv; + +/* + * Utility functions to set and get entry attributes by translating + * character-set. These are designed for use in format readers and writers. + * + * The return code and interface of these are quite different from other + * functions for archive_entry defined in archive_entry.h. + * Common return code are: + * Return 0 if the string conversion succeeded. + * Return -1 if the string conversion failed. + */ + +#define archive_entry_gname_l _archive_entry_gname_l +int _archive_entry_gname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_hardlink_l _archive_entry_hardlink_l +int _archive_entry_hardlink_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_pathname_l _archive_entry_pathname_l +int _archive_entry_pathname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_symlink_l _archive_entry_symlink_l +int _archive_entry_symlink_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_uname_l _archive_entry_uname_l +int _archive_entry_uname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_acl_text_l _archive_entry_acl_text_l +int _archive_entry_acl_text_l(struct archive_entry *, int, +const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED; +#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l +char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int, + struct archive_string_conv *); +#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l +int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text, + int type, struct archive_string_conv *); +#define archive_entry_copy_gname_l _archive_entry_copy_gname_l +int _archive_entry_copy_gname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l +int _archive_entry_copy_hardlink_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_link_l _archive_entry_copy_link_l +int _archive_entry_copy_link_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l +int _archive_entry_copy_pathname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l +int _archive_entry_copy_symlink_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_uname_l _archive_entry_copy_uname_l +int _archive_entry_copy_uname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); + +#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_private.h b/src/3rdparty/libarchive/libarchive/archive_entry_private.h new file mode 100644 index 00000000..c69233e6 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_private.h @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_entry_private.h 201096 2009-12-28 02:41:27Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED +#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED + +#include "archive_acl_private.h" +#include "archive_string.h" + +struct ae_xattr { + struct ae_xattr *next; + + char *name; + void *value; + size_t size; +}; + +struct ae_sparse { + struct ae_sparse *next; + + int64_t offset; + int64_t length; +}; + +/* + * Description of an archive entry. + * + * Basically, this is a "struct stat" with a few text fields added in. + * + * TODO: Add "comment", "charset", and possibly other entries + * that are supported by "pax interchange" format. However, GNU, ustar, + * cpio, and other variants don't support these features, so they're not an + * excruciatingly high priority right now. + * + * TODO: "pax interchange" format allows essentially arbitrary + * key/value attributes to be attached to any entry. Supporting + * such extensions may make this library useful for special + * applications (e.g., a package manager could attach special + * package-management attributes to each entry). There are tricky + * API issues involved, so this is not going to happen until + * there's a real demand for it. + * + * TODO: Design a good API for handling sparse files. + */ +struct archive_entry { + struct archive *archive; + + /* + * Note that ae_stat.st_mode & AE_IFMT can be 0! + * + * This occurs when the actual file type of the object is not + * in the archive. For example, 'tar' archives store + * hardlinks without marking the type of the underlying + * object. + */ + + /* + * We have a "struct aest" for holding file metadata rather than just + * a "struct stat" because on some platforms the "struct stat" has + * fields which are too narrow to hold the range of possible values; + * we don't want to lose information if we read an archive and write + * out another (e.g., in "tar -cf new.tar @old.tar"). + * + * The "stat" pointer points to some form of platform-specific struct + * stat; it is declared as a void * rather than a struct stat * as + * some platforms have multiple varieties of stat structures. + */ + void *stat; + int stat_valid; /* Set to 0 whenever a field in aest changes. */ + + struct aest { + int64_t aest_atime; + uint32_t aest_atime_nsec; + int64_t aest_ctime; + uint32_t aest_ctime_nsec; + int64_t aest_mtime; + uint32_t aest_mtime_nsec; + int64_t aest_birthtime; + uint32_t aest_birthtime_nsec; + int64_t aest_gid; + int64_t aest_ino; + uint32_t aest_nlink; + uint64_t aest_size; + int64_t aest_uid; + /* + * Because converting between device codes and + * major/minor values is platform-specific and + * inherently a bit risky, we only do that conversion + * lazily. That way, we will do a better job of + * preserving information in those cases where no + * conversion is actually required. + */ + int aest_dev_is_broken_down; + dev_t aest_dev; + dev_t aest_devmajor; + dev_t aest_devminor; + int aest_rdev_is_broken_down; + dev_t aest_rdev; + dev_t aest_rdevmajor; + dev_t aest_rdevminor; + } ae_stat; + + int ae_set; /* bitmap of fields that are currently set */ +#define AE_SET_HARDLINK 1 +#define AE_SET_SYMLINK 2 +#define AE_SET_ATIME 4 +#define AE_SET_CTIME 8 +#define AE_SET_MTIME 16 +#define AE_SET_BIRTHTIME 32 +#define AE_SET_SIZE 64 +#define AE_SET_INO 128 +#define AE_SET_DEV 256 + + /* + * Use aes here so that we get transparent mbs<->wcs conversions. + */ + struct archive_mstring ae_fflags_text; /* Text fflags per fflagstostr(3) */ + unsigned long ae_fflags_set; /* Bitmap fflags */ + unsigned long ae_fflags_clear; + struct archive_mstring ae_gname; /* Name of owning group */ + struct archive_mstring ae_hardlink; /* Name of target for hardlink */ + struct archive_mstring ae_pathname; /* Name of entry */ + struct archive_mstring ae_symlink; /* symlink contents */ + struct archive_mstring ae_uname; /* Name of owner */ + + /* Not used within libarchive; useful for some clients. */ + struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */ + +#define AE_ENCRYPTION_NONE 0 +#define AE_ENCRYPTION_DATA 1 +#define AE_ENCRYPTION_METADATA 2 + char encryption; + + void *mac_metadata; + size_t mac_metadata_size; + + /* ACL support. */ + struct archive_acl acl; + + /* extattr support. */ + struct ae_xattr *xattr_head; + struct ae_xattr *xattr_p; + + /* sparse support. */ + struct ae_sparse *sparse_head; + struct ae_sparse *sparse_tail; + struct ae_sparse *sparse_p; + + /* Miscellaneous. */ + char strmode[12]; +}; + +#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_sparse.c b/src/3rdparty/libarchive/libarchive/archive_entry_sparse.c new file mode 100644 index 00000000..74917b37 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_sparse.c @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2010-2011 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_entry_private.h" + +/* + * sparse handling + */ + +void +archive_entry_sparse_clear(struct archive_entry *entry) +{ + struct ae_sparse *sp; + + while (entry->sparse_head != NULL) { + sp = entry->sparse_head->next; + free(entry->sparse_head); + entry->sparse_head = sp; + } + entry->sparse_tail = NULL; +} + +void +archive_entry_sparse_add_entry(struct archive_entry *entry, + la_int64_t offset, la_int64_t length) +{ + struct ae_sparse *sp; + + if (offset < 0 || length < 0) + /* Invalid value */ + return; + if (offset > INT64_MAX - length || + offset + length > archive_entry_size(entry)) + /* A value of "length" parameter is too large. */ + return; + if ((sp = entry->sparse_tail) != NULL) { + if (sp->offset + sp->length > offset) + /* Invalid value. */ + return; + if (sp->offset + sp->length == offset) { + if (sp->offset + sp->length + length < 0) + /* A value of "length" parameter is + * too large. */ + return; + /* Expand existing sparse block size. */ + sp->length += length; + return; + } + } + + if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL) + /* XXX Error XXX */ + return; + + sp->offset = offset; + sp->length = length; + sp->next = NULL; + + if (entry->sparse_head == NULL) + entry->sparse_head = entry->sparse_tail = sp; + else { + /* Add a new sparse block to the tail of list. */ + if (entry->sparse_tail != NULL) + entry->sparse_tail->next = sp; + entry->sparse_tail = sp; + } +} + + +/* + * returns number of the sparse entries + */ +int +archive_entry_sparse_count(struct archive_entry *entry) +{ + struct ae_sparse *sp; + int count = 0; + + for (sp = entry->sparse_head; sp != NULL; sp = sp->next) + count++; + + /* + * Sanity check if this entry is exactly sparse. + * If amount of sparse blocks is just one and it indicates the whole + * file data, we should remove it and return zero. + */ + if (count == 1) { + sp = entry->sparse_head; + if (sp->offset == 0 && + sp->length >= archive_entry_size(entry)) { + count = 0; + archive_entry_sparse_clear(entry); + } + } + + return (count); +} + +int +archive_entry_sparse_reset(struct archive_entry * entry) +{ + entry->sparse_p = entry->sparse_head; + + return archive_entry_sparse_count(entry); +} + +int +archive_entry_sparse_next(struct archive_entry * entry, + la_int64_t *offset, la_int64_t *length) +{ + if (entry->sparse_p) { + *offset = entry->sparse_p->offset; + *length = entry->sparse_p->length; + + entry->sparse_p = entry->sparse_p->next; + + return (ARCHIVE_OK); + } else { + *offset = 0; + *length = 0; + return (ARCHIVE_WARN); + } +} + +/* + * end of sparse handling + */ diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_stat.c b/src/3rdparty/libarchive/libarchive/archive_entry_stat.c new file mode 100644 index 00000000..71a407b1 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_stat.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_stat.c 201100 2009-12-28 03:05:31Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "archive_entry.h" +#include "archive_entry_private.h" + +const struct stat * +archive_entry_stat(struct archive_entry *entry) +{ + struct stat *st; + if (entry->stat == NULL) { + entry->stat = calloc(1, sizeof(*st)); + if (entry->stat == NULL) + return (NULL); + entry->stat_valid = 0; + } + + /* + * If none of the underlying fields have been changed, we + * don't need to regenerate. In theory, we could use a bitmap + * here to flag only those items that have changed, but the + * extra complexity probably isn't worth it. It will be very + * rare for anyone to change just one field then request a new + * stat structure. + */ + if (entry->stat_valid) + return (entry->stat); + + st = entry->stat; + /* + * Use the public interfaces to extract items, so that + * the appropriate conversions get invoked. + */ + st->st_atime = archive_entry_atime(entry); +#if HAVE_STRUCT_STAT_ST_BIRTHTIME + st->st_birthtime = archive_entry_birthtime(entry); +#endif + st->st_ctime = archive_entry_ctime(entry); + st->st_mtime = archive_entry_mtime(entry); + st->st_dev = archive_entry_dev(entry); + st->st_gid = (gid_t)archive_entry_gid(entry); + st->st_uid = (uid_t)archive_entry_uid(entry); + st->st_ino = (ino_t)archive_entry_ino64(entry); + st->st_nlink = archive_entry_nlink(entry); + st->st_rdev = archive_entry_rdev(entry); + st->st_size = (off_t)archive_entry_size(entry); + st->st_mode = archive_entry_mode(entry); + + /* + * On systems that support high-res timestamps, copy that + * information into struct stat. + */ +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry); + st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry); + st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry); +#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + st->st_atim.tv_nsec = archive_entry_atime_nsec(entry); + st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry); + st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry); +#elif HAVE_STRUCT_STAT_ST_MTIME_N + st->st_atime_n = archive_entry_atime_nsec(entry); + st->st_ctime_n = archive_entry_ctime_nsec(entry); + st->st_mtime_n = archive_entry_mtime_nsec(entry); +#elif HAVE_STRUCT_STAT_ST_UMTIME + st->st_uatime = archive_entry_atime_nsec(entry) / 1000; + st->st_uctime = archive_entry_ctime_nsec(entry) / 1000; + st->st_umtime = archive_entry_mtime_nsec(entry) / 1000; +#elif HAVE_STRUCT_STAT_ST_MTIME_USEC + st->st_atime_usec = archive_entry_atime_nsec(entry) / 1000; + st->st_ctime_usec = archive_entry_ctime_nsec(entry) / 1000; + st->st_mtime_usec = archive_entry_mtime_nsec(entry) / 1000; +#endif +#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC + st->st_birthtimespec.tv_nsec = archive_entry_birthtime_nsec(entry); +#endif + + /* + * TODO: On Linux, store 32 or 64 here depending on whether + * the cached stat structure is a stat32 or a stat64. This + * will allow us to support both variants interchangeably. + */ + entry->stat_valid = 1; + + return (st); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_strmode.c b/src/3rdparty/libarchive/libarchive/archive_entry_strmode.c new file mode 100644 index 00000000..af2517a3 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_strmode.c @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.4 2008/06/15 05:14:01 kientzle Exp $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive_entry.h" +#include "archive_entry_private.h" + +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; + 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; + case AE_IFCHR: bp[0] = 'c'; break; + case AE_IFDIR: bp[0] = 'd'; break; + case AE_IFLNK: bp[0] = 'l'; break; + 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; + } + } + + for (i = 0; i < 9; i++) + if (!(mode & permbits[i])) + bp[i+1] = '-'; + + 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] = '+'; + + return (bp); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_entry_xattr.c b/src/3rdparty/libarchive/libarchive/archive_entry_xattr.c new file mode 100644 index 00000000..5fe726b9 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_entry_xattr.c @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_xattr.c 201096 2009-12-28 02:41:27Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include /* for Linux file flags */ +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include /* for Linux file flags */ +#endif +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_entry_private.h" + +/* + * extended attribute handling + */ + +void +archive_entry_xattr_clear(struct archive_entry *entry) +{ + struct ae_xattr *xp; + + while (entry->xattr_head != NULL) { + xp = entry->xattr_head->next; + free(entry->xattr_head->name); + free(entry->xattr_head->value); + free(entry->xattr_head); + entry->xattr_head = xp; + } + + entry->xattr_head = NULL; +} + +void +archive_entry_xattr_add_entry(struct archive_entry *entry, + const char *name, const void *value, size_t size) +{ + struct ae_xattr *xp; + + if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL) + __archive_errx(1, "Out of memory"); + + 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; + + xp->next = entry->xattr_head; + entry->xattr_head = xp; +} + + +/* + * returns number of the extended attribute entries + */ +int +archive_entry_xattr_count(struct archive_entry *entry) +{ + struct ae_xattr *xp; + int count = 0; + + for (xp = entry->xattr_head; xp != NULL; xp = xp->next) + count++; + + return count; +} + +int +archive_entry_xattr_reset(struct archive_entry * entry) +{ + entry->xattr_p = entry->xattr_head; + + return archive_entry_xattr_count(entry); +} + +int +archive_entry_xattr_next(struct archive_entry * entry, + const char **name, const void **value, size_t *size) +{ + if (entry->xattr_p) { + *name = entry->xattr_p->name; + *value = entry->xattr_p->value; + *size = entry->xattr_p->size; + + entry->xattr_p = entry->xattr_p->next; + + return (ARCHIVE_OK); + } else { + *name = NULL; + *value = NULL; + *size = (size_t)0; + return (ARCHIVE_WARN); + } +} + +/* + * end of xattr handling + */ diff --git a/src/3rdparty/libarchive/libarchive/archive_getdate.c b/src/3rdparty/libarchive/libarchive/archive_getdate.c new file mode 100644 index 00000000..030c083c --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_getdate.c @@ -0,0 +1,1038 @@ +/* + * This code is in the public domain and has no copyright. + * + * This is a plain C recursive-descent translation of an old + * public-domain YACC grammar that has been used for parsing dates in + * very many open-source projects. + * + * Since the original authors were generous enough to donate their + * work to the public domain, I feel compelled to match their + * generosity. + * + * Tim Kientzle, February 2009. + */ + +/* + * Header comment from original getdate.y: + */ + +/* +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990; +** +** This grammar has 10 shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ + +#ifdef __FreeBSD__ +#include +__FBSDID("$FreeBSD$"); +#endif + +#include +#include +#include +#include +#include + +#define __LIBARCHIVE_BUILD 1 +#include "archive_getdate.h" + +/* Basic time units. */ +#define EPOCH 1970 +#define MINUTE (60L) +#define HOUR (60L * MINUTE) +#define DAY (24L * HOUR) + +/* Daylight-savings mode: on, off, or not yet known. */ +enum DSTMODE { DSTon, DSToff, DSTmaybe }; +/* Meridian: am or pm. */ +enum { tAM, tPM }; +/* Token types returned by nexttoken() */ +enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT, + tUNUMBER, tZONE, tDST }; +struct token { int token; time_t value; }; + +/* + * Parser state. + */ +struct gdstate { + struct token *tokenp; /* Pointer to next token. */ + /* HaveXxxx counts how many of this kind of phrase we've seen; + * it's a fatal error to have more than one time, zone, day, + * or date phrase. */ + int HaveYear; + int HaveMonth; + int HaveDay; + int HaveWeekDay; /* Day of week */ + int HaveTime; /* Hour/minute/second */ + int HaveZone; /* timezone and/or DST info */ + int HaveRel; /* time offset; we can have more than one */ + /* Absolute time values. */ + time_t Timezone; /* Seconds offset from GMT */ + time_t Day; + time_t Hour; + time_t Minutes; + time_t Month; + time_t Seconds; + time_t Year; + /* DST selection */ + enum DSTMODE DSTmode; + /* Day of week accounting, e.g., "3rd Tuesday" */ + time_t DayOrdinal; /* "3" in "3rd Tuesday" */ + time_t DayNumber; /* "Tuesday" in "3rd Tuesday" */ + /* Relative time values: hour/day/week offsets are measured in + * seconds, month/year are counted in months. */ + time_t RelMonth; + time_t RelSeconds; +}; + +/* + * A series of functions that recognize certain common time phrases. + * Each function returns 1 if it managed to make sense of some of the + * tokens, zero otherwise. + */ + +/* + * hour:minute or hour:minute:second with optional AM, PM, or numeric + * timezone offset + */ +static int +timephrase(struct gdstate *gds) +{ + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == ':' + && gds->tokenp[2].token == tUNUMBER + && gds->tokenp[3].token == ':' + && gds->tokenp[4].token == tUNUMBER) { + /* "12:14:18" or "22:08:07" */ + ++gds->HaveTime; + gds->Hour = gds->tokenp[0].value; + gds->Minutes = gds->tokenp[2].value; + gds->Seconds = gds->tokenp[4].value; + gds->tokenp += 5; + } + else if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == ':' + && gds->tokenp[2].token == tUNUMBER) { + /* "12:14" or "22:08" */ + ++gds->HaveTime; + gds->Hour = gds->tokenp[0].value; + gds->Minutes = gds->tokenp[2].value; + gds->Seconds = 0; + gds->tokenp += 3; + } + else if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tAMPM) { + /* "7" is a time if it's followed by "am" or "pm" */ + ++gds->HaveTime; + gds->Hour = gds->tokenp[0].value; + gds->Minutes = gds->Seconds = 0; + /* We'll handle the AM/PM below. */ + gds->tokenp += 1; + } else { + /* We can't handle this. */ + return 0; + } + + if (gds->tokenp[0].token == tAMPM) { + /* "7:12pm", "12:20:13am" */ + if (gds->Hour == 12) + gds->Hour = 0; + if (gds->tokenp[0].value == tPM) + gds->Hour += 12; + gds->tokenp += 1; + } + if (gds->tokenp[0].token == '+' + && gds->tokenp[1].token == tUNUMBER) { + /* "7:14+0700" */ + gds->HaveZone++; + gds->DSTmode = DSToff; + gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR + + (gds->tokenp[1].value % 100) * MINUTE); + gds->tokenp += 2; + } + if (gds->tokenp[0].token == '-' + && gds->tokenp[1].token == tUNUMBER) { + /* "19:14:12-0530" */ + gds->HaveZone++; + gds->DSTmode = DSToff; + gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR + + (gds->tokenp[1].value % 100) * MINUTE); + gds->tokenp += 2; + } + return 1; +} + +/* + * Timezone name, possibly including DST. + */ +static int +zonephrase(struct gdstate *gds) +{ + if (gds->tokenp[0].token == tZONE + && gds->tokenp[1].token == tDST) { + gds->HaveZone++; + gds->Timezone = gds->tokenp[0].value; + gds->DSTmode = DSTon; + gds->tokenp += 1; + return 1; + } + + if (gds->tokenp[0].token == tZONE) { + gds->HaveZone++; + gds->Timezone = gds->tokenp[0].value; + gds->DSTmode = DSToff; + gds->tokenp += 1; + return 1; + } + + if (gds->tokenp[0].token == tDAYZONE) { + gds->HaveZone++; + gds->Timezone = gds->tokenp[0].value; + gds->DSTmode = DSTon; + gds->tokenp += 1; + return 1; + } + return 0; +} + +/* + * Year/month/day in various combinations. + */ +static int +datephrase(struct gdstate *gds) +{ + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == '/' + && gds->tokenp[2].token == tUNUMBER + && gds->tokenp[3].token == '/' + && gds->tokenp[4].token == tUNUMBER) { + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + if (gds->tokenp[0].value >= 13) { + /* First number is big: 2004/01/29, 99/02/17 */ + gds->Year = gds->tokenp[0].value; + gds->Month = gds->tokenp[2].value; + gds->Day = gds->tokenp[4].value; + } else if ((gds->tokenp[4].value >= 13) + || (gds->tokenp[2].value >= 13)) { + /* Last number is big: 01/07/98 */ + /* Middle number is big: 01/29/04 */ + gds->Month = gds->tokenp[0].value; + gds->Day = gds->tokenp[2].value; + gds->Year = gds->tokenp[4].value; + } else { + /* No significant clues: 02/03/04 */ + gds->Month = gds->tokenp[0].value; + gds->Day = gds->tokenp[2].value; + gds->Year = gds->tokenp[4].value; + } + gds->tokenp += 5; + return 1; + } + + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == '/' + && gds->tokenp[2].token == tUNUMBER) { + /* "1/15" */ + gds->HaveMonth++; + gds->HaveDay++; + gds->Month = gds->tokenp[0].value; + gds->Day = gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == '-' + && gds->tokenp[2].token == tUNUMBER + && gds->tokenp[3].token == '-' + && gds->tokenp[4].token == tUNUMBER) { + /* ISO 8601 format. yyyy-mm-dd. */ + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + gds->Year = gds->tokenp[0].value; + gds->Month = gds->tokenp[2].value; + gds->Day = gds->tokenp[4].value; + gds->tokenp += 5; + return 1; + } + + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == '-' + && gds->tokenp[2].token == tMONTH + && gds->tokenp[3].token == '-' + && gds->tokenp[4].token == tUNUMBER) { + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + if (gds->tokenp[0].value > 31) { + /* e.g. 1992-Jun-17 */ + gds->Year = gds->tokenp[0].value; + gds->Month = gds->tokenp[2].value; + gds->Day = gds->tokenp[4].value; + } else { + /* e.g. 17-JUN-1992. */ + gds->Day = gds->tokenp[0].value; + gds->Month = gds->tokenp[2].value; + gds->Year = gds->tokenp[4].value; + } + gds->tokenp += 5; + return 1; + } + + if (gds->tokenp[0].token == tMONTH + && gds->tokenp[1].token == tUNUMBER + && gds->tokenp[2].token == ',' + && gds->tokenp[3].token == tUNUMBER) { + /* "June 17, 2001" */ + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + gds->Month = gds->tokenp[0].value; + gds->Day = gds->tokenp[1].value; + gds->Year = gds->tokenp[3].value; + gds->tokenp += 4; + return 1; + } + + if (gds->tokenp[0].token == tMONTH + && gds->tokenp[1].token == tUNUMBER) { + /* "May 3" */ + gds->HaveMonth++; + gds->HaveDay++; + gds->Month = gds->tokenp[0].value; + gds->Day = gds->tokenp[1].value; + gds->tokenp += 2; + return 1; + } + + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tMONTH + && gds->tokenp[2].token == tUNUMBER) { + /* "12 Sept 1997" */ + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + gds->Day = gds->tokenp[0].value; + gds->Month = gds->tokenp[1].value; + gds->Year = gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tMONTH) { + /* "12 Sept" */ + gds->HaveMonth++; + gds->HaveDay++; + gds->Day = gds->tokenp[0].value; + gds->Month = gds->tokenp[1].value; + gds->tokenp += 2; + return 1; + } + + return 0; +} + +/* + * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc. + */ +static int +relunitphrase(struct gdstate *gds) +{ + if (gds->tokenp[0].token == '-' + && gds->tokenp[1].token == tUNUMBER + && gds->tokenp[2].token == tSEC_UNIT) { + /* "-3 hours" */ + gds->HaveRel++; + gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + if (gds->tokenp[0].token == '+' + && gds->tokenp[1].token == tUNUMBER + && gds->tokenp[2].token == tSEC_UNIT) { + /* "+1 minute" */ + gds->HaveRel++; + gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tSEC_UNIT) { + /* "1 day" */ + gds->HaveRel++; + gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value; + gds->tokenp += 2; + return 1; + } + if (gds->tokenp[0].token == '-' + && gds->tokenp[1].token == tUNUMBER + && gds->tokenp[2].token == tMONTH_UNIT) { + /* "-3 months" */ + gds->HaveRel++; + gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + if (gds->tokenp[0].token == '+' + && gds->tokenp[1].token == tUNUMBER + && gds->tokenp[2].token == tMONTH_UNIT) { + /* "+5 years" */ + gds->HaveRel++; + gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value; + gds->tokenp += 3; + return 1; + } + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tMONTH_UNIT) { + /* "2 years" */ + gds->HaveRel++; + gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value; + gds->tokenp += 2; + return 1; + } + if (gds->tokenp[0].token == tSEC_UNIT) { + /* "now", "tomorrow" */ + gds->HaveRel++; + gds->RelSeconds += gds->tokenp[0].value; + gds->tokenp += 1; + return 1; + } + if (gds->tokenp[0].token == tMONTH_UNIT) { + /* "month" */ + gds->HaveRel++; + gds->RelMonth += gds->tokenp[0].value; + gds->tokenp += 1; + return 1; + } + return 0; +} + +/* + * Day of the week specification. + */ +static int +dayphrase(struct gdstate *gds) +{ + if (gds->tokenp[0].token == tDAY) { + /* "tues", "wednesday," */ + gds->HaveWeekDay++; + gds->DayOrdinal = 1; + gds->DayNumber = gds->tokenp[0].value; + gds->tokenp += 1; + if (gds->tokenp[0].token == ',') + gds->tokenp += 1; + return 1; + } + if (gds->tokenp[0].token == tUNUMBER + && gds->tokenp[1].token == tDAY) { + /* "second tues" "3 wed" */ + gds->HaveWeekDay++; + gds->DayOrdinal = gds->tokenp[0].value; + gds->DayNumber = gds->tokenp[1].value; + gds->tokenp += 2; + return 1; + } + return 0; +} + +/* + * Try to match a phrase using one of the above functions. + * This layer also deals with a couple of generic issues. + */ +static int +phrase(struct gdstate *gds) +{ + if (timephrase(gds)) + return 1; + if (zonephrase(gds)) + return 1; + if (datephrase(gds)) + return 1; + if (dayphrase(gds)) + return 1; + if (relunitphrase(gds)) { + if (gds->tokenp[0].token == tAGO) { + gds->RelSeconds = -gds->RelSeconds; + gds->RelMonth = -gds->RelMonth; + gds->tokenp += 1; + } + return 1; + } + + /* Bare numbers sometimes have meaning. */ + if (gds->tokenp[0].token == tUNUMBER) { + if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) { + gds->HaveYear++; + gds->Year = gds->tokenp[0].value; + gds->tokenp += 1; + return 1; + } + + if(gds->tokenp[0].value > 10000) { + /* "20040301" */ + gds->HaveYear++; + gds->HaveMonth++; + gds->HaveDay++; + gds->Day= (gds->tokenp[0].value)%100; + gds->Month= (gds->tokenp[0].value/100)%100; + gds->Year = gds->tokenp[0].value/10000; + gds->tokenp += 1; + return 1; + } + + if (gds->tokenp[0].value < 24) { + gds->HaveTime++; + gds->Hour = gds->tokenp[0].value; + gds->Minutes = 0; + gds->Seconds = 0; + gds->tokenp += 1; + return 1; + } + + if ((gds->tokenp[0].value / 100 < 24) + && (gds->tokenp[0].value % 100 < 60)) { + /* "513" is same as "5:13" */ + gds->Hour = gds->tokenp[0].value / 100; + gds->Minutes = gds->tokenp[0].value % 100; + gds->Seconds = 0; + gds->tokenp += 1; + return 1; + } + } + + return 0; +} + +/* + * A dictionary of time words. + */ +static struct LEXICON { + size_t abbrev; + const char *name; + int type; + time_t value; +} const TimeWords[] = { + /* am/pm */ + { 0, "am", tAMPM, tAM }, + { 0, "pm", tAMPM, tPM }, + + /* Month names. */ + { 3, "january", tMONTH, 1 }, + { 3, "february", tMONTH, 2 }, + { 3, "march", tMONTH, 3 }, + { 3, "april", tMONTH, 4 }, + { 3, "may", tMONTH, 5 }, + { 3, "june", tMONTH, 6 }, + { 3, "july", tMONTH, 7 }, + { 3, "august", tMONTH, 8 }, + { 3, "september", tMONTH, 9 }, + { 3, "october", tMONTH, 10 }, + { 3, "november", tMONTH, 11 }, + { 3, "december", tMONTH, 12 }, + + /* Days of the week. */ + { 2, "sunday", tDAY, 0 }, + { 3, "monday", tDAY, 1 }, + { 2, "tuesday", tDAY, 2 }, + { 3, "wednesday", tDAY, 3 }, + { 2, "thursday", tDAY, 4 }, + { 2, "friday", tDAY, 5 }, + { 2, "saturday", tDAY, 6 }, + + /* Timezones: Offsets are in seconds. */ + { 0, "gmt", tZONE, 0*HOUR }, /* Greenwich Mean */ + { 0, "ut", tZONE, 0*HOUR }, /* Universal (Coordinated) */ + { 0, "utc", tZONE, 0*HOUR }, + { 0, "wet", tZONE, 0*HOUR }, /* Western European */ + { 0, "bst", tDAYZONE, 0*HOUR }, /* British Summer */ + { 0, "wat", tZONE, 1*HOUR }, /* West Africa */ + { 0, "at", tZONE, 2*HOUR }, /* Azores */ + /* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */ + /* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/ + { 0, "nft", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland */ + { 0, "nst", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Standard */ + { 0, "ndt", tDAYZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Daylight */ + { 0, "ast", tZONE, 4*HOUR }, /* Atlantic Standard */ + { 0, "adt", tDAYZONE, 4*HOUR }, /* Atlantic Daylight */ + { 0, "est", tZONE, 5*HOUR }, /* Eastern Standard */ + { 0, "edt", tDAYZONE, 5*HOUR }, /* Eastern Daylight */ + { 0, "cst", tZONE, 6*HOUR }, /* Central Standard */ + { 0, "cdt", tDAYZONE, 6*HOUR }, /* Central Daylight */ + { 0, "mst", tZONE, 7*HOUR }, /* Mountain Standard */ + { 0, "mdt", tDAYZONE, 7*HOUR }, /* Mountain Daylight */ + { 0, "pst", tZONE, 8*HOUR }, /* Pacific Standard */ + { 0, "pdt", tDAYZONE, 8*HOUR }, /* Pacific Daylight */ + { 0, "yst", tZONE, 9*HOUR }, /* Yukon Standard */ + { 0, "ydt", tDAYZONE, 9*HOUR }, /* Yukon Daylight */ + { 0, "hst", tZONE, 10*HOUR }, /* Hawaii Standard */ + { 0, "hdt", tDAYZONE, 10*HOUR }, /* Hawaii Daylight */ + { 0, "cat", tZONE, 10*HOUR }, /* Central Alaska */ + { 0, "ahst", tZONE, 10*HOUR }, /* Alaska-Hawaii Standard */ + { 0, "nt", tZONE, 11*HOUR }, /* Nome */ + { 0, "idlw", tZONE, 12*HOUR }, /* Intl Date Line West */ + { 0, "cet", tZONE, -1*HOUR }, /* Central European */ + { 0, "met", tZONE, -1*HOUR }, /* Middle European */ + { 0, "mewt", tZONE, -1*HOUR }, /* Middle European Winter */ + { 0, "mest", tDAYZONE, -1*HOUR }, /* Middle European Summer */ + { 0, "swt", tZONE, -1*HOUR }, /* Swedish Winter */ + { 0, "sst", tDAYZONE, -1*HOUR }, /* Swedish Summer */ + { 0, "fwt", tZONE, -1*HOUR }, /* French Winter */ + { 0, "fst", tDAYZONE, -1*HOUR }, /* French Summer */ + { 0, "eet", tZONE, -2*HOUR }, /* Eastern Eur, USSR Zone 1 */ + { 0, "bt", tZONE, -3*HOUR }, /* Baghdad, USSR Zone 2 */ + { 0, "it", tZONE, -3*HOUR-30*MINUTE },/* Iran */ + { 0, "zp4", tZONE, -4*HOUR }, /* USSR Zone 3 */ + { 0, "zp5", tZONE, -5*HOUR }, /* USSR Zone 4 */ + { 0, "ist", tZONE, -5*HOUR-30*MINUTE },/* Indian Standard */ + { 0, "zp6", tZONE, -6*HOUR }, /* USSR Zone 5 */ + /* { 0, "nst", tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */ + /* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */ + { 0, "wast", tZONE, -7*HOUR }, /* West Australian Standard */ + { 0, "wadt", tDAYZONE, -7*HOUR }, /* West Australian Daylight */ + { 0, "jt", tZONE, -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/ + { 0, "cct", tZONE, -8*HOUR }, /* China Coast, USSR Zone 7 */ + { 0, "jst", tZONE, -9*HOUR }, /* Japan Std, USSR Zone 8 */ + { 0, "cast", tZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Std */ + { 0, "cadt", tDAYZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */ + { 0, "east", tZONE, -10*HOUR }, /* Eastern Australian Std */ + { 0, "eadt", tDAYZONE, -10*HOUR }, /* Eastern Australian Daylt */ + { 0, "gst", tZONE, -10*HOUR }, /* Guam Std, USSR Zone 9 */ + { 0, "nzt", tZONE, -12*HOUR }, /* New Zealand */ + { 0, "nzst", tZONE, -12*HOUR }, /* New Zealand Standard */ + { 0, "nzdt", tDAYZONE, -12*HOUR }, /* New Zealand Daylight */ + { 0, "idle", tZONE, -12*HOUR }, /* Intl Date Line East */ + + { 0, "dst", tDST, 0 }, + + /* Time units. */ + { 4, "years", tMONTH_UNIT, 12 }, + { 5, "months", tMONTH_UNIT, 1 }, + { 9, "fortnights", tSEC_UNIT, 14 * DAY }, + { 4, "weeks", tSEC_UNIT, 7 * DAY }, + { 3, "days", tSEC_UNIT, DAY }, + { 4, "hours", tSEC_UNIT, HOUR }, + { 3, "minutes", tSEC_UNIT, MINUTE }, + { 3, "seconds", tSEC_UNIT, 1 }, + + /* Relative-time words. */ + { 0, "tomorrow", tSEC_UNIT, DAY }, + { 0, "yesterday", tSEC_UNIT, -DAY }, + { 0, "today", tSEC_UNIT, 0 }, + { 0, "now", tSEC_UNIT, 0 }, + { 0, "last", tUNUMBER, -1 }, + { 0, "this", tSEC_UNIT, 0 }, + { 0, "next", tUNUMBER, 2 }, + { 0, "first", tUNUMBER, 1 }, + { 0, "1st", tUNUMBER, 1 }, +/* { 0, "second", tUNUMBER, 2 }, */ + { 0, "2nd", tUNUMBER, 2 }, + { 0, "third", tUNUMBER, 3 }, + { 0, "3rd", tUNUMBER, 3 }, + { 0, "fourth", tUNUMBER, 4 }, + { 0, "4th", tUNUMBER, 4 }, + { 0, "fifth", tUNUMBER, 5 }, + { 0, "5th", tUNUMBER, 5 }, + { 0, "sixth", tUNUMBER, 6 }, + { 0, "seventh", tUNUMBER, 7 }, + { 0, "eighth", tUNUMBER, 8 }, + { 0, "ninth", tUNUMBER, 9 }, + { 0, "tenth", tUNUMBER, 10 }, + { 0, "eleventh", tUNUMBER, 11 }, + { 0, "twelfth", tUNUMBER, 12 }, + { 0, "ago", tAGO, 1 }, + + /* Military timezones. */ + { 0, "a", tZONE, 1*HOUR }, + { 0, "b", tZONE, 2*HOUR }, + { 0, "c", tZONE, 3*HOUR }, + { 0, "d", tZONE, 4*HOUR }, + { 0, "e", tZONE, 5*HOUR }, + { 0, "f", tZONE, 6*HOUR }, + { 0, "g", tZONE, 7*HOUR }, + { 0, "h", tZONE, 8*HOUR }, + { 0, "i", tZONE, 9*HOUR }, + { 0, "k", tZONE, 10*HOUR }, + { 0, "l", tZONE, 11*HOUR }, + { 0, "m", tZONE, 12*HOUR }, + { 0, "n", tZONE, -1*HOUR }, + { 0, "o", tZONE, -2*HOUR }, + { 0, "p", tZONE, -3*HOUR }, + { 0, "q", tZONE, -4*HOUR }, + { 0, "r", tZONE, -5*HOUR }, + { 0, "s", tZONE, -6*HOUR }, + { 0, "t", tZONE, -7*HOUR }, + { 0, "u", tZONE, -8*HOUR }, + { 0, "v", tZONE, -9*HOUR }, + { 0, "w", tZONE, -10*HOUR }, + { 0, "x", tZONE, -11*HOUR }, + { 0, "y", tZONE, -12*HOUR }, + { 0, "z", tZONE, 0*HOUR }, + + /* End of table. */ + { 0, NULL, 0, 0 } +}; + +/* + * Year is either: + * = A number from 0 to 99, which means a year from 1970 to 2069, or + * = The actual year (>=100). + */ +static time_t +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, + time_t Timezone, enum DSTMODE DSTmode) +{ + signed char DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t Julian; + int i; + + if (Year < 69) + Year += 2000; + else if (Year < 100) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + /* Checking for 2038 bogusly assumes that time_t is 32 bits. But + I'm too lazy to try to check for time_t overflow in another way. */ + if (Year < EPOCH || Year > 2038 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month] + || Hours < 0 || Hours > 23 + || Minutes < 0 || Minutes > 59 + || Seconds < 0 || Seconds > 59) + return -1; + + Julian = Day - 1; + for (i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= DAY; + Julian += Timezone; + Julian += Hours * HOUR + Minutes * MINUTE + Seconds; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= HOUR; + return Julian; +} + + +static time_t +DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * HOUR; +} + + +static time_t +RelativeDate(time_t Start, time_t zone, int dstmode, + time_t DayOrdinal, time_t DayNumber) +{ + struct tm *tm; + time_t t, now; + + t = Start - zone; + tm = gmtime(&t); + now = Start; + now += DAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + if (dstmode == DSTmaybe) + return DSTcorrect(Start, now); + return now - Start; +} + + +static time_t +RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + Timezone, DSTmaybe)); +} + +/* + * Tokenizer. + */ +static int +nexttoken(const char **in, time_t *value) +{ + char c; + char buff[64]; + + for ( ; ; ) { + while (isspace((unsigned char)**in)) + ++*in; + + /* Skip parenthesized comments. */ + if (**in == '(') { + int Count = 0; + do { + c = *(*in)++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + continue; + } + + /* Try the next token in the word table first. */ + /* This allows us to match "2nd", for example. */ + { + const char *src = *in; + const struct LEXICON *tp; + unsigned i = 0; + + /* Force to lowercase and strip '.' characters. */ + while (*src != '\0' + && (isalnum((unsigned char)*src) || *src == '.') + && i < sizeof(buff)-1) { + if (*src != '.') { + if (isupper((unsigned char)*src)) + buff[i++] = tolower((unsigned char)*src); + else + buff[i++] = *src; + } + src++; + } + buff[i] = '\0'; + + /* + * Find the first match. If the word can be + * abbreviated, make sure we match at least + * the minimum abbreviation. + */ + for (tp = TimeWords; tp->name; tp++) { + size_t abbrev = tp->abbrev; + if (abbrev == 0) + abbrev = strlen(tp->name); + if (strlen(buff) >= abbrev + && strncmp(tp->name, buff, strlen(buff)) + == 0) { + /* Skip over token. */ + *in = src; + /* Return the match. */ + *value = tp->value; + return tp->type; + } + } + } + + /* + * 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. + */ + if (isdigit((unsigned char)(c = **in))) { + for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); ) + *value = 10 * *value + c - '0'; + (*in)--; + return (tUNUMBER); + } + + return *(*in)++; + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR + + (a->tm_min - b->tm_min) * MINUTE + + (a->tm_sec - b->tm_sec)); +} + +/* + * + * The public function. + * + * TODO: tokens[] array should be dynamically sized. + */ +time_t +__archive_get_date(time_t now, const char *p) +{ + struct token tokens[256]; + struct gdstate _gds; + struct token *lasttoken; + struct gdstate *gds; + struct tm local, *tm; + struct tm gmt, *gmt_ptr; + time_t Start; + time_t tod; + long tzone; + + /* Clear out the parsed token array. */ + memset(tokens, 0, sizeof(tokens)); + /* Initialize the parser state. */ + memset(&_gds, 0, sizeof(_gds)); + gds = &_gds; + + /* Look up the current time. */ + memset(&local, 0, sizeof(local)); + tm = localtime (&now); + if (tm == NULL) + return -1; + local = *tm; + + /* Look up UTC if we can and use that to determine the current + * timezone offset. */ + memset(&gmt, 0, sizeof(gmt)); + gmt_ptr = gmtime (&now); + if (gmt_ptr != NULL) { + /* Copy, in case localtime and gmtime use the same buffer. */ + gmt = *gmt_ptr; + } + if (gmt_ptr != NULL) + tzone = difftm (&gmt, &local); + else + /* This system doesn't understand timezones; fake it. */ + tzone = 0; + if(local.tm_isdst) + tzone += HOUR; + + /* Tokenize the input string. */ + lasttoken = tokens; + while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) { + ++lasttoken; + if (lasttoken > tokens + 255) + return -1; + } + gds->tokenp = tokens; + + /* Match phrases until we run out of input tokens. */ + while (gds->tokenp < lasttoken) { + if (!phrase(gds)) + return -1; + } + + /* Use current local timezone if none was specified. */ + if (!gds->HaveZone) { + gds->Timezone = tzone; + gds->DSTmode = DSTmaybe; + } + + /* If a timezone was specified, use that for generating the default + * time components instead of the local timezone. */ + if (gds->HaveZone && gmt_ptr != NULL) { + now -= gds->Timezone; + gmt_ptr = gmtime (&now); + if (gmt_ptr != NULL) + local = *gmt_ptr; + now += gds->Timezone; + } + + if (!gds->HaveYear) + gds->Year = local.tm_year + 1900; + if (!gds->HaveMonth) + gds->Month = local.tm_mon + 1; + if (!gds->HaveDay) + gds->Day = local.tm_mday; + /* Note: No default for hour/min/sec; a specifier that just + * gives date always refers to 00:00 on that date. */ + + /* If we saw more than one time, timezone, weekday, year, month, + * or day, then give up. */ + if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1 + || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1) + return -1; + + /* Compute an absolute time based on whatever absolute information + * we collected. */ + if (gds->HaveYear || gds->HaveMonth || gds->HaveDay + || gds->HaveTime || gds->HaveWeekDay) { + Start = Convert(gds->Month, gds->Day, gds->Year, + gds->Hour, gds->Minutes, gds->Seconds, + gds->Timezone, gds->DSTmode); + if (Start < 0) + return -1; + } else { + Start = now; + if (!gds->HaveRel) + Start -= local.tm_hour * HOUR + local.tm_min * MINUTE + + local.tm_sec; + } + + /* Add the relative offset. */ + Start += gds->RelSeconds; + Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth); + + /* Adjust for day-of-week offsets. */ + if (gds->HaveWeekDay + && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) { + tod = RelativeDate(Start, gds->Timezone, + gds->DSTmode, gds->DayOrdinal, gds->DayNumber); + Start += tod; + } + + /* -1 is an error indicator, so return 0 instead of -1 if + * that's the actual time. */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(int argc, char **argv) +{ + time_t d; + time_t now = time(NULL); + + while (*++argv != NULL) { + (void)printf("Input: %s\n", *argv); + d = get_date(now, *argv); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("Output: %s\n", ctime(&d)); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/src/3rdparty/libarchive/libarchive/archive_getdate.h b/src/3rdparty/libarchive/libarchive/archive_getdate.h new file mode 100644 index 00000000..666ff5ff --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_getdate.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2003-2015 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_GETDATE_H_INCLUDED +#define ARCHIVE_GETDATE_H_INCLUDED + +#include + +time_t __archive_get_date(time_t now, const char *); + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_match.c b/src/3rdparty/libarchive/libarchive/archive_match.c new file mode 100644 index 00000000..be72066e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_match.c @@ -0,0 +1,1846 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_entry.h" +#include "archive_getdate.h" +#include "archive_pathmatch.h" +#include "archive_rb.h" +#include "archive_string.h" + +struct match { + struct match *next; + int matches; + struct archive_mstring pattern; +}; + +struct match_list { + struct match *first; + struct match **last; + int count; + int unmatched_count; + struct match *unmatched_next; + int unmatched_eof; +}; + +struct match_file { + struct archive_rb_node node; + struct match_file *next; + struct archive_mstring pathname; + int flag; + time_t mtime_sec; + long mtime_nsec; + time_t ctime_sec; + long ctime_nsec; +}; + +struct entry_list { + struct match_file *first; + struct match_file **last; + int count; +}; + +struct id_array { + size_t size;/* Allocated size */ + size_t count; + int64_t *ids; +}; + +#define PATTERN_IS_SET 1 +#define TIME_IS_SET 2 +#define ID_IS_SET 4 + +struct archive_match { + struct archive archive; + + /* exclusion/inclusion set flag. */ + int setflag; + + /* + * Matching filename patterns. + */ + struct match_list exclusions; + struct match_list inclusions; + + /* + * Matching time stamps. + */ + time_t now; + int newer_mtime_filter; + time_t newer_mtime_sec; + long newer_mtime_nsec; + int newer_ctime_filter; + time_t newer_ctime_sec; + long newer_ctime_nsec; + int older_mtime_filter; + time_t older_mtime_sec; + long older_mtime_nsec; + int older_ctime_filter; + time_t older_ctime_sec; + long older_ctime_nsec; + /* + * Matching time stamps with its filename. + */ + struct archive_rb_tree exclusion_tree; + struct entry_list exclusion_entry_list; + + /* + * Matching file owners. + */ + struct id_array inclusion_uids; + struct id_array inclusion_gids; + struct match_list inclusion_unames; + struct match_list inclusion_gnames; +}; + +static int add_pattern_from_file(struct archive_match *, + struct match_list *, int, const void *, int); +static int add_entry(struct archive_match *, int, + struct archive_entry *); +static int add_owner_id(struct archive_match *, struct id_array *, + int64_t); +static int add_owner_name(struct archive_match *, struct match_list *, + int, const void *); +static int add_pattern_mbs(struct archive_match *, struct match_list *, + const char *); +static int add_pattern_wcs(struct archive_match *, struct match_list *, + const wchar_t *); +static int cmp_key_mbs(const struct archive_rb_node *, const void *); +static int cmp_key_wcs(const struct archive_rb_node *, const void *); +static int cmp_node_mbs(const struct archive_rb_node *, + const struct archive_rb_node *); +static int cmp_node_wcs(const struct archive_rb_node *, + const struct archive_rb_node *); +static void entry_list_add(struct entry_list *, struct match_file *); +static void entry_list_free(struct entry_list *); +static void entry_list_init(struct entry_list *); +static int error_nomem(struct archive_match *); +static void match_list_add(struct match_list *, struct match *); +static void match_list_free(struct match_list *); +static void match_list_init(struct match_list *); +static int match_list_unmatched_inclusions_next(struct archive_match *, + struct match_list *, int, const void **); +static int match_owner_id(struct id_array *, int64_t); +#if !defined(_WIN32) || defined(__CYGWIN__) +static int match_owner_name_mbs(struct archive_match *, + struct match_list *, const char *); +#else +static int match_owner_name_wcs(struct archive_match *, + struct match_list *, const wchar_t *); +#endif +static int match_path_exclusion(struct archive_match *, + struct match *, int, const void *); +static int match_path_inclusion(struct archive_match *, + struct match *, int, const void *); +static int owner_excluded(struct archive_match *, + struct archive_entry *); +static int path_excluded(struct archive_match *, int, const void *); +static int set_timefilter(struct archive_match *, int, time_t, long, + time_t, long); +static int set_timefilter_pathname_mbs(struct archive_match *, + int, const char *); +static int set_timefilter_pathname_wcs(struct archive_match *, + int, const wchar_t *); +static int set_timefilter_date(struct archive_match *, int, const char *); +static int set_timefilter_date_w(struct archive_match *, int, + const wchar_t *); +static int time_excluded(struct archive_match *, + struct archive_entry *); +static int validate_time_flag(struct archive *, int, const char *); + +#define get_date __archive_get_date + +static const struct archive_rb_tree_ops rb_ops_mbs = { + cmp_node_mbs, cmp_key_mbs +}; + +static const struct archive_rb_tree_ops rb_ops_wcs = { + cmp_node_wcs, cmp_key_wcs +}; + +/* + * The matching logic here needs to be re-thought. I started out to + * try to mimic gtar's matching logic, but it's not entirely + * consistent. In particular 'tar -t' and 'tar -x' interpret patterns + * on the command line as anchored, but --exclude doesn't. + */ + +static int +error_nomem(struct archive_match *a) +{ + archive_set_error(&(a->archive), ENOMEM, "No memory"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); +} + +/* + * Create an ARCHIVE_MATCH object. + */ +struct archive * +archive_match_new(void) +{ + struct archive_match *a; + + a = (struct archive_match *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_MATCH_MAGIC; + a->archive.state = ARCHIVE_STATE_NEW; + match_list_init(&(a->inclusions)); + match_list_init(&(a->exclusions)); + __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); + entry_list_init(&(a->exclusion_entry_list)); + match_list_init(&(a->inclusion_unames)); + match_list_init(&(a->inclusion_gnames)); + time(&a->now); + return (&(a->archive)); +} + +/* + * Free an ARCHIVE_MATCH object. + */ +int +archive_match_free(struct archive *_a) +{ + struct archive_match *a; + + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free"); + a = (struct archive_match *)_a; + match_list_free(&(a->inclusions)); + match_list_free(&(a->exclusions)); + entry_list_free(&(a->exclusion_entry_list)); + free(a->inclusion_uids.ids); + free(a->inclusion_gids.ids); + match_list_free(&(a->inclusion_unames)); + match_list_free(&(a->inclusion_gnames)); + free(a); + return (ARCHIVE_OK); +} + +/* + * Convenience function to perform all exclusion tests. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_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_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + r = 0; + if (a->setflag & PATTERN_IS_SET) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = path_excluded(a, 0, archive_entry_pathname_w(entry)); +#else + r = path_excluded(a, 1, archive_entry_pathname(entry)); +#endif + if (r != 0) + return (r); + } + + if (a->setflag & TIME_IS_SET) { + r = time_excluded(a, entry); + if (r != 0) + return (r); + } + + if (a->setflag & ID_IS_SET) + r = owner_excluded(a, entry); + return (r); +} + +/* + * Utility functions to manage exclusion/inclusion patterns + */ + +int +archive_match_exclude_pattern(struct archive *_a, const char *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == '\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_exclude_pattern_from_file(struct archive *_a, + const char *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->exclusions), 1, pathname, + nullSeparator); +} + +int +archive_match_exclude_pattern_from_file_w(struct archive *_a, + const wchar_t *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->exclusions), 0, pathname, + nullSeparator); +} + +int +archive_match_include_pattern(struct archive *_a, const char *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == '\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_w"); + a = (struct archive_match *)_a; + + if (pattern == NULL || *pattern == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pattern is empty"); + return (ARCHIVE_FAILED); + } + if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK) + return (r); + return (ARCHIVE_OK); +} + +int +archive_match_include_pattern_from_file(struct archive *_a, + const char *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->inclusions), 1, pathname, + nullSeparator); +} + +int +archive_match_include_pattern_from_file_w(struct archive *_a, + const wchar_t *pathname, int nullSeparator) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w"); + a = (struct archive_match *)_a; + + return add_pattern_from_file(a, &(a->inclusions), 0, pathname, + nullSeparator); +} + +/* + * Test functions for pathname patterns. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_path_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_path_excluded"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have exclusion/inclusion pattern set at all, + * the entry is always not excluded. */ + if ((a->setflag & PATTERN_IS_SET) == 0) + return (0); +#if defined(_WIN32) && !defined(__CYGWIN__) + return (path_excluded(a, 0, archive_entry_pathname_w(entry))); +#else + return (path_excluded(a, 1, archive_entry_pathname(entry))); +#endif +} + +/* + * Utility functions to get statistic information for inclusion patterns. + */ +int +archive_match_path_unmatched_inclusions(struct archive *_a) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); + a = (struct archive_match *)_a; + + return (a->inclusions.unmatched_count); +} + +int +archive_match_path_unmatched_inclusions_next(struct archive *_a, + const char **_p) +{ + struct archive_match *a; + const void *v; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next"); + a = (struct archive_match *)_a; + + r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v); + *_p = (const char *)v; + return (r); +} + +int +archive_match_path_unmatched_inclusions_next_w(struct archive *_a, + const wchar_t **_p) +{ + struct archive_match *a; + const void *v; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w"); + a = (struct archive_match *)_a; + + r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v); + *_p = (const wchar_t *)v; + return (r); +} + +/* + * Add inclusion/exclusion patterns. + */ +static int +add_pattern_mbs(struct archive_match *a, struct match_list *list, + const char *pattern) +{ + struct match *match; + size_t len; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + /* Both "foo/" and "foo" should match "foo/bar". */ + len = strlen(pattern); + if (len && pattern[len - 1] == '/') + --len; + archive_mstring_copy_mbs_len(&(match->pattern), pattern, len); + match_list_add(list, match); + a->setflag |= PATTERN_IS_SET; + return (ARCHIVE_OK); +} + +static int +add_pattern_wcs(struct archive_match *a, struct match_list *list, + const wchar_t *pattern) +{ + struct match *match; + size_t len; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + /* Both "foo/" and "foo" should match "foo/bar". */ + len = wcslen(pattern); + if (len && pattern[len - 1] == L'/') + --len; + archive_mstring_copy_wcs_len(&(match->pattern), pattern, len); + match_list_add(list, match); + a->setflag |= PATTERN_IS_SET; + return (ARCHIVE_OK); +} + +static int +add_pattern_from_file(struct archive_match *a, struct match_list *mlist, + int mbs, const void *pathname, int nullSeparator) +{ + struct archive *ar; + struct archive_entry *ae; + struct archive_string as; + const void *buff; + size_t size; + int64_t offset; + int r; + + ar = archive_read_new(); + if (ar == NULL) { + archive_set_error(&(a->archive), ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + r = archive_read_support_format_raw(ar); + r = archive_read_support_format_empty(ar); + if (r != ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + return (r); + } + if (mbs) + r = archive_read_open_filename(ar, pathname, 512*20); + else + r = archive_read_open_filename_w(ar, pathname, 512*20); + if (r != ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + return (r); + } + r = archive_read_next_header(ar, &ae); + if (r != ARCHIVE_OK) { + archive_read_free(ar); + if (r == ARCHIVE_EOF) { + return (ARCHIVE_OK); + } else { + archive_copy_error(&(a->archive), ar); + return (r); + } + } + + archive_string_init(&as); + + while ((r = archive_read_data_block(ar, &buff, &size, &offset)) + == ARCHIVE_OK) { + const char *b = (const char *)buff; + + while (size) { + const char *s = (const char *)b; + size_t length = 0; + int found_separator = 0; + + while (length < size) { + if (nullSeparator) { + if (*b == '\0') { + found_separator = 1; + break; + } + } else { + if (*b == 0x0d || *b == 0x0a) { + found_separator = 1; + break; + } + } + b++; + length++; + } + if (!found_separator) { + archive_strncat(&as, s, length); + /* Read next data block. */ + break; + } + b++; + size -= length + 1; + archive_strncat(&as, s, length); + + /* If the line is not empty, add the pattern. */ + if (archive_strlen(&as) > 0) { + /* Add pattern. */ + r = add_pattern_mbs(a, mlist, as.s); + if (r != ARCHIVE_OK) { + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + archive_string_empty(&as); + } + } + } + + /* If an error occurred, report it immediately. */ + if (r < ARCHIVE_OK) { + archive_copy_error(&(a->archive), ar); + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + + /* If the line is not empty, add the pattern. */ + if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { + /* Add pattern. */ + r = add_pattern_mbs(a, mlist, as.s); + if (r != ARCHIVE_OK) { + archive_read_free(ar); + archive_string_free(&as); + return (r); + } + } + archive_read_free(ar); + archive_string_free(&as); + return (ARCHIVE_OK); +} + +/* + * Test if pathname is excluded by inclusion/exclusion patterns. + */ +static int +path_excluded(struct archive_match *a, int mbs, const void *pathname) +{ + struct match *match; + struct match *matched; + int r; + + if (a == NULL) + return (0); + + /* Mark off any unmatched inclusions. */ + /* In particular, if a filename does appear in the archive and + * is explicitly included and excluded, then we don't report + * it as missing even though we don't extract it. + */ + matched = NULL; + for (match = a->inclusions.first; match != NULL; + match = match->next){ + if (match->matches == 0 && + (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { + if (r < 0) + return (r); + a->inclusions.unmatched_count--; + match->matches++; + matched = match; + } + } + + /* Exclusions take priority */ + for (match = a->exclusions.first; match != NULL; + match = match->next){ + r = match_path_exclusion(a, match, mbs, pathname); + if (r) + return (r); + } + + /* It's not excluded and we found an inclusion above, so it's + * included. */ + if (matched != NULL) + return (0); + + + /* We didn't find an unmatched inclusion, check the remaining ones. */ + for (match = a->inclusions.first; match != NULL; + match = match->next){ + /* We looked at previously-unmatched inclusions already. */ + if (match->matches > 0 && + (r = match_path_inclusion(a, match, mbs, pathname)) != 0) { + if (r < 0) + return (r); + match->matches++; + return (0); + } + } + + /* If there were inclusions, default is to exclude. */ + if (a->inclusions.first != NULL) + return (1); + + /* No explicit inclusions, default is to match. */ + return (0); +} + +/* + * This is a little odd, but it matches the default behavior of + * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' + * + */ +static int +match_path_exclusion(struct archive_match *a, struct match *m, + int mbs, const void *pn) +{ + int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END; + int r; + + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch(p, (const char *)pn, flag)); + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch_w(p, (const wchar_t *)pn, + flag)); + } + if (errno == ENOMEM) + return (error_nomem(a)); + return (0); +} + +/* + * Again, mimic gtar: inclusions are always anchored (have to match + * the beginning of the path) even though exclusions are not anchored. + */ +static int +match_path_inclusion(struct archive_match *a, struct match *m, + int mbs, const void *pn) +{ + int flag = PATHMATCH_NO_ANCHOR_END; + int r; + + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch(p, (const char *)pn, flag)); + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p); + if (r == 0) + return (archive_pathmatch_w(p, (const wchar_t *)pn, + flag)); + } + if (errno == ENOMEM) + return (error_nomem(a)); + return (0); +} + +static void +match_list_init(struct match_list *list) +{ + list->first = NULL; + list->last = &(list->first); + list->count = 0; +} + +static void +match_list_free(struct match_list *list) +{ + struct match *p, *q; + + for (p = list->first; p != NULL; ) { + q = p; + p = p->next; + archive_mstring_clean(&(q->pattern)); + free(q); + } +} + +static void +match_list_add(struct match_list *list, struct match *m) +{ + *list->last = m; + list->last = &(m->next); + list->count++; + list->unmatched_count++; +} + +static int +match_list_unmatched_inclusions_next(struct archive_match *a, + struct match_list *list, int mbs, const void **vp) +{ + struct match *m; + + *vp = NULL; + if (list->unmatched_eof) { + list->unmatched_eof = 0; + return (ARCHIVE_EOF); + } + if (list->unmatched_next == NULL) { + if (list->unmatched_count == 0) + return (ARCHIVE_EOF); + list->unmatched_next = list->first; + } + + for (m = list->unmatched_next; m != NULL; m = m->next) { + int r; + + if (m->matches) + continue; + if (mbs) { + const char *p; + r = archive_mstring_get_mbs(&(a->archive), + &(m->pattern), &p); + if (r < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p == NULL) + p = ""; + *vp = p; + } else { + const wchar_t *p; + r = archive_mstring_get_wcs(&(a->archive), + &(m->pattern), &p); + if (r < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p == NULL) + p = L""; + *vp = p; + } + list->unmatched_next = m->next; + if (list->unmatched_next == NULL) + /* To return EOF next time. */ + list->unmatched_eof = 1; + return (ARCHIVE_OK); + } + list->unmatched_next = NULL; + return (ARCHIVE_EOF); +} + +/* + * Utility functions to manage inclusion timestamps. + */ +int +archive_match_include_time(struct archive *_a, int flag, time_t sec, + long nsec) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_time"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter((struct archive_match *)_a, flag, + sec, nsec, sec, nsec); +} + +int +archive_match_include_date(struct archive *_a, int flag, + const char *datestr) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_date"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_date((struct archive_match *)_a, flag, datestr); +} + +int +archive_match_include_date_w(struct archive *_a, int flag, + const wchar_t *datestr) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_date_w"); + if (r != ARCHIVE_OK) + return (r); + + return set_timefilter_date_w((struct archive_match *)_a, flag, datestr); +} + +int +archive_match_include_file_time(struct archive *_a, int flag, + const char *pathname) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_file_time"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_pathname_mbs((struct archive_match *)_a, + flag, pathname); +} + +int +archive_match_include_file_time_w(struct archive *_a, int flag, + const wchar_t *pathname) +{ + int r; + + r = validate_time_flag(_a, flag, "archive_match_include_file_time_w"); + if (r != ARCHIVE_OK) + return (r); + return set_timefilter_pathname_wcs((struct archive_match *)_a, + flag, pathname); +} + +int +archive_match_exclude_entry(struct archive *_a, int flag, + struct archive_entry *entry) +{ + struct archive_match *a; + int r; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_time_include_entry"); + a = (struct archive_match *)_a; + + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + r = validate_time_flag(_a, flag, "archive_match_exclude_entry"); + if (r != ARCHIVE_OK) + return (r); + return (add_entry(a, flag, entry)); +} + +/* + * Test function for time stamps. + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_time_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have inclusion time set at all, the entry is always + * not excluded. */ + if ((a->setflag & TIME_IS_SET) == 0) + return (0); + return (time_excluded(a, entry)); +} + +static int +validate_time_flag(struct archive *_a, int flag, const char *_fn) +{ + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, _fn); + + /* Check a type of time. */ + if (flag & + ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) { + archive_set_error(_a, EINVAL, "Invalid time flag"); + return (ARCHIVE_FAILED); + } + if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) { + archive_set_error(_a, EINVAL, "No time flag"); + return (ARCHIVE_FAILED); + } + + /* Check a type of comparison. */ + if (flag & + ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER + | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) { + archive_set_error(_a, EINVAL, "Invalid comparison flag"); + return (ARCHIVE_FAILED); + } + if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER + | ARCHIVE_MATCH_EQUAL)) == 0) { + archive_set_error(_a, EINVAL, "No comparison flag"); + return (ARCHIVE_FAILED); + } + + return (ARCHIVE_OK); +} + +#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\ + ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL) +static int +set_timefilter(struct archive_match *a, int timetype, + time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec) +{ + if (timetype & ARCHIVE_MATCH_MTIME) { + if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { + a->newer_mtime_filter = timetype; + a->newer_mtime_sec = mtime_sec; + a->newer_mtime_nsec = mtime_nsec; + a->setflag |= TIME_IS_SET; + } + if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { + a->older_mtime_filter = timetype; + a->older_mtime_sec = mtime_sec; + a->older_mtime_nsec = mtime_nsec; + a->setflag |= TIME_IS_SET; + } + } + if (timetype & ARCHIVE_MATCH_CTIME) { + if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) { + a->newer_ctime_filter = timetype; + a->newer_ctime_sec = ctime_sec; + a->newer_ctime_nsec = ctime_nsec; + a->setflag |= TIME_IS_SET; + } + if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) { + a->older_ctime_filter = timetype; + a->older_ctime_sec = ctime_sec; + a->older_ctime_nsec = ctime_nsec; + a->setflag |= TIME_IS_SET; + } + } + return (ARCHIVE_OK); +} + +static int +set_timefilter_date(struct archive_match *a, int timetype, const char *datestr) +{ + time_t t; + + if (datestr == NULL || *datestr == '\0') { + archive_set_error(&(a->archive), EINVAL, "date is empty"); + return (ARCHIVE_FAILED); + } + t = get_date(a->now, datestr); + if (t == (time_t)-1) { + archive_set_error(&(a->archive), EINVAL, "invalid date string"); + return (ARCHIVE_FAILED); + } + return set_timefilter(a, timetype, t, 0, t, 0); +} + +static int +set_timefilter_date_w(struct archive_match *a, int timetype, + const wchar_t *datestr) +{ + struct archive_string as; + time_t t; + + if (datestr == NULL || *datestr == L'\0') { + archive_set_error(&(a->archive), EINVAL, "date is empty"); + return (ARCHIVE_FAILED); + } + + archive_string_init(&as); + if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { + archive_string_free(&as); + if (errno == ENOMEM) + return (error_nomem(a)); + archive_set_error(&(a->archive), -1, + "Failed to convert WCS to MBS"); + return (ARCHIVE_FAILED); + } + t = get_date(a->now, as.s); + archive_string_free(&as); + if (t == (time_t)-1) { + archive_set_error(&(a->archive), EINVAL, "invalid date string"); + return (ARCHIVE_FAILED); + } + return set_timefilter(a, timetype, t, 0, t, 0); +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) +static int +set_timefilter_find_data(struct archive_match *a, int timetype, + DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, + DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) +{ + ULARGE_INTEGER utc; + time_t ctime_sec, mtime_sec; + long ctime_ns, mtime_ns; + + utc.HighPart = ftCreationTime_dwHighDateTime; + utc.LowPart = ftCreationTime_dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + ctime_sec = (time_t)(utc.QuadPart / 10000000); + ctime_ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + ctime_sec = 0; + ctime_ns = 0; + } + utc.HighPart = ftLastWriteTime_dwHighDateTime; + utc.LowPart = ftLastWriteTime_dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + mtime_sec = (time_t)(utc.QuadPart / 10000000); + mtime_ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + mtime_sec = 0; + mtime_ns = 0; + } + return set_timefilter(a, timetype, + mtime_sec, mtime_ns, ctime_sec, ctime_ns); +} + +static int +set_timefilter_pathname_mbs(struct archive_match *a, int timetype, + const char *path) +{ + /* NOTE: stat() on Windows cannot handle nano seconds. */ + HANDLE h; + WIN32_FIND_DATAA d; + + if (path == NULL || *path == '\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + h = FindFirstFileA(path, &d); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&(a->archive), errno, + "Failed to FindFirstFileA"); + return (ARCHIVE_FAILED); + } + FindClose(h); + return set_timefilter_find_data(a, timetype, + d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, + d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); +} + +static int +set_timefilter_pathname_wcs(struct archive_match *a, int timetype, + const wchar_t *path) +{ + HANDLE h; + WIN32_FIND_DATAW d; + + if (path == NULL || *path == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + h = FindFirstFileW(path, &d); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&(a->archive), errno, + "Failed to FindFirstFile"); + return (ARCHIVE_FAILED); + } + FindClose(h); + return set_timefilter_find_data(a, timetype, + d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, + d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); +} + +#else /* _WIN32 && !__CYGWIN__ */ + +static int +set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st) +{ + struct archive_entry *ae; + time_t ctime_sec, mtime_sec; + long ctime_ns, mtime_ns; + + ae = archive_entry_new(); + if (ae == NULL) + return (error_nomem(a)); + archive_entry_copy_stat(ae, st); + ctime_sec = archive_entry_ctime(ae); + ctime_ns = archive_entry_ctime_nsec(ae); + mtime_sec = archive_entry_mtime(ae); + mtime_ns = archive_entry_mtime_nsec(ae); + archive_entry_free(ae); + return set_timefilter(a, timetype, mtime_sec, mtime_ns, + ctime_sec, ctime_ns); +} + +static int +set_timefilter_pathname_mbs(struct archive_match *a, int timetype, + const char *path) +{ + struct stat st; + + if (path == NULL || *path == '\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + if (stat(path, &st) != 0) { + archive_set_error(&(a->archive), errno, "Failed to stat()"); + return (ARCHIVE_FAILED); + } + return (set_timefilter_stat(a, timetype, &st)); +} + +static int +set_timefilter_pathname_wcs(struct archive_match *a, int timetype, + const wchar_t *path) +{ + struct archive_string as; + int r; + + if (path == NULL || *path == L'\0') { + archive_set_error(&(a->archive), EINVAL, "pathname is empty"); + return (ARCHIVE_FAILED); + } + + /* Convert WCS filename to MBS filename. */ + archive_string_init(&as); + if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { + archive_string_free(&as); + if (errno == ENOMEM) + return (error_nomem(a)); + archive_set_error(&(a->archive), -1, + "Failed to convert WCS to MBS"); + return (ARCHIVE_FAILED); + } + + r = set_timefilter_pathname_mbs(a, timetype, as.s); + archive_string_free(&as); + + return (r); +} +#endif /* _WIN32 && !__CYGWIN__ */ + +/* + * Call back functions for archive_rb. + */ +static int +cmp_node_mbs(const struct archive_rb_node *n1, + const struct archive_rb_node *n2) +{ + struct match_file *f1 = (struct match_file *)(uintptr_t)n1; + struct match_file *f2 = (struct match_file *)(uintptr_t)n2; + const char *p1, *p2; + + archive_mstring_get_mbs(NULL, &(f1->pathname), &p1); + archive_mstring_get_mbs(NULL, &(f2->pathname), &p2); + if (p1 == NULL) + return (1); + if (p2 == NULL) + return (-1); + return (strcmp(p1, p2)); +} + +static int +cmp_key_mbs(const struct archive_rb_node *n, const void *key) +{ + struct match_file *f = (struct match_file *)(uintptr_t)n; + const char *p; + + archive_mstring_get_mbs(NULL, &(f->pathname), &p); + if (p == NULL) + return (-1); + return (strcmp(p, (const char *)key)); +} + +static int +cmp_node_wcs(const struct archive_rb_node *n1, + const struct archive_rb_node *n2) +{ + struct match_file *f1 = (struct match_file *)(uintptr_t)n1; + struct match_file *f2 = (struct match_file *)(uintptr_t)n2; + const wchar_t *p1, *p2; + + archive_mstring_get_wcs(NULL, &(f1->pathname), &p1); + archive_mstring_get_wcs(NULL, &(f2->pathname), &p2); + if (p1 == NULL) + return (1); + if (p2 == NULL) + return (-1); + return (wcscmp(p1, p2)); +} + +static int +cmp_key_wcs(const struct archive_rb_node *n, const void *key) +{ + struct match_file *f = (struct match_file *)(uintptr_t)n; + const wchar_t *p; + + archive_mstring_get_wcs(NULL, &(f->pathname), &p); + if (p == NULL) + return (-1); + return (wcscmp(p, (const wchar_t *)key)); +} + +static void +entry_list_init(struct entry_list *list) +{ + list->first = NULL; + list->last = &(list->first); + list->count = 0; +} + +static void +entry_list_free(struct entry_list *list) +{ + struct match_file *p, *q; + + for (p = list->first; p != NULL; ) { + q = p; + p = p->next; + archive_mstring_clean(&(q->pathname)); + free(q); + } +} + +static void +entry_list_add(struct entry_list *list, struct match_file *file) +{ + *list->last = file; + list->last = &(file->next); + list->count++; +} + +static int +add_entry(struct archive_match *a, int flag, + struct archive_entry *entry) +{ + struct match_file *f; + const void *pathname; + int r; + + f = calloc(1, sizeof(*f)); + if (f == NULL) + return (error_nomem(a)); + +#if defined(_WIN32) && !defined(__CYGWIN__) + pathname = archive_entry_pathname_w(entry); + if (pathname == NULL) { + free(f); + archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); + return (ARCHIVE_FAILED); + } + archive_mstring_copy_wcs(&(f->pathname), pathname); + a->exclusion_tree.rbt_ops = &rb_ops_wcs; +#else + (void)rb_ops_wcs; + pathname = archive_entry_pathname(entry); + if (pathname == NULL) { + free(f); + archive_set_error(&(a->archive), EINVAL, "pathname is NULL"); + return (ARCHIVE_FAILED); + } + archive_mstring_copy_mbs(&(f->pathname), pathname); + a->exclusion_tree.rbt_ops = &rb_ops_mbs; +#endif + f->flag = flag; + f->mtime_sec = archive_entry_mtime(entry); + f->mtime_nsec = archive_entry_mtime_nsec(entry); + f->ctime_sec = archive_entry_ctime(entry); + f->ctime_nsec = archive_entry_ctime_nsec(entry); + r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node)); + if (!r) { + struct match_file *f2; + + /* Get the duplicated file. */ + f2 = (struct match_file *)__archive_rb_tree_find_node( + &(a->exclusion_tree), pathname); + + /* + * We always overwrite comparison condition. + * If you do not want to overwrite it, you should not + * call archive_match_exclude_entry(). We cannot know + * what behavior you really expect since overwriting + * condition might be different with the flag. + */ + if (f2 != NULL) { + f2->flag = f->flag; + f2->mtime_sec = f->mtime_sec; + f2->mtime_nsec = f->mtime_nsec; + f2->ctime_sec = f->ctime_sec; + f2->ctime_nsec = f->ctime_nsec; + } + /* Release the duplicated file. */ + archive_mstring_clean(&(f->pathname)); + free(f); + return (ARCHIVE_OK); + } + entry_list_add(&(a->exclusion_entry_list), f); + a->setflag |= TIME_IS_SET; + return (ARCHIVE_OK); +} + +/* + * Test if entry is excluded by its timestamp. + */ +static int +time_excluded(struct archive_match *a, struct archive_entry *entry) +{ + struct match_file *f; + const void *pathname; + time_t sec; + long nsec; + + /* + * If this file/dir is excluded by a time comparison, skip it. + */ + if (a->newer_ctime_filter) { + /* If ctime is not set, use mtime instead. */ + if (archive_entry_ctime_is_set(entry)) + sec = archive_entry_ctime(entry); + else + sec = archive_entry_mtime(entry); + if (sec < a->newer_ctime_sec) + return (1); /* Too old, skip it. */ + if (sec == a->newer_ctime_sec) { + if (archive_entry_ctime_is_set(entry)) + nsec = archive_entry_ctime_nsec(entry); + else + nsec = archive_entry_mtime_nsec(entry); + if (nsec < a->newer_ctime_nsec) + return (1); /* Too old, skip it. */ + if (nsec == a->newer_ctime_nsec && + (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + if (a->older_ctime_filter) { + /* If ctime is not set, use mtime instead. */ + if (archive_entry_ctime_is_set(entry)) + sec = archive_entry_ctime(entry); + else + sec = archive_entry_mtime(entry); + if (sec > a->older_ctime_sec) + return (1); /* Too new, skip it. */ + if (sec == a->older_ctime_sec) { + if (archive_entry_ctime_is_set(entry)) + nsec = archive_entry_ctime_nsec(entry); + else + nsec = archive_entry_mtime_nsec(entry); + if (nsec > a->older_ctime_nsec) + return (1); /* Too new, skip it. */ + if (nsec == a->older_ctime_nsec && + (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + if (a->newer_mtime_filter) { + sec = archive_entry_mtime(entry); + if (sec < a->newer_mtime_sec) + return (1); /* Too old, skip it. */ + if (sec == a->newer_mtime_sec) { + nsec = archive_entry_mtime_nsec(entry); + if (nsec < a->newer_mtime_nsec) + return (1); /* Too old, skip it. */ + if (nsec == a->newer_mtime_nsec && + (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + if (a->older_mtime_filter) { + sec = archive_entry_mtime(entry); + if (sec > a->older_mtime_sec) + return (1); /* Too new, skip it. */ + nsec = archive_entry_mtime_nsec(entry); + if (sec == a->older_mtime_sec) { + if (nsec > a->older_mtime_nsec) + return (1); /* Too new, skip it. */ + if (nsec == a->older_mtime_nsec && + (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL) + == 0) + return (1); /* Equal, skip it. */ + } + } + + /* If there is no exclusion list, include the file. */ + if (a->exclusion_entry_list.count == 0) + return (0); + +#if defined(_WIN32) && !defined(__CYGWIN__) + pathname = archive_entry_pathname_w(entry); + a->exclusion_tree.rbt_ops = &rb_ops_wcs; +#else + (void)rb_ops_wcs; + pathname = archive_entry_pathname(entry); + a->exclusion_tree.rbt_ops = &rb_ops_mbs; +#endif + if (pathname == NULL) + return (0); + + f = (struct match_file *)__archive_rb_tree_find_node( + &(a->exclusion_tree), pathname); + /* If the file wasn't rejected, include it. */ + if (f == NULL) + return (0); + + if (f->flag & ARCHIVE_MATCH_CTIME) { + sec = archive_entry_ctime(entry); + if (f->ctime_sec > sec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->ctime_sec < sec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else { + nsec = archive_entry_ctime_nsec(entry); + if (f->ctime_nsec > nsec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->ctime_nsec < nsec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else if (f->flag & ARCHIVE_MATCH_EQUAL) + return (1); + } + } + if (f->flag & ARCHIVE_MATCH_MTIME) { + sec = archive_entry_mtime(entry); + if (f->mtime_sec > sec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->mtime_sec < sec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else { + nsec = archive_entry_mtime_nsec(entry); + if (f->mtime_nsec > nsec) { + if (f->flag & ARCHIVE_MATCH_OLDER) + return (1); + } else if (f->mtime_nsec < nsec) { + if (f->flag & ARCHIVE_MATCH_NEWER) + return (1); + } else if (f->flag & ARCHIVE_MATCH_EQUAL) + return (1); + } + } + return (0); +} + +/* + * Utility functions to manage inclusion owners + */ + +int +archive_match_include_uid(struct archive *_a, int64_t uid) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uid"); + a = (struct archive_match *)_a; + return (add_owner_id(a, &(a->inclusion_uids), uid)); +} + +int +archive_match_include_gid(struct archive *_a, int64_t gid) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gid"); + a = (struct archive_match *)_a; + return (add_owner_id(a, &(a->inclusion_gids), gid)); +} + +int +archive_match_include_uname(struct archive *_a, const char *uname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uname"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_unames), 1, uname)); +} + +int +archive_match_include_uname_w(struct archive *_a, const wchar_t *uname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_uname_w"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_unames), 0, uname)); +} + +int +archive_match_include_gname(struct archive *_a, const char *gname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gname"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_gnames), 1, gname)); +} + +int +archive_match_include_gname_w(struct archive *_a, const wchar_t *gname) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_include_gname_w"); + a = (struct archive_match *)_a; + return (add_owner_name(a, &(a->inclusion_gnames), 0, gname)); +} + +/* + * Test function for owner(uid, gid, uname, gname). + * + * Returns 1 if archive entry is excluded. + * Returns 0 if archive entry is not excluded. + * Returns <0 if something error happened. + */ +int +archive_match_owner_excluded(struct archive *_a, + struct archive_entry *entry) +{ + struct archive_match *a; + + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, + ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae"); + + a = (struct archive_match *)_a; + if (entry == NULL) { + archive_set_error(&(a->archive), EINVAL, "entry is NULL"); + return (ARCHIVE_FAILED); + } + + /* If we don't have inclusion id set at all, the entry is always + * not excluded. */ + if ((a->setflag & ID_IS_SET) == 0) + return (0); + return (owner_excluded(a, entry)); +} + +static int +add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) +{ + unsigned i; + + if (ids->count + 1 >= ids->size) { + void *p; + + if (ids->size == 0) + ids->size = 8; + else + ids->size *= 2; + p = realloc(ids->ids, sizeof(*ids->ids) * ids->size); + if (p == NULL) + return (error_nomem(a)); + ids->ids = (int64_t *)p; + } + + /* Find an insert point. */ + for (i = 0; i < ids->count; i++) { + if (ids->ids[i] >= id) + break; + } + + /* Add owner id. */ + if (i == ids->count) + ids->ids[ids->count++] = id; + else if (ids->ids[i] != id) { + memmove(&(ids->ids[i+1]), &(ids->ids[i]), + (ids->count - i) * sizeof(ids->ids[0])); + ids->ids[i] = id; + ids->count++; + } + a->setflag |= ID_IS_SET; + return (ARCHIVE_OK); +} + +static int +match_owner_id(struct id_array *ids, int64_t id) +{ + unsigned b, m, t; + + t = 0; + b = (unsigned)ids->count; + while (t < b) { + m = (t + b)>>1; + if (ids->ids[m] == id) + return (1); + if (ids->ids[m] < id) + t = m + 1; + else + b = m; + } + return (0); +} + +static int +add_owner_name(struct archive_match *a, struct match_list *list, + int mbs, const void *name) +{ + struct match *match; + + match = calloc(1, sizeof(*match)); + if (match == NULL) + return (error_nomem(a)); + if (mbs) + archive_mstring_copy_mbs(&(match->pattern), name); + else + archive_mstring_copy_wcs(&(match->pattern), name); + match_list_add(list, match); + a->setflag |= ID_IS_SET; + return (ARCHIVE_OK); +} + +#if !defined(_WIN32) || defined(__CYGWIN__) +static int +match_owner_name_mbs(struct archive_match *a, struct match_list *list, + const char *name) +{ + struct match *m; + const char *p; + + if (name == NULL || *name == '\0') + return (0); + for (m = list->first; m; m = m->next) { + if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p) + < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p != NULL && strcmp(p, name) == 0) { + m->matches++; + return (1); + } + } + return (0); +} +#else +static int +match_owner_name_wcs(struct archive_match *a, struct match_list *list, + const wchar_t *name) +{ + struct match *m; + const wchar_t *p; + + if (name == NULL || *name == L'\0') + return (0); + for (m = list->first; m; m = m->next) { + if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p) + < 0 && errno == ENOMEM) + return (error_nomem(a)); + if (p != NULL && wcscmp(p, name) == 0) { + m->matches++; + return (1); + } + } + return (0); +} +#endif + +/* + * Test if entry is excluded by uid, gid, uname or gname. + */ +static int +owner_excluded(struct archive_match *a, struct archive_entry *entry) +{ + int r; + + if (a->inclusion_uids.count) { + if (!match_owner_id(&(a->inclusion_uids), + archive_entry_uid(entry))) + return (1); + } + + if (a->inclusion_gids.count) { + if (!match_owner_id(&(a->inclusion_gids), + archive_entry_gid(entry))) + return (1); + } + + if (a->inclusion_unames.count) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = match_owner_name_wcs(a, &(a->inclusion_unames), + archive_entry_uname_w(entry)); +#else + r = match_owner_name_mbs(a, &(a->inclusion_unames), + archive_entry_uname(entry)); +#endif + if (!r) + return (1); + else if (r < 0) + return (r); + } + + if (a->inclusion_gnames.count) { +#if defined(_WIN32) && !defined(__CYGWIN__) + r = match_owner_name_wcs(a, &(a->inclusion_gnames), + archive_entry_gname_w(entry)); +#else + r = match_owner_name_mbs(a, &(a->inclusion_gnames), + archive_entry_gname(entry)); +#endif + if (!r) + return (1); + else if (r < 0) + return (r); + } + return (0); +} + diff --git a/src/3rdparty/libarchive/libarchive/archive_options.c b/src/3rdparty/libarchive/libarchive/archive_options.c new file mode 100644 index 00000000..6496025a --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_options.c @@ -0,0 +1,218 @@ +/*- + * 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 "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive_options_private.h" + +static const char * +parse_option(const char **str, + const char **mod, const char **opt, const char **val); + +int +_archive_set_option(struct archive *a, + const char *m, const char *o, const char *v, + int magic, const char *fn, option_handler use_option) +{ + const char *mp, *op, *vp; + int r; + + archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); + + mp = (m != NULL && m[0] != '\0') ? m : NULL; + op = (o != NULL && o[0] != '\0') ? o : NULL; + vp = (v != NULL && v[0] != '\0') ? v : NULL; + + if (op == NULL && vp == NULL) + return (ARCHIVE_OK); + if (op == NULL) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option"); + return (ARCHIVE_FAILED); + } + + r = use_option(a, mp, op, vp); + if (r == ARCHIVE_WARN - 1) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unknown module name: `%s'", mp); + return (ARCHIVE_FAILED); + } + if (r == ARCHIVE_WARN) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Undefined option: `%s%s%s%s%s%s'", + vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:""); + return (ARCHIVE_FAILED); + } + return (r); +} + +int +_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v, + option_handler use_format_option, option_handler use_filter_option) +{ + int r1, r2; + + if (o == NULL && v == NULL) + return (ARCHIVE_OK); + if (o == NULL) + return (ARCHIVE_FAILED); + + r1 = use_format_option(a, m, o, v); + if (r1 == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + + r2 = use_filter_option(a, m, o, v); + if (r2 == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + + if (r2 == ARCHIVE_WARN - 1) + return r1; + return r1 > r2 ? r1 : r2; +} + +int +_archive_set_options(struct archive *a, const char *options, + 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; + + archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); + + if (options == NULL || options[0] == '\0') + return ARCHIVE_OK; + + if ((data = strdup(options)) == NULL) { + archive_set_error(a, + ENOMEM, "Out of memory adding file to list"); + return (ARCHIVE_FATAL); + } + s = (const char *)data; + + do { + mod = opt = val = NULL; + + parse_option(&s, &mod, &opt, &val); + if (mod == NULL && opt != NULL && + strcmp("__ignore_wrong_module_name__", opt) == 0) { + /* Ignore module name error */ + if (val != NULL) { + ignore_mod_err = 1; + anyok = 1; + } + continue; + } + + r = use_option(a, mod, opt, val); + if (r == ARCHIVE_FATAL) { + free(data); + return (ARCHIVE_FATAL); + } + if (r == ARCHIVE_FAILED && mod != NULL) { + free(data); + return (ARCHIVE_FAILED); + } + if (r == ARCHIVE_WARN - 1) { + if (ignore_mod_err) + continue; + /* The module name is wrong. */ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unknown module name: `%s'", mod); + free(data); + return (ARCHIVE_FAILED); + } + if (r == ARCHIVE_WARN) { + /* The option name is wrong. No-one used this. */ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Undefined option: `%s%s%s'", + mod?mod:"", mod?":":"", opt); + free(data); + return (ARCHIVE_FAILED); + } + if (r == ARCHIVE_OK) + anyok = 1; + else + allok = 0; + } while (s != NULL); + + free(data); + 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) +{ + const char *end, *mod, *opt, *val; + char *p; + + end = NULL; + mod = NULL; + opt = *s; + val = "1"; + + p = strchr(opt, ','); + + if (p != NULL) { + *p = '\0'; + end = ((const char *)p) + 1; + } + + if (0 == strlen(opt)) { + *s = end; + *m = NULL; + *o = NULL; + *v = NULL; + return end; + } + + p = strchr(opt, ':'); + if (p != NULL) { + *p = '\0'; + mod = opt; + opt = ++p; + } + + p = strchr(opt, '='); + if (p != NULL) { + *p = '\0'; + val = ++p; + } else if (opt[0] == '!') { + ++opt; + val = NULL; + } + + *s = end; + *m = mod; + *o = opt; + *v = val; + + return end; +} + diff --git a/src/3rdparty/libarchive/libarchive/archive_options_private.h b/src/3rdparty/libarchive/libarchive/archive_options_private.h new file mode 100644 index 00000000..6ef0165a --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_options_private.h @@ -0,0 +1,47 @@ +/*- + * 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 "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive_private.h" + +typedef int (*option_handler)(struct archive *a, + const char *mod, const char *opt, const char *val); + +int +_archive_set_option(struct archive *a, + const char *mod, const char *opt, const char *val, + int magic, const char *fn, option_handler use_option); + +int +_archive_set_options(struct archive *a, const char *options, + int magic, const char *fn, option_handler use_option); + +int +_archive_set_either_option(struct archive *a, + const char *m, const char *o, const char *v, + option_handler use_format_option, option_handler use_filter_option); + diff --git a/src/3rdparty/libarchive/libarchive/archive_pack_dev.h b/src/3rdparty/libarchive/libarchive/archive_pack_dev.h new file mode 100644 index 00000000..749fd3d2 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_pack_dev.h @@ -0,0 +1,49 @@ +/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Originally from NetBSD's mknod(8) source. */ + +#ifndef _PACK_DEV_H +#define _PACK_DEV_H + +typedef dev_t pack_t(int, unsigned long [], const char **); + +pack_t *pack_find(const char *); +pack_t pack_native; + +#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) +#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) + +#endif /* _PACK_DEV_H */ diff --git a/src/3rdparty/libarchive/libarchive/archive_pathmatch.c b/src/3rdparty/libarchive/libarchive/archive_pathmatch.c new file mode 100644 index 00000000..619e2b62 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_pathmatch.c @@ -0,0 +1,459 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#include "archive_pathmatch.h" + +/* + * Check whether a character 'c' is matched by a list specification [...]: + * * Leading '!' or '^' negates the class. + * * - is a range of characters + * * \ removes any special meaning for + * + * Some interesting boundary cases: + * a-d-e is one range (a-d) followed by two single characters - and e. + * \a-\d is same as a-d + * a\-d is three single characters: a, d, - + * Trailing - is not special (so [a-] is two characters a and -). + * Initial - is not special ([a-] is same as [-a] is same as [\\-a]) + * This function never sees a trailing \. + * [] always fails + * [!] always succeeds + */ +static int +pm_list(const char *start, const char *end, const char c, int flags) +{ + const char *p = start; + char rangeStart = '\0', nextRangeStart; + int match = 1, nomatch = 0; + + /* This will be used soon... */ + (void)flags; /* UNUSED */ + + /* If this is a negated class, return success for nomatch. */ + if ((*p == '!' || *p == '^') && p < end) { + match = 0; + nomatch = 1; + ++p; + } + + while (p < end) { + nextRangeStart = '\0'; + switch (*p) { + case '-': + /* Trailing or initial '-' is not special. */ + if ((rangeStart == '\0') || (p == end - 1)) { + if (*p == c) + return (match); + } else { + char rangeEnd = *++p; + if (rangeEnd == '\\') + rangeEnd = *++p; + if ((rangeStart <= c) && (c <= rangeEnd)) + return (match); + } + break; + case '\\': + ++p; + /* Fall through */ + default: + if (*p == c) + return (match); + nextRangeStart = *p; /* Possible start of range. */ + } + rangeStart = nextRangeStart; + ++p; + } + return (nomatch); +} + +static int +pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags) +{ + const wchar_t *p = start; + wchar_t rangeStart = L'\0', nextRangeStart; + int match = 1, nomatch = 0; + + /* This will be used soon... */ + (void)flags; /* UNUSED */ + + /* If this is a negated class, return success for nomatch. */ + if ((*p == L'!' || *p == L'^') && p < end) { + match = 0; + nomatch = 1; + ++p; + } + + while (p < end) { + nextRangeStart = L'\0'; + switch (*p) { + case L'-': + /* Trailing or initial '-' is not special. */ + if ((rangeStart == L'\0') || (p == end - 1)) { + if (*p == c) + return (match); + } else { + wchar_t rangeEnd = *++p; + if (rangeEnd == L'\\') + rangeEnd = *++p; + if ((rangeStart <= c) && (c <= rangeEnd)) + return (match); + } + break; + case L'\\': + ++p; + /* Fall through */ + default: + if (*p == c) + return (match); + nextRangeStart = *p; /* Possible start of range. */ + } + rangeStart = nextRangeStart; + ++p; + } + return (nomatch); +} + +/* + * If s is pointing to "./", ".//", "./././" or the like, skip it. + */ +static const char * +pm_slashskip(const char *s) { + while ((*s == '/') + || (s[0] == '.' && s[1] == '/') + || (s[0] == '.' && s[1] == '\0')) + ++s; + return (s); +} + +static const wchar_t * +pm_slashskip_w(const wchar_t *s) { + while ((*s == L'/') + || (s[0] == L'.' && s[1] == L'/') + || (s[0] == L'.' && s[1] == L'\0')) + ++s; + return (s); +} + +static int +pm(const char *p, const char *s, int flags) +{ + const char *end; + + /* + * Ignore leading './', './/', '././', etc. + */ + if (s[0] == '.' && s[1] == '/') + s = pm_slashskip(s + 1); + if (p[0] == '.' && p[1] == '/') + p = pm_slashskip(p + 1); + + for (;;) { + switch (*p) { + case '\0': + if (s[0] == '/') { + if (flags & PATHMATCH_NO_ANCHOR_END) + return (1); + /* "dir" == "dir/" == "dir/." */ + s = pm_slashskip(s); + } + return (*s == '\0'); + case '?': + /* ? always succeeds, unless we hit end of 's' */ + if (*s == '\0') + return (0); + break; + case '*': + /* "*" == "**" == "***" ... */ + while (*p == '*') + ++p; + /* Trailing '*' always succeeds. */ + if (*p == '\0') + return (1); + while (*s) { + if (archive_pathmatch(p, s, flags)) + return (1); + ++s; + } + return (0); + case '[': + /* + * Find the end of the [...] character class, + * ignoring \] that might occur within the class. + */ + end = p + 1; + while (*end != '\0' && *end != ']') { + if (*end == '\\' && end[1] != '\0') + ++end; + ++end; + } + if (*end == ']') { + /* We found [...], try to match it. */ + if (!pm_list(p + 1, end, *s, flags)) + return (0); + p = end; /* Jump to trailing ']' char. */ + break; + } else + /* No final ']', so just match '['. */ + if (*p != *s) + return (0); + break; + case '\\': + /* Trailing '\\' matches itself. */ + if (p[1] == '\0') { + if (*s != '\\') + return (0); + } else { + ++p; + if (*p != *s) + return (0); + } + break; + case '/': + if (*s != '/' && *s != '\0') + return (0); + /* Note: pattern "/\./" won't match "/"; + * pm_slashskip() correctly stops at backslash. */ + p = pm_slashskip(p); + s = pm_slashskip(s); + if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)) + return (1); + --p; /* Counteract the increment below. */ + --s; + break; + case '$': + /* '$' is special only at end of pattern and only + * if PATHMATCH_NO_ANCHOR_END is specified. */ + if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ + /* "dir" == "dir/" == "dir/." */ + return (*pm_slashskip(s) == '\0'); + } + /* Otherwise, '$' is not special. */ + /* FALL THROUGH */ + default: + if (*p != *s) + return (0); + break; + } + ++p; + ++s; + } +} + +static int +pm_w(const wchar_t *p, const wchar_t *s, int flags) +{ + const wchar_t *end; + + /* + * Ignore leading './', './/', '././', etc. + */ + if (s[0] == L'.' && s[1] == L'/') + s = pm_slashskip_w(s + 1); + if (p[0] == L'.' && p[1] == L'/') + p = pm_slashskip_w(p + 1); + + for (;;) { + switch (*p) { + case L'\0': + if (s[0] == L'/') { + if (flags & PATHMATCH_NO_ANCHOR_END) + return (1); + /* "dir" == "dir/" == "dir/." */ + s = pm_slashskip_w(s); + } + return (*s == L'\0'); + case L'?': + /* ? always succeeds, unless we hit end of 's' */ + if (*s == L'\0') + return (0); + break; + case L'*': + /* "*" == "**" == "***" ... */ + while (*p == L'*') + ++p; + /* Trailing '*' always succeeds. */ + if (*p == L'\0') + return (1); + while (*s) { + if (archive_pathmatch_w(p, s, flags)) + return (1); + ++s; + } + return (0); + case L'[': + /* + * Find the end of the [...] character class, + * ignoring \] that might occur within the class. + */ + end = p + 1; + while (*end != L'\0' && *end != L']') { + if (*end == L'\\' && end[1] != L'\0') + ++end; + ++end; + } + if (*end == L']') { + /* We found [...], try to match it. */ + if (!pm_list_w(p + 1, end, *s, flags)) + return (0); + p = end; /* Jump to trailing ']' char. */ + break; + } else + /* No final ']', so just match '['. */ + if (*p != *s) + return (0); + break; + case L'\\': + /* Trailing '\\' matches itself. */ + if (p[1] == L'\0') { + if (*s != L'\\') + return (0); + } else { + ++p; + if (*p != *s) + return (0); + } + break; + case L'/': + if (*s != L'/' && *s != L'\0') + return (0); + /* Note: pattern "/\./" won't match "/"; + * pm_slashskip() correctly stops at backslash. */ + p = pm_slashskip_w(p); + s = pm_slashskip_w(s); + if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)) + return (1); + --p; /* Counteract the increment below. */ + --s; + break; + case L'$': + /* '$' is special only at end of pattern and only + * if PATHMATCH_NO_ANCHOR_END is specified. */ + if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ + /* "dir" == "dir/" == "dir/." */ + return (*pm_slashskip_w(s) == L'\0'); + } + /* Otherwise, '$' is not special. */ + /* FALL THROUGH */ + default: + if (*p != *s) + return (0); + break; + } + ++p; + ++s; + } +} + +/* Main entry point. */ +int +__archive_pathmatch(const char *p, const char *s, int flags) +{ + /* Empty pattern only matches the empty string. */ + if (p == NULL || *p == '\0') + return (s == NULL || *s == '\0'); + + /* Leading '^' anchors the start of the pattern. */ + if (*p == '^') { + ++p; + flags &= ~PATHMATCH_NO_ANCHOR_START; + } + + if (*p == '/' && *s != '/') + return (0); + + /* Certain patterns anchor implicitly. */ + if (*p == '*' || *p == '/') { + while (*p == '/') + ++p; + while (*s == '/') + ++s; + return (pm(p, s, flags)); + } + + /* If start is unanchored, try to match start of each path element. */ + if (flags & PATHMATCH_NO_ANCHOR_START) { + for ( ; s != NULL; s = strchr(s, '/')) { + if (*s == '/') + s++; + if (pm(p, s, flags)) + return (1); + } + return (0); + } + + /* Default: Match from beginning. */ + return (pm(p, s, flags)); +} + +int +__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags) +{ + /* Empty pattern only matches the empty string. */ + if (p == NULL || *p == L'\0') + return (s == NULL || *s == L'\0'); + + /* Leading '^' anchors the start of the pattern. */ + if (*p == L'^') { + ++p; + flags &= ~PATHMATCH_NO_ANCHOR_START; + } + + if (*p == L'/' && *s != L'/') + return (0); + + /* Certain patterns anchor implicitly. */ + if (*p == L'*' || *p == L'/') { + while (*p == L'/') + ++p; + while (*s == L'/') + ++s; + return (pm_w(p, s, flags)); + } + + /* 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'/')) { + if (*s == L'/') + s++; + if (pm_w(p, s, flags)) + return (1); + } + return (0); + } + + /* Default: Match from beginning. */ + return (pm_w(p, s, flags)); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_pathmatch.h b/src/3rdparty/libarchive/libarchive/archive_pathmatch.h new file mode 100644 index 00000000..e6901774 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_pathmatch.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_PATHMATCH_H +#define ARCHIVE_PATHMATCH_H + +/* Don't anchor at beginning unless the pattern starts with "^" */ +#define PATHMATCH_NO_ANCHOR_START 1 +/* Don't anchor at end unless the pattern ends with "$" */ +#define PATHMATCH_NO_ANCHOR_END 2 + +/* Note that "^" and "$" are not special unless you set the corresponding + * flag above. */ + +int __archive_pathmatch(const char *p, const char *s, int flags); +int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags); + +#define archive_pathmatch(p, s, f) __archive_pathmatch(p, s, f) +#define archive_pathmatch_w(p, s, f) __archive_pathmatch_w(p, s, f) + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_platform.h b/src/3rdparty/libarchive/libarchive/archive_platform.h new file mode 100644 index 00000000..34be8eda --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_platform.h @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_platform.h 201090 2009-12-28 02:22:04Z kientzle $ + */ + +/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ + +/* + * This header is the first thing included in any of the libarchive + * source files. As far as possible, platform-specific issues should + * be dealt with here and not within individual source files. I'm + * actively trying to minimize #if blocks within the main source, + * since they obfuscate the code. + */ + +#ifndef ARCHIVE_PLATFORM_H_INCLUDED +#define ARCHIVE_PLATFORM_H_INCLUDED + +/* archive.h and archive_entry.h require this. */ +#define __LIBARCHIVE_BUILD 1 + +#if defined(PLATFORM_CONFIG_H) +/* Use hand-built config.h in environments that need it. */ +#include PLATFORM_CONFIG_H +#elif defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "config.h" +#else +/* Warn if the library hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no pre-built configuration in archive_platform.h. +#endif + +/* It should be possible to get rid of this by extending the feature-test + * macros to cover Windows API functions, probably along with non-trivial + * refactoring of code to find structures that sit more cleanly on top of + * either Windows or Posix APIs. */ +#if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__) +#include "archive_windows.h" +#endif + +/* + * The config files define a lot of feature macros. The following + * uses those macros to select/define replacements and include key + * headers as required. + */ + +/* Get a real definition for __FBSDID or __RCSID if we can */ +#if HAVE_SYS_CDEFS_H +#include +#endif + +/* If not, define them so as to avoid dangling semicolons. */ +#ifndef __FBSDID +#define __FBSDID(a) struct _undefined_hack +#endif +#ifndef __RCSID +#define __RCSID(a) struct _undefined_hack +#endif + +/* Try to get standard C99-style integer type definitions. */ +#if HAVE_INTTYPES_H +#include +#endif +#if HAVE_STDINT_H +#include +#endif + +/* Borland warns about its own constants! */ +#if defined(__BORLANDC__) +# if HAVE_DECL_UINT64_MAX +# undef UINT64_MAX +# undef HAVE_DECL_UINT64_MAX +# endif +# if HAVE_DECL_UINT64_MIN +# undef UINT64_MIN +# undef HAVE_DECL_UINT64_MIN +# endif +# if HAVE_DECL_INT64_MAX +# undef INT64_MAX +# undef HAVE_DECL_INT64_MAX +# endif +# if HAVE_DECL_INT64_MIN +# undef INT64_MIN +# undef HAVE_DECL_INT64_MIN +# endif +#endif + +/* Some platforms lack the standard *_MAX definitions. */ +#if !HAVE_DECL_SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif +#if !HAVE_DECL_SSIZE_MAX +#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1)) +#endif +#if !HAVE_DECL_UINT32_MAX +#define UINT32_MAX (~(uint32_t)0) +#endif +#if !HAVE_DECL_INT32_MAX +#define INT32_MAX ((int32_t)(UINT32_MAX >> 1)) +#endif +#if !HAVE_DECL_INT32_MIN +#define INT32_MIN ((int32_t)(~INT32_MAX)) +#endif +#if !HAVE_DECL_UINT64_MAX +#define UINT64_MAX (~(uint64_t)0) +#endif +#if !HAVE_DECL_INT64_MAX +#define INT64_MAX ((int64_t)(UINT64_MAX >> 1)) +#endif +#if !HAVE_DECL_INT64_MIN +#define INT64_MIN ((int64_t)(~INT64_MAX)) +#endif +#if !HAVE_DECL_UINTMAX_MAX +#define UINTMAX_MAX (~(uintmax_t)0) +#endif +#if !HAVE_DECL_INTMAX_MAX +#define INTMAX_MAX ((intmax_t)(UINTMAX_MAX >> 1)) +#endif +#if !HAVE_DECL_INTMAX_MIN +#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX)) +#endif + +/* + * If we can't restore metadata using a file descriptor, then + * for compatibility's sake, close files before trying to restore metadata. + */ +#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN) +#define CAN_RESTORE_METADATA_FD +#endif + +/* + * glibc 2.24 deprecates readdir_r + */ +#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) +#define USE_READDIR_R 1 +#else +#undef USE_READDIR_R +#endif + +/* Set up defaults for internal error codes. */ +#ifndef ARCHIVE_ERRNO_FILE_FORMAT +#if HAVE_EFTYPE +#define ARCHIVE_ERRNO_FILE_FORMAT EFTYPE +#else +#if HAVE_EILSEQ +#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ +#else +#define ARCHIVE_ERRNO_FILE_FORMAT EINVAL +#endif +#endif +#endif + +#ifndef ARCHIVE_ERRNO_PROGRAMMER +#define ARCHIVE_ERRNO_PROGRAMMER EINVAL +#endif + +#ifndef ARCHIVE_ERRNO_MISC +#define ARCHIVE_ERRNO_MISC (-1) +#endif + +#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_platform_acl.h b/src/3rdparty/libarchive/libarchive/archive_platform_acl.h new file mode 100644 index 00000000..3498f78b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_platform_acl.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ + +#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED +#define ARCHIVE_PLATFORM_ACL_H_INCLUDED + +/* + * Determine what ACL types are supported + */ +#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL +#define ARCHIVE_ACL_POSIX1E 1 +#endif + +#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \ + ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL +#define ARCHIVE_ACL_NFS4 1 +#endif + +#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4 +#define ARCHIVE_ACL_SUPPORT 1 +#endif + +#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_ppmd7.c b/src/3rdparty/libarchive/libarchive/archive_ppmd7.c new file mode 100644 index 00000000..1aed922d --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_ppmd7.c @@ -0,0 +1,1168 @@ +/* Ppmd7.c -- PPMdH codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "archive_platform.h" + +#include + +#include "archive_ppmd7_private.h" + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +#define kTopValue (1 << 24) +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; +static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +static void Ppmd7_Update1(CPpmd7 *p); +static void Ppmd7_Update1_0(CPpmd7 *p); +static void Ppmd7_Update2(CPpmd7 *p); +static void Ppmd7_UpdateBin(CPpmd7 *p); +static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, + UInt32 *scale); + +/* ----------- Base ----------- */ + +static void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while(--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +static void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + /* RestartModel() below assumes that p->Size >= UNIT_SIZE + (see the calculation of m->MinContext). */ + if (size < UNIT_SIZE) { + return False; + } + Ppmd7_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + )) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + while (numPs != 0) + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +static void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +static void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +static void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +static void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} + +/* ---------- Decode ---------- */ + +static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Low = p->Bottom = 0; + p->Range = 0xFFFFFFFF; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + if (p->Stream->Read((void *)p->Stream) != 0) + return False; + return Ppmd_RangeDec_Init(p); +} + +static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + if (!Ppmd_RangeDec_Init(p)) + return False; + p->Bottom = 0x8000; + return True; +} + +static UInt32 Range_GetThreshold(void *pp, UInt32 total) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + return (p->Code - p->Low) / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + while (1) + { + if((p->Low ^ (p->Low + p->Range)) >= kTopValue) + { + if(p->Range >= p->Bottom) + break; + else + p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1); + } + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + p->Low <<= 8; + } +} + +static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Low += start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE); + if(value < size0) + { + bit = 0; + p->p.Decode(p, 0, size0); + } + else + { + bit = 1; + p->p.Decode(p, size0, PPMD_BIN_SCALE - size0); + } + return bit; +} + +static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode_7z; + p->p.DecodeBit = Range_DecodeBit_7z; +} + +static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode_RAR; + p->p.DecodeBit = Range_DecodeBit_RAR; +} + +#define MASK(sym) ((signed char *)charMask)[sym] + +static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} + +/* ---------- Encode ---------- Ppmd7Enc.c */ + +#define kTopValue (1 << 24) + +static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) +{ + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Cache = 0; + p->CacheSize = 1; +} + +static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) +{ + if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) + { + Byte temp = p->Cache; + do + { + p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); + temp = 0xFF; + } + while(--p->CacheSize != 0); + p->Cache = (Byte)((UInt32)p->Low >> 24); + } + p->CacheSize++; + p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF; +} + +static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + p->Range = (p->Range >> 14) * size0; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + UInt32 newBound = (p->Range >> 14) * size0; + p->Low += newBound; + p->Range -= newBound; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd7_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd7_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} + +const IPpmd7 __archive_ppmd7_functions = +{ + &Ppmd7_Construct, + &Ppmd7_Alloc, + &Ppmd7_Free, + &Ppmd7_Init, + &Ppmd7z_RangeDec_CreateVTable, + &PpmdRAR_RangeDec_CreateVTable, + &Ppmd7z_RangeDec_Init, + &PpmdRAR_RangeDec_Init, + &Ppmd7_DecodeSymbol, + &Ppmd7z_RangeEnc_Init, + &Ppmd7z_RangeEnc_FlushData, + &Ppmd7_EncodeSymbol +}; diff --git a/src/3rdparty/libarchive/libarchive/archive_ppmd7_private.h b/src/3rdparty/libarchive/libarchive/archive_ppmd7_private.h new file mode 100644 index 00000000..06c99e82 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_ppmd7_private.h @@ -0,0 +1,119 @@ +/* Ppmd7.h -- PPMdH compression codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED +#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED + +#include "archive_ppmd_private.h" + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +/* ---------- Decode ---------- */ + +typedef struct +{ + UInt32 (*GetThreshold)(void *p, UInt32 total); + void (*Decode)(void *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void *p, UInt32 size0); +} IPpmd7_RangeDec; + +typedef struct +{ + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + UInt32 Low; + UInt32 Bottom; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +typedef struct +{ + /* Base Functions */ + void (*Ppmd7_Construct)(CPpmd7 *p); + Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); + void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc); + void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder); + #define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + /* Decode Functions */ + void (*Ppmd7z_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p); + void (*PpmdRAR_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p); + Bool (*Ppmd7z_RangeDec_Init)(CPpmd7z_RangeDec *p); + Bool (*PpmdRAR_RangeDec_Init)(CPpmd7z_RangeDec *p); + #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + int (*Ppmd7_DecodeSymbol)(CPpmd7 *p, IPpmd7_RangeDec *rc); + + /* Encode Functions */ + void (*Ppmd7z_RangeEnc_Init)(CPpmd7z_RangeEnc *p); + void (*Ppmd7z_RangeEnc_FlushData)(CPpmd7z_RangeEnc *p); + + void (*Ppmd7_EncodeSymbol)(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); +} IPpmd7; + +extern const IPpmd7 __archive_ppmd7_functions; +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_ppmd_private.h b/src/3rdparty/libarchive/libarchive/archive_ppmd_private.h new file mode 100644 index 00000000..e78bde59 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_ppmd_private.h @@ -0,0 +1,158 @@ +/* Ppmd.h -- PPMD codec common code +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED +#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED + +#include + +#include "archive_read_private.h" + +/*** Begin defined in Types.h ***/ + +#if !defined(ZCONF_H) +typedef unsigned char Byte; +#endif +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +typedef int Bool; +#define True 1 +#define False 0 + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + struct archive_read *a; + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + struct archive_write *a; + void (*Write)(void *p, Byte b); +} IByteOut; + + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +/*** End defined in Types.h ***/ +/*** Begin defined in CpuArch.h ***/ + +#if defined(_M_IX86) || defined(__i386__) +#define MY_CPU_X86 +#endif + +#if defined(MY_CPU_X86) || defined(_M_ARM) +#define MY_CPU_32BIT +#endif + +#ifdef MY_CPU_32BIT +#define PPMD_32BIT +#endif + +/*** End defined in CpuArch.h ***/ + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \ + p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }} + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_private.h b/src/3rdparty/libarchive/libarchive/archive_private.h new file mode 100644 index 00000000..4b4be979 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_private.h @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_private.h 201098 2009-12-28 02:58:14Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_PRIVATE_H_INCLUDED +#define ARCHIVE_PRIVATE_H_INCLUDED + +#if HAVE_ICONV_H +#include +#endif + +#include "archive.h" +#include "archive_string.h" + +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) +#define __LA_DEAD __attribute__((__noreturn__)) +#else +#define __LA_DEAD +#endif + +#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU) +#define ARCHIVE_READ_MAGIC (0xdeb0c5U) +#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U) +#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) +#define ARCHIVE_MATCH_MAGIC (0xcad11c9U) + +#define ARCHIVE_STATE_NEW 1U +#define ARCHIVE_STATE_HEADER 2U +#define ARCHIVE_STATE_DATA 4U +#define ARCHIVE_STATE_EOF 0x10U +#define ARCHIVE_STATE_CLOSED 0x20U +#define ARCHIVE_STATE_FATAL 0x8000U +#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL) + +struct archive_vtable { + int (*archive_close)(struct archive *); + int (*archive_free)(struct archive *); + int (*archive_write_header)(struct archive *, + struct archive_entry *); + int (*archive_write_finish_entry)(struct archive *); + ssize_t (*archive_write_data)(struct archive *, + const void *, size_t); + ssize_t (*archive_write_data_block)(struct archive *, + const void *, size_t, int64_t); + + int (*archive_read_next_header)(struct archive *, + struct archive_entry **); + int (*archive_read_next_header2)(struct archive *, + struct archive_entry *); + int (*archive_read_data_block)(struct archive *, + const void **, size_t *, int64_t *); + + int (*archive_filter_count)(struct archive *); + int64_t (*archive_filter_bytes)(struct archive *, int); + int (*archive_filter_code)(struct archive *, int); + const char * (*archive_filter_name)(struct archive *, int); +}; + +struct archive_string_conv; + +struct archive { + /* + * The magic/state values are used to sanity-check the + * client's usage. If an API function is called at a + * ridiculous time, or the client passes us an invalid + * pointer, these values allow me to catch that. + */ + unsigned int magic; + unsigned int state; + + /* + * Some public API functions depend on the "real" type of the + * archive object. + */ + struct archive_vtable *vtable; + + int archive_format; + const char *archive_format_name; + + int compression_code; /* Currently active compression. */ + const char *compression_name; + + /* Number of file entries processed. */ + int file_count; + + int archive_error_number; + const char *error; + struct archive_string error_string; + + char *current_code; + unsigned current_codepage; /* Current ACP(ANSI CodePage). */ + unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */ + struct archive_string_conv *sconv; + + /* + * Used by archive_read_data() to track blocks and copy + * data to client buffers, filling gaps with zero bytes. + */ + const char *read_data_block; + int64_t read_data_offset; + int64_t read_data_output_offset; + size_t read_data_remaining; + + /* + * Used by formats/filters to determine the amount of data + * requested from a call to archive_read_data(). This is only + * useful when the format/filter has seek support. + */ + char read_data_is_posix_read; + size_t read_data_requested; +}; + +/* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */ +int __archive_check_magic(struct archive *, unsigned int magic, + unsigned int state, const char *func); +#define archive_check_magic(a, expected_magic, allowed_states, function_name) \ + do { \ + int magic_test = __archive_check_magic((a), (expected_magic), \ + (allowed_states), (function_name)); \ + if (magic_test == ARCHIVE_FATAL) \ + return ARCHIVE_FATAL; \ + } while (0) + +void __archive_errx(int retvalue, const char *msg) __LA_DEAD; + +void __archive_ensure_cloexec_flag(int fd); +int __archive_mktemp(const char *tmpdir); + +int __archive_clean(struct archive *); + +void __archive_reset_read_data(struct archive *); + +#define err_combine(a,b) ((a) < (b) ? (a) : (b)) + +#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300) +# define ARCHIVE_LITERAL_LL(x) x##i64 +# define ARCHIVE_LITERAL_ULL(x) x##ui64 +#else +# define ARCHIVE_LITERAL_LL(x) x##ll +# define ARCHIVE_LITERAL_ULL(x) x##ull +#endif + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_random.c b/src/3rdparty/libarchive/libarchive/archive_random.c new file mode 100644 index 00000000..65ea6915 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_random.c @@ -0,0 +1,272 @@ +/*- + * Copyright (c) 2014 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_STDLIB_H +#include +#endif + +#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) + +#ifdef HAVE_FCNTL +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_PTHREAD_H +#include +#endif + +static void arc4random_buf(void *, size_t); + +#endif /* HAVE_ARC4RANDOM_BUF */ + +#include "archive.h" +#include "archive_random_private.h" + +#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) +#include +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* + * Random number generator function. + * This simply calls arc4random_buf function if the platform provides it. + */ + +int +archive_random(void *buf, size_t nbytes) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + HCRYPTPROV hProv; + BOOL success; + + success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) { + success = CryptAcquireContext(&hProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + } + if (success) { + success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf); + CryptReleaseContext(hProv, 0); + if (success) + return ARCHIVE_OK; + } + /* TODO: Does this case really happen? */ + return ARCHIVE_FAILED; +#else + arc4random_buf(buf, nbytes); + return ARCHIVE_OK; +#endif +} + +#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) + +/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ +/* + * Copyright (c) 1996, David Mazieres + * Copyright (c) 2008, Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Arc4 random number generator for OpenBSD. + * + * This code is derived from section 17.1 of Applied Cryptography, + * second edition, which describes a stream cipher allegedly + * compatible with RSA Labs "RC4" cipher (the actual description of + * which is a trade secret). The same algorithm is used as a stream + * cipher called "arcfour" in Tatu Ylonen's ssh package. + * + * RC4 is a registered trademark of RSA Laboratories. + */ + +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +struct arc4_stream { + uint8_t i; + uint8_t j; + uint8_t s[256]; +}; + +#define RANDOMDEV "/dev/urandom" +#define KEYSIZE 128 +#ifdef HAVE_PTHREAD_H +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx); +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx); +#else +#define _ARC4_LOCK() +#define _ARC4_UNLOCK() +#endif + +static int rs_initialized; +static struct arc4_stream rs; +static pid_t arc4_stir_pid; +static int arc4_count; + +static inline uint8_t arc4_getbyte(void); +static void arc4_stir(void); + +static inline void +arc4_init(void) +{ + int n; + + for (n = 0; n < 256; n++) + rs.s[n] = n; + rs.i = 0; + rs.j = 0; +} + +static inline void +arc4_addrandom(u_char *dat, int datlen) +{ + int n; + uint8_t si; + + rs.i--; + for (n = 0; n < 256; n++) { + rs.i = (rs.i + 1); + si = rs.s[rs.i]; + rs.j = (rs.j + si + dat[n % datlen]); + rs.s[rs.i] = rs.s[rs.j]; + rs.s[rs.j] = si; + } + rs.j = rs.i; +} + +static void +arc4_stir(void) +{ + int done, fd, i; + struct { + struct timeval tv; + pid_t pid; + u_char rnd[KEYSIZE]; + } rdat; + + if (!rs_initialized) { + arc4_init(); + rs_initialized = 1; + } + done = 0; + fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); + if (fd >= 0) { + if (read(fd, &rdat, KEYSIZE) == KEYSIZE) + done = 1; + (void)close(fd); + } + if (!done) { + (void)gettimeofday(&rdat.tv, NULL); + rdat.pid = getpid(); + /* We'll just take whatever was on the stack too... */ + } + + arc4_addrandom((u_char *)&rdat, KEYSIZE); + + /* + * Discard early keystream, as per recommendations in: + * "(Not So) Random Shuffles of RC4" by Ilya Mironov. + * As per the Network Operations Division, cryptographic requirements + * published on wikileaks on March 2017. + */ + + for (i = 0; i < 3072; i++) + (void)arc4_getbyte(); + arc4_count = 1600000; +} + +static void +arc4_stir_if_needed(void) +{ + pid_t pid = getpid(); + + if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { + arc4_stir_pid = pid; + arc4_stir(); + } +} + +static inline uint8_t +arc4_getbyte(void) +{ + uint8_t si, sj; + + rs.i = (rs.i + 1); + si = rs.s[rs.i]; + rs.j = (rs.j + si); + sj = rs.s[rs.j]; + rs.s[rs.i] = sj; + rs.s[rs.j] = si; + return (rs.s[(si + sj) & 0xff]); +} + +static void +arc4random_buf(void *_buf, size_t n) +{ + u_char *buf = (u_char *)_buf; + _ARC4_LOCK(); + arc4_stir_if_needed(); + while (n--) { + if (--arc4_count <= 0) + arc4_stir(); + buf[n] = arc4_getbyte(); + } + _ARC4_UNLOCK(); +} + +#endif /* !HAVE_ARC4RANDOM_BUF */ diff --git a/src/3rdparty/libarchive/libarchive/archive_random_private.h b/src/3rdparty/libarchive/libarchive/archive_random_private.h new file mode 100644 index 00000000..c414779f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_random_private.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2014 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_RANDOM_PRIVATE_H_INCLUDED +#define ARCHIVE_RANDOM_PRIVATE_H_INCLUDED + +/* Random number generator. */ +int archive_random(void *buf, size_t nbytes); + +#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_rb.c b/src/3rdparty/libarchive/libarchive/archive_rb.c new file mode 100644 index 00000000..cf58ac33 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_rb.c @@ -0,0 +1,709 @@ +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Based on: NetBSD: rb.c,v 1.6 2010/04/30 13:58:09 joerg Exp + */ + +#include "archive_platform.h" + +#include + +#include "archive_rb.h" + +/* Keep in sync with archive_rb.h */ +#define RB_DIR_LEFT 0 +#define RB_DIR_RIGHT 1 +#define RB_DIR_OTHER 1 +#define rb_left rb_nodes[RB_DIR_LEFT] +#define rb_right rb_nodes[RB_DIR_RIGHT] + +#define RB_FLAG_POSITION 0x2 +#define RB_FLAG_RED 0x1 +#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED) +#define RB_FATHER(rb) \ + ((struct archive_rb_node *)((rb)->rb_info & ~RB_FLAG_MASK)) +#define RB_SET_FATHER(rb, father) \ + ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK))) + +#define RB_SENTINEL_P(rb) ((rb) == NULL) +#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left) +#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right) +#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb))) +#define RB_CHILDLESS_P(rb) \ + (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb))) +#define RB_TWOCHILDREN_P(rb) \ + (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb)) + +#define RB_POSITION(rb) \ + (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT) +#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT) +#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT) +#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0) +#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0) +#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED)) +#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED)) +#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED)) +#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb)) +#define RB_SET_POSITION(rb, position) \ + ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \ + ((rb)->rb_info &= ~RB_FLAG_POSITION))) +#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK)) +#define RB_COPY_PROPERTIES(dst, src) \ + ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK)) +#define RB_SWAP_PROPERTIES(a, b) do { \ + uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \ + (a)->rb_info ^= xorinfo; \ + (b)->rb_info ^= xorinfo; \ + } while (/*CONSTCOND*/ 0) + +static void __archive_rb_tree_insert_rebalance(struct archive_rb_tree *, + struct archive_rb_node *); +static void __archive_rb_tree_removal_rebalance(struct archive_rb_tree *, + struct archive_rb_node *, unsigned int); + +#define RB_SENTINEL_NODE NULL + +#define T 1 +#define F 0 + +void +__archive_rb_tree_init(struct archive_rb_tree *rbt, + const struct archive_rb_tree_ops *ops) +{ + rbt->rbt_ops = ops; + *((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE; +} + +struct archive_rb_node * +__archive_rb_tree_find_node(struct archive_rb_tree *rbt, const void *key) +{ + archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct archive_rb_node *parent = rbt->rbt_root; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + parent = parent->rb_nodes[diff > 0]; + } + + return NULL; +} + +struct archive_rb_node * +__archive_rb_tree_find_node_geq(struct archive_rb_tree *rbt, const void *key) +{ + archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct archive_rb_node *parent = rbt->rbt_root; + struct archive_rb_node *last = NULL; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + if (diff < 0) + last = parent; + parent = parent->rb_nodes[diff > 0]; + } + + return last; +} + +struct archive_rb_node * +__archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key) +{ + archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct archive_rb_node *parent = rbt->rbt_root; + struct archive_rb_node *last = NULL; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + if (diff > 0) + last = parent; + parent = parent->rb_nodes[diff > 0]; + } + + return last; +} + +int +__archive_rb_tree_insert_node(struct archive_rb_tree *rbt, + struct archive_rb_node *self) +{ + archive_rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes; + struct archive_rb_node *parent, *tmp; + unsigned int position; + int rebalance; + + tmp = rbt->rbt_root; + /* + * This is a hack. Because rbt->rbt_root is just a + * struct archive_rb_node *, just like rb_node->rb_nodes[RB_DIR_LEFT], + * we can use this fact to avoid a lot of tests for root and know + * that even at root, updating + * RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will + * update rbt->rbt_root. + */ + parent = (struct archive_rb_node *)(void *)&rbt->rbt_root; + position = RB_DIR_LEFT; + + /* + * Find out where to place this new leaf. + */ + while (!RB_SENTINEL_P(tmp)) { + const signed int diff = (*compare_nodes)(tmp, self); + if (diff == 0) { + /* + * Node already exists; don't insert. + */ + return F; + } + parent = tmp; + position = (diff > 0); + tmp = parent->rb_nodes[position]; + } + + /* + * Initialize the node and insert as a leaf into the tree. + */ + RB_SET_FATHER(self, parent); + RB_SET_POSITION(self, position); + if (parent == (struct archive_rb_node *)(void *)&rbt->rbt_root) { + RB_MARK_BLACK(self); /* root is always black */ + rebalance = F; + } else { + /* + * All new nodes are colored red. We only need to rebalance + * if our parent is also red. + */ + RB_MARK_RED(self); + rebalance = RB_RED_P(parent); + } + self->rb_left = parent->rb_nodes[position]; + self->rb_right = parent->rb_nodes[position]; + parent->rb_nodes[position] = self; + + /* + * Rebalance tree after insertion + */ + if (rebalance) + __archive_rb_tree_insert_rebalance(rbt, self); + + return T; +} + +/* + * Swap the location and colors of 'self' and its child @ which. The child + * can not be a sentinel node. This is our rotation function. However, + * since it preserves coloring, it great simplifies both insertion and + * removal since rotation almost always involves the exchanging of colors + * as a separate step. + */ +/*ARGSUSED*/ +static void +__archive_rb_tree_reparent_nodes( + struct archive_rb_node *old_father, const unsigned int which) +{ + const unsigned int other = which ^ RB_DIR_OTHER; + struct archive_rb_node * const grandpa = RB_FATHER(old_father); + struct archive_rb_node * const old_child = old_father->rb_nodes[which]; + struct archive_rb_node * const new_father = old_child; + struct archive_rb_node * const new_child = old_father; + + if (new_father == NULL) + return; + /* + * Exchange descendant linkages. + */ + grandpa->rb_nodes[RB_POSITION(old_father)] = new_father; + new_child->rb_nodes[which] = old_child->rb_nodes[other]; + new_father->rb_nodes[other] = new_child; + + /* + * Update ancestor linkages + */ + RB_SET_FATHER(new_father, grandpa); + RB_SET_FATHER(new_child, new_father); + + /* + * Exchange properties between new_father and new_child. The only + * change is that new_child's position is now on the other side. + */ + RB_SWAP_PROPERTIES(new_father, new_child); + RB_SET_POSITION(new_child, other); + + /* + * Make sure to reparent the new child to ourself. + */ + if (!RB_SENTINEL_P(new_child->rb_nodes[which])) { + RB_SET_FATHER(new_child->rb_nodes[which], new_child); + RB_SET_POSITION(new_child->rb_nodes[which], which); + } + +} + +static void +__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt, + struct archive_rb_node *self) +{ + struct archive_rb_node * father = RB_FATHER(self); + struct archive_rb_node * grandpa; + struct archive_rb_node * uncle; + unsigned int which; + unsigned int other; + + for (;;) { + /* + * We are red and our parent is red, therefore we must have a + * grandfather and he must be black. + */ + grandpa = RB_FATHER(father); + which = (father == grandpa->rb_right); + other = which ^ RB_DIR_OTHER; + uncle = grandpa->rb_nodes[other]; + + if (RB_BLACK_P(uncle)) + break; + + /* + * Case 1: our uncle is red + * Simply invert the colors of our parent and + * uncle and make our grandparent red. And + * then solve the problem up at his level. + */ + RB_MARK_BLACK(uncle); + RB_MARK_BLACK(father); + if (RB_ROOT_P(rbt, grandpa)) { + /* + * If our grandpa is root, don't bother + * setting him to red, just return. + */ + return; + } + RB_MARK_RED(grandpa); + self = grandpa; + father = RB_FATHER(self); + if (RB_BLACK_P(father)) { + /* + * If our great-grandpa is black, we're done. + */ + return; + } + } + + /* + * Case 2&3: our uncle is black. + */ + if (self == father->rb_nodes[other]) { + /* + * Case 2: we are on the same side as our uncle + * Swap ourselves with our parent so this case + * becomes case 3. Basically our parent becomes our + * child. + */ + __archive_rb_tree_reparent_nodes(father, other); + } + /* + * Case 3: we are opposite a child of a black uncle. + * Swap our parent and grandparent. Since our grandfather + * is black, our father will become black and our new sibling + * (former grandparent) will become red. + */ + __archive_rb_tree_reparent_nodes(grandpa, which); + + /* + * Final step: Set the root to black. + */ + RB_MARK_BLACK(rbt->rbt_root); +} + +static void +__archive_rb_tree_prune_node(struct archive_rb_tree *rbt, + struct archive_rb_node *self, int rebalance) +{ + const unsigned int which = RB_POSITION(self); + struct archive_rb_node *father = RB_FATHER(self); + + /* + * Since we are childless, we know that self->rb_left is pointing + * to the sentinel node. + */ + father->rb_nodes[which] = self->rb_left; + + /* + * Rebalance if requested. + */ + if (rebalance) + __archive_rb_tree_removal_rebalance(rbt, father, which); +} + +/* + * When deleting an interior node + */ +static void +__archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt, + struct archive_rb_node *self, struct archive_rb_node *standin) +{ + const unsigned int standin_which = RB_POSITION(standin); + unsigned int standin_other = standin_which ^ RB_DIR_OTHER; + struct archive_rb_node *standin_son; + struct archive_rb_node *standin_father = RB_FATHER(standin); + int rebalance = RB_BLACK_P(standin); + + if (standin_father == self) { + /* + * As a child of self, any children would be opposite of + * our parent. + */ + standin_son = standin->rb_nodes[standin_which]; + } else { + /* + * Since we aren't a child of self, any children would be + * on the same side as our parent. + */ + standin_son = standin->rb_nodes[standin_other]; + } + + if (RB_RED_P(standin_son)) { + /* + * We know we have a red child so if we flip it to black + * we don't have to rebalance. + */ + RB_MARK_BLACK(standin_son); + rebalance = F; + + if (standin_father != self) { + /* + * Change the son's parentage to point to his grandpa. + */ + RB_SET_FATHER(standin_son, standin_father); + RB_SET_POSITION(standin_son, standin_which); + } + } + + if (standin_father == self) { + /* + * If we are about to delete the standin's father, then when + * we call rebalance, we need to use ourselves as our father. + * Otherwise remember our original father. Also, since we are + * our standin's father we only need to reparent the standin's + * brother. + * + * | R --> S | + * | Q S --> Q T | + * | t --> | + * + * Have our son/standin adopt his brother as his new son. + */ + standin_father = standin; + } else { + /* + * | R --> S . | + * | / \ | T --> / \ | / | + * | ..... | S --> ..... | T | + * + * Sever standin's connection to his father. + */ + standin_father->rb_nodes[standin_which] = standin_son; + /* + * Adopt the far son. + */ + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + /* + * Use standin_other because we need to preserve standin_which + * for the removal_rebalance. + */ + standin_other = standin_which; + } + + /* + * Move the only remaining son to our standin. If our standin is our + * son, this will be the only son needed to be moved. + */ + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + + /* + * Now copy the result of self to standin and then replace + * self with standin in the tree. + */ + RB_COPY_PROPERTIES(standin, self); + RB_SET_FATHER(standin, RB_FATHER(self)); + RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin; + + if (rebalance) + __archive_rb_tree_removal_rebalance(rbt, standin_father, standin_which); +} + +/* + * We could do this by doing + * __archive_rb_tree_node_swap(rbt, self, which); + * __archive_rb_tree_prune_node(rbt, self, F); + * + * But it's more efficient to just evaluate and recolor the child. + */ +static void +__archive_rb_tree_prune_blackred_branch( + struct archive_rb_node *self, unsigned int which) +{ + struct archive_rb_node *father = RB_FATHER(self); + struct archive_rb_node *son = self->rb_nodes[which]; + + /* + * Remove ourselves from the tree and give our former child our + * properties (position, color, root). + */ + RB_COPY_PROPERTIES(son, self); + father->rb_nodes[RB_POSITION(son)] = son; + RB_SET_FATHER(son, father); +} +/* + * + */ +void +__archive_rb_tree_remove_node(struct archive_rb_tree *rbt, + struct archive_rb_node *self) +{ + struct archive_rb_node *standin; + unsigned int which; + + /* + * In the following diagrams, we (the node to be removed) are S. Red + * nodes are lowercase. T could be either red or black. + * + * Remember the major axiom of the red-black tree: the number of + * black nodes from the root to each leaf is constant across all + * leaves, only the number of red nodes varies. + * + * Thus removing a red leaf doesn't require any other changes to a + * red-black tree. So if we must remove a node, attempt to rearrange + * the tree so we can remove a red node. + * + * The simplest case is a childless red node or a childless root node: + * + * | T --> T | or | R --> * | + * | s --> * | + */ + if (RB_CHILDLESS_P(self)) { + const int rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self); + __archive_rb_tree_prune_node(rbt, self, rebalance); + return; + } + if (!RB_TWOCHILDREN_P(self)) { + /* + * The next simplest case is the node we are deleting is + * black and has one red child. + * + * | T --> T --> T | + * | S --> R --> R | + * | r --> s --> * | + */ + which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT; + __archive_rb_tree_prune_blackred_branch(self, which); + return; + } + + /* + * We invert these because we prefer to remove from the inside of + * the tree. + */ + which = RB_POSITION(self) ^ RB_DIR_OTHER; + + /* + * Let's find the node closes to us opposite of our parent + * Now swap it with ourself, "prune" it, and rebalance, if needed. + */ + standin = __archive_rb_tree_iterate(rbt, self, which); + __archive_rb_tree_swap_prune_and_rebalance(rbt, self, standin); +} + +static void +__archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt, + struct archive_rb_node *parent, unsigned int which) +{ + + while (RB_BLACK_P(parent->rb_nodes[which])) { + unsigned int other = which ^ RB_DIR_OTHER; + struct archive_rb_node *brother = parent->rb_nodes[other]; + + if (brother == NULL) + return;/* The tree may be broken. */ + /* + * For cases 1, 2a, and 2b, our brother's children must + * be black and our father must be black + */ + if (RB_BLACK_P(parent) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)) { + if (RB_RED_P(brother)) { + /* + * Case 1: Our brother is red, swap its + * position (and colors) with our parent. + * This should now be case 2b (unless C or E + * has a red child which is case 3; thus no + * explicit branch to case 2b). + * + * B -> D + * A d -> b E + * C E -> A C + */ + __archive_rb_tree_reparent_nodes(parent, other); + brother = parent->rb_nodes[other]; + if (brother == NULL) + return;/* The tree may be broken. */ + } else { + /* + * Both our parent and brother are black. + * Change our brother to red, advance up rank + * and go through the loop again. + * + * B -> *B + * *A D -> A d + * C E -> C E + */ + RB_MARK_RED(brother); + if (RB_ROOT_P(rbt, parent)) + return; /* root == parent == black */ + which = RB_POSITION(parent); + parent = RB_FATHER(parent); + continue; + } + } + /* + * Avoid an else here so that case 2a above can hit either + * case 2b, 3, or 4. + */ + if (RB_RED_P(parent) + && RB_BLACK_P(brother) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)) { + /* + * We are black, our father is red, our brother and + * both nephews are black. Simply invert/exchange the + * colors of our father and brother (to black and red + * respectively). + * + * | f --> F | + * | * B --> * b | + * | N N --> N N | + */ + RB_MARK_BLACK(parent); + RB_MARK_RED(brother); + break; /* We're done! */ + } else { + /* + * Our brother must be black and have at least one + * red child (it may have two). + */ + if (RB_BLACK_P(brother->rb_nodes[other])) { + /* + * Case 3: our brother is black, our near + * nephew is red, and our far nephew is black. + * Swap our brother with our near nephew. + * This result in a tree that matches case 4. + * (Our father could be red or black). + * + * | F --> F | + * | x B --> x B | + * | n --> n | + */ + __archive_rb_tree_reparent_nodes(brother, which); + brother = parent->rb_nodes[other]; + } + /* + * Case 4: our brother is black and our far nephew + * is red. Swap our father and brother locations and + * change our far nephew to black. (these can be + * done in either order so we change the color first). + * The result is a valid red-black tree and is a + * terminal case. (again we don't care about the + * father's color) + * + * If the father is red, we will get a red-black-black + * tree: + * | f -> f --> b | + * | B -> B --> F N | + * | n -> N --> | + * + * If the father is black, we will get an all black + * tree: + * | F -> F --> B | + * | B -> B --> F N | + * | n -> N --> | + * + * If we had two red nephews, then after the swap, + * our former father would have a red grandson. + */ + if (brother->rb_nodes[other] == NULL) + return;/* The tree may be broken. */ + RB_MARK_BLACK(brother->rb_nodes[other]); + __archive_rb_tree_reparent_nodes(parent, other); + break; /* We're done! */ + } + } +} + +struct archive_rb_node * +__archive_rb_tree_iterate(struct archive_rb_tree *rbt, + struct archive_rb_node *self, const unsigned int direction) +{ + const unsigned int other = direction ^ RB_DIR_OTHER; + + if (self == NULL) { + self = rbt->rbt_root; + if (RB_SENTINEL_P(self)) + return NULL; + while (!RB_SENTINEL_P(self->rb_nodes[direction])) + self = self->rb_nodes[direction]; + return self; + } + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(rbt, self)) { + if (other == (unsigned int)RB_POSITION(self)) + return RB_FATHER(self); + self = RB_FATHER(self); + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_rb.h b/src/3rdparty/libarchive/libarchive/archive_rb.h new file mode 100644 index 00000000..4562e9eb --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_rb.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Based on NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp + */ +#ifndef ARCHIVE_RB_H_ +#define ARCHIVE_RB_H_ + +struct archive_rb_node { + struct archive_rb_node *rb_nodes[2]; + /* + * rb_info contains the two flags and the parent back pointer. + * We put the two flags in the low two bits since we know that + * rb_node will have an alignment of 4 or 8 bytes. + */ + uintptr_t rb_info; +}; + +#define ARCHIVE_RB_DIR_LEFT 0 +#define ARCHIVE_RB_DIR_RIGHT 1 + +#define ARCHIVE_RB_TREE_MIN(T) \ + __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_LEFT) +#define ARCHIVE_RB_TREE_MAX(T) \ + __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_RIGHT) +#define ARCHIVE_RB_TREE_FOREACH(N, T) \ + for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \ + (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT)) +#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \ + for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \ + (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT)) + +/* + * archive_rbto_compare_nodes_fn: + * return a positive value if the first node < the second node. + * return a negative value if the first node > the second node. + * return 0 if they are considered same. + * + * archive_rbto_compare_key_fn: + * return a positive value if the node < the key. + * return a negative value if the node > the key. + * return 0 if they are considered same. + */ + +typedef signed int (*const archive_rbto_compare_nodes_fn)(const struct archive_rb_node *, + const struct archive_rb_node *); +typedef signed int (*const archive_rbto_compare_key_fn)(const struct archive_rb_node *, + const void *); + +struct archive_rb_tree_ops { + archive_rbto_compare_nodes_fn rbto_compare_nodes; + archive_rbto_compare_key_fn rbto_compare_key; +}; + +struct archive_rb_tree { + struct archive_rb_node *rbt_root; + const struct archive_rb_tree_ops *rbt_ops; +}; + +void __archive_rb_tree_init(struct archive_rb_tree *, + const struct archive_rb_tree_ops *); +int __archive_rb_tree_insert_node(struct archive_rb_tree *, + struct archive_rb_node *); +struct archive_rb_node * + __archive_rb_tree_find_node(struct archive_rb_tree *, const void *); +struct archive_rb_node * + __archive_rb_tree_find_node_geq(struct archive_rb_tree *, const void *); +struct archive_rb_node * + __archive_rb_tree_find_node_leq(struct archive_rb_tree *, const void *); +void __archive_rb_tree_remove_node(struct archive_rb_tree *, struct archive_rb_node *); +struct archive_rb_node * + __archive_rb_tree_iterate(struct archive_rb_tree *, + struct archive_rb_node *, const unsigned int); + +#endif /* ARCHIVE_RB_H_*/ diff --git a/src/3rdparty/libarchive/libarchive/archive_read.c b/src/3rdparty/libarchive/libarchive/archive_read.c new file mode 100644 index 00000000..a642a336 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read.c @@ -0,0 +1,1739 @@ +/*- + * Copyright (c) 2003-2011 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the "essential" portions of the read API, that + * is, stuff that will probably always be used by any client that + * actually needs to read an archive. Optional pieces have been, as + * far as possible, separated out into separate files to avoid + * needlessly bloating statically-linked clients. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:23Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_private.h" + +#define minimum(a, b) (a < b ? a : b) + +static int choose_filters(struct archive_read *); +static int choose_format(struct archive_read *); +static int close_filters(struct archive_read *); +static struct archive_vtable *archive_read_vtable(void); +static int64_t _archive_filter_bytes(struct archive *, int); +static int _archive_filter_code(struct archive *, int); +static const char *_archive_filter_name(struct archive *, int); +static int _archive_filter_count(struct archive *); +static int _archive_read_close(struct archive *); +static int _archive_read_data_block(struct archive *, + const void **, size_t *, int64_t *); +static int _archive_read_free(struct archive *); +static int _archive_read_next_header(struct archive *, + struct archive_entry **); +static int _archive_read_next_header2(struct archive *, + struct archive_entry *); +static int64_t advance_file_pointer(struct archive_read_filter *, int64_t); + +static struct archive_vtable * +archive_read_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_filter_bytes = _archive_filter_bytes; + av.archive_filter_code = _archive_filter_code; + av.archive_filter_name = _archive_filter_name; + av.archive_filter_count = _archive_filter_count; + av.archive_read_data_block = _archive_read_data_block; + av.archive_read_next_header = _archive_read_next_header; + av.archive_read_next_header2 = _archive_read_next_header2; + av.archive_free = _archive_read_free; + av.archive_close = _archive_read_close; + inited = 1; + } + return (&av); +} + +/* + * Allocate, initialize and return a struct archive object. + */ +struct archive * +archive_read_new(void) +{ + struct archive_read *a; + + a = (struct archive_read *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_READ_MAGIC; + + a->archive.state = ARCHIVE_STATE_NEW; + a->entry = archive_entry_new2(&a->archive); + a->archive.vtable = archive_read_vtable(); + + a->passphrases.last = &a->passphrases.first; + + return (&a->archive); +} + +/* + * Record the do-not-extract-to file. This belongs in archive_read_extract.c. + */ +void +archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i) +{ + struct archive_read *a = (struct archive_read *)_a; + + if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file")) + return; + a->skip_file_set = 1; + a->skip_file_dev = d; + a->skip_file_ino = i; +} + +/* + * Open the archive + */ +int +archive_read_open(struct archive *a, void *client_data, + archive_open_callback *client_opener, archive_read_callback *client_reader, + archive_close_callback *client_closer) +{ + /* 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); + return archive_read_open1(a); +} + + +int +archive_read_open2(struct archive *a, void *client_data, + archive_open_callback *client_opener, + archive_read_callback *client_reader, + archive_skip_callback *client_skipper, + archive_close_callback *client_closer) +{ + /* Old archive_read_open2() is just a thin shell around + * archive_read_open1. */ + archive_read_set_callback_data(a, client_data); + archive_read_set_open_callback(a, client_opener); + archive_read_set_read_callback(a, client_reader); + archive_read_set_skip_callback(a, client_skipper); + archive_read_set_close_callback(a, client_closer); + return archive_read_open1(a); +} + +static ssize_t +client_read_proxy(struct archive_read_filter *self, const void **buff) +{ + ssize_t r; + r = (self->archive->client.reader)(&self->archive->archive, + self->data, buff); + return (r); +} + +static int64_t +client_skip_proxy(struct archive_read_filter *self, int64_t request) +{ + if (request < 0) + __archive_errx(1, "Negative skip requested."); + if (request == 0) + return 0; + + if (self->archive->client.skipper != NULL) { + /* Seek requests over 1GiB are broken down into + * multiple seeks. This avoids overflows when the + * requests get passed through 32-bit arguments. */ + int64_t skip_limit = (int64_t)1 << 30; + int64_t total = 0; + for (;;) { + int64_t get, ask = request; + if (ask > skip_limit) + ask = skip_limit; + get = (self->archive->client.skipper) + (&self->archive->archive, self->data, ask); + total += get; + if (get == 0 || get == request) + return (total); + if (get > request) + return ARCHIVE_FATAL; + request -= get; + } + } else if (self->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. + * + * Note: This isn't always a good idea. The client + * skipper is allowed to skip by less than requested + * if it needs to maintain block alignment. The + * seeker is not allowed to play such games, so using + * the seeker here may be a performance loss compared + * 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); + if (after != before + request) + return ARCHIVE_FATAL; + return after - before; + } + return 0; +} + +static int64_t +client_seek_proxy(struct archive_read_filter *self, 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, + "Current client reader does not support seeking a device"); + return (ARCHIVE_FAILED); + } + return (self->archive->client.seeker)(&self->archive->archive, + self->data, offset, whence); +} + +static int +client_close_proxy(struct archive_read_filter *self) +{ + int r = ARCHIVE_OK, r2; + unsigned int i; + + if (self->archive->client.closer == NULL) + return (r); + for (i = 0; i < self->archive->client.nodes; i++) + { + r2 = (self->archive->client.closer) + ((struct archive *)self->archive, + self->archive->client.dataset[i].data); + if (r > r2) + r = r2; + } + return (r); +} + +static int +client_open_proxy(struct archive_read_filter *self) +{ + int r = ARCHIVE_OK; + if (self->archive->client.opener != NULL) + r = (self->archive->client.opener)( + (struct archive *)self->archive, self->data); + return (r); +} + +static int +client_switch_proxy(struct archive_read_filter *self, unsigned int iindex) +{ + int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; + void *data2 = NULL; + + /* Don't do anything if already in the specified data node */ + if (self->archive->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) + { + r1 = r2 = (self->archive->client.switcher) + ((struct archive *)self->archive, self->data, data2); + self->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; + if (self->archive->client.opener != NULL) + r2 = (self->archive->client.opener) + ((struct archive *)self->archive, self->data); + } + return (r1 < r2) ? r1 : r2; +} + +int +archive_read_set_open_callback(struct archive *_a, + archive_open_callback *client_opener) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_open_callback"); + a->client.opener = client_opener; + return ARCHIVE_OK; +} + +int +archive_read_set_read_callback(struct archive *_a, + archive_read_callback *client_reader) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_read_callback"); + a->client.reader = client_reader; + return ARCHIVE_OK; +} + +int +archive_read_set_skip_callback(struct archive *_a, + archive_skip_callback *client_skipper) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_skip_callback"); + a->client.skipper = client_skipper; + return ARCHIVE_OK; +} + +int +archive_read_set_seek_callback(struct archive *_a, + archive_seek_callback *client_seeker) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_seek_callback"); + a->client.seeker = client_seeker; + return ARCHIVE_OK; +} + +int +archive_read_set_close_callback(struct archive *_a, + archive_close_callback *client_closer) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_close_callback"); + a->client.closer = client_closer; + return ARCHIVE_OK; +} + +int +archive_read_set_switch_callback(struct archive *_a, + archive_switch_callback *client_switcher) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_switch_callback"); + a->client.switcher = client_switcher; + return ARCHIVE_OK; +} + +int +archive_read_set_callback_data(struct archive *_a, void *client_data) +{ + return archive_read_set_callback_data2(_a, client_data, 0); +} + +int +archive_read_set_callback_data2(struct archive *_a, void *client_data, + unsigned int iindex) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_set_callback_data2"); + + if (a->client.nodes == 0) + { + a->client.dataset = (struct archive_read_data_node *) + calloc(1, sizeof(*a->client.dataset)); + if (a->client.dataset == NULL) + { + archive_set_error(&a->archive, ENOMEM, + "No memory."); + return ARCHIVE_FATAL; + } + a->client.nodes = 1; + } + + if (iindex > a->client.nodes - 1) + { + archive_set_error(&a->archive, EINVAL, + "Invalid index specified."); + return ARCHIVE_FATAL; + } + a->client.dataset[iindex].data = client_data; + a->client.dataset[iindex].begin_position = -1; + a->client.dataset[iindex].total_size = -1; + return ARCHIVE_OK; +} + +int +archive_read_add_callback_data(struct archive *_a, void *client_data, + unsigned int iindex) +{ + struct archive_read *a = (struct archive_read *)_a; + void *p; + unsigned int i; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_add_callback_data"); + if (iindex > a->client.nodes) { + archive_set_error(&a->archive, EINVAL, + "Invalid index specified."); + return ARCHIVE_FATAL; + } + p = realloc(a->client.dataset, sizeof(*a->client.dataset) + * (++(a->client.nodes))); + if (p == NULL) { + archive_set_error(&a->archive, ENOMEM, + "No memory."); + return ARCHIVE_FATAL; + } + a->client.dataset = (struct archive_read_data_node *)p; + for (i = a->client.nodes - 1; i > iindex && i > 0; i--) { + a->client.dataset[i].data = a->client.dataset[i-1].data; + a->client.dataset[i].begin_position = -1; + a->client.dataset[i].total_size = -1; + } + a->client.dataset[iindex].data = client_data; + a->client.dataset[iindex].begin_position = -1; + a->client.dataset[iindex].total_size = -1; + return ARCHIVE_OK; +} + +int +archive_read_append_callback_data(struct archive *_a, void *client_data) +{ + struct archive_read *a = (struct archive_read *)_a; + return archive_read_add_callback_data(_a, client_data, a->client.nodes); +} + +int +archive_read_prepend_callback_data(struct archive *_a, void *client_data) +{ + return archive_read_add_callback_data(_a, client_data, 0); +} + +int +archive_read_open1(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter *filter, *tmp; + int slot, e = ARCHIVE_OK; + unsigned int i; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "archive_read_open"); + archive_clear_error(&a->archive); + + if (a->client.reader == NULL) { + archive_set_error(&a->archive, EINVAL, + "No reader function provided to archive_read_open"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + + /* Open data source. */ + if (a->client.opener != NULL) { + e = (a->client.opener)(&a->archive, a->client.dataset[0].data); + if (e != 0) { + /* If the open failed, call the closer to clean up. */ + if (a->client.closer) { + for (i = 0; i < a->client.nodes; i++) + (a->client.closer)(&a->archive, + a->client.dataset[i].data); + } + return (e); + } + } + + filter = calloc(1, sizeof(*filter)); + if (filter == NULL) + return (ARCHIVE_FATAL); + filter->bidder = NULL; + filter->upstream = NULL; + filter->archive = a; + filter->data = a->client.dataset[0].data; + filter->open = client_open_proxy; + filter->read = client_read_proxy; + filter->skip = client_skip_proxy; + filter->seek = client_seek_proxy; + filter->close = client_close_proxy; + filter->sswitch = client_switch_proxy; + filter->name = "none"; + filter->code = ARCHIVE_FILTER_NONE; + + a->client.dataset[0].begin_position = 0; + if (!a->filter || !a->bypass_filter_bidding) + { + a->filter = filter; + /* Build out the input pipeline. */ + e = choose_filters(a); + if (e < ARCHIVE_WARN) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } + else + { + /* Need to add "NONE" type filter at the end of the filter chain */ + tmp = a->filter; + while (tmp->upstream) + tmp = tmp->upstream; + tmp->upstream = filter; + } + + if (!a->format) + { + slot = choose_format(a); + if (slot < 0) { + close_filters(a); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + a->format = &(a->formats[slot]); + } + + a->archive.state = ARCHIVE_STATE_HEADER; + + /* Ensure libarchive starts from the first node in a multivolume set */ + client_switch_proxy(a->filter, 0); + return (e); +} + +/* + * Allow each registered stream transform to bid on whether + * it wants to handle this stream. Repeat until we've finished + * building the pipeline. + */ + +/* We won't build a filter pipeline with more stages than this. */ +#define MAX_NUMBER_FILTERS 25 + +static int +choose_filters(struct archive_read *a) +{ + int number_bidders, i, bid, best_bid, number_filters; + struct archive_read_filter_bidder *bidder, *best_bidder; + struct archive_read_filter *filter; + ssize_t avail; + int r; + + for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) { + number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); + + best_bid = 0; + best_bidder = NULL; + + bidder = a->bidders; + for (i = 0; i < number_bidders; i++, bidder++) { + if (bidder->bid != NULL) { + bid = (bidder->bid)(bidder, a->filter); + if (bid > best_bid) { + best_bid = bid; + best_bidder = bidder; + } + } + } + + /* If no bidder, we're done. */ + if (best_bidder == NULL) { + /* Verify the filter by asking it for some data. */ + __archive_read_filter_ahead(a->filter, 1, &avail); + if (avail < 0) { + __archive_read_free_filters(a); + return (ARCHIVE_FATAL); + } + a->archive.compression_name = a->filter->name; + a->archive.compression_code = a->filter->code; + return (ARCHIVE_OK); + } + + filter + = (struct archive_read_filter *)calloc(1, sizeof(*filter)); + if (filter == NULL) + return (ARCHIVE_FATAL); + filter->bidder = best_bidder; + filter->archive = a; + filter->upstream = a->filter; + a->filter = filter; + r = (best_bidder->init)(a->filter); + if (r != ARCHIVE_OK) { + __archive_read_free_filters(a); + return (ARCHIVE_FATAL); + } + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Input requires too many filters for decoding"); + return (ARCHIVE_FATAL); +} + +/* + * Read header of next entry. + */ +static int +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) +{ + struct archive_read *a = (struct archive_read *)_a; + int r1 = ARCHIVE_OK, r2; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_next_header"); + + archive_entry_clear(entry); + archive_clear_error(&a->archive); + + /* + * If client didn't consume entire data, skip any remainder + * (This is especially important for GNU incremental directories.) + */ + if (a->archive.state == ARCHIVE_STATE_DATA) { + r1 = archive_read_data_skip(&a->archive); + if (r1 == ARCHIVE_EOF) + archive_set_error(&a->archive, EIO, + "Premature end-of-file."); + if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } + + /* Record start-of-header offset in uncompressed stream. */ + a->header_position = a->filter->position; + + ++_a->file_count; + r2 = (a->format->read_header)(a, entry); + + /* + * EOF and FATAL are persistent at this layer. By + * modifying the state, we guarantee that future calls to + * read a header or read data will fail. + */ + switch (r2) { + case ARCHIVE_EOF: + a->archive.state = ARCHIVE_STATE_EOF; + --_a->file_count;/* Revert a file counter. */ + break; + case ARCHIVE_OK: + a->archive.state = ARCHIVE_STATE_DATA; + break; + case ARCHIVE_WARN: + a->archive.state = ARCHIVE_STATE_DATA; + break; + case ARCHIVE_RETRY: + break; + case ARCHIVE_FATAL: + a->archive.state = ARCHIVE_STATE_FATAL; + break; + } + + __archive_reset_read_data(&a->archive); + + a->data_start_node = a->client.cursor; + /* EOF always wins; otherwise return the worst error. */ + return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1; +} + +static int +_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) +{ + int ret; + struct archive_read *a = (struct archive_read *)_a; + *entryp = NULL; + ret = _archive_read_next_header2(_a, a->entry); + *entryp = a->entry; + return ret; +} + +/* + * Allow each registered format to bid on whether it wants to handle + * the next entry. Return index of winning bidder. + */ +static int +choose_format(struct archive_read *a) +{ + int slots; + int i; + int bid, best_bid; + int best_bid_slot; + + slots = sizeof(a->formats) / sizeof(a->formats[0]); + best_bid = -1; + best_bid_slot = -1; + + /* Set up a->format for convenience of bidders. */ + a->format = &(a->formats[0]); + for (i = 0; i < slots; i++, a->format++) { + if (a->format->bid) { + bid = (a->format->bid)(a, best_bid); + if (bid == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + if (a->filter->position != 0) + __archive_read_seek(a, 0, SEEK_SET); + if ((bid > best_bid) || (best_bid_slot < 0)) { + best_bid = bid; + best_bid_slot = i; + } + } + } + + /* + * There were no bidders; this is a serious programmer error + * and demands a quick and definitive abort. + */ + if (best_bid_slot < 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "No formats registered"); + return (ARCHIVE_FATAL); + } + + /* + * There were bidders, but no non-zero bids; this means we + * can't support this stream. + */ + if (best_bid < 1) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unrecognized archive format"); + return (ARCHIVE_FATAL); + } + + return (best_bid_slot); +} + +/* + * Return the file offset (within the uncompressed data stream) where + * the last header started. + */ +int64_t +archive_read_header_position(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_header_position"); + return (a->header_position); +} + +/* + * Returns 1 if the archive contains at least one encrypted entry. + * If the archive format not support encryption at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. + * If for any other reason (e.g. not enough data read so far) + * we cannot say whether there are encrypted entries, then + * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. + * In general, this function will return values below zero when the + * reader is uncertain or totally incapable of encryption support. + * When this function returns 0 you can be sure that the reader + * supports encryption detection but no encrypted entries have + * been found yet. + * + * NOTE: If the metadata/header of an archive is also encrypted, you + * cannot rely on the number of encrypted entries. That is why this + * function does not return the number of encrypted entries but# + * just shows that there are some. + */ +int +archive_read_has_encrypted_entries(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + int format_supports_encryption = archive_read_format_capabilities(_a) + & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); + + if (!_a || !format_supports_encryption) { + /* Format in general doesn't support encryption */ + return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED; + } + + /* A reader potentially has read enough data now. */ + if (a->format && a->format->has_encrypted_entries) { + return (a->format->has_encrypted_entries)(a); + } + + /* For any other reason we cannot say how many entries are there. */ + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} + +/* + * Returns a bitmask of capabilities that are supported by the archive format reader. + * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. + */ +int +archive_read_format_capabilities(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + if (a && a->format && a->format->format_capabilties) { + return (a->format->format_capabilties)(a); + } + return ARCHIVE_READ_FORMAT_CAPS_NONE; +} + +/* + * Read data from an archive entry, using a read(2)-style interface. + * This is a convenience routine that just calls + * archive_read_data_block and copies the results into the client + * buffer, filling any gaps with zero bytes. Clients using this + * API can be completely ignorant of sparse-file issues; sparse files + * will simply be padded with nulls. + * + * DO NOT intermingle calls to this function and archive_read_data_block + * to read a single entry body. + */ +ssize_t +archive_read_data(struct archive *_a, void *buff, size_t s) +{ + struct archive *a = (struct archive *)_a; + char *dest; + const void *read_buf; + size_t bytes_read; + size_t len; + int r; + + bytes_read = 0; + dest = (char *)buff; + + while (s > 0) { + if (a->read_data_remaining == 0) { + read_buf = a->read_data_block; + a->read_data_is_posix_read = 1; + a->read_data_requested = s; + r = archive_read_data_block(a, &read_buf, + &a->read_data_remaining, &a->read_data_offset); + a->read_data_block = read_buf; + if (r == ARCHIVE_EOF) + return (bytes_read); + /* + * Error codes are all negative, so the status + * return here cannot be confused with a valid + * byte count. (ARCHIVE_OK is zero.) + */ + if (r < ARCHIVE_OK) + return (r); + } + + if (a->read_data_offset < a->read_data_output_offset) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Encountered out-of-order sparse blocks"); + return (ARCHIVE_RETRY); + } + + /* Compute the amount of zero padding needed. */ + if (a->read_data_output_offset + (int64_t)s < + a->read_data_offset) { + len = s; + } else if (a->read_data_output_offset < + a->read_data_offset) { + len = (size_t)(a->read_data_offset - + a->read_data_output_offset); + } else + len = 0; + + /* Add zeroes. */ + memset(dest, 0, len); + s -= len; + a->read_data_output_offset += len; + dest += len; + bytes_read += len; + + /* Copy data if there is any space left. */ + if (s > 0) { + len = a->read_data_remaining; + if (len > s) + len = s; + if (len) + memcpy(dest, a->read_data_block, len); + s -= len; + a->read_data_block += len; + a->read_data_remaining -= len; + a->read_data_output_offset += len; + a->read_data_offset += len; + dest += len; + bytes_read += len; + } + } + a->read_data_is_posix_read = 0; + a->read_data_requested = 0; + return (bytes_read); +} + +/* + * Reset the read_data_* variables, used for starting a new entry. + */ +void __archive_reset_read_data(struct archive * a) +{ + a->read_data_output_offset = 0; + a->read_data_remaining = 0; + a->read_data_is_posix_read = 0; + a->read_data_requested = 0; + + /* extra resets, from rar.c */ + a->read_data_block = NULL; + a->read_data_offset = 0; +} + +/* + * Skip over all remaining data in this entry. + */ +int +archive_read_data_skip(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + int r; + const void *buff; + size_t size; + int64_t offset; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_data_skip"); + + if (a->format->read_data_skip != NULL) + r = (a->format->read_data_skip)(a); + else { + while ((r = archive_read_data_block(&a->archive, + &buff, &size, &offset)) + == ARCHIVE_OK) + ; + } + + if (r == ARCHIVE_EOF) + r = ARCHIVE_OK; + + a->archive.state = ARCHIVE_STATE_HEADER; + return (r); +} + +int64_t +archive_seek_data(struct archive *_a, int64_t offset, int whence) +{ + struct archive_read *a = (struct archive_read *)_a; + 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); + } + + return (a->format->seek_data)(a, offset, whence); +} + +/* + * Read the next block of entry data from the archive. + * This is a zero-copy interface; the client receives a pointer, + * size, and file offset of the next available block of data. + * + * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if + * the end of entry is encountered. + */ +static int +_archive_read_data_block(struct archive *_a, + const void **buff, size_t *size, int64_t *offset) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_data_block"); + + if (a->format->read_data == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: " + "No format->read_data function registered"); + return (ARCHIVE_FATAL); + } + + return (a->format->read_data)(a, buff, size, offset); +} + +static int +close_filters(struct archive_read *a) +{ + struct archive_read_filter *f = a->filter; + int r = ARCHIVE_OK; + /* Close each filter in the pipeline. */ + while (f != NULL) { + struct archive_read_filter *t = f->upstream; + if (!f->closed && f->close != NULL) { + int r1 = (f->close)(f); + f->closed = 1; + if (r1 < r) + r = r1; + } + free(f->buffer); + f->buffer = NULL; + f = t; + } + return r; +} + +void +__archive_read_free_filters(struct archive_read *a) +{ + /* Make sure filters are closed and their buffers are freed */ + close_filters(a); + + while (a->filter != NULL) { + struct archive_read_filter *t = a->filter->upstream; + free(a->filter); + a->filter = t; + } +} + +/* + * return the count of # of filters in use + */ +static int +_archive_filter_count(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter *p = a->filter; + int count = 0; + while(p) { + count++; + p = p->upstream; + } + return count; +} + +/* + * Close the file and all I/O. + */ +static int +_archive_read_close(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + int r = ARCHIVE_OK, r1 = ARCHIVE_OK; + + archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); + if (a->archive.state == ARCHIVE_STATE_CLOSED) + return (ARCHIVE_OK); + archive_clear_error(&a->archive); + a->archive.state = ARCHIVE_STATE_CLOSED; + + /* TODO: Clean up the formatters. */ + + /* Release the filter objects. */ + r1 = close_filters(a); + if (r1 < r) + r = r1; + + return (r); +} + +/* + * Release memory and other resources. + */ +static int +_archive_read_free(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_passphrase *p; + int i, n; + int slots; + int r = ARCHIVE_OK; + + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); + if (a->archive.state != ARCHIVE_STATE_CLOSED + && a->archive.state != ARCHIVE_STATE_FATAL) + r = archive_read_close(&a->archive); + + /* Call cleanup functions registered by optional components. */ + if (a->cleanup_archive_extract != NULL) + r = (a->cleanup_archive_extract)(a); + + /* Cleanup format-specific data. */ + slots = sizeof(a->formats) / sizeof(a->formats[0]); + for (i = 0; i < slots; i++) { + a->format = &(a->formats[i]); + if (a->formats[i].cleanup) + (a->formats[i].cleanup)(a); + } + + /* Free the filters */ + __archive_read_free_filters(a); + + /* Release the bidder objects. */ + n = sizeof(a->bidders)/sizeof(a->bidders[0]); + for (i = 0; i < n; i++) { + if (a->bidders[i].free != NULL) { + int r1 = (a->bidders[i].free)(&a->bidders[i]); + if (r1 < r) + r = r1; + } + } + + /* Release passphrase list. */ + p = a->passphrases.first; + while (p != NULL) { + struct archive_read_passphrase *np = p->next; + + /* A passphrase should be cleaned. */ + memset(p->passphrase, 0, strlen(p->passphrase)); + free(p->passphrase); + free(p); + p = np; + } + + archive_string_free(&a->archive.error_string); + archive_entry_free(a->entry); + a->archive.magic = 0; + __archive_clean(&a->archive); + free(a->client.dataset); + free(a); + return (r); +} + +static struct archive_read_filter * +get_filter(struct archive *_a, int n) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter *f = a->filter; + /* We use n == -1 for 'the last filter', which is always the + * client proxy. */ + if (n == -1 && f != NULL) { + struct archive_read_filter *last = f; + f = f->upstream; + while (f != NULL) { + last = f; + f = f->upstream; + } + return (last); + } + if (n < 0) + return NULL; + while (n > 0 && f != NULL) { + f = f->upstream; + --n; + } + return (f); +} + +static int +_archive_filter_code(struct archive *_a, int n) +{ + struct archive_read_filter *f = get_filter(_a, n); + return f == NULL ? -1 : f->code; +} + +static const char * +_archive_filter_name(struct archive *_a, int n) +{ + struct archive_read_filter *f = get_filter(_a, n); + return f != NULL ? f->name : NULL; +} + +static int64_t +_archive_filter_bytes(struct archive *_a, int n) +{ + struct archive_read_filter *f = get_filter(_a, n); + return f == NULL ? -1 : f->position; +} + +/* + * Used internally by read format handlers to register their bid and + * initialization functions. + */ +int +__archive_read_register_format(struct archive_read *a, + void *format_data, + const char *name, + int (*bid)(struct archive_read *, int), + int (*options)(struct archive_read *, const char *, const char *), + int (*read_header)(struct archive_read *, struct archive_entry *), + int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), + int (*read_data_skip)(struct archive_read *), + int64_t (*seek_data)(struct archive_read *, int64_t, int), + int (*cleanup)(struct archive_read *), + int (*format_capabilities)(struct archive_read *), + int (*has_encrypted_entries)(struct archive_read *)) +{ + int i, number_slots; + + archive_check_magic(&a->archive, + ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, + "__archive_read_register_format"); + + number_slots = sizeof(a->formats) / sizeof(a->formats[0]); + + for (i = 0; i < number_slots; i++) { + if (a->formats[i].bid == bid) + return (ARCHIVE_WARN); /* We've already installed */ + if (a->formats[i].bid == NULL) { + a->formats[i].bid = bid; + a->formats[i].options = options; + a->formats[i].read_header = read_header; + a->formats[i].read_data = read_data; + a->formats[i].read_data_skip = read_data_skip; + a->formats[i].seek_data = seek_data; + a->formats[i].cleanup = cleanup; + a->formats[i].data = format_data; + a->formats[i].name = name; + a->formats[i].format_capabilties = format_capabilities; + a->formats[i].has_encrypted_entries = has_encrypted_entries; + return (ARCHIVE_OK); + } + } + + archive_set_error(&a->archive, ENOMEM, + "Not enough slots for format registration"); + return (ARCHIVE_FATAL); +} + +/* + * Used internally by decompression routines to register their bid and + * initialization functions. + */ +int +__archive_read_get_bidder(struct archive_read *a, + struct archive_read_filter_bidder **bidder) +{ + int i, number_slots; + + number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]); + + for (i = 0; i < number_slots; i++) { + if (a->bidders[i].bid == NULL) { + memset(a->bidders + i, 0, sizeof(a->bidders[0])); + *bidder = (a->bidders + i); + return (ARCHIVE_OK); + } + } + + archive_set_error(&a->archive, ENOMEM, + "Not enough slots for filter registration"); + return (ARCHIVE_FATAL); +} + +/* + * The next section implements the peek/consume internal I/O + * system used by archive readers. This system allows simple + * read-ahead for consumers while preserving zero-copy operation + * most of the time. + * + * The two key operations: + * * The read-ahead function returns a pointer to a block of data + * that satisfies a minimum request. + * * The consume function advances the file pointer. + * + * In the ideal case, filters generate blocks of data + * and __archive_read_ahead() just returns pointers directly into + * those blocks. Then __archive_read_consume() just bumps those + * pointers. Only if your request would span blocks does the I/O + * layer use a copy buffer to provide you with a contiguous block of + * data. + * + * A couple of useful idioms: + * * "I just want some data." Ask for 1 byte and pay attention to + * the "number of bytes available" from __archive_read_ahead(). + * Consume whatever you actually use. + * * "I want to output a large block of data." As above, ask for 1 byte, + * emit all that's available (up to whatever limit you have), consume + * it all, then repeat until you're done. This effectively means that + * you're passing along the blocks that came from your provider. + * * "I want to peek ahead by a large amount." Ask for 4k or so, then + * double and repeat until you get an error or have enough. Note + * that the I/O layer will likely end up expanding its copy buffer + * to fit your request, so use this technique cautiously. This + * technique is used, for example, by some of the format tasting + * code that has uncertain look-ahead needs. + */ + +/* + * Looks ahead in the input stream: + * * If 'avail' pointer is provided, that returns number of bytes available + * in the current buffer, which may be much larger than requested. + * * If end-of-file, *avail gets set to zero. + * * If error, *avail gets error code. + * * If request can be met, returns pointer to data. + * * If minimum request cannot be met, returns NULL. + * + * Note: If you just want "some data", ask for 1 byte and pay attention + * to *avail, which will have the actual amount available. If you + * know exactly how many bytes you need, just ask for that and treat + * a NULL return as an error. + * + * Important: This does NOT move the file pointer. See + * __archive_read_consume() below. + */ +const void * +__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) +{ + return (__archive_read_filter_ahead(a->filter, min, avail)); +} + +const void * +__archive_read_filter_ahead(struct archive_read_filter *filter, + size_t min, ssize_t *avail) +{ + ssize_t bytes_read; + size_t tocopy; + + if (filter->fatal) { + if (avail) + *avail = ARCHIVE_FATAL; + return (NULL); + } + + /* + * Keep pulling more data until we can satisfy the request. + */ + for (;;) { + + /* + * If we can satisfy from the copy buffer (and the + * copy buffer isn't empty), we're done. In particular, + * note that min == 0 is a perfectly well-defined + * request. + */ + if (filter->avail >= min && filter->avail > 0) { + if (avail != NULL) + *avail = filter->avail; + return (filter->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) { + /* "Roll back" to client buffer. */ + filter->client_avail += filter->avail; + filter->client_next -= filter->avail; + /* Copy buffer is now empty. */ + filter->avail = 0; + filter->next = filter->buffer; + /* Return data from client buffer. */ + if (avail != NULL) + *avail = filter->client_avail; + return (filter->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 we've used up the client data, get more. */ + if (filter->client_avail <= 0) { + if (filter->end_of_file) { + if (avail != NULL) + *avail = 0; + return (NULL); + } + bytes_read = (filter->read)(filter, + &filter->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; + 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) + == 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; + /* Return whatever we do have. */ + if (avail != NULL) + *avail = filter->avail; + return (NULL); + } + filter->client_total = bytes_read; + filter->client_avail = filter->client_total; + filter->client_next = filter->client_buff; + } else { + /* + * We can't satisfy the request from the copy + * buffer or the existing client data, so we + * need to copy more client data over to the + * copy buffer. + */ + + /* Ensure the buffer is big enough. */ + if (min > filter->buffer_size) { + size_t s, t; + char *p; + + /* Double the buffer; watch for overflow. */ + s = t = filter->buffer_size; + if (s == 0) + s = min; + while (s < min) { + t *= 2; + if (t <= s) { /* Integer overflow! */ + archive_set_error( + &filter->archive->archive, + ENOMEM, + "Unable to allocate copy" + " buffer"); + filter->fatal = 1; + if (avail != NULL) + *avail = ARCHIVE_FATAL; + return (NULL); + } + s = t; + } + /* Now s >= min, so allocate a new buffer. */ + p = (char *)malloc(s); + if (p == NULL) { + archive_set_error( + &filter->archive->archive, + ENOMEM, + "Unable to allocate copy buffer"); + filter->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; + } + + /* 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); + /* Don't waste time buffering more than we need to. */ + if (tocopy + filter->avail > min) + tocopy = min - filter->avail; + /* Don't copy more than is available. */ + if (tocopy > filter->client_avail) + tocopy = filter->client_avail; + + memcpy(filter->next + filter->avail, + filter->client_next, tocopy); + /* Remove this data from client buffer. */ + filter->client_next += tocopy; + filter->client_avail -= tocopy; + /* add it to copy buffer. */ + filter->avail += tocopy; + } + } +} + +/* + * Move the file pointer forward. + */ +int64_t +__archive_read_consume(struct archive_read *a, int64_t request) +{ + return (__archive_read_filter_consume(a->filter, request)); +} + +int64_t +__archive_read_filter_consume(struct archive_read_filter * filter, + int64_t request) +{ + int64_t skipped; + + if (request < 0) + return ARCHIVE_FATAL; + if (request == 0) + return 0; + + skipped = advance_file_pointer(filter, 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_ERRNO_MISC, + "Truncated input file (needed %jd bytes, only %jd available)", + (intmax_t)request, (intmax_t)skipped); + return (ARCHIVE_FATAL); +} + +/* + * Advance the file pointer by the amount requested. + * Returns the amount actually advanced, which may be less than the + * request if EOF is encountered first. + * 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) +{ + int64_t bytes_skipped, total_bytes_skipped = 0; + ssize_t bytes_read; + size_t min; + + if (filter->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; + request -= min; + filter->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; + request -= min; + filter->position += min; + total_bytes_skipped += min; + } + if (request == 0) + return (total_bytes_skipped); + + /* If there's an optimized skip function, use it. */ + if (filter->skip != NULL) { + bytes_skipped = (filter->skip)(filter, request); + if (bytes_skipped < 0) { /* error */ + filter->fatal = 1; + return (bytes_skipped); + } + filter->position += bytes_skipped; + total_bytes_skipped += bytes_skipped; + request -= bytes_skipped; + if (request == 0) + return (total_bytes_skipped); + } + + /* Use ordinary reads as necessary to complete the request. */ + for (;;) { + bytes_read = (filter->read)(filter, &filter->client_buff); + if (bytes_read < 0) { + filter->client_buff = NULL; + filter->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) + == ARCHIVE_OK) + continue; + } + filter->client_buff = NULL; + filter->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; + total_bytes_skipped += request; + filter->position += request; + return (total_bytes_skipped); + } + + filter->position += bytes_read; + total_bytes_skipped += bytes_read; + request -= bytes_read; + } +} + +/** + * Returns ARCHIVE_FAILED if seeking isn't supported. + */ +int64_t +__archive_read_seek(struct archive_read *a, int64_t offset, int whence) +{ + return __archive_read_filter_seek(a->filter, offset, whence); +} + +int64_t +__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, + int whence) +{ + struct archive_read_client *client; + int64_t r; + unsigned int cursor; + + if (filter->closed || filter->fatal) + return (ARCHIVE_FATAL); + if (filter->seek == NULL) + return (ARCHIVE_FAILED); + + client = &(filter->archive->client); + switch (whence) { + case SEEK_CUR: + /* Adjust the offset and use SEEK_SET instead */ + offset += filter->position; + case SEEK_SET: + cursor = 0; + while (1) + { + if (client->dataset[cursor].begin_position < 0 || + client->dataset[cursor].total_size < 0 || + client->dataset[cursor].begin_position + + client->dataset[cursor].total_size - 1 > offset || + cursor + 1 >= client->nodes) + break; + r = client->dataset[cursor].begin_position + + client->dataset[cursor].total_size; + client->dataset[++cursor].begin_position = r; + } + while (1) { + r = client_switch_proxy(filter, cursor); + if (r != ARCHIVE_OK) + return r; + if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) + return r; + client->dataset[cursor].total_size = r; + if (client->dataset[cursor].begin_position + + client->dataset[cursor].total_size - 1 > offset || + cursor + 1 >= client->nodes) + break; + r = client->dataset[cursor].begin_position + + client->dataset[cursor].total_size; + client->dataset[++cursor].begin_position = r; + } + offset -= client->dataset[cursor].begin_position; + if (offset < 0 + || offset > client->dataset[cursor].total_size) + return ARCHIVE_FATAL; + if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0) + return r; + break; + + case SEEK_END: + cursor = 0; + while (1) { + if (client->dataset[cursor].begin_position < 0 || + client->dataset[cursor].total_size < 0 || + cursor + 1 >= client->nodes) + break; + r = client->dataset[cursor].begin_position + + client->dataset[cursor].total_size; + client->dataset[++cursor].begin_position = r; + } + while (1) { + r = client_switch_proxy(filter, cursor); + if (r != ARCHIVE_OK) + return r; + if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) + return r; + client->dataset[cursor].total_size = r; + r = client->dataset[cursor].begin_position + + client->dataset[cursor].total_size; + if (cursor + 1 >= client->nodes) + break; + client->dataset[++cursor].begin_position = r; + } + while (1) { + if (r + offset >= + client->dataset[cursor].begin_position) + break; + offset += client->dataset[cursor].total_size; + if (cursor == 0) + break; + cursor--; + r = client->dataset[cursor].begin_position + + client->dataset[cursor].total_size; + } + offset = (r + offset) - client->dataset[cursor].begin_position; + if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK) + return r; + r = client_seek_proxy(filter, offset, SEEK_SET); + if (r < ARCHIVE_OK) + return r; + break; + + default: + return (ARCHIVE_FATAL); + } + r += client->dataset[cursor].begin_position; + + if (r >= 0) { + /* + * Ouch. Clearing the buffer like this hurts, especially + * at bid time. A lot of our efficiency at bid time comes + * from having bidders reuse the data we've already read. + * + * TODO: If the seek request is in data we already + * have, then don't call the seek callback. + * + * TODO: Zip seeks to end-of-file at bid time. If + * other formats also start doing this, we may need to + * find a way for clients to fudge the seek offset to + * a block boundary. + * + * Hmmm... If whence was SEEK_END, we know the file + * 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; + } + return r; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_append_filter.c b/src/3rdparty/libarchive/libarchive/archive_read_append_filter.c new file mode 100644 index 00000000..5e4d1630 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_append_filter.c @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2003-2012 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_read_private.h" + +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; + struct archive_read *a = (struct archive_read *)_a; + + r2 = (ARCHIVE_OK); + switch (code) + { + case ARCHIVE_FILTER_NONE: + /* No filter to add, so do nothing. + * NOTE: An initial "NONE" type filter is always set at the end of the + * filter chain. + */ + r1 = (ARCHIVE_OK); + break; + case ARCHIVE_FILTER_GZIP: + strcpy(str, "gzip"); + r1 = archive_read_support_filter_gzip(_a); + break; + case ARCHIVE_FILTER_BZIP2: + strcpy(str, "bzip2"); + r1 = archive_read_support_filter_bzip2(_a); + break; + case ARCHIVE_FILTER_COMPRESS: + strcpy(str, "compress (.Z)"); + r1 = archive_read_support_filter_compress(_a); + break; + case ARCHIVE_FILTER_PROGRAM: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Cannot append program filter using archive_read_append_filter"); + return (ARCHIVE_FATAL); + case ARCHIVE_FILTER_LZMA: + strcpy(str, "lzma"); + r1 = archive_read_support_filter_lzma(_a); + break; + case ARCHIVE_FILTER_XZ: + strcpy(str, "xz"); + r1 = archive_read_support_filter_xz(_a); + break; + case ARCHIVE_FILTER_UU: + strcpy(str, "uu"); + r1 = archive_read_support_filter_uu(_a); + break; + case ARCHIVE_FILTER_RPM: + strcpy(str, "rpm"); + r1 = archive_read_support_filter_rpm(_a); + break; + case ARCHIVE_FILTER_LZ4: + strcpy(str, "lz4"); + r1 = archive_read_support_filter_lz4(_a); + break; + case ARCHIVE_FILTER_LZIP: + strcpy(str, "lzip"); + r1 = archive_read_support_filter_lzip(_a); + break; + case ARCHIVE_FILTER_LRZIP: + strcpy(str, "lrzip"); + r1 = archive_read_support_filter_lrzip(_a); + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Invalid filter code specified"); + return (ARCHIVE_FATAL); + } + + if (code != ARCHIVE_FILTER_NONE) + { + number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); + + bidder = a->bidders; + for (i = 0; i < number_bidders; i++, bidder++) + { + if (!bidder->name || !strcmp(bidder->name, str)) + break; + } + if (!bidder->name || strcmp(bidder->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to append filter"); + return (ARCHIVE_FATAL); + } + + filter + = (struct archive_read_filter *)calloc(1, sizeof(*filter)); + if (filter == 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->init)(a->filter); + if (r2 != ARCHIVE_OK) { + __archive_read_free_filters(a); + return (ARCHIVE_FATAL); + } + } + + a->bypass_filter_bidding = 1; + return (r1 < r2) ? r1 : r2; +} + +int +archive_read_append_filter_program(struct archive *_a, const char *cmd) +{ + return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0)); +} + +int +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 *a = (struct archive_read *)_a; + + if (archive_read_support_filter_program_signature(_a, cmd, signature, + signature_len) != (ARCHIVE_OK)) + return (ARCHIVE_FATAL); + + number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); + + bidder = a->bidders; + for (i = 0; i < number_bidders; i++, bidder++) + { + /* Program bidder name set to filter name after initialization */ + if (bidder->data && !bidder->name) + break; + } + if (!bidder->data) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to append program filter"); + return (ARCHIVE_FATAL); + } + + filter + = (struct archive_read_filter *)calloc(1, sizeof(*filter)); + if (filter == 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->init)(a->filter); + if (r != ARCHIVE_OK) { + __archive_read_free_filters(a); + return (ARCHIVE_FATAL); + } + bidder->name = a->filter->name; + + a->bypass_filter_bidding = 1; + return r; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c b/src/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c new file mode 100644 index 00000000..b4398f1e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_data_into_fd.c @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/05/23 05:01:29 cperciva Exp $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" + +/* Maximum amount of data to write at one time. */ +#define MAX_WRITE (1024 * 1024) + +/* + * This implementation minimizes copying of data and is sparse-file aware. + */ +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) +{ + size_t to_write; + ssize_t bytes_written; + + if (can_lseek) { + actual_offset = lseek(fd, + target_offset - actual_offset, SEEK_CUR); + if (actual_offset != target_offset) { + archive_set_error(a, errno, "Seek error"); + return (ARCHIVE_FATAL); + } + return (ARCHIVE_OK); + } + 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); + if (bytes_written < 0) { + archive_set_error(a, errno, "Write error"); + return (ARCHIVE_FATAL); + } + actual_offset += bytes_written; + } + return (ARCHIVE_OK); +} + + +int +archive_read_data_into_fd(struct archive *a, int fd) +{ + struct stat st; + int r, r2; + const void *buff; + size_t size, bytes_to_write; + ssize_t bytes_written; + int64_t target_offset; + int64_t actual_offset = 0; + 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"); + + can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode); + if (!can_lseek) + nulls = calloc(1, nulls_size); + + while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) == + ARCHIVE_OK) { + const char *p = buff; + if (target_offset > actual_offset) { + r = pad_to(a, fd, can_lseek, nulls_size, nulls, + target_offset, actual_offset); + if (r != ARCHIVE_OK) + break; + actual_offset = target_offset; + } + while (size > 0) { + bytes_to_write = size; + if (bytes_to_write > MAX_WRITE) + bytes_to_write = MAX_WRITE; + bytes_written = write(fd, p, bytes_to_write); + if (bytes_written < 0) { + archive_set_error(a, errno, "Write error"); + r = ARCHIVE_FATAL; + goto cleanup; + } + actual_offset += bytes_written; + p += bytes_written; + size -= bytes_written; + } + } + + 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; + } + +cleanup: + free(nulls); + if (r != ARCHIVE_EOF) + return (r); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c b/src/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c new file mode 100644 index 00000000..548ba89e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c @@ -0,0 +1,1041 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD"); + +/* This is the tree-walking code for POSIX systems. */ +#if !defined(_WIN32) || defined(__CYGWIN__) + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if defined(HAVE_SYS_XATTR_H) +#include +#elif defined(HAVE_ATTR_XATTR_H) +#include +#endif +#ifdef HAVE_SYS_EA_H +#include +#endif +#ifdef HAVE_COPYFILE_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#ifdef HAVE_LINUX_FIEMAP_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include /* Linux file flags, broken on Cygwin */ +#endif +#ifdef HAVE_PATHS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +static int setup_mac_metadata(struct archive_read_disk *, + struct archive_entry *, int *fd); +static int setup_xattrs(struct archive_read_disk *, + struct archive_entry *, int *fd); +static int setup_sparse(struct archive_read_disk *, + struct archive_entry *, int *fd); +#if defined(HAVE_LINUX_FIEMAP_H) +static int setup_sparse_fiemap(struct archive_read_disk *, + struct archive_entry *, int *fd); +#endif + +#if !ARCHIVE_ACL_SUPPORT +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)fd; /* UNUSED */ + return (ARCHIVE_OK); +} +#endif + +/* + * Enter working directory and return working pathname of archive_entry. + * If a pointer to an integer is provided and its value is below zero + * open a file descriptor on this pahtname. + */ +const char * +archive_read_disk_entry_setup_path(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *path; + + path = archive_entry_sourcepath(entry); + + if (path == NULL || (a->tree != NULL && + a->tree_enter_working_dir(a->tree) != 0)) + path = archive_entry_pathname(entry); + if (path == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Couldn't determine path"); + } else if (fd != NULL && *fd < 0 && a->tree != NULL && + (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) { + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + } + return (path); +} + +int +archive_read_disk_entry_from_file(struct archive *_a, + struct archive_entry *entry, + int fd, + const struct stat *st) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + const char *path, *name; + struct stat s; + int initial_fd = fd; + int r, r1; + + archive_clear_error(_a); + path = archive_entry_sourcepath(entry); + if (path == NULL) + path = archive_entry_pathname(entry); + + if (a->tree == NULL) { + if (st == NULL) { +#if HAVE_FSTAT + if (fd >= 0) { + if (fstat(fd, &s) != 0) { + archive_set_error(&a->archive, errno, + "Can't fstat"); + return (ARCHIVE_FAILED); + } + } else +#endif +#if HAVE_LSTAT + if (!a->follow_symlinks) { + if (lstat(path, &s) != 0) { + archive_set_error(&a->archive, errno, + "Can't lstat %s", path); + return (ARCHIVE_FAILED); + } + } else +#endif + if (stat(path, &s) != 0) { + archive_set_error(&a->archive, errno, + "Can't stat %s", path); + return (ARCHIVE_FAILED); + } + st = &s; + } + archive_entry_copy_stat(entry, st); + } + + /* Lookup uname/gname */ + name = archive_read_disk_uname(_a, archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(_a, archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); + +#ifdef HAVE_STRUCT_STAT_ST_FLAGS + /* On FreeBSD, we get flags for free with the stat. */ + /* TODO: Does this belong in copy_stat()? */ + if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0) + archive_entry_set_fflags(entry, st->st_flags, 0); +#endif + +#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ + (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) + /* Linux requires an extra ioctl to pull the flags. Although + * this is an extra step, it has a nice side-effect: We get an + * open file descriptor which we can use in the subsequent lookups. */ + if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && + (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) { + if (fd < 0) { + if (a->tree != NULL) + fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK | O_CLOEXEC); + else + fd = open(path, O_RDONLY | O_NONBLOCK | + O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + } + if (fd >= 0) { + int stflags; + r = ioctl(fd, +#if defined(FS_IOC_GETFLAGS) + FS_IOC_GETFLAGS, +#else + EXT2_IOC_GETFLAGS, +#endif + &stflags); + if (r == 0 && stflags != 0) + archive_entry_set_fflags(entry, stflags, 0); + } + } +#endif + +#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT) + if (S_ISLNK(st->st_mode)) { + size_t linkbuffer_len = st->st_size + 1; + char *linkbuffer; + int lnklen; + + linkbuffer = malloc(linkbuffer_len); + if (linkbuffer == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Couldn't read link data"); + return (ARCHIVE_FAILED); + } + if (a->tree != NULL) { +#ifdef HAVE_READLINKAT + lnklen = readlinkat(a->tree_current_dir_fd(a->tree), + path, linkbuffer, linkbuffer_len); +#else + if (a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Couldn't read link data"); + free(linkbuffer); + return (ARCHIVE_FAILED); + } + lnklen = readlink(path, linkbuffer, linkbuffer_len); +#endif /* HAVE_READLINKAT */ + } else + lnklen = readlink(path, linkbuffer, linkbuffer_len); + if (lnklen < 0) { + archive_set_error(&a->archive, errno, + "Couldn't read link data"); + free(linkbuffer); + return (ARCHIVE_FAILED); + } + linkbuffer[lnklen] = 0; + archive_entry_set_symlink(entry, linkbuffer); + free(linkbuffer); + } +#endif /* HAVE_READLINK || HAVE_READLINKAT */ + + r = 0; + if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0) + r = archive_read_disk_entry_setup_acls(a, entry, &fd); + if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) { + r1 = setup_xattrs(a, entry, &fd); + if (r1 < r) + r = r1; + } + if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { + r1 = setup_mac_metadata(a, entry, &fd); + if (r1 < r) + r = r1; + } + r1 = setup_sparse(a, entry, &fd); + if (r1 < r) + r = r1; + + /* If we opened the file earlier in this function, close it. */ + if (initial_fd != fd) + close(fd); + return (r); +} + +#if defined(__APPLE__) && defined(HAVE_COPYFILE_H) +/* + * The Mac OS "copyfile()" API copies the extended metadata for a + * file into a separate file in AppleDouble format (see RFC 1740). + * + * Mac OS tar and cpio implementations store this extended + * metadata as a separate entry just before the regular entry + * with a "._" prefix added to the filename. + * + * Note that this is currently done unconditionally; the tar program has + * an option to discard this information before the archive is written. + * + * TODO: If there's a failure, report it and return ARCHIVE_WARN. + */ +static int +setup_mac_metadata(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + int tempfd = -1; + int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR; + struct stat copyfile_stat; + int ret = ARCHIVE_OK; + void *buff = NULL; + int have_attrs; + const char *name, *tempdir; + struct archive_string tempfile; + + (void)fd; /* UNUSED */ + + name = archive_read_disk_entry_setup_path(a, entry, NULL); + if (name == NULL) + return (ARCHIVE_WARN); + + /* Short-circuit if there's nothing to do. */ + have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); + if (have_attrs == -1) { + archive_set_error(&a->archive, errno, + "Could not check extended attributes"); + return (ARCHIVE_WARN); + } + if (have_attrs == 0) + return (ARCHIVE_OK); + + tempdir = NULL; + if (issetugid() == 0) + tempdir = getenv("TMPDIR"); + if (tempdir == NULL) + tempdir = _PATH_TMP; + archive_string_init(&tempfile); + archive_strcpy(&tempfile, tempdir); + archive_strcat(&tempfile, "tar.md.XXXXXX"); + tempfd = mkstemp(tempfile.s); + if (tempfd < 0) { + archive_set_error(&a->archive, errno, + "Could not open extended attribute file"); + ret = ARCHIVE_WARN; + goto cleanup; + } + __archive_ensure_cloexec_flag(tempfd); + + /* XXX I wish copyfile() could pack directly to a memory + * buffer; that would avoid the temp file here. For that + * matter, it would be nice if fcopyfile() actually worked, + * that would reduce the many open/close races here. */ + if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) { + archive_set_error(&a->archive, errno, + "Could not pack extended attributes"); + ret = ARCHIVE_WARN; + goto cleanup; + } + if (fstat(tempfd, ©file_stat)) { + archive_set_error(&a->archive, errno, + "Could not check size of extended attributes"); + ret = ARCHIVE_WARN; + goto cleanup; + } + buff = malloc(copyfile_stat.st_size); + if (buff == NULL) { + archive_set_error(&a->archive, errno, + "Could not allocate memory for extended attributes"); + ret = ARCHIVE_WARN; + goto cleanup; + } + if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) { + archive_set_error(&a->archive, errno, + "Could not read extended attributes into memory"); + ret = ARCHIVE_WARN; + goto cleanup; + } + archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size); + +cleanup: + if (tempfd >= 0) { + close(tempfd); + unlink(tempfile.s); + } + archive_string_free(&tempfile); + free(buff); + return (ret); +} + +#else + +/* + * Stub implementation for non-Mac systems. + */ +static int +setup_mac_metadata(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)fd; /* UNUSED */ + return (ARCHIVE_OK); +} +#endif + +#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX + +/* + * Linux, Darwin and AIX extended attribute support. + * + * TODO: By using a stack-allocated buffer for the first + * call to getxattr(), we might be able to avoid the second + * call entirely. We only need the second call if the + * stack-allocated buffer is too small. But a modest buffer + * of 1024 bytes or so will often be big enough. Same applies + * to listxattr(). + */ + + +static int +setup_xattr(struct archive_read_disk *a, + struct archive_entry *entry, const char *name, int fd, const char *accpath) +{ + ssize_t size; + void *value = NULL; + + + if (fd >= 0) { +#if ARCHIVE_XATTR_LINUX + size = fgetxattr(fd, name, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + size = fgetxattr(fd, name, NULL, 0, 0, 0); +#elif ARCHIVE_XATTR_AIX + size = fgetea(fd, name, NULL, 0); +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + size = lgetxattr(accpath, name, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + size = lgetea(accpath, name, NULL, 0); +#endif + } else { +#if ARCHIVE_XATTR_LINUX + size = getxattr(accpath, name, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, NULL, 0, 0, 0); +#elif ARCHIVE_XATTR_AIX + size = getea(accpath, name, NULL, 0); +#endif + } + + if (size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't query extended attribute"); + return (ARCHIVE_WARN); + } + + if (size > 0 && (value = malloc(size)) == NULL) { + archive_set_error(&a->archive, errno, "Out of memory"); + return (ARCHIVE_FATAL); + } + + + if (fd >= 0) { +#if ARCHIVE_XATTR_LINUX + size = fgetxattr(fd, name, value, size); +#elif ARCHIVE_XATTR_DARWIN + size = fgetxattr(fd, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX + size = fgetea(fd, name, value, size); +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + size = lgetxattr(accpath, name, value, size); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + size = lgetea(accpath, name, value, size); +#endif + } else { +#if ARCHIVE_XATTR_LINUX + size = getxattr(accpath, name, value, size); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX + size = getea(accpath, name, value, size); +#endif + } + + if (size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't read extended attribute"); + return (ARCHIVE_WARN); + } + + archive_entry_xattr_add_entry(entry, name, value, size); + + free(value); + return (ARCHIVE_OK); +} + +static int +setup_xattrs(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + char *list, *p; + const char *path; + ssize_t list_size; + + path = NULL; + + if (*fd < 0) { + path = archive_read_disk_entry_setup_path(a, entry, fd); + if (path == NULL) + return (ARCHIVE_WARN); + } + + if (*fd >= 0) { +#if ARCHIVE_XATTR_LINUX + list_size = flistxattr(*fd, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + list_size = flistxattr(*fd, NULL, 0, 0); +#elif ARCHIVE_XATTR_AIX + list_size = flistea(*fd, NULL, 0); +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + list_size = llistxattr(path, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + list_size = llistea(path, NULL, 0); +#endif + } else { +#if ARCHIVE_XATTR_LINUX + list_size = listxattr(path, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, NULL, 0, 0); +#elif ARCHIVE_XATTR_AIX + list_size = listea(path, NULL, 0); +#endif + } + + if (list_size == -1) { + if (errno == ENOTSUP || errno == ENOSYS) + return (ARCHIVE_OK); + archive_set_error(&a->archive, errno, + "Couldn't list extended attributes"); + return (ARCHIVE_WARN); + } + + if (list_size == 0) + return (ARCHIVE_OK); + + if ((list = malloc(list_size)) == NULL) { + archive_set_error(&a->archive, errno, "Out of memory"); + return (ARCHIVE_FATAL); + } + + if (*fd >= 0) { +#if ARCHIVE_XATTR_LINUX + list_size = flistxattr(*fd, list, list_size); +#elif ARCHIVE_XATTR_DARWIN + list_size = flistxattr(*fd, list, list_size, 0); +#elif ARCHIVE_XATTR_AIX + list_size = flistea(*fd, list, list_size); +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + list_size = llistxattr(path, list, list_size); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + list_size = llistea(path, list, list_size); +#endif + } else { +#if ARCHIVE_XATTR_LINUX + list_size = listxattr(path, list, list_size); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, list, list_size, 0); +#elif ARCHIVE_XATTR_AIX + list_size = listea(path, list, list_size); +#endif + } + + if (list_size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't retrieve extended attributes"); + free(list); + return (ARCHIVE_WARN); + } + + for (p = list; (p - list) < list_size; p += strlen(p) + 1) { +#if ARCHIVE_XATTR_LINUX + /* Linux: skip POSIX.1e ACL extended attributes */ + if (strncmp(p, "system.", 7) == 0 && + (strcmp(p + 7, "posix_acl_access") == 0 || + strcmp(p + 7, "posix_acl_default") == 0)) + continue; + if (strncmp(p, "trusted.SGI_", 12) == 0 && + (strcmp(p + 12, "ACL_DEFAULT") == 0 || + strcmp(p + 12, "ACL_FILE") == 0)) + continue; + + /* Linux: xfsroot namespace is obsolete and unsupported */ + if (strncmp(p, "xfsroot.", 8) == 0) + continue; +#endif + setup_xattr(a, entry, p, *fd, path); + } + + free(list); + return (ARCHIVE_OK); +} + +#elif ARCHIVE_XATTR_FREEBSD + +/* + * FreeBSD extattr interface. + */ + +/* TODO: Implement this. Follow the Linux model above, but + * with FreeBSD-specific system calls, of course. Be careful + * to not include the system extattrs that hold ACLs; we handle + * those separately. + */ +static int +setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, + int namespace, const char *name, const char *fullname, int fd, + const char *path); + +static int +setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, + int namespace, const char *name, const char *fullname, int fd, + const char *accpath) +{ + ssize_t size; + void *value = NULL; + + if (fd >= 0) + size = extattr_get_fd(fd, namespace, name, NULL, 0); + else if (!a->follow_symlinks) + size = extattr_get_link(accpath, namespace, name, NULL, 0); + else + size = extattr_get_file(accpath, namespace, name, NULL, 0); + + if (size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't query extended attribute"); + return (ARCHIVE_WARN); + } + + if (size > 0 && (value = malloc(size)) == NULL) { + archive_set_error(&a->archive, errno, "Out of memory"); + return (ARCHIVE_FATAL); + } + + if (fd >= 0) + size = extattr_get_fd(fd, namespace, name, value, size); + else if (!a->follow_symlinks) + size = extattr_get_link(accpath, namespace, name, value, size); + else + size = extattr_get_file(accpath, namespace, name, value, size); + + if (size == -1) { + free(value); + archive_set_error(&a->archive, errno, + "Couldn't read extended attribute"); + return (ARCHIVE_WARN); + } + + archive_entry_xattr_add_entry(entry, fullname, value, size); + + free(value); + return (ARCHIVE_OK); +} + +static int +setup_xattrs(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + char buff[512]; + char *list, *p; + ssize_t list_size; + const char *path; + int namespace = EXTATTR_NAMESPACE_USER; + + path = NULL; + + if (*fd < 0) { + path = archive_read_disk_entry_setup_path(a, entry, fd); + if (path == NULL) + return (ARCHIVE_WARN); + } + + if (*fd >= 0) + list_size = extattr_list_fd(*fd, namespace, NULL, 0); + else if (!a->follow_symlinks) + list_size = extattr_list_link(path, namespace, NULL, 0); + else + list_size = extattr_list_file(path, namespace, NULL, 0); + + if (list_size == -1 && errno == EOPNOTSUPP) + return (ARCHIVE_OK); + if (list_size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't list extended attributes"); + return (ARCHIVE_WARN); + } + + if (list_size == 0) + return (ARCHIVE_OK); + + if ((list = malloc(list_size)) == NULL) { + archive_set_error(&a->archive, errno, "Out of memory"); + return (ARCHIVE_FATAL); + } + + if (*fd >= 0) + list_size = extattr_list_fd(*fd, namespace, list, list_size); + else if (!a->follow_symlinks) + list_size = extattr_list_link(path, namespace, list, list_size); + else + list_size = extattr_list_file(path, namespace, list, list_size); + + if (list_size == -1) { + archive_set_error(&a->archive, errno, + "Couldn't retrieve extended attributes"); + free(list); + return (ARCHIVE_WARN); + } + + p = list; + while ((p - list) < list_size) { + size_t len = 255 & (int)*p; + char *name; + + strcpy(buff, "user."); + name = buff + strlen(buff); + memcpy(name, p + 1, len); + name[len] = '\0'; + setup_xattr(a, entry, namespace, name, buff, *fd, path); + p += 1 + len; + } + + free(list); + return (ARCHIVE_OK); +} + +#else + +/* + * Generic (stub) extended attribute support. + */ +static int +setup_xattrs(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)fd; /* UNUSED */ + return (ARCHIVE_OK); +} + +#endif + +#if defined(HAVE_LINUX_FIEMAP_H) + +/* + * Linux FIEMAP sparse interface. + * + * The FIEMAP ioctl returns an "extent" for each physical allocation + * on disk. We need to process those to generate a more compact list + * of logical file blocks. We also need to be very careful to use + * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes + * does not report allocations for newly-written data that hasn't + * been synced to disk. + * + * It's important to return a minimal sparse file list because we want + * to not trigger sparse file extensions if we don't have to, since + * not all readers support them. + */ + +static int +setup_sparse_fiemap(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + char buff[4096]; + struct fiemap *fm; + struct fiemap_extent *fe; + int64_t size; + int count, do_fiemap, iters; + int exit_sts = ARCHIVE_OK; + const char *path; + + if (archive_entry_filetype(entry) != AE_IFREG + || archive_entry_size(entry) <= 0 + || archive_entry_hardlink(entry) != NULL) + return (ARCHIVE_OK); + + if (*fd < 0) { + path = archive_read_disk_entry_setup_path(a, entry, NULL); + if (path == NULL) + return (ARCHIVE_FAILED); + + if (a->tree != NULL) + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK | O_CLOEXEC); + else + *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (*fd < 0) { + archive_set_error(&a->archive, errno, + "Can't open `%s'", path); + return (ARCHIVE_FAILED); + } + __archive_ensure_cloexec_flag(*fd); + } + + /* Initialize buffer to avoid the error valgrind complains about. */ + memset(buff, 0, sizeof(buff)); + count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe); + fm = (struct fiemap *)buff; + fm->fm_start = 0; + fm->fm_length = ~0ULL;; + fm->fm_flags = FIEMAP_FLAG_SYNC; + fm->fm_extent_count = count; + do_fiemap = 1; + size = archive_entry_size(entry); + for (iters = 0; ; ++iters) { + int i, r; + + r = ioctl(*fd, FS_IOC_FIEMAP, fm); + if (r < 0) { + /* When something error happens, it is better we + * should return ARCHIVE_OK because an earlier + * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */ + goto exit_setup_sparse_fiemap; + } + if (fm->fm_mapped_extents == 0) { + if (iters == 0) { + /* Fully sparse file; insert a zero-length "data" entry */ + archive_entry_sparse_add_entry(entry, 0, 0); + } + break; + } + fe = fm->fm_extents; + for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) { + if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) { + /* The fe_length of the last block does not + * adjust itself to its size files. */ + int64_t length = fe->fe_length; + if (fe->fe_logical + length > (uint64_t)size) + length -= fe->fe_logical + length - size; + if (fe->fe_logical == 0 && length == size) { + /* This is not sparse. */ + do_fiemap = 0; + break; + } + if (length > 0) + archive_entry_sparse_add_entry(entry, + fe->fe_logical, length); + } + if (fe->fe_flags & FIEMAP_EXTENT_LAST) + do_fiemap = 0; + } + if (do_fiemap) { + fe = fm->fm_extents + fm->fm_mapped_extents -1; + fm->fm_start = fe->fe_logical + fe->fe_length; + } else + break; + } +exit_setup_sparse_fiemap: + return (exit_sts); +} + +#if !defined(SEEK_HOLE) || !defined(SEEK_DATA) +static int +setup_sparse(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + return setup_sparse_fiemap(a, entry, fd); +} +#endif +#endif /* defined(HAVE_LINUX_FIEMAP_H) */ + +#if defined(SEEK_HOLE) && defined(SEEK_DATA) + +/* + * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris) + */ + +static int +setup_sparse(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + int64_t size; + off_t initial_off; + off_t off_s, off_e; + int exit_sts = ARCHIVE_OK; + int check_fully_sparse = 0; + const char *path; + + if (archive_entry_filetype(entry) != AE_IFREG + || archive_entry_size(entry) <= 0 + || archive_entry_hardlink(entry) != NULL) + return (ARCHIVE_OK); + + /* Does filesystem support the reporting of hole ? */ + if (*fd < 0) + path = archive_read_disk_entry_setup_path(a, entry, fd); + else + path = NULL; + + if (*fd >= 0) { +#ifdef _PC_MIN_HOLE_SIZE + if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0) + return (ARCHIVE_OK); +#endif + initial_off = lseek(*fd, 0, SEEK_CUR); + if (initial_off != 0) + lseek(*fd, 0, SEEK_SET); + } else { + if (path == NULL) + return (ARCHIVE_FAILED); +#ifdef _PC_MIN_HOLE_SIZE + if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) + return (ARCHIVE_OK); +#endif + *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (*fd < 0) { + archive_set_error(&a->archive, errno, + "Can't open `%s'", path); + return (ARCHIVE_FAILED); + } + __archive_ensure_cloexec_flag(*fd); + initial_off = 0; + } + +#ifndef _PC_MIN_HOLE_SIZE + /* Check if the underlying filesystem supports seek hole */ + off_s = lseek(*fd, 0, SEEK_HOLE); + if (off_s < 0) +#if defined(HAVE_LINUX_FIEMAP_H) + return setup_sparse_fiemap(a, entry, fd); +#else + goto exit_setup_sparse; +#endif + else if (off_s > 0) + lseek(*fd, 0, SEEK_SET); +#endif + + off_s = 0; + size = archive_entry_size(entry); + while (off_s < size) { + off_s = lseek(*fd, off_s, SEEK_DATA); + if (off_s == (off_t)-1) { + if (errno == ENXIO) { + /* no more hole */ + if (archive_entry_sparse_count(entry) == 0) { + /* Potentially a fully-sparse file. */ + check_fully_sparse = 1; + } + break; + } + archive_set_error(&a->archive, errno, + "lseek(SEEK_HOLE) failed"); + exit_sts = ARCHIVE_FAILED; + goto exit_setup_sparse; + } + off_e = lseek(*fd, off_s, SEEK_HOLE); + if (off_e == (off_t)-1) { + if (errno == ENXIO) { + off_e = lseek(*fd, 0, SEEK_END); + if (off_e != (off_t)-1) + break;/* no more data */ + } + archive_set_error(&a->archive, errno, + "lseek(SEEK_DATA) failed"); + exit_sts = ARCHIVE_FAILED; + goto exit_setup_sparse; + } + if (off_s == 0 && off_e == size) + break;/* This is not sparse. */ + archive_entry_sparse_add_entry(entry, off_s, + off_e - off_s); + off_s = off_e; + } + + if (check_fully_sparse) { + if (lseek(*fd, 0, SEEK_HOLE) == 0 && + lseek(*fd, 0, SEEK_END) == size) { + /* Fully sparse file; insert a zero-length "data" entry */ + archive_entry_sparse_add_entry(entry, 0, 0); + } + } +exit_setup_sparse: + lseek(*fd, initial_off, SEEK_SET); + return (exit_sts); +} + +#elif !defined(HAVE_LINUX_FIEMAP_H) + +/* + * Generic (stub) sparse support. + */ +static int +setup_sparse(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)fd; /* UNUSED */ + return (ARCHIVE_OK); +} + +#endif + +#endif /* !defined(_WIN32) || defined(__CYGWIN__) */ + diff --git a/src/3rdparty/libarchive/libarchive/archive_read_disk_posix.c b/src/3rdparty/libarchive/libarchive/archive_read_disk_posix.c new file mode 100644 index 00000000..6961ae6a --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_disk_posix.c @@ -0,0 +1,2661 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This is the tree-walking code for POSIX systems. */ +#if !defined(_WIN32) || defined(__CYGWIN__) + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_STATFS_H +#include +#endif +#ifdef HAVE_SYS_STATVFS_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_LINUX_MAGIC_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include /* Linux file flags, broken on Cygwin */ +#endif +#ifdef HAVE_DIRECT_H +#include +#endif +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include "archive.h" +#include "archive_string.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" + +#ifndef HAVE_FCHDIR +#error fchdir function required. +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/*- + * This is a new directory-walking system that addresses a number + * of problems I've had with fts(3). In particular, it has no + * pathname-length limits (other than the size of 'int'), handles + * deep logical traversals, uses considerably less memory, and has + * an opaque interface (easier to modify in the future). + * + * Internally, it keeps a single list of "tree_entry" items that + * represent filesystem objects that require further attention. + * Non-directories are not kept in memory: they are pulled from + * readdir(), returned to the client, then freed as soon as possible. + * Any directory entry to be traversed gets pushed onto the stack. + * + * There is surprisingly little information that needs to be kept for + * each item on the stack. Just the name, depth (represented here as the + * string length of the parent directory's pathname), and some markers + * indicating how to get back to the parent (via chdir("..") for a + * regular dir or via fchdir(2) for a symlink). + */ +/* + * TODO: + * 1) Loop checking. + * 3) Arbitrary logical traversals by closing/reopening intermediate fds. + */ + +struct restore_time { + const char *name; + time_t mtime; + long mtime_nsec; + time_t atime; + long atime_nsec; + mode_t filetype; + int noatime; +}; + +struct tree_entry { + int depth; + struct tree_entry *next; + struct tree_entry *parent; + struct archive_string name; + size_t dirname_length; + int64_t dev; + int64_t ino; + int flags; + int filesystem_id; + /* How to return back to the parent of a symlink. */ + int symlink_parent_fd; + /* How to restore time of a directory. */ + struct restore_time restore_time; +}; + +struct filesystem { + int64_t dev; + int synthetic; + int remote; + int noatime; +#if defined(USE_READDIR_R) + size_t name_max; +#endif + long incr_xfer_size; + long max_xfer_size; + long min_xfer_size; + long xfer_align; + + /* + * Buffer used for reading file contents. + */ + /* Exactly allocated memory pointer. */ + unsigned char *allocation_ptr; + /* Pointer adjusted to the filesystem alignment . */ + unsigned char *buff; + size_t buff_size; +}; + +/* Definitions for tree_entry.flags bitmap. */ +#define isDir 1 /* This entry is a regular directory. */ +#define isDirLink 2 /* This entry is a symbolic link to a directory. */ +#define needsFirstVisit 4 /* This is an initial entry. */ +#define needsDescent 8 /* This entry needs to be previsited. */ +#define needsOpen 16 /* This is a directory that needs to be opened. */ +#define needsAscent 32 /* This entry needs to be postvisited. */ + +/* + * Local data for this package. + */ +struct tree { + struct tree_entry *stack; + struct tree_entry *current; + DIR *d; +#define INVALID_DIR_HANDLE NULL + struct dirent *de; +#if defined(USE_READDIR_R) + struct dirent *dirent; + size_t dirent_allocated; +#endif + int flags; + int visit_type; + /* Error code from last failed operation. */ + int tree_errno; + + /* Dynamically-sized buffer for holding path */ + struct archive_string path; + + /* Last path element */ + const char *basename; + /* Leading dir length */ + size_t dirname_length; + + int depth; + int openCount; + int maxOpenCount; + int initial_dir_fd; + int working_dir_fd; + + struct stat lst; + struct stat st; + int descend; + int nlink; + /* How to restore time of a file. */ + struct restore_time restore_time; + + struct entry_sparse { + int64_t length; + int64_t offset; + } *sparse_list, *current_sparse; + int sparse_count; + int sparse_list_size; + + char initial_symlink_mode; + char symlink_mode; + struct filesystem *current_filesystem; + struct filesystem *filesystem_table; + int initial_filesystem_id; + int current_filesystem_id; + int max_filesystem_id; + int allocated_filesystem; + + int entry_fd; + int entry_eof; + int64_t entry_remaining_bytes; + int64_t entry_total; + unsigned char *entry_buff; + size_t entry_buff_size; +}; + +/* Definitions for tree.flags bitmap. */ +#define hasStat 16 /* The st entry is valid. */ +#define hasLstat 32 /* The lst entry is valid. */ +#define onWorkingDir 64 /* We are on the working dir where we are + * reading directory entry at this time. */ +#define needsRestoreTimes 128 +#define onInitialDir 256 /* We are on the initial dir. */ + +static int +tree_dir_next_posix(struct tree *t); + +#ifdef HAVE_DIRENT_D_NAMLEN +/* BSD extension; avoids need for a strlen() call. */ +#define D_NAMELEN(dp) (dp)->d_namlen +#else +#define D_NAMELEN(dp) (strlen((dp)->d_name)) +#endif + +/* Initiate/terminate a tree traversal. */ +static struct tree *tree_open(const char *, int, int); +static struct tree *tree_reopen(struct tree *, const char *, int); +static void tree_close(struct tree *); +static void tree_free(struct tree *); +static void tree_push(struct tree *, const char *, int, int64_t, int64_t, + struct restore_time *); +static int tree_enter_initial_dir(struct tree *); +static int tree_enter_working_dir(struct tree *); +static int tree_current_dir_fd(struct tree *); + +/* + * tree_next() returns Zero if there is no next entry, non-zero if + * there is. Note that directories are visited three times. + * Directories are always visited first as part of enumerating their + * parent; that is a "regular" visit. If tree_descend() is invoked at + * that time, the directory is added to a work list and will + * subsequently be visited two more times: once just after descending + * into the directory ("postdescent") and again just after ascending + * back to the parent ("postascent"). + * + * TREE_ERROR_DIR is returned if the descent failed (because the + * directory couldn't be opened, for instance). This is returned + * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a + * fatal error, but it does imply that the relevant subtree won't be + * visited. TREE_ERROR_FATAL is returned for an error that left the + * traversal completely hosed. Right now, this is only returned for + * chdir() failures during ascent. + */ +#define TREE_REGULAR 1 +#define TREE_POSTDESCENT 2 +#define TREE_POSTASCENT 3 +#define TREE_ERROR_DIR -1 +#define TREE_ERROR_FATAL -2 + +static int tree_next(struct tree *); + +/* + * Return information about the current entry. + */ + +/* + * The current full pathname, length of the full pathname, and a name + * that can be used to access the file. Because tree does use chdir + * extensively, the access path is almost never the same as the full + * current path. + * + * TODO: On platforms that support it, use openat()-style operations + * to eliminate the chdir() operations entirely while still supporting + * arbitrarily deep traversals. This makes access_path troublesome to + * support, of course, which means we'll need a rich enough interface + * that clients can function without it. (In particular, we'll need + * tree_current_open() that returns an open file descriptor.) + * + */ +static const char *tree_current_path(struct tree *); +static const char *tree_current_access_path(struct tree *); + +/* + * Request the lstat() or stat() data for the current path. Since the + * tree package needs to do some of this anyway, and caches the + * results, you should take advantage of it here if you need it rather + * than make a redundant stat() or lstat() call of your own. + */ +static const struct stat *tree_current_stat(struct tree *); +static const struct stat *tree_current_lstat(struct tree *); +static int tree_current_is_symblic_link_target(struct tree *); + +/* The following functions use tricks to avoid a certain number of + * stat()/lstat() calls. */ +/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ +static int tree_current_is_physical_dir(struct tree *); +/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ +static int tree_current_is_dir(struct tree *); +static int update_current_filesystem(struct archive_read_disk *a, + int64_t dev); +static int setup_current_filesystem(struct archive_read_disk *); +static int tree_target_is_same_as_parent(struct tree *, const struct stat *); + +static int _archive_read_disk_open(struct archive *, const char *); +static int _archive_read_free(struct archive *); +static int _archive_read_close(struct archive *); +static int _archive_read_data_block(struct archive *, + const void **, size_t *, int64_t *); +static int _archive_read_next_header(struct archive *, + struct archive_entry **); +static int _archive_read_next_header2(struct archive *, + struct archive_entry *); +static const char *trivial_lookup_gname(void *, int64_t gid); +static const char *trivial_lookup_uname(void *, int64_t uid); +static int setup_sparse(struct archive_read_disk *, struct archive_entry *); +static int close_and_restore_time(int fd, struct tree *, + struct restore_time *); +static int open_on_current_dir(struct tree *, const char *, int); +static int tree_dup(int); + + +static struct archive_vtable * +archive_read_disk_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_free = _archive_read_free; + av.archive_close = _archive_read_close; + av.archive_read_data_block = _archive_read_data_block; + av.archive_read_next_header = _archive_read_next_header; + av.archive_read_next_header2 = _archive_read_next_header2; + inited = 1; + } + return (&av); +} + +const char * +archive_read_disk_gname(struct archive *_a, int64_t gid) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_gname")) + return (NULL); + if (a->lookup_gname == NULL) + return (NULL); + return ((*a->lookup_gname)(a->lookup_gname_data, gid)); +} + +const char * +archive_read_disk_uname(struct archive *_a, int64_t uid) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_uname")) + return (NULL); + if (a->lookup_uname == NULL) + return (NULL); + return ((*a->lookup_uname)(a->lookup_uname_data, uid)); +} + +int +archive_read_disk_set_gname_lookup(struct archive *_a, + void *private_data, + const char * (*lookup_gname)(void *private, int64_t gid), + void (*cleanup_gname)(void *private)) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); + + if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) + (a->cleanup_gname)(a->lookup_gname_data); + + a->lookup_gname = lookup_gname; + a->cleanup_gname = cleanup_gname; + a->lookup_gname_data = private_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_uname_lookup(struct archive *_a, + void *private_data, + const char * (*lookup_uname)(void *private, int64_t uid), + void (*cleanup_uname)(void *private)) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); + + if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) + (a->cleanup_uname)(a->lookup_uname_data); + + a->lookup_uname = lookup_uname; + a->cleanup_uname = cleanup_uname; + a->lookup_uname_data = private_data; + return (ARCHIVE_OK); +} + +/* + * Create a new archive_read_disk object and initialize it with global state. + */ +struct archive * +archive_read_disk_new(void) +{ + struct archive_read_disk *a; + + a = (struct archive_read_disk *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_READ_DISK_MAGIC; + a->archive.state = ARCHIVE_STATE_NEW; + a->archive.vtable = archive_read_disk_vtable(); + a->entry = archive_entry_new2(&a->archive); + a->lookup_uname = trivial_lookup_uname; + a->lookup_gname = trivial_lookup_gname; + a->flags = ARCHIVE_READDISK_MAC_COPYFILE; + a->open_on_current_dir = open_on_current_dir; + a->tree_current_dir_fd = tree_current_dir_fd; + a->tree_enter_working_dir = tree_enter_working_dir; + return (&a->archive); +} + +static int +_archive_read_free(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + int r; + + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); + + if (a->archive.state != ARCHIVE_STATE_CLOSED) + r = _archive_read_close(&a->archive); + else + r = ARCHIVE_OK; + + tree_free(a->tree); + if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) + (a->cleanup_gname)(a->lookup_gname_data); + if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) + (a->cleanup_uname)(a->lookup_uname_data); + archive_string_free(&a->archive.error_string); + archive_entry_free(a->entry); + a->archive.magic = 0; + __archive_clean(&a->archive); + free(a); + return (r); +} + +static int +_archive_read_close(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); + + if (a->archive.state != ARCHIVE_STATE_FATAL) + a->archive.state = ARCHIVE_STATE_CLOSED; + + tree_close(a->tree); + + return (ARCHIVE_OK); +} + +static void +setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, + int follow_symlinks) +{ + a->symlink_mode = symlink_mode; + a->follow_symlinks = follow_symlinks; + if (a->tree != NULL) { + a->tree->initial_symlink_mode = a->symlink_mode; + a->tree->symlink_mode = a->symlink_mode; + } +} + +int +archive_read_disk_set_symlink_logical(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); + setup_symlink_mode(a, 'L', 1); + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_symlink_physical(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); + setup_symlink_mode(a, 'P', 0); + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_symlink_hybrid(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); + setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_atime_restored(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); +#ifdef HAVE_UTIMES + a->flags |= ARCHIVE_READDISK_RESTORE_ATIME; + if (a->tree != NULL) + a->tree->flags |= needsRestoreTimes; + return (ARCHIVE_OK); +#else + /* Display warning and unset flag */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore access time on this system"); + a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME; + return (ARCHIVE_WARN); +#endif +} + +int +archive_read_disk_set_behavior(struct archive *_a, int flags) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + int r = ARCHIVE_OK; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); + + a->flags = flags; + + if (flags & ARCHIVE_READDISK_RESTORE_ATIME) + r = archive_read_disk_set_atime_restored(_a); + else { + if (a->tree != NULL) + a->tree->flags &= ~needsRestoreTimes; + } + return (r); +} + +/* + * Trivial implementations of gname/uname lookup functions. + * These are normally overridden by the client, but these stub + * versions ensure that we always have something that works. + */ +static const char * +trivial_lookup_gname(void *private_data, int64_t gid) +{ + (void)private_data; /* UNUSED */ + (void)gid; /* UNUSED */ + return (NULL); +} + +static const char * +trivial_lookup_uname(void *private_data, int64_t uid) +{ + (void)private_data; /* UNUSED */ + (void)uid; /* UNUSED */ + return (NULL); +} + +/* + * Allocate memory for the reading buffer adjusted to the filesystem + * alignment. + */ +static int +setup_suitable_read_buffer(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + struct filesystem *cf = t->current_filesystem; + size_t asize; + size_t s; + + if (cf->allocation_ptr == NULL) { + /* If we couldn't get a filesystem alignment, + * we use 4096 as default value but we won't use + * O_DIRECT to open() and openat() operations. */ + long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align; + + if (cf->max_xfer_size != -1) + asize = cf->max_xfer_size + xfer_align; + else { + long incr = cf->incr_xfer_size; + /* Some platform does not set a proper value to + * incr_xfer_size.*/ + if (incr < 0) + incr = cf->min_xfer_size; + if (cf->min_xfer_size < 0) { + incr = xfer_align; + asize = xfer_align; + } else + asize = cf->min_xfer_size; + + /* Increase a buffer size up to 64K bytes in + * a proper increment size. */ + while (asize < 1024*64) + asize += incr; + /* Take a margin to adjust to the filesystem + * alignment. */ + asize += xfer_align; + } + cf->allocation_ptr = malloc(asize); + if (cf->allocation_ptr == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Couldn't allocate memory"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + + /* + * Calculate proper address for the filesystem. + */ + s = (uintptr_t)cf->allocation_ptr; + s %= xfer_align; + if (s > 0) + s = xfer_align - s; + + /* + * Set a read buffer pointer in the proper alignment of + * the current filesystem. + */ + cf->buff = cf->allocation_ptr + s; + cf->buff_size = asize - xfer_align; + } + return (ARCHIVE_OK); +} + +static int +_archive_read_data_block(struct archive *_a, const void **buff, + size_t *size, int64_t *offset) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + int r; + ssize_t bytes; + size_t buffbytes; + int empty_sparse_region = 0; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_data_block"); + + if (t->entry_eof || t->entry_remaining_bytes <= 0) { + r = ARCHIVE_EOF; + goto abort_read_data; + } + + /* + * Open the current file. + */ + if (t->entry_fd < 0) { + int flags = O_RDONLY | O_BINARY | O_CLOEXEC; + + /* + * Eliminate or reduce cache effects if we can. + * + * Carefully consider this to be enabled. + */ +#if defined(O_DIRECT) && 0/* Disabled for now */ + if (t->current_filesystem->xfer_align != -1 && + t->nlink == 1) + flags |= O_DIRECT; +#endif +#if defined(O_NOATIME) + /* + * Linux has O_NOATIME flag; use it if we need. + */ + if ((t->flags & needsRestoreTimes) != 0 && + t->restore_time.noatime == 0) + flags |= O_NOATIME; + do { +#endif + t->entry_fd = open_on_current_dir(t, + tree_current_access_path(t), flags); + __archive_ensure_cloexec_flag(t->entry_fd); +#if defined(O_NOATIME) + /* + * When we did open the file with O_NOATIME flag, + * if successful, set 1 to t->restore_time.noatime + * not to restore an atime of the file later. + * if failed by EPERM, retry it without O_NOATIME flag. + */ + if (flags & O_NOATIME) { + if (t->entry_fd >= 0) + t->restore_time.noatime = 1; + else if (errno == EPERM) { + flags &= ~O_NOATIME; + continue; + } + } + } while (0); +#endif + if (t->entry_fd < 0) { + archive_set_error(&a->archive, errno, + "Couldn't open %s", tree_current_path(t)); + r = ARCHIVE_FAILED; + tree_enter_initial_dir(t); + goto abort_read_data; + } + tree_enter_initial_dir(t); + } + + /* + * Allocate read buffer if not allocated. + */ + if (t->current_filesystem->allocation_ptr == NULL) { + r = setup_suitable_read_buffer(a); + if (r != ARCHIVE_OK) { + a->archive.state = ARCHIVE_STATE_FATAL; + goto abort_read_data; + } + } + t->entry_buff = t->current_filesystem->buff; + t->entry_buff_size = t->current_filesystem->buff_size; + + buffbytes = t->entry_buff_size; + if ((int64_t)buffbytes > t->current_sparse->length) + buffbytes = t->current_sparse->length; + + if (t->current_sparse->length == 0) + empty_sparse_region = 1; + + /* + * Skip hole. + * TODO: Should we consider t->current_filesystem->xfer_align? + */ + if (t->current_sparse->offset > t->entry_total) { + if (lseek(t->entry_fd, + (off_t)t->current_sparse->offset, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, "Seek error"); + r = ARCHIVE_FATAL; + a->archive.state = ARCHIVE_STATE_FATAL; + goto abort_read_data; + } + bytes = t->current_sparse->offset - t->entry_total; + t->entry_remaining_bytes -= bytes; + t->entry_total += bytes; + } + + /* + * Read file contents. + */ + if (buffbytes > 0) { + bytes = read(t->entry_fd, t->entry_buff, buffbytes); + if (bytes < 0) { + archive_set_error(&a->archive, errno, "Read error"); + r = ARCHIVE_FATAL; + a->archive.state = ARCHIVE_STATE_FATAL; + goto abort_read_data; + } + } else + bytes = 0; + /* + * Return an EOF unless we've read a leading empty sparse region, which + * is used to represent fully-sparse files. + */ + if (bytes == 0 && !empty_sparse_region) { + /* Get EOF */ + t->entry_eof = 1; + r = ARCHIVE_EOF; + goto abort_read_data; + } + *buff = t->entry_buff; + *size = bytes; + *offset = t->entry_total; + t->entry_total += bytes; + t->entry_remaining_bytes -= bytes; + if (t->entry_remaining_bytes == 0) { + /* Close the current file descriptor */ + close_and_restore_time(t->entry_fd, t, &t->restore_time); + t->entry_fd = -1; + t->entry_eof = 1; + } + t->current_sparse->offset += bytes; + t->current_sparse->length -= bytes; + if (t->current_sparse->length == 0 && !t->entry_eof) + t->current_sparse++; + return (ARCHIVE_OK); + +abort_read_data: + *buff = NULL; + *size = 0; + *offset = t->entry_total; + if (t->entry_fd >= 0) { + /* Close the current file descriptor */ + close_and_restore_time(t->entry_fd, t, &t->restore_time); + t->entry_fd = -1; + } + return (r); +} + +static int +next_entry(struct archive_read_disk *a, struct tree *t, + struct archive_entry *entry) +{ + const struct stat *st; /* info to use for this entry */ + const struct stat *lst;/* lstat() information */ + const char *name; + int descend, r; + + st = NULL; + lst = NULL; + t->descend = 0; + do { + switch (tree_next(t)) { + case TREE_ERROR_FATAL: + archive_set_error(&a->archive, t->tree_errno, + "%s: Unable to continue traversing directory tree", + tree_current_path(t)); + a->archive.state = ARCHIVE_STATE_FATAL; + tree_enter_initial_dir(t); + return (ARCHIVE_FATAL); + case TREE_ERROR_DIR: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: Couldn't visit directory", + tree_current_path(t)); + tree_enter_initial_dir(t); + return (ARCHIVE_FAILED); + case 0: + tree_enter_initial_dir(t); + return (ARCHIVE_EOF); + case TREE_POSTDESCENT: + case TREE_POSTASCENT: + break; + case TREE_REGULAR: + lst = tree_current_lstat(t); + if (lst == NULL) { + archive_set_error(&a->archive, errno, + "%s: Cannot stat", + tree_current_path(t)); + tree_enter_initial_dir(t); + return (ARCHIVE_FAILED); + } + break; + } + } while (lst == NULL); + +#ifdef __APPLE__ + if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { + /* If we're using copyfile(), ignore "._XXX" files. */ + const char *bname = strrchr(tree_current_path(t), '/'); + if (bname == NULL) + bname = tree_current_path(t); + else + ++bname; + if (bname[0] == '.' && bname[1] == '_') + return (ARCHIVE_RETRY); + } +#endif + + archive_entry_copy_pathname(entry, tree_current_path(t)); + /* + * Perform path matching. + */ + if (a->matching) { + r = archive_match_path_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* + * Distinguish 'L'/'P'/'H' symlink following. + */ + switch(t->symlink_mode) { + case 'H': + /* 'H': After the first item, rest like 'P'. */ + t->symlink_mode = 'P'; + /* 'H': First item (from command line) like 'L'. */ + /* FALLTHROUGH */ + case 'L': + /* 'L': Do descend through a symlink to dir. */ + descend = tree_current_is_dir(t); + /* 'L': Follow symlinks to files. */ + a->symlink_mode = 'L'; + a->follow_symlinks = 1; + /* 'L': Archive symlinks as targets, if we can. */ + st = tree_current_stat(t); + if (st != NULL && !tree_target_is_same_as_parent(t, st)) + break; + /* If stat fails, we have a broken symlink; + * in that case, don't follow the link. */ + /* FALLTHROUGH */ + default: + /* 'P': Don't descend through a symlink to dir. */ + descend = tree_current_is_physical_dir(t); + /* 'P': Don't follow symlinks to files. */ + a->symlink_mode = 'P'; + a->follow_symlinks = 0; + /* 'P': Archive symlinks as symlinks. */ + st = lst; + break; + } + + if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) { + a->archive.state = ARCHIVE_STATE_FATAL; + tree_enter_initial_dir(t); + return (ARCHIVE_FATAL); + } + if (t->initial_filesystem_id == -1) + t->initial_filesystem_id = t->current_filesystem_id; + if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) { + if (t->initial_filesystem_id != t->current_filesystem_id) + descend = 0; + } + t->descend = descend; + + /* + * Honor nodump flag. + * If the file is marked with nodump flag, do not return this entry. + */ + if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) { +#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) + if (st->st_flags & UF_NODUMP) + return (ARCHIVE_RETRY); +#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \ + defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ + (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \ + defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) + if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { + int stflags; + + t->entry_fd = open_on_current_dir(t, + tree_current_access_path(t), + O_RDONLY | O_NONBLOCK | O_CLOEXEC); + __archive_ensure_cloexec_flag(t->entry_fd); + if (t->entry_fd >= 0) { + r = ioctl(t->entry_fd, +#ifdef FS_IOC_GETFLAGS + FS_IOC_GETFLAGS, +#else + EXT2_IOC_GETFLAGS, +#endif + &stflags); +#ifdef FS_NODUMP_FL + if (r == 0 && (stflags & FS_NODUMP_FL) != 0) +#else + if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) +#endif + return (ARCHIVE_RETRY); + } + } +#endif + } + + archive_entry_copy_stat(entry, st); + + /* Save the times to be restored. This must be in before + * calling archive_read_disk_descend() or any chance of it, + * especially, invoking a callback. */ + t->restore_time.mtime = archive_entry_mtime(entry); + t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); + t->restore_time.atime = archive_entry_atime(entry); + t->restore_time.atime_nsec = archive_entry_atime_nsec(entry); + t->restore_time.filetype = archive_entry_filetype(entry); + t->restore_time.noatime = t->current_filesystem->noatime; + + /* + * Perform time matching. + */ + if (a->matching) { + r = archive_match_time_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* Lookup uname/gname */ + name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); + + /* + * Perform owner matching. + */ + if (a->matching) { + r = archive_match_owner_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* + * Invoke a meta data filter callback. + */ + if (a->metadata_filter_func) { + if (!a->metadata_filter_func(&(a->archive), + a->metadata_filter_data, entry)) + return (ARCHIVE_RETRY); + } + + /* + * Populate the archive_entry with metadata from the disk. + */ + archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); + r = archive_read_disk_entry_from_file(&(a->archive), entry, + t->entry_fd, st); + + return (r); +} + +static int +_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) +{ + int ret; + struct archive_read_disk *a = (struct archive_read_disk *)_a; + *entryp = NULL; + ret = _archive_read_next_header2(_a, a->entry); + *entryp = a->entry; + return ret; +} + +static int +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t; + int r; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_next_header2"); + + t = a->tree; + if (t->entry_fd >= 0) { + close_and_restore_time(t->entry_fd, t, &t->restore_time); + t->entry_fd = -1; + } + + for (;;) { + r = next_entry(a, t, entry); + if (t->entry_fd >= 0) { + close(t->entry_fd); + t->entry_fd = -1; + } + + if (r == ARCHIVE_RETRY) { + archive_entry_clear(entry); + continue; + } + break; + } + + /* Return to the initial directory. */ + tree_enter_initial_dir(t); + + /* + * EOF and FATAL are persistent at this layer. By + * modifying the state, we guarantee that future calls to + * read a header or read data will fail. + */ + switch (r) { + case ARCHIVE_EOF: + a->archive.state = ARCHIVE_STATE_EOF; + break; + case ARCHIVE_OK: + case ARCHIVE_WARN: + /* Overwrite the sourcepath based on the initial directory. */ + archive_entry_copy_sourcepath(entry, tree_current_path(t)); + t->entry_total = 0; + if (archive_entry_filetype(entry) == AE_IFREG) { + t->nlink = archive_entry_nlink(entry); + t->entry_remaining_bytes = archive_entry_size(entry); + t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; + if (!t->entry_eof && + setup_sparse(a, entry) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + t->entry_remaining_bytes = 0; + t->entry_eof = 1; + } + a->archive.state = ARCHIVE_STATE_DATA; + break; + case ARCHIVE_RETRY: + break; + case ARCHIVE_FATAL: + a->archive.state = ARCHIVE_STATE_FATAL; + break; + } + + __archive_reset_read_data(&a->archive); + return (r); +} + +static int +setup_sparse(struct archive_read_disk *a, struct archive_entry *entry) +{ + struct tree *t = a->tree; + int64_t length, offset; + int i; + + t->sparse_count = archive_entry_sparse_reset(entry); + if (t->sparse_count+1 > t->sparse_list_size) { + free(t->sparse_list); + t->sparse_list_size = t->sparse_count + 1; + t->sparse_list = malloc(sizeof(t->sparse_list[0]) * + t->sparse_list_size); + if (t->sparse_list == NULL) { + t->sparse_list_size = 0; + archive_set_error(&a->archive, ENOMEM, + "Can't allocate data"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } + for (i = 0; i < t->sparse_count; i++) { + archive_entry_sparse_next(entry, &offset, &length); + t->sparse_list[i].offset = offset; + t->sparse_list[i].length = length; + } + if (i == 0) { + t->sparse_list[i].offset = 0; + t->sparse_list[i].length = archive_entry_size(entry); + } else { + t->sparse_list[i].offset = archive_entry_size(entry); + t->sparse_list[i].length = 0; + } + t->current_sparse = t->sparse_list; + + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_matching(struct archive *_a, struct archive *_ma, + void (*_excluded_func)(struct archive *, void *, struct archive_entry *), + void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); + a->matching = _ma; + a->excluded_cb_func = _excluded_func; + a->excluded_cb_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_metadata_filter_callback(struct archive *_a, + int (*_metadata_filter_func)(struct archive *, void *, + struct archive_entry *), void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, + "archive_read_disk_set_metadata_filter_callback"); + + a->metadata_filter_func = _metadata_filter_func; + a->metadata_filter_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_can_descend(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_disk_can_descend"); + + return (t->visit_type == TREE_REGULAR && t->descend); +} + +/* + * Called by the client to mark the directory just returned from + * tree_next() as needing to be visited. + */ +int +archive_read_disk_descend(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_disk_descend"); + + if (t->visit_type != TREE_REGULAR || !t->descend) + return (ARCHIVE_OK); + + if (tree_current_is_physical_dir(t)) { + tree_push(t, t->basename, t->current_filesystem_id, + t->lst.st_dev, t->lst.st_ino, &t->restore_time); + t->stack->flags |= isDir; + } else if (tree_current_is_dir(t)) { + tree_push(t, t->basename, t->current_filesystem_id, + t->st.st_dev, t->st.st_ino, &t->restore_time); + t->stack->flags |= isDirLink; + } + t->descend = 0; + return (ARCHIVE_OK); +} + +int +archive_read_disk_open(struct archive *_a, const char *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, + "archive_read_disk_open"); + archive_clear_error(&a->archive); + + return (_archive_read_disk_open(_a, pathname)); +} + +int +archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct archive_string path; + int ret; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, + "archive_read_disk_open_w"); + archive_clear_error(&a->archive); + + /* Make a char string from a wchar_t string. */ + archive_string_init(&path); + if (archive_string_append_from_wcs(&path, pathname, + wcslen(pathname)) != 0) { + if (errno == ENOMEM) + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can't convert a path to a char string"); + a->archive.state = ARCHIVE_STATE_FATAL; + ret = ARCHIVE_FATAL; + } else + ret = _archive_read_disk_open(_a, path.s); + + archive_string_free(&path); + return (ret); +} + +static int +_archive_read_disk_open(struct archive *_a, const char *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + if (a->tree != NULL) + a->tree = tree_reopen(a->tree, pathname, + a->flags & ARCHIVE_READDISK_RESTORE_ATIME); + else + a->tree = tree_open(pathname, a->symlink_mode, + a->flags & ARCHIVE_READDISK_RESTORE_ATIME); + if (a->tree == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate tar data"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + a->archive.state = ARCHIVE_STATE_HEADER; + + return (ARCHIVE_OK); +} + +/* + * Return a current filesystem ID which is index of the filesystem entry + * you've visited through archive_read_disk. + */ +int +archive_read_disk_current_filesystem(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem_id); +} + +static int +update_current_filesystem(struct archive_read_disk *a, int64_t dev) +{ + struct tree *t = a->tree; + int i, fid; + + if (t->current_filesystem != NULL && + t->current_filesystem->dev == dev) + return (ARCHIVE_OK); + + for (i = 0; i < t->max_filesystem_id; i++) { + if (t->filesystem_table[i].dev == dev) { + /* There is the filesystem ID we've already generated. */ + t->current_filesystem_id = i; + t->current_filesystem = &(t->filesystem_table[i]); + return (ARCHIVE_OK); + } + } + + /* + * This is the new filesystem which we have to generate a new ID for. + */ + fid = t->max_filesystem_id++; + if (t->max_filesystem_id > t->allocated_filesystem) { + size_t s; + void *p; + + s = t->max_filesystem_id * 2; + p = realloc(t->filesystem_table, + s * sizeof(*t->filesystem_table)); + if (p == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate tar data"); + return (ARCHIVE_FATAL); + } + t->filesystem_table = (struct filesystem *)p; + t->allocated_filesystem = s; + } + t->current_filesystem_id = fid; + t->current_filesystem = &(t->filesystem_table[fid]); + t->current_filesystem->dev = dev; + t->current_filesystem->allocation_ptr = NULL; + t->current_filesystem->buff = NULL; + + /* Setup the current filesystem properties which depend on + * platform specific. */ + return (setup_current_filesystem(a)); +} + +/* + * Returns 1 if current filesystem is generated filesystem, 0 if it is not + * or -1 if it is unknown. + */ +int +archive_read_disk_current_filesystem_is_synthetic(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem->synthetic); +} + +/* + * Returns 1 if current filesystem is remote filesystem, 0 if it is not + * or -1 if it is unknown. + */ +int +archive_read_disk_current_filesystem_is_remote(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem->remote); +} + +#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\ + defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN) +static int +get_xfer_size(struct tree *t, int fd, const char *path) +{ + t->current_filesystem->xfer_align = -1; + errno = 0; + if (fd >= 0) { + t->current_filesystem->incr_xfer_size = + fpathconf(fd, _PC_REC_INCR_XFER_SIZE); + t->current_filesystem->max_xfer_size = + fpathconf(fd, _PC_REC_MAX_XFER_SIZE); + t->current_filesystem->min_xfer_size = + fpathconf(fd, _PC_REC_MIN_XFER_SIZE); + t->current_filesystem->xfer_align = + fpathconf(fd, _PC_REC_XFER_ALIGN); + } else if (path != NULL) { + t->current_filesystem->incr_xfer_size = + pathconf(path, _PC_REC_INCR_XFER_SIZE); + t->current_filesystem->max_xfer_size = + pathconf(path, _PC_REC_MAX_XFER_SIZE); + t->current_filesystem->min_xfer_size = + pathconf(path, _PC_REC_MIN_XFER_SIZE); + t->current_filesystem->xfer_align = + pathconf(path, _PC_REC_XFER_ALIGN); + } + /* At least we need an alignment size. */ + if (t->current_filesystem->xfer_align == -1) + return ((errno == EINVAL)?1:-1); + else + return (0); +} +#else +static int +get_xfer_size(struct tree *t, int fd, const char *path) +{ + (void)t; /* UNUSED */ + (void)fd; /* UNUSED */ + (void)path; /* UNUSED */ + return (1);/* Not supported */ +} +#endif + +#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \ + && !defined(ST_LOCAL) + +/* + * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X. + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + struct statfs sfs; +#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) +/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make + * this accurate; some platforms have both and we need the one that's + * used by getvfsbyname() + * + * Then the following would become: + * #if defined(GETVFSBYNAME_ARG_TYPE) + * GETVFSBYNAME_ARG_TYPE vfc; + * #endif + */ +# if defined(HAVE_STRUCT_XVFSCONF) + struct xvfsconf vfc; +# else + struct vfsconf vfc; +# endif +#endif + int r, xr = 0; +#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) + long nm; +#endif + + t->current_filesystem->synthetic = -1; + t->current_filesystem->remote = -1; + if (tree_current_is_symblic_link_target(t)) { +#if defined(HAVE_OPENAT) + /* + * Get file system statistics on any directory + * where current is. + */ + int fd = openat(tree_current_dir_fd(t), + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + if (fd < 0) { + archive_set_error(&a->archive, errno, + "openat failed"); + return (ARCHIVE_FAILED); + } + r = fstatfs(fd, &sfs); + if (r == 0) + xr = get_xfer_size(t, fd, NULL); + close(fd); +#else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + r = statfs(tree_current_access_path(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, tree_current_access_path(t)); +#endif + } else { + r = fstatfs(tree_current_dir_fd(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); + } + if (r == -1 || xr == -1) { + archive_set_error(&a->archive, errno, "statfs failed"); + return (ARCHIVE_FAILED); + } else if (xr == 1) { + /* pathconf(_PC_REX_*) operations are not supported. */ + t->current_filesystem->xfer_align = sfs.f_bsize; + t->current_filesystem->max_xfer_size = -1; + t->current_filesystem->min_xfer_size = sfs.f_iosize; + t->current_filesystem->incr_xfer_size = sfs.f_iosize; + } + if (sfs.f_flags & MNT_LOCAL) + t->current_filesystem->remote = 0; + else + t->current_filesystem->remote = 1; + +#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) + r = getvfsbyname(sfs.f_fstypename, &vfc); + if (r == -1) { + archive_set_error(&a->archive, errno, "getvfsbyname failed"); + return (ARCHIVE_FAILED); + } + if (vfc.vfc_flags & VFCF_SYNTHETIC) + t->current_filesystem->synthetic = 1; + else + t->current_filesystem->synthetic = 0; +#endif + +#if defined(MNT_NOATIME) + if (sfs.f_flags & MNT_NOATIME) + t->current_filesystem->noatime = 1; + else +#endif + t->current_filesystem->noatime = 0; + +#if defined(USE_READDIR_R) + /* Set maximum filename length. */ +#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) + t->current_filesystem->name_max = sfs.f_namemax; +#else +# if defined(_PC_NAME_MAX) + /* Mac OS X does not have f_namemax in struct statfs. */ + if (tree_current_is_symblic_link_target(t)) { + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); + } else + nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); +# else + nm = -1; +# endif + if (nm == -1) + t->current_filesystem->name_max = NAME_MAX; + else + t->current_filesystem->name_max = nm; +#endif +#endif /* USE_READDIR_R */ + return (ARCHIVE_OK); +} + +#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL) + +/* + * Gather current filesystem properties on NetBSD + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + struct statvfs sfs; + int r, xr = 0; + + t->current_filesystem->synthetic = -1; + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + if (tree_current_is_symblic_link_target(t)) { + r = statvfs(tree_current_access_path(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, tree_current_access_path(t)); + } else { +#ifdef HAVE_FSTATVFS + r = fstatvfs(tree_current_dir_fd(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); +#else + r = statvfs(".", &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, "."); +#endif + } + if (r == -1 || xr == -1) { + t->current_filesystem->remote = -1; + archive_set_error(&a->archive, errno, "statvfs failed"); + return (ARCHIVE_FAILED); + } else if (xr == 1) { + /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN + * for pathconf() function. */ + t->current_filesystem->xfer_align = sfs.f_frsize; + t->current_filesystem->max_xfer_size = -1; +#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) + t->current_filesystem->min_xfer_size = sfs.f_iosize; + t->current_filesystem->incr_xfer_size = sfs.f_iosize; +#else + t->current_filesystem->min_xfer_size = sfs.f_bsize; + t->current_filesystem->incr_xfer_size = sfs.f_bsize; +#endif + } + if (sfs.f_flag & ST_LOCAL) + t->current_filesystem->remote = 0; + else + t->current_filesystem->remote = 1; + +#if defined(ST_NOATIME) + if (sfs.f_flag & ST_NOATIME) + t->current_filesystem->noatime = 1; + else +#endif + t->current_filesystem->noatime = 0; + + /* Set maximum filename length. */ + t->current_filesystem->name_max = sfs.f_namemax; + return (ARCHIVE_OK); +} + +#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\ + defined(HAVE_STATFS) && defined(HAVE_FSTATFS) +/* + * Note: statfs is deprecated since LSB 3.2 + */ + +#ifndef CIFS_SUPER_MAGIC +#define CIFS_SUPER_MAGIC 0xFF534D42 +#endif +#ifndef DEVFS_SUPER_MAGIC +#define DEVFS_SUPER_MAGIC 0x1373 +#endif + +/* + * Gather current filesystem properties on Linux + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + struct statfs sfs; +#if defined(HAVE_STATVFS) + struct statvfs svfs; +#endif + int r, vr = 0, xr = 0; + + if (tree_current_is_symblic_link_target(t)) { +#if defined(HAVE_OPENAT) + /* + * Get file system statistics on any directory + * where current is. + */ + int fd = openat(tree_current_dir_fd(t), + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + if (fd < 0) { + archive_set_error(&a->archive, errno, + "openat failed"); + return (ARCHIVE_FAILED); + } +#if defined(HAVE_FSTATVFS) + vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */ +#endif + r = fstatfs(fd, &sfs); + if (r == 0) + xr = get_xfer_size(t, fd, NULL); + close(fd); +#else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } +#if defined(HAVE_STATVFS) + vr = statvfs(tree_current_access_path(t), &svfs); +#endif + r = statfs(tree_current_access_path(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, tree_current_access_path(t)); +#endif + } else { +#ifdef HAVE_FSTATFS +#if defined(HAVE_FSTATVFS) + vr = fstatvfs(tree_current_dir_fd(t), &svfs); +#endif + r = fstatfs(tree_current_dir_fd(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); +#else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } +#if defined(HAVE_STATVFS) + vr = statvfs(".", &svfs); +#endif + r = statfs(".", &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, "."); +#endif + } + if (r == -1 || xr == -1 || vr == -1) { + t->current_filesystem->synthetic = -1; + t->current_filesystem->remote = -1; + archive_set_error(&a->archive, errno, "statfs failed"); + return (ARCHIVE_FAILED); + } else if (xr == 1) { + /* pathconf(_PC_REX_*) operations are not supported. */ +#if defined(HAVE_STATVFS) + t->current_filesystem->xfer_align = svfs.f_frsize; + t->current_filesystem->max_xfer_size = -1; + t->current_filesystem->min_xfer_size = svfs.f_bsize; + t->current_filesystem->incr_xfer_size = svfs.f_bsize; +#else + t->current_filesystem->xfer_align = sfs.f_frsize; + t->current_filesystem->max_xfer_size = -1; + t->current_filesystem->min_xfer_size = sfs.f_bsize; + t->current_filesystem->incr_xfer_size = sfs.f_bsize; +#endif + } + switch (sfs.f_type) { + case AFS_SUPER_MAGIC: + case CIFS_SUPER_MAGIC: + case CODA_SUPER_MAGIC: + case NCP_SUPER_MAGIC:/* NetWare */ + case NFS_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + t->current_filesystem->remote = 1; + t->current_filesystem->synthetic = 0; + break; + case DEVFS_SUPER_MAGIC: + case PROC_SUPER_MAGIC: + case USBDEVICE_SUPER_MAGIC: + t->current_filesystem->remote = 0; + t->current_filesystem->synthetic = 1; + break; + default: + t->current_filesystem->remote = 0; + t->current_filesystem->synthetic = 0; + break; + } + +#if defined(ST_NOATIME) +#if defined(HAVE_STATVFS) + if (svfs.f_flag & ST_NOATIME) +#else + if (sfs.f_flag & ST_NOATIME) +#endif + t->current_filesystem->noatime = 1; + else +#endif + t->current_filesystem->noatime = 0; + +#if defined(USE_READDIR_R) + /* Set maximum filename length. */ + t->current_filesystem->name_max = sfs.f_namelen; +#endif + return (ARCHIVE_OK); +} + +#elif defined(HAVE_SYS_STATVFS_H) &&\ + (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) + +/* + * Gather current filesystem properties on other posix platform. + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + struct statvfs sfs; + int r, xr = 0; + + t->current_filesystem->synthetic = -1;/* Not supported */ + t->current_filesystem->remote = -1;/* Not supported */ + if (tree_current_is_symblic_link_target(t)) { +#if defined(HAVE_OPENAT) + /* + * Get file system statistics on any directory + * where current is. + */ + int fd = openat(tree_current_dir_fd(t), + tree_current_access_path(t), O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + if (fd < 0) { + archive_set_error(&a->archive, errno, + "openat failed"); + return (ARCHIVE_FAILED); + } + r = fstatvfs(fd, &sfs); + if (r == 0) + xr = get_xfer_size(t, fd, NULL); + close(fd); +#else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + r = statvfs(tree_current_access_path(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, tree_current_access_path(t)); +#endif + } else { +#ifdef HAVE_FSTATVFS + r = fstatvfs(tree_current_dir_fd(t), &sfs); + if (r == 0) + xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); +#else + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + r = statvfs(".", &sfs); + if (r == 0) + xr = get_xfer_size(t, -1, "."); +#endif + } + if (r == -1 || xr == -1) { + t->current_filesystem->synthetic = -1; + t->current_filesystem->remote = -1; + archive_set_error(&a->archive, errno, "statvfs failed"); + return (ARCHIVE_FAILED); + } else if (xr == 1) { + /* pathconf(_PC_REX_*) operations are not supported. */ + t->current_filesystem->xfer_align = sfs.f_frsize; + t->current_filesystem->max_xfer_size = -1; + t->current_filesystem->min_xfer_size = sfs.f_bsize; + t->current_filesystem->incr_xfer_size = sfs.f_bsize; + } + +#if defined(ST_NOATIME) + if (sfs.f_flag & ST_NOATIME) + t->current_filesystem->noatime = 1; + else +#endif + t->current_filesystem->noatime = 0; + +#if defined(USE_READDIR_R) + /* Set maximum filename length. */ + t->current_filesystem->name_max = sfs.f_namemax; +#endif + return (ARCHIVE_OK); +} + +#else + +/* + * Generic: Gather current filesystem properties. + * TODO: Is this generic function really needed? + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; +#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R) + long nm; +#endif + t->current_filesystem->synthetic = -1;/* Not supported */ + t->current_filesystem->remote = -1;/* Not supported */ + t->current_filesystem->noatime = 0; + (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */ + t->current_filesystem->xfer_align = -1;/* Unknown */ + t->current_filesystem->max_xfer_size = -1; + t->current_filesystem->min_xfer_size = -1; + t->current_filesystem->incr_xfer_size = -1; + +#if defined(USE_READDIR_R) + /* Set maximum filename length. */ +# if defined(_PC_NAME_MAX) + if (tree_current_is_symblic_link_target(t)) { + if (tree_enter_working_dir(t) != 0) { + archive_set_error(&a->archive, errno, "fchdir failed"); + return (ARCHIVE_FAILED); + } + nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); + } else + nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); + if (nm == -1) +# endif /* _PC_NAME_MAX */ + /* + * Some systems (HP-UX or others?) incorrectly defined + * NAME_MAX macro to be a smaller value. + */ +# if defined(NAME_MAX) && NAME_MAX >= 255 + t->current_filesystem->name_max = NAME_MAX; +# else + /* No way to get a trusted value of maximum filename + * length. */ + t->current_filesystem->name_max = PATH_MAX; +# endif /* NAME_MAX */ +# if defined(_PC_NAME_MAX) + else + t->current_filesystem->name_max = nm; +# endif /* _PC_NAME_MAX */ +#endif /* USE_READDIR_R */ + return (ARCHIVE_OK); +} + +#endif + +static int +close_and_restore_time(int fd, struct tree *t, struct restore_time *rt) +{ +#ifndef HAVE_UTIMES + (void)t; /* UNUSED */ + (void)rt; /* UNUSED */ + return (close(fd)); +#else +#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) + struct timespec timespecs[2]; +#endif + struct timeval times[2]; + + if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) { + if (fd >= 0) + return (close(fd)); + else + return (0); + } + +#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) + timespecs[1].tv_sec = rt->mtime; + timespecs[1].tv_nsec = rt->mtime_nsec; + + timespecs[0].tv_sec = rt->atime; + timespecs[0].tv_nsec = rt->atime_nsec; + /* futimens() is defined in POSIX.1-2008. */ + if (futimens(fd, timespecs) == 0) + return (close(fd)); +#endif + + times[1].tv_sec = rt->mtime; + times[1].tv_usec = rt->mtime_nsec / 1000; + + times[0].tv_sec = rt->atime; + times[0].tv_usec = rt->atime_nsec / 1000; + +#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__) + if (futimes(fd, times) == 0) + return (close(fd)); +#endif + close(fd); +#if defined(HAVE_FUTIMESAT) + if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0) + return (0); +#endif +#ifdef HAVE_LUTIMES + if (lutimes(rt->name, times) != 0) +#else + if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0) +#endif + return (-1); +#endif + return (0); +} + +static int +open_on_current_dir(struct tree *t, const char *path, int flags) +{ +#ifdef HAVE_OPENAT + return (openat(tree_current_dir_fd(t), path, flags)); +#else + if (tree_enter_working_dir(t) != 0) + return (-1); + return (open(path, flags)); +#endif +} + +static int +tree_dup(int fd) +{ + int new_fd; +#ifdef F_DUPFD_CLOEXEC + static volatile int can_dupfd_cloexec = 1; + + if (can_dupfd_cloexec) { + new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); + if (new_fd != -1) + return (new_fd); + /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, + * but it cannot be used. So we have to try dup(). */ + /* We won't try F_DUPFD_CLOEXEC. */ + can_dupfd_cloexec = 0; + } +#endif /* F_DUPFD_CLOEXEC */ + new_fd = dup(fd); + __archive_ensure_cloexec_flag(new_fd); + return (new_fd); +} + +/* + * Add a directory path to the current stack. + */ +static void +tree_push(struct tree *t, const char *path, int filesystem_id, + int64_t dev, int64_t ino, struct restore_time *rt) +{ + struct tree_entry *te; + + te = calloc(1, sizeof(*te)); + te->next = t->stack; + te->parent = t->current; + if (te->parent) + te->depth = te->parent->depth + 1; + t->stack = te; + archive_string_init(&te->name); + te->symlink_parent_fd = -1; + archive_strcpy(&te->name, path); + te->flags = needsDescent | needsOpen | needsAscent; + te->filesystem_id = filesystem_id; + te->dev = dev; + te->ino = ino; + te->dirname_length = t->dirname_length; + te->restore_time.name = te->name.s; + if (rt != NULL) { + te->restore_time.mtime = rt->mtime; + te->restore_time.mtime_nsec = rt->mtime_nsec; + te->restore_time.atime = rt->atime; + te->restore_time.atime_nsec = rt->atime_nsec; + te->restore_time.filetype = rt->filetype; + te->restore_time.noatime = rt->noatime; + } +} + +/* + * Append a name to the current dir path. + */ +static void +tree_append(struct tree *t, const char *name, size_t name_length) +{ + size_t size_needed; + + t->path.s[t->dirname_length] = '\0'; + t->path.length = t->dirname_length; + /* Strip trailing '/' from name, unless entire name is "/". */ + while (name_length > 1 && name[name_length - 1] == '/') + name_length--; + + /* Resize pathname buffer as needed. */ + size_needed = name_length + t->dirname_length + 2; + archive_string_ensure(&t->path, size_needed); + /* Add a separating '/' if it's needed. */ + if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/') + archive_strappend_char(&t->path, '/'); + t->basename = t->path.s + archive_strlen(&t->path); + archive_strncat(&t->path, name, name_length); + t->restore_time.name = t->basename; +} + +/* + * Open a directory tree for traversal. + */ +static struct tree * +tree_open(const char *path, int symlink_mode, int restore_time) +{ + struct tree *t; + + if ((t = calloc(1, sizeof(*t))) == NULL) + return (NULL); + archive_string_init(&t->path); + archive_string_ensure(&t->path, 31); + t->initial_symlink_mode = symlink_mode; + return (tree_reopen(t, path, restore_time)); +} + +static struct tree * +tree_reopen(struct tree *t, const char *path, int restore_time) +{ + t->flags = (restore_time != 0)?needsRestoreTimes:0; + t->flags |= onInitialDir; + t->visit_type = 0; + t->tree_errno = 0; + t->dirname_length = 0; + t->depth = 0; + t->descend = 0; + t->current = NULL; + t->d = INVALID_DIR_HANDLE; + t->symlink_mode = t->initial_symlink_mode; + archive_string_empty(&t->path); + t->entry_fd = -1; + t->entry_eof = 0; + t->entry_remaining_bytes = 0; + t->initial_filesystem_id = -1; + + /* First item is set up a lot like a symlink traversal. */ + tree_push(t, path, 0, 0, 0, NULL); + t->stack->flags = needsFirstVisit; + t->maxOpenCount = t->openCount = 1; + t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(t->initial_dir_fd); + t->working_dir_fd = tree_dup(t->initial_dir_fd); + return (t); +} + +static int +tree_descent(struct tree *t) +{ + int flag, new_fd, r = 0; + + t->dirname_length = archive_strlen(&t->path); + flag = O_RDONLY | O_CLOEXEC; +#if defined(O_DIRECTORY) + flag |= O_DIRECTORY; +#endif + new_fd = open_on_current_dir(t, t->stack->name.s, flag); + __archive_ensure_cloexec_flag(new_fd); + if (new_fd < 0) { + t->tree_errno = errno; + r = TREE_ERROR_DIR; + } else { + t->depth++; + /* If it is a link, set up fd for the ascent. */ + if (t->stack->flags & isDirLink) { + t->stack->symlink_parent_fd = t->working_dir_fd; + t->openCount++; + if (t->openCount > t->maxOpenCount) + t->maxOpenCount = t->openCount; + } else + close(t->working_dir_fd); + /* Renew the current working directory. */ + t->working_dir_fd = new_fd; + t->flags &= ~onWorkingDir; + } + return (r); +} + +/* + * We've finished a directory; ascend back to the parent. + */ +static int +tree_ascend(struct tree *t) +{ + struct tree_entry *te; + int new_fd, r = 0, prev_dir_fd; + + te = t->stack; + prev_dir_fd = t->working_dir_fd; + if (te->flags & isDirLink) + new_fd = te->symlink_parent_fd; + else { + new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC); + __archive_ensure_cloexec_flag(new_fd); + } + if (new_fd < 0) { + t->tree_errno = errno; + r = TREE_ERROR_FATAL; + } else { + /* Renew the current working directory. */ + t->working_dir_fd = new_fd; + t->flags &= ~onWorkingDir; + /* Current directory has been changed, we should + * close an fd of previous working directory. */ + close_and_restore_time(prev_dir_fd, t, &te->restore_time); + if (te->flags & isDirLink) { + t->openCount--; + te->symlink_parent_fd = -1; + } + t->depth--; + } + return (r); +} + +/* + * Return to the initial directory where tree_open() was performed. + */ +static int +tree_enter_initial_dir(struct tree *t) +{ + int r = 0; + + if ((t->flags & onInitialDir) == 0) { + r = fchdir(t->initial_dir_fd); + if (r == 0) { + t->flags &= ~onWorkingDir; + t->flags |= onInitialDir; + } + } + return (r); +} + +/* + * Restore working directory of directory traversals. + */ +static int +tree_enter_working_dir(struct tree *t) +{ + int r = 0; + + /* + * Change the current directory if really needed. + * Sometimes this is unneeded when we did not do + * descent. + */ + if (t->depth > 0 && (t->flags & onWorkingDir) == 0) { + r = fchdir(t->working_dir_fd); + if (r == 0) { + t->flags &= ~onInitialDir; + t->flags |= onWorkingDir; + } + } + return (r); +} + +static int +tree_current_dir_fd(struct tree *t) +{ + return (t->working_dir_fd); +} + +/* + * Pop the working stack. + */ +static void +tree_pop(struct tree *t) +{ + struct tree_entry *te; + + t->path.s[t->dirname_length] = '\0'; + t->path.length = t->dirname_length; + if (t->stack == t->current && t->current != NULL) + t->current = t->current->parent; + te = t->stack; + t->stack = te->next; + t->dirname_length = te->dirname_length; + t->basename = t->path.s + t->dirname_length; + while (t->basename[0] == '/') + t->basename++; + archive_string_free(&te->name); + free(te); +} + +/* + * Get the next item in the tree traversal. + */ +static int +tree_next(struct tree *t) +{ + int r; + + while (t->stack != NULL) { + /* If there's an open dir, get the next entry from there. */ + if (t->d != INVALID_DIR_HANDLE) { + r = tree_dir_next_posix(t); + if (r == 0) + continue; + return (r); + } + + if (t->stack->flags & needsFirstVisit) { + /* Top stack item needs a regular visit. */ + t->current = t->stack; + tree_append(t, t->stack->name.s, + archive_strlen(&(t->stack->name))); + /* t->dirname_length = t->path_length; */ + /* tree_pop(t); */ + t->stack->flags &= ~needsFirstVisit; + return (t->visit_type = TREE_REGULAR); + } else if (t->stack->flags & needsDescent) { + /* Top stack item is dir to descend into. */ + t->current = t->stack; + tree_append(t, t->stack->name.s, + archive_strlen(&(t->stack->name))); + t->stack->flags &= ~needsDescent; + r = tree_descent(t); + if (r != 0) { + tree_pop(t); + t->visit_type = r; + } else + t->visit_type = TREE_POSTDESCENT; + return (t->visit_type); + } else if (t->stack->flags & needsOpen) { + t->stack->flags &= ~needsOpen; + r = tree_dir_next_posix(t); + if (r == 0) + continue; + return (r); + } else if (t->stack->flags & needsAscent) { + /* Top stack item is dir and we're done with it. */ + r = tree_ascend(t); + tree_pop(t); + t->visit_type = r != 0 ? r : TREE_POSTASCENT; + return (t->visit_type); + } else { + /* Top item on stack is dead. */ + tree_pop(t); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + } + } + return (t->visit_type = 0); +} + +static int +tree_dir_next_posix(struct tree *t) +{ + int r; + const char *name; + size_t namelen; + + if (t->d == NULL) { +#if defined(USE_READDIR_R) + size_t dirent_size; +#endif + +#if defined(HAVE_FDOPENDIR) + t->d = fdopendir(tree_dup(t->working_dir_fd)); +#else /* HAVE_FDOPENDIR */ + if (tree_enter_working_dir(t) == 0) { + t->d = opendir("."); +#if HAVE_DIRFD || defined(dirfd) + __archive_ensure_cloexec_flag(dirfd(t->d)); +#endif + } +#endif /* HAVE_FDOPENDIR */ + if (t->d == NULL) { + r = tree_ascend(t); /* Undo "chdir" */ + tree_pop(t); + t->tree_errno = errno; + t->visit_type = r != 0 ? r : TREE_ERROR_DIR; + return (t->visit_type); + } +#if defined(USE_READDIR_R) + dirent_size = offsetof(struct dirent, d_name) + + t->filesystem_table[t->current->filesystem_id].name_max + 1; + if (t->dirent == NULL || t->dirent_allocated < dirent_size) { + free(t->dirent); + t->dirent = malloc(dirent_size); + if (t->dirent == NULL) { + closedir(t->d); + t->d = INVALID_DIR_HANDLE; + (void)tree_ascend(t); + tree_pop(t); + t->tree_errno = ENOMEM; + t->visit_type = TREE_ERROR_DIR; + return (t->visit_type); + } + t->dirent_allocated = dirent_size; + } +#endif /* USE_READDIR_R */ + } + for (;;) { + errno = 0; +#if defined(USE_READDIR_R) + r = readdir_r(t->d, t->dirent, &t->de); +#ifdef _AIX + /* Note: According to the man page, return value 9 indicates + * that the readdir_r was not successful and the error code + * is set to the global errno variable. And then if the end + * of directory entries was reached, the return value is 9 + * and the third parameter is set to NULL and errno is + * unchanged. */ + if (r == 9) + r = errno; +#endif /* _AIX */ + if (r != 0 || t->de == NULL) { +#else + t->de = readdir(t->d); + if (t->de == NULL) { + r = errno; +#endif + closedir(t->d); + t->d = INVALID_DIR_HANDLE; + if (r != 0) { + t->tree_errno = r; + t->visit_type = TREE_ERROR_DIR; + return (t->visit_type); + } else + return (0); + } + name = t->de->d_name; + namelen = D_NAMELEN(t->de); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + if (name[0] == '.' && name[1] == '\0') + continue; + if (name[0] == '.' && name[1] == '.' && name[2] == '\0') + continue; + tree_append(t, name, namelen); + return (t->visit_type = TREE_REGULAR); + } +} + + +/* + * Get the stat() data for the entry just returned from tree_next(). + */ +static const struct stat * +tree_current_stat(struct tree *t) +{ + if (!(t->flags & hasStat)) { +#ifdef HAVE_FSTATAT + if (fstatat(tree_current_dir_fd(t), + tree_current_access_path(t), &t->st, 0) != 0) +#else + if (tree_enter_working_dir(t) != 0) + return NULL; + if (stat(tree_current_access_path(t), &t->st) != 0) +#endif + return NULL; + t->flags |= hasStat; + } + return (&t->st); +} + +/* + * Get the lstat() data for the entry just returned from tree_next(). + */ +static const struct stat * +tree_current_lstat(struct tree *t) +{ + if (!(t->flags & hasLstat)) { +#ifdef HAVE_FSTATAT + if (fstatat(tree_current_dir_fd(t), + tree_current_access_path(t), &t->lst, + AT_SYMLINK_NOFOLLOW) != 0) +#else + if (tree_enter_working_dir(t) != 0) + return NULL; + if (lstat(tree_current_access_path(t), &t->lst) != 0) +#endif + return NULL; + t->flags |= hasLstat; + } + return (&t->lst); +} + +/* + * Test whether current entry is a dir or link to a dir. + */ +static int +tree_current_is_dir(struct tree *t) +{ + const struct stat *st; + /* + * If we already have lstat() info, then try some + * cheap tests to determine if this is a dir. + */ + if (t->flags & hasLstat) { + /* If lstat() says it's a dir, it must be a dir. */ + st = tree_current_lstat(t); + if (st == NULL) + return 0; + if (S_ISDIR(st->st_mode)) + return 1; + /* Not a dir; might be a link to a dir. */ + /* If it's not a link, then it's not a link to a dir. */ + if (!S_ISLNK(st->st_mode)) + return 0; + /* + * It's a link, but we don't know what it's a link to, + * so we'll have to use stat(). + */ + } + + st = tree_current_stat(t); + /* If we can't stat it, it's not a dir. */ + if (st == NULL) + return 0; + /* Use the definitive test. Hopefully this is cached. */ + return (S_ISDIR(st->st_mode)); +} + +/* + * Test whether current entry is a physical directory. Usually, we + * already have at least one of stat() or lstat() in memory, so we + * use tricks to try to avoid an extra trip to the disk. + */ +static int +tree_current_is_physical_dir(struct tree *t) +{ + const struct stat *st; + + /* + * If stat() says it isn't a dir, then it's not a dir. + * If stat() data is cached, this check is free, so do it first. + */ + if (t->flags & hasStat) { + st = tree_current_stat(t); + if (st == NULL) + return (0); + if (!S_ISDIR(st->st_mode)) + return (0); + } + + /* + * Either stat() said it was a dir (in which case, we have + * to determine whether it's really a link to a dir) or + * stat() info wasn't available. So we use lstat(), which + * hopefully is already cached. + */ + + st = tree_current_lstat(t); + /* If we can't stat it, it's not a dir. */ + if (st == NULL) + return 0; + /* Use the definitive test. Hopefully this is cached. */ + return (S_ISDIR(st->st_mode)); +} + +/* + * Test whether the same file has been in the tree as its parent. + */ +static int +tree_target_is_same_as_parent(struct tree *t, const struct stat *st) +{ + struct tree_entry *te; + + for (te = t->current->parent; te != NULL; te = te->parent) { + if (te->dev == (int64_t)st->st_dev && + te->ino == (int64_t)st->st_ino) + return (1); + } + return (0); +} + +/* + * Test whether the current file is symbolic link target and + * on the other filesystem. + */ +static int +tree_current_is_symblic_link_target(struct tree *t) +{ + static const struct stat *lst, *st; + + lst = tree_current_lstat(t); + st = tree_current_stat(t); + return (st != NULL && lst != NULL && + (int64_t)st->st_dev == t->current_filesystem->dev && + st->st_dev != lst->st_dev); +} + +/* + * Return the access path for the entry just returned from tree_next(). + */ +static const char * +tree_current_access_path(struct tree *t) +{ + return (t->basename); +} + +/* + * Return the full path for the entry just returned from tree_next(). + */ +static const char * +tree_current_path(struct tree *t) +{ + return (t->path.s); +} + +/* + * Terminate the traversal. + */ +static void +tree_close(struct tree *t) +{ + + if (t == NULL) + return; + if (t->entry_fd >= 0) { + close_and_restore_time(t->entry_fd, t, &t->restore_time); + t->entry_fd = -1; + } + /* Close the handle of readdir(). */ + if (t->d != INVALID_DIR_HANDLE) { + closedir(t->d); + t->d = INVALID_DIR_HANDLE; + } + /* Release anything remaining in the stack. */ + while (t->stack != NULL) { + if (t->stack->flags & isDirLink) + close(t->stack->symlink_parent_fd); + tree_pop(t); + } + if (t->working_dir_fd >= 0) { + close(t->working_dir_fd); + t->working_dir_fd = -1; + } + if (t->initial_dir_fd >= 0) { + close(t->initial_dir_fd); + t->initial_dir_fd = -1; + } +} + +/* + * Release any resources. + */ +static void +tree_free(struct tree *t) +{ + int i; + + if (t == NULL) + return; + archive_string_free(&t->path); +#if defined(USE_READDIR_R) + free(t->dirent); +#endif + free(t->sparse_list); + for (i = 0; i < t->max_filesystem_id; i++) + free(t->filesystem_table[i].allocation_ptr); + free(t->filesystem_table); + free(t); +} + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_read_disk_private.h b/src/3rdparty/libarchive/libarchive/archive_read_disk_private.h new file mode 100644 index 00000000..f03a0a9c --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_disk_private.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_read_disk_private.h 201105 2009-12-28 03:20:54Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED +#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED + +#include "archive_platform_acl.h" + +struct tree; +struct archive_entry; + +struct archive_read_disk { + struct archive archive; + + /* Reused by archive_read_next_header() */ + struct archive_entry *entry; + + /* + * Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid, + * following an old BSD convention. 'L' follows all symlinks, + * 'P' follows none, 'H' follows symlinks only for the first + * item. + */ + char symlink_mode; + + /* + * Since symlink interaction changes, we need to track whether + * we're following symlinks for the current item. 'L' mode above + * sets this true, 'P' sets it false, 'H' changes it as we traverse. + */ + char follow_symlinks; /* Either 'L' or 'P'. */ + + /* Directory traversals. */ + struct tree *tree; + int (*open_on_current_dir)(struct tree*, const char *, int); + int (*tree_current_dir_fd)(struct tree*); + int (*tree_enter_working_dir)(struct tree*); + + /* Bitfield with ARCHIVE_READDISK_* tunables */ + int flags; + + const char * (*lookup_gname)(void *private, int64_t gid); + void (*cleanup_gname)(void *private); + void *lookup_gname_data; + const char * (*lookup_uname)(void *private, int64_t uid); + void (*cleanup_uname)(void *private); + void *lookup_uname_data; + + int (*metadata_filter_func)(struct archive *, void *, + struct archive_entry *); + void *metadata_filter_data; + + /* ARCHIVE_MATCH object. */ + struct archive *matching; + /* Callback function, this will be invoked when ARCHIVE_MATCH + * archive_match_*_excluded_ae return true. */ + void (*excluded_cb_func)(struct archive *, void *, + struct archive_entry *); + void *excluded_cb_data; +}; + +const char * +archive_read_disk_entry_setup_path(struct archive_read_disk *, + struct archive_entry *, int *); + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *, + struct archive_entry *, int *); +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c b/src/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c new file mode 100644 index 00000000..c7fd2471 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c @@ -0,0 +1,313 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_set_standard_lookup.c 201109 2009-12-28 03:30:31Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +int +archive_read_disk_set_standard_lookup(struct archive *a) +{ + archive_set_error(a, -1, "Standard lookups not available on Windows"); + return (ARCHIVE_FATAL); +} +#else /* ! (_WIN32 && !__CYGWIN__) */ +#define name_cache_size 127 + +static const char * const NO_NAME = "(noname)"; + +struct name_cache { + struct archive *archive; + char *buff; + size_t buff_size; + int probes; + int hits; + size_t size; + struct { + id_t id; + const char *name; + } cache[name_cache_size]; +}; + +static const char * lookup_gname(void *, int64_t); +static const char * lookup_uname(void *, int64_t); +static void cleanup(void *); +static const char * lookup_gname_helper(struct name_cache *, id_t gid); +static const char * lookup_uname_helper(struct name_cache *, id_t uid); + +/* + * Installs functions that use getpwuid()/getgrgid()---along with + * a simple cache to accelerate such lookups---into the archive_read_disk + * object. This is in a separate file because getpwuid()/getgrgid() + * can pull in a LOT of library code (including NIS/LDAP functions, which + * pull in DNS resolvers, etc). This can easily top 500kB, which makes + * it inappropriate for some space-constrained applications. + * + * Applications that are size-sensitive may want to just use the + * real default functions (defined in archive_read_disk.c) that just + * use the uid/gid without the lookup. Or define your own custom functions + * if you prefer. + */ +int +archive_read_disk_set_standard_lookup(struct archive *a) +{ + struct name_cache *ucache = malloc(sizeof(struct name_cache)); + struct name_cache *gcache = malloc(sizeof(struct name_cache)); + + if (ucache == NULL || gcache == NULL) { + archive_set_error(a, ENOMEM, + "Can't allocate uname/gname lookup cache"); + free(ucache); + free(gcache); + return (ARCHIVE_FATAL); + } + + memset(ucache, 0, sizeof(*ucache)); + ucache->archive = a; + ucache->size = name_cache_size; + memset(gcache, 0, sizeof(*gcache)); + gcache->archive = a; + gcache->size = name_cache_size; + + archive_read_disk_set_gname_lookup(a, gcache, lookup_gname, cleanup); + archive_read_disk_set_uname_lookup(a, ucache, lookup_uname, cleanup); + + return (ARCHIVE_OK); +} + +static void +cleanup(void *data) +{ + struct name_cache *cache = (struct name_cache *)data; + size_t i; + + if (cache != NULL) { + for (i = 0; i < cache->size; i++) { + if (cache->cache[i].name != NULL && + cache->cache[i].name != NO_NAME) + free((void *)(uintptr_t)cache->cache[i].name); + } + free(cache->buff); + free(cache); + } +} + +/* + * Lookup uid/gid from uname/gname, return NULL if no match. + */ +static const char * +lookup_name(struct name_cache *cache, + const char * (*lookup_fn)(struct name_cache *, id_t), id_t id) +{ + const char *name; + int slot; + + + cache->probes++; + + slot = id % cache->size; + if (cache->cache[slot].name != NULL) { + if (cache->cache[slot].id == id) { + cache->hits++; + if (cache->cache[slot].name == NO_NAME) + return (NULL); + return (cache->cache[slot].name); + } + if (cache->cache[slot].name != NO_NAME) + free((void *)(uintptr_t)cache->cache[slot].name); + cache->cache[slot].name = NULL; + } + + name = (lookup_fn)(cache, id); + if (name == NULL) { + /* Cache and return the negative response. */ + cache->cache[slot].name = NO_NAME; + cache->cache[slot].id = id; + return (NULL); + } + + cache->cache[slot].name = name; + cache->cache[slot].id = id; + return (cache->cache[slot].name); +} + +static const char * +lookup_uname(void *data, int64_t uid) +{ + struct name_cache *uname_cache = (struct name_cache *)data; + return (lookup_name(uname_cache, + &lookup_uname_helper, (id_t)uid)); +} + +#if HAVE_GETPWUID_R +static const char * +lookup_uname_helper(struct name_cache *cache, id_t id) +{ + struct passwd pwent, *result; + char * nbuff; + size_t nbuff_size; + int r; + + if (cache->buff_size == 0) { + cache->buff_size = 256; + cache->buff = malloc(cache->buff_size); + } + if (cache->buff == NULL) + return (NULL); + for (;;) { + result = &pwent; /* Old getpwuid_r ignores last arg. */ + r = getpwuid_r((uid_t)id, &pwent, + cache->buff, cache->buff_size, &result); + if (r == 0) + break; + if (r != ERANGE) + break; + /* 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. 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; + nbuff = realloc(cache->buff, nbuff_size); + if (nbuff == NULL) + break; + cache->buff = nbuff; + cache->buff_size = nbuff_size; + } + if (r != 0) { + archive_set_error(cache->archive, errno, + "Can't lookup user for id %d", (int)id); + return (NULL); + } + if (result == NULL) + return (NULL); + + return strdup(result->pw_name); +} +#else +static const char * +lookup_uname_helper(struct name_cache *cache, id_t id) +{ + struct passwd *result; + (void)cache; /* UNUSED */ + + result = getpwuid((uid_t)id); + + if (result == NULL) + return (NULL); + + return strdup(result->pw_name); +} +#endif + +static const char * +lookup_gname(void *data, int64_t gid) +{ + struct name_cache *gname_cache = (struct name_cache *)data; + return (lookup_name(gname_cache, + &lookup_gname_helper, (id_t)gid)); +} + +#if HAVE_GETGRGID_R +static const char * +lookup_gname_helper(struct name_cache *cache, id_t id) +{ + struct group grent, *result; + char * nbuff; + size_t nbuff_size; + int r; + + if (cache->buff_size == 0) { + cache->buff_size = 256; + cache->buff = malloc(cache->buff_size); + } + if (cache->buff == NULL) + return (NULL); + for (;;) { + result = &grent; /* Old getgrgid_r ignores last arg. */ + r = getgrgid_r((gid_t)id, &grent, + cache->buff, cache->buff_size, &result); + if (r == 0) + break; + if (r != ERANGE) + break; + /* 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; + nbuff = realloc(cache->buff, nbuff_size); + if (nbuff == NULL) + break; + cache->buff = nbuff; + cache->buff_size = nbuff_size; + } + if (r != 0) { + archive_set_error(cache->archive, errno, + "Can't lookup group for id %d", (int)id); + return (NULL); + } + if (result == NULL) + return (NULL); + + return strdup(result->gr_name); +} +#else +static const char * +lookup_gname_helper(struct name_cache *cache, id_t id) +{ + struct group *result; + (void)cache; /* UNUSED */ + + result = getgrgid((gid_t)id); + + if (result == NULL) + return (NULL); + + return strdup(result->gr_name); +} +#endif + +#endif /* ! (_WIN32 && !__CYGWIN__) */ diff --git a/src/3rdparty/libarchive/libarchive/archive_read_disk_windows.c b/src/3rdparty/libarchive/libarchive/archive_read_disk_windows.c new file mode 100644 index 00000000..3b903304 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_disk_windows.c @@ -0,0 +1,2298 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#include "archive.h" +#include "archive_string.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef IO_REPARSE_TAG_SYMLINK +/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ +#define IO_REPARSE_TAG_SYMLINK 0xA000000CL +#endif + +/*- + * This is a new directory-walking system that addresses a number + * of problems I've had with fts(3). In particular, it has no + * pathname-length limits (other than the size of 'int'), handles + * deep logical traversals, uses considerably less memory, and has + * an opaque interface (easier to modify in the future). + * + * Internally, it keeps a single list of "tree_entry" items that + * represent filesystem objects that require further attention. + * Non-directories are not kept in memory: they are pulled from + * readdir(), returned to the client, then freed as soon as possible. + * Any directory entry to be traversed gets pushed onto the stack. + * + * There is surprisingly little information that needs to be kept for + * each item on the stack. Just the name, depth (represented here as the + * string length of the parent directory's pathname), and some markers + * indicating how to get back to the parent (via chdir("..") for a + * regular dir or via fchdir(2) for a symlink). + */ + +struct restore_time { + const wchar_t *full_path; + FILETIME lastWriteTime; + FILETIME lastAccessTime; + mode_t filetype; +}; + +struct tree_entry { + int depth; + struct tree_entry *next; + struct tree_entry *parent; + size_t full_path_dir_length; + struct archive_wstring name; + struct archive_wstring full_path; + size_t dirname_length; + int64_t dev; + int64_t ino; + int flags; + int filesystem_id; + /* How to restore time of a directory. */ + struct restore_time restore_time; +}; + +struct filesystem { + int64_t dev; + int synthetic; + int remote; + DWORD bytesPerSector; +}; + +/* Definitions for tree_entry.flags bitmap. */ +#define isDir 1 /* This entry is a regular directory. */ +#define isDirLink 2 /* This entry is a symbolic link to a directory. */ +#define needsFirstVisit 4 /* This is an initial entry. */ +#define needsDescent 8 /* This entry needs to be previsited. */ +#define needsOpen 16 /* This is a directory that needs to be opened. */ +#define needsAscent 32 /* This entry needs to be postvisited. */ + +/* + * On Windows, "first visit" is handled as a pattern to be handed to + * _findfirst(). This is consistent with Windows conventions that + * file patterns are handled within the application. On Posix, + * "first visit" is just returned to the client. + */ + +#define MAX_OVERLAPPED 8 +#define BUFFER_SIZE (1024 * 8) +#define DIRECT_IO 0/* Disabled */ +#define ASYNC_IO 1/* Enabled */ + +/* + * Local data for this package. + */ +struct tree { + struct tree_entry *stack; + struct tree_entry *current; + HANDLE d; + WIN32_FIND_DATAW _findData; + WIN32_FIND_DATAW *findData; + int flags; + int visit_type; + /* Error code from last failed operation. */ + int tree_errno; + + /* A full path with "\\?\" prefix. */ + struct archive_wstring full_path; + size_t full_path_dir_length; + /* Dynamically-sized buffer for holding path */ + struct archive_wstring path; + + /* Last path element */ + const wchar_t *basename; + /* Leading dir length */ + size_t dirname_length; + + int depth; + + BY_HANDLE_FILE_INFORMATION lst; + BY_HANDLE_FILE_INFORMATION st; + int descend; + /* How to restore time of a file. */ + struct restore_time restore_time; + + struct entry_sparse { + int64_t length; + int64_t offset; + } *sparse_list, *current_sparse; + int sparse_count; + int sparse_list_size; + + char initial_symlink_mode; + char symlink_mode; + struct filesystem *current_filesystem; + struct filesystem *filesystem_table; + int initial_filesystem_id; + int current_filesystem_id; + int max_filesystem_id; + int allocated_filesystem; + + HANDLE entry_fh; + int entry_eof; + int64_t entry_remaining_bytes; + int64_t entry_total; + + int ol_idx_doing; + int ol_idx_done; + int ol_num_doing; + int ol_num_done; + int64_t ol_remaining_bytes; + int64_t ol_total; + struct la_overlapped { + OVERLAPPED ol; + struct archive * _a; + unsigned char *buff; + size_t buff_size; + int64_t offset; + size_t bytes_expected; + size_t bytes_transferred; + } ol[MAX_OVERLAPPED]; + int direct_io; + int async_io; +}; + +#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber) +/* Treat FileIndex as i-node. We should remove a sequence number + * which is high-16-bits of nFileIndexHigh. */ +#define bhfi_ino(bhfi) \ + ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \ + + (bhfi)->nFileIndexLow) + +/* Definitions for tree.flags bitmap. */ +#define hasStat 16 /* The st entry is valid. */ +#define hasLstat 32 /* The lst entry is valid. */ +#define needsRestoreTimes 128 + +static int +tree_dir_next_windows(struct tree *t, const wchar_t *pattern); + +/* Initiate/terminate a tree traversal. */ +static struct tree *tree_open(const wchar_t *, int, int); +static struct tree *tree_reopen(struct tree *, const wchar_t *, int); +static void tree_close(struct tree *); +static void tree_free(struct tree *); +static void tree_push(struct tree *, const wchar_t *, const wchar_t *, + int, int64_t, int64_t, struct restore_time *); + +/* + * tree_next() returns Zero if there is no next entry, non-zero if + * there is. Note that directories are visited three times. + * Directories are always visited first as part of enumerating their + * parent; that is a "regular" visit. If tree_descend() is invoked at + * that time, the directory is added to a work list and will + * subsequently be visited two more times: once just after descending + * into the directory ("postdescent") and again just after ascending + * back to the parent ("postascent"). + * + * TREE_ERROR_DIR is returned if the descent failed (because the + * directory couldn't be opened, for instance). This is returned + * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a + * fatal error, but it does imply that the relevant subtree won't be + * visited. TREE_ERROR_FATAL is returned for an error that left the + * traversal completely hosed. Right now, this is only returned for + * chdir() failures during ascent. + */ +#define TREE_REGULAR 1 +#define TREE_POSTDESCENT 2 +#define TREE_POSTASCENT 3 +#define TREE_ERROR_DIR -1 +#define TREE_ERROR_FATAL -2 + +static int tree_next(struct tree *); + +/* + * Return information about the current entry. + */ + +/* + * The current full pathname, length of the full pathname, and a name + * that can be used to access the file. Because tree does use chdir + * extensively, the access path is almost never the same as the full + * current path. + * + */ +static const wchar_t *tree_current_path(struct tree *); +static const wchar_t *tree_current_access_path(struct tree *); + +/* + * Request the lstat() or stat() data for the current path. Since the + * tree package needs to do some of this anyway, and caches the + * results, you should take advantage of it here if you need it rather + * than make a redundant stat() or lstat() call of your own. + */ +static const BY_HANDLE_FILE_INFORMATION *tree_current_stat(struct tree *); +static const BY_HANDLE_FILE_INFORMATION *tree_current_lstat(struct tree *); + +/* The following functions use tricks to avoid a certain number of + * stat()/lstat() calls. */ +/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ +static int tree_current_is_physical_dir(struct tree *); +/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */ +static int tree_current_is_physical_link(struct tree *); +/* Instead of archive_entry_copy_stat for BY_HANDLE_FILE_INFORMATION */ +static void tree_archive_entry_copy_bhfi(struct archive_entry *, + struct tree *, const BY_HANDLE_FILE_INFORMATION *); +/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ +static int tree_current_is_dir(struct tree *); +static int update_current_filesystem(struct archive_read_disk *a, + int64_t dev); +static int setup_current_filesystem(struct archive_read_disk *); +static int tree_target_is_same_as_parent(struct tree *, + const BY_HANDLE_FILE_INFORMATION *); + +static int _archive_read_disk_open_w(struct archive *, const wchar_t *); +static int _archive_read_free(struct archive *); +static int _archive_read_close(struct archive *); +static int _archive_read_data_block(struct archive *, + const void **, size_t *, int64_t *); +static int _archive_read_next_header(struct archive *, + struct archive_entry **); +static int _archive_read_next_header2(struct archive *, + struct archive_entry *); +static const char *trivial_lookup_gname(void *, int64_t gid); +static const char *trivial_lookup_uname(void *, int64_t uid); +static int setup_sparse(struct archive_read_disk *, struct archive_entry *); +static int close_and_restore_time(HANDLE, struct tree *, + struct restore_time *); +static int setup_sparse_from_disk(struct archive_read_disk *, + struct archive_entry *, HANDLE); + + + +static struct archive_vtable * +archive_read_disk_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_free = _archive_read_free; + av.archive_close = _archive_read_close; + av.archive_read_data_block = _archive_read_data_block; + av.archive_read_next_header = _archive_read_next_header; + av.archive_read_next_header2 = _archive_read_next_header2; + inited = 1; + } + return (&av); +} + +const char * +archive_read_disk_gname(struct archive *_a, int64_t gid) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_gname")) + return (NULL); + if (a->lookup_gname == NULL) + return (NULL); + return ((*a->lookup_gname)(a->lookup_gname_data, gid)); +} + +const char * +archive_read_disk_uname(struct archive *_a, int64_t uid) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_uname")) + return (NULL); + if (a->lookup_uname == NULL) + return (NULL); + return ((*a->lookup_uname)(a->lookup_uname_data, uid)); +} + +int +archive_read_disk_set_gname_lookup(struct archive *_a, + void *private_data, + const char * (*lookup_gname)(void *private, int64_t gid), + void (*cleanup_gname)(void *private)) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); + + if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) + (a->cleanup_gname)(a->lookup_gname_data); + + a->lookup_gname = lookup_gname; + a->cleanup_gname = cleanup_gname; + a->lookup_gname_data = private_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_uname_lookup(struct archive *_a, + void *private_data, + const char * (*lookup_uname)(void *private, int64_t uid), + void (*cleanup_uname)(void *private)) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); + + if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) + (a->cleanup_uname)(a->lookup_uname_data); + + a->lookup_uname = lookup_uname; + a->cleanup_uname = cleanup_uname; + a->lookup_uname_data = private_data; + return (ARCHIVE_OK); +} + +/* + * Create a new archive_read_disk object and initialize it with global state. + */ +struct archive * +archive_read_disk_new(void) +{ + struct archive_read_disk *a; + + a = (struct archive_read_disk *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_READ_DISK_MAGIC; + a->archive.state = ARCHIVE_STATE_NEW; + a->archive.vtable = archive_read_disk_vtable(); + a->entry = archive_entry_new2(&a->archive); + a->lookup_uname = trivial_lookup_uname; + a->lookup_gname = trivial_lookup_gname; + a->flags = ARCHIVE_READDISK_MAC_COPYFILE; + return (&a->archive); +} + +static int +_archive_read_free(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + int r; + + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); + + if (a->archive.state != ARCHIVE_STATE_CLOSED) + r = _archive_read_close(&a->archive); + else + r = ARCHIVE_OK; + + tree_free(a->tree); + if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) + (a->cleanup_gname)(a->lookup_gname_data); + if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) + (a->cleanup_uname)(a->lookup_uname_data); + archive_string_free(&a->archive.error_string); + archive_entry_free(a->entry); + a->archive.magic = 0; + free(a); + return (r); +} + +static int +_archive_read_close(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); + + if (a->archive.state != ARCHIVE_STATE_FATAL) + a->archive.state = ARCHIVE_STATE_CLOSED; + + tree_close(a->tree); + + return (ARCHIVE_OK); +} + +static void +setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, + int follow_symlinks) +{ + a->symlink_mode = symlink_mode; + a->follow_symlinks = follow_symlinks; + if (a->tree != NULL) { + a->tree->initial_symlink_mode = a->symlink_mode; + a->tree->symlink_mode = a->symlink_mode; + } +} + +int +archive_read_disk_set_symlink_logical(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); + setup_symlink_mode(a, 'L', 1); + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_symlink_physical(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); + setup_symlink_mode(a, 'P', 0); + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_symlink_hybrid(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); + setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_atime_restored(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); + a->flags |= ARCHIVE_READDISK_RESTORE_ATIME; + if (a->tree != NULL) + a->tree->flags |= needsRestoreTimes; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_behavior(struct archive *_a, int flags) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + int r = ARCHIVE_OK; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); + + a->flags = flags; + + if (flags & ARCHIVE_READDISK_RESTORE_ATIME) + r = archive_read_disk_set_atime_restored(_a); + else { + if (a->tree != NULL) + a->tree->flags &= ~needsRestoreTimes; + } + return (r); +} + +/* + * Trivial implementations of gname/uname lookup functions. + * These are normally overridden by the client, but these stub + * versions ensure that we always have something that works. + */ +static const char * +trivial_lookup_gname(void *private_data, int64_t gid) +{ + (void)private_data; /* UNUSED */ + (void)gid; /* UNUSED */ + return (NULL); +} + +static const char * +trivial_lookup_uname(void *private_data, int64_t uid) +{ + (void)private_data; /* UNUSED */ + (void)uid; /* UNUSED */ + return (NULL); +} + +static int64_t +align_num_per_sector(struct tree *t, int64_t size) +{ + int64_t surplus; + + size += t->current_filesystem->bytesPerSector -1; + surplus = size % t->current_filesystem->bytesPerSector; + size -= surplus; + return (size); +} + +static int +start_next_async_read(struct archive_read_disk *a, struct tree *t) +{ + struct la_overlapped *olp; + DWORD buffbytes, rbytes; + + if (t->ol_remaining_bytes == 0) + return (ARCHIVE_EOF); + + olp = &(t->ol[t->ol_idx_doing]); + t->ol_idx_doing = (t->ol_idx_doing + 1) % MAX_OVERLAPPED; + + /* Allocate read buffer. */ + if (olp->buff == NULL) { + void *p; + size_t s = (size_t)align_num_per_sector(t, BUFFER_SIZE); + p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE); + if (p == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Couldn't allocate memory"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + olp->buff = p; + olp->buff_size = s; + olp->_a = &a->archive; + olp->ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if (olp->ol.hEvent == NULL) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "CreateEvent failed"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } else + ResetEvent(olp->ol.hEvent); + + buffbytes = (DWORD)olp->buff_size; + if (buffbytes > t->current_sparse->length) + buffbytes = (DWORD)t->current_sparse->length; + + /* Skip hole. */ + if (t->current_sparse->offset > t->ol_total) { + t->ol_remaining_bytes -= + t->current_sparse->offset - t->ol_total; + } + + olp->offset = t->current_sparse->offset; + olp->ol.Offset = (DWORD)(olp->offset & 0xffffffff); + olp->ol.OffsetHigh = (DWORD)(olp->offset >> 32); + + if (t->ol_remaining_bytes > buffbytes) { + olp->bytes_expected = buffbytes; + t->ol_remaining_bytes -= buffbytes; + } else { + olp->bytes_expected = (size_t)t->ol_remaining_bytes; + t->ol_remaining_bytes = 0; + } + olp->bytes_transferred = 0; + t->current_sparse->offset += buffbytes; + t->current_sparse->length -= buffbytes; + t->ol_total = t->current_sparse->offset; + if (t->current_sparse->length == 0 && t->ol_remaining_bytes > 0) + t->current_sparse++; + + if (!ReadFile(t->entry_fh, olp->buff, buffbytes, &rbytes, &(olp->ol))) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_HANDLE_EOF) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Reading file truncated"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } else if (lasterr != ERROR_IO_PENDING) { + if (lasterr == ERROR_NO_DATA) + errno = EAGAIN; + else if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + la_dosmaperr(lasterr); + archive_set_error(&a->archive, errno, "Read error"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } else + olp->bytes_transferred = rbytes; + t->ol_num_doing++; + + return (t->ol_remaining_bytes == 0)? ARCHIVE_EOF: ARCHIVE_OK; +} + +static void +cancel_async(struct tree *t) +{ + if (t->ol_num_doing != t->ol_num_done) { + CancelIo(t->entry_fh); + t->ol_num_doing = t->ol_num_done = 0; + } +} + +static int +_archive_read_data_block(struct archive *_a, const void **buff, + size_t *size, int64_t *offset) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + struct la_overlapped *olp; + DWORD bytes_transferred; + int r = ARCHIVE_FATAL; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_data_block"); + + if (t->entry_eof || t->entry_remaining_bytes <= 0) { + r = ARCHIVE_EOF; + goto abort_read_data; + } + + /* + * Make a request to read the file in asynchronous. + */ + if (t->ol_num_doing == 0) { + do { + r = start_next_async_read(a, t); + if (r == ARCHIVE_FATAL) + goto abort_read_data; + if (!t->async_io) + break; + } while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED); + } else { + if (start_next_async_read(a, t) == ARCHIVE_FATAL) + goto abort_read_data; + } + + olp = &(t->ol[t->ol_idx_done]); + t->ol_idx_done = (t->ol_idx_done + 1) % MAX_OVERLAPPED; + if (olp->bytes_transferred) + bytes_transferred = (DWORD)olp->bytes_transferred; + else if (!GetOverlappedResult(t->entry_fh, &(olp->ol), + &bytes_transferred, TRUE)) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "GetOverlappedResult failed"); + a->archive.state = ARCHIVE_STATE_FATAL; + r = ARCHIVE_FATAL; + goto abort_read_data; + } + t->ol_num_done++; + + if (bytes_transferred == 0 || + olp->bytes_expected != bytes_transferred) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Reading file truncated"); + a->archive.state = ARCHIVE_STATE_FATAL; + r = ARCHIVE_FATAL; + goto abort_read_data; + } + + *buff = olp->buff; + *size = bytes_transferred; + *offset = olp->offset; + if (olp->offset > t->entry_total) + t->entry_remaining_bytes -= olp->offset - t->entry_total; + t->entry_total = olp->offset + *size; + t->entry_remaining_bytes -= *size; + if (t->entry_remaining_bytes == 0) { + /* Close the current file descriptor */ + close_and_restore_time(t->entry_fh, t, &t->restore_time); + t->entry_fh = INVALID_HANDLE_VALUE; + t->entry_eof = 1; + } + return (ARCHIVE_OK); + +abort_read_data: + *buff = NULL; + *size = 0; + *offset = t->entry_total; + if (t->entry_fh != INVALID_HANDLE_VALUE) { + cancel_async(t); + /* Close the current file descriptor */ + close_and_restore_time(t->entry_fh, t, &t->restore_time); + t->entry_fh = INVALID_HANDLE_VALUE; + } + return (r); +} + +static int +next_entry(struct archive_read_disk *a, struct tree *t, + struct archive_entry *entry) +{ + const BY_HANDLE_FILE_INFORMATION *st; + const BY_HANDLE_FILE_INFORMATION *lst; + const char*name; + int descend, r; + + st = NULL; + lst = NULL; + t->descend = 0; + do { + switch (tree_next(t)) { + case TREE_ERROR_FATAL: + archive_set_error(&a->archive, t->tree_errno, + "%ls: Unable to continue traversing directory tree", + tree_current_path(t)); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + case TREE_ERROR_DIR: + archive_set_error(&a->archive, t->tree_errno, + "%ls: Couldn't visit directory", + tree_current_path(t)); + return (ARCHIVE_FAILED); + case 0: + return (ARCHIVE_EOF); + case TREE_POSTDESCENT: + case TREE_POSTASCENT: + break; + case TREE_REGULAR: + lst = tree_current_lstat(t); + if (lst == NULL) { + archive_set_error(&a->archive, t->tree_errno, + "%ls: Cannot stat", + tree_current_path(t)); + return (ARCHIVE_FAILED); + } + break; + } + } while (lst == NULL); + + archive_entry_copy_pathname_w(entry, tree_current_path(t)); + + /* + * Perform path matching. + */ + if (a->matching) { + r = archive_match_path_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* + * Distinguish 'L'/'P'/'H' symlink following. + */ + switch(t->symlink_mode) { + case 'H': + /* 'H': After the first item, rest like 'P'. */ + t->symlink_mode = 'P'; + /* 'H': First item (from command line) like 'L'. */ + /* FALLTHROUGH */ + case 'L': + /* 'L': Do descend through a symlink to dir. */ + descend = tree_current_is_dir(t); + /* 'L': Follow symlinks to files. */ + a->symlink_mode = 'L'; + a->follow_symlinks = 1; + /* 'L': Archive symlinks as targets, if we can. */ + st = tree_current_stat(t); + if (st != NULL && !tree_target_is_same_as_parent(t, st)) + break; + /* If stat fails, we have a broken symlink; + * in that case, don't follow the link. */ + /* FALLTHROUGH */ + default: + /* 'P': Don't descend through a symlink to dir. */ + descend = tree_current_is_physical_dir(t); + /* 'P': Don't follow symlinks to files. */ + a->symlink_mode = 'P'; + a->follow_symlinks = 0; + /* 'P': Archive symlinks as symlinks. */ + st = lst; + break; + } + + if (update_current_filesystem(a, bhfi_dev(st)) != ARCHIVE_OK) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + if (t->initial_filesystem_id == -1) + t->initial_filesystem_id = t->current_filesystem_id; + if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) { + if (t->initial_filesystem_id != t->current_filesystem_id) + return (ARCHIVE_RETRY); + } + t->descend = descend; + + tree_archive_entry_copy_bhfi(entry, t, st); + + /* Save the times to be restored. This must be in before + * calling archive_read_disk_descend() or any chance of it, + * especially, invoking a callback. */ + t->restore_time.lastWriteTime = st->ftLastWriteTime; + t->restore_time.lastAccessTime = st->ftLastAccessTime; + t->restore_time.filetype = archive_entry_filetype(entry); + + /* + * Perform time matching. + */ + if (a->matching) { + r = archive_match_time_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* Lookup uname/gname */ + name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); + + /* + * Perform owner matching. + */ + if (a->matching) { + r = archive_match_owner_excluded(a->matching, entry); + if (r < 0) { + archive_set_error(&(a->archive), errno, + "Failed : %s", archive_error_string(a->matching)); + return (r); + } + if (r) { + if (a->excluded_cb_func) + a->excluded_cb_func(&(a->archive), + a->excluded_cb_data, entry); + return (ARCHIVE_RETRY); + } + } + + /* + * Invoke a meta data filter callback. + */ + if (a->metadata_filter_func) { + if (!a->metadata_filter_func(&(a->archive), + a->metadata_filter_data, entry)) + return (ARCHIVE_RETRY); + } + + archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t)); + + r = ARCHIVE_OK; + if (archive_entry_filetype(entry) == AE_IFREG && + archive_entry_size(entry) > 0) { + DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; + if (t->async_io) + flags |= FILE_FLAG_OVERLAPPED; + if (t->direct_io) + flags |= FILE_FLAG_NO_BUFFERING; + else + flags |= FILE_FLAG_SEQUENTIAL_SCAN; + t->entry_fh = CreateFileW(tree_current_access_path(t), + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL); + if (t->entry_fh == INVALID_HANDLE_VALUE) { + archive_set_error(&a->archive, errno, + "Couldn't open %ls", tree_current_path(a->tree)); + return (ARCHIVE_FAILED); + } + + /* Find sparse data from the disk. */ + if (archive_entry_hardlink(entry) == NULL && + (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0) + r = setup_sparse_from_disk(a, entry, t->entry_fh); + } + return (r); +} + +static int +_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) +{ + int ret; + struct archive_read_disk *a = (struct archive_read_disk *)_a; + *entryp = NULL; + ret = _archive_read_next_header2(_a, a->entry); + *entryp = a->entry; + return ret; +} + +static int +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t; + int r; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_next_header2"); + + t = a->tree; + if (t->entry_fh != INVALID_HANDLE_VALUE) { + cancel_async(t); + close_and_restore_time(t->entry_fh, t, &t->restore_time); + t->entry_fh = INVALID_HANDLE_VALUE; + } + + while ((r = next_entry(a, t, entry)) == ARCHIVE_RETRY) + archive_entry_clear(entry); + + /* + * EOF and FATAL are persistent at this layer. By + * modifying the state, we guarantee that future calls to + * read a header or read data will fail. + */ + switch (r) { + case ARCHIVE_EOF: + a->archive.state = ARCHIVE_STATE_EOF; + break; + case ARCHIVE_OK: + case ARCHIVE_WARN: + t->entry_total = 0; + if (archive_entry_filetype(entry) == AE_IFREG) { + t->entry_remaining_bytes = archive_entry_size(entry); + t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; + if (!t->entry_eof && + setup_sparse(a, entry) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + t->entry_remaining_bytes = 0; + t->entry_eof = 1; + } + t->ol_idx_doing = t->ol_idx_done = 0; + t->ol_num_doing = t->ol_num_done = 0; + t->ol_remaining_bytes = t->entry_remaining_bytes; + t->ol_total = 0; + a->archive.state = ARCHIVE_STATE_DATA; + break; + case ARCHIVE_RETRY: + break; + case ARCHIVE_FATAL: + a->archive.state = ARCHIVE_STATE_FATAL; + break; + } + + __archive_reset_read_data(&a->archive); + return (r); +} + +static int +setup_sparse(struct archive_read_disk *a, struct archive_entry *entry) +{ + struct tree *t = a->tree; + int64_t aligned, length, offset; + int i; + + t->sparse_count = archive_entry_sparse_reset(entry); + if (t->sparse_count+1 > t->sparse_list_size) { + free(t->sparse_list); + t->sparse_list_size = t->sparse_count + 1; + t->sparse_list = malloc(sizeof(t->sparse_list[0]) * + t->sparse_list_size); + if (t->sparse_list == NULL) { + t->sparse_list_size = 0; + archive_set_error(&a->archive, ENOMEM, + "Can't allocate data"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } + /* + * Get sparse list and make sure those offsets and lengths are + * aligned by a sector size. + */ + for (i = 0; i < t->sparse_count; i++) { + archive_entry_sparse_next(entry, &offset, &length); + aligned = align_num_per_sector(t, offset); + if (aligned != offset) { + aligned -= t->current_filesystem->bytesPerSector; + length += offset - aligned; + } + t->sparse_list[i].offset = aligned; + aligned = align_num_per_sector(t, length); + t->sparse_list[i].length = aligned; + } + + aligned = align_num_per_sector(t, archive_entry_size(entry)); + if (i == 0) { + t->sparse_list[i].offset = 0; + t->sparse_list[i].length = aligned; + } else { + int j, last = i; + + t->sparse_list[i].offset = aligned; + t->sparse_list[i].length = 0; + for (i = 0; i < last; i++) { + if ((t->sparse_list[i].offset + + t->sparse_list[i].length) <= + t->sparse_list[i+1].offset) + continue; + /* + * Now sparse_list[i+1] is overlapped by sparse_list[i]. + * Merge those two. + */ + length = t->sparse_list[i+1].offset - + t->sparse_list[i].offset; + t->sparse_list[i+1].offset = t->sparse_list[i].offset; + t->sparse_list[i+1].length += length; + /* Remove sparse_list[i]. */ + for (j = i; j < last; j++) { + t->sparse_list[j].offset = + t->sparse_list[j+1].offset; + t->sparse_list[j].length = + t->sparse_list[j+1].length; + } + last--; + } + } + t->current_sparse = t->sparse_list; + + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_matching(struct archive *_a, struct archive *_ma, + void (*_excluded_func)(struct archive *, void *, struct archive_entry *), + void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); + a->matching = _ma; + a->excluded_cb_func = _excluded_func; + a->excluded_cb_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_set_metadata_filter_callback(struct archive *_a, + int (*_metadata_filter_func)(struct archive *, void *, + struct archive_entry *), void *_client_data) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, + "archive_read_disk_set_metadata_filter_callback"); + + a->metadata_filter_func = _metadata_filter_func; + a->metadata_filter_data = _client_data; + return (ARCHIVE_OK); +} + +int +archive_read_disk_can_descend(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_disk_can_descend"); + + return (t->visit_type == TREE_REGULAR && t->descend); +} + +/* + * Called by the client to mark the directory just returned from + * tree_next() as needing to be visited. + */ +int +archive_read_disk_descend(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct tree *t = a->tree; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_read_disk_descend"); + + if (t->visit_type != TREE_REGULAR || !t->descend) + return (ARCHIVE_OK); + + if (tree_current_is_physical_dir(t)) { + tree_push(t, t->basename, t->full_path.s, + t->current_filesystem_id, + bhfi_dev(&(t->lst)), bhfi_ino(&(t->lst)), + &t->restore_time); + t->stack->flags |= isDir; + } else if (tree_current_is_dir(t)) { + tree_push(t, t->basename, t->full_path.s, + t->current_filesystem_id, + bhfi_dev(&(t->st)), bhfi_ino(&(t->st)), + &t->restore_time); + t->stack->flags |= isDirLink; + } + t->descend = 0; + return (ARCHIVE_OK); +} + +int +archive_read_disk_open(struct archive *_a, const char *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + struct archive_wstring wpath; + int ret; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, + "archive_read_disk_open"); + archive_clear_error(&a->archive); + + /* Make a wchar_t string from a char string. */ + archive_string_init(&wpath); + if (archive_wstring_append_from_mbs(&wpath, pathname, + strlen(pathname)) != 0) { + if (errno == ENOMEM) + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can't convert a path to a wchar_t string"); + a->archive.state = ARCHIVE_STATE_FATAL; + ret = ARCHIVE_FATAL; + } else + ret = _archive_read_disk_open_w(_a, wpath.s); + + archive_wstring_free(&wpath); + return (ret); +} + +int +archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, + "archive_read_disk_open_w"); + archive_clear_error(&a->archive); + + return (_archive_read_disk_open_w(_a, pathname)); +} + +static int +_archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + if (a->tree != NULL) + a->tree = tree_reopen(a->tree, pathname, + a->flags & ARCHIVE_READDISK_RESTORE_ATIME); + else + a->tree = tree_open(pathname, a->symlink_mode, + a->flags & ARCHIVE_READDISK_RESTORE_ATIME); + if (a->tree == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate directory traversal data"); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + a->archive.state = ARCHIVE_STATE_HEADER; + + return (ARCHIVE_OK); +} + +/* + * Return a current filesystem ID which is index of the filesystem entry + * you've visited through archive_read_disk. + */ +int +archive_read_disk_current_filesystem(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem_id); +} + +static int +update_current_filesystem(struct archive_read_disk *a, int64_t dev) +{ + struct tree *t = a->tree; + int i, fid; + + if (t->current_filesystem != NULL && + t->current_filesystem->dev == dev) + return (ARCHIVE_OK); + + for (i = 0; i < t->max_filesystem_id; i++) { + if (t->filesystem_table[i].dev == dev) { + /* There is the filesystem ID we've already generated. */ + t->current_filesystem_id = i; + t->current_filesystem = &(t->filesystem_table[i]); + return (ARCHIVE_OK); + } + } + + /* + * There is a new filesystem, we generate a new ID for. + */ + fid = t->max_filesystem_id++; + if (t->max_filesystem_id > t->allocated_filesystem) { + size_t s; + void *p; + + s = t->max_filesystem_id * 2; + p = realloc(t->filesystem_table, + s * sizeof(*t->filesystem_table)); + if (p == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate tar data"); + return (ARCHIVE_FATAL); + } + t->filesystem_table = (struct filesystem *)p; + t->allocated_filesystem = (int)s; + } + t->current_filesystem_id = fid; + t->current_filesystem = &(t->filesystem_table[fid]); + t->current_filesystem->dev = dev; + + return (setup_current_filesystem(a)); +} + +/* + * Returns 1 if current filesystem is generated filesystem, 0 if it is not + * or -1 if it is unknown. + */ +int +archive_read_disk_current_filesystem_is_synthetic(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem->synthetic); +} + +/* + * Returns 1 if current filesystem is remote filesystem, 0 if it is not + * or -1 if it is unknown. + */ +int +archive_read_disk_current_filesystem_is_remote(struct archive *_a) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + + archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, + "archive_read_disk_current_filesystem"); + + return (a->tree->current_filesystem->remote); +} + +/* + * If symlink is broken, statfs or statvfs will fail. + * Use its directory path instead. + */ +static wchar_t * +safe_path_for_statfs(struct tree *t) +{ + const wchar_t *path; + wchar_t *cp, *p = NULL; + + path = tree_current_access_path(t); + if (tree_current_stat(t) == NULL) { + p = _wcsdup(path); + cp = wcsrchr(p, '/'); + if (cp != NULL && wcslen(cp) >= 2) { + cp[1] = '.'; + cp[2] = '\0'; + path = p; + } + } else + p = _wcsdup(path); + return (p); +} + +/* + * Get conditions of synthetic and remote on Windows + */ +static int +setup_current_filesystem(struct archive_read_disk *a) +{ + struct tree *t = a->tree; + wchar_t vol[256]; + wchar_t *path; + + t->current_filesystem->synthetic = -1;/* Not supported */ + path = safe_path_for_statfs(t); + if (!GetVolumePathNameW(path, vol, sizeof(vol)/sizeof(vol[0]))) { + free(path); + t->current_filesystem->remote = -1; + t->current_filesystem->bytesPerSector = 0; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "GetVolumePathName failed: %d", (int)GetLastError()); + return (ARCHIVE_FAILED); + } + free(path); + switch (GetDriveTypeW(vol)) { + case DRIVE_UNKNOWN: + case DRIVE_NO_ROOT_DIR: + t->current_filesystem->remote = -1; + break; + case DRIVE_REMOTE: + t->current_filesystem->remote = 1; + break; + default: + t->current_filesystem->remote = 0; + break; + } + + if (!GetDiskFreeSpaceW(vol, NULL, + &(t->current_filesystem->bytesPerSector), NULL, NULL)) { + t->current_filesystem->bytesPerSector = 0; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "GetDiskFreeSpace failed: %d", (int)GetLastError()); + return (ARCHIVE_FAILED); + } + + return (ARCHIVE_OK); +} + +static int +close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt) +{ + HANDLE handle; + int r = 0; + + if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype) + return (0); + + /* Close a file descriptor. + * It will not be used for SetFileTime() because it has been opened + * by a read only mode. + */ + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + if ((t->flags & needsRestoreTimes) == 0) + return (r); + + handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES, + 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (handle == INVALID_HANDLE_VALUE) { + errno = EINVAL; + return (-1); + } + + if (SetFileTime(handle, NULL, &rt->lastAccessTime, + &rt->lastWriteTime) == 0) { + errno = EINVAL; + r = -1; + } else + r = 0; + CloseHandle(handle); + return (r); +} + +/* + * Add a directory path to the current stack. + */ +static void +tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path, + int filesystem_id, int64_t dev, int64_t ino, struct restore_time *rt) +{ + struct tree_entry *te; + + te = calloc(1, sizeof(*te)); + te->next = t->stack; + te->parent = t->current; + if (te->parent) + te->depth = te->parent->depth + 1; + t->stack = te; + archive_string_init(&te->name); + archive_wstrcpy(&te->name, path); + archive_string_init(&te->full_path); + archive_wstrcpy(&te->full_path, full_path); + te->flags = needsDescent | needsOpen | needsAscent; + te->filesystem_id = filesystem_id; + te->dev = dev; + te->ino = ino; + te->dirname_length = t->dirname_length; + te->full_path_dir_length = t->full_path_dir_length; + te->restore_time.full_path = te->full_path.s; + if (rt != NULL) { + te->restore_time.lastWriteTime = rt->lastWriteTime; + te->restore_time.lastAccessTime = rt->lastAccessTime; + te->restore_time.filetype = rt->filetype; + } +} + +/* + * Append a name to the current dir path. + */ +static void +tree_append(struct tree *t, const wchar_t *name, size_t name_length) +{ + size_t size_needed; + + t->path.s[t->dirname_length] = L'\0'; + t->path.length = t->dirname_length; + /* Strip trailing '/' from name, unless entire name is "/". */ + while (name_length > 1 && name[name_length - 1] == L'/') + name_length--; + + /* Resize pathname buffer as needed. */ + size_needed = name_length + t->dirname_length + 2; + archive_wstring_ensure(&t->path, size_needed); + /* Add a separating '/' if it's needed. */ + if (t->dirname_length > 0 && + t->path.s[archive_strlen(&t->path)-1] != L'/') + archive_wstrappend_wchar(&t->path, L'/'); + t->basename = t->path.s + archive_strlen(&t->path); + archive_wstrncat(&t->path, name, name_length); + t->restore_time.full_path = t->basename; + if (t->full_path_dir_length > 0) { + t->full_path.s[t->full_path_dir_length] = L'\0'; + t->full_path.length = t->full_path_dir_length; + size_needed = name_length + t->full_path_dir_length + 2; + archive_wstring_ensure(&t->full_path, size_needed); + /* Add a separating '\' if it's needed. */ + if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\') + archive_wstrappend_wchar(&t->full_path, L'\\'); + archive_wstrncat(&t->full_path, name, name_length); + t->restore_time.full_path = t->full_path.s; + } +} + +/* + * Open a directory tree for traversal. + */ +static struct tree * +tree_open(const wchar_t *path, int symlink_mode, int restore_time) +{ + struct tree *t; + + t = calloc(1, sizeof(*t)); + archive_string_init(&(t->full_path)); + archive_string_init(&t->path); + archive_wstring_ensure(&t->path, 15); + t->initial_symlink_mode = symlink_mode; + return (tree_reopen(t, path, restore_time)); +} + +static struct tree * +tree_reopen(struct tree *t, const wchar_t *path, int restore_time) +{ + struct archive_wstring ws; + wchar_t *pathname, *p, *base; + + t->flags = (restore_time != 0)?needsRestoreTimes:0; + t->visit_type = 0; + t->tree_errno = 0; + t->full_path_dir_length = 0; + t->dirname_length = 0; + t->depth = 0; + t->descend = 0; + t->current = NULL; + t->d = INVALID_HANDLE_VALUE; + t->symlink_mode = t->initial_symlink_mode; + archive_string_empty(&(t->full_path)); + archive_string_empty(&t->path); + t->entry_fh = INVALID_HANDLE_VALUE; + t->entry_eof = 0; + t->entry_remaining_bytes = 0; + t->initial_filesystem_id = -1; + + /* Get wchar_t strings from char strings. */ + archive_string_init(&ws); + archive_wstrcpy(&ws, path); + pathname = ws.s; + /* Get a full-path-name. */ + p = __la_win_permissive_name_w(pathname); + if (p == NULL) + goto failed; + archive_wstrcpy(&(t->full_path), p); + free(p); + + /* Convert path separators from '\' to '/' */ + for (p = pathname; *p != L'\0'; ++p) { + if (*p == L'\\') + *p = L'/'; + } + base = pathname; + + /* First item is set up a lot like a symlink traversal. */ + /* printf("Looking for wildcard in %s\n", path); */ + if ((base[0] == L'/' && base[1] == L'/' && + base[2] == L'?' && base[3] == L'/' && + (wcschr(base+4, L'*') || wcschr(base+4, L'?'))) || + (!(base[0] == L'/' && base[1] == L'/' && + base[2] == L'?' && base[3] == L'/') && + (wcschr(base, L'*') || wcschr(base, L'?')))) { + // It has a wildcard in it... + // Separate the last element. + p = wcsrchr(base, L'/'); + if (p != NULL) { + *p = L'\0'; + tree_append(t, base, p - base); + t->dirname_length = archive_strlen(&t->path); + base = p + 1; + } + p = wcsrchr(t->full_path.s, L'\\'); + if (p != NULL) { + *p = L'\0'; + t->full_path.length = wcslen(t->full_path.s); + t->full_path_dir_length = archive_strlen(&t->full_path); + } + } + tree_push(t, base, t->full_path.s, 0, 0, 0, NULL); + archive_wstring_free(&ws); + t->stack->flags = needsFirstVisit; + /* + * Debug flag for Direct IO(No buffering) or Async IO. + * Those dependent on environment variable switches + * will be removed until next release. + */ + { + const char *e; + if ((e = getenv("LIBARCHIVE_DIRECT_IO")) != NULL) { + if (e[0] == '0') + t->direct_io = 0; + else + t->direct_io = 1; + fprintf(stderr, "LIBARCHIVE_DIRECT_IO=%s\n", + (t->direct_io)?"Enabled":"Disabled"); + } else + t->direct_io = DIRECT_IO; + if ((e = getenv("LIBARCHIVE_ASYNC_IO")) != NULL) { + if (e[0] == '0') + t->async_io = 0; + else + t->async_io = 1; + fprintf(stderr, "LIBARCHIVE_ASYNC_IO=%s\n", + (t->async_io)?"Enabled":"Disabled"); + } else + t->async_io = ASYNC_IO; + } + return (t); +failed: + archive_wstring_free(&ws); + tree_free(t); + return (NULL); +} + +static int +tree_descent(struct tree *t) +{ + t->dirname_length = archive_strlen(&t->path); + t->full_path_dir_length = archive_strlen(&t->full_path); + t->depth++; + return (0); +} + +/* + * We've finished a directory; ascend back to the parent. + */ +static int +tree_ascend(struct tree *t) +{ + struct tree_entry *te; + + te = t->stack; + t->depth--; + close_and_restore_time(INVALID_HANDLE_VALUE, t, &te->restore_time); + return (0); +} + +/* + * Pop the working stack. + */ +static void +tree_pop(struct tree *t) +{ + struct tree_entry *te; + + t->full_path.s[t->full_path_dir_length] = L'\0'; + t->full_path.length = t->full_path_dir_length; + t->path.s[t->dirname_length] = L'\0'; + t->path.length = t->dirname_length; + if (t->stack == t->current && t->current != NULL) + t->current = t->current->parent; + te = t->stack; + t->stack = te->next; + t->dirname_length = te->dirname_length; + t->basename = t->path.s + t->dirname_length; + t->full_path_dir_length = te->full_path_dir_length; + while (t->basename[0] == L'/') + t->basename++; + archive_wstring_free(&te->name); + archive_wstring_free(&te->full_path); + free(te); +} + +/* + * Get the next item in the tree traversal. + */ +static int +tree_next(struct tree *t) +{ + int r; + + while (t->stack != NULL) { + /* If there's an open dir, get the next entry from there. */ + if (t->d != INVALID_HANDLE_VALUE) { + r = tree_dir_next_windows(t, NULL); + if (r == 0) + continue; + return (r); + } + + if (t->stack->flags & needsFirstVisit) { + wchar_t *d = t->stack->name.s; + t->stack->flags &= ~needsFirstVisit; + if (!(d[0] == L'/' && d[1] == L'/' && + d[2] == L'?' && d[3] == L'/') && + (wcschr(d, L'*') || wcschr(d, L'?'))) { + r = tree_dir_next_windows(t, d); + if (r == 0) + continue; + return (r); + } else { + HANDLE h = FindFirstFileW(d, &t->_findData); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + t->tree_errno = errno; + t->visit_type = TREE_ERROR_DIR; + return (t->visit_type); + } + t->findData = &t->_findData; + FindClose(h); + } + /* Top stack item needs a regular visit. */ + t->current = t->stack; + tree_append(t, t->stack->name.s, + archive_strlen(&(t->stack->name))); + //t->dirname_length = t->path_length; + //tree_pop(t); + t->stack->flags &= ~needsFirstVisit; + return (t->visit_type = TREE_REGULAR); + } else if (t->stack->flags & needsDescent) { + /* Top stack item is dir to descend into. */ + t->current = t->stack; + tree_append(t, t->stack->name.s, + archive_strlen(&(t->stack->name))); + t->stack->flags &= ~needsDescent; + r = tree_descent(t); + if (r != 0) { + tree_pop(t); + t->visit_type = r; + } else + t->visit_type = TREE_POSTDESCENT; + return (t->visit_type); + } else if (t->stack->flags & needsOpen) { + t->stack->flags &= ~needsOpen; + r = tree_dir_next_windows(t, L"*"); + if (r == 0) + continue; + return (r); + } else if (t->stack->flags & needsAscent) { + /* Top stack item is dir and we're done with it. */ + r = tree_ascend(t); + tree_pop(t); + t->visit_type = r != 0 ? r : TREE_POSTASCENT; + return (t->visit_type); + } else { + /* Top item on stack is dead. */ + tree_pop(t); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + } + } + return (t->visit_type = 0); +} + +static int +tree_dir_next_windows(struct tree *t, const wchar_t *pattern) +{ + const wchar_t *name; + size_t namelen; + int r; + + for (;;) { + if (pattern != NULL) { + struct archive_wstring pt; + + archive_string_init(&pt); + archive_wstring_ensure(&pt, + archive_strlen(&(t->full_path)) + + 2 + wcslen(pattern)); + archive_wstring_copy(&pt, &(t->full_path)); + archive_wstrappend_wchar(&pt, L'\\'); + archive_wstrcat(&pt, pattern); + t->d = FindFirstFileW(pt.s, &t->_findData); + archive_wstring_free(&pt); + if (t->d == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + t->tree_errno = errno; + r = tree_ascend(t); /* Undo "chdir" */ + tree_pop(t); + t->visit_type = r != 0 ? r : TREE_ERROR_DIR; + return (t->visit_type); + } + t->findData = &t->_findData; + pattern = NULL; + } else if (!FindNextFileW(t->d, &t->_findData)) { + FindClose(t->d); + t->d = INVALID_HANDLE_VALUE; + t->findData = NULL; + return (0); + } + name = t->findData->cFileName; + namelen = wcslen(name); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + if (name[0] == L'.' && name[1] == L'\0') + continue; + if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0') + continue; + tree_append(t, name, namelen); + return (t->visit_type = TREE_REGULAR); + } +} + +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) +static void +fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + /* milli seconds base */ + *t = (time_t)(utc.QuadPart / 10000000); + /* nano seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + *t = 0; + *ns = 0; + } +} + +static void +entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path, + const WIN32_FIND_DATAW *findData, + const BY_HANDLE_FILE_INFORMATION *bhfi) +{ + time_t secs; + long nsecs; + mode_t mode; + + fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); + archive_entry_set_atime(entry, secs, nsecs); + fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); + archive_entry_set_mtime(entry, secs, nsecs); + fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); + archive_entry_set_birthtime(entry, secs, nsecs); + archive_entry_set_ctime(entry, secs, nsecs); + archive_entry_set_dev(entry, bhfi_dev(bhfi)); + archive_entry_set_ino64(entry, bhfi_ino(bhfi)); + if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + archive_entry_set_nlink(entry, bhfi->nNumberOfLinks + 1); + else + archive_entry_set_nlink(entry, bhfi->nNumberOfLinks); + archive_entry_set_size(entry, + (((int64_t)bhfi->nFileSizeHigh) << 32) + + bhfi->nFileSizeLow); + archive_entry_set_uid(entry, 0); + archive_entry_set_gid(entry, 0); + archive_entry_set_rdev(entry, 0); + + mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + findData != NULL && + findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK) + mode |= S_IFLNK; + else if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else { + const wchar_t *p; + + mode |= S_IFREG; + p = wcsrchr(path, L'.'); + if (p != NULL && wcslen(p) == 4) { + switch (p[1]) { + case L'B': case L'b': + if ((p[2] == L'A' || p[2] == L'a' ) && + (p[3] == L'T' || p[3] == L't' )) + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + case L'C': case L'c': + if (((p[2] == L'M' || p[2] == L'm' ) && + (p[3] == L'D' || p[3] == L'd' ))) + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + case L'E': case L'e': + if ((p[2] == L'X' || p[2] == L'x' ) && + (p[3] == L'E' || p[3] == L'e' )) + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + default: + break; + } + } + } + archive_entry_set_mode(entry, mode); +} + +static void +tree_archive_entry_copy_bhfi(struct archive_entry *entry, struct tree *t, + const BY_HANDLE_FILE_INFORMATION *bhfi) +{ + entry_copy_bhfi(entry, tree_current_path(t), t->findData, bhfi); +} + +static int +tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st, + int sim_lstat) +{ + HANDLE h; + int r; + DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; + + if (sim_lstat && tree_current_is_physical_link(t)) + flag |= FILE_FLAG_OPEN_REPARSE_POINT; + h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL, + OPEN_EXISTING, flag, NULL); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + t->tree_errno = errno; + return (0); + } + r = GetFileInformationByHandle(h, st); + CloseHandle(h); + return (r); +} + +/* + * Get the stat() data for the entry just returned from tree_next(). + */ +static const BY_HANDLE_FILE_INFORMATION * +tree_current_stat(struct tree *t) +{ + if (!(t->flags & hasStat)) { + if (!tree_current_file_information(t, &t->st, 0)) + return NULL; + t->flags |= hasStat; + } + return (&t->st); +} + +/* + * Get the lstat() data for the entry just returned from tree_next(). + */ +static const BY_HANDLE_FILE_INFORMATION * +tree_current_lstat(struct tree *t) +{ + if (!(t->flags & hasLstat)) { + if (!tree_current_file_information(t, &t->lst, 1)) + return NULL; + t->flags |= hasLstat; + } + return (&t->lst); +} + +/* + * Test whether current entry is a dir or link to a dir. + */ +static int +tree_current_is_dir(struct tree *t) +{ + if (t->findData) + return (t->findData->dwFileAttributes + & FILE_ATTRIBUTE_DIRECTORY); + return (0); +} + +/* + * Test whether current entry is a physical directory. Usually, we + * already have at least one of stat() or lstat() in memory, so we + * use tricks to try to avoid an extra trip to the disk. + */ +static int +tree_current_is_physical_dir(struct tree *t) +{ + if (tree_current_is_physical_link(t)) + return (0); + return (tree_current_is_dir(t)); +} + +/* + * Test whether current entry is a symbolic link. + */ +static int +tree_current_is_physical_link(struct tree *t) +{ + if (t->findData) + return ((t->findData->dwFileAttributes + & FILE_ATTRIBUTE_REPARSE_POINT) && + (t->findData->dwReserved0 + == IO_REPARSE_TAG_SYMLINK)); + return (0); +} + +/* + * Test whether the same file has been in the tree as its parent. + */ +static int +tree_target_is_same_as_parent(struct tree *t, + const BY_HANDLE_FILE_INFORMATION *st) +{ + struct tree_entry *te; + int64_t dev = bhfi_dev(st); + int64_t ino = bhfi_ino(st); + + for (te = t->current->parent; te != NULL; te = te->parent) { + if (te->dev == dev && te->ino == ino) + return (1); + } + return (0); +} + +/* + * Return the access path for the entry just returned from tree_next(). + */ +static const wchar_t * +tree_current_access_path(struct tree *t) +{ + return (t->full_path.s); +} + +/* + * Return the full path for the entry just returned from tree_next(). + */ +static const wchar_t * +tree_current_path(struct tree *t) +{ + return (t->path.s); +} + +/* + * Terminate the traversal. + */ +static void +tree_close(struct tree *t) +{ + + if (t == NULL) + return; + if (t->entry_fh != INVALID_HANDLE_VALUE) { + cancel_async(t); + close_and_restore_time(t->entry_fh, t, &t->restore_time); + t->entry_fh = INVALID_HANDLE_VALUE; + } + /* Close the handle of FindFirstFileW */ + if (t->d != INVALID_HANDLE_VALUE) { + FindClose(t->d); + t->d = INVALID_HANDLE_VALUE; + t->findData = NULL; + } + /* Release anything remaining in the stack. */ + while (t->stack != NULL) + tree_pop(t); +} + +/* + * Release any resources. + */ +static void +tree_free(struct tree *t) +{ + int i; + + if (t == NULL) + return; + archive_wstring_free(&t->path); + archive_wstring_free(&t->full_path); + free(t->sparse_list); + free(t->filesystem_table); + for (i = 0; i < MAX_OVERLAPPED; i++) { + if (t->ol[i].buff) + VirtualFree(t->ol[i].buff, 0, MEM_RELEASE); + CloseHandle(t->ol[i].ol.hEvent); + } + free(t); +} + + +/* + * Populate the archive_entry with metadata from the disk. + */ +int +archive_read_disk_entry_from_file(struct archive *_a, + struct archive_entry *entry, int fd, const struct stat *st) +{ + struct archive_read_disk *a = (struct archive_read_disk *)_a; + const wchar_t *path; + const wchar_t *wname; + const char *name; + HANDLE h; + BY_HANDLE_FILE_INFORMATION bhfi; + DWORD fileAttributes = 0; + int r; + + archive_clear_error(_a); + wname = archive_entry_sourcepath_w(entry); + if (wname == NULL) + wname = archive_entry_pathname_w(entry); + if (wname == NULL) { + archive_set_error(&a->archive, EINVAL, + "Can't get a wide character version of the path"); + return (ARCHIVE_FAILED); + } + path = __la_win_permissive_name_w(wname); + + if (st == NULL) { + /* + * Get metadata through GetFileInformationByHandle(). + */ + if (fd >= 0) { + h = (HANDLE)_get_osfhandle(fd); + r = GetFileInformationByHandle(h, &bhfi); + if (r == 0) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't GetFileInformationByHandle"); + return (ARCHIVE_FAILED); + } + entry_copy_bhfi(entry, path, NULL, &bhfi); + } else { + WIN32_FIND_DATAW findData; + DWORD flag, desiredAccess; + + h = FindFirstFileW(path, &findData); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't FindFirstFileW"); + return (ARCHIVE_FAILED); + } + FindClose(h); + + flag = FILE_FLAG_BACKUP_SEMANTICS; + if (!a->follow_symlinks && + (findData.dwFileAttributes + & FILE_ATTRIBUTE_REPARSE_POINT) && + (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + flag |= FILE_FLAG_OPEN_REPARSE_POINT; + desiredAccess = 0; + } else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + desiredAccess = 0; + } else + desiredAccess = GENERIC_READ; + + h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL, + OPEN_EXISTING, flag, NULL); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't CreateFileW"); + return (ARCHIVE_FAILED); + } + r = GetFileInformationByHandle(h, &bhfi); + if (r == 0) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't GetFileInformationByHandle"); + CloseHandle(h); + return (ARCHIVE_FAILED); + } + entry_copy_bhfi(entry, path, &findData, &bhfi); + } + fileAttributes = bhfi.dwFileAttributes; + } else { + archive_entry_copy_stat(entry, st); + h = INVALID_HANDLE_VALUE; + } + + /* Lookup uname/gname */ + name = archive_read_disk_uname(_a, archive_entry_uid(entry)); + if (name != NULL) + archive_entry_copy_uname(entry, name); + name = archive_read_disk_gname(_a, archive_entry_gid(entry)); + if (name != NULL) + archive_entry_copy_gname(entry, name); + + /* + * Can this file be sparse file ? + */ + if (archive_entry_filetype(entry) != AE_IFREG + || archive_entry_size(entry) <= 0 + || archive_entry_hardlink(entry) != NULL) { + if (h != INVALID_HANDLE_VALUE && fd < 0) + CloseHandle(h); + return (ARCHIVE_OK); + } + + if (h == INVALID_HANDLE_VALUE) { + if (fd >= 0) { + h = (HANDLE)_get_osfhandle(fd); + } else { + h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't CreateFileW"); + return (ARCHIVE_FAILED); + } + } + r = GetFileInformationByHandle(h, &bhfi); + if (r == 0) { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "Can't GetFileInformationByHandle"); + if (h != INVALID_HANDLE_VALUE && fd < 0) + CloseHandle(h); + return (ARCHIVE_FAILED); + } + fileAttributes = bhfi.dwFileAttributes; + } + + /* Sparse file must be set a mark, FILE_ATTRIBUTE_SPARSE_FILE */ + if ((fileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { + if (fd < 0) + CloseHandle(h); + return (ARCHIVE_OK); + } + + r = setup_sparse_from_disk(a, entry, h); + if (fd < 0) + CloseHandle(h); + + return (r); +} + +/* + * Windows sparse interface. + */ +#if defined(__MINGW32__) && !defined(FSCTL_QUERY_ALLOCATED_RANGES) +#define FSCTL_QUERY_ALLOCATED_RANGES 0x940CF +typedef struct { + LARGE_INTEGER FileOffset; + LARGE_INTEGER Length; +} FILE_ALLOCATED_RANGE_BUFFER; +#endif + +static int +setup_sparse_from_disk(struct archive_read_disk *a, + struct archive_entry *entry, HANDLE handle) +{ + FILE_ALLOCATED_RANGE_BUFFER range, *outranges = NULL; + size_t outranges_size; + int64_t entry_size = archive_entry_size(entry); + int exit_sts = ARCHIVE_OK; + + range.FileOffset.QuadPart = 0; + range.Length.QuadPart = entry_size; + outranges_size = 2048; + outranges = (FILE_ALLOCATED_RANGE_BUFFER *)malloc(outranges_size); + if (outranges == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Couldn't allocate memory"); + exit_sts = ARCHIVE_FATAL; + goto exit_setup_sparse; + } + + for (;;) { + DWORD retbytes; + BOOL ret; + + for (;;) { + ret = DeviceIoControl(handle, + FSCTL_QUERY_ALLOCATED_RANGES, + &range, sizeof(range), outranges, + (DWORD)outranges_size, &retbytes, NULL); + if (ret == 0 && GetLastError() == ERROR_MORE_DATA) { + free(outranges); + outranges_size *= 2; + outranges = (FILE_ALLOCATED_RANGE_BUFFER *) + malloc(outranges_size); + if (outranges == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Couldn't allocate memory"); + exit_sts = ARCHIVE_FATAL; + goto exit_setup_sparse; + } + continue; + } else + break; + } + if (ret != 0) { + if (retbytes > 0) { + DWORD i, n; + + n = retbytes / sizeof(outranges[0]); + if (n == 1 && + outranges[0].FileOffset.QuadPart == 0 && + outranges[0].Length.QuadPart == entry_size) + break;/* This is not sparse. */ + for (i = 0; i < n; i++) + archive_entry_sparse_add_entry(entry, + outranges[i].FileOffset.QuadPart, + outranges[i].Length.QuadPart); + range.FileOffset.QuadPart = + outranges[n-1].FileOffset.QuadPart + + outranges[n-1].Length.QuadPart; + range.Length.QuadPart = + entry_size - range.FileOffset.QuadPart; + if (range.Length.QuadPart > 0) + continue; + } else { + /* The remaining data is hole. */ + archive_entry_sparse_add_entry(entry, + range.FileOffset.QuadPart, + range.Length.QuadPart); + } + break; + } else { + la_dosmaperr(GetLastError()); + archive_set_error(&a->archive, errno, + "DeviceIoControl Failed: %lu", GetLastError()); + exit_sts = ARCHIVE_FAILED; + goto exit_setup_sparse; + } + } +exit_setup_sparse: + free(outranges); + + return (exit_sts); +} + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_read_extract.c b/src/3rdparty/libarchive/libarchive/archive_read_extract.c new file mode 100644 index 00000000..b7973fa8 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_extract.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $"); + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_private.h" + +int +archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags) +{ + struct archive_read_extract *extract; + struct archive_read * a = (struct archive_read *)_a; + + extract = __archive_read_get_extract(a); + if (extract == NULL) + return (ARCHIVE_FATAL); + + /* If we haven't initialized the archive_write_disk object, do it now. */ + if (extract->ad == NULL) { + extract->ad = archive_write_disk_new(); + if (extract->ad == NULL) { + archive_set_error(&a->archive, ENOMEM, "Can't extract"); + return (ARCHIVE_FATAL); + } + archive_write_disk_set_standard_lookup(extract->ad); + } + + archive_write_disk_set_options(extract->ad, flags); + return (archive_read_extract2(&a->archive, entry, extract->ad)); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_open_fd.c b/src/3rdparty/libarchive/libarchive/archive_read_open_fd.c new file mode 100644 index 00000000..f59cd07f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_open_fd.c @@ -0,0 +1,211 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_fd.c 201103 2009-12-28 03:13:49Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" + +struct read_fd_data { + int fd; + size_t block_size; + char use_lseek; + void *buffer; +}; + +static int file_close(struct archive *, void *); +static ssize_t file_read(struct archive *, void *, const void **buff); +static int64_t file_seek(struct archive *, void *, int64_t request, int); +static int64_t file_skip(struct archive *, void *, int64_t request); + +int +archive_read_open_fd(struct archive *a, int fd, size_t block_size) +{ + struct stat st; + struct read_fd_data *mine; + void *b; + + archive_clear_error(a); + if (fstat(fd, &st) != 0) { + archive_set_error(a, errno, "Can't stat fd %d", fd); + return (ARCHIVE_FATAL); + } + + mine = (struct read_fd_data *)calloc(1, sizeof(*mine)); + b = malloc(block_size); + if (mine == NULL || b == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + free(mine); + free(b); + return (ARCHIVE_FATAL); + } + mine->block_size = block_size; + mine->buffer = b; + mine->fd = fd; + /* + * Skip support is a performance optimization for anything + * that supports lseek(). On FreeBSD, only regular files and + * raw disk devices support lseek() and there's no portable + * way to determine if a device is a raw disk device, so we + * only enable this optimization for regular files. + */ + if (S_ISREG(st.st_mode)) { + archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); + mine->use_lseek = 1; + } +#if defined(__CYGWIN__) || defined(_WIN32) + setmode(mine->fd, O_BINARY); +#endif + + archive_read_set_read_callback(a, file_read); + archive_read_set_skip_callback(a, file_skip); + archive_read_set_seek_callback(a, file_seek); + archive_read_set_close_callback(a, file_close); + archive_read_set_callback_data(a, mine); + return (archive_read_open1(a)); +} + +static ssize_t +file_read(struct archive *a, void *client_data, const void **buff) +{ + struct read_fd_data *mine = (struct read_fd_data *)client_data; + ssize_t bytes_read; + + *buff = mine->buffer; + for (;;) { + bytes_read = read(mine->fd, mine->buffer, mine->block_size); + if (bytes_read < 0) { + if (errno == EINTR) + continue; + archive_set_error(a, errno, "Error reading fd %d", + mine->fd); + } + return (bytes_read); + } +} + +static int64_t +file_skip(struct archive *a, void *client_data, int64_t request) +{ + struct read_fd_data *mine = (struct read_fd_data *)client_data; + int64_t skip = request; + int64_t old_offset, new_offset; + int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ + + if (!mine->use_lseek) + return (0); + + /* Reduce a request that would overflow the 'skip' variable. */ + if (sizeof(request) > sizeof(skip)) { + int64_t max_skip = + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; + if (request > max_skip) + skip = max_skip; + } + + /* Reduce request to the next smallest multiple of block_size */ + request = (request / mine->block_size) * mine->block_size; + if (request == 0) + return (0); + + if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && + ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)) + return (new_offset - old_offset); + + /* If seek failed once, it will probably fail again. */ + mine->use_lseek = 0; + + /* Let libarchive recover with read+discard. */ + if (errno == ESPIPE) + return (0); + + /* + * There's been an error other than ESPIPE. This is most + * likely caused by a programmer error (too large request) + * or a corrupted archive file. + */ + archive_set_error(a, errno, "Error seeking"); + return (-1); +} + +/* + * TODO: Store the offset and use it in the read callback. + */ +static int64_t +file_seek(struct archive *a, void *client_data, int64_t request, int whence) +{ + struct read_fd_data *mine = (struct read_fd_data *)client_data; + int64_t r; + + /* We use off_t here because lseek() is declared that way. */ + /* See above for notes about when off_t is less than 64 bits. */ + r = lseek(mine->fd, request, whence); + if (r >= 0) + return r; + + if (errno == ESPIPE) { + archive_set_error(a, errno, + "A file descriptor(%d) is not seekable(PIPE)", mine->fd); + return (ARCHIVE_FAILED); + } else { + /* If the input is corrupted or truncated, fail. */ + archive_set_error(a, errno, + "Error seeking in a file descriptor(%d)", mine->fd); + return (ARCHIVE_FATAL); + } +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct read_fd_data *mine = (struct read_fd_data *)client_data; + + (void)a; /* UNUSED */ + free(mine->buffer); + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_open_file.c b/src/3rdparty/libarchive/libarchive/archive_read_open_file.c new file mode 100644 index 00000000..bfe933bf --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_open_file.c @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_file.c 201093 2009-12-28 02:28:44Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" + +struct read_FILE_data { + FILE *f; + size_t block_size; + void *buffer; + char can_skip; +}; + +static int file_close(struct archive *, void *); +static ssize_t file_read(struct archive *, void *, const void **buff); +static int64_t file_skip(struct archive *, void *, int64_t request); + +int +archive_read_open_FILE(struct archive *a, FILE *f) +{ + struct stat st; + struct read_FILE_data *mine; + size_t block_size = 128 * 1024; + void *b; + + archive_clear_error(a); + mine = (struct read_FILE_data *)malloc(sizeof(*mine)); + b = malloc(block_size); + if (mine == NULL || b == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + free(mine); + free(b); + return (ARCHIVE_FATAL); + } + mine->block_size = block_size; + mine->buffer = b; + mine->f = f; + /* + * If we can't fstat() the file, it may just be that it's not + * a file. (On some platforms, FILE * objects can wrap I/O + * streams that don't support fileno()). As a result, fileno() + * should be used cautiously.) + */ + if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { + archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); + /* Enable the seek optimization only for regular files. */ + mine->can_skip = 1; + } else + mine->can_skip = 0; + +#if defined(__CYGWIN__) || defined(_WIN32) + setmode(fileno(mine->f), O_BINARY); +#endif + + archive_read_set_read_callback(a, file_read); + archive_read_set_skip_callback(a, file_skip); + archive_read_set_close_callback(a, file_close); + archive_read_set_callback_data(a, mine); + return (archive_read_open1(a)); +} + +static ssize_t +file_read(struct archive *a, void *client_data, const void **buff) +{ + struct read_FILE_data *mine = (struct read_FILE_data *)client_data; + size_t bytes_read; + + *buff = mine->buffer; + bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f); + if (bytes_read < mine->block_size && ferror(mine->f)) { + archive_set_error(a, errno, "Error reading file"); + } + return (bytes_read); +} + +static int64_t +file_skip(struct archive *a, void *client_data, int64_t request) +{ + struct read_FILE_data *mine = (struct read_FILE_data *)client_data; +#if HAVE_FSEEKO + off_t skip = (off_t)request; +#elif HAVE__FSEEKI64 + int64_t skip = request; +#else + long skip = (long)request; +#endif + int skip_bits = sizeof(skip) * 8 - 1; + + (void)a; /* UNUSED */ + + /* + * If we can't skip, return 0 as the amount we did step and + * the caller will work around by reading and discarding. + */ + if (!mine->can_skip) + return (0); + if (request == 0) + return (0); + + /* If request is too big for a long or an off_t, reduce it. */ + if (sizeof(request) > sizeof(skip)) { + int64_t max_skip = + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; + if (request > max_skip) + skip = max_skip; + } + +#ifdef __ANDROID__ + /* fileno() isn't safe on all platforms ... see above. */ + if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0) +#elif HAVE_FSEEKO + if (fseeko(mine->f, skip, SEEK_CUR) != 0) +#elif HAVE__FSEEKI64 + if (_fseeki64(mine->f, skip, SEEK_CUR) != 0) +#else + if (fseek(mine->f, skip, SEEK_CUR) != 0) +#endif + { + mine->can_skip = 0; + return (0); + } + return (request); +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct read_FILE_data *mine = (struct read_FILE_data *)client_data; + + (void)a; /* UNUSED */ + if (mine->buffer != NULL) + free(mine->buffer); + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_open_filename.c b/src/3rdparty/libarchive/libarchive/archive_read_open_filename.c new file mode 100644 index 00000000..86635e21 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_open_filename.c @@ -0,0 +1,582 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_filename.c 201093 2009-12-28 02:28:44Z kientzle $"); + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +#elif defined(__NetBSD__) || defined(__OpenBSD__) +#include +#include +#elif defined(__DragonFly__) +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +struct read_file_data { + int fd; + size_t block_size; + void *buffer; + mode_t st_mode; /* Mode bits for opened file. */ + char use_lseek; + enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type; + union { + char m[1];/* MBS filename. */ + wchar_t w[1];/* WCS filename. */ + } filename; /* Must be last! */ +}; + +static int file_open(struct archive *, void *); +static int file_close(struct archive *, void *); +static int file_close2(struct archive *, void *); +static int file_switch(struct archive *, void *, void *); +static ssize_t file_read(struct archive *, void *, const void **buff); +static int64_t file_seek(struct archive *, void *, int64_t request, int); +static int64_t file_skip(struct archive *, void *, int64_t request); +static int64_t file_skip_lseek(struct archive *, void *, int64_t request); + +int +archive_read_open_file(struct archive *a, const char *filename, + size_t block_size) +{ + return (archive_read_open_filename(a, filename, block_size)); +} + +int +archive_read_open_filename(struct archive *a, const char *filename, + size_t block_size) +{ + const char *filenames[2]; + filenames[0] = filename; + filenames[1] = NULL; + return archive_read_open_filenames(a, filenames, block_size); +} + +int +archive_read_open_filenames(struct archive *a, const char **filenames, + size_t block_size) +{ + struct read_file_data *mine; + const char *filename = NULL; + if (filenames) + filename = *(filenames++); + + archive_clear_error(a); + do + { + if (filename == NULL) + filename = ""; + mine = (struct read_file_data *)calloc(1, + sizeof(*mine) + strlen(filename)); + if (mine == NULL) + goto no_memory; + strcpy(mine->filename.m, filename); + mine->block_size = block_size; + mine->fd = -1; + mine->buffer = NULL; + mine->st_mode = mine->use_lseek = 0; + if (filename == NULL || filename[0] == '\0') { + mine->filename_type = FNT_STDIN; + } else + mine->filename_type = FNT_MBS; + if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) + return (ARCHIVE_FATAL); + if (filenames == NULL) + break; + filename = *(filenames++); + } while (filename != NULL && filename[0] != '\0'); + archive_read_set_open_callback(a, file_open); + archive_read_set_read_callback(a, file_read); + archive_read_set_skip_callback(a, file_skip); + archive_read_set_close_callback(a, file_close); + archive_read_set_switch_callback(a, file_switch); + archive_read_set_seek_callback(a, file_seek); + + return (archive_read_open1(a)); +no_memory: + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); +} + +int +archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, + size_t block_size) +{ + struct read_file_data *mine = (struct read_file_data *)calloc(1, + sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t)); + if (!mine) + { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + mine->fd = -1; + mine->block_size = block_size; + + if (wfilename == NULL || wfilename[0] == L'\0') { + mine->filename_type = FNT_STDIN; + } else { +#if defined(_WIN32) && !defined(__CYGWIN__) + mine->filename_type = FNT_WCS; + wcscpy(mine->filename.w, wfilename); +#else + /* + * POSIX system does not support a wchar_t interface for + * open() system call, so we have to translate a wchar_t + * filename to multi-byte one and use it. + */ + struct archive_string fn; + + archive_string_init(&fn); + if (archive_string_append_from_wcs(&fn, wfilename, + wcslen(wfilename)) != 0) { + if (errno == ENOMEM) + archive_set_error(a, errno, + "Can't allocate memory"); + else + archive_set_error(a, EINVAL, + "Failed to convert a wide-character" + " filename to a multi-byte filename"); + archive_string_free(&fn); + free(mine); + return (ARCHIVE_FATAL); + } + mine->filename_type = FNT_MBS; + strcpy(mine->filename.m, fn.s); + archive_string_free(&fn); +#endif + } + if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) + return (ARCHIVE_FATAL); + archive_read_set_open_callback(a, file_open); + archive_read_set_read_callback(a, file_read); + archive_read_set_skip_callback(a, file_skip); + archive_read_set_close_callback(a, file_close); + archive_read_set_switch_callback(a, file_switch); + archive_read_set_seek_callback(a, file_seek); + + return (archive_read_open1(a)); +} + +static int +file_open(struct archive *a, void *client_data) +{ + struct stat st; + struct read_file_data *mine = (struct read_file_data *)client_data; + void *buffer; + const char *filename = NULL; + const wchar_t *wfilename = NULL; + int fd = -1; + int is_disk_like = 0; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */ +#elif defined(__NetBSD__) || defined(__OpenBSD__) + struct disklabel dl; +#elif defined(__DragonFly__) + struct partinfo pi; +#endif + + archive_clear_error(a); + if (mine->filename_type == FNT_STDIN) { + /* We used to delegate stdin support by + * directly calling archive_read_open_fd(a,0,block_size) + * here, but that doesn't (and shouldn't) handle the + * end-of-file flush when reading stdout from a pipe. + * Basically, read_open_fd() is intended for folks who + * are willing to handle such details themselves. This + * API is intended to be a little smarter for folks who + * want easy handling of the common case. + */ + fd = 0; +#if defined(__CYGWIN__) || defined(_WIN32) + setmode(0, O_BINARY); +#endif + filename = ""; + } else if (mine->filename_type == FNT_MBS) { + filename = mine->filename.m; + fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + if (fd < 0) { + archive_set_error(a, errno, + "Failed to open '%s'", filename); + return (ARCHIVE_FATAL); + } + } else { +#if defined(_WIN32) && !defined(__CYGWIN__) + wfilename = mine->filename.w; + fd = _wopen(wfilename, O_RDONLY | O_BINARY); + if (fd < 0 && errno == ENOENT) { + wchar_t *fullpath; + fullpath = __la_win_permissive_name_w(wfilename); + if (fullpath != NULL) { + fd = _wopen(fullpath, O_RDONLY | O_BINARY); + free(fullpath); + } + } + if (fd < 0) { + archive_set_error(a, errno, + "Failed to open '%S'", wfilename); + return (ARCHIVE_FATAL); + } +#else + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unexpedted operation in archive_read_open_filename"); + goto fail; +#endif + } + if (fstat(fd, &st) != 0) { + if (mine->filename_type == FNT_WCS) + archive_set_error(a, errno, "Can't stat '%S'", + wfilename); + else + archive_set_error(a, errno, "Can't stat '%s'", + filename); + goto fail; + } + + /* + * Determine whether the input looks like a disk device or a + * tape device. The results are used below to select an I/O + * strategy: + * = "disk-like" devices support arbitrary lseek() and will + * support I/O requests of any size. So we get easy skipping + * and can cheat on block sizes to get better performance. + * = "tape-like" devices require strict blocking and use + * specialized ioctls for seeking. + * = "socket-like" devices cannot seek at all but can improve + * performance by using nonblocking I/O to read "whatever is + * available right now". + * + * Right now, we only specially recognize disk-like devices, + * but it should be straightforward to add probes and strategy + * here for tape-like and socket-like devices. + */ + if (S_ISREG(st.st_mode)) { + /* Safety: Tell the extractor not to overwrite the input. */ + archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); + /* Regular files act like disks. */ + is_disk_like = 1; + } +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + /* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */ + else if (S_ISCHR(st.st_mode) && + ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 && + mediasize > 0) { + is_disk_like = 1; + } +#elif defined(__NetBSD__) || defined(__OpenBSD__) + /* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */ + else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) && + ioctl(fd, DIOCGDINFO, &dl) == 0 && + dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) { + is_disk_like = 1; + } +#elif defined(__DragonFly__) + /* DragonFly BSD: if it supports DIOCGPART ioctl, it's disk-like. */ + else if (S_ISCHR(st.st_mode) && + ioctl(fd, DIOCGPART, &pi) == 0 && + pi.media_size > 0) { + is_disk_like = 1; + } +#elif defined(__linux__) + /* Linux: All block devices are disk-like. */ + else if (S_ISBLK(st.st_mode) && + lseek(fd, 0, SEEK_CUR) == 0 && + lseek(fd, 0, SEEK_SET) == 0 && + lseek(fd, 0, SEEK_END) > 0 && + lseek(fd, 0, SEEK_SET) == 0) { + is_disk_like = 1; + } +#endif + /* TODO: Add an "is_tape_like" variable and appropriate tests. */ + + /* Disk-like devices prefer power-of-two block sizes. */ + /* Use provided block_size as a guide so users have some control. */ + if (is_disk_like) { + size_t new_block_size = 64 * 1024; + while (new_block_size < mine->block_size + && new_block_size < 64 * 1024 * 1024) + new_block_size *= 2; + mine->block_size = new_block_size; + } + buffer = malloc(mine->block_size); + if (buffer == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + goto fail; + } + mine->buffer = buffer; + mine->fd = fd; + /* Remember mode so close can decide whether to flush. */ + mine->st_mode = st.st_mode; + + /* Disk-like inputs can use lseek(). */ + if (is_disk_like) + mine->use_lseek = 1; + + return (ARCHIVE_OK); +fail: + /* + * Don't close file descriptors not opened or ones pointing referring + * to `FNT_STDIN`. + */ + if (fd != -1 && fd != 0) + close(fd); + return (ARCHIVE_FATAL); +} + +static ssize_t +file_read(struct archive *a, void *client_data, const void **buff) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; + ssize_t bytes_read; + + /* TODO: If a recent lseek() operation has left us + * mis-aligned, read and return a short block to try to get + * us back in alignment. */ + + /* TODO: Someday, try mmap() here; if that succeeds, give + * the entire file to libarchive as a single block. That + * could be a lot faster than block-by-block manual I/O. */ + + /* TODO: We might be able to improve performance on pipes and + * sockets by setting non-blocking I/O and just accepting + * whatever we get here instead of waiting for a full block + * worth of data. */ + + *buff = mine->buffer; + for (;;) { + bytes_read = read(mine->fd, mine->buffer, mine->block_size); + if (bytes_read < 0) { + if (errno == EINTR) + continue; + else if (mine->filename_type == FNT_STDIN) + archive_set_error(a, errno, + "Error reading stdin"); + else if (mine->filename_type == FNT_MBS) + archive_set_error(a, errno, + "Error reading '%s'", mine->filename.m); + else + archive_set_error(a, errno, + "Error reading '%S'", mine->filename.w); + } + return (bytes_read); + } +} + +/* + * Regular files and disk-like block devices can use simple lseek + * without needing to round the request to the block size. + * + * TODO: This can leave future reads mis-aligned. Since we know the + * offset here, we should store it and use it in file_read() above + * to determine whether we should perform a short read to get back + * into alignment. Long series of mis-aligned reads can negatively + * impact disk throughput. (Of course, the performance impact should + * be carefully tested; extra code complexity is only worthwhile if + * it does provide measurable improvement.) + * + * TODO: Be lazy about the actual seek. There are a few pathological + * cases where libarchive makes a bunch of seek requests in a row + * without any intervening reads. This isn't a huge performance + * problem, since the kernel handles seeks lazily already, but + * it would be very slightly faster if we simply remembered the + * seek request here and then actually performed the seek at the + * top of the read callback above. + */ +static int64_t +file_skip_lseek(struct archive *a, void *client_data, int64_t request) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; +#if defined(_WIN32) && !defined(__CYGWIN__) + /* We use _lseeki64() on Windows. */ + int64_t old_offset, new_offset; +#else + off_t old_offset, new_offset; +#endif + + /* We use off_t here because lseek() is declared that way. */ + + /* TODO: Deal with case where off_t isn't 64 bits. + * This shouldn't be a problem on Linux or other POSIX + * systems, since the configuration logic for libarchive + * tries to obtain a 64-bit off_t. + */ + if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && + (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0) + return (new_offset - old_offset); + + /* If lseek() fails, don't bother trying again. */ + mine->use_lseek = 0; + + /* Let libarchive recover with read+discard */ + if (errno == ESPIPE) + return (0); + + /* If the input is corrupted or truncated, fail. */ + if (mine->filename_type == FNT_STDIN) + archive_set_error(a, errno, "Error seeking in stdin"); + else if (mine->filename_type == FNT_MBS) + archive_set_error(a, errno, "Error seeking in '%s'", + mine->filename.m); + else + archive_set_error(a, errno, "Error seeking in '%S'", + mine->filename.w); + return (-1); +} + + +/* + * TODO: Implement another file_skip_XXXX that uses MTIO ioctls to + * accelerate operation on tape drives. + */ + +static int64_t +file_skip(struct archive *a, void *client_data, int64_t request) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; + + /* Delegate skip requests. */ + if (mine->use_lseek) + return (file_skip_lseek(a, client_data, request)); + + /* If we can't skip, return 0; libarchive will read+discard instead. */ + return (0); +} + +/* + * TODO: Store the offset and use it in the read callback. + */ +static int64_t +file_seek(struct archive *a, void *client_data, int64_t request, int whence) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; + int64_t r; + + /* We use off_t here because lseek() is declared that way. */ + /* See above for notes about when off_t is less than 64 bits. */ + r = lseek(mine->fd, request, whence); + if (r >= 0) + return r; + + /* If the input is corrupted or truncated, fail. */ + if (mine->filename_type == FNT_STDIN) + archive_set_error(a, errno, "Error seeking in stdin"); + else if (mine->filename_type == FNT_MBS) + archive_set_error(a, errno, "Error seeking in '%s'", + mine->filename.m); + else + archive_set_error(a, errno, "Error seeking in '%S'", + mine->filename.w); + return (ARCHIVE_FATAL); +} + +static int +file_close2(struct archive *a, void *client_data) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; + + (void)a; /* UNUSED */ + + /* Only flush and close if open succeeded. */ + if (mine->fd >= 0) { + /* + * Sometimes, we should flush the input before closing. + * Regular files: faster to just close without flush. + * Disk-like devices: Ditto. + * Tapes: must not flush (user might need to + * read the "next" item on a non-rewind device). + * Pipes and sockets: must flush (otherwise, the + * program feeding the pipe or socket may complain). + * Here, I flush everything except for regular files and + * device nodes. + */ + if (!S_ISREG(mine->st_mode) + && !S_ISCHR(mine->st_mode) + && !S_ISBLK(mine->st_mode)) { + ssize_t bytesRead; + do { + bytesRead = read(mine->fd, mine->buffer, + mine->block_size); + } while (bytesRead > 0); + } + /* If a named file was opened, then it needs to be closed. */ + if (mine->filename_type != FNT_STDIN) + close(mine->fd); + } + free(mine->buffer); + mine->buffer = NULL; + mine->fd = -1; + return (ARCHIVE_OK); +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct read_file_data *mine = (struct read_file_data *)client_data; + file_close2(a, client_data); + free(mine); + return (ARCHIVE_OK); +} + +static int +file_switch(struct archive *a, void *client_data1, void *client_data2) +{ + file_close2(a, client_data1); + return file_open(a, client_data2); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_open_memory.c b/src/3rdparty/libarchive/libarchive/archive_read_open_memory.c new file mode 100644 index 00000000..311be470 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_open_memory.c @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/06 15:51:59 kientzle Exp $"); + +#include +#include +#include + +#include "archive.h" + +/* + * Glue to read an archive from a block of memory. + * + * This is mostly a huge help in building test harnesses; + * test programs can build archives in memory and read them + * back again without having to mess with files on disk. + */ + +struct read_memory_data { + const unsigned char *start; + const unsigned char *p; + const unsigned char *end; + ssize_t read_size; +}; + +static int memory_read_close(struct archive *, void *); +static int memory_read_open(struct archive *, void *); +static int64_t memory_read_seek(struct archive *, void *, int64_t offset, int whence); +static int64_t memory_read_skip(struct archive *, void *, int64_t request); +static ssize_t memory_read(struct archive *, void *, const void **buff); + +int +archive_read_open_memory(struct archive *a, const void *buff, size_t size) +{ + return archive_read_open_memory2(a, buff, size, size); +} + +/* + * Don't use _open_memory2() in production code; the archive_read_open_memory() + * version is the one you really want. This is just here so that + * test harnesses can exercise block operations inside the library. + */ +int +archive_read_open_memory2(struct archive *a, const void *buff, + size_t size, size_t read_size) +{ + struct read_memory_data *mine; + + mine = (struct read_memory_data *)calloc(1, sizeof(*mine)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + mine->start = mine->p = (const unsigned char *)buff; + mine->end = mine->start + size; + mine->read_size = read_size; + archive_read_set_open_callback(a, memory_read_open); + archive_read_set_read_callback(a, memory_read); + 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); + return (archive_read_open1(a)); +} + +/* + * There's nothing to open. + */ +static int +memory_read_open(struct archive *a, void *client_data) +{ + (void)a; /* UNUSED */ + (void)client_data; /* UNUSED */ + return (ARCHIVE_OK); +} + +/* + * This is scary simple: Just advance a pointer. Limiting + * to read_size is not technically necessary, but it exercises + * more of the internal logic when used with a small block size + * in a test harness. Production use should not specify a block + * size; then this is much faster. + */ +static ssize_t +memory_read(struct archive *a, void *client_data, const void **buff) +{ + struct read_memory_data *mine = (struct read_memory_data *)client_data; + ssize_t size; + + (void)a; /* UNUSED */ + *buff = mine->p; + size = mine->end - mine->p; + if (size > mine->read_size) + size = mine->read_size; + mine->p += size; + return (size); +} + +/* + * Advancing is just as simple. Again, this is doing more than + * necessary in order to better exercise internal code when used + * as a test harness. + */ +static int64_t +memory_read_skip(struct archive *a, void *client_data, int64_t skip) +{ + struct read_memory_data *mine = (struct read_memory_data *)client_data; + + (void)a; /* UNUSED */ + if ((int64_t)skip > (int64_t)(mine->end - mine->p)) + skip = mine->end - mine->p; + /* Round down to block size. */ + skip /= mine->read_size; + skip *= mine->read_size; + mine->p += skip; + return (skip); +} + +/* + * Seeking. + */ +static int64_t +memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence) +{ + struct read_memory_data *mine = (struct read_memory_data *)client_data; + + (void)a; /* UNUSED */ + switch (whence) { + case SEEK_SET: + mine->p = mine->start + offset; + break; + case SEEK_CUR: + mine->p += offset; + break; + case SEEK_END: + mine->p = mine->end + offset; + break; + default: + return ARCHIVE_FATAL; + } + if (mine->p < mine->start) { + mine->p = mine->start; + return ARCHIVE_FAILED; + } + if (mine->p > mine->end) { + mine->p = mine->end; + return ARCHIVE_FAILED; + } + return (mine->p - mine->start); +} + +/* + * Close is just cleaning up our one small bit of data. + */ +static int +memory_read_close(struct archive *a, void *client_data) +{ + struct read_memory_data *mine = (struct read_memory_data *)client_data; + (void)a; /* UNUSED */ + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_private.h b/src/3rdparty/libarchive/libarchive/archive_read_private.h new file mode 100644 index 00000000..78546dca --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_private.h @@ -0,0 +1,263 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_read_private.h 201088 2009-12-28 02:18:55Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED +#define ARCHIVE_READ_PRIVATE_H_INCLUDED + +#include "archive.h" +#include "archive_string.h" +#include "archive_private.h" + +struct archive_read; +struct archive_read_filter_bidder; +struct archive_read_filter; + +/* + * How bidding works for filters: + * * The bid manager initializes the client-provided reader as the + * first filter. + * * It invokes the bidder for each registered filter with the + * current head filter. + * * The bidders can use archive_read_filter_ahead() to peek ahead + * at the incoming data to compose their bids. + * * The bid manager creates a new filter structure for the winning + * bidder and gives the winning bidder a chance to initialize it. + * * The new filter becomes the new top filter and we repeat the + * process. + * This ends only when no bidder provides a non-zero bid. Then + * we perform a similar dance with the registered format handlers. + */ +struct archive_read_filter_bidder { + /* Configuration data for the bidder. */ + void *data; + /* Name of the filter */ + const char *name; + /* Taste the upstream filter to see if we handle this. */ + int (*bid)(struct archive_read_filter_bidder *, + struct archive_read_filter *); + /* Initialize a newly-created filter. */ + int (*init)(struct archive_read_filter *); + /* Set an option for the filter bidder. */ + int (*options)(struct archive_read_filter_bidder *, + const char *key, const char *value); + /* Release the bidder's configuration data. */ + int (*free)(struct archive_read_filter_bidder *); +}; + +/* + * This structure is allocated within the archive_read core + * and initialized by archive_read and the init() method of the + * corresponding bidder above. + */ +struct archive_read_filter { + int64_t position; + /* Essentially all filters will need these values, so + * just declare them here. */ + struct archive_read_filter_bidder *bidder; /* My bidder. */ + struct archive_read_filter *upstream; /* Who I read from. */ + struct archive_read *archive; /* Associated archive. */ + /* Open a block for reading */ + int (*open)(struct archive_read_filter *self); + /* Return next block. */ + ssize_t (*read)(struct archive_read_filter *, const void **); + /* Skip forward this many bytes. */ + int64_t (*skip)(struct archive_read_filter *self, int64_t request); + /* Seek to an absolute location. */ + int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence); + /* Close (just this filter) and free(self). */ + int (*close)(struct archive_read_filter *self); + /* Function that handles switching from reading one block to the next/prev */ + int (*sswitch)(struct archive_read_filter *self, unsigned int iindex); + /* My private data. */ + void *data; + + const char *name; + int code; + + /* Used by reblocking logic. */ + char *buffer; + size_t buffer_size; + char *next; /* Current read location. */ + size_t avail; /* Bytes in my buffer. */ + const void *client_buff; /* Client buffer information. */ + size_t client_total; + const char *client_next; + size_t client_avail; + char end_of_file; + char closed; + char fatal; +}; + +/* + * The client looks a lot like a filter, so we just wrap it here. + * + * TODO: Make archive_read_filter and archive_read_client identical so + * that users of the library can easily register their own + * transformation filters. This will probably break the API/ABI and + * so should be deferred at least until libarchive 3.0. + */ +struct archive_read_data_node { + int64_t begin_position; + int64_t total_size; + void *data; +}; +struct archive_read_client { + archive_open_callback *opener; + archive_read_callback *reader; + archive_skip_callback *skipper; + archive_seek_callback *seeker; + archive_close_callback *closer; + archive_switch_callback *switcher; + unsigned int nodes; + unsigned int cursor; + int64_t position; + struct archive_read_data_node *dataset; +}; +struct archive_read_passphrase { + char *passphrase; + struct archive_read_passphrase *next; +}; + +struct archive_read_extract { + struct archive *ad; /* archive_write_disk object */ + + /* Progress function invoked during extract. */ + void (*extract_progress)(void *); + void *extract_progress_user_data; +}; + +struct archive_read { + struct archive archive; + + struct archive_entry *entry; + + /* Dev/ino of the archive being read/written. */ + int skip_file_set; + int64_t skip_file_dev; + int64_t skip_file_ino; + + /* Callbacks to open/read/write/close client archive streams. */ + struct archive_read_client client; + + /* Registered filter bidders. */ + struct archive_read_filter_bidder bidders[16]; + + /* Last filter in chain */ + struct archive_read_filter *filter; + + /* Whether to bypass filter bidding process */ + int bypass_filter_bidding; + + /* File offset of beginning of most recently-read header. */ + int64_t header_position; + + /* Nodes and offsets of compressed data block */ + unsigned int data_start_node; + unsigned int data_end_node; + + /* + * Format detection is mostly the same as compression + * detection, with one significant difference: The bidders + * use the read_ahead calls above to examine the stream rather + * than having the supervisor hand them a block of data to + * examine. + */ + + struct archive_format_descriptor { + void *data; + const char *name; + int (*bid)(struct archive_read *, int best_bid); + int (*options)(struct archive_read *, const char *key, + const char *value); + int (*read_header)(struct archive_read *, struct archive_entry *); + int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *); + int (*read_data_skip)(struct archive_read *); + int64_t (*seek_data)(struct archive_read *, int64_t, int); + int (*cleanup)(struct archive_read *); + int (*format_capabilties)(struct archive_read *); + int (*has_encrypted_entries)(struct archive_read *); + } formats[16]; + struct archive_format_descriptor *format; /* Active format. */ + + /* + * Various information needed by archive_extract. + */ + struct archive_read_extract *extract; + int (*cleanup_archive_extract)(struct archive_read *); + + /* + * Decryption passphrase. + */ + struct { + struct archive_read_passphrase *first; + struct archive_read_passphrase **last; + int candidate; + archive_passphrase_callback *callback; + void *client_data; + } passphrases; +}; + +int __archive_read_register_format(struct archive_read *a, + void *format_data, + const char *name, + int (*bid)(struct archive_read *, int), + int (*options)(struct archive_read *, const char *, const char *), + int (*read_header)(struct archive_read *, struct archive_entry *), + int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), + int (*read_data_skip)(struct archive_read *), + int64_t (*seek_data)(struct archive_read *, int64_t, int), + int (*cleanup)(struct archive_read *), + int (*format_capabilities)(struct archive_read *), + int (*has_encrypted_entries)(struct archive_read *)); + +int __archive_read_get_bidder(struct archive_read *a, + struct archive_read_filter_bidder **bidder); + +const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *); +const void *__archive_read_filter_ahead(struct archive_read_filter *, + size_t, ssize_t *); +int64_t __archive_read_seek(struct archive_read*, int64_t, int); +int64_t __archive_read_filter_seek(struct archive_read_filter *, int64_t, int); +int64_t __archive_read_consume(struct archive_read *, int64_t); +int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t); +int __archive_read_program(struct archive_read_filter *, const char *); +void __archive_read_free_filters(struct archive_read *); +struct archive_read_extract *__archive_read_get_extract(struct archive_read *); + + +/* + * Get a decryption passphrase. + */ +void __archive_read_reset_passphrase(struct archive_read *a); +const char * __archive_read_next_passphrase(struct archive_read *a); +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_read_set_format.c b/src/3rdparty/libarchive/libarchive/archive_read_set_format.c new file mode 100644 index 00000000..190f4369 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_set_format.c @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2003-2012 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_read_private.h" + +int +archive_read_set_format(struct archive *_a, int code) +{ + int r1, r2, slots, i; + char str[10]; + struct archive_read *a = (struct archive_read *)_a; + + if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK)) + return r1; + + r1 = r2 = (ARCHIVE_OK); + if (a->format) + r2 = (ARCHIVE_WARN); + switch (code & ARCHIVE_FORMAT_BASE_MASK) + { + case ARCHIVE_FORMAT_7ZIP: + strcpy(str, "7zip"); + break; + case ARCHIVE_FORMAT_AR: + strcpy(str, "ar"); + break; + case ARCHIVE_FORMAT_CAB: + strcpy(str, "cab"); + break; + case ARCHIVE_FORMAT_CPIO: + strcpy(str, "cpio"); + break; + case ARCHIVE_FORMAT_ISO9660: + strcpy(str, "iso9660"); + break; + case ARCHIVE_FORMAT_LHA: + strcpy(str, "lha"); + break; + case ARCHIVE_FORMAT_MTREE: + strcpy(str, "mtree"); + break; + case ARCHIVE_FORMAT_RAR: + strcpy(str, "rar"); + break; + case ARCHIVE_FORMAT_TAR: + strcpy(str, "tar"); + break; + case ARCHIVE_FORMAT_XAR: + strcpy(str, "xar"); + break; + case ARCHIVE_FORMAT_ZIP: + strcpy(str, "zip"); + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Invalid format code specified"); + return (ARCHIVE_FATAL); + } + + slots = sizeof(a->formats) / sizeof(a->formats[0]); + a->format = &(a->formats[0]); + for (i = 0; i < slots; i++, a->format++) { + if (!a->format->name || !strcmp(a->format->name, str)) + break; + } + if (!a->format->name || strcmp(a->format->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to set format"); + r1 = (ARCHIVE_FATAL); + } + + return (r1 < r2) ? r1 : r2; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_set_options.c b/src/3rdparty/libarchive/libarchive/archive_read_set_options.c new file mode 100644 index 00000000..2e2eea69 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_set_options.c @@ -0,0 +1,155 @@ +/*- + * 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 "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive_read_private.h" +#include "archive_options_private.h" + +static int archive_set_format_option(struct archive *a, + const char *m, const char *o, const char *v); +static int archive_set_filter_option(struct archive *a, + const char *m, const char *o, const char *v); +static int archive_set_option(struct archive *a, + const char *m, const char *o, const char *v); + +int +archive_read_set_format_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_READ_MAGIC, "archive_read_set_format_option", + archive_set_format_option); +} + +int +archive_read_set_filter_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_READ_MAGIC, "archive_read_set_filter_option", + archive_set_filter_option); +} + +int +archive_read_set_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_READ_MAGIC, "archive_read_set_option", + archive_set_option); +} + +int +archive_read_set_options(struct archive *a, const char *options) +{ + return _archive_set_options(a, options, + ARCHIVE_READ_MAGIC, "archive_read_set_options", + archive_set_option); +} + +static int +archive_set_format_option(struct archive *_a, const char *m, const char *o, + const char *v) +{ + struct archive_read *a = (struct archive_read *)_a; + size_t i; + int r, rv = ARCHIVE_WARN, matched_modules = 0; + + for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) { + struct archive_format_descriptor *format = &a->formats[i]; + + if (format->options == NULL || format->name == NULL) + /* This format does not support option. */ + continue; + if (m != NULL) { + if (strcmp(format->name, m) != 0) + continue; + ++matched_modules; + } + + a->format = format; + r = format->options(a, o, v); + a->format = NULL; + + if (r == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + + if (r == ARCHIVE_OK) + rv = ARCHIVE_OK; + } + /* If the format name didn't match, return a special code for + * _archive_set_option[s]. */ + if (m != NULL && matched_modules == 0) + return ARCHIVE_WARN - 1; + return (rv); +} + +static int +archive_set_filter_option(struct archive *_a, const char *m, const char *o, + const char *v) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter *filter; + struct archive_read_filter_bidder *bidder; + int r, rv = ARCHIVE_WARN, matched_modules = 0; + + for (filter = a->filter; filter != NULL; filter = filter->upstream) { + bidder = filter->bidder; + if (bidder == NULL) + continue; + if (bidder->options == NULL) + /* This bidder does not support option */ + continue; + if (m != NULL) { + if (strcmp(filter->name, m) != 0) + continue; + ++matched_modules; + } + + r = bidder->options(bidder, o, v); + + if (r == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + + if (r == ARCHIVE_OK) + rv = ARCHIVE_OK; + } + /* If the filter name didn't match, return a special code for + * _archive_set_option[s]. */ + if (m != NULL && matched_modules == 0) + return ARCHIVE_WARN - 1; + return (rv); +} + +static int +archive_set_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_either_option(a, m, o, v, + archive_set_format_option, + archive_set_filter_option); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c new file mode 100644 index 00000000..3885a7cf --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_bzip2.c @@ -0,0 +1,371 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_read_private.h" + +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) +struct private_data { + bz_stream stream; + char *out_block; + size_t out_block_size; + char valid; /* True = decompressor is initialized */ + char eof; /* True = found end of compressed data. */ +}; + +/* Bzip2 filter */ +static ssize_t bzip2_filter_read(struct archive_read_filter *, const void **); +static int bzip2_filter_close(struct archive_read_filter *); +#endif + +/* + * 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. + */ +static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); +static int bzip2_reader_init(struct archive_read_filter *); +static int bzip2_reader_free(struct archive_read_filter_bidder *); + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Deprecated; remove in libarchive 4.0 */ +int +archive_read_support_compression_bzip2(struct archive *a) +{ + return archive_read_support_filter_bzip2(a); +} +#endif + +int +archive_read_support_filter_bzip2(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *reader; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2"); + + if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + reader->data = NULL; + reader->name = "bzip2"; + reader->bid = bzip2_reader_bid; + reader->init = bzip2_reader_init; + reader->options = NULL; + reader->free = bzip2_reader_free; +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) + return (ARCHIVE_OK); +#else + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "Using external bzip2 program"); + return (ARCHIVE_WARN); +#endif +} + +static int +bzip2_reader_free(struct archive_read_filter_bidder *self){ + (void)self; /* UNUSED */ + return (ARCHIVE_OK); +} + +/* + * Test whether we can handle this data. + * + * This logic returns zero if any part of the signature fails. It + * also tries to Do The Right Thing if a very short buffer prevents us + * from verifying as much as we would like. + */ +static int +bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter) +{ + const unsigned char *buffer; + ssize_t avail; + int bits_checked; + + (void)self; /* UNUSED */ + + /* Minimal bzip2 archive is 14 bytes. */ + buffer = __archive_read_filter_ahead(filter, 14, &avail); + if (buffer == NULL) + return (0); + + /* First three bytes must be "BZh" */ + bits_checked = 0; + if (memcmp(buffer, "BZh", 3) != 0) + return (0); + bits_checked += 24; + + /* Next follows a compression flag which must be an ASCII digit. */ + if (buffer[3] < '1' || buffer[3] > '9') + return (0); + bits_checked += 5; + + /* After BZh[1-9], there must be either a data block + * which begins with 0x314159265359 or an end-of-data + * marker of 0x177245385090. */ + if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0) + bits_checked += 48; + else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0) + bits_checked += 48; + else + return (0); + + return (bits_checked); +} + +#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. + */ +static int +bzip2_reader_init(struct archive_read_filter *self) +{ + int r; + + r = __archive_read_program(self, "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"; + return (r); +} + + +#else + +/* + * Setup the callbacks. + */ +static int +bzip2_reader_init(struct archive_read_filter *self) +{ + static const size_t out_block_size = 64 * 1024; + void *out_block; + struct private_data *state; + + self->code = ARCHIVE_FILTER_BZIP2; + self->name = "bzip2"; + + state = (struct private_data *)calloc(sizeof(*state), 1); + out_block = (unsigned char *)malloc(out_block_size); + if (state == NULL || out_block == NULL) { + archive_set_error(&self->archive->archive, ENOMEM, + "Can't allocate data for bzip2 decompression"); + free(out_block); + free(state); + return (ARCHIVE_FATAL); + } + + self->data = state; + state->out_block_size = out_block_size; + state->out_block = out_block; + self->read = bzip2_filter_read; + self->skip = NULL; /* not supported */ + self->close = bzip2_filter_close; + + return (ARCHIVE_OK); +} + +/* + * Return the next block of decompressed data. + */ +static ssize_t +bzip2_filter_read(struct archive_read_filter *self, const void **p) +{ + struct private_data *state; + size_t decompressed; + const char *read_buf; + ssize_t ret; + + state = (struct private_data *)self->data; + + if (state->eof) { + *p = NULL; + return (0); + } + + /* Empty our output buffer. */ + state->stream.next_out = state->out_block; + state->stream.avail_out = state->out_block_size; + + /* Try to fill the output buffer. */ + 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; + return (decompressed); + } + /* Initialize compression library. */ + ret = BZ2_bzDecompressInit(&(state->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), + 0 /* library verbosity */, + 1 /* do use low-mem algo */); + + if (ret != BZ_OK) { + const char *detail = NULL; + int err = ARCHIVE_ERRNO_MISC; + switch (ret) { + case BZ_PARAM_ERROR: + detail = "invalid setup parameter"; + break; + case BZ_MEM_ERROR: + err = ENOMEM; + detail = "out of memory"; + break; + case BZ_CONFIG_ERROR: + detail = "mis-compiled library"; + break; + } + archive_set_error(&self->archive->archive, err, + "Internal error initializing decompressor%s%s", + detail == NULL ? "" : ": ", + detail); + return (ARCHIVE_FATAL); + } + state->valid = 1; + } + + /* stream.next_in is really const, but bzlib + * doesn't declare it so. */ + read_buf = + __archive_read_filter_ahead(self->upstream, 1, &ret); + if (read_buf == NULL) { + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "truncated bzip2 input"); + return (ARCHIVE_FATAL); + } + state->stream.next_in = (char *)(uintptr_t)read_buf; + state->stream.avail_in = 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); + } + + /* 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); + + switch (ret) { + case BZ_STREAM_END: /* Found end of stream. */ + switch (BZ2_bzDecompressEnd(&(state->stream))) { + case BZ_OK: + break; + default: + archive_set_error(&(self->archive->archive), + ARCHIVE_ERRNO_MISC, + "Failed to clean up decompressor"); + return (ARCHIVE_FATAL); + } + state->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; + return (decompressed); + } + break; + default: /* Return an error. */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, "bzip decompression failed"); + return (ARCHIVE_FATAL); + } + } +} + +/* + * Clean up the decompressor. + */ +static int +bzip2_filter_close(struct archive_read_filter *self) +{ + struct private_data *state; + int ret = ARCHIVE_OK; + + state = (struct private_data *)self->data; + + if (state->valid) { + switch (BZ2_bzDecompressEnd(&state->stream)) { + case BZ_OK: + break; + default: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Failed to clean up decompressor"); + ret = ARCHIVE_FATAL; + } + state->valid = 0; + } + + free(state->out_block); + free(state); + return (ret); +} + +#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */ diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c new file mode 100644 index 00000000..fa8c675d --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_gzip.c @@ -0,0 +1,477 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD$"); + + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_read_private.h" + +#ifdef HAVE_ZLIB_H +struct private_data { + z_stream stream; + char in_stream; + unsigned char *out_block; + size_t out_block_size; + int64_t total_out; + unsigned long crc; + char eof; /* True = found end of compressed data. */ +}; + +/* Gzip Filter. */ +static ssize_t gzip_filter_read(struct archive_read_filter *, const void **); +static int gzip_filter_close(struct archive_read_filter *); +#endif + +/* + * 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. + */ +static int gzip_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *); +static int gzip_bidder_init(struct archive_read_filter *); + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Deprecated; remove in libarchive 4.0 */ +int +archive_read_support_compression_gzip(struct archive *a) +{ + return archive_read_support_filter_gzip(a); +} +#endif + +int +archive_read_support_filter_gzip(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *bidder; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip"); + + if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + bidder->data = NULL; + bidder->name = "gzip"; + bidder->bid = gzip_bidder_bid; + bidder->init = gzip_bidder_init; + bidder->options = NULL; + bidder->free = NULL; /* No data, so no cleanup necessary. */ + /* Signal the extent of gzip support with the return value here. */ +#if HAVE_ZLIB_H + return (ARCHIVE_OK); +#else + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "Using external gzip program"); + return (ARCHIVE_WARN); +#endif +} + +/* + * Read and verify the header. + * + * Returns zero if the header couldn't be validated, else returns + * number of bytes in header. If pbits is non-NULL, it receives a + * count of bits verified, suitable for use by bidder. + */ +static ssize_t +peek_at_header(struct archive_read_filter *filter, int *pbits) +{ + const unsigned char *p; + ssize_t avail, len; + int bits = 0; + int header_flags; + + /* 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) + return (0); + /* We only support deflation- third byte must be 0x08. */ + if (memcmp(p, "\x1F\x8B\x08", 3) != 0) + return (0); + bits += 24; + if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */ + return (0); + bits += 3; + header_flags = p[3]; + /* Bytes 4-7 are mod time. */ + /* Byte 8 is deflate flags. */ + /* XXXX TODO: return deflate flags back to consume_header for use + in initializing the decompressor. */ + /* Byte 9 is OS. */ + + /* Optional extra data: 2 byte length plus variable body. */ + if (header_flags & 4) { + p = __archive_read_filter_ahead(filter, len + 2, &avail); + if (p == NULL) + return (0); + len += ((int)p[len + 1] << 8) | (int)p[len]; + len += 2; + } + + /* Null-terminated optional filename. */ + if (header_flags & 8) { + do { + ++len; + if (avail < len) + p = __archive_read_filter_ahead(filter, + len, &avail); + if (p == NULL) + return (0); + } while (p[len - 1] != 0); + } + + /* Null-terminated optional comment. */ + if (header_flags & 16) { + do { + ++len; + if (avail < len) + p = __archive_read_filter_ahead(filter, + len, &avail); + if (p == NULL) + return (0); + } while (p[len - 1] != 0); + } + + /* Optional header CRC */ + if ((header_flags & 2)) { + p = __archive_read_filter_ahead(filter, len + 2, &avail); + if (p == NULL) + return (0); +#if 0 + int hcrc = ((int)p[len + 1] << 8) | (int)p[len]; + int crc = /* XXX TODO: Compute header CRC. */; + if (crc != hcrc) + return (0); + bits += 16; +#endif + len += 2; + } + + if (pbits != NULL) + *pbits = bits; + return (len); +} + +/* + * 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) +{ + int bits_checked; + + (void)self; /* UNUSED */ + + if (peek_at_header(filter, &bits_checked)) + return (bits_checked); + return (0); +} + + +#ifndef HAVE_ZLIB_H + +/* + * If we don't have the library on this system, we can't do the + * decompression directly. We can, however, try to run "gzip -d" + * in case that's available. + */ +static int +gzip_bidder_init(struct archive_read_filter *self) +{ + int r; + + r = __archive_read_program(self, "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"; + return (r); +} + +#else + +/* + * Initialize the filter object. + */ +static int +gzip_bidder_init(struct archive_read_filter *self) +{ + struct private_data *state; + static const size_t out_block_size = 64 * 1024; + void *out_block; + + self->code = ARCHIVE_FILTER_GZIP; + self->name = "gzip"; + + state = (struct private_data *)calloc(sizeof(*state), 1); + out_block = (unsigned char *)malloc(out_block_size); + if (state == NULL || out_block == NULL) { + free(out_block); + free(state); + archive_set_error(&self->archive->archive, ENOMEM, + "Can't allocate data for gzip decompression"); + return (ARCHIVE_FATAL); + } + + self->data = state; + state->out_block_size = out_block_size; + state->out_block = out_block; + self->read = gzip_filter_read; + self->skip = NULL; /* not supported */ + self->close = gzip_filter_close; + + state->in_stream = 0; /* We're not actually within a stream yet. */ + + return (ARCHIVE_OK); +} + +static int +consume_header(struct archive_read_filter *self) +{ + struct private_data *state; + ssize_t avail; + 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); + if (len == 0) + return (ARCHIVE_EOF); + __archive_read_filter_consume(self->upstream, len); + + /* Initialize CRC accumulator. */ + state->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), + -15 /* Don't check for zlib header */); + + /* Decipher the error code. */ + switch (ret) { + case Z_OK: + state->in_stream = 1; + return (ARCHIVE_OK); + case Z_STREAM_ERROR: + archive_set_error(&self->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, + "Internal error initializing compression library: " + "out of memory"); + break; + case Z_VERSION_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + "invalid library version"); + break; + default: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + " Zlib error %d", ret); + break; + } + return (ARCHIVE_FATAL); +} + +static int +consume_trailer(struct archive_read_filter *self) +{ + struct private_data *state; + const unsigned char *p; + ssize_t avail; + + state = (struct private_data *)self->data; + + state->in_stream = 0; + switch (inflateEnd(&(state->stream))) { + case Z_OK: + break; + default: + archive_set_error(&self->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) + 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); + + return (ARCHIVE_OK); +} + +static ssize_t +gzip_filter_read(struct archive_read_filter *self, const void **p) +{ + struct private_data *state; + size_t decompressed; + ssize_t avail_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; + + /* Try to fill the output buffer. */ + while (state->stream.avail_out > 0 && !state->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 (ret == ARCHIVE_EOF) { + state->eof = 1; + break; + } + if (ret < ARCHIVE_OK) + return (ret); + } + + /* 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, + ARCHIVE_ERRNO_MISC, + "truncated gzip input"); + return (ARCHIVE_FATAL); + } + state->stream.avail_in = (uInt)avail_in; + + /* Decompress and consume some of that data. */ + ret = inflate(&(state->stream), 0); + switch (ret) { + case Z_OK: /* Decompressor made some progress. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); + break; + case Z_STREAM_END: /* Found end of stream. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); + /* Consume the stream trailer; release the + * decompression library. */ + ret = consume_trailer(self); + if (ret < ARCHIVE_OK) + return (ret); + break; + default: + /* Return an error. */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "gzip decompression failed"); + return (ARCHIVE_FATAL); + } + } + + /* We've read as much as we can. */ + decompressed = state->stream.next_out - state->out_block; + state->total_out += decompressed; + if (decompressed == 0) + *p = NULL; + else + *p = state->out_block; + return (decompressed); +} + +/* + * Clean up the decompressor. + */ +static int +gzip_filter_close(struct archive_read_filter *self) +{ + struct private_data *state; + int ret; + + state = (struct private_data *)self->data; + ret = ARCHIVE_OK; + + if (state->in_stream) { + switch (inflateEnd(&(state->stream))) { + case Z_OK: + break; + default: + archive_set_error(&(self->archive->archive), + ARCHIVE_ERRNO_MISC, + "Failed to clean up gzip compressor"); + ret = ARCHIVE_FATAL; + } + } + + free(state->out_block); + free(state); + return (ret); +} + +#endif /* HAVE_ZLIB_H */ diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c new file mode 100644 index 00000000..95e5cfdb --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_none.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive.h" +#include "archive_private.h" + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Deprecated; remove in libarchive 4.0 */ +int +archive_read_support_compression_none(struct archive *a) +{ + return archive_read_support_filter_none(a); +} +#endif + +/* + * Uncompressed streams are handled implicitly by the read core, + * so this is now a no-op. + */ +int +archive_read_support_filter_none(struct archive *a) +{ + archive_check_magic(a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_none"); + + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c new file mode 100644 index 00000000..b8bf1288 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 2007 Joerg Sonnenberger + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_LIMITS_H +# include +#endif +#ifdef HAVE_SIGNAL_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" +#include "archive_read_private.h" +#include "filter_fork.h" + + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Deprecated; remove in libarchive 4.0 */ +int +archive_read_support_compression_program(struct archive *a, const char *cmd) +{ + return archive_read_support_filter_program(a, cmd); +} + +int +archive_read_support_compression_program_signature(struct archive *a, + const char *cmd, const void *signature, size_t signature_len) +{ + return archive_read_support_filter_program_signature(a, + cmd, signature, signature_len); +} +#endif + +int +archive_read_support_filter_program(struct archive *a, const char *cmd) +{ + return (archive_read_support_filter_program_signature(a, cmd, NULL, 0)); +} + +/* + * The bidder object stores the command and the signature to watch for. + * The 'inhibit' entry here is used to ensure that unchecked filters never + * bid twice in the same pipeline. + */ +struct program_bidder { + char *description; + char *cmd; + void *signature; + size_t signature_len; + int inhibit; +}; + +static int program_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *upstream); +static int program_bidder_init(struct archive_read_filter *); +static int program_bidder_free(struct archive_read_filter_bidder *); + +/* + * The actual filter needs to track input and output data. + */ +struct program_filter { + struct archive_string description; +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE child; +#else + pid_t child; +#endif + int exit_status; + int waitpid_return; + int child_stdin, child_stdout; + + char *out_buf; + size_t out_buf_len; +}; + +static ssize_t program_filter_read(struct archive_read_filter *, + const void **); +static int program_filter_close(struct archive_read_filter *); +static void free_state(struct program_bidder *); + +static int +set_bidder_signature(struct archive_read_filter_bidder *bidder, + struct program_bidder *state, const void *signature, size_t signature_len) +{ + + if (signature != NULL && signature_len > 0) { + state->signature_len = signature_len; + state->signature = malloc(signature_len); + memcpy(state->signature, signature, signature_len); + } + + /* + * Fill in the bidder object. + */ + bidder->data = state; + bidder->bid = program_bidder_bid; + bidder->init = program_bidder_init; + bidder->options = NULL; + bidder->free = program_bidder_free; + return (ARCHIVE_OK); +} + +int +archive_read_support_filter_program_signature(struct archive *_a, + const char *cmd, const void *signature, size_t signature_len) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *bidder; + struct program_bidder *state; + + /* + * Get a bidder object from the read core. + */ + if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + /* + * Allocate our private state. + */ + state = (struct program_bidder *)calloc(1, sizeof (*state)); + if (state == NULL) + goto memerr; + state->cmd = strdup(cmd); + if (state->cmd == NULL) + goto memerr; + + return set_bidder_signature(bidder, state, signature, signature_len); +memerr: + free_state(state); + archive_set_error(_a, ENOMEM, "Can't allocate memory"); + return (ARCHIVE_FATAL); +} + +static int +program_bidder_free(struct archive_read_filter_bidder *self) +{ + struct program_bidder *state = (struct program_bidder *)self->data; + + free_state(state); + return (ARCHIVE_OK); +} + +static void +free_state(struct program_bidder *state) +{ + + if (state) { + free(state->cmd); + free(state->signature); + free(state); + } +} + +/* + * If we do have a signature, bid only if that matches. + * + * If there's no signature, we bid INT_MAX the first time + * we're called, then never bid again. + */ +static int +program_bidder_bid(struct archive_read_filter_bidder *self, + struct archive_read_filter *upstream) +{ + struct program_bidder *state = self->data; + const char *p; + + /* If we have a signature, use that to match. */ + if (state->signature_len > 0) { + p = __archive_read_filter_ahead(upstream, + state->signature_len, NULL); + if (p == NULL) + return (0); + /* No match, so don't bid. */ + if (memcmp(p, state->signature, state->signature_len) != 0) + return (0); + return ((int)state->signature_len * 8); + } + + /* Otherwise, bid once and then never bid again. */ + if (state->inhibit) + return (0); + state->inhibit = 1; + return (INT_MAX); +} + +/* + * Shut down the child, return ARCHIVE_OK if it exited normally. + * + * Note that the return value is sticky; if we're called again, + * we won't reap the child again, but we will return the same status + * (including error message if the child came to a bad end). + */ +static int +child_stop(struct archive_read_filter *self, struct program_filter *state) +{ + /* Close our side of the I/O with the child. */ + if (state->child_stdin != -1) { + close(state->child_stdin); + state->child_stdin = -1; + } + if (state->child_stdout != -1) { + close(state->child_stdout); + state->child_stdout = -1; + } + + if (state->child != 0) { + /* Reap the child. */ + do { + state->waitpid_return + = waitpid(state->child, &state->exit_status, 0); + } while (state->waitpid_return == -1 && errno == EINTR); +#if defined(_WIN32) && !defined(__CYGWIN__) + CloseHandle(state->child); +#endif + state->child = 0; + } + + if (state->waitpid_return < 0) { + /* waitpid() failed? This is ugly. */ + archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, + "Child process exited badly"); + return (ARCHIVE_WARN); + } + +#if !defined(_WIN32) || defined(__CYGWIN__) + if (WIFSIGNALED(state->exit_status)) { +#ifdef SIGPIPE + /* If the child died because we stopped reading before + * it was done, that's okay. Some archive formats + * have padding at the end that we routinely ignore. */ + /* 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) + return (ARCHIVE_OK); +#endif + archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, + "Child process exited with signal %d", + WTERMSIG(state->exit_status)); + return (ARCHIVE_WARN); + } +#endif /* !_WIN32 || __CYGWIN__ */ + + if (WIFEXITED(state->exit_status)) { + if (WEXITSTATUS(state->exit_status) == 0) + return (ARCHIVE_OK); + + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Child process exited with status %d", + WEXITSTATUS(state->exit_status)); + return (ARCHIVE_WARN); + } + + return (ARCHIVE_WARN); +} + +/* + * 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) +{ + struct program_filter *state = self->data; + ssize_t ret, requested, avail; + const char *p; +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout); +#endif + + requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; + + for (;;) { + do { +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Avoid infinity wait. + * Note: If there is no data in the pipe, ReadFile() + * called in read() never returns and so we won't + * write remaining encoded data to the pipe. + * Note: This way may cause performance problem. + * we are looking forward to great code to resolve + * this. */ + DWORD pipe_avail = -1; + int cnt = 2; + + while (PeekNamedPipe(handle, NULL, 0, NULL, + &pipe_avail, NULL) != 0 && pipe_avail == 0 && + cnt--) + Sleep(5); + if (pipe_avail == 0) { + ret = -1; + errno = EAGAIN; + break; + } +#endif + ret = read(state->child_stdout, buf, requested); + } while (ret == -1 && errno == EINTR); + + if (ret > 0) + return (ret); + if (ret == 0 || (ret == -1 && errno == EPIPE)) + /* Child has closed its output; reap the child + * and return the status. */ + return (child_stop(self, state)); + if (ret == -1 && errno != EAGAIN) + return (-1); + + if (state->child_stdin == -1) { + /* Block until child has some I/O ready. */ + __archive_check_child(state->child_stdin, + state->child_stdout); + continue; + } + + /* Get some more data from upstream. */ + p = __archive_read_filter_ahead(self->upstream, 1, &avail); + if (p == NULL) { + close(state->child_stdin); + state->child_stdin = -1; + fcntl(state->child_stdout, F_SETFL, 0); + if (avail < 0) + return (avail); + continue; + } + + do { + ret = write(state->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); + } else if (ret == -1 && errno == EAGAIN) { + /* Block until child has some I/O ready. */ + __archive_check_child(state->child_stdin, + state->child_stdout); + } else { + /* Write failed. */ + close(state->child_stdin); + state->child_stdin = -1; + fcntl(state->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. */ + if (ret == -1 && errno != EPIPE) + return (-1); + } + } +} + +int +__archive_read_program(struct archive_read_filter *self, const char *cmd) +{ + struct program_filter *state; + static const size_t out_buf_len = 65536; + char *out_buf; + const char *prefix = "Program: "; + pid_t child; + size_t l; + + l = strlen(prefix) + strlen(cmd) + 1; + state = (struct program_filter *)calloc(1, sizeof(*state)); + out_buf = (char *)malloc(out_buf_len); + if (state == NULL || out_buf == NULL || + archive_string_ensure(&state->description, l) == NULL) { + archive_set_error(&self->archive->archive, ENOMEM, + "Can't allocate input data"); + if (state != NULL) { + archive_string_free(&state->description); + free(state); + } + free(out_buf); + return (ARCHIVE_FATAL); + } + archive_strcpy(&state->description, prefix); + archive_strcat(&state->description, cmd); + + self->code = ARCHIVE_FILTER_PROGRAM; + self->name = state->description.s; + + state->out_buf = out_buf; + state->out_buf_len = out_buf_len; + + child = __archive_create_child(cmd, &state->child_stdin, + &state->child_stdout); + if (child == -1) { + free(state->out_buf); + archive_string_free(&state->description); + free(state); + archive_set_error(&self->archive->archive, EINVAL, + "Can't initialize filter; unable to run program \"%s\"", + cmd); + return (ARCHIVE_FATAL); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child); + if (state->child == NULL) { + child_stop(self, state); + free(state->out_buf); + archive_string_free(&state->description); + free(state); + archive_set_error(&self->archive->archive, EINVAL, + "Can't initialize filter; unable to run program \"%s\"", + cmd); + return (ARCHIVE_FATAL); + } +#else + state->child = child; +#endif + + self->data = state; + self->read = program_filter_read; + self->skip = NULL; + self->close = program_filter_close; + + /* XXX Check that we can read at least one byte? */ + return (ARCHIVE_OK); +} + +static int +program_bidder_init(struct archive_read_filter *self) +{ + struct program_bidder *bidder_state; + + bidder_state = (struct program_bidder *)self->bidder->data; + return (__archive_read_program(self, bidder_state->cmd)); +} + +static ssize_t +program_filter_read(struct archive_read_filter *self, const void **buff) +{ + struct program_filter *state; + 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); + if (bytes < 0) + /* No recovery is possible if we can no longer + * read from the child. */ + return (ARCHIVE_FATAL); + if (bytes == 0) + /* We got EOF from the child. */ + break; + total += bytes; + p += bytes; + } + + *buff = state->out_buf; + return (total); +} + +static int +program_filter_close(struct archive_read_filter *self) +{ + struct program_filter *state; + int e; + + state = (struct program_filter *)self->data; + e = child_stop(self, state); + + /* Release our private data. */ + free(state->out_buf); + archive_string_free(&state->description); + free(state); + + return (e); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c new file mode 100644 index 00000000..11807cf6 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c @@ -0,0 +1,796 @@ +/*- + * Copyright (c) 2009-2011 Michihiro NAKAJIMA + * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#if HAVE_LZMA_H +#include +#endif + +#include "archive.h" +#include "archive_endian.h" +#include "archive_private.h" +#include "archive_read_private.h" + +#if HAVE_LZMA_H && HAVE_LIBLZMA + +struct private_data { + 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; + + /* Following variables are used for lzip only. */ + char lzip_ver; + uint32_t crc32; + int64_t member_in; + int64_t member_out; +}; + +#if LZMA_VERSION_MAJOR >= 5 +/* Effectively disable the limiter. */ +#define LZMA_MEMLIMIT UINT64_MAX +#else +/* NOTE: This needs to check memory size which running system has. */ +#define LZMA_MEMLIMIT (1U << 30) +#endif + +/* Combined lzip/lzma/xz filter */ +static ssize_t xz_filter_read(struct archive_read_filter *, const void **); +static int xz_filter_close(struct archive_read_filter *); +static int xz_lzma_bidder_init(struct archive_read_filter *); + +#endif + +/* + * 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. + */ +static int xz_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *); +static int xz_bidder_init(struct archive_read_filter *); +static int lzma_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *); +static int lzma_bidder_init(struct archive_read_filter *); +static int lzip_has_member(struct archive_read_filter *); +static int lzip_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *); +static int lzip_bidder_init(struct archive_read_filter *); + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Deprecated; remove in libarchive 4.0 */ +int +archive_read_support_compression_xz(struct archive *a) +{ + return archive_read_support_filter_xz(a); +} +#endif + +int +archive_read_support_filter_xz(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *bidder; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_xz"); + + if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + bidder->data = NULL; + bidder->name = "xz"; + bidder->bid = xz_bidder_bid; + bidder->init = xz_bidder_init; + bidder->options = NULL; + bidder->free = NULL; +#if HAVE_LZMA_H && HAVE_LIBLZMA + return (ARCHIVE_OK); +#else + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "Using external xz program for xz decompression"); + return (ARCHIVE_WARN); +#endif +} + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_read_support_compression_lzma(struct archive *a) +{ + return archive_read_support_filter_lzma(a); +} +#endif + +int +archive_read_support_filter_lzma(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *bidder; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma"); + + if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + bidder->data = NULL; + bidder->name = "lzma"; + bidder->bid = lzma_bidder_bid; + bidder->init = lzma_bidder_init; + bidder->options = NULL; + bidder->free = NULL; +#if HAVE_LZMA_H && HAVE_LIBLZMA + return (ARCHIVE_OK); +#else + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "Using external lzma program for lzma decompression"); + return (ARCHIVE_WARN); +#endif +} + + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_read_support_compression_lzip(struct archive *a) +{ + return archive_read_support_filter_lzip(a); +} +#endif + +int +archive_read_support_filter_lzip(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct archive_read_filter_bidder *bidder; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip"); + + if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + bidder->data = NULL; + bidder->name = "lzip"; + bidder->bid = lzip_bidder_bid; + bidder->init = lzip_bidder_init; + bidder->options = NULL; + bidder->free = NULL; +#if HAVE_LZMA_H && HAVE_LIBLZMA + return (ARCHIVE_OK); +#else + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "Using external lzip program for lzip decompression"); + return (ARCHIVE_WARN); +#endif +} + +/* + * Test whether we can handle this data. + */ +static int +xz_bidder_bid(struct archive_read_filter_bidder *self, + struct archive_read_filter *filter) +{ + const unsigned char *buffer; + ssize_t avail; + + (void)self; /* UNUSED */ + + buffer = __archive_read_filter_ahead(filter, 6, &avail); + if (buffer == NULL) + return (0); + + /* + * Verify Header Magic Bytes : FD 37 7A 58 5A 00 + */ + if (memcmp(buffer, "\xFD\x37\x7A\x58\x5A\x00", 6) != 0) + return (0); + + return (48); +} + +/* + * Test whether we can handle this data. + * + * LZMA has a rather poor file signature. Zeros do not + * make good signature bytes as a rule, and the only non-zero byte + * here is an ASCII character. For example, an uncompressed tar + * archive whose first file is ']' would satisfy this check. It may + * be necessary to exclude LZMA from compression_all() because of + * this. Clients of libarchive would then have to explicitly enable + * LZMA checking instead of (or in addition to) compression_all() when + * 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) +{ + const unsigned char *buffer; + ssize_t avail; + uint32_t dicsize; + uint64_t uncompressed_size; + int bits_checked; + + (void)self; /* UNUSED */ + + buffer = __archive_read_filter_ahead(filter, 14, &avail); + if (buffer == NULL) + return (0); + + /* First byte of raw LZMA stream is commonly 0x5d. + * The first byte is a special number, which consists of + * three parameters of LZMA compression, a number of literal + * context bits(which is from 0 to 8, default is 3), a number + * of literal pos bits(which is from 0 to 4, default is 0), + * a number of pos bits(which is from 0 to 4, default is 2). + * The first byte is made by + * (pos bits * 5 + literal pos bit) * 9 + * literal contest bit, + * and so the default value in this field is + * (2 * 5 + 0) * 9 + 3 = 0x5d. + * lzma of LZMA SDK has options to change those parameters. + * It means a range of this field is from 0 to 224. And lzma of + * XZ Utils with option -e records 0x5e in this field. */ + /* NOTE: If this checking of the first byte increases false + * recognition, we should allow only 0x5d and 0x5e for the first + * byte of LZMA stream. */ + bits_checked = 0; + if (buffer[0] > (4 * 5 + 4) * 9 + 8) + return (0); + /* Most likely value in the first byte of LZMA stream. */ + if (buffer[0] == 0x5d || buffer[0] == 0x5e) + bits_checked += 8; + + /* Sixth through fourteenth bytes are uncompressed size, + * stored in little-endian order. `-1' means uncompressed + * size is unknown and lzma of XZ Utils always records `-1' + * in this field. */ + uncompressed_size = archive_le64dec(buffer+5); + if (uncompressed_size == (uint64_t)ARCHIVE_LITERAL_LL(-1)) + bits_checked += 64; + + /* Second through fifth bytes are dictionary size, stored in + * little-endian order. The minimum dictionary size is + * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option + * -d12 and the maximum dictionary size is 1 << 27(128MiB) + * which the one uses with option -d27. + * NOTE: A comment of LZMA SDK source code says this dictionary + * range is from 1 << 12 to 1 << 30. */ + dicsize = archive_le32dec(buffer+1); + switch (dicsize) { + case 0x00001000:/* lzma of LZMA SDK option -d12. */ + case 0x00002000:/* lzma of LZMA SDK option -d13. */ + case 0x00004000:/* lzma of LZMA SDK option -d14. */ + case 0x00008000:/* lzma of LZMA SDK option -d15. */ + case 0x00010000:/* lzma of XZ Utils option -0 and -1. + * lzma of LZMA SDK option -d16. */ + case 0x00020000:/* lzma of LZMA SDK option -d17. */ + case 0x00040000:/* lzma of LZMA SDK option -d18. */ + case 0x00080000:/* lzma of XZ Utils option -2. + * lzma of LZMA SDK option -d19. */ + case 0x00100000:/* lzma of XZ Utils option -3. + * lzma of LZMA SDK option -d20. */ + case 0x00200000:/* lzma of XZ Utils option -4. + * lzma of LZMA SDK option -d21. */ + case 0x00400000:/* lzma of XZ Utils option -5. + * lzma of LZMA SDK option -d22. */ + case 0x00800000:/* lzma of XZ Utils option -6. + * lzma of LZMA SDK option -d23. */ + case 0x01000000:/* lzma of XZ Utils option -7. + * lzma of LZMA SDK option -d24. */ + case 0x02000000:/* lzma of XZ Utils option -8. + * lzma of LZMA SDK option -d25. */ + case 0x04000000:/* lzma of XZ Utils option -9. + * lzma of LZMA SDK option -d26. */ + case 0x08000000:/* lzma of LZMA SDK option -d27. */ + bits_checked += 32; + break; + default: + /* If a memory usage for encoding was not enough on + * the platform where LZMA stream was made, lzma of + * XZ Utils automatically decreased the dictionary + * size to enough memory for encoding by 1Mi bytes + * (1 << 20).*/ + if (dicsize <= 0x03F00000 && dicsize >= 0x00300000 && + (dicsize & ((1 << 20)-1)) == 0 && + bits_checked == 8 + 64) { + bits_checked += 32; + break; + } + /* Otherwise dictionary size is unlikely. But it is + * possible that someone makes lzma stream with + * liblzma/LZMA SDK in one's dictionary size. */ + return (0); + } + + /* TODO: The above test is still very weak. It would be + * good to do better. */ + + return (bits_checked); +} + +static int +lzip_has_member(struct archive_read_filter *filter) +{ + const unsigned char *buffer; + ssize_t avail; + int bits_checked; + int log2dic; + + buffer = __archive_read_filter_ahead(filter, 6, &avail); + if (buffer == NULL) + return (0); + + /* + * Verify Header Magic Bytes : 4C 5A 49 50 (`LZIP') + */ + bits_checked = 0; + if (memcmp(buffer, "LZIP", 4) != 0) + return (0); + bits_checked += 32; + + /* A version number must be 0 or 1 */ + if (buffer[4] != 0 && buffer[4] != 1) + return (0); + bits_checked += 8; + + /* Dictionary size. */ + log2dic = buffer[5] & 0x1f; + if (log2dic < 12 || log2dic > 27) + return (0); + bits_checked += 8; + + return (bits_checked); +} + +static int +lzip_bidder_bid(struct archive_read_filter_bidder *self, + struct archive_read_filter *filter) +{ + + (void)self; /* UNUSED */ + return (lzip_has_member(filter)); +} + +#if HAVE_LZMA_H && HAVE_LIBLZMA + +/* + * liblzma 4.999.7 and later support both lzma and xz streams. + */ +static int +xz_bidder_init(struct archive_read_filter *self) +{ + self->code = ARCHIVE_FILTER_XZ; + self->name = "xz"; + return (xz_lzma_bidder_init(self)); +} + +static int +lzma_bidder_init(struct archive_read_filter *self) +{ + self->code = ARCHIVE_FILTER_LZMA; + self->name = "lzma"; + return (xz_lzma_bidder_init(self)); +} + +static int +lzip_bidder_init(struct archive_read_filter *self) +{ + self->code = ARCHIVE_FILTER_LZIP; + self->name = "lzip"; + return (xz_lzma_bidder_init(self)); +} + +/* + * Set an error code and choose an error message + */ +static void +set_error(struct archive_read_filter *self, int ret) +{ + + switch (ret) { + case LZMA_STREAM_END: /* Found end of stream. */ + case LZMA_OK: /* Decompressor made some progress. */ + break; + case LZMA_MEM_ERROR: + archive_set_error(&self->archive->archive, ENOMEM, + "Lzma library error: Cannot allocate memory"); + break; + case LZMA_MEMLIMIT_ERROR: + archive_set_error(&self->archive->archive, ENOMEM, + "Lzma library error: Out of memory"); + break; + case LZMA_FORMAT_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma library error: format not recognized"); + break; + case LZMA_OPTIONS_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma library error: Invalid options"); + break; + case LZMA_DATA_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma library error: Corrupted input data"); + break; + case LZMA_BUF_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma library error: No progress is possible"); + break; + default: + /* Return an error. */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma decompression failed: Unknown error"); + break; + } +} + +/* + * Setup the callbacks. + */ +static int +xz_lzma_bidder_init(struct archive_read_filter *self) +{ + static const size_t out_block_size = 64 * 1024; + void *out_block; + struct private_data *state; + int ret; + + state = (struct private_data *)calloc(sizeof(*state), 1); + out_block = (unsigned char *)malloc(out_block_size); + if (state == NULL || out_block == NULL) { + archive_set_error(&self->archive->archive, ENOMEM, + "Can't allocate data for xz decompression"); + free(out_block); + free(state); + return (ARCHIVE_FATAL); + } + + self->data = state; + state->out_block_size = out_block_size; + state->out_block = out_block; + self->read = xz_filter_read; + self->skip = NULL; /* not supported */ + self->close = xz_filter_close; + + state->stream.avail_in = 0; + + state->stream.next_out = state->out_block; + state->stream.avail_out = state->out_block_size; + + state->crc32 = 0; + if (self->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; + return (ARCHIVE_OK); + } else + state->in_stream = 1; + + /* Initialize compression library. */ + if (self->code == ARCHIVE_FILTER_XZ) + ret = lzma_stream_decoder(&(state->stream), + LZMA_MEMLIMIT,/* memlimit */ + LZMA_CONCATENATED); + else + ret = lzma_alone_decoder(&(state->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); + + free(state->out_block); + free(state); + self->data = NULL; + return (ARCHIVE_FATAL); +} + +static int +lzip_init(struct archive_read_filter *self) +{ + struct private_data *state; + 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); + if (h == NULL) + return (ARCHIVE_FATAL); + + /* Get a version number. */ + state->lzip_ver = h[4]; + + /* + * Setup lzma property. + */ + props[0] = 0x5d; + + /* Get dictionary size. */ + log2dic = h[5] & 0x1f; + if (log2dic < 12 || log2dic > 27) + return (ARCHIVE_FATAL); + dicsize = 1U << log2dic; + if (log2dic > 12) + dicsize -= (dicsize / 16) * (h[5] >> 5); + archive_le32enc(props+1, dicsize); + + /* Consume lzip header. */ + __archive_read_filter_consume(self->upstream, 6); + state->member_in = 6; + + filters[0].id = LZMA_FILTER_LZMA1; + filters[0].options = NULL; + filters[1].id = LZMA_VLI_UNKNOWN; + filters[1].options = NULL; + + ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props)); + if (ret != LZMA_OK) { + set_error(self, ret); + return (ARCHIVE_FATAL); + } + ret = lzma_raw_decoder(&(state->stream), filters); + free(filters[0].options); + if (ret != LZMA_OK) { + set_error(self, ret); + return (ARCHIVE_FATAL); + } + return (ARCHIVE_OK); +} + +static int +lzip_tail(struct archive_read_filter *self) +{ + struct private_data *state; + const unsigned char *f; + ssize_t avail_in; + int tail; + + state = (struct private_data *)self->data; + if (state->lzip_ver == 0) + tail = 12; + else + tail = 20; + f = __archive_read_filter_ahead(self->upstream, tail, &avail_in); + if (f == NULL && avail_in < 0) + return (ARCHIVE_FATAL); + if (f == NULL || avail_in < tail) { + archive_set_error(&self->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)) { + archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, + "Lzip: CRC32 error"); + return (ARCHIVE_FAILED); + } + + /* 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, + "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, + "Lzip: Member size error"); + return (ARCHIVE_FAILED); + } + __archive_read_filter_consume(self->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; + } + return (ARCHIVE_OK); +} + +/* + * Return the next block of decompressed data. + */ +static ssize_t +xz_filter_read(struct archive_read_filter *self, const void **p) +{ + struct private_data *state; + size_t decompressed; + ssize_t avail_in; + int ret; + + state = (struct private_data *)self->data; + + /* Empty our output buffer. */ + state->stream.next_out = state->out_block; + state->stream.avail_out = state->out_block_size; + + /* Try to fill the output buffer. */ + while (state->stream.avail_out > 0 && !state->eof) { + if (!state->in_stream) { + /* + * Initialize liblzma for lzip + */ + ret = lzip_init(self); + if (ret != ARCHIVE_OK) + return (ret); + state->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, + ARCHIVE_ERRNO_MISC, + "truncated input"); + return (ARCHIVE_FATAL); + } + state->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); + switch (ret) { + case LZMA_STREAM_END: /* Found end of stream. */ + state->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; + break; + default: + set_error(self, ret); + return (ARCHIVE_FATAL); + } + } + + decompressed = state->stream.next_out - state->out_block; + state->total_out += decompressed; + state->member_out += decompressed; + if (decompressed == 0) + *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); + if (ret != ARCHIVE_OK) + return (ret); + } + } + } + return (decompressed); +} + +/* + * Clean up the decompressor. + */ +static int +xz_filter_close(struct archive_read_filter *self) +{ + struct private_data *state; + + state = (struct private_data *)self->data; + lzma_end(&(state->stream)); + free(state->out_block); + free(state); + return (ARCHIVE_OK); +} + +#else + +/* + * + * If we have no suitable library on this system, we can't actually do + * the decompression. We can, however, still detect compressed + * archives and emit a useful message. + * + */ +static int +lzma_bidder_init(struct archive_read_filter *self) +{ + int r; + + r = __archive_read_program(self, "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"; + return (r); +} + +static int +xz_bidder_init(struct archive_read_filter *self) +{ + int r; + + r = __archive_read_program(self, "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"; + return (r); +} + +static int +lzip_bidder_init(struct archive_read_filter *self) +{ + int r; + + r = __archive_read_program(self, "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"; + return (r); +} + +#endif /* HAVE_LZMA_H */ diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c b/src/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c new file mode 100644 index 00000000..084563f4 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_format_by_code.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2003-2011 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive.h" +#include "archive_private.h" + +int +archive_read_support_format_by_code(struct archive *a, int format_code) +{ + archive_check_magic(a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_by_code"); + + switch (format_code & ARCHIVE_FORMAT_BASE_MASK) { + case ARCHIVE_FORMAT_7ZIP: + return archive_read_support_format_7zip(a); + break; + case ARCHIVE_FORMAT_AR: + return archive_read_support_format_ar(a); + break; + case ARCHIVE_FORMAT_CAB: + return archive_read_support_format_cab(a); + break; + case ARCHIVE_FORMAT_CPIO: + return archive_read_support_format_cpio(a); + break; + case ARCHIVE_FORMAT_ISO9660: + return archive_read_support_format_iso9660(a); + break; + case ARCHIVE_FORMAT_LHA: + return archive_read_support_format_lha(a); + break; + case ARCHIVE_FORMAT_MTREE: + return archive_read_support_format_mtree(a); + break; + case ARCHIVE_FORMAT_RAR: + return archive_read_support_format_rar(a); + break; + case ARCHIVE_FORMAT_TAR: + return archive_read_support_format_tar(a); + break; + case ARCHIVE_FORMAT_XAR: + return archive_read_support_format_xar(a); + break; + case ARCHIVE_FORMAT_ZIP: + return archive_read_support_format_zip(a); + break; + } + return (ARCHIVE_FATAL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c b/src/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c new file mode 100644 index 00000000..c641eb9b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_empty.c 191524 2009-04-26 18:24:14Z kientzle $"); + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_private.h" + +static int archive_read_format_empty_bid(struct archive_read *, int); +static int archive_read_format_empty_read_data(struct archive_read *, + const void **, size_t *, int64_t *); +static int archive_read_format_empty_read_header(struct archive_read *, + struct archive_entry *); +int +archive_read_support_format_empty(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + int r; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_empty"); + + r = __archive_read_register_format(a, + NULL, + NULL, + archive_read_format_empty_bid, + NULL, + archive_read_format_empty_read_header, + archive_read_format_empty_read_data, + NULL, + NULL, + NULL, + NULL, + NULL); + + return (r); +} + + +static int +archive_read_format_empty_bid(struct archive_read *a, int best_bid) +{ + if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) == NULL) + return (1); + return (-1); +} + +static int +archive_read_format_empty_read_header(struct archive_read *a, + struct archive_entry *entry) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + + a->archive.archive_format = ARCHIVE_FORMAT_EMPTY; + a->archive.archive_format_name = "Empty file"; + + return (ARCHIVE_EOF); +} + +static int +archive_read_format_empty_read_data(struct archive_read *a, + const void **buff, size_t *size, int64_t *offset) +{ + (void)a; /* UNUSED */ + (void)buff; /* UNUSED */ + (void)size; /* UNUSED */ + (void)offset; /* UNUSED */ + + return (ARCHIVE_EOF); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c b/src/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c new file mode 100644 index 00000000..30d5bc83 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c @@ -0,0 +1,2883 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_tar.c 201161 2009-12-29 05:44:39Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_acl_private.h" /* For ACL parsing routines. */ +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_read_private.h" + +#define tar_min(a,b) ((a) < (b) ? (a) : (b)) + +/* + * Layout of POSIX 'ustar' tar header. + */ +struct archive_entry_header_ustar { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char typeflag[1]; + char linkname[100]; /* "old format" header ends here */ + char magic[6]; /* For POSIX: "ustar\0" */ + char version[2]; /* For POSIX: "00" */ + char uname[32]; + char gname[32]; + char rdevmajor[8]; + char rdevminor[8]; + char prefix[155]; +}; + +/* + * Structure of GNU tar header + */ +struct gnu_sparse { + char offset[12]; + char numbytes[12]; +}; + +struct archive_entry_header_gnutar { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char typeflag[1]; + char linkname[100]; + char magic[8]; /* "ustar \0" (note blank/blank/null at end) */ + char uname[32]; + char gname[32]; + char rdevmajor[8]; + char rdevminor[8]; + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; + char unused[1]; + struct gnu_sparse sparse[4]; + char isextended[1]; + char realsize[12]; + /* + * Old GNU format doesn't use POSIX 'prefix' field; they use + * the 'L' (longname) entry instead. + */ +}; + +/* + * Data specific to this format. + */ +struct sparse_block { + struct sparse_block *next; + int64_t offset; + int64_t remaining; + int hole; +}; + +struct tar { + struct archive_string acl_text; + struct archive_string entry_pathname; + /* For "GNU.sparse.name" and other similar path extensions. */ + struct archive_string entry_pathname_override; + struct archive_string entry_linkpath; + struct archive_string entry_uname; + struct archive_string entry_gname; + struct archive_string longlink; + struct archive_string longname; + struct archive_string pax_header; + struct archive_string pax_global; + struct archive_string line; + int pax_hdrcharset_binary; + int header_recursion_depth; + int64_t entry_bytes_remaining; + int64_t entry_offset; + int64_t entry_padding; + int64_t entry_bytes_unconsumed; + int64_t realsize; + int sparse_allowed; + struct sparse_block *sparse_list; + struct sparse_block *sparse_last; + int64_t sparse_offset; + int64_t sparse_numbytes; + int sparse_gnu_major; + int sparse_gnu_minor; + char sparse_gnu_pending; + + struct archive_string localname; + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv; + struct archive_string_conv *sconv_acl; + struct archive_string_conv *sconv_default; + int init_default_conversion; + int compat_2x; + int process_mac_extensions; + int read_concatenated_archives; + int realsize_override; +}; + +static int archive_block_is_null(const char *p); +static char *base64_decode(const char *, size_t, size_t *); +static int gnu_add_sparse_entry(struct archive_read *, struct tar *, + int64_t offset, int64_t remaining); + +static void gnu_clear_sparse_list(struct tar *); +static int gnu_sparse_old_read(struct archive_read *, struct tar *, + const struct archive_entry_header_gnutar *header, size_t *); +static int gnu_sparse_old_parse(struct archive_read *, struct tar *, + const struct gnu_sparse *sparse, int length); +static int gnu_sparse_01_parse(struct archive_read *, struct tar *, + const char *); +static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *, + size_t *); +static int header_Solaris_ACL(struct archive_read *, struct tar *, + struct archive_entry *, const void *, size_t *); +static int header_common(struct archive_read *, struct tar *, + struct archive_entry *, const void *); +static int header_old_tar(struct archive_read *, struct tar *, + struct archive_entry *, const void *); +static int header_pax_extensions(struct archive_read *, struct tar *, + struct archive_entry *, const void *, size_t *); +static int header_pax_global(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int header_longlink(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int header_longname(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int read_mac_metadata_blob(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int header_volume(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int header_ustar(struct archive_read *, struct tar *, + struct archive_entry *, const void *h); +static int header_gnutar(struct archive_read *, struct tar *, + struct archive_entry *, const void *h, size_t *); +static int archive_read_format_tar_bid(struct archive_read *, int); +static int archive_read_format_tar_options(struct archive_read *, + const char *, const char *); +static int archive_read_format_tar_cleanup(struct archive_read *); +static int archive_read_format_tar_read_data(struct archive_read *a, + const void **buff, size_t *size, int64_t *offset); +static int archive_read_format_tar_skip(struct archive_read *a); +static int archive_read_format_tar_read_header(struct archive_read *, + struct archive_entry *); +static int checksum(struct archive_read *, const void *); +static int pax_attribute(struct archive_read *, struct tar *, + struct archive_entry *, const char *key, const char *value, + size_t value_length); +static int pax_attribute_acl(struct archive_read *, struct tar *, + struct archive_entry *, const char *, int); +static int pax_attribute_xattr(struct archive_entry *, const char *, + const char *); +static int pax_header(struct archive_read *, struct tar *, + struct archive_entry *, struct archive_string *); +static void pax_time(const char *, int64_t *sec, long *nanos); +static ssize_t readline(struct archive_read *, struct tar *, const char **, + ssize_t limit, size_t *); +static int read_body_to_string(struct archive_read *, struct tar *, + struct archive_string *, const void *h, size_t *); +static int solaris_sparse_parse(struct archive_read *, struct tar *, + struct archive_entry *, const char *); +static int64_t tar_atol(const char *, size_t); +static int64_t tar_atol10(const char *, size_t); +static int64_t tar_atol256(const char *, size_t); +static int64_t tar_atol8(const char *, size_t); +static int tar_read_header(struct archive_read *, struct tar *, + struct archive_entry *, size_t *); +static int tohex(int c); +static char *url_decode(const char *); +static void tar_flush_unconsumed(struct archive_read *, size_t *); + + +int +archive_read_support_format_gnutar(struct archive *a) +{ + archive_check_magic(a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_gnutar"); + return (archive_read_support_format_tar(a)); +} + + +int +archive_read_support_format_tar(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct tar *tar; + int r; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_tar"); + + tar = (struct tar *)calloc(1, sizeof(*tar)); +#ifdef HAVE_COPYFILE_H + /* Set this by default on Mac OS. */ + tar->process_mac_extensions = 1; +#endif + if (tar == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate tar data"); + return (ARCHIVE_FATAL); + } + + r = __archive_read_register_format(a, tar, "tar", + archive_read_format_tar_bid, + archive_read_format_tar_options, + archive_read_format_tar_read_header, + archive_read_format_tar_read_data, + archive_read_format_tar_skip, + NULL, + archive_read_format_tar_cleanup, + NULL, + NULL); + + if (r != ARCHIVE_OK) + free(tar); + return (ARCHIVE_OK); +} + +static int +archive_read_format_tar_cleanup(struct archive_read *a) +{ + struct tar *tar; + + tar = (struct tar *)(a->format->data); + gnu_clear_sparse_list(tar); + archive_string_free(&tar->acl_text); + archive_string_free(&tar->entry_pathname); + archive_string_free(&tar->entry_pathname_override); + archive_string_free(&tar->entry_linkpath); + archive_string_free(&tar->entry_uname); + archive_string_free(&tar->entry_gname); + archive_string_free(&tar->line); + archive_string_free(&tar->pax_global); + archive_string_free(&tar->pax_header); + archive_string_free(&tar->longname); + archive_string_free(&tar->longlink); + archive_string_free(&tar->localname); + free(tar); + (a->format->data) = NULL; + return (ARCHIVE_OK); +} + +/* + * Validate number field + * + * This has to be pretty lenient in order to accommodate the enormous + * variety of tar writers in the world: + * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading + * zeros and allows fields to be terminated with space or null characters + * = Many writers use different termination (in particular, libarchive + * omits terminator bytes to squeeze one or two more digits) + * = Many writers pad with space and omit leading zeros + * = GNU tar and star write base-256 values if numbers are too + * big to be represented in octal + * + * Examples of specific tar headers that we should support: + * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two + * null bytes, pads size with spaces and other numeric fields with zeroes + * = plexus-archiver prior to 2.6.3 (before switching to commons-compress) + * may have uid and gid fields filled with spaces without any octal digits + * at all and pads all numeric fields with spaces + * + * This should tolerate all variants in use. It will reject a field + * where the writer just left garbage after a trailing NUL. + */ +static int +validate_number_field(const char* p_field, size_t i_size) +{ + unsigned char marker = (unsigned char)p_field[0]; + if (marker == 128 || marker == 255 || marker == 0) { + /* Base-256 marker, there's nothing we can check. */ + return 1; + } else { + /* Must be octal */ + size_t i = 0; + /* Skip any leading spaces */ + while (i < i_size && p_field[i] == ' ') { + ++i; + } + /* Skip octal digits. */ + while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') { + ++i; + } + /* Any remaining characters must be space or NUL padding. */ + while (i < i_size) { + if (p_field[i] != ' ' && p_field[i] != 0) { + return 0; + } + ++i; + } + return 1; + } +} + +static int +archive_read_format_tar_bid(struct archive_read *a, int best_bid) +{ + int bid; + const char *h; + const struct archive_entry_header_ustar *header; + + (void)best_bid; /* UNUSED */ + + bid = 0; + + /* Now let's look at the actual header and see if it matches. */ + h = __archive_read_ahead(a, 512, NULL); + if (h == NULL) + return (-1); + + /* If it's an end-of-archive mark, we can handle it. */ + if (h[0] == 0 && archive_block_is_null(h)) { + /* + * Usually, I bid the number of bits verified, but + * in this case, 4096 seems excessive so I picked 10 as + * an arbitrary but reasonable-seeming value. + */ + return (10); + } + + /* If it's not an end-of-archive mark, it must have a valid checksum.*/ + if (!checksum(a, h)) + return (0); + bid += 48; /* Checksum is usually 6 octal digits. */ + + header = (const struct archive_entry_header_ustar *)h; + + /* Recognize POSIX formats. */ + if ((memcmp(header->magic, "ustar\0", 6) == 0) + && (memcmp(header->version, "00", 2) == 0)) + bid += 56; + + /* Recognize GNU tar format. */ + if ((memcmp(header->magic, "ustar ", 6) == 0) + && (memcmp(header->version, " \0", 2) == 0)) + bid += 56; + + /* Type flag must be null, digit or A-Z, a-z. */ + if (header->typeflag[0] != 0 && + !( header->typeflag[0] >= '0' && header->typeflag[0] <= '9') && + !( header->typeflag[0] >= 'A' && header->typeflag[0] <= 'Z') && + !( header->typeflag[0] >= 'a' && header->typeflag[0] <= 'z') ) + return (0); + bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */ + + /* + * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields. + */ + if (bid > 0 && ( + validate_number_field(header->mode, sizeof(header->mode)) == 0 + || validate_number_field(header->uid, sizeof(header->uid)) == 0 + || validate_number_field(header->gid, sizeof(header->gid)) == 0 + || validate_number_field(header->mtime, sizeof(header->mtime)) == 0 + || validate_number_field(header->size, sizeof(header->size)) == 0 + || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 + || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) { + bid = 0; + } + + return (bid); +} + +static int +archive_read_format_tar_options(struct archive_read *a, + const char *key, const char *val) +{ + struct tar *tar; + 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); + tar->init_default_conversion = tar->compat_2x; + return (ARCHIVE_OK); + } else if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "tar: hdrcharset option needs a character-set name"); + else { + tar->opt_sconv = + archive_string_conversion_from_charset( + &a->archive, val, 0); + if (tar->opt_sconv != NULL) + ret = ARCHIVE_OK; + else + ret = ARCHIVE_FATAL; + } + return (ret); + } else if (strcmp(key, "mac-ext") == 0) { + tar->process_mac_extensions = (val != NULL && val[0] != 0); + return (ARCHIVE_OK); + } else if (strcmp(key, "read_concatenated_archives") == 0) { + tar->read_concatenated_archives = (val != NULL && val[0] != 0); + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +/* utility function- this exists to centralize the logic of tracking + * how much unconsumed data we have floating around, and to consume + * anything outstanding since we're going to do read_aheads + */ +static void +tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed) +{ + if (*unconsumed) { +/* + void *data = (void *)__archive_read_ahead(a, *unconsumed, NULL); + * this block of code is to poison claimed unconsumed space, ensuring + * things break if it is in use still. + * currently it WILL break things, so enable it only for debugging this issue + if (data) { + memset(data, 0xff, *unconsumed); + } +*/ + __archive_read_consume(a, *unconsumed); + *unconsumed = 0; + } +} + +/* + * The function invoked by archive_read_next_header(). This + * just sets up a few things and then calls the internal + * tar_read_header() function below. + */ +static int +archive_read_format_tar_read_header(struct archive_read *a, + struct archive_entry *entry) +{ + /* + * When converting tar archives to cpio archives, it is + * essential that each distinct file have a distinct inode + * number. To simplify this, we keep a static count here to + * assign fake dev/inode numbers to each tar entry. Note that + * pax format archives may overwrite this with something more + * useful. + * + * Ideally, we would track every file read from the archive so + * that we could assign the same dev/ino pair to hardlinks, + * but the memory required to store a complete lookup table is + * probably not worthwhile just to support the relatively + * obscure tar->cpio conversion case. + */ + static int default_inode; + static int default_dev; + struct tar *tar; + const char *p; + const wchar_t *wp; + int r; + size_t l, 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. */ + /* Limit generated st_ino number to 16 bits. */ + if (default_inode >= 0xffff) { + ++default_dev; + default_inode = 0; + } + + tar = (struct tar *)(a->format->data); + tar->entry_offset = 0; + gnu_clear_sparse_list(tar); + tar->realsize = -1; /* Mark this as "unset" */ + tar->realsize_override = 0; + + /* Setup default string conversion. */ + tar->sconv = tar->opt_sconv; + if (tar->sconv == NULL) { + if (!tar->init_default_conversion) { + tar->sconv_default = + archive_string_default_conversion_for_read(&(a->archive)); + tar->init_default_conversion = 1; + } + tar->sconv = tar->sconv_default; + } + + r = tar_read_header(a, tar, entry, &unconsumed); + + tar_flush_unconsumed(a, &unconsumed); + + /* + * "non-sparse" files are really just sparse files with + * a single block. + */ + if (tar->sparse_list == NULL) { + if (gnu_add_sparse_entry(a, tar, 0, tar->entry_bytes_remaining) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + struct sparse_block *sb; + + for (sb = tar->sparse_list; sb != NULL; sb = sb->next) { + if (!sb->hole) + archive_entry_sparse_add_entry(entry, + sb->offset, sb->remaining); + } + } + + if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) { + /* + * "Regular" entry with trailing '/' is really + * directory: This is needed for certain old tar + * variants and even for some broken newer ones. + */ + 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); + } + } else if ((p = archive_entry_pathname(entry)) != NULL) { + l = strlen(p); + if (l > 0 && p[l - 1] == '/') { + archive_entry_set_filetype(entry, AE_IFDIR); + } + } + } + return (r); +} + +static int +archive_read_format_tar_read_data(struct archive_read *a, + const void **buff, size_t *size, int64_t *offset) +{ + 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 && + tar->sparse_list->remaining == 0) { + p = tar->sparse_list; + tar->sparse_list = p->next; + free(p); + } + + if (tar->entry_bytes_unconsumed) { + __archive_read_consume(a, tar->entry_bytes_unconsumed); + tar->entry_bytes_unconsumed = 0; + } + + /* If we're at end of file, return EOF. */ + if (tar->sparse_list == NULL || + tar->entry_bytes_remaining == 0) { + if (__archive_read_consume(a, tar->entry_padding) < 0) + return (ARCHIVE_FATAL); + tar->entry_padding = 0; + *buff = NULL; + *size = 0; + *offset = tar->realsize; + return (ARCHIVE_EOF); + } + + *buff = __archive_read_ahead(a, 1, &bytes_read); + if (bytes_read < 0) + return (ARCHIVE_FATAL); + if (*buff == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Truncated tar archive"); + return (ARCHIVE_FATAL); + } + if (bytes_read > tar->entry_bytes_remaining) + bytes_read = (ssize_t)tar->entry_bytes_remaining; + /* Don't read more than is available in the + * current sparse block. */ + if (tar->sparse_list->remaining < bytes_read) + bytes_read = (ssize_t)tar->sparse_list->remaining; + *size = bytes_read; + *offset = tar->sparse_list->offset; + tar->sparse_list->remaining -= bytes_read; + tar->sparse_list->offset += bytes_read; + tar->entry_bytes_remaining -= bytes_read; + tar->entry_bytes_unconsumed = bytes_read; + + if (!tar->sparse_list->hole) + return (ARCHIVE_OK); + /* Current is hole data and skip this. */ + } +} + +static int +archive_read_format_tar_skip(struct archive_read *a) +{ + int64_t bytes_skipped; + int64_t request; + struct sparse_block *p; + struct tar* tar; + + tar = (struct tar *)(a->format->data); + + /* Do not consume the hole of a sparse file. */ + request = 0; + for (p = tar->sparse_list; p != NULL; p = p->next) { + if (!p->hole) { + if (p->remaining >= INT64_MAX - request) { + return ARCHIVE_FATAL; + } + request += p->remaining; + } + } + if (request > tar->entry_bytes_remaining) + request = tar->entry_bytes_remaining; + request += tar->entry_padding + tar->entry_bytes_unconsumed; + + bytes_skipped = __archive_read_consume(a, request); + if (bytes_skipped < 0) + return (ARCHIVE_FATAL); + + tar->entry_bytes_remaining = 0; + tar->entry_bytes_unconsumed = 0; + tar->entry_padding = 0; + + /* Free the sparse list. */ + gnu_clear_sparse_list(tar); + + return (ARCHIVE_OK); +} + +/* + * This function recursively interprets all of the headers associated + * with a single entry. + */ +static int +tar_read_header(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, size_t *unconsumed) +{ + ssize_t bytes; + int err; + const char *h; + const struct archive_entry_header_ustar *header; + const struct archive_entry_header_gnutar *gnuheader; + + /* Loop until we find a workable header record. */ + for (;;) { + tar_flush_unconsumed(a, unconsumed); + + /* Read 512-byte header record */ + h = __archive_read_ahead(a, 512, &bytes); + if (bytes < 0) + return ((int)bytes); + if (bytes == 0) { /* EOF at a block boundary. */ + /* Some writers do omit the block of nulls. */ + return (ARCHIVE_EOF); + } + if (bytes < 512) { /* Short block at EOF; this is bad. */ + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated tar archive"); + return (ARCHIVE_FATAL); + } + *unconsumed = 512; + + /* Header is workable if it's not an end-of-archive mark. */ + if (h[0] != 0 || !archive_block_is_null(h)) + break; + + /* Ensure format is set for archives with only null blocks. */ + if (a->archive.archive_format_name == NULL) { + a->archive.archive_format = ARCHIVE_FORMAT_TAR; + a->archive.archive_format_name = "tar"; + } + + if (!tar->read_concatenated_archives) { + /* Try to consume a second all-null record, as well. */ + tar_flush_unconsumed(a, unconsumed); + h = __archive_read_ahead(a, 512, NULL); + if (h != NULL && h[0] == 0 && archive_block_is_null(h)) + __archive_read_consume(a, 512); + archive_clear_error(&a->archive); + return (ARCHIVE_EOF); + } + + /* + * We're reading concatenated archives, ignore this block and + * loop to get the next. + */ + } + + /* + * Note: If the checksum fails and we return ARCHIVE_RETRY, + * then the client is likely to just retry. This is a very + * crude way to search for the next valid header! + * + * TODO: Improve this by implementing a real header scan. + */ + if (!checksum(a, h)) { + tar_flush_unconsumed(a, unconsumed); + archive_set_error(&a->archive, EINVAL, "Damaged tar archive"); + return (ARCHIVE_RETRY); /* Retryable: Invalid header */ + } + + if (++tar->header_recursion_depth > 32) { + tar_flush_unconsumed(a, unconsumed); + archive_set_error(&a->archive, EINVAL, "Too many special headers"); + return (ARCHIVE_WARN); + } + + /* Determine the format variant. */ + header = (const struct archive_entry_header_ustar *)h; + + switch(header->typeflag[0]) { + case 'A': /* Solaris tar ACL */ + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; + a->archive.archive_format_name = "Solaris tar"; + err = header_Solaris_ACL(a, tar, entry, h, unconsumed); + break; + case 'g': /* POSIX-standard 'g' header. */ + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; + a->archive.archive_format_name = "POSIX pax interchange format"; + err = header_pax_global(a, tar, entry, h, unconsumed); + if (err == ARCHIVE_EOF) + return (err); + break; + case 'K': /* Long link name (GNU tar, others) */ + err = header_longlink(a, tar, entry, h, unconsumed); + break; + case 'L': /* Long filename (GNU tar, others) */ + err = header_longname(a, tar, entry, h, unconsumed); + break; + case 'V': /* GNU volume header */ + err = header_volume(a, tar, entry, h, unconsumed); + break; + case 'X': /* Used by SUN tar; same as 'x'. */ + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; + a->archive.archive_format_name = + "POSIX pax interchange format (Sun variant)"; + err = header_pax_extensions(a, tar, entry, h, unconsumed); + break; + case 'x': /* POSIX-standard 'x' header. */ + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; + a->archive.archive_format_name = "POSIX pax interchange format"; + err = header_pax_extensions(a, tar, entry, h, unconsumed); + break; + default: + gnuheader = (const struct archive_entry_header_gnutar *)h; + if (memcmp(gnuheader->magic, "ustar \0", 8) == 0) { + a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; + a->archive.archive_format_name = "GNU tar format"; + err = header_gnutar(a, tar, entry, h, unconsumed); + } else if (memcmp(header->magic, "ustar", 5) == 0) { + if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) { + a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; + a->archive.archive_format_name = "POSIX ustar format"; + } + err = header_ustar(a, tar, entry, h); + } else { + a->archive.archive_format = ARCHIVE_FORMAT_TAR; + a->archive.archive_format_name = "tar (non-POSIX)"; + err = header_old_tar(a, tar, entry, h); + } + } + if (err == ARCHIVE_FATAL) + return (err); + + tar_flush_unconsumed(a, unconsumed); + + h = NULL; + header = NULL; + + --tar->header_recursion_depth; + /* Yuck. Apple's design here ends up storing long pathname + * extensions for both the AppleDouble extension entry and the + * regular entry. + */ + if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) && + tar->header_recursion_depth == 0 && + tar->process_mac_extensions) { + int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed); + if (err2 < err) + err = err2; + } + + /* We return warnings or success as-is. Anything else is fatal. */ + if (err == ARCHIVE_WARN || err == ARCHIVE_OK) { + if (tar->sparse_gnu_pending) { + if (tar->sparse_gnu_major == 1 && + tar->sparse_gnu_minor == 0) { + ssize_t bytes_read; + + tar->sparse_gnu_pending = 0; + /* Read initial sparse map. */ + bytes_read = gnu_sparse_10_read(a, tar, unconsumed); + if (bytes_read < 0) + return ((int)bytes_read); + tar->entry_bytes_remaining -= bytes_read; + } else { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Unrecognized GNU sparse file format"); + return (ARCHIVE_WARN); + } + tar->sparse_gnu_pending = 0; + } + return (err); + } + if (err == ARCHIVE_EOF) + /* EOF when recursively reading a header is bad. */ + archive_set_error(&a->archive, EINVAL, "Damaged tar archive"); + return (ARCHIVE_FATAL); +} + +/* + * Return true if block checksum is correct. + */ +static int +checksum(struct archive_read *a, const void *h) +{ + const unsigned char *bytes; + const struct archive_entry_header_ustar *header; + int check, sum; + size_t i; + + (void)a; /* UNUSED */ + bytes = (const unsigned char *)h; + header = (const struct archive_entry_header_ustar *)h; + + /* Checksum field must hold an octal number */ + for (i = 0; i < sizeof(header->checksum); ++i) { + char c = header->checksum[i]; + if (c != ' ' && c != '\0' && (c < '0' || c > '7')) + return 0; + } + + /* + * Test the checksum. Note that POSIX specifies _unsigned_ + * bytes for this calculation. + */ + sum = (int)tar_atol(header->checksum, sizeof(header->checksum)); + check = 0; + for (i = 0; i < 148; i++) + check += (unsigned char)bytes[i]; + for (; i < 156; i++) + check += 32; + for (; i < 512; i++) + check += (unsigned char)bytes[i]; + if (sum == check) + return (1); + + /* + * Repeat test with _signed_ bytes, just in case this archive + * was created by an old BSD, Solaris, or HP-UX tar with a + * broken checksum calculation. + */ + check = 0; + for (i = 0; i < 148; i++) + check += (signed char)bytes[i]; + for (; i < 156; i++) + check += 32; + for (; i < 512; i++) + check += (signed char)bytes[i]; + if (sum == check) + return (1); + + return (0); +} + +/* + * Return true if this block contains only nulls. + */ +static int +archive_block_is_null(const char *p) +{ + unsigned i; + + for (i = 0; i < 512; i++) + if (*p++) + return (0); + return (1); +} + +/* + * Interpret 'A' Solaris ACL header + */ +static int +header_Solaris_ACL(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + const struct archive_entry_header_ustar *header; + size_t size; + int err, acl_type; + int64_t type; + char *acl, *p; + + /* + * read_body_to_string adds a NUL terminator, but we need a little + * more to make sure that we don't overrun acl_text later. + */ + header = (const struct archive_entry_header_ustar *)h; + size = (size_t)tar_atol(header->size, sizeof(header->size)); + err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed); + if (err != ARCHIVE_OK) + return (err); + + /* Recursively read next header */ + err = tar_read_header(a, tar, entry, unconsumed); + if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) + return (err); + + /* TODO: Examine the first characters to see if this + * is an AIX ACL descriptor. We'll likely never support + * them, but it would be polite to recognize and warn when + * we do see them. */ + + /* Leading octal number indicates ACL type and number of entries. */ + p = acl = tar->acl_text.s; + type = 0; + while (*p != '\0' && p < acl + size) { + if (*p < '0' || *p > '7') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Malformed Solaris ACL attribute (invalid digit)"); + return(ARCHIVE_WARN); + } + type <<= 3; + type += *p - '0'; + if (type > 077777777) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Malformed Solaris ACL attribute (count too large)"); + return (ARCHIVE_WARN); + } + p++; + } + switch ((int)type & ~0777777) { + case 01000000: + /* POSIX.1e ACL */ + acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + break; + case 03000000: + /* NFSv4 ACL */ + acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4; + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Malformed Solaris ACL attribute (unsupported type %o)", + (int)type); + return (ARCHIVE_WARN); + } + p++; + + if (p >= acl + size) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Malformed Solaris ACL attribute (body overflow)"); + return(ARCHIVE_WARN); + } + + /* ACL text is null-terminated; find the end. */ + size -= (p - acl); + acl = p; + + while (*p != '\0' && p < acl + size) + p++; + + if (tar->sconv_acl == NULL) { + tar->sconv_acl = archive_string_conversion_from_charset( + &(a->archive), "UTF-8", 1); + if (tar->sconv_acl == NULL) + return (ARCHIVE_FATAL); + } + archive_strncpy(&(tar->localname), acl, p - acl); + err = archive_acl_from_text_l(archive_entry_acl(entry), + tar->localname.s, acl_type, tar->sconv_acl); + if (err != ARCHIVE_OK) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for ACL"); + } else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Malformed Solaris ACL attribute (unparsable)"); + } + return (err); +} + +/* + * Interpret 'K' long linkname header. + */ +static int +header_longlink(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + int err; + + err = read_body_to_string(a, tar, &(tar->longlink), h, unconsumed); + if (err != ARCHIVE_OK) + return (err); + err = tar_read_header(a, tar, entry, unconsumed); + if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) + return (err); + /* Set symlink if symlink already set, else hardlink. */ + archive_entry_copy_link(entry, tar->longlink.s); + return (ARCHIVE_OK); +} + +static int +set_conversion_failed_error(struct archive_read *a, + struct archive_string_conv *sconv, const char *name) +{ + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for %s", name); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "%s can't be converted from %s to current locale.", + name, archive_string_conversion_charset_name(sconv)); + return (ARCHIVE_WARN); +} + +/* + * Interpret 'L' long filename header. + */ +static int +header_longname(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + int err; + + err = read_body_to_string(a, tar, &(tar->longname), h, unconsumed); + if (err != ARCHIVE_OK) + return (err); + /* Read and parse "real" header, then override name. */ + err = tar_read_header(a, tar, entry, unconsumed); + if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) + return (err); + if (archive_entry_copy_pathname_l(entry, tar->longname.s, + archive_strlen(&(tar->longname)), tar->sconv) != 0) + err = set_conversion_failed_error(a, tar->sconv, "Pathname"); + return (err); +} + + +/* + * Interpret 'V' GNU tar volume header. + */ +static int +header_volume(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + (void)h; + + /* Just skip this and read the next header. */ + return (tar_read_header(a, tar, entry, unconsumed)); +} + +/* + * Read body of an archive entry into an archive_string object. + */ +static int +read_body_to_string(struct archive_read *a, struct tar *tar, + struct archive_string *as, const void *h, size_t *unconsumed) +{ + int64_t size; + const struct archive_entry_header_ustar *header; + const void *src; + + (void)tar; /* UNUSED */ + header = (const struct archive_entry_header_ustar *)h; + size = tar_atol(header->size, sizeof(header->size)); + if ((size > 1048576) || (size < 0)) { + archive_set_error(&a->archive, EINVAL, + "Special header too large"); + return (ARCHIVE_FATAL); + } + + /* Fail if we can't make our buffer big enough. */ + if (archive_string_ensure(as, (size_t)size+1) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "No memory"); + return (ARCHIVE_FATAL); + } + + tar_flush_unconsumed(a, unconsumed); + + /* Read the body into the string. */ + *unconsumed = (size_t)((size + 511) & ~ 511); + src = __archive_read_ahead(a, *unconsumed, NULL); + if (src == NULL) { + *unconsumed = 0; + return (ARCHIVE_FATAL); + } + memcpy(as->s, src, (size_t)size); + as->s[size] = '\0'; + as->length = (size_t)size; + return (ARCHIVE_OK); +} + +/* + * Parse out common header elements. + * + * This would be the same as header_old_tar, except that the + * filename is handled slightly differently for old and POSIX + * entries (POSIX entries support a 'prefix'). This factoring + * allows header_old_tar and header_ustar + * to handle filenames differently, while still putting most of the + * common parsing into one place. + */ +static int +header_common(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h) +{ + const struct archive_entry_header_ustar *header; + char tartype; + int err = ARCHIVE_OK; + + header = (const struct archive_entry_header_ustar *)h; + if (header->linkname[0]) + archive_strncpy(&(tar->entry_linkpath), + header->linkname, sizeof(header->linkname)); + else + archive_string_empty(&(tar->entry_linkpath)); + + /* Parse out the numeric fields (all are octal) */ + archive_entry_set_mode(entry, + (mode_t)tar_atol(header->mode, sizeof(header->mode))); + archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid))); + archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid))); + tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size)); + if (tar->entry_bytes_remaining < 0) { + tar->entry_bytes_remaining = 0; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Tar entry has negative size"); + return (ARCHIVE_FATAL); + } + if (tar->entry_bytes_remaining == INT64_MAX) { + /* Note: tar_atol returns INT64_MAX on overflow */ + tar->entry_bytes_remaining = 0; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Tar entry size overflow"); + return (ARCHIVE_FATAL); + } + tar->realsize = tar->entry_bytes_remaining; + archive_entry_set_size(entry, tar->entry_bytes_remaining); + archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0); + + /* Handle the tar type flag appropriately. */ + tartype = header->typeflag[0]; + + switch (tartype) { + case '1': /* Hard link */ + if (archive_entry_copy_hardlink_l(entry, tar->entry_linkpath.s, + archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, + "Linkname"); + if (err == ARCHIVE_FATAL) + return (err); + } + /* + * The following may seem odd, but: Technically, tar + * does not store the file type for a "hard link" + * entry, only the fact that it is a hard link. So, I + * leave the type zero normally. But, pax interchange + * format allows hard links to have data, which + * implies that the underlying entry is a regular + * file. + */ + if (archive_entry_size(entry) > 0) + archive_entry_set_filetype(entry, AE_IFREG); + + /* + * A tricky point: Traditionally, tar readers have + * ignored the size field when reading hardlink + * entries, and some writers put non-zero sizes even + * though the body is empty. POSIX blessed this + * convention in the 1988 standard, but broke with + * this tradition in 2001 by permitting hardlink + * entries to store valid bodies in pax interchange + * format, but not in ustar format. Since there is no + * hard and fast way to distinguish pax interchange + * from earlier archives (the 'x' and 'g' entries are + * optional, after all), we need a heuristic. + */ + if (archive_entry_size(entry) == 0) { + /* If the size is already zero, we're done. */ + } else if (a->archive.archive_format + == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) { + /* Definitely pax extended; must obey hardlink size. */ + } else if (a->archive.archive_format == ARCHIVE_FORMAT_TAR + || a->archive.archive_format == ARCHIVE_FORMAT_TAR_GNUTAR) + { + /* Old-style or GNU tar: we must ignore the size. */ + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + } else if (archive_read_format_tar_bid(a, 50) > 50) { + /* + * We don't know if it's pax: If the bid + * function sees a valid ustar header + * immediately following, then let's ignore + * the hardlink size. + */ + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + } + /* + * TODO: There are still two cases I'd like to handle: + * = a ustar non-pax archive with a hardlink entry at + * end-of-archive. (Look for block of nulls following?) + * = a pax archive that has not seen any pax headers + * and has an entry which is a hardlink entry storing + * a body containing an uncompressed tar archive. + * The first is worth addressing; I don't see any reliable + * way to deal with the second possibility. + */ + break; + case '2': /* Symlink */ + archive_entry_set_filetype(entry, AE_IFLNK); + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + if (archive_entry_copy_symlink_l(entry, tar->entry_linkpath.s, + archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, + "Linkname"); + if (err == ARCHIVE_FATAL) + return (err); + } + break; + case '3': /* Character device */ + archive_entry_set_filetype(entry, AE_IFCHR); + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + break; + case '4': /* Block device */ + archive_entry_set_filetype(entry, AE_IFBLK); + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + break; + case '5': /* Dir */ + archive_entry_set_filetype(entry, AE_IFDIR); + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + break; + case '6': /* FIFO device */ + archive_entry_set_filetype(entry, AE_IFIFO); + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + break; + case 'D': /* GNU incremental directory type */ + /* + * No special handling is actually required here. + * It might be nice someday to preprocess the file list and + * provide it to the client, though. + */ + archive_entry_set_filetype(entry, AE_IFDIR); + break; + case 'M': /* GNU "Multi-volume" (remainder of file from last archive)*/ + /* + * As far as I can tell, this is just like a regular file + * entry, except that the contents should be _appended_ to + * the indicated file at the indicated offset. This may + * require some API work to fully support. + */ + break; + case 'N': /* Old GNU "long filename" entry. */ + /* The body of this entry is a script for renaming + * previously-extracted entries. Ugh. It will never + * be supported by libarchive. */ + archive_entry_set_filetype(entry, AE_IFREG); + break; + case 'S': /* GNU sparse files */ + /* + * Sparse files are really just regular files with + * sparse information in the extended area. + */ + /* FALLTHROUGH */ + case '0': + /* + * Enable sparse file "read" support only for regular + * files and explicit GNU sparse files. However, we + * don't allow non-standard file types to be sparse. + */ + tar->sparse_allowed = 1; + /* FALLTHROUGH */ + default: /* Regular file and non-standard types */ + /* + * Per POSIX: non-recognized types should always be + * treated as regular files. + */ + archive_entry_set_filetype(entry, AE_IFREG); + break; + } + return (err); +} + +/* + * Parse out header elements for "old-style" tar archives. + */ +static int +header_old_tar(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h) +{ + const struct archive_entry_header_ustar *header; + int err = ARCHIVE_OK, err2; + + /* Copy filename over (to ensure null termination). */ + header = (const struct archive_entry_header_ustar *)h; + if (archive_entry_copy_pathname_l(entry, + header->name, sizeof(header->name), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Pathname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + /* Grab rest of common fields */ + err2 = header_common(a, tar, entry, h); + if (err > err2) + err = err2; + + tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); + return (err); +} + +/* + * Read a Mac AppleDouble-encoded blob of file metadata, + * if there is one. + */ +static int +read_mac_metadata_blob(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + int64_t size; + const void *data; + const char *p, *name; + const wchar_t *wp, *wname; + + (void)h; /* UNUSED */ + + wname = wp = archive_entry_pathname_w(entry); + if (wp != NULL) { + /* Find the last path element. */ + for (; *wp != L'\0'; ++wp) { + if (wp[0] == '/' && wp[1] != L'\0') + wname = wp + 1; + } + /* + * If last path element starts with "._", then + * this is a Mac extension. + */ + if (wname[0] != L'.' || wname[1] != L'_' || wname[2] == L'\0') + return ARCHIVE_OK; + } 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; + } + /* + * If last path element starts with "._", then + * this is a Mac extension. + */ + if (name[0] != '.' || name[1] != '_' || name[2] == '\0') + return ARCHIVE_OK; + } + + /* Read the body as a Mac OS metadata blob. */ + size = archive_entry_size(entry); + + /* + * TODO: Look beyond the body here to peek at the next header. + * If it's a regular header (not an extension header) + * that has the wrong name, just return the current + * entry as-is, without consuming the body here. + * That would reduce the risk of us mis-identifying + * an ordinary file that just happened to have + * a name starting with "._". + * + * Q: Is the above idea really possible? Even + * when there are GNU or pax extension entries? + */ + data = __archive_read_ahead(a, (size_t)size, NULL); + if (data == NULL) { + *unconsumed = 0; + return (ARCHIVE_FATAL); + } + archive_entry_copy_mac_metadata(entry, data, (size_t)size); + *unconsumed = (size_t)((size + 511) & ~ 511); + tar_flush_unconsumed(a, unconsumed); + return (tar_read_header(a, tar, entry, unconsumed)); +} + +/* + * Parse a file header for a pax extended archive entry. + */ +static int +header_pax_global(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + int err; + + err = read_body_to_string(a, tar, &(tar->pax_global), h, unconsumed); + if (err != ARCHIVE_OK) + return (err); + err = tar_read_header(a, tar, entry, unconsumed); + return (err); +} + +static int +header_pax_extensions(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + int err, err2; + + err = read_body_to_string(a, tar, &(tar->pax_header), h, unconsumed); + if (err != ARCHIVE_OK) + return (err); + + /* Parse the next header. */ + err = tar_read_header(a, tar, entry, unconsumed); + if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) + return (err); + + /* + * TODO: Parse global/default options into 'entry' struct here + * before handling file-specific options. + * + * This design (parse standard header, then overwrite with pax + * extended attribute data) usually works well, but isn't ideal; + * it would be better to parse the pax extended attributes first + * and then skip any fields in the standard header that were + * defined in the pax header. + */ + err2 = pax_header(a, tar, entry, &tar->pax_header); + err = err_combine(err, err2); + tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); + return (err); +} + + +/* + * Parse a file header for a Posix "ustar" archive entry. This also + * handles "pax" or "extended ustar" entries. + */ +static int +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. */ + as = &(tar->entry_pathname); + 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)); + } else { + archive_strncpy(as, header->name, sizeof(header->name)); + } + if (archive_entry_copy_pathname_l(entry, as->s, archive_strlen(as), + tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Pathname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + /* Handle rest of common fields. */ + r = header_common(a, tar, entry, h); + if (r == ARCHIVE_FATAL) + return (r); + if (r < err) + err = r; + + /* Handle POSIX ustar fields. */ + if (archive_entry_copy_uname_l(entry, + header->uname, sizeof(header->uname), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Uname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + if (archive_entry_copy_gname_l(entry, + header->gname, sizeof(header->gname), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Gname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + /* Parse out device numbers only for char and block specials. */ + if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { + archive_entry_set_rdevmajor(entry, (dev_t) + tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); + archive_entry_set_rdevminor(entry, (dev_t) + tar_atol(header->rdevminor, sizeof(header->rdevminor))); + } + + tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); + + return (err); +} + + +/* + * Parse the pax extended attributes record. + * + * Returns non-zero if there's an error in the data. + */ +static int +pax_header(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, struct archive_string *in_as) +{ + size_t attr_length, l, line_length, value_length; + char *p; + char *key, *value; + struct archive_string *as; + struct archive_string_conv *sconv; + int err, err2; + char *attr = in_as->s; + + attr_length = in_as->length; + tar->pax_hdrcharset_binary = 0; + archive_string_empty(&(tar->entry_gname)); + archive_string_empty(&(tar->entry_linkpath)); + archive_string_empty(&(tar->entry_pathname)); + archive_string_empty(&(tar->entry_pathname_override)); + archive_string_empty(&(tar->entry_uname)); + err = ARCHIVE_OK; + while (attr_length > 0) { + /* Parse decimal length field at start of line. */ + line_length = 0; + l = attr_length; + p = attr; /* Record start of line. */ + while (l>0) { + if (*p == ' ') { + p++; + l--; + break; + } + if (*p < '0' || *p > '9') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Ignoring malformed pax extended attributes"); + return (ARCHIVE_WARN); + } + line_length *= 10; + line_length += *p - '0'; + if (line_length > 999999) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Rejecting pax extended attribute > 1MB"); + return (ARCHIVE_WARN); + } + p++; + l--; + } + + /* + * Parsed length must be no bigger than available data, + * at least 1, and the last character of the line must + * be '\n'. + */ + if (line_length > attr_length + || line_length < 1 + || attr[line_length - 1] != '\n') + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Ignoring malformed pax extended attribute"); + return (ARCHIVE_WARN); + } + + /* Null-terminate the line. */ + attr[line_length - 1] = '\0'; + + /* Find end of key and null terminate it. */ + key = p; + if (key[0] == '=') + return (-1); + while (*p && *p != '=') + ++p; + if (*p == '\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid pax extended attributes"); + return (ARCHIVE_WARN); + } + *p = '\0'; + + value = p + 1; + + /* Some values may be binary data */ + value_length = attr + line_length - 1 - value; + + /* Identify this attribute and set it in the entry. */ + err2 = pax_attribute(a, tar, entry, key, value, value_length); + if (err2 == ARCHIVE_FATAL) + return (err2); + err = err_combine(err, err2); + + /* Skip to next line */ + attr += line_length; + attr_length -= line_length; + } + + /* + * PAX format uses UTF-8 as default charset for its metadata + * unless hdrcharset=BINARY is present in its header. + * We apply the charset specified by the hdrcharset option only + * when the hdrcharset attribute(in PAX header) is BINARY because + * we respect the charset described in PAX header and BINARY also + * means that metadata(filename,uname and gname) character-set + * is unknown. + */ + if (tar->pax_hdrcharset_binary) + sconv = tar->opt_sconv; + else { + sconv = archive_string_conversion_from_charset( + &(a->archive), "UTF-8", 1); + if (sconv == NULL) + return (ARCHIVE_FATAL); + if (tar->compat_2x) + archive_string_conversion_set_opt(sconv, + SCONV_SET_OPT_UTF8_LIBARCHIVE2X); + } + + if (archive_strlen(&(tar->entry_gname)) > 0) { + if (archive_entry_copy_gname_l(entry, tar->entry_gname.s, + archive_strlen(&(tar->entry_gname)), sconv) != 0) { + err = set_conversion_failed_error(a, sconv, "Gname"); + if (err == ARCHIVE_FATAL) + return (err); + /* Use a converted an original name. */ + archive_entry_copy_gname(entry, tar->entry_gname.s); + } + } + if (archive_strlen(&(tar->entry_linkpath)) > 0) { + if (archive_entry_copy_link_l(entry, tar->entry_linkpath.s, + archive_strlen(&(tar->entry_linkpath)), sconv) != 0) { + err = set_conversion_failed_error(a, sconv, "Linkname"); + if (err == ARCHIVE_FATAL) + return (err); + /* Use a converted an original name. */ + archive_entry_copy_link(entry, tar->entry_linkpath.s); + } + } + /* + * Some extensions (such as the GNU sparse file extensions) + * deliberately store a synthetic name under the regular 'path' + * attribute and the real file name under a different attribute. + * Since we're supposed to not care about the order, we + * have no choice but to store all of the various filenames + * we find and figure it all out afterwards. This is the + * figuring out part. + */ + as = NULL; + if (archive_strlen(&(tar->entry_pathname_override)) > 0) + as = &(tar->entry_pathname_override); + else if (archive_strlen(&(tar->entry_pathname)) > 0) + as = &(tar->entry_pathname); + if (as != NULL) { + if (archive_entry_copy_pathname_l(entry, as->s, + archive_strlen(as), sconv) != 0) { + err = set_conversion_failed_error(a, sconv, "Pathname"); + if (err == ARCHIVE_FATAL) + return (err); + /* Use a converted an original name. */ + archive_entry_copy_pathname(entry, as->s); + } + } + if (archive_strlen(&(tar->entry_uname)) > 0) { + if (archive_entry_copy_uname_l(entry, tar->entry_uname.s, + archive_strlen(&(tar->entry_uname)), sconv) != 0) { + err = set_conversion_failed_error(a, sconv, "Uname"); + if (err == ARCHIVE_FATAL) + return (err); + /* Use a converted an original name. */ + archive_entry_copy_uname(entry, tar->entry_uname.s); + } + } + return (err); +} + +static int +pax_attribute_xattr(struct archive_entry *entry, + const char *name, const char *value) +{ + char *name_decoded; + void *value_decoded; + size_t value_len; + + if (strlen(name) < 18 || (memcmp(name, "LIBARCHIVE.xattr.", 17)) != 0) + return 3; + + name += 17; + + /* URL-decode name */ + name_decoded = url_decode(name); + if (name_decoded == NULL) + return 2; + + /* Base-64 decode value */ + value_decoded = base64_decode(value, strlen(value), &value_len); + if (value_decoded == NULL) { + free(name_decoded); + return 1; + } + + archive_entry_xattr_add_entry(entry, name_decoded, + value_decoded, value_len); + + free(name_decoded); + free(value_decoded); + return 0; +} + +static int +pax_attribute_schily_xattr(struct archive_entry *entry, + const char *name, const char *value, size_t value_length) +{ + if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0) + return 1; + + name += 13; + + archive_entry_xattr_add_entry(entry, name, value, value_length); + + return 0; +} + +static int +pax_attribute_acl(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const char *value, int type) +{ + int r; + const char* errstr; + + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + errstr = "SCHILY.acl.access"; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + errstr = "SCHILY.acl.default"; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + errstr = "SCHILY.acl.ace"; + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Unknown ACL type: %d", type); + return(ARCHIVE_FATAL); + } + + if (tar->sconv_acl == NULL) { + tar->sconv_acl = + archive_string_conversion_from_charset( + &(a->archive), "UTF-8", 1); + if (tar->sconv_acl == NULL) + return (ARCHIVE_FATAL); + } + + r = archive_acl_from_text_l(archive_entry_acl(entry), value, type, + tar->sconv_acl); + if (r != ARCHIVE_OK) { + if (r == ARCHIVE_FATAL) { + archive_set_error(&a->archive, ENOMEM, + "%s %s", "Can't allocate memory for ", + errstr); + return (r); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr); + } + return (r); +} + +/* + * Parse a single key=value attribute. key/value pointers are + * assumed to point into reasonably long-lived storage. + * + * Note that POSIX reserves all-lowercase keywords. Vendor-specific + * extensions should always have keywords of the form "VENDOR.attribute" + * In particular, it's quite feasible to support many different + * vendor extensions here. I'm using "LIBARCHIVE" for extensions + * unique to this library. + * + * Investigate other vendor-specific extensions and see if + * any of them look useful. + */ +static int +pax_attribute(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const char *key, const char *value, size_t value_length) +{ + int64_t s; + long n; + int err = ARCHIVE_OK, r; + + if (value == NULL) + value = ""; /* Disable compiler warning; do not pass + * NULL pointer to strlen(). */ + switch (key[0]) { + case 'G': + /* Reject GNU.sparse.* headers on non-regular files. */ + if (strncmp(key, "GNU.sparse", 10) == 0 && + !tar->sparse_allowed) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Non-regular file cannot be sparse"); + return (ARCHIVE_FATAL); + } + + /* GNU "0.0" sparse pax format. */ + if (strcmp(key, "GNU.sparse.numblocks") == 0) { + tar->sparse_offset = -1; + tar->sparse_numbytes = -1; + tar->sparse_gnu_major = 0; + tar->sparse_gnu_minor = 0; + } + if (strcmp(key, "GNU.sparse.offset") == 0) { + tar->sparse_offset = tar_atol10(value, strlen(value)); + if (tar->sparse_numbytes != -1) { + if (gnu_add_sparse_entry(a, tar, + tar->sparse_offset, tar->sparse_numbytes) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + tar->sparse_offset = -1; + tar->sparse_numbytes = -1; + } + } + if (strcmp(key, "GNU.sparse.numbytes") == 0) { + tar->sparse_numbytes = tar_atol10(value, strlen(value)); + if (tar->sparse_numbytes != -1) { + if (gnu_add_sparse_entry(a, tar, + tar->sparse_offset, tar->sparse_numbytes) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + tar->sparse_offset = -1; + tar->sparse_numbytes = -1; + } + } + if (strcmp(key, "GNU.sparse.size") == 0) { + tar->realsize = tar_atol10(value, strlen(value)); + archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; + } + + /* GNU "0.1" sparse pax format. */ + if (strcmp(key, "GNU.sparse.map") == 0) { + tar->sparse_gnu_major = 0; + tar->sparse_gnu_minor = 1; + if (gnu_sparse_01_parse(a, tar, value) != ARCHIVE_OK) + return (ARCHIVE_WARN); + } + + /* GNU "1.0" sparse pax format */ + if (strcmp(key, "GNU.sparse.major") == 0) { + tar->sparse_gnu_major = (int)tar_atol10(value, strlen(value)); + tar->sparse_gnu_pending = 1; + } + if (strcmp(key, "GNU.sparse.minor") == 0) { + tar->sparse_gnu_minor = (int)tar_atol10(value, strlen(value)); + tar->sparse_gnu_pending = 1; + } + if (strcmp(key, "GNU.sparse.name") == 0) { + /* + * The real filename; when storing sparse + * files, GNU tar puts a synthesized name into + * the regular 'path' attribute in an attempt + * to limit confusion. ;-) + */ + archive_strcpy(&(tar->entry_pathname_override), value); + } + if (strcmp(key, "GNU.sparse.realsize") == 0) { + tar->realsize = tar_atol10(value, strlen(value)); + archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; + } + break; + case 'L': + /* Our extensions */ +/* TODO: Handle arbitrary extended attributes... */ +/* + if (strcmp(key, "LIBARCHIVE.xxxxxxx") == 0) + archive_entry_set_xxxxxx(entry, value); +*/ + if (strcmp(key, "LIBARCHIVE.creationtime") == 0) { + pax_time(value, &s, &n); + archive_entry_set_birthtime(entry, s, n); + } + if (memcmp(key, "LIBARCHIVE.xattr.", 17) == 0) + pax_attribute_xattr(entry, key, value); + break; + case 'S': + /* We support some keys used by the "star" archiver */ + if (strcmp(key, "SCHILY.acl.access") == 0) { + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + if (r == ARCHIVE_FATAL) + return (r); + } else if (strcmp(key, "SCHILY.acl.default") == 0) { + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); + if (r == ARCHIVE_FATAL) + return (r); + } else if (strcmp(key, "SCHILY.acl.ace") == 0) { + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_NFS4); + if (r == ARCHIVE_FATAL) + return (r); + } else if (strcmp(key, "SCHILY.devmajor") == 0) { + archive_entry_set_rdevmajor(entry, + (dev_t)tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.devminor") == 0) { + archive_entry_set_rdevminor(entry, + (dev_t)tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.fflags") == 0) { + archive_entry_copy_fflags_text(entry, value); + } else if (strcmp(key, "SCHILY.dev") == 0) { + archive_entry_set_dev(entry, + (dev_t)tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.ino") == 0) { + archive_entry_set_ino(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.nlink") == 0) { + archive_entry_set_nlink(entry, (unsigned) + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.realsize") == 0) { + tar->realsize = tar_atol10(value, strlen(value)); + tar->realsize_override = 1; + archive_entry_set_size(entry, tar->realsize); + } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) { + pax_attribute_schily_xattr(entry, key, value, + value_length); + } else if (strcmp(key, "SUN.holesdata") == 0) { + /* A Solaris extension for sparse. */ + r = solaris_sparse_parse(a, tar, entry, value); + if (r < err) { + if (r == ARCHIVE_FATAL) + return (r); + err = r; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Parse error: SUN.holesdata"); + } + } + break; + case 'a': + if (strcmp(key, "atime") == 0) { + pax_time(value, &s, &n); + archive_entry_set_atime(entry, s, n); + } + break; + case 'c': + if (strcmp(key, "ctime") == 0) { + pax_time(value, &s, &n); + archive_entry_set_ctime(entry, s, n); + } else if (strcmp(key, "charset") == 0) { + /* TODO: Publish charset information in entry. */ + } else if (strcmp(key, "comment") == 0) { + /* TODO: Publish comment in entry. */ + } + break; + case 'g': + if (strcmp(key, "gid") == 0) { + archive_entry_set_gid(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "gname") == 0) { + archive_strcpy(&(tar->entry_gname), value); + } + break; + case 'h': + if (strcmp(key, "hdrcharset") == 0) { + if (strcmp(value, "BINARY") == 0) + /* Binary mode. */ + tar->pax_hdrcharset_binary = 1; + else if (strcmp(value, "ISO-IR 10646 2000 UTF-8") == 0) + tar->pax_hdrcharset_binary = 0; + } + break; + case 'l': + /* pax interchange doesn't distinguish hardlink vs. symlink. */ + if (strcmp(key, "linkpath") == 0) { + archive_strcpy(&(tar->entry_linkpath), value); + } + break; + case 'm': + if (strcmp(key, "mtime") == 0) { + pax_time(value, &s, &n); + archive_entry_set_mtime(entry, s, n); + } + break; + case 'p': + if (strcmp(key, "path") == 0) { + archive_strcpy(&(tar->entry_pathname), value); + } + break; + case 'r': + /* POSIX has reserved 'realtime.*' */ + break; + case 's': + /* POSIX has reserved 'security.*' */ + /* Someday: if (strcmp(key, "security.acl") == 0) { ... } */ + if (strcmp(key, "size") == 0) { + /* "size" is the size of the data in the entry. */ + tar->entry_bytes_remaining + = tar_atol10(value, strlen(value)); + /* + * The "size" pax header keyword always overrides the + * "size" field in the tar header. + * GNU.sparse.realsize, GNU.sparse.size and + * SCHILY.realsize override this value. + */ + if (!tar->realsize_override) { + archive_entry_set_size(entry, + tar->entry_bytes_remaining); + tar->realsize + = tar->entry_bytes_remaining; + } + } + break; + case 'u': + if (strcmp(key, "uid") == 0) { + archive_entry_set_uid(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "uname") == 0) { + archive_strcpy(&(tar->entry_uname), value); + } + break; + } + return (err); +} + + + +/* + * parse a decimal time value, which may include a fractional portion + */ +static void +pax_time(const char *p, int64_t *ps, long *pn) +{ + char digit; + int64_t s; + unsigned long l; + int sign; + int64_t limit, last_digit_limit; + + limit = INT64_MAX / 10; + last_digit_limit = INT64_MAX % 10; + + s = 0; + sign = 1; + if (*p == '-') { + sign = -1; + p++; + } + while (*p >= '0' && *p <= '9') { + digit = *p - '0'; + if (s > limit || + (s == limit && digit > last_digit_limit)) { + s = INT64_MAX; + break; + } + s = (s * 10) + digit; + ++p; + } + + *ps = s * sign; + + /* Calculate nanoseconds. */ + *pn = 0; + + if (*p != '.') + return; + + l = 100000000UL; + do { + ++p; + if (*p >= '0' && *p <= '9') + *pn += (*p - '0') * l; + else + break; + } while (l /= 10); +} + +/* + * Parse GNU tar header + */ +static int +header_gnutar(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const void *h, size_t *unconsumed) +{ + const struct archive_entry_header_gnutar *header; + int64_t t; + int err = ARCHIVE_OK; + + /* + * GNU header is like POSIX ustar, except 'prefix' is + * replaced with some other fields. This also means the + * filename is stored as in old-style archives. + */ + + /* Grab fields common to all tar variants. */ + err = header_common(a, tar, entry, h); + if (err == ARCHIVE_FATAL) + return (err); + + /* Copy filename over (to ensure null termination). */ + header = (const struct archive_entry_header_gnutar *)h; + if (archive_entry_copy_pathname_l(entry, + header->name, sizeof(header->name), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Pathname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + /* Fields common to ustar and GNU */ + /* XXX Can the following be factored out since it's common + * to ustar and gnu tar? Is it okay to move it down into + * header_common, perhaps? */ + if (archive_entry_copy_uname_l(entry, + header->uname, sizeof(header->uname), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Uname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + if (archive_entry_copy_gname_l(entry, + header->gname, sizeof(header->gname), tar->sconv) != 0) { + err = set_conversion_failed_error(a, tar->sconv, "Gname"); + if (err == ARCHIVE_FATAL) + return (err); + } + + /* Parse out device numbers only for char and block specials */ + if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { + archive_entry_set_rdevmajor(entry, (dev_t) + tar_atol(header->rdevmajor, sizeof(header->rdevmajor))); + archive_entry_set_rdevminor(entry, (dev_t) + tar_atol(header->rdevminor, sizeof(header->rdevminor))); + } else + archive_entry_set_rdev(entry, 0); + + tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); + + /* Grab GNU-specific fields. */ + t = tar_atol(header->atime, sizeof(header->atime)); + if (t > 0) + archive_entry_set_atime(entry, t, 0); + t = tar_atol(header->ctime, sizeof(header->ctime)); + if (t > 0) + archive_entry_set_ctime(entry, t, 0); + + if (header->realsize[0] != 0) { + tar->realsize + = tar_atol(header->realsize, sizeof(header->realsize)); + archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; + } + + if (header->sparse[0].offset[0] != 0) { + if (gnu_sparse_old_read(a, tar, header, unconsumed) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + if (header->isextended[0] != 0) { + /* XXX WTF? XXX */ + } + } + + return (err); +} + +static int +gnu_add_sparse_entry(struct archive_read *a, struct tar *tar, + int64_t offset, int64_t remaining) +{ + struct sparse_block *p; + + p = (struct sparse_block *)calloc(1, sizeof(*p)); + if (p == NULL) { + archive_set_error(&a->archive, ENOMEM, "Out of memory"); + return (ARCHIVE_FATAL); + } + if (tar->sparse_last != NULL) + tar->sparse_last->next = p; + else + tar->sparse_list = p; + tar->sparse_last = p; + if (remaining < 0 || offset < 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data"); + return (ARCHIVE_FATAL); + } + p->offset = offset; + p->remaining = remaining; + return (ARCHIVE_OK); +} + +static void +gnu_clear_sparse_list(struct tar *tar) +{ + struct sparse_block *p; + + while (tar->sparse_list != NULL) { + p = tar->sparse_list; + tar->sparse_list = p->next; + free(p); + } + tar->sparse_last = NULL; +} + +/* + * GNU tar old-format sparse data. + * + * GNU old-format sparse data is stored in a fixed-field + * format. Offset/size values are 11-byte octal fields (same + * format as 'size' field in ustart header). These are + * stored in the header, allocating subsequent header blocks + * as needed. Extending the header in this way is a pretty + * severe POSIX violation; this design has earned GNU tar a + * lot of criticism. + */ + +static int +gnu_sparse_old_read(struct archive_read *a, struct tar *tar, + const struct archive_entry_header_gnutar *header, size_t *unconsumed) +{ + ssize_t bytes_read; + const void *data; + struct extended { + struct gnu_sparse sparse[21]; + char isextended[1]; + char padding[7]; + }; + const struct extended *ext; + + if (gnu_sparse_old_parse(a, tar, header->sparse, 4) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + if (header->isextended[0] == 0) + return (ARCHIVE_OK); + + do { + tar_flush_unconsumed(a, unconsumed); + data = __archive_read_ahead(a, 512, &bytes_read); + if (bytes_read < 0) + return (ARCHIVE_FATAL); + if (bytes_read < 512) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated tar archive " + "detected while reading sparse file data"); + return (ARCHIVE_FATAL); + } + *unconsumed = 512; + ext = (const struct extended *)data; + if (gnu_sparse_old_parse(a, tar, ext->sparse, 21) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } while (ext->isextended[0] != 0); + if (tar->sparse_list != NULL) + tar->entry_offset = tar->sparse_list->offset; + return (ARCHIVE_OK); +} + +static int +gnu_sparse_old_parse(struct archive_read *a, struct tar *tar, + const struct gnu_sparse *sparse, int length) +{ + while (length > 0 && sparse->offset[0] != 0) { + if (gnu_add_sparse_entry(a, tar, + tar_atol(sparse->offset, sizeof(sparse->offset)), + tar_atol(sparse->numbytes, sizeof(sparse->numbytes))) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + sparse++; + length--; + } + return (ARCHIVE_OK); +} + +/* + * GNU tar sparse format 0.0 + * + * Beginning with GNU tar 1.15, sparse files are stored using + * information in the pax extended header. The GNU tar maintainers + * have gone through a number of variations in the process of working + * out this scheme; fortunately, they're all numbered. + * + * Sparse format 0.0 uses attribute GNU.sparse.numblocks to store the + * number of blocks, and GNU.sparse.offset/GNU.sparse.numbytes to + * store offset/size for each block. The repeated instances of these + * latter fields violate the pax specification (which frowns on + * duplicate keys), so this format was quickly replaced. + */ + +/* + * GNU tar sparse format 0.1 + * + * This version replaced the offset/numbytes attributes with + * a single "map" attribute that stored a list of integers. This + * format had two problems: First, the "map" attribute could be very + * long, which caused problems for some implementations. More + * importantly, the sparse data was lost when extracted by archivers + * that didn't recognize this extension. + */ + +static int +gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p) +{ + const char *e; + int64_t offset = -1, size = -1; + + for (;;) { + e = p; + while (*e != '\0' && *e != ',') { + if (*e < '0' || *e > '9') + return (ARCHIVE_WARN); + e++; + } + if (offset < 0) { + offset = tar_atol10(p, e - p); + if (offset < 0) + return (ARCHIVE_WARN); + } else { + size = tar_atol10(p, e - p); + if (size < 0) + return (ARCHIVE_WARN); + if (gnu_add_sparse_entry(a, tar, offset, size) + != ARCHIVE_OK) + return (ARCHIVE_FATAL); + offset = -1; + } + if (*e == '\0') + return (ARCHIVE_OK); + p = e + 1; + } +} + +/* + * GNU tar sparse format 1.0 + * + * The idea: The offset/size data is stored as a series of base-10 + * ASCII numbers prepended to the file data, so that dearchivers that + * don't support this format will extract the block map along with the + * data and a separate post-process can restore the sparseness. + * + * Unfortunately, GNU tar 1.16 had a bug that added unnecessary + * padding to the body of the file when using this format. GNU tar + * 1.17 corrected this bug without bumping the version number, so + * it's not possible to support both variants. This code supports + * the later variant at the expense of not supporting the former. + * + * This variant also replaced GNU.sparse.size with GNU.sparse.realsize + * and introduced the GNU.sparse.major/GNU.sparse.minor attributes. + */ + +/* + * Read the next line from the input, and parse it as a decimal + * integer followed by '\n'. Returns positive integer value or + * negative on error. + */ +static int64_t +gnu_sparse_10_atol(struct archive_read *a, struct tar *tar, + int64_t *remaining, size_t *unconsumed) +{ + int64_t l, limit, last_digit_limit; + 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 + * don't require this, but they should. + */ + do { + bytes_read = readline(a, tar, &p, + (ssize_t)tar_min(*remaining, 100), unconsumed); + if (bytes_read <= 0) + return (ARCHIVE_FATAL); + *remaining -= bytes_read; + } while (p[0] == '#'); + + l = 0; + while (bytes_read > 0) { + if (*p == '\n') + return (l); + if (*p < '0' || *p >= '0' + base) + return (ARCHIVE_WARN); + digit = *p - '0'; + if (l > limit || (l == limit && digit > last_digit_limit)) + l = INT64_MAX; /* Truncate on overflow. */ + else + l = (l * base) + digit; + p++; + bytes_read--; + } + /* TODO: Error message. */ + return (ARCHIVE_WARN); +} + +/* + * Returns length (in bytes) of the sparse data description + * that was read. + */ +static ssize_t +gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) +{ + ssize_t bytes_read; + int entries; + int64_t offset, size, to_skip, remaining; + + /* Clear out the existing sparse list. */ + gnu_clear_sparse_list(tar); + + remaining = tar->entry_bytes_remaining; + + /* Parse entries. */ + entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed); + if (entries < 0) + return (ARCHIVE_FATAL); + /* Parse the individual entries. */ + while (entries-- > 0) { + /* Parse offset/size */ + offset = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); + if (offset < 0) + return (ARCHIVE_FATAL); + size = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); + if (size < 0) + return (ARCHIVE_FATAL); + /* Add a new sparse entry. */ + if (gnu_add_sparse_entry(a, tar, offset, size) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } + /* Skip rest of block... */ + tar_flush_unconsumed(a, unconsumed); + bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining); + to_skip = 0x1ff & -bytes_read; + /* Fail if tar->entry_bytes_remaing would get negative */ + if (to_skip > remaining) + return (ARCHIVE_FATAL); + if (to_skip != __archive_read_consume(a, to_skip)) + return (ARCHIVE_FATAL); + return ((ssize_t)(bytes_read + to_skip)); +} + +/* + * Solaris pax extension for a sparse file. This is recorded with the + * data and hole pairs. The way recording sparse information by Solaris' + * pax simply indicates where data and sparse are, so the stored contents + * consist of both data and hole. + */ +static int +solaris_sparse_parse(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const char *p) +{ + const char *e; + int64_t start, end; + int hole = 1; + + (void)entry; /* UNUSED */ + + end = 0; + if (*p == ' ') + p++; + else + return (ARCHIVE_WARN); + for (;;) { + e = p; + while (*e != '\0' && *e != ' ') { + if (*e < '0' || *e > '9') + return (ARCHIVE_WARN); + e++; + } + start = end; + end = tar_atol10(p, e - p); + if (end < 0) + return (ARCHIVE_WARN); + if (start < end) { + if (gnu_add_sparse_entry(a, tar, start, + end - start) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + tar->sparse_last->hole = hole; + } + if (*e == '\0') + return (ARCHIVE_OK); + p = e + 1; + hole = hole == 0; + } +} + +/*- + * Convert text->integer. + * + * Traditional tar formats (including POSIX) specify base-8 for + * all of the standard numeric fields. This is a significant limitation + * in practice: + * = file size is limited to 8GB + * = rdevmajor and rdevminor are limited to 21 bits + * = uid/gid are limited to 21 bits + * + * There are two workarounds for this: + * = pax extended headers, which use variable-length string fields + * = GNU tar and STAR both allow either base-8 or base-256 in + * most fields. The high bit is set to indicate base-256. + * + * On read, this implementation supports both extensions. + */ +static int64_t +tar_atol(const char *p, size_t char_cnt) +{ + /* + * Technically, GNU tar considers a field to be in base-256 + * only if the first byte is 0xff or 0x80. + */ + if (*p & 0x80) + return (tar_atol256(p, char_cnt)); + return (tar_atol8(p, char_cnt)); +} + +/* + * Note that this implementation does not (and should not!) obey + * locale settings; you cannot simply substitute strtol here, since + * it does obey locale. + */ +static int64_t +tar_atol_base_n(const char *p, size_t char_cnt, int base) +{ + int64_t l, maxval, limit, last_digit_limit; + int digit, sign; + + maxval = INT64_MAX; + limit = INT64_MAX / base; + last_digit_limit = INT64_MAX % base; + + /* the pointer will not be dereferenced if char_cnt is zero + * due to the way the && operator is evaluated. + */ + while (char_cnt != 0 && (*p == ' ' || *p == '\t')) { + p++; + char_cnt--; + } + + sign = 1; + if (char_cnt != 0 && *p == '-') { + sign = -1; + p++; + char_cnt--; + + maxval = INT64_MIN; + limit = -(INT64_MIN / base); + last_digit_limit = INT64_MIN % base; + } + + l = 0; + if (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--; + } + } + return (sign < 0) ? -l : l; +} + +static int64_t +tar_atol8(const char *p, size_t char_cnt) +{ + return tar_atol_base_n(p, char_cnt, 8); +} + +static int64_t +tar_atol10(const char *p, size_t char_cnt) +{ + return tar_atol_base_n(p, char_cnt, 10); +} + +/* + * Parse a base-256 integer. This is just a variable-length + * twos-complement signed binary value in big-endian order, except + * that the high-order bit is ignored. The values here can be up to + * 12 bytes, so we need to be careful about overflowing 64-bit + * (8-byte) integers. + * + * This code unashamedly assumes that the local machine uses 8-bit + * bytes and twos-complement arithmetic. + */ +static int64_t +tar_atol256(const char *_p, size_t char_cnt) +{ + uint64_t l; + const unsigned char *p = (const unsigned char *)_p; + unsigned char c, neg; + + /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */ + c = *p; + if (c & 0x40) { + neg = 0xff; + c |= 0x80; + l = ~ARCHIVE_LITERAL_ULL(0); + } else { + neg = 0; + c &= 0x7f; + l = 0; + } + + /* If more than 8 bytes, check that we can ignore + * high-order bits without overflow. */ + while (char_cnt > sizeof(int64_t)) { + --char_cnt; + if (c != neg) + return neg ? INT64_MIN : INT64_MAX; + c = *++p; + } + + /* c is first byte that fits; if sign mismatch, return overflow */ + if ((c ^ neg) & 0x80) { + return neg ? INT64_MIN : INT64_MAX; + } + + /* Accumulate remaining bytes. */ + while (--char_cnt > 0) { + l = (l << 8) | c; + c = *++p; + } + l = (l << 8) | c; + /* Return signed twos-complement value. */ + return (int64_t)(l); +} + +/* + * Returns length of line (including trailing newline) + * or negative on error. 'start' argument is updated to + * point to first character of line. This avoids copying + * when possible. + */ +static ssize_t +readline(struct archive_read *a, struct tar *tar, const char **start, + ssize_t limit, size_t *unconsumed) +{ + ssize_t bytes_read; + ssize_t total_size = 0; + const void *t; + const char *s; + void *p; + + tar_flush_unconsumed(a, unconsumed); + + t = __archive_read_ahead(a, 1, &bytes_read); + if (bytes_read <= 0) + return (ARCHIVE_FATAL); + s = t; /* Start of line? */ + p = memchr(t, '\n', bytes_read); + /* If we found '\n' in the read buffer, return pointer to that. */ + if (p != NULL) { + bytes_read = 1 + ((const char *)p) - s; + if (bytes_read > limit) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Line too long"); + return (ARCHIVE_FATAL); + } + *unconsumed = bytes_read; + *start = s; + return (bytes_read); + } + *unconsumed = bytes_read; + /* Otherwise, we need to accumulate in a line buffer. */ + for (;;) { + if (total_size + bytes_read > limit) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Line too long"); + return (ARCHIVE_FATAL); + } + if (archive_string_ensure(&tar->line, total_size + bytes_read) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate working buffer"); + return (ARCHIVE_FATAL); + } + memcpy(tar->line.s + total_size, t, bytes_read); + tar_flush_unconsumed(a, unconsumed); + total_size += bytes_read; + /* If we found '\n', clean up and return. */ + if (p != NULL) { + *start = tar->line.s; + return (total_size); + } + /* Read some more. */ + t = __archive_read_ahead(a, 1, &bytes_read); + if (bytes_read <= 0) + return (ARCHIVE_FATAL); + s = t; /* Start of line? */ + p = memchr(t, '\n', bytes_read); + /* If we found '\n', trim the read. */ + if (p != NULL) { + bytes_read = 1 + ((const char *)p) - s; + } + *unconsumed = bytes_read; + } +} + +/* + * base64_decode - Base64 decode + * + * This accepts most variations of base-64 encoding, including: + * * with or without line breaks + * * with or without the final group padded with '=' or '_' characters + * (The most economical Base-64 variant does not pad the last group and + * omits line breaks; RFC1341 used for MIME requires both.) + */ +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]; + 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 = (char *)malloc(len - len / 4 + 1); + if (out == NULL) { + *out_len = 0; + return (NULL); + } + d = out; + + while (len > 0) { + /* Collect the next group of (up to) four characters. */ + int v = 0; + int group_size = 0; + while (group_size < 4 && len > 0) { + /* '=' or '_' padding indicates final group. */ + if (*src == '=' || *src == '_') { + len = 0; + break; + } + /* Skip illegal characters (including line breaks) */ + if (*src > 127 || *src < 32 + || decode_table[*src] == 0xff) { + len--; + src++; + continue; + } + v <<= 6; + v |= decode_table[*src++]; + len --; + group_size++; + } + /* Align a short group properly. */ + v <<= 6 * (4 - group_size); + /* Unpack the group we just collected. */ + switch (group_size) { + case 4: d[2] = v & 0xff; + /* FALLTHROUGH */ + case 3: d[1] = (v >> 8) & 0xff; + /* FALLTHROUGH */ + case 2: d[0] = (v >> 16) & 0xff; + break; + case 1: /* this is invalid! */ + break; + } + d += group_size * 3 / 4; + } + + *out_len = d - out; + return (out); +} + +static char * +url_decode(const char *in) +{ + char *out, *d; + const char *s; + + out = (char *)malloc(strlen(in) + 1); + if (out == NULL) + return (NULL); + for (s = in, d = out; *s != '\0'; ) { + if (s[0] == '%' && s[1] != '\0' && s[2] != '\0') { + /* Try to convert % escape */ + int digit1 = tohex(s[1]); + int digit2 = tohex(s[2]); + if (digit1 >= 0 && digit2 >= 0) { + /* Looks good, consume three chars */ + s += 3; + /* Convert output */ + *d++ = ((digit1 << 4) | digit2); + continue; + } + /* Else fall through and treat '%' as normal char */ + } + *d++ = *s++; + } + *d = '\0'; + return (out); +} + +static int +tohex(int c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else + return (-1); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_string.c b/src/3rdparty/libarchive/libarchive/archive_string.c new file mode 100644 index 00000000..5ae09b62 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_string.c @@ -0,0 +1,4207 @@ +/*- + * Copyright (c) 2003-2011 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33:22Z kientzle $"); + +/* + * Basic resizable string support, to simplify manipulating arbitrary-sized + * strings while minimizing heap activity. + * + * In particular, the buffer used by a string object is only grown, it + * never shrinks, so you can clear and reuse the same string object + * without incurring additional memory allocations. + */ + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_ICONV_H +#include +#endif +#ifdef HAVE_LANGINFO_H +#include +#endif +#ifdef HAVE_LOCALCHARSET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#endif + +#include "archive_endian.h" +#include "archive_private.h" +#include "archive_string.h" +#include "archive_string_composition.h" + +#if !defined(HAVE_WMEMCPY) && !defined(wmemcpy) +#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) +#endif + +#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove) +#define wmemmove(a,b,i) (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t)) +#endif + +struct archive_string_conv { + struct archive_string_conv *next; + char *from_charset; + char *to_charset; + unsigned from_cp; + unsigned to_cp; + /* Set 1 if from_charset and to_charset are the same. */ + int same; + int flag; +#define SCONV_TO_CHARSET 1 /* MBS is being converted to specified + * charset. */ +#define SCONV_FROM_CHARSET (1<<1) /* MBS is being converted from + * specified charset. */ +#define SCONV_BEST_EFFORT (1<<2) /* Copy at least ASCII code. */ +#define SCONV_WIN_CP (1<<3) /* Use Windows API for converting + * MBS. */ +#define SCONV_UTF8_LIBARCHIVE_2 (1<<4) /* Incorrect UTF-8 made by libarchive + * 2.x in the wrong assumption. */ +#define SCONV_NORMALIZATION_C (1<<6) /* Need normalization to be Form C. + * Before UTF-8 characters are actually + * processed. */ +#define SCONV_NORMALIZATION_D (1<<7) /* Need normalization to be Form D. + * Before UTF-8 characters are actually + * processed. + * Currently this only for MAC OS X. */ +#define SCONV_TO_UTF8 (1<<8) /* "to charset" side is UTF-8. */ +#define SCONV_FROM_UTF8 (1<<9) /* "from charset" side is UTF-8. */ +#define SCONV_TO_UTF16BE (1<<10) /* "to charset" side is UTF-16BE. */ +#define SCONV_FROM_UTF16BE (1<<11) /* "from charset" side is UTF-16BE. */ +#define SCONV_TO_UTF16LE (1<<12) /* "to charset" side is UTF-16LE. */ +#define SCONV_FROM_UTF16LE (1<<13) /* "from charset" side is UTF-16LE. */ +#define SCONV_TO_UTF16 (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE) +#define SCONV_FROM_UTF16 (SCONV_FROM_UTF16BE | SCONV_FROM_UTF16LE) + +#if HAVE_ICONV + iconv_t cd; + iconv_t cd_w;/* Use at archive_mstring on + * Windows. */ +#endif + /* A temporary buffer for normalization. */ + struct archive_string utftmp; + int (*converter[2])(struct archive_string *, const void *, size_t, + struct archive_string_conv *); + int nconverter; +}; + +#define CP_C_LOCALE 0 /* "C" locale only for this file. */ +#define CP_UTF16LE 1200 +#define CP_UTF16BE 1201 + +#define IS_HIGH_SURROGATE_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDBFF) +#define IS_LOW_SURROGATE_LA(uc) ((uc) >= 0xDC00 && (uc) <= 0xDFFF) +#define IS_SURROGATE_PAIR_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDFFF) +#define UNICODE_MAX 0x10FFFF +#define UNICODE_R_CHAR 0xFFFD /* Replacement character. */ +/* Set U+FFFD(Replacement character) in UTF-8. */ +static const char utf8_replacement_char[] = {0xef, 0xbf, 0xbd}; + +static struct archive_string_conv *find_sconv_object(struct archive *, + const char *, const char *); +static void add_sconv_object(struct archive *, struct archive_string_conv *); +static struct archive_string_conv *create_sconv_object(const char *, + const char *, unsigned, int); +static void free_sconv_object(struct archive_string_conv *); +static struct archive_string_conv *get_sconv_object(struct archive *, + const char *, const char *, int); +static unsigned make_codepage_from_charset(const char *); +static unsigned get_current_codepage(void); +static unsigned get_current_oemcp(void); +static size_t mbsnbytes(const void *, size_t); +static size_t utf16nbytes(const void *, size_t); +#if defined(_WIN32) && !defined(__CYGWIN__) +static int archive_wstring_append_from_mbs_in_codepage( + struct archive_wstring *, const char *, size_t, + struct archive_string_conv *); +static int archive_string_append_from_wcs_in_codepage(struct archive_string *, + const wchar_t *, size_t, struct archive_string_conv *); +static int is_big_endian(void); +static int strncat_in_codepage(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int win_strncat_from_utf16be(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int win_strncat_from_utf16le(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int win_strncat_to_utf16be(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int win_strncat_to_utf16le(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +#endif +static int best_effort_strncat_from_utf16be(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_from_utf16le(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_to_utf16be(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int best_effort_strncat_to_utf16le(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +#if defined(HAVE_ICONV) +static int iconv_strncat_in_locale(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +#endif +static int best_effort_strncat_in_locale(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int _utf8_to_unicode(uint32_t *, const char *, size_t); +static int utf8_to_unicode(uint32_t *, const char *, size_t); +static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t); +static int cesu8_to_unicode(uint32_t *, const char *, size_t); +static size_t unicode_to_utf8(char *, size_t, uint32_t); +static int utf16_to_unicode(uint32_t *, const char *, size_t, int); +static size_t unicode_to_utf16be(char *, size_t, uint32_t); +static size_t unicode_to_utf16le(char *, size_t, uint32_t); +static int strncat_from_utf8_libarchive2(struct archive_string *, + const void *, size_t, struct archive_string_conv *); +static int strncat_from_utf8_to_utf8(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int archive_string_normalize_C(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int archive_string_normalize_D(struct archive_string *, const void *, + size_t, struct archive_string_conv *); +static int archive_string_append_unicode(struct archive_string *, + const void *, size_t, struct archive_string_conv *); + +static struct archive_string * +archive_string_append(struct archive_string *as, const char *p, size_t s) +{ + if (archive_string_ensure(as, as->length + s + 1) == NULL) + return (NULL); + if (s) + memmove(as->s + as->length, p, s); + as->length += s; + as->s[as->length] = 0; + return (as); +} + +static struct archive_wstring * +archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s) +{ + if (archive_wstring_ensure(as, as->length + s + 1) == NULL) + return (NULL); + wmemmove(as->s + as->length, p, s); + as->length += s; + as->s[as->length] = 0; + return (as); +} + +struct archive_string * +archive_array_append(struct archive_string *as, const char *p, size_t s) +{ + return archive_string_append(as, p, s); +} + +void +archive_string_concat(struct archive_string *dest, struct archive_string *src) +{ + if (archive_string_append(dest, src->s, src->length) == NULL) + __archive_errx(1, "Out of memory"); +} + +void +archive_wstring_concat(struct archive_wstring *dest, + struct archive_wstring *src) +{ + if (archive_wstring_append(dest, src->s, src->length) == NULL) + __archive_errx(1, "Out of memory"); +} + +void +archive_string_free(struct archive_string *as) +{ + as->length = 0; + as->buffer_length = 0; + free(as->s); + as->s = NULL; +} + +void +archive_wstring_free(struct archive_wstring *as) +{ + as->length = 0; + as->buffer_length = 0; + free(as->s); + as->s = NULL; +} + +struct archive_wstring * +archive_wstring_ensure(struct archive_wstring *as, size_t s) +{ + return (struct archive_wstring *) + archive_string_ensure((struct archive_string *)as, + s * sizeof(wchar_t)); +} + +/* Returns NULL on any allocation failure. */ +struct archive_string * +archive_string_ensure(struct archive_string *as, size_t s) +{ + char *p; + size_t new_length; + + /* If buffer is already big enough, don't reallocate. */ + if (as->s && (s <= as->buffer_length)) + return (as); + + /* + * Growing the buffer at least exponentially ensures that + * append operations are always linear in the number of + * characters appended. Using a smaller growth rate for + * larger buffers reduces memory waste somewhat at the cost of + * a larger constant factor. + */ + if (as->buffer_length < 32) + /* Start with a minimum 32-character buffer. */ + new_length = 32; + else if (as->buffer_length < 8192) + /* Buffers under 8k are doubled for speed. */ + new_length = as->buffer_length + as->buffer_length; + else { + /* Buffers 8k and over grow by at least 25% each time. */ + new_length = as->buffer_length + as->buffer_length / 4; + /* Be safe: If size wraps, fail. */ + if (new_length < as->buffer_length) { + /* On failure, wipe the string and return NULL. */ + archive_string_free(as); + errno = ENOMEM;/* Make sure errno has ENOMEM. */ + return (NULL); + } + } + /* + * The computation above is a lower limit to how much we'll + * grow the buffer. In any case, we have to grow it enough to + * hold the request. + */ + if (new_length < s) + new_length = s; + /* Now we can reallocate the buffer. */ + p = (char *)realloc(as->s, new_length); + if (p == NULL) { + /* On failure, wipe the string and return NULL. */ + archive_string_free(as); + errno = ENOMEM;/* Make sure errno has ENOMEM. */ + return (NULL); + } + + as->s = p; + as->buffer_length = new_length; + return (as); +} + +/* + * TODO: See if there's a way to avoid scanning + * the source string twice. Then test to see + * if it actually helps (remember that we're almost + * always called with pretty short arguments, so + * such an optimization might not help). + */ +struct archive_string * +archive_strncat(struct archive_string *as, const void *_p, size_t n) +{ + size_t s; + const char *p, *pp; + + p = (const char *)_p; + + /* Like strlen(p), except won't examine positions beyond p[n]. */ + s = 0; + pp = p; + while (s < n && *pp) { + pp++; + s++; + } + if ((as = archive_string_append(as, p, s)) == NULL) + __archive_errx(1, "Out of memory"); + return (as); +} + +struct archive_wstring * +archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n) +{ + size_t s; + const wchar_t *pp; + + /* Like strlen(p), except won't examine positions beyond p[n]. */ + s = 0; + pp = p; + while (s < n && *pp) { + pp++; + s++; + } + if ((as = archive_wstring_append(as, p, s)) == NULL) + __archive_errx(1, "Out of memory"); + return (as); +} + +struct archive_string * +archive_strcat(struct archive_string *as, const void *p) +{ + /* strcat is just strncat without an effective limit. + * Assert that we'll never get called with a source + * string over 16MB. + * TODO: Review all uses of strcat in the source + * and try to replace them with strncat(). + */ + return archive_strncat(as, p, 0x1000000); +} + +struct archive_wstring * +archive_wstrcat(struct archive_wstring *as, const wchar_t *p) +{ + /* Ditto. */ + return archive_wstrncat(as, p, 0x1000000); +} + +struct archive_string * +archive_strappend_char(struct archive_string *as, char c) +{ + if ((as = archive_string_append(as, &c, 1)) == NULL) + __archive_errx(1, "Out of memory"); + return (as); +} + +struct archive_wstring * +archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c) +{ + if ((as = archive_wstring_append(as, &c, 1)) == NULL) + __archive_errx(1, "Out of memory"); + return (as); +} + +/* + * Get the "current character set" name to use with iconv. + * On FreeBSD, the empty character set name "" chooses + * the correct character encoding for the current locale, + * so this isn't necessary. + * But iconv on Mac OS 10.6 doesn't seem to handle this correctly; + * on that system, we have to explicitly call nl_langinfo() + * to get the right name. Not sure about other platforms. + * + * NOTE: GNU libiconv does not recognize the character-set name + * which some platform nl_langinfo(CODESET) returns, so we should + * use locale_charset() instead of nl_langinfo(CODESET) for GNU libiconv. + */ +static const char * +default_iconv_charset(const char *charset) { + if (charset != NULL && charset[0] != '\0') + return charset; +#if HAVE_LOCALE_CHARSET && !defined(__APPLE__) + /* locale_charset() is broken on Mac OS */ + return locale_charset(); +#elif HAVE_NL_LANGINFO + return nl_langinfo(CODESET); +#else + return ""; +#endif +} + +#if defined(_WIN32) && !defined(__CYGWIN__) + +/* + * Convert MBS to WCS. + * Note: returns -1 if conversion fails. + */ +int +archive_wstring_append_from_mbs(struct archive_wstring *dest, + const char *p, size_t len) +{ + return archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL); +} + +static int +archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, + const char *s, size_t length, struct archive_string_conv *sc) +{ + int count, ret = 0; + UINT from_cp; + + if (sc != NULL) + from_cp = sc->from_cp; + else + from_cp = get_current_codepage(); + + if (from_cp == CP_C_LOCALE) { + /* + * "C" locale special process. + */ + wchar_t *ws; + const unsigned char *mp; + + if (NULL == archive_wstring_ensure(dest, + dest->length + length + 1)) + return (-1); + + ws = dest->s + dest->length; + mp = (const unsigned char *)s; + count = 0; + while (count < (int)length && *mp) { + *ws++ = (wchar_t)*mp++; + count++; + } + } else if (sc != NULL && + (sc->flag & (SCONV_NORMALIZATION_C | SCONV_NORMALIZATION_D))) { + /* + * Normalize UTF-8 and UTF-16BE and convert it directly + * to UTF-16 as wchar_t. + */ + struct archive_string u16; + int saved_flag = sc->flag;/* save current flag. */ + + if (is_big_endian()) + sc->flag |= SCONV_TO_UTF16BE; + else + sc->flag |= SCONV_TO_UTF16LE; + + if (sc->flag & SCONV_FROM_UTF16) { + /* + * UTF-16BE/LE NFD ===> UTF-16 NFC + * UTF-16BE/LE NFC ===> UTF-16 NFD + */ + count = (int)utf16nbytes(s, length); + } else { + /* + * UTF-8 NFD ===> UTF-16 NFC + * UTF-8 NFC ===> UTF-16 NFD + */ + count = (int)mbsnbytes(s, length); + } + u16.s = (char *)dest->s; + u16.length = dest->length << 1;; + u16.buffer_length = dest->buffer_length; + if (sc->flag & SCONV_NORMALIZATION_C) + ret = archive_string_normalize_C(&u16, s, count, sc); + else + ret = archive_string_normalize_D(&u16, s, count, sc); + dest->s = (wchar_t *)u16.s; + dest->length = u16.length >> 1; + dest->buffer_length = u16.buffer_length; + sc->flag = saved_flag;/* restore the saved flag. */ + return (ret); + } else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) { + count = (int)utf16nbytes(s, length); + count >>= 1; /* to be WCS length */ + /* Allocate memory for WCS. */ + if (NULL == archive_wstring_ensure(dest, + dest->length + count + 1)) + return (-1); + wmemcpy(dest->s + dest->length, (const wchar_t *)s, count); + if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) { + uint16_t *u16 = (uint16_t *)(dest->s + dest->length); + int b; + for (b = 0; b < count; b++) { + uint16_t val = archive_le16dec(u16+b); + archive_be16enc(u16+b, val); + } + } else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) { + uint16_t *u16 = (uint16_t *)(dest->s + dest->length); + int b; + for (b = 0; b < count; b++) { + uint16_t val = archive_be16dec(u16+b); + archive_le16enc(u16+b, val); + } + } + } else { + DWORD mbflag; + size_t buffsize; + + if (sc == NULL) + mbflag = 0; + else if (sc->flag & SCONV_FROM_CHARSET) { + /* Do not trust the length which comes from + * an archive file. */ + length = mbsnbytes(s, length); + mbflag = 0; + } else + mbflag = MB_PRECOMPOSED; + + buffsize = dest->length + length + 1; + do { + /* Allocate memory for WCS. */ + if (NULL == archive_wstring_ensure(dest, buffsize)) + return (-1); + /* Convert MBS to WCS. */ + count = MultiByteToWideChar(from_cp, + mbflag, s, (int)length, dest->s + dest->length, + (int)(dest->buffer_length >> 1) -1); + if (count == 0 && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + /* Expand the WCS buffer. */ + buffsize = dest->buffer_length << 1; + continue; + } + if (count == 0 && length != 0) + ret = -1; + break; + } while (1); + } + dest->length += count; + dest->s[dest->length] = L'\0'; + return (ret); +} + +#else + +/* + * Convert MBS to WCS. + * Note: returns -1 if conversion fails. + */ +int +archive_wstring_append_from_mbs(struct archive_wstring *dest, + const char *p, size_t len) +{ + size_t r; + int ret_val = 0; + /* + * No single byte will be more than one wide character, + * so this length estimate will always be big enough. + */ + size_t wcs_length = len; + size_t mbs_length = len; + const char *mbs = p; + wchar_t *wcs; +#if HAVE_MBRTOWC + mbstate_t shift_state; + + memset(&shift_state, 0, sizeof(shift_state)); +#endif + if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1)) + return (-1); + wcs = dest->s + dest->length; + /* + * We cannot use mbsrtowcs/mbstowcs here because those may convert + * extra MBS when strlen(p) > len and one wide character consists of + * multi bytes. + */ + while (*mbs && mbs_length > 0) { + if (wcs_length == 0) { + dest->length = wcs - dest->s; + dest->s[dest->length] = L'\0'; + wcs_length = mbs_length; + if (NULL == archive_wstring_ensure(dest, + dest->length + wcs_length + 1)) + return (-1); + wcs = dest->s + dest->length; + } +#if HAVE_MBRTOWC + r = mbrtowc(wcs, mbs, wcs_length, &shift_state); +#else + r = mbtowc(wcs, mbs, wcs_length); +#endif + if (r == (size_t)-1 || r == (size_t)-2) { + ret_val = -1; + if (errno == EILSEQ) { + ++mbs; + --mbs_length; + continue; + } else + break; + } + if (r == 0 || r > mbs_length) + break; + wcs++; + wcs_length--; + mbs += r; + mbs_length -= r; + } + dest->length = wcs - dest->s; + dest->s[dest->length] = L'\0'; + return (ret_val); +} + +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) + +/* + * WCS ==> MBS. + * Note: returns -1 if conversion fails. + * + * Win32 builds use WideCharToMultiByte from the Windows API. + * (Maybe Cygwin should too? WideCharToMultiByte will know a + * lot more about local character encodings than the wcrtomb() + * wrapper is going to know.) + */ +int +archive_string_append_from_wcs(struct archive_string *as, + const wchar_t *w, size_t len) +{ + return archive_string_append_from_wcs_in_codepage(as, w, len, NULL); +} + +static int +archive_string_append_from_wcs_in_codepage(struct archive_string *as, + const wchar_t *ws, size_t len, struct archive_string_conv *sc) +{ + BOOL defchar_used, *dp; + int count, ret = 0; + UINT to_cp; + int wslen = (int)len; + + if (sc != NULL) + to_cp = sc->to_cp; + else + to_cp = get_current_codepage(); + + if (to_cp == CP_C_LOCALE) { + /* + * "C" locale special process. + */ + const wchar_t *wp = ws; + char *p; + + if (NULL == archive_string_ensure(as, + as->length + wslen +1)) + return (-1); + p = as->s + as->length; + count = 0; + defchar_used = 0; + while (count < wslen && *wp) { + if (*wp > 255) { + *p++ = '?'; + wp++; + defchar_used = 1; + } else + *p++ = (char)*wp++; + count++; + } + } else if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) { + uint16_t *u16; + + if (NULL == + archive_string_ensure(as, as->length + len * 2 + 2)) + return (-1); + u16 = (uint16_t *)(as->s + as->length); + count = 0; + defchar_used = 0; + if (sc->flag & SCONV_TO_UTF16BE) { + while (count < (int)len && *ws) { + archive_be16enc(u16+count, *ws); + ws++; + count++; + } + } else { + while (count < (int)len && *ws) { + archive_le16enc(u16+count, *ws); + ws++; + count++; + } + } + count <<= 1; /* to be byte size */ + } else { + /* Make sure the MBS buffer has plenty to set. */ + if (NULL == + archive_string_ensure(as, as->length + len * 2 + 1)) + return (-1); + do { + defchar_used = 0; + if (to_cp == CP_UTF8 || sc == NULL) + dp = NULL; + else + dp = &defchar_used; + count = WideCharToMultiByte(to_cp, 0, ws, wslen, + as->s + as->length, (int)as->buffer_length-1, NULL, dp); + if (count == 0 && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + /* Expand the MBS buffer and retry. */ + if (NULL == archive_string_ensure(as, + as->buffer_length + len)) + return (-1); + continue; + } + if (count == 0) + ret = -1; + break; + } while (1); + } + as->length += count; + as->s[as->length] = '\0'; + return (defchar_used?-1:ret); +} + +#elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB) + +/* + * Translates a wide character string into current locale character set + * and appends to the archive_string. Note: returns -1 if conversion + * fails. + */ +int +archive_string_append_from_wcs(struct archive_string *as, + const wchar_t *w, size_t len) +{ + /* We cannot use the standard wcstombs() here because it + * cannot tell us how big the output buffer should be. So + * I've built a loop around wcrtomb() or wctomb() that + * converts a character at a time and resizes the string as + * needed. We prefer wcrtomb() when it's available because + * it's thread-safe. */ + int n, ret_val = 0; + char *p; + char *end; +#if HAVE_WCRTOMB + mbstate_t shift_state; + + memset(&shift_state, 0, sizeof(shift_state)); +#else + /* Clear the shift state before starting. */ + wctomb(NULL, L'\0'); +#endif + /* + * Allocate buffer for MBS. + * We need this allocation here since it is possible that + * as->s is still NULL. + */ + if (archive_string_ensure(as, as->length + len + 1) == NULL) + return (-1); + + p = as->s + as->length; + end = as->s + as->buffer_length - MB_CUR_MAX -1; + while (*w != L'\0' && len > 0) { + if (p >= end) { + as->length = p - as->s; + as->s[as->length] = '\0'; + /* Re-allocate buffer for MBS. */ + if (archive_string_ensure(as, + as->length + len * 2 + 1) == NULL) + return (-1); + p = as->s + as->length; + end = as->s + as->buffer_length - MB_CUR_MAX -1; + } +#if HAVE_WCRTOMB + n = wcrtomb(p, *w++, &shift_state); +#else + n = wctomb(p, *w++); +#endif + if (n == -1) { + if (errno == EILSEQ) { + /* Skip an illegal wide char. */ + *p++ = '?'; + ret_val = -1; + } else { + ret_val = -1; + break; + } + } else + p += n; + len--; + } + as->length = p - as->s; + as->s[as->length] = '\0'; + return (ret_val); +} + +#else /* HAVE_WCTOMB || HAVE_WCRTOMB */ + +/* + * TODO: Test if __STDC_ISO_10646__ is defined. + * Non-Windows uses ISO C wcrtomb() or wctomb() to perform the conversion + * one character at a time. If a non-Windows platform doesn't have + * either of these, fall back to the built-in UTF8 conversion. + */ +int +archive_string_append_from_wcs(struct archive_string *as, + const wchar_t *w, size_t len) +{ + (void)as;/* UNUSED */ + (void)w;/* UNUSED */ + (void)len;/* UNUSED */ + errno = ENOSYS; + return (-1); +} + +#endif /* HAVE_WCTOMB || HAVE_WCRTOMB */ + +/* + * Find a string conversion object by a pair of 'from' charset name + * and 'to' charset name from an archive object. + * Return NULL if not found. + */ +static struct archive_string_conv * +find_sconv_object(struct archive *a, const char *fc, const char *tc) +{ + struct archive_string_conv *sc; + + if (a == NULL) + return (NULL); + + for (sc = a->sconv; sc != NULL; sc = sc->next) { + if (strcmp(sc->from_charset, fc) == 0 && + strcmp(sc->to_charset, tc) == 0) + break; + } + return (sc); +} + +/* + * Register a string object to an archive object. + */ +static void +add_sconv_object(struct archive *a, struct archive_string_conv *sc) +{ + struct archive_string_conv **psc; + + /* Add a new sconv to sconv list. */ + psc = &(a->sconv); + while (*psc != NULL) + psc = &((*psc)->next); + *psc = sc; +} + +static void +add_converter(struct archive_string_conv *sc, int (*converter) + (struct archive_string *, const void *, size_t, + struct archive_string_conv *)) +{ + if (sc == NULL || sc->nconverter >= 2) + __archive_errx(1, "Programing error"); + sc->converter[sc->nconverter++] = converter; +} + +static void +setup_converter(struct archive_string_conv *sc) +{ + + /* Reset. */ + sc->nconverter = 0; + + /* + * Perform special sequence for the incorrect UTF-8 filenames + * made by libarchive2.x. + */ + if (sc->flag & SCONV_UTF8_LIBARCHIVE_2) { + add_converter(sc, strncat_from_utf8_libarchive2); + return; + } + + /* + * Convert a string to UTF-16BE/LE. + */ + if (sc->flag & SCONV_TO_UTF16) { + /* + * If the current locale is UTF-8, we can translate + * a UTF-8 string into a UTF-16BE string. + */ + if (sc->flag & SCONV_FROM_UTF8) { + add_converter(sc, archive_string_append_unicode); + return; + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sc->flag & SCONV_WIN_CP) { + if (sc->flag & SCONV_TO_UTF16BE) + add_converter(sc, win_strncat_to_utf16be); + else + add_converter(sc, win_strncat_to_utf16le); + return; + } +#endif + +#if defined(HAVE_ICONV) + if (sc->cd != (iconv_t)-1) { + add_converter(sc, iconv_strncat_in_locale); + return; + } +#endif + + if (sc->flag & SCONV_BEST_EFFORT) { + if (sc->flag & SCONV_TO_UTF16BE) + add_converter(sc, + best_effort_strncat_to_utf16be); + else + add_converter(sc, + best_effort_strncat_to_utf16le); + } else + /* Make sure we have no converter. */ + sc->nconverter = 0; + return; + } + + /* + * Convert a string from UTF-16BE/LE. + */ + if (sc->flag & SCONV_FROM_UTF16) { + /* + * At least we should normalize a UTF-16BE string. + */ + if (sc->flag & SCONV_NORMALIZATION_D) + add_converter(sc,archive_string_normalize_D); + else if (sc->flag & SCONV_NORMALIZATION_C) + add_converter(sc, archive_string_normalize_C); + + if (sc->flag & SCONV_TO_UTF8) { + /* + * If the current locale is UTF-8, we can translate + * a UTF-16BE/LE string into a UTF-8 string directly. + */ + if (!(sc->flag & + (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C))) + add_converter(sc, + archive_string_append_unicode); + return; + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sc->flag & SCONV_WIN_CP) { + if (sc->flag & SCONV_FROM_UTF16BE) + add_converter(sc, win_strncat_from_utf16be); + else + add_converter(sc, win_strncat_from_utf16le); + return; + } +#endif + +#if defined(HAVE_ICONV) + if (sc->cd != (iconv_t)-1) { + add_converter(sc, iconv_strncat_in_locale); + return; + } +#endif + + if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE)) + == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE)) + add_converter(sc, best_effort_strncat_from_utf16be); + else if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE)) + == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE)) + add_converter(sc, best_effort_strncat_from_utf16le); + else + /* Make sure we have no converter. */ + sc->nconverter = 0; + return; + } + + if (sc->flag & SCONV_FROM_UTF8) { + /* + * At least we should normalize a UTF-8 string. + */ + if (sc->flag & SCONV_NORMALIZATION_D) + add_converter(sc,archive_string_normalize_D); + else if (sc->flag & SCONV_NORMALIZATION_C) + add_converter(sc, archive_string_normalize_C); + + /* + * Copy UTF-8 string with a check of CESU-8. + * Apparently, iconv does not check surrogate pairs in UTF-8 + * when both from-charset and to-charset are UTF-8, and then + * we use our UTF-8 copy code. + */ + if (sc->flag & SCONV_TO_UTF8) { + /* + * If the current locale is UTF-8, we can translate + * a UTF-16BE string into a UTF-8 string directly. + */ + if (!(sc->flag & + (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C))) + add_converter(sc, strncat_from_utf8_to_utf8); + return; + } + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * On Windows we can use Windows API for a string conversion. + */ + if (sc->flag & SCONV_WIN_CP) { + add_converter(sc, strncat_in_codepage); + return; + } +#endif + +#if HAVE_ICONV + if (sc->cd != (iconv_t)-1) { + add_converter(sc, iconv_strncat_in_locale); + /* + * iconv generally does not support UTF-8-MAC and so + * we have to the output of iconv from NFC to NFD if + * need. + */ + if ((sc->flag & SCONV_FROM_CHARSET) && + (sc->flag & SCONV_TO_UTF8)) { + if (sc->flag & SCONV_NORMALIZATION_D) + add_converter(sc, archive_string_normalize_D); + } + return; + } +#endif + + /* + * Try conversion in the best effort or no conversion. + */ + if ((sc->flag & SCONV_BEST_EFFORT) || sc->same) + add_converter(sc, best_effort_strncat_in_locale); + else + /* Make sure we have no converter. */ + sc->nconverter = 0; +} + +/* + * Return canonicalized charset-name but this supports just UTF-8, UTF-16BE + * and CP932 which are referenced in create_sconv_object(). + */ +static const char * +canonical_charset_name(const char *charset) +{ + char cs[16]; + char *p; + const char *s; + + if (charset == NULL || charset[0] == '\0' + || strlen(charset) > 15) + return (charset); + + /* Copy name to uppercase. */ + p = cs; + s = charset; + while (*s) { + char c = *s++; + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + *p++ = c; + } + *p++ = '\0'; + + if (strcmp(cs, "UTF-8") == 0 || + strcmp(cs, "UTF8") == 0) + return ("UTF-8"); + if (strcmp(cs, "UTF-16BE") == 0 || + strcmp(cs, "UTF16BE") == 0) + return ("UTF-16BE"); + if (strcmp(cs, "UTF-16LE") == 0 || + strcmp(cs, "UTF16LE") == 0) + return ("UTF-16LE"); + if (strcmp(cs, "CP932") == 0) + return ("CP932"); + return (charset); +} + +/* + * Create a string conversion object. + */ +static struct archive_string_conv * +create_sconv_object(const char *fc, const char *tc, + unsigned current_codepage, int flag) +{ + struct archive_string_conv *sc; + + sc = calloc(1, sizeof(*sc)); + if (sc == NULL) + return (NULL); + sc->next = NULL; + sc->from_charset = strdup(fc); + if (sc->from_charset == NULL) { + free(sc); + return (NULL); + } + sc->to_charset = strdup(tc); + if (sc->to_charset == NULL) { + free(sc->from_charset); + free(sc); + return (NULL); + } + archive_string_init(&sc->utftmp); + + if (flag & SCONV_TO_CHARSET) { + /* + * Convert characters from the current locale charset to + * a specified charset. + */ + sc->from_cp = current_codepage; + sc->to_cp = make_codepage_from_charset(tc); +#if defined(_WIN32) && !defined(__CYGWIN__) + if (IsValidCodePage(sc->to_cp)) + flag |= SCONV_WIN_CP; +#endif + } else if (flag & SCONV_FROM_CHARSET) { + /* + * Convert characters from a specified charset to + * the current locale charset. + */ + sc->to_cp = current_codepage; + sc->from_cp = make_codepage_from_charset(fc); +#if defined(_WIN32) && !defined(__CYGWIN__) + if (IsValidCodePage(sc->from_cp)) + flag |= SCONV_WIN_CP; +#endif + } + + /* + * Check if "from charset" and "to charset" are the same. + */ + if (strcmp(fc, tc) == 0 || + (sc->from_cp != (unsigned)-1 && sc->from_cp == sc->to_cp)) + sc->same = 1; + else + sc->same = 0; + + /* + * Mark if "from charset" or "to charset" are UTF-8 or UTF-16BE/LE. + */ + if (strcmp(tc, "UTF-8") == 0) + flag |= SCONV_TO_UTF8; + else if (strcmp(tc, "UTF-16BE") == 0) + flag |= SCONV_TO_UTF16BE; + else if (strcmp(tc, "UTF-16LE") == 0) + flag |= SCONV_TO_UTF16LE; + if (strcmp(fc, "UTF-8") == 0) + flag |= SCONV_FROM_UTF8; + else if (strcmp(fc, "UTF-16BE") == 0) + flag |= SCONV_FROM_UTF16BE; + else if (strcmp(fc, "UTF-16LE") == 0) + flag |= SCONV_FROM_UTF16LE; +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sc->to_cp == CP_UTF8) + flag |= SCONV_TO_UTF8; + else if (sc->to_cp == CP_UTF16BE) + flag |= SCONV_TO_UTF16BE | SCONV_WIN_CP; + else if (sc->to_cp == CP_UTF16LE) + flag |= SCONV_TO_UTF16LE | SCONV_WIN_CP; + if (sc->from_cp == CP_UTF8) + flag |= SCONV_FROM_UTF8; + else if (sc->from_cp == CP_UTF16BE) + flag |= SCONV_FROM_UTF16BE | SCONV_WIN_CP; + else if (sc->from_cp == CP_UTF16LE) + flag |= SCONV_FROM_UTF16LE | SCONV_WIN_CP; +#endif + + /* + * Set a flag for Unicode NFD. Usually iconv cannot correctly + * handle it. So we have to translate NFD characters to NFC ones + * ourselves before iconv handles. Another reason is to prevent + * that the same sight of two filenames, one is NFC and other + * is NFD, would be in its directory. + * On Mac OS X, although its filesystem layer automatically + * convert filenames to NFD, it would be useful for filename + * comparing to find out the same filenames that we normalize + * that to be NFD ourselves. + */ + if ((flag & SCONV_FROM_CHARSET) && + (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) { +#if defined(__APPLE__) + if (flag & SCONV_TO_UTF8) + flag |= SCONV_NORMALIZATION_D; + else +#endif + flag |= SCONV_NORMALIZATION_C; + } +#if defined(__APPLE__) + /* + * In case writing an archive file, make sure that a filename + * going to be passed to iconv is a Unicode NFC string since + * a filename in HFS Plus filesystem is a Unicode NFD one and + * iconv cannot handle it with "UTF-8" charset. It is simpler + * than a use of "UTF-8-MAC" charset. + */ + if ((flag & SCONV_TO_CHARSET) && + (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + !(flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) + flag |= SCONV_NORMALIZATION_C; + /* + * In case reading an archive file. make sure that a filename + * will be passed to users is a Unicode NFD string in order to + * correctly compare the filename with other one which comes + * from HFS Plus filesystem. + */ + if ((flag & SCONV_FROM_CHARSET) && + !(flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + (flag & SCONV_TO_UTF8)) + flag |= SCONV_NORMALIZATION_D; +#endif + +#if defined(HAVE_ICONV) + sc->cd_w = (iconv_t)-1; + /* + * Create an iconv object. + */ + if (((flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) && + (flag & (SCONV_FROM_UTF8 | SCONV_FROM_UTF16))) || + (flag & SCONV_WIN_CP)) { + /* This case we won't use iconv. */ + sc->cd = (iconv_t)-1; + } else { + sc->cd = iconv_open(tc, fc); + if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) { + /* + * Unfortunately, all of iconv implements do support + * "CP932" character-set, so we should use "SJIS" + * instead if iconv_open failed. + */ + if (strcmp(tc, "CP932") == 0) + sc->cd = iconv_open("SJIS", fc); + else if (strcmp(fc, "CP932") == 0) + sc->cd = iconv_open(tc, "SJIS"); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * archive_mstring on Windows directly convert multi-bytes + * into archive_wstring in order not to depend on locale + * so that you can do a I18N programming. This will be + * used only in archive_mstring_copy_mbs_len_l so far. + */ + if (flag & SCONV_FROM_CHARSET) { + sc->cd_w = iconv_open("UTF-8", fc); + if (sc->cd_w == (iconv_t)-1 && + (sc->flag & SCONV_BEST_EFFORT)) { + if (strcmp(fc, "CP932") == 0) + sc->cd_w = iconv_open("UTF-8", "SJIS"); + } + } +#endif /* _WIN32 && !__CYGWIN__ */ + } +#endif /* HAVE_ICONV */ + + sc->flag = flag; + + /* + * Set up converters. + */ + setup_converter(sc); + + return (sc); +} + +/* + * Free a string conversion object. + */ +static void +free_sconv_object(struct archive_string_conv *sc) +{ + free(sc->from_charset); + free(sc->to_charset); + archive_string_free(&sc->utftmp); +#if HAVE_ICONV + if (sc->cd != (iconv_t)-1) + iconv_close(sc->cd); + if (sc->cd_w != (iconv_t)-1) + iconv_close(sc->cd_w); +#endif + free(sc); +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +static unsigned +my_atoi(const char *p) +{ + unsigned cp; + + cp = 0; + while (*p) { + if (*p >= '0' && *p <= '9') + cp = cp * 10 + (*p - '0'); + else + return (-1); + p++; + } + return (cp); +} + +/* + * Translate Charset name (as used by iconv) into CodePage (as used by Windows) + * Return -1 if failed. + * + * Note: This translation code may be insufficient. + */ +static struct charset { + const char *name; + unsigned cp; +} charsets[] = { + /* MUST BE SORTED! */ + {"ASCII", 1252}, + {"ASMO-708", 708}, + {"BIG5", 950}, + {"CHINESE", 936}, + {"CP367", 1252}, + {"CP819", 1252}, + {"CP1025", 21025}, + {"DOS-720", 720}, + {"DOS-862", 862}, + {"EUC-CN", 51936}, + {"EUC-JP", 51932}, + {"EUC-KR", 949}, + {"EUCCN", 51936}, + {"EUCJP", 51932}, + {"EUCKR", 949}, + {"GB18030", 54936}, + {"GB2312", 936}, + {"HEBREW", 1255}, + {"HZ-GB-2312", 52936}, + {"IBM273", 20273}, + {"IBM277", 20277}, + {"IBM278", 20278}, + {"IBM280", 20280}, + {"IBM284", 20284}, + {"IBM285", 20285}, + {"IBM290", 20290}, + {"IBM297", 20297}, + {"IBM367", 1252}, + {"IBM420", 20420}, + {"IBM423", 20423}, + {"IBM424", 20424}, + {"IBM819", 1252}, + {"IBM871", 20871}, + {"IBM880", 20880}, + {"IBM905", 20905}, + {"IBM924", 20924}, + {"ISO-8859-1", 28591}, + {"ISO-8859-13", 28603}, + {"ISO-8859-15", 28605}, + {"ISO-8859-2", 28592}, + {"ISO-8859-3", 28593}, + {"ISO-8859-4", 28594}, + {"ISO-8859-5", 28595}, + {"ISO-8859-6", 28596}, + {"ISO-8859-7", 28597}, + {"ISO-8859-8", 28598}, + {"ISO-8859-9", 28599}, + {"ISO8859-1", 28591}, + {"ISO8859-13", 28603}, + {"ISO8859-15", 28605}, + {"ISO8859-2", 28592}, + {"ISO8859-3", 28593}, + {"ISO8859-4", 28594}, + {"ISO8859-5", 28595}, + {"ISO8859-6", 28596}, + {"ISO8859-7", 28597}, + {"ISO8859-8", 28598}, + {"ISO8859-9", 28599}, + {"JOHAB", 1361}, + {"KOI8-R", 20866}, + {"KOI8-U", 21866}, + {"KS_C_5601-1987", 949}, + {"LATIN1", 1252}, + {"LATIN2", 28592}, + {"MACINTOSH", 10000}, + {"SHIFT-JIS", 932}, + {"SHIFT_JIS", 932}, + {"SJIS", 932}, + {"US", 1252}, + {"US-ASCII", 1252}, + {"UTF-16", 1200}, + {"UTF-16BE", 1201}, + {"UTF-16LE", 1200}, + {"UTF-8", CP_UTF8}, + {"X-EUROPA", 29001}, + {"X-MAC-ARABIC", 10004}, + {"X-MAC-CE", 10029}, + {"X-MAC-CHINESEIMP", 10008}, + {"X-MAC-CHINESETRAD", 10002}, + {"X-MAC-CROATIAN", 10082}, + {"X-MAC-CYRILLIC", 10007}, + {"X-MAC-GREEK", 10006}, + {"X-MAC-HEBREW", 10005}, + {"X-MAC-ICELANDIC", 10079}, + {"X-MAC-JAPANESE", 10001}, + {"X-MAC-KOREAN", 10003}, + {"X-MAC-ROMANIAN", 10010}, + {"X-MAC-THAI", 10021}, + {"X-MAC-TURKISH", 10081}, + {"X-MAC-UKRAINIAN", 10017}, +}; +static unsigned +make_codepage_from_charset(const char *charset) +{ + char cs[16]; + char *p; + unsigned cp; + int a, b; + + if (charset == NULL || strlen(charset) > 15) + return -1; + + /* Copy name to uppercase. */ + p = cs; + while (*charset) { + char c = *charset++; + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + *p++ = c; + } + *p++ = '\0'; + cp = -1; + + /* Look it up in the table first, so that we can easily + * override CP367, which we map to 1252 instead of 367. */ + a = 0; + b = sizeof(charsets)/sizeof(charsets[0]); + while (b > a) { + int c = (b + a) / 2; + int r = strcmp(charsets[c].name, cs); + if (r < 0) + a = c + 1; + else if (r > 0) + b = c; + else + return charsets[c].cp; + } + + /* If it's not in the table, try to parse it. */ + switch (*cs) { + case 'C': + if (cs[1] == 'P' && cs[2] >= '0' && cs[2] <= '9') { + cp = my_atoi(cs + 2); + } else if (strcmp(cs, "CP_ACP") == 0) + cp = get_current_codepage(); + else if (strcmp(cs, "CP_OEMCP") == 0) + cp = get_current_oemcp(); + break; + case 'I': + if (cs[1] == 'B' && cs[2] == 'M' && + cs[3] >= '0' && cs[3] <= '9') { + cp = my_atoi(cs + 3); + } + break; + case 'W': + if (strncmp(cs, "WINDOWS-", 8) == 0) { + cp = my_atoi(cs + 8); + if (cp != 874 && (cp < 1250 || cp > 1258)) + cp = -1;/* This may invalid code. */ + } + break; + } + return (cp); +} + +/* + * Return ANSI Code Page of current locale set by setlocale(). + */ +static unsigned +get_current_codepage(void) +{ + char *locale, *p; + unsigned cp; + + locale = setlocale(LC_CTYPE, NULL); + if (locale == NULL) + return (GetACP()); + if (locale[0] == 'C' && locale[1] == '\0') + return (CP_C_LOCALE); + p = strrchr(locale, '.'); + if (p == NULL) + return (GetACP()); + cp = my_atoi(p+1); + if (cp <= 0) + return (GetACP()); + return (cp); +} + +/* + * Translation table between Locale Name and ACP/OEMCP. + */ +static struct { + unsigned acp; + unsigned ocp; + const char *locale; +} acp_ocp_map[] = { + { 950, 950, "Chinese_Taiwan" }, + { 936, 936, "Chinese_People's Republic of China" }, + { 950, 950, "Chinese_Taiwan" }, + { 1250, 852, "Czech_Czech Republic" }, + { 1252, 850, "Danish_Denmark" }, + { 1252, 850, "Dutch_Netherlands" }, + { 1252, 850, "Dutch_Belgium" }, + { 1252, 437, "English_United States" }, + { 1252, 850, "English_Australia" }, + { 1252, 850, "English_Canada" }, + { 1252, 850, "English_New Zealand" }, + { 1252, 850, "English_United Kingdom" }, + { 1252, 437, "English_United States" }, + { 1252, 850, "Finnish_Finland" }, + { 1252, 850, "French_France" }, + { 1252, 850, "French_Belgium" }, + { 1252, 850, "French_Canada" }, + { 1252, 850, "French_Switzerland" }, + { 1252, 850, "German_Germany" }, + { 1252, 850, "German_Austria" }, + { 1252, 850, "German_Switzerland" }, + { 1253, 737, "Greek_Greece" }, + { 1250, 852, "Hungarian_Hungary" }, + { 1252, 850, "Icelandic_Iceland" }, + { 1252, 850, "Italian_Italy" }, + { 1252, 850, "Italian_Switzerland" }, + { 932, 932, "Japanese_Japan" }, + { 949, 949, "Korean_Korea" }, + { 1252, 850, "Norwegian (BokmOl)_Norway" }, + { 1252, 850, "Norwegian (BokmOl)_Norway" }, + { 1252, 850, "Norwegian-Nynorsk_Norway" }, + { 1250, 852, "Polish_Poland" }, + { 1252, 850, "Portuguese_Portugal" }, + { 1252, 850, "Portuguese_Brazil" }, + { 1251, 866, "Russian_Russia" }, + { 1250, 852, "Slovak_Slovakia" }, + { 1252, 850, "Spanish_Spain" }, + { 1252, 850, "Spanish_Mexico" }, + { 1252, 850, "Spanish_Spain" }, + { 1252, 850, "Swedish_Sweden" }, + { 1254, 857, "Turkish_Turkey" }, + { 0, 0, NULL} +}; + +/* + * Return OEM Code Page of current locale set by setlocale(). + */ +static unsigned +get_current_oemcp(void) +{ + int i; + char *locale, *p; + size_t len; + + locale = setlocale(LC_CTYPE, NULL); + if (locale == NULL) + return (GetOEMCP()); + if (locale[0] == 'C' && locale[1] == '\0') + return (CP_C_LOCALE); + + p = strrchr(locale, '.'); + if (p == NULL) + return (GetOEMCP()); + len = p - locale; + for (i = 0; acp_ocp_map[i].acp; i++) { + if (strncmp(acp_ocp_map[i].locale, locale, len) == 0) + return (acp_ocp_map[i].ocp); + } + return (GetOEMCP()); +} +#else + +/* + * POSIX platform does not use CodePage. + */ + +static unsigned +get_current_codepage(void) +{ + return (-1);/* Unknown */ +} +static unsigned +make_codepage_from_charset(const char *charset) +{ + (void)charset; /* UNUSED */ + return (-1);/* Unknown */ +} +static unsigned +get_current_oemcp(void) +{ + return (-1);/* Unknown */ +} + +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ + +/* + * Return a string conversion object. + */ +static struct archive_string_conv * +get_sconv_object(struct archive *a, const char *fc, const char *tc, int flag) +{ + struct archive_string_conv *sc; + unsigned current_codepage; + + /* Check if we have made the sconv object. */ + sc = find_sconv_object(a, fc, tc); + if (sc != NULL) + return (sc); + + if (a == NULL) + current_codepage = get_current_codepage(); + else + current_codepage = a->current_codepage; + + sc = create_sconv_object(canonical_charset_name(fc), + canonical_charset_name(tc), current_codepage, flag); + if (sc == NULL) { + if (a != NULL) + archive_set_error(a, ENOMEM, + "Could not allocate memory for " + "a string conversion object"); + return (NULL); + } + + /* + * If there is no converter for current string conversion object, + * we cannot handle this conversion. + */ + if (sc->nconverter == 0) { + if (a != NULL) { +#if HAVE_ICONV + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "iconv_open failed : Cannot handle ``%s''", + (flag & SCONV_TO_CHARSET)?tc:fc); +#else + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "A character-set conversion not fully supported " + "on this platform"); +#endif + } + /* Failed; free a sconv object. */ + free_sconv_object(sc); + return (NULL); + } + + /* + * Success! + */ + if (a != NULL) + add_sconv_object(a, sc); + return (sc); +} + +static const char * +get_current_charset(struct archive *a) +{ + const char *cur_charset; + + if (a == NULL) + cur_charset = default_iconv_charset(""); + else { + cur_charset = default_iconv_charset(a->current_code); + if (a->current_code == NULL) { + a->current_code = strdup(cur_charset); + a->current_codepage = get_current_codepage(); + a->current_oemcp = get_current_oemcp(); + } + } + return (cur_charset); +} + +/* + * Make and Return a string conversion object. + * Return NULL if the platform does not support the specified conversion + * and best_effort is 0. + * If best_effort is set, A string conversion object must be returned + * unless memory allocation for the object fails, but the conversion + * might fail when non-ASCII code is found. + */ +struct archive_string_conv * +archive_string_conversion_to_charset(struct archive *a, const char *charset, + int best_effort) +{ + int flag = SCONV_TO_CHARSET; + + if (best_effort) + flag |= SCONV_BEST_EFFORT; + return (get_sconv_object(a, get_current_charset(a), charset, flag)); +} + +struct archive_string_conv * +archive_string_conversion_from_charset(struct archive *a, const char *charset, + int best_effort) +{ + int flag = SCONV_FROM_CHARSET; + + if (best_effort) + flag |= SCONV_BEST_EFFORT; + return (get_sconv_object(a, charset, get_current_charset(a), flag)); +} + +/* + * archive_string_default_conversion_*_archive() are provided for Windows + * platform because other archiver application use CP_OEMCP for + * MultiByteToWideChar() and WideCharToMultiByte() for the filenames + * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP + * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP). + * So we should make a string conversion between CP_ACP and CP_OEMCP + * for compatibility. + */ +#if defined(_WIN32) && !defined(__CYGWIN__) +struct archive_string_conv * +archive_string_default_conversion_for_read(struct archive *a) +{ + const char *cur_charset = get_current_charset(a); + char oemcp[16]; + + /* NOTE: a check of cur_charset is unneeded but we need + * that get_current_charset() has been surely called at + * this time whatever C compiler optimized. */ + if (cur_charset != NULL && + (a->current_codepage == CP_C_LOCALE || + a->current_codepage == a->current_oemcp)) + return (NULL);/* no conversion. */ + + _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp); + /* Make sure a null termination must be set. */ + oemcp[sizeof(oemcp)-1] = '\0'; + return (get_sconv_object(a, oemcp, cur_charset, + SCONV_FROM_CHARSET)); +} + +struct archive_string_conv * +archive_string_default_conversion_for_write(struct archive *a) +{ + const char *cur_charset = get_current_charset(a); + char oemcp[16]; + + /* NOTE: a check of cur_charset is unneeded but we need + * that get_current_charset() has been surely called at + * this time whatever C compiler optimized. */ + if (cur_charset != NULL && + (a->current_codepage == CP_C_LOCALE || + a->current_codepage == a->current_oemcp)) + return (NULL);/* no conversion. */ + + _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp); + /* Make sure a null termination must be set. */ + oemcp[sizeof(oemcp)-1] = '\0'; + return (get_sconv_object(a, cur_charset, oemcp, + SCONV_TO_CHARSET)); +} +#else +struct archive_string_conv * +archive_string_default_conversion_for_read(struct archive *a) +{ + (void)a; /* UNUSED */ + return (NULL); +} + +struct archive_string_conv * +archive_string_default_conversion_for_write(struct archive *a) +{ + (void)a; /* UNUSED */ + return (NULL); +} +#endif + +/* + * Dispose of all character conversion objects in the archive object. + */ +void +archive_string_conversion_free(struct archive *a) +{ + struct archive_string_conv *sc; + struct archive_string_conv *sc_next; + + for (sc = a->sconv; sc != NULL; sc = sc_next) { + sc_next = sc->next; + free_sconv_object(sc); + } + a->sconv = NULL; + free(a->current_code); + a->current_code = NULL; +} + +/* + * Return a conversion charset name. + */ +const char * +archive_string_conversion_charset_name(struct archive_string_conv *sc) +{ + if (sc->flag & SCONV_TO_CHARSET) + return (sc->to_charset); + else + return (sc->from_charset); +} + +/* + * Change the behavior of a string conversion. + */ +void +archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt) +{ + switch (opt) { + /* + * A filename in UTF-8 was made with libarchive 2.x in a wrong + * assumption that wchar_t was Unicode. + * This option enables simulating the assumption in order to read + * that filename correctly. + */ + case SCONV_SET_OPT_UTF8_LIBARCHIVE2X: +#if (defined(_WIN32) && !defined(__CYGWIN__)) \ + || defined(__STDC_ISO_10646__) || defined(__APPLE__) + /* + * Nothing to do for it since wchar_t on these platforms + * is really Unicode. + */ + (void)sc; /* UNUSED */ +#else + if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) { + sc->flag |= SCONV_UTF8_LIBARCHIVE_2; + /* Set up string converters. */ + setup_converter(sc); + } +#endif + break; + case SCONV_SET_OPT_NORMALIZATION_C: + if ((sc->flag & SCONV_NORMALIZATION_C) == 0) { + sc->flag |= SCONV_NORMALIZATION_C; + sc->flag &= ~SCONV_NORMALIZATION_D; + /* Set up string converters. */ + setup_converter(sc); + } + break; + case SCONV_SET_OPT_NORMALIZATION_D: +#if defined(HAVE_ICONV) + /* + * If iconv will take the string, do not change the + * setting of the normalization. + */ + if (!(sc->flag & SCONV_WIN_CP) && + (sc->flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) && + !(sc->flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8))) + break; +#endif + if ((sc->flag & SCONV_NORMALIZATION_D) == 0) { + sc->flag |= SCONV_NORMALIZATION_D; + sc->flag &= ~SCONV_NORMALIZATION_C; + /* Set up string converters. */ + setup_converter(sc); + } + break; + default: + break; + } +} + +/* + * + * Copy one archive_string to another in locale conversion. + * + * archive_strncat_l(); + * archive_strncpy_l(); + * + */ + +static size_t +mbsnbytes(const void *_p, size_t n) +{ + size_t s; + const char *p, *pp; + + if (_p == NULL) + return (0); + p = (const char *)_p; + + /* Like strlen(p), except won't examine positions beyond p[n]. */ + s = 0; + pp = p; + while (s < n && *pp) { + pp++; + s++; + } + return (s); +} + +static size_t +utf16nbytes(const void *_p, size_t n) +{ + size_t s; + const char *p, *pp; + + if (_p == NULL) + return (0); + p = (const char *)_p; + + /* Like strlen(p), except won't examine positions beyond p[n]. */ + s = 0; + pp = p; + n >>= 1; + while (s < n && (pp[0] || pp[1])) { + pp += 2; + s++; + } + return (s<<1); +} + +int +archive_strncpy_l(struct archive_string *as, const void *_p, size_t n, + struct archive_string_conv *sc) +{ + as->length = 0; + return (archive_strncat_l(as, _p, n, sc)); +} + +int +archive_strncat_l(struct archive_string *as, const void *_p, size_t n, + struct archive_string_conv *sc) +{ + const void *s; + size_t length = 0; + int i, r = 0, r2; + + if (_p != NULL && n > 0) { + if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) + length = utf16nbytes(_p, n); + else + length = mbsnbytes(_p, n); + } + + /* We must allocate memory even if there is no data for conversion + * or copy. This simulates archive_string_append behavior. */ + if (length == 0) { + int tn = 1; + if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) + tn = 2; + if (archive_string_ensure(as, as->length + tn) == NULL) + return (-1); + as->s[as->length] = 0; + if (tn == 2) + as->s[as->length+1] = 0; + return (0); + } + + /* + * If sc is NULL, we just make a copy. + */ + if (sc == NULL) { + if (archive_string_append(as, _p, length) == NULL) + return (-1);/* No memory */ + return (0); + } + + s = _p; + i = 0; + if (sc->nconverter > 1) { + sc->utftmp.length = 0; + r2 = sc->converter[0](&(sc->utftmp), s, length, sc); + if (r2 != 0 && errno == ENOMEM) + return (r2); + if (r > r2) + r = r2; + s = sc->utftmp.s; + length = sc->utftmp.length; + ++i; + } + r2 = sc->converter[i](as, s, length, sc); + if (r > r2) + r = r2; + return (r); +} + +#if HAVE_ICONV + +/* + * Return -1 if conversion fails. + */ +static int +iconv_strncat_in_locale(struct archive_string *as, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + ICONV_CONST char *itp; + size_t remaining; + iconv_t cd; + char *outp; + size_t avail, bs; + int return_value = 0; /* success */ + int to_size, from_size; + + if (sc->flag & SCONV_TO_UTF16) + to_size = 2; + else + to_size = 1; + if (sc->flag & SCONV_FROM_UTF16) + from_size = 2; + else + from_size = 1; + + if (archive_string_ensure(as, as->length + length*2+to_size) == NULL) + return (-1); + + cd = sc->cd; + itp = (char *)(uintptr_t)_p; + remaining = length; + outp = as->s + as->length; + avail = as->buffer_length - as->length - to_size; + while (remaining >= (size_t)from_size) { + size_t result = iconv(cd, &itp, &remaining, &outp, &avail); + + if (result != (size_t)-1) + break; /* Conversion completed. */ + + if (errno == EILSEQ || errno == EINVAL) { + /* + * If an output charset is UTF-8 or UTF-16BE/LE, + * unknown character should be U+FFFD + * (replacement character). + */ + if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) { + size_t rbytes; + if (sc->flag & SCONV_TO_UTF8) + rbytes = sizeof(utf8_replacement_char); + else + rbytes = 2; + + if (avail < rbytes) { + as->length = outp - as->s; + bs = as->buffer_length + + (remaining * to_size) + rbytes; + if (NULL == + archive_string_ensure(as, bs)) + return (-1); + outp = as->s + as->length; + avail = as->buffer_length + - as->length - to_size; + } + if (sc->flag & SCONV_TO_UTF8) + memcpy(outp, utf8_replacement_char, sizeof(utf8_replacement_char)); + else if (sc->flag & SCONV_TO_UTF16BE) + archive_be16enc(outp, UNICODE_R_CHAR); + else + archive_le16enc(outp, UNICODE_R_CHAR); + outp += rbytes; + avail -= rbytes; + } else { + /* Skip the illegal input bytes. */ + *outp++ = '?'; + avail--; + } + itp += from_size; + remaining -= from_size; + return_value = -1; /* failure */ + } else { + /* E2BIG no output buffer, + * Increase an output buffer. */ + as->length = outp - as->s; + bs = as->buffer_length + remaining * 2; + if (NULL == archive_string_ensure(as, bs)) + return (-1); + outp = as->s + as->length; + avail = as->buffer_length - as->length - to_size; + } + } + as->length = outp - as->s; + as->s[as->length] = 0; + if (to_size == 2) + as->s[as->length+1] = 0; + return (return_value); +} + +#endif /* HAVE_ICONV */ + + +#if defined(_WIN32) && !defined(__CYGWIN__) + +/* + * Translate a string from a some CodePage to an another CodePage by + * Windows APIs, and copy the result. Return -1 if conversion fails. + */ +static int +strncat_in_codepage(struct archive_string *as, + const void *_p, size_t length, struct archive_string_conv *sc) +{ + const char *s = (const char *)_p; + struct archive_wstring aws; + size_t l; + int r, saved_flag; + + archive_string_init(&aws); + saved_flag = sc->flag; + sc->flag &= ~(SCONV_NORMALIZATION_D | SCONV_NORMALIZATION_C); + r = archive_wstring_append_from_mbs_in_codepage(&aws, s, length, sc); + sc->flag = saved_flag; + if (r != 0) { + archive_wstring_free(&aws); + if (errno != ENOMEM) + archive_string_append(as, s, length); + return (-1); + } + + l = as->length; + r = archive_string_append_from_wcs_in_codepage( + as, aws.s, aws.length, sc); + if (r != 0 && errno != ENOMEM && l == as->length) + archive_string_append(as, s, length); + archive_wstring_free(&aws); + return (r); +} + +/* + * Test whether MBS ==> WCS is okay. + */ +static int +invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) +{ + const char *p = (const char *)_p; + unsigned codepage; + DWORD mbflag = MB_ERR_INVALID_CHARS; + + if (sc->flag & SCONV_FROM_CHARSET) + codepage = sc->to_cp; + else + codepage = sc->from_cp; + + if (codepage == CP_C_LOCALE) + return (0); + if (codepage != CP_UTF8) + mbflag |= MB_PRECOMPOSED; + + if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0) + return (-1); /* Invalid */ + return (0); /* Okay */ +} + +#else + +/* + * Test whether MBS ==> WCS is okay. + */ +static int +invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) +{ + const char *p = (const char *)_p; + size_t r; + +#if HAVE_MBRTOWC + mbstate_t shift_state; + + memset(&shift_state, 0, sizeof(shift_state)); +#else + /* Clear the shift state before starting. */ + mbtowc(NULL, NULL, 0); +#endif + while (n) { + wchar_t wc; + +#if HAVE_MBRTOWC + r = mbrtowc(&wc, p, n, &shift_state); +#else + r = mbtowc(&wc, p, n); +#endif + if (r == (size_t)-1 || r == (size_t)-2) + return (-1);/* Invalid. */ + if (r == 0) + break; + p += r; + n -= r; + } + (void)sc; /* UNUSED */ + return (0); /* All Okey. */ +} + +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ + +/* + * Basically returns -1 because we cannot make a conversion of charset + * without iconv but in some cases this would return 0. + * Returns 0 if all copied characters are ASCII. + * Returns 0 if both from-locale and to-locale are the same and those + * can be WCS with no error. + */ +static int +best_effort_strncat_in_locale(struct archive_string *as, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + size_t remaining; + const uint8_t *itp; + int return_value = 0; /* success */ + + /* + * If both from-locale and to-locale is the same, this makes a copy. + * And then this checks all copied MBS can be WCS if so returns 0. + */ + if (sc->same) { + if (archive_string_append(as, _p, length) == NULL) + return (-1);/* No memory */ + return (invalid_mbs(_p, length, sc)); + } + + /* + * If a character is ASCII, this just copies it. If not, this + * assigns '?' character instead but in UTF-8 locale this assigns + * byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD, + * a Replacement Character in Unicode. + */ + + remaining = length; + itp = (const uint8_t *)_p; + while (*itp && remaining > 0) { + if (*itp > 127) { + // Non-ASCII: Substitute with suitable replacement + if (sc->flag & SCONV_TO_UTF8) { + if (archive_string_append(as, utf8_replacement_char, sizeof(utf8_replacement_char)) == NULL) { + __archive_errx(1, "Out of memory"); + } + } else { + archive_strappend_char(as, '?'); + } + return_value = -1; + } else { + archive_strappend_char(as, *itp); + } + ++itp; + } + return (return_value); +} + + +/* + * Unicode conversion functions. + * - UTF-8 <===> UTF-8 in removing surrogate pairs. + * - UTF-8 NFD ===> UTF-8 NFC in removing surrogate pairs. + * - UTF-8 made by libarchive 2.x ===> UTF-8. + * - UTF-16BE <===> UTF-8. + * + */ + +/* + * Utility to convert a single UTF-8 sequence. + * + * Usually return used bytes, return used byte in negative value when + * a unicode character is replaced with U+FFFD. + * See also http://unicode.org/review/pr-121.html Public Review Issue #121 + * Recommended Practice for Replacement Characters. + */ +static int +_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) +{ + static const char utf8_count[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ + }; + int ch, i; + int cnt; + uint32_t wc; + + /* Sanity check. */ + if (n == 0) + return (0); + /* + * Decode 1-4 bytes depending on the value of the first byte. + */ + ch = (unsigned char)*s; + if (ch == 0) + return (0); /* Standard: return 0 for end-of-string. */ + cnt = utf8_count[ch]; + + /* Invalid sequence or there are not plenty bytes. */ + if ((int)n < cnt) { + cnt = (int)n; + for (i = 1; i < cnt; i++) { + if ((s[i] & 0xc0) != 0x80) { + cnt = i; + break; + } + } + goto invalid_sequence; + } + + /* Make a Unicode code point from a single UTF-8 sequence. */ + switch (cnt) { + case 1: /* 1 byte sequence. */ + *pwc = ch & 0x7f; + return (cnt); + case 2: /* 2 bytes sequence. */ + if ((s[1] & 0xc0) != 0x80) { + cnt = 1; + goto invalid_sequence; + } + *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); + return (cnt); + case 3: /* 3 bytes sequence. */ + if ((s[1] & 0xc0) != 0x80) { + cnt = 1; + goto invalid_sequence; + } + if ((s[2] & 0xc0) != 0x80) { + cnt = 2; + goto invalid_sequence; + } + wc = ((ch & 0x0f) << 12) + | ((s[1] & 0x3f) << 6) + | (s[2] & 0x3f); + if (wc < 0x800) + goto invalid_sequence;/* Overlong sequence. */ + break; + case 4: /* 4 bytes sequence. */ + if ((s[1] & 0xc0) != 0x80) { + cnt = 1; + goto invalid_sequence; + } + if ((s[2] & 0xc0) != 0x80) { + cnt = 2; + goto invalid_sequence; + } + if ((s[3] & 0xc0) != 0x80) { + cnt = 3; + goto invalid_sequence; + } + wc = ((ch & 0x07) << 18) + | ((s[1] & 0x3f) << 12) + | ((s[2] & 0x3f) << 6) + | (s[3] & 0x3f); + if (wc < 0x10000) + goto invalid_sequence;/* Overlong sequence. */ + break; + default: /* Others are all invalid sequence. */ + if (ch == 0xc0 || ch == 0xc1) + cnt = 2; + else if (ch >= 0xf5 && ch <= 0xf7) + cnt = 4; + else if (ch >= 0xf8 && ch <= 0xfb) + cnt = 5; + else if (ch == 0xfc || ch == 0xfd) + cnt = 6; + else + cnt = 1; + if ((int)n < cnt) + cnt = (int)n; + for (i = 1; i < cnt; i++) { + if ((s[i] & 0xc0) != 0x80) { + cnt = i; + break; + } + } + goto invalid_sequence; + } + + /* The code point larger than 0x10FFFF is not legal + * Unicode values. */ + if (wc > UNICODE_MAX) + goto invalid_sequence; + /* Correctly gets a Unicode, returns used bytes. */ + *pwc = wc; + return (cnt); +invalid_sequence: + *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */ + return (cnt * -1); +} + +static int +utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) +{ + int cnt; + + cnt = _utf8_to_unicode(pwc, s, n); + /* Any of Surrogate pair is not legal Unicode values. */ + if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc)) + return (-3); + return (cnt); +} + +static inline uint32_t +combine_surrogate_pair(uint32_t uc, uint32_t uc2) +{ + uc -= 0xD800; + uc *= 0x400; + uc += uc2 - 0xDC00; + uc += 0x10000; + return (uc); +} + +/* + * Convert a single UTF-8/CESU-8 sequence to a Unicode code point in + * removing surrogate pairs. + * + * CESU-8: The Compatibility Encoding Scheme for UTF-16. + * + * Usually return used bytes, return used byte in negative value when + * a unicode character is replaced with U+FFFD. + */ +static int +cesu8_to_unicode(uint32_t *pwc, const char *s, size_t n) +{ + uint32_t wc = 0; + int cnt; + + cnt = _utf8_to_unicode(&wc, s, n); + if (cnt == 3 && IS_HIGH_SURROGATE_LA(wc)) { + uint32_t wc2 = 0; + if (n - 3 < 3) { + /* Invalid byte sequence. */ + goto invalid_sequence; + } + cnt = _utf8_to_unicode(&wc2, s+3, n-3); + if (cnt != 3 || !IS_LOW_SURROGATE_LA(wc2)) { + /* Invalid byte sequence. */ + goto invalid_sequence; + } + wc = combine_surrogate_pair(wc, wc2); + cnt = 6; + } else if (cnt == 3 && IS_LOW_SURROGATE_LA(wc)) { + /* Invalid byte sequence. */ + goto invalid_sequence; + } + *pwc = wc; + return (cnt); +invalid_sequence: + *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */ + if (cnt > 0) + cnt *= -1; + return (cnt); +} + +/* + * Convert a Unicode code point to a single UTF-8 sequence. + * + * NOTE:This function does not check if the Unicode is legal or not. + * Please you definitely check it before calling this. + */ +static size_t +unicode_to_utf8(char *p, size_t remaining, uint32_t uc) +{ + char *_p = p; + + /* Invalid Unicode char maps to Replacement character */ + if (uc > UNICODE_MAX) + uc = UNICODE_R_CHAR; + /* Translate code point to UTF8 */ + if (uc <= 0x7f) { + if (remaining == 0) + return (0); + *p++ = (char)uc; + } else if (uc <= 0x7ff) { + if (remaining < 2) + return (0); + *p++ = 0xc0 | ((uc >> 6) & 0x1f); + *p++ = 0x80 | (uc & 0x3f); + } else if (uc <= 0xffff) { + if (remaining < 3) + return (0); + *p++ = 0xe0 | ((uc >> 12) & 0x0f); + *p++ = 0x80 | ((uc >> 6) & 0x3f); + *p++ = 0x80 | (uc & 0x3f); + } else { + if (remaining < 4) + return (0); + *p++ = 0xf0 | ((uc >> 18) & 0x07); + *p++ = 0x80 | ((uc >> 12) & 0x3f); + *p++ = 0x80 | ((uc >> 6) & 0x3f); + *p++ = 0x80 | (uc & 0x3f); + } + return (p - _p); +} + +static int +utf16be_to_unicode(uint32_t *pwc, const char *s, size_t n) +{ + return (utf16_to_unicode(pwc, s, n, 1)); +} + +static int +utf16le_to_unicode(uint32_t *pwc, const char *s, size_t n) +{ + return (utf16_to_unicode(pwc, s, n, 0)); +} + +static int +utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be) +{ + const char *utf16 = s; + unsigned uc; + + if (n == 0) + return (0); + if (n == 1) { + /* set the Replacement Character instead. */ + *pwc = UNICODE_R_CHAR; + return (-1); + } + + if (be) + uc = archive_be16dec(utf16); + else + uc = archive_le16dec(utf16); + utf16 += 2; + + /* If this is a surrogate pair, assemble the full code point.*/ + if (IS_HIGH_SURROGATE_LA(uc)) { + unsigned uc2; + + if (n >= 4) { + if (be) + uc2 = archive_be16dec(utf16); + else + uc2 = archive_le16dec(utf16); + } else + uc2 = 0; + if (IS_LOW_SURROGATE_LA(uc2)) { + uc = combine_surrogate_pair(uc, uc2); + utf16 += 2; + } else { + /* Undescribed code point should be U+FFFD + * (replacement character). */ + *pwc = UNICODE_R_CHAR; + return (-2); + } + } + + /* + * Surrogate pair values(0xd800 through 0xdfff) are only + * used by UTF-16, so, after above calculation, the code + * must not be surrogate values, and Unicode has no codes + * larger than 0x10ffff. Thus, those are not legal Unicode + * values. + */ + if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) { + /* Undescribed code point should be U+FFFD + * (replacement character). */ + *pwc = UNICODE_R_CHAR; + return (((int)(utf16 - s)) * -1); + } + *pwc = uc; + return ((int)(utf16 - s)); +} + +static size_t +unicode_to_utf16be(char *p, size_t remaining, uint32_t uc) +{ + char *utf16 = p; + + if (uc > 0xffff) { + /* We have a code point that won't fit into a + * wchar_t; convert it to a surrogate pair. */ + if (remaining < 4) + return (0); + uc -= 0x10000; + archive_be16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800); + archive_be16enc(utf16+2, (uc & 0x3ff) + 0xDC00); + return (4); + } else { + if (remaining < 2) + return (0); + archive_be16enc(utf16, uc); + return (2); + } +} + +static size_t +unicode_to_utf16le(char *p, size_t remaining, uint32_t uc) +{ + char *utf16 = p; + + if (uc > 0xffff) { + /* We have a code point that won't fit into a + * wchar_t; convert it to a surrogate pair. */ + if (remaining < 4) + return (0); + uc -= 0x10000; + archive_le16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800); + archive_le16enc(utf16+2, (uc & 0x3ff) + 0xDC00); + return (4); + } else { + if (remaining < 2) + return (0); + archive_le16enc(utf16, uc); + return (2); + } +} + +/* + * Copy UTF-8 string in checking surrogate pair. + * If any surrogate pair are found, it would be canonicalized. + */ +static int +strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) +{ + const char *s; + char *p, *endp; + int n, ret = 0; + + (void)sc; /* UNUSED */ + + if (archive_string_ensure(as, as->length + len + 1) == NULL) + return (-1); + + s = (const char *)_p; + p = as->s + as->length; + endp = as->s + as->buffer_length -1; + do { + uint32_t uc; + const char *ss = s; + size_t w; + + /* + * Forward byte sequence until a conversion of that is needed. + */ + while ((n = utf8_to_unicode(&uc, s, len)) > 0) { + s += n; + len -= n; + } + if (ss < s) { + if (p + (s - ss) > endp) { + as->length = p - as->s; + if (archive_string_ensure(as, + as->buffer_length + len + 1) == NULL) + return (-1); + p = as->s + as->length; + endp = as->s + as->buffer_length -1; + } + + memcpy(p, ss, s - ss); + p += s - ss; + } + + /* + * If n is negative, current byte sequence needs a replacement. + */ + if (n < 0) { + if (n == -3 && IS_SURROGATE_PAIR_LA(uc)) { + /* Current byte sequence may be CESU-8. */ + n = cesu8_to_unicode(&uc, s, len); + } + if (n < 0) { + ret = -1; + n *= -1;/* Use a replaced unicode character. */ + } + + /* Rebuild UTF-8 byte sequence. */ + while ((w = unicode_to_utf8(p, endp - p, uc)) == 0) { + as->length = p - as->s; + if (archive_string_ensure(as, + as->buffer_length + len + 1) == NULL) + return (-1); + p = as->s + as->length; + endp = as->s + as->buffer_length -1; + } + p += w; + s += n; + len -= n; + } + } while (n > 0); + as->length = p - as->s; + as->s[as->length] = '\0'; + return (ret); +} + +static int +archive_string_append_unicode(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) +{ + const char *s; + char *p, *endp; + uint32_t uc; + size_t w; + int n, ret = 0, ts, tm; + int (*parse)(uint32_t *, const char *, size_t); + size_t (*unparse)(char *, size_t, uint32_t); + + if (sc->flag & SCONV_TO_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + } else if (sc->flag & SCONV_TO_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + } else if (sc->flag & SCONV_TO_UTF8) { + unparse = unicode_to_utf8; + ts = 1; + } else { + /* + * This case is going to be converted to another + * character-set through iconv. + */ + if (sc->flag & SCONV_FROM_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + } else if (sc->flag & SCONV_FROM_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + } else { + unparse = unicode_to_utf8; + ts = 1; + } + } + + if (sc->flag & SCONV_FROM_UTF16BE) { + parse = utf16be_to_unicode; + tm = 1; + } else if (sc->flag & SCONV_FROM_UTF16LE) { + parse = utf16le_to_unicode; + tm = 1; + } else { + parse = cesu8_to_unicode; + tm = ts; + } + + if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) + return (-1); + + s = (const char *)_p; + p = as->s + as->length; + endp = as->s + as->buffer_length - ts; + while ((n = parse(&uc, s, len)) != 0) { + if (n < 0) { + /* Use a replaced unicode character. */ + n *= -1; + ret = -1; + } + s += n; + len -= n; + while ((w = unparse(p, endp - p, uc)) == 0) { + /* There is not enough output buffer so + * we have to expand it. */ + as->length = p - as->s; + if (archive_string_ensure(as, + as->buffer_length + len * tm + ts) == NULL) + return (-1); + p = as->s + as->length; + endp = as->s + as->buffer_length - ts; + } + p += w; + } + as->length = p - as->s; + as->s[as->length] = '\0'; + if (ts == 2) + as->s[as->length+1] = '\0'; + return (ret); +} + +/* + * Following Constants for Hangul compositions this information comes from + * Unicode Standard Annex #15 http://unicode.org/reports/tr15/ + */ +#define HC_SBASE 0xAC00 +#define HC_LBASE 0x1100 +#define HC_VBASE 0x1161 +#define HC_TBASE 0x11A7 +#define HC_LCOUNT 19 +#define HC_VCOUNT 21 +#define HC_TCOUNT 28 +#define HC_NCOUNT (HC_VCOUNT * HC_TCOUNT) +#define HC_SCOUNT (HC_LCOUNT * HC_NCOUNT) + +static uint32_t +get_nfc(uint32_t uc, uint32_t uc2) +{ + int t, b; + + t = 0; + b = sizeof(u_composition_table)/sizeof(u_composition_table[0]) -1; + while (b >= t) { + int m = (t + b) / 2; + if (u_composition_table[m].cp1 < uc) + t = m + 1; + else if (u_composition_table[m].cp1 > uc) + b = m - 1; + else if (u_composition_table[m].cp2 < uc2) + t = m + 1; + else if (u_composition_table[m].cp2 > uc2) + b = m - 1; + else + return (u_composition_table[m].nfc); + } + return (0); +} + +#define FDC_MAX 10 /* The maximum number of Following Decomposable + * Characters. */ + +/* + * Update first code point. + */ +#define UPDATE_UC(new_uc) do { \ + uc = new_uc; \ + ucptr = NULL; \ +} while (0) + +/* + * Replace first code point with second code point. + */ +#define REPLACE_UC_WITH_UC2() do { \ + uc = uc2; \ + ucptr = uc2ptr; \ + n = n2; \ +} while (0) + +#define EXPAND_BUFFER() do { \ + as->length = p - as->s; \ + if (archive_string_ensure(as, \ + as->buffer_length + len * tm + ts) == NULL)\ + return (-1); \ + p = as->s + as->length; \ + endp = as->s + as->buffer_length - ts; \ +} while (0) + +#define UNPARSE(p, endp, uc) do { \ + while ((w = unparse(p, (endp) - (p), uc)) == 0) {\ + EXPAND_BUFFER(); \ + } \ + p += w; \ +} while (0) + +/* + * Write first code point. + * If the code point has not be changed from its original code, + * this just copies it from its original buffer pointer. + * If not, this converts it to UTF-8 byte sequence and copies it. + */ +#define WRITE_UC() do { \ + if (ucptr) { \ + if (p + n > endp) \ + EXPAND_BUFFER(); \ + switch (n) { \ + case 4: \ + *p++ = *ucptr++; \ + /* FALL THROUGH */ \ + case 3: \ + *p++ = *ucptr++; \ + /* FALL THROUGH */ \ + case 2: \ + *p++ = *ucptr++; \ + /* FALL THROUGH */ \ + case 1: \ + *p++ = *ucptr; \ + break; \ + } \ + ucptr = NULL; \ + } else { \ + UNPARSE(p, endp, uc); \ + } \ +} while (0) + +/* + * Collect following decomposable code points. + */ +#define COLLECT_CPS(start) do { \ + int _i; \ + for (_i = start; _i < FDC_MAX ; _i++) { \ + nx = parse(&ucx[_i], s, len); \ + if (nx <= 0) \ + break; \ + cx = CCC(ucx[_i]); \ + if (cl >= cx && cl != 228 && cx != 228)\ + break; \ + s += nx; \ + len -= nx; \ + cl = cx; \ + ccx[_i] = cx; \ + } \ + if (_i >= FDC_MAX) { \ + ret = -1; \ + ucx_size = FDC_MAX; \ + } else \ + ucx_size = _i; \ +} while (0) + +/* + * Normalize UTF-8/UTF-16BE characters to Form C and copy the result. + * + * TODO: Convert composition exclusions, which are never converted + * from NFC,NFD,NFKC and NFKD, to Form C. + */ +static int +archive_string_normalize_C(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) +{ + const char *s = (const char *)_p; + char *p, *endp; + uint32_t uc, uc2; + size_t w; + int always_replace, n, n2, ret = 0, spair, ts, tm; + int (*parse)(uint32_t *, const char *, size_t); + size_t (*unparse)(char *, size_t, uint32_t); + + always_replace = 1; + ts = 1;/* text size. */ + if (sc->flag & SCONV_TO_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16BE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16LE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF8) { + unparse = unicode_to_utf8; + if (sc->flag & SCONV_FROM_UTF8) + always_replace = 0; + } else { + /* + * This case is going to be converted to another + * character-set through iconv. + */ + always_replace = 0; + if (sc->flag & SCONV_FROM_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + } else if (sc->flag & SCONV_FROM_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + } else { + unparse = unicode_to_utf8; + } + } + + if (sc->flag & SCONV_FROM_UTF16BE) { + parse = utf16be_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else if (sc->flag & SCONV_FROM_UTF16LE) { + parse = utf16le_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else { + parse = cesu8_to_unicode; + tm = ts; + spair = 6;/* surrogate pair size in UTF-8. */ + } + + if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) + return (-1); + + p = as->s + as->length; + endp = as->s + as->buffer_length - ts; + while ((n = parse(&uc, s, len)) != 0) { + const char *ucptr, *uc2ptr; + + if (n < 0) { + /* Use a replaced unicode character. */ + UNPARSE(p, endp, uc); + s += n*-1; + len -= n*-1; + ret = -1; + continue; + } else if (n == spair || always_replace) + /* uc is converted from a surrogate pair. + * this should be treated as a changed code. */ + ucptr = NULL; + else + ucptr = s; + s += n; + len -= n; + + /* Read second code point. */ + while ((n2 = parse(&uc2, s, len)) > 0) { + uint32_t ucx[FDC_MAX]; + int ccx[FDC_MAX]; + int cl, cx, i, nx, ucx_size; + int LIndex,SIndex; + uint32_t nfc; + + if (n2 == spair || always_replace) + /* uc2 is converted from a surrogate pair. + * this should be treated as a changed code. */ + uc2ptr = NULL; + else + uc2ptr = s; + s += n2; + len -= n2; + + /* + * If current second code point is out of decomposable + * code points, finding compositions is unneeded. + */ + if (!IS_DECOMPOSABLE_BLOCK(uc2)) { + WRITE_UC(); + REPLACE_UC_WITH_UC2(); + continue; + } + + /* + * Try to combine current code points. + */ + /* + * We have to combine Hangul characters according to + * http://uniicode.org/reports/tr15/#Hangul + */ + if (0 <= (LIndex = uc - HC_LBASE) && + LIndex < HC_LCOUNT) { + /* + * Hangul Composition. + * 1. Two current code points are L and V. + */ + int VIndex = uc2 - HC_VBASE; + if (0 <= VIndex && VIndex < HC_VCOUNT) { + /* Make syllable of form LV. */ + UPDATE_UC(HC_SBASE + + (LIndex * HC_VCOUNT + VIndex) * + HC_TCOUNT); + } else { + WRITE_UC(); + REPLACE_UC_WITH_UC2(); + } + continue; + } else if (0 <= (SIndex = uc - HC_SBASE) && + SIndex < HC_SCOUNT && (SIndex % HC_TCOUNT) == 0) { + /* + * Hangul Composition. + * 2. Two current code points are LV and T. + */ + int TIndex = uc2 - HC_TBASE; + if (0 < TIndex && TIndex < HC_TCOUNT) { + /* Make syllable of form LVT. */ + UPDATE_UC(uc + TIndex); + } else { + WRITE_UC(); + REPLACE_UC_WITH_UC2(); + } + continue; + } else if ((nfc = get_nfc(uc, uc2)) != 0) { + /* A composition to current code points + * is found. */ + UPDATE_UC(nfc); + continue; + } else if ((cl = CCC(uc2)) == 0) { + /* Clearly 'uc2' the second code point is not + * a decomposable code. */ + WRITE_UC(); + REPLACE_UC_WITH_UC2(); + continue; + } + + /* + * Collect following decomposable code points. + */ + cx = 0; + ucx[0] = uc2; + ccx[0] = cl; + COLLECT_CPS(1); + + /* + * Find a composed code in the collected code points. + */ + i = 1; + while (i < ucx_size) { + int j; + + if ((nfc = get_nfc(uc, ucx[i])) == 0) { + i++; + continue; + } + + /* + * nfc is composed of uc and ucx[i]. + */ + UPDATE_UC(nfc); + + /* + * Remove ucx[i] by shifting + * following code points. + */ + for (j = i; j+1 < ucx_size; j++) { + ucx[j] = ucx[j+1]; + ccx[j] = ccx[j+1]; + } + ucx_size --; + + /* + * Collect following code points blocked + * by ucx[i] the removed code point. + */ + if (ucx_size > 0 && i == ucx_size && + nx > 0 && cx == cl) { + cl = ccx[ucx_size-1]; + COLLECT_CPS(ucx_size); + } + /* + * Restart finding a composed code with + * the updated uc from the top of the + * collected code points. + */ + i = 0; + } + + /* + * Apparently the current code points are not + * decomposed characters or already composed. + */ + WRITE_UC(); + for (i = 0; i < ucx_size; i++) + UNPARSE(p, endp, ucx[i]); + + /* + * Flush out remaining canonical combining characters. + */ + if (nx > 0 && cx == cl && len > 0) { + while ((nx = parse(&ucx[0], s, len)) + > 0) { + cx = CCC(ucx[0]); + if (cl > cx) + break; + s += nx; + len -= nx; + cl = cx; + UNPARSE(p, endp, ucx[0]); + } + } + break; + } + if (n2 < 0) { + WRITE_UC(); + /* Use a replaced unicode character. */ + UNPARSE(p, endp, uc2); + s += n2*-1; + len -= n2*-1; + ret = -1; + continue; + } else if (n2 == 0) { + WRITE_UC(); + break; + } + } + as->length = p - as->s; + as->s[as->length] = '\0'; + if (ts == 2) + as->s[as->length+1] = '\0'; + return (ret); +} + +static int +get_nfd(uint32_t *cp1, uint32_t *cp2, uint32_t uc) +{ + int t, b; + + /* + * These are not converted to NFD on Mac OS. + */ + if ((uc >= 0x2000 && uc <= 0x2FFF) || + (uc >= 0xF900 && uc <= 0xFAFF) || + (uc >= 0x2F800 && uc <= 0x2FAFF)) + return (0); + /* + * Those code points are not converted to NFD on Mac OS. + * I do not know the reason because it is undocumented. + * NFC NFD + * 1109A ==> 11099 110BA + * 1109C ==> 1109B 110BA + * 110AB ==> 110A5 110BA + */ + if (uc == 0x1109A || uc == 0x1109C || uc == 0x110AB) + return (0); + + t = 0; + b = sizeof(u_decomposition_table)/sizeof(u_decomposition_table[0]) -1; + while (b >= t) { + int m = (t + b) / 2; + if (u_decomposition_table[m].nfc < uc) + t = m + 1; + else if (u_decomposition_table[m].nfc > uc) + b = m - 1; + else { + *cp1 = u_decomposition_table[m].cp1; + *cp2 = u_decomposition_table[m].cp2; + return (1); + } + } + return (0); +} + +#define REPLACE_UC_WITH(cp) do { \ + uc = cp; \ + ucptr = NULL; \ +} while (0) + +/* + * Normalize UTF-8 characters to Form D and copy the result. + */ +static int +archive_string_normalize_D(struct archive_string *as, const void *_p, + size_t len, struct archive_string_conv *sc) +{ + const char *s = (const char *)_p; + char *p, *endp; + uint32_t uc, uc2; + size_t w; + int always_replace, n, n2, ret = 0, spair, ts, tm; + int (*parse)(uint32_t *, const char *, size_t); + size_t (*unparse)(char *, size_t, uint32_t); + + always_replace = 1; + ts = 1;/* text size. */ + if (sc->flag & SCONV_TO_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16BE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + if (sc->flag & SCONV_FROM_UTF16LE) + always_replace = 0; + } else if (sc->flag & SCONV_TO_UTF8) { + unparse = unicode_to_utf8; + if (sc->flag & SCONV_FROM_UTF8) + always_replace = 0; + } else { + /* + * This case is going to be converted to another + * character-set through iconv. + */ + always_replace = 0; + if (sc->flag & SCONV_FROM_UTF16BE) { + unparse = unicode_to_utf16be; + ts = 2; + } else if (sc->flag & SCONV_FROM_UTF16LE) { + unparse = unicode_to_utf16le; + ts = 2; + } else { + unparse = unicode_to_utf8; + } + } + + if (sc->flag & SCONV_FROM_UTF16BE) { + parse = utf16be_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else if (sc->flag & SCONV_FROM_UTF16LE) { + parse = utf16le_to_unicode; + tm = 1; + spair = 4;/* surrogate pair size in UTF-16. */ + } else { + parse = cesu8_to_unicode; + tm = ts; + spair = 6;/* surrogate pair size in UTF-8. */ + } + + if (archive_string_ensure(as, as->length + len * tm + ts) == NULL) + return (-1); + + p = as->s + as->length; + endp = as->s + as->buffer_length - ts; + while ((n = parse(&uc, s, len)) != 0) { + const char *ucptr; + uint32_t cp1, cp2; + int SIndex; + struct { + uint32_t uc; + int ccc; + } fdc[FDC_MAX]; + int fdi, fdj; + int ccc; + +check_first_code: + if (n < 0) { + /* Use a replaced unicode character. */ + UNPARSE(p, endp, uc); + s += n*-1; + len -= n*-1; + ret = -1; + continue; + } else if (n == spair || always_replace) + /* uc is converted from a surrogate pair. + * this should be treated as a changed code. */ + ucptr = NULL; + else + ucptr = s; + s += n; + len -= n; + + /* Hangul Decomposition. */ + if ((SIndex = uc - HC_SBASE) >= 0 && SIndex < HC_SCOUNT) { + int L = HC_LBASE + SIndex / HC_NCOUNT; + int V = HC_VBASE + (SIndex % HC_NCOUNT) / HC_TCOUNT; + int T = HC_TBASE + SIndex % HC_TCOUNT; + + REPLACE_UC_WITH(L); + WRITE_UC(); + REPLACE_UC_WITH(V); + WRITE_UC(); + if (T != HC_TBASE) { + REPLACE_UC_WITH(T); + WRITE_UC(); + } + continue; + } + if (IS_DECOMPOSABLE_BLOCK(uc) && CCC(uc) != 0) { + WRITE_UC(); + continue; + } + + fdi = 0; + while (get_nfd(&cp1, &cp2, uc) && fdi < FDC_MAX) { + int k; + + for (k = fdi; k > 0; k--) + fdc[k] = fdc[k-1]; + fdc[0].ccc = CCC(cp2); + fdc[0].uc = cp2; + fdi++; + REPLACE_UC_WITH(cp1); + } + + /* Read following code points. */ + while ((n2 = parse(&uc2, s, len)) > 0 && + (ccc = CCC(uc2)) != 0 && fdi < FDC_MAX) { + int j, k; + + s += n2; + len -= n2; + for (j = 0; j < fdi; j++) { + if (fdc[j].ccc > ccc) + break; + } + if (j < fdi) { + for (k = fdi; k > j; k--) + fdc[k] = fdc[k-1]; + fdc[j].ccc = ccc; + fdc[j].uc = uc2; + } else { + fdc[fdi].ccc = ccc; + fdc[fdi].uc = uc2; + } + fdi++; + } + + WRITE_UC(); + for (fdj = 0; fdj < fdi; fdj++) { + REPLACE_UC_WITH(fdc[fdj].uc); + WRITE_UC(); + } + + if (n2 == 0) + break; + REPLACE_UC_WITH(uc2); + n = n2; + goto check_first_code; + } + as->length = p - as->s; + as->s[as->length] = '\0'; + if (ts == 2) + as->s[as->length+1] = '\0'; + return (ret); +} + +/* + * libarchive 2.x made incorrect UTF-8 strings in the wrong assumption + * that WCS is Unicode. It is true for several platforms but some are false. + * And then people who did not use UTF-8 locale on the non Unicode WCS + * platform and made a tar file with libarchive(mostly bsdtar) 2.x. Those + * now cannot get right filename from libarchive 3.x and later since we + * fixed the wrong assumption and it is incompatible to older its versions. + * So we provide special option, "compat-2x.x", for resolving it. + * That option enable the string conversion of libarchive 2.x. + * + * Translates the wrong UTF-8 string made by libarchive 2.x into current + * locale character set and appends to the archive_string. + * Note: returns -1 if conversion fails. + */ +static int +strncat_from_utf8_libarchive2(struct archive_string *as, + const void *_p, size_t len, struct archive_string_conv *sc) +{ + const char *s; + int n; + char *p; + char *end; + uint32_t unicode; +#if HAVE_WCRTOMB + mbstate_t shift_state; + + memset(&shift_state, 0, sizeof(shift_state)); +#else + /* Clear the shift state before starting. */ + wctomb(NULL, L'\0'); +#endif + (void)sc; /* UNUSED */ + /* + * Allocate buffer for MBS. + * We need this allocation here since it is possible that + * as->s is still NULL. + */ + if (archive_string_ensure(as, as->length + len + 1) == NULL) + return (-1); + + s = (const char *)_p; + p = as->s + as->length; + end = as->s + as->buffer_length - MB_CUR_MAX -1; + while ((n = _utf8_to_unicode(&unicode, s, len)) != 0) { + wchar_t wc; + + if (p >= end) { + as->length = p - as->s; + /* Re-allocate buffer for MBS. */ + if (archive_string_ensure(as, + as->length + len * 2 + 1) == NULL) + return (-1); + p = as->s + as->length; + end = as->s + as->buffer_length - MB_CUR_MAX -1; + } + + /* + * As libarchive 2.x, translates the UTF-8 characters into + * wide-characters in the assumption that WCS is Unicode. + */ + if (n < 0) { + n *= -1; + wc = L'?'; + } else + wc = (wchar_t)unicode; + + s += n; + len -= n; + /* + * Translates the wide-character into the current locale MBS. + */ +#if HAVE_WCRTOMB + n = (int)wcrtomb(p, wc, &shift_state); +#else + n = (int)wctomb(p, wc); +#endif + if (n == -1) + return (-1); + p += n; + } + as->length = p - as->s; + as->s[as->length] = '\0'; + return (0); +} + + +/* + * Conversion functions between current locale dependent MBS and UTF-16BE. + * strncat_from_utf16be() : UTF-16BE --> MBS + * strncat_to_utf16be() : MBS --> UTF16BE + */ + +#if defined(_WIN32) && !defined(__CYGWIN__) + +/* + * Convert a UTF-16BE/LE string to current locale and copy the result. + * Return -1 if conversion fails. + */ +static int +win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, + struct archive_string_conv *sc, int be) +{ + struct archive_string tmp; + const char *u16; + int ll; + BOOL defchar; + char *mbs; + size_t mbs_size, b; + int ret = 0; + + bytes &= ~1; + if (archive_string_ensure(as, as->length + bytes +1) == NULL) + return (-1); + + mbs = as->s + as->length; + mbs_size = as->buffer_length - as->length -1; + + if (sc->to_cp == CP_C_LOCALE) { + /* + * "C" locale special process. + */ + u16 = _p; + ll = 0; + for (b = 0; b < bytes; b += 2) { + uint16_t val; + if (be) + val = archive_be16dec(u16+b); + else + val = archive_le16dec(u16+b); + if (val > 255) { + *mbs++ = '?'; + ret = -1; + } else + *mbs++ = (char)(val&0xff); + ll++; + } + as->length += ll; + as->s[as->length] = '\0'; + return (ret); + } + + archive_string_init(&tmp); + if (be) { + if (is_big_endian()) { + u16 = _p; + } else { + if (archive_string_ensure(&tmp, bytes+2) == NULL) + return (-1); + memcpy(tmp.s, _p, bytes); + for (b = 0; b < bytes; b += 2) { + uint16_t val = archive_be16dec(tmp.s+b); + archive_le16enc(tmp.s+b, val); + } + u16 = tmp.s; + } + } else { + if (!is_big_endian()) { + u16 = _p; + } else { + if (archive_string_ensure(&tmp, bytes+2) == NULL) + return (-1); + memcpy(tmp.s, _p, bytes); + for (b = 0; b < bytes; b += 2) { + uint16_t val = archive_le16dec(tmp.s+b); + archive_be16enc(tmp.s+b, val); + } + u16 = tmp.s; + } + } + + do { + defchar = 0; + ll = WideCharToMultiByte(sc->to_cp, 0, + (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size, + NULL, &defchar); + /* Exit loop if we succeeded */ + if (ll != 0 || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + break; + } + /* Else expand buffer and loop to try again. */ + ll = WideCharToMultiByte(sc->to_cp, 0, + (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL); + if (archive_string_ensure(as, ll +1) == NULL) + return (-1); + mbs = as->s + as->length; + mbs_size = as->buffer_length - as->length -1; + } while (1); + archive_string_free(&tmp); + as->length += ll; + as->s[as->length] = '\0'; + if (ll == 0 || defchar) + ret = -1; + return (ret); +} + +static int +win_strncat_from_utf16be(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) +{ + return (win_strncat_from_utf16(as, _p, bytes, sc, 1)); +} + +static int +win_strncat_from_utf16le(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) +{ + return (win_strncat_from_utf16(as, _p, bytes, sc, 0)); +} + +static int +is_big_endian(void) +{ + uint16_t d = 1; + + return (archive_be16dec(&d) == 1); +} + +/* + * Convert a current locale string to UTF-16BE/LE and copy the result. + * Return -1 if conversion fails. + */ +static int +win_strncat_to_utf16(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc, int bigendian) +{ + const char *s = (const char *)_p; + char *u16; + size_t count, avail; + + if (archive_string_ensure(as16, + as16->length + (length + 1) * 2) == NULL) + return (-1); + + u16 = as16->s + as16->length; + avail = as16->buffer_length - 2; + if (sc->from_cp == CP_C_LOCALE) { + /* + * "C" locale special process. + */ + count = 0; + while (count < length && *s) { + if (bigendian) + archive_be16enc(u16, *s); + else + archive_le16enc(u16, *s); + u16 += 2; + s++; + count++; + } + as16->length += count << 1; + as16->s[as16->length] = 0; + as16->s[as16->length+1] = 0; + return (0); + } + do { + count = MultiByteToWideChar(sc->from_cp, + MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1); + /* Exit loop if we succeeded */ + if (count != 0 || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + break; + } + /* Expand buffer and try again */ + count = MultiByteToWideChar(sc->from_cp, + MB_PRECOMPOSED, s, (int)length, NULL, 0); + if (archive_string_ensure(as16, (count +1) * 2) + == NULL) + return (-1); + u16 = as16->s + as16->length; + avail = as16->buffer_length - 2; + } while (1); + as16->length += count * 2; + as16->s[as16->length] = 0; + as16->s[as16->length+1] = 0; + if (count == 0) + return (-1); + + if (is_big_endian()) { + if (!bigendian) { + while (count > 0) { + uint16_t v = archive_be16dec(u16); + archive_le16enc(u16, v); + u16 += 2; + count--; + } + } + } else { + if (bigendian) { + while (count > 0) { + uint16_t v = archive_le16dec(u16); + archive_be16enc(u16, v); + u16 += 2; + count--; + } + } + } + return (0); +} + +static int +win_strncat_to_utf16be(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + return (win_strncat_to_utf16(as16, _p, length, sc, 1)); +} + +static int +win_strncat_to_utf16le(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + return (win_strncat_to_utf16(as16, _p, length, sc, 0)); +} + +#endif /* _WIN32 && !__CYGWIN__ */ + +/* + * Do the best effort for conversions. + * We cannot handle UTF-16BE character-set without such iconv, + * but there is a chance if a string consists just ASCII code or + * a current locale is UTF-8. + */ + +/* + * Convert a UTF-16BE string to current locale and copy the result. + * Return -1 if conversion fails. + */ +static int +best_effort_strncat_from_utf16(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc, int be) +{ + const char *utf16 = (const char *)_p; + char *mbs; + uint32_t uc; + int n, ret; + + (void)sc; /* UNUSED */ + /* + * Other case, we should do the best effort. + * If all character are ASCII(<0x7f), we can convert it. + * if not , we set a alternative character and return -1. + */ + ret = 0; + if (archive_string_ensure(as, as->length + bytes +1) == NULL) + return (-1); + mbs = as->s + as->length; + + while ((n = utf16_to_unicode(&uc, utf16, bytes, be)) != 0) { + if (n < 0) { + n *= -1; + ret = -1; + } + bytes -= n; + utf16 += n; + + if (uc > 127) { + /* We cannot handle it. */ + *mbs++ = '?'; + ret = -1; + } else + *mbs++ = (char)uc; + } + as->length = mbs - as->s; + as->s[as->length] = '\0'; + return (ret); +} + +static int +best_effort_strncat_from_utf16be(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) +{ + return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 1)); +} + +static int +best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p, + size_t bytes, struct archive_string_conv *sc) +{ + return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 0)); +} + +/* + * Convert a current locale string to UTF-16BE/LE and copy the result. + * Return -1 if conversion fails. + */ +static int +best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc, int bigendian) +{ + const char *s = (const char *)_p; + char *utf16; + size_t remaining; + int ret; + + (void)sc; /* UNUSED */ + /* + * Other case, we should do the best effort. + * If all character are ASCII(<0x7f), we can convert it. + * if not , we set a alternative character and return -1. + */ + ret = 0; + remaining = length; + + if (archive_string_ensure(as16, + as16->length + (length + 1) * 2) == NULL) + return (-1); + + utf16 = as16->s + as16->length; + while (remaining--) { + unsigned c = *s++; + if (c > 127) { + /* We cannot handle it. */ + c = UNICODE_R_CHAR; + ret = -1; + } + if (bigendian) + archive_be16enc(utf16, c); + else + archive_le16enc(utf16, c); + utf16 += 2; + } + as16->length = utf16 - as16->s; + as16->s[as16->length] = 0; + as16->s[as16->length+1] = 0; + return (ret); +} + +static int +best_effort_strncat_to_utf16be(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + return (best_effort_strncat_to_utf16(as16, _p, length, sc, 1)); +} + +static int +best_effort_strncat_to_utf16le(struct archive_string *as16, const void *_p, + size_t length, struct archive_string_conv *sc) +{ + return (best_effort_strncat_to_utf16(as16, _p, length, sc, 0)); +} + + +/* + * Multistring operations. + */ + +void +archive_mstring_clean(struct archive_mstring *aes) +{ + archive_wstring_free(&(aes->aes_wcs)); + archive_string_free(&(aes->aes_mbs)); + archive_string_free(&(aes->aes_utf8)); + archive_string_free(&(aes->aes_mbs_in_locale)); + aes->aes_set = 0; +} + +void +archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src) +{ + dest->aes_set = src->aes_set; + archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); + archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); + archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs)); +} + +int +archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes, + const char **p) +{ + struct archive_string_conv *sc; + int r; + + /* If we already have a UTF8 form, return that immediately. */ + if (aes->aes_set & AES_SET_UTF8) { + *p = aes->aes_utf8.s; + return (0); + } + + *p = NULL; + if (aes->aes_set & AES_SET_MBS) { + sc = archive_string_conversion_to_charset(a, "UTF-8", 1); + if (sc == NULL) + return (-1);/* Couldn't allocate memory for sc. */ + r = archive_strncpy_l(&(aes->aes_utf8), aes->aes_mbs.s, + aes->aes_mbs.length, sc); + if (a == NULL) + free_sconv_object(sc); + if (r == 0) { + aes->aes_set |= AES_SET_UTF8; + *p = aes->aes_utf8.s; + return (0);/* success. */ + } else + return (-1);/* failure. */ + } + return (0);/* success. */ +} + +int +archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes, + const char **p) +{ + int r, ret = 0; + + (void)a; /* UNUSED */ + /* If we already have an MBS form, return that immediately. */ + if (aes->aes_set & AES_SET_MBS) { + *p = aes->aes_mbs.s; + return (ret); + } + + *p = NULL; + /* If there's a WCS form, try converting with the native locale. */ + if (aes->aes_set & AES_SET_WCS) { + archive_string_empty(&(aes->aes_mbs)); + r = archive_string_append_from_wcs(&(aes->aes_mbs), + aes->aes_wcs.s, aes->aes_wcs.length); + *p = aes->aes_mbs.s; + if (r == 0) { + aes->aes_set |= AES_SET_MBS; + return (ret); + } else + ret = -1; + } + + /* + * Only a UTF-8 form cannot avail because its conversion already + * failed at archive_mstring_update_utf8(). + */ + return (ret); +} + +int +archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes, + const wchar_t **wp) +{ + int r, ret = 0; + + (void)a;/* UNUSED */ + /* Return WCS form if we already have it. */ + if (aes->aes_set & AES_SET_WCS) { + *wp = aes->aes_wcs.s; + return (ret); + } + + *wp = NULL; + /* Try converting MBS to WCS using native locale. */ + if (aes->aes_set & AES_SET_MBS) { + archive_wstring_empty(&(aes->aes_wcs)); + r = archive_wstring_append_from_mbs(&(aes->aes_wcs), + aes->aes_mbs.s, aes->aes_mbs.length); + if (r == 0) { + aes->aes_set |= AES_SET_WCS; + *wp = aes->aes_wcs.s; + } else + ret = -1;/* failure. */ + } + return (ret); +} + +int +archive_mstring_get_mbs_l(struct archive_mstring *aes, + const char **p, size_t *length, struct archive_string_conv *sc) +{ + int r, ret = 0; + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * Internationalization programming on Windows must use Wide + * characters because Windows platform cannot make locale UTF-8. + */ + if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) { + archive_string_empty(&(aes->aes_mbs_in_locale)); + r = archive_string_append_from_wcs_in_codepage( + &(aes->aes_mbs_in_locale), aes->aes_wcs.s, + aes->aes_wcs.length, sc); + if (r == 0) { + *p = aes->aes_mbs_in_locale.s; + if (length != NULL) + *length = aes->aes_mbs_in_locale.length; + return (0); + } else if (errno == ENOMEM) + return (-1); + else + ret = -1; + } +#endif + + /* If there is not an MBS form but is a WCS form, try converting + * with the native locale to be used for translating it to specified + * character-set. */ + if ((aes->aes_set & AES_SET_MBS) == 0 && + (aes->aes_set & AES_SET_WCS) != 0) { + archive_string_empty(&(aes->aes_mbs)); + r = archive_string_append_from_wcs(&(aes->aes_mbs), + aes->aes_wcs.s, aes->aes_wcs.length); + if (r == 0) + aes->aes_set |= AES_SET_MBS; + else if (errno == ENOMEM) + return (-1); + else + ret = -1; + } + /* If we already have an MBS form, use it to be translated to + * specified character-set. */ + if (aes->aes_set & AES_SET_MBS) { + if (sc == NULL) { + /* Conversion is unneeded. */ + *p = aes->aes_mbs.s; + if (length != NULL) + *length = aes->aes_mbs.length; + return (0); + } + ret = archive_strncpy_l(&(aes->aes_mbs_in_locale), + aes->aes_mbs.s, aes->aes_mbs.length, sc); + *p = aes->aes_mbs_in_locale.s; + if (length != NULL) + *length = aes->aes_mbs_in_locale.length; + } else { + *p = NULL; + if (length != NULL) + *length = 0; + } + return (ret); +} + +int +archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs) +{ + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + return (archive_mstring_copy_mbs_len(aes, mbs, strlen(mbs))); +} + +int +archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs, + size_t len) +{ + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ + archive_strncpy(&(aes->aes_mbs), mbs, len); + archive_string_empty(&(aes->aes_utf8)); + archive_wstring_empty(&(aes->aes_wcs)); + return (0); +} + +int +archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs) +{ + return archive_mstring_copy_wcs_len(aes, wcs, + wcs == NULL ? 0 : wcslen(wcs)); +} + +int +archive_mstring_copy_utf8(struct archive_mstring *aes, const char *utf8) +{ + if (utf8 == NULL) { + aes->aes_set = 0; + } + aes->aes_set = AES_SET_UTF8; + archive_string_empty(&(aes->aes_mbs)); + archive_string_empty(&(aes->aes_wcs)); + archive_strncpy(&(aes->aes_utf8), utf8, strlen(utf8)); + return (int)strlen(utf8); +} + +int +archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs, + size_t len) +{ + if (wcs == NULL) { + aes->aes_set = 0; + } + aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ + archive_string_empty(&(aes->aes_mbs)); + archive_string_empty(&(aes->aes_utf8)); + archive_wstrncpy(&(aes->aes_wcs), wcs, len); + return (0); +} + +int +archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, + const char *mbs, size_t len, struct archive_string_conv *sc) +{ + int r; + + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + archive_string_empty(&(aes->aes_mbs)); + archive_wstring_empty(&(aes->aes_wcs)); + archive_string_empty(&(aes->aes_utf8)); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * Internationalization programming on Windows must use Wide + * characters because Windows platform cannot make locale UTF-8. + */ + if (sc == NULL) { + if (archive_string_append(&(aes->aes_mbs), + mbs, mbsnbytes(mbs, len)) == NULL) { + aes->aes_set = 0; + r = -1; + } else { + aes->aes_set = AES_SET_MBS; + r = 0; + } +#if defined(HAVE_ICONV) + } else if (sc != NULL && sc->cd_w != (iconv_t)-1) { + /* + * This case happens only when MultiByteToWideChar() cannot + * handle sc->from_cp, and we have to iconv in order to + * translate character-set to wchar_t,UTF-16. + */ + iconv_t cd = sc->cd; + unsigned from_cp; + int flag; + + /* + * Translate multi-bytes from some character-set to UTF-8. + */ + sc->cd = sc->cd_w; + r = archive_strncpy_l(&(aes->aes_utf8), mbs, len, sc); + sc->cd = cd; + if (r != 0) { + aes->aes_set = 0; + return (r); + } + aes->aes_set = AES_SET_UTF8; + + /* + * Append the UTF-8 string into wstring. + */ + flag = sc->flag; + sc->flag &= ~(SCONV_NORMALIZATION_C + | SCONV_TO_UTF16| SCONV_FROM_UTF16); + from_cp = sc->from_cp; + sc->from_cp = CP_UTF8; + r = archive_wstring_append_from_mbs_in_codepage(&(aes->aes_wcs), + aes->aes_utf8.s, aes->aes_utf8.length, sc); + sc->flag = flag; + sc->from_cp = from_cp; + if (r == 0) + aes->aes_set |= AES_SET_WCS; +#endif + } else { + r = archive_wstring_append_from_mbs_in_codepage( + &(aes->aes_wcs), mbs, len, sc); + if (r == 0) + aes->aes_set = AES_SET_WCS; + else + aes->aes_set = 0; + } +#else + r = archive_strncpy_l(&(aes->aes_mbs), mbs, len, sc); + if (r == 0) + aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ + else + aes->aes_set = 0; +#endif + return (r); +} + +/* + * The 'update' form tries to proactively update all forms of + * this string (WCS and MBS) and returns an error if any of + * them fail. This is used by the 'pax' handler, for instance, + * to detect and report character-conversion failures early while + * still allowing clients to get potentially useful values from + * the more tolerant lazy conversions. (get_mbs and get_wcs will + * strive to give the user something useful, so you can get hopefully + * usable values even if some of the character conversions are failing.) + */ +int +archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes, + const char *utf8) +{ + struct archive_string_conv *sc; + int r; + + if (utf8 == NULL) { + aes->aes_set = 0; + return (0); /* Succeeded in clearing everything. */ + } + + /* Save the UTF8 string. */ + archive_strcpy(&(aes->aes_utf8), utf8); + + /* Empty the mbs and wcs strings. */ + archive_string_empty(&(aes->aes_mbs)); + archive_wstring_empty(&(aes->aes_wcs)); + + aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ + + /* Try converting UTF-8 to MBS, return false on failure. */ + sc = archive_string_conversion_from_charset(a, "UTF-8", 1); + if (sc == NULL) + return (-1);/* Couldn't allocate memory for sc. */ + r = archive_strcpy_l(&(aes->aes_mbs), utf8, sc); + if (a == NULL) + free_sconv_object(sc); + if (r != 0) + return (-1); + aes->aes_set = AES_SET_UTF8 | AES_SET_MBS; /* Both UTF8 and MBS set. */ + + /* Try converting MBS to WCS, return false on failure. */ + if (archive_wstring_append_from_mbs(&(aes->aes_wcs), aes->aes_mbs.s, + aes->aes_mbs.length)) + return (-1); + aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; + + /* All conversions succeeded. */ + return (0); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_string.h b/src/3rdparty/libarchive/libarchive/archive_string.h new file mode 100644 index 00000000..56dfbb28 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_string.h @@ -0,0 +1,243 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_string.h 201092 2009-12-28 02:26:06Z kientzle $ + * + */ + +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_STRING_H_INCLUDED +#define ARCHIVE_STRING_H_INCLUDED + +#include +#ifdef HAVE_STDLIB_H +#include /* required for wchar_t on some systems */ +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#include "archive.h" + +/* + * Basic resizable/reusable string support similar to Java's "StringBuffer." + * + * Unlike sbuf(9), the buffers here are fully reusable and track the + * length throughout. + */ + +struct archive_string { + char *s; /* Pointer to the storage */ + size_t length; /* Length of 's' in characters */ + size_t buffer_length; /* Length of malloc-ed storage in bytes. */ +}; + +struct archive_wstring { + wchar_t *s; /* Pointer to the storage */ + size_t length; /* Length of 's' in characters */ + size_t buffer_length; /* Length of malloc-ed storage in bytes. */ +}; + +struct archive_string_conv; + +/* Initialize an archive_string object on the stack or elsewhere. */ +#define archive_string_init(a) \ + do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0) + +/* Append a C char to an archive_string, resizing as necessary. */ +struct archive_string * +archive_strappend_char(struct archive_string *, char); + +/* Ditto for a wchar_t and an archive_wstring. */ +struct archive_wstring * +archive_wstrappend_wchar(struct archive_wstring *, wchar_t); + +/* Append a raw array to an archive_string, resizing as necessary */ +struct archive_string * +archive_array_append(struct archive_string *, const char *, size_t); + +/* Convert a Unicode string to current locale and append the result. */ +/* Returns -1 if conversion fails. */ +int +archive_string_append_from_wcs(struct archive_string *, const wchar_t *, size_t); + + +/* Create a string conversion object. + * Return NULL and set a error message if the conversion is not supported + * on the platform. */ +struct archive_string_conv * +archive_string_conversion_to_charset(struct archive *, const char *, int); +struct archive_string_conv * +archive_string_conversion_from_charset(struct archive *, const char *, int); +/* Create the default string conversion object for reading/writing an archive. + * Return NULL if the conversion is unneeded. + * Note: On non Windows platform this always returns NULL. + */ +struct archive_string_conv * +archive_string_default_conversion_for_read(struct archive *); +struct archive_string_conv * +archive_string_default_conversion_for_write(struct archive *); +/* Dispose of a string conversion object. */ +void +archive_string_conversion_free(struct archive *); +const char * +archive_string_conversion_charset_name(struct archive_string_conv *); +void +archive_string_conversion_set_opt(struct archive_string_conv *, int); +#define SCONV_SET_OPT_UTF8_LIBARCHIVE2X 1 +#define SCONV_SET_OPT_NORMALIZATION_C 2 +#define SCONV_SET_OPT_NORMALIZATION_D 4 + + +/* Copy one archive_string to another in locale conversion. + * Return -1 if conversion fails. */ +int +archive_strncpy_l(struct archive_string *, const void *, size_t, + struct archive_string_conv *); + +/* Copy one archive_string to another in locale conversion. + * Return -1 if conversion fails. */ +int +archive_strncat_l(struct archive_string *, const void *, size_t, + struct archive_string_conv *); + + +/* Copy one archive_string to another */ +#define archive_string_copy(dest, src) \ + ((dest)->length = 0, archive_string_concat((dest), (src))) +#define archive_wstring_copy(dest, src) \ + ((dest)->length = 0, archive_wstring_concat((dest), (src))) + +/* Concatenate one archive_string to another */ +void archive_string_concat(struct archive_string *dest, struct archive_string *src); +void archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src); + +/* Ensure that the underlying buffer is at least as large as the request. */ +struct archive_string * +archive_string_ensure(struct archive_string *, size_t); +struct archive_wstring * +archive_wstring_ensure(struct archive_wstring *, size_t); + +/* Append C string, which may lack trailing \0. */ +/* The source is declared void * here because this gets used with + * "signed char *", "unsigned char *" and "char *" arguments. + * Declaring it "char *" as with some of the other functions just + * leads to a lot of extra casts. */ +struct archive_string * +archive_strncat(struct archive_string *, const void *, size_t); +struct archive_wstring * +archive_wstrncat(struct archive_wstring *, const wchar_t *, size_t); + +/* Append a C string to an archive_string, resizing as necessary. */ +struct archive_string * +archive_strcat(struct archive_string *, const void *); +struct archive_wstring * +archive_wstrcat(struct archive_wstring *, const wchar_t *); + +/* Copy a C string to an archive_string, resizing as necessary. */ +#define archive_strcpy(as,p) \ + archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p))) +#define archive_wstrcpy(as,p) \ + archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(p))) +#define archive_strcpy_l(as,p,lo) \ + archive_strncpy_l((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo)) + +/* Copy a C string to an archive_string with limit, resizing as necessary. */ +#define archive_strncpy(as,p,l) \ + ((as)->length=0, archive_strncat((as), (p), (l))) +#define archive_wstrncpy(as,p,l) \ + ((as)->length = 0, archive_wstrncat((as), (p), (l))) + +/* Return length of string. */ +#define archive_strlen(a) ((a)->length) + +/* Set string length to zero. */ +#define archive_string_empty(a) ((a)->length = 0) +#define archive_wstring_empty(a) ((a)->length = 0) + +/* Release any allocated storage resources. */ +void archive_string_free(struct archive_string *); +void archive_wstring_free(struct archive_wstring *); + +/* Like 'vsprintf', but resizes the underlying string as necessary. */ +/* Note: This only implements a small subset of standard printf functionality. */ +void archive_string_vsprintf(struct archive_string *, const char *, + va_list) __LA_PRINTF(2, 0); +void archive_string_sprintf(struct archive_string *, const char *, ...) + __LA_PRINTF(2, 3); + +/* Translates from MBS to Unicode. */ +/* Returns non-zero if conversion failed in any way. */ +int archive_wstring_append_from_mbs(struct archive_wstring *dest, + const char *, size_t); + + +/* A "multistring" can hold Unicode, UTF8, or MBS versions of + * the string. If you set and read the same version, no translation + * is done. If you set and read different versions, the library + * will attempt to transparently convert. + */ +struct archive_mstring { + struct archive_string aes_mbs; + struct archive_string aes_utf8; + struct archive_wstring aes_wcs; + struct archive_string aes_mbs_in_locale; + /* Bitmap of which of the above are valid. Because we're lazy + * about malloc-ing and reusing the underlying storage, we + * can't rely on NULL pointers to indicate whether a string + * has been set. */ + int aes_set; +#define AES_SET_MBS 1 +#define AES_SET_UTF8 2 +#define AES_SET_WCS 4 +}; + +void archive_mstring_clean(struct archive_mstring *); +void archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src); +int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **); +int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **); +int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **); +int archive_mstring_get_mbs_l(struct archive_mstring *, const char **, + size_t *, struct archive_string_conv *); +int archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs); +int archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs, + size_t); +int archive_mstring_copy_utf8(struct archive_mstring *, const char *utf8); +int archive_mstring_copy_wcs(struct archive_mstring *, const wchar_t *wcs); +int archive_mstring_copy_wcs_len(struct archive_mstring *, + const wchar_t *wcs, size_t); +int archive_mstring_copy_mbs_len_l(struct archive_mstring *, + const char *mbs, size_t, struct archive_string_conv *); +int archive_mstring_update_utf8(struct archive *, struct archive_mstring *aes, const char *utf8); + + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_string_composition.h b/src/3rdparty/libarchive/libarchive/archive_string_composition.h new file mode 100644 index 00000000..8902ac1f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_string_composition.h @@ -0,0 +1,2292 @@ +/*- + * Copyright (c) 2011-2012 libarchive Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +/* + * ATTENTION! + * This file is generated by build/utils/gen_archive_string_composition_h.sh + * from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt + * + * See also http://unicode.org/report/tr15/ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_STRING_COMPOSITION_H_INCLUDED +#define ARCHIVE_STRING_COMPOSITION_H_INCLUDED + +struct unicode_composition_table { + uint32_t cp1; + uint32_t cp2; + uint32_t nfc; +}; + +static const struct unicode_composition_table u_composition_table[] = { + { 0x0003C , 0x00338 , 0x0226E }, + { 0x0003D , 0x00338 , 0x02260 }, + { 0x0003E , 0x00338 , 0x0226F }, + { 0x00041 , 0x00300 , 0x000C0 }, + { 0x00041 , 0x00301 , 0x000C1 }, + { 0x00041 , 0x00302 , 0x000C2 }, + { 0x00041 , 0x00303 , 0x000C3 }, + { 0x00041 , 0x00304 , 0x00100 }, + { 0x00041 , 0x00306 , 0x00102 }, + { 0x00041 , 0x00307 , 0x00226 }, + { 0x00041 , 0x00308 , 0x000C4 }, + { 0x00041 , 0x00309 , 0x01EA2 }, + { 0x00041 , 0x0030A , 0x000C5 }, + { 0x00041 , 0x0030C , 0x001CD }, + { 0x00041 , 0x0030F , 0x00200 }, + { 0x00041 , 0x00311 , 0x00202 }, + { 0x00041 , 0x00323 , 0x01EA0 }, + { 0x00041 , 0x00325 , 0x01E00 }, + { 0x00041 , 0x00328 , 0x00104 }, + { 0x00042 , 0x00307 , 0x01E02 }, + { 0x00042 , 0x00323 , 0x01E04 }, + { 0x00042 , 0x00331 , 0x01E06 }, + { 0x00043 , 0x00301 , 0x00106 }, + { 0x00043 , 0x00302 , 0x00108 }, + { 0x00043 , 0x00307 , 0x0010A }, + { 0x00043 , 0x0030C , 0x0010C }, + { 0x00043 , 0x00327 , 0x000C7 }, + { 0x00044 , 0x00307 , 0x01E0A }, + { 0x00044 , 0x0030C , 0x0010E }, + { 0x00044 , 0x00323 , 0x01E0C }, + { 0x00044 , 0x00327 , 0x01E10 }, + { 0x00044 , 0x0032D , 0x01E12 }, + { 0x00044 , 0x00331 , 0x01E0E }, + { 0x00045 , 0x00300 , 0x000C8 }, + { 0x00045 , 0x00301 , 0x000C9 }, + { 0x00045 , 0x00302 , 0x000CA }, + { 0x00045 , 0x00303 , 0x01EBC }, + { 0x00045 , 0x00304 , 0x00112 }, + { 0x00045 , 0x00306 , 0x00114 }, + { 0x00045 , 0x00307 , 0x00116 }, + { 0x00045 , 0x00308 , 0x000CB }, + { 0x00045 , 0x00309 , 0x01EBA }, + { 0x00045 , 0x0030C , 0x0011A }, + { 0x00045 , 0x0030F , 0x00204 }, + { 0x00045 , 0x00311 , 0x00206 }, + { 0x00045 , 0x00323 , 0x01EB8 }, + { 0x00045 , 0x00327 , 0x00228 }, + { 0x00045 , 0x00328 , 0x00118 }, + { 0x00045 , 0x0032D , 0x01E18 }, + { 0x00045 , 0x00330 , 0x01E1A }, + { 0x00046 , 0x00307 , 0x01E1E }, + { 0x00047 , 0x00301 , 0x001F4 }, + { 0x00047 , 0x00302 , 0x0011C }, + { 0x00047 , 0x00304 , 0x01E20 }, + { 0x00047 , 0x00306 , 0x0011E }, + { 0x00047 , 0x00307 , 0x00120 }, + { 0x00047 , 0x0030C , 0x001E6 }, + { 0x00047 , 0x00327 , 0x00122 }, + { 0x00048 , 0x00302 , 0x00124 }, + { 0x00048 , 0x00307 , 0x01E22 }, + { 0x00048 , 0x00308 , 0x01E26 }, + { 0x00048 , 0x0030C , 0x0021E }, + { 0x00048 , 0x00323 , 0x01E24 }, + { 0x00048 , 0x00327 , 0x01E28 }, + { 0x00048 , 0x0032E , 0x01E2A }, + { 0x00049 , 0x00300 , 0x000CC }, + { 0x00049 , 0x00301 , 0x000CD }, + { 0x00049 , 0x00302 , 0x000CE }, + { 0x00049 , 0x00303 , 0x00128 }, + { 0x00049 , 0x00304 , 0x0012A }, + { 0x00049 , 0x00306 , 0x0012C }, + { 0x00049 , 0x00307 , 0x00130 }, + { 0x00049 , 0x00308 , 0x000CF }, + { 0x00049 , 0x00309 , 0x01EC8 }, + { 0x00049 , 0x0030C , 0x001CF }, + { 0x00049 , 0x0030F , 0x00208 }, + { 0x00049 , 0x00311 , 0x0020A }, + { 0x00049 , 0x00323 , 0x01ECA }, + { 0x00049 , 0x00328 , 0x0012E }, + { 0x00049 , 0x00330 , 0x01E2C }, + { 0x0004A , 0x00302 , 0x00134 }, + { 0x0004B , 0x00301 , 0x01E30 }, + { 0x0004B , 0x0030C , 0x001E8 }, + { 0x0004B , 0x00323 , 0x01E32 }, + { 0x0004B , 0x00327 , 0x00136 }, + { 0x0004B , 0x00331 , 0x01E34 }, + { 0x0004C , 0x00301 , 0x00139 }, + { 0x0004C , 0x0030C , 0x0013D }, + { 0x0004C , 0x00323 , 0x01E36 }, + { 0x0004C , 0x00327 , 0x0013B }, + { 0x0004C , 0x0032D , 0x01E3C }, + { 0x0004C , 0x00331 , 0x01E3A }, + { 0x0004D , 0x00301 , 0x01E3E }, + { 0x0004D , 0x00307 , 0x01E40 }, + { 0x0004D , 0x00323 , 0x01E42 }, + { 0x0004E , 0x00300 , 0x001F8 }, + { 0x0004E , 0x00301 , 0x00143 }, + { 0x0004E , 0x00303 , 0x000D1 }, + { 0x0004E , 0x00307 , 0x01E44 }, + { 0x0004E , 0x0030C , 0x00147 }, + { 0x0004E , 0x00323 , 0x01E46 }, + { 0x0004E , 0x00327 , 0x00145 }, + { 0x0004E , 0x0032D , 0x01E4A }, + { 0x0004E , 0x00331 , 0x01E48 }, + { 0x0004F , 0x00300 , 0x000D2 }, + { 0x0004F , 0x00301 , 0x000D3 }, + { 0x0004F , 0x00302 , 0x000D4 }, + { 0x0004F , 0x00303 , 0x000D5 }, + { 0x0004F , 0x00304 , 0x0014C }, + { 0x0004F , 0x00306 , 0x0014E }, + { 0x0004F , 0x00307 , 0x0022E }, + { 0x0004F , 0x00308 , 0x000D6 }, + { 0x0004F , 0x00309 , 0x01ECE }, + { 0x0004F , 0x0030B , 0x00150 }, + { 0x0004F , 0x0030C , 0x001D1 }, + { 0x0004F , 0x0030F , 0x0020C }, + { 0x0004F , 0x00311 , 0x0020E }, + { 0x0004F , 0x0031B , 0x001A0 }, + { 0x0004F , 0x00323 , 0x01ECC }, + { 0x0004F , 0x00328 , 0x001EA }, + { 0x00050 , 0x00301 , 0x01E54 }, + { 0x00050 , 0x00307 , 0x01E56 }, + { 0x00052 , 0x00301 , 0x00154 }, + { 0x00052 , 0x00307 , 0x01E58 }, + { 0x00052 , 0x0030C , 0x00158 }, + { 0x00052 , 0x0030F , 0x00210 }, + { 0x00052 , 0x00311 , 0x00212 }, + { 0x00052 , 0x00323 , 0x01E5A }, + { 0x00052 , 0x00327 , 0x00156 }, + { 0x00052 , 0x00331 , 0x01E5E }, + { 0x00053 , 0x00301 , 0x0015A }, + { 0x00053 , 0x00302 , 0x0015C }, + { 0x00053 , 0x00307 , 0x01E60 }, + { 0x00053 , 0x0030C , 0x00160 }, + { 0x00053 , 0x00323 , 0x01E62 }, + { 0x00053 , 0x00326 , 0x00218 }, + { 0x00053 , 0x00327 , 0x0015E }, + { 0x00054 , 0x00307 , 0x01E6A }, + { 0x00054 , 0x0030C , 0x00164 }, + { 0x00054 , 0x00323 , 0x01E6C }, + { 0x00054 , 0x00326 , 0x0021A }, + { 0x00054 , 0x00327 , 0x00162 }, + { 0x00054 , 0x0032D , 0x01E70 }, + { 0x00054 , 0x00331 , 0x01E6E }, + { 0x00055 , 0x00300 , 0x000D9 }, + { 0x00055 , 0x00301 , 0x000DA }, + { 0x00055 , 0x00302 , 0x000DB }, + { 0x00055 , 0x00303 , 0x00168 }, + { 0x00055 , 0x00304 , 0x0016A }, + { 0x00055 , 0x00306 , 0x0016C }, + { 0x00055 , 0x00308 , 0x000DC }, + { 0x00055 , 0x00309 , 0x01EE6 }, + { 0x00055 , 0x0030A , 0x0016E }, + { 0x00055 , 0x0030B , 0x00170 }, + { 0x00055 , 0x0030C , 0x001D3 }, + { 0x00055 , 0x0030F , 0x00214 }, + { 0x00055 , 0x00311 , 0x00216 }, + { 0x00055 , 0x0031B , 0x001AF }, + { 0x00055 , 0x00323 , 0x01EE4 }, + { 0x00055 , 0x00324 , 0x01E72 }, + { 0x00055 , 0x00328 , 0x00172 }, + { 0x00055 , 0x0032D , 0x01E76 }, + { 0x00055 , 0x00330 , 0x01E74 }, + { 0x00056 , 0x00303 , 0x01E7C }, + { 0x00056 , 0x00323 , 0x01E7E }, + { 0x00057 , 0x00300 , 0x01E80 }, + { 0x00057 , 0x00301 , 0x01E82 }, + { 0x00057 , 0x00302 , 0x00174 }, + { 0x00057 , 0x00307 , 0x01E86 }, + { 0x00057 , 0x00308 , 0x01E84 }, + { 0x00057 , 0x00323 , 0x01E88 }, + { 0x00058 , 0x00307 , 0x01E8A }, + { 0x00058 , 0x00308 , 0x01E8C }, + { 0x00059 , 0x00300 , 0x01EF2 }, + { 0x00059 , 0x00301 , 0x000DD }, + { 0x00059 , 0x00302 , 0x00176 }, + { 0x00059 , 0x00303 , 0x01EF8 }, + { 0x00059 , 0x00304 , 0x00232 }, + { 0x00059 , 0x00307 , 0x01E8E }, + { 0x00059 , 0x00308 , 0x00178 }, + { 0x00059 , 0x00309 , 0x01EF6 }, + { 0x00059 , 0x00323 , 0x01EF4 }, + { 0x0005A , 0x00301 , 0x00179 }, + { 0x0005A , 0x00302 , 0x01E90 }, + { 0x0005A , 0x00307 , 0x0017B }, + { 0x0005A , 0x0030C , 0x0017D }, + { 0x0005A , 0x00323 , 0x01E92 }, + { 0x0005A , 0x00331 , 0x01E94 }, + { 0x00061 , 0x00300 , 0x000E0 }, + { 0x00061 , 0x00301 , 0x000E1 }, + { 0x00061 , 0x00302 , 0x000E2 }, + { 0x00061 , 0x00303 , 0x000E3 }, + { 0x00061 , 0x00304 , 0x00101 }, + { 0x00061 , 0x00306 , 0x00103 }, + { 0x00061 , 0x00307 , 0x00227 }, + { 0x00061 , 0x00308 , 0x000E4 }, + { 0x00061 , 0x00309 , 0x01EA3 }, + { 0x00061 , 0x0030A , 0x000E5 }, + { 0x00061 , 0x0030C , 0x001CE }, + { 0x00061 , 0x0030F , 0x00201 }, + { 0x00061 , 0x00311 , 0x00203 }, + { 0x00061 , 0x00323 , 0x01EA1 }, + { 0x00061 , 0x00325 , 0x01E01 }, + { 0x00061 , 0x00328 , 0x00105 }, + { 0x00062 , 0x00307 , 0x01E03 }, + { 0x00062 , 0x00323 , 0x01E05 }, + { 0x00062 , 0x00331 , 0x01E07 }, + { 0x00063 , 0x00301 , 0x00107 }, + { 0x00063 , 0x00302 , 0x00109 }, + { 0x00063 , 0x00307 , 0x0010B }, + { 0x00063 , 0x0030C , 0x0010D }, + { 0x00063 , 0x00327 , 0x000E7 }, + { 0x00064 , 0x00307 , 0x01E0B }, + { 0x00064 , 0x0030C , 0x0010F }, + { 0x00064 , 0x00323 , 0x01E0D }, + { 0x00064 , 0x00327 , 0x01E11 }, + { 0x00064 , 0x0032D , 0x01E13 }, + { 0x00064 , 0x00331 , 0x01E0F }, + { 0x00065 , 0x00300 , 0x000E8 }, + { 0x00065 , 0x00301 , 0x000E9 }, + { 0x00065 , 0x00302 , 0x000EA }, + { 0x00065 , 0x00303 , 0x01EBD }, + { 0x00065 , 0x00304 , 0x00113 }, + { 0x00065 , 0x00306 , 0x00115 }, + { 0x00065 , 0x00307 , 0x00117 }, + { 0x00065 , 0x00308 , 0x000EB }, + { 0x00065 , 0x00309 , 0x01EBB }, + { 0x00065 , 0x0030C , 0x0011B }, + { 0x00065 , 0x0030F , 0x00205 }, + { 0x00065 , 0x00311 , 0x00207 }, + { 0x00065 , 0x00323 , 0x01EB9 }, + { 0x00065 , 0x00327 , 0x00229 }, + { 0x00065 , 0x00328 , 0x00119 }, + { 0x00065 , 0x0032D , 0x01E19 }, + { 0x00065 , 0x00330 , 0x01E1B }, + { 0x00066 , 0x00307 , 0x01E1F }, + { 0x00067 , 0x00301 , 0x001F5 }, + { 0x00067 , 0x00302 , 0x0011D }, + { 0x00067 , 0x00304 , 0x01E21 }, + { 0x00067 , 0x00306 , 0x0011F }, + { 0x00067 , 0x00307 , 0x00121 }, + { 0x00067 , 0x0030C , 0x001E7 }, + { 0x00067 , 0x00327 , 0x00123 }, + { 0x00068 , 0x00302 , 0x00125 }, + { 0x00068 , 0x00307 , 0x01E23 }, + { 0x00068 , 0x00308 , 0x01E27 }, + { 0x00068 , 0x0030C , 0x0021F }, + { 0x00068 , 0x00323 , 0x01E25 }, + { 0x00068 , 0x00327 , 0x01E29 }, + { 0x00068 , 0x0032E , 0x01E2B }, + { 0x00068 , 0x00331 , 0x01E96 }, + { 0x00069 , 0x00300 , 0x000EC }, + { 0x00069 , 0x00301 , 0x000ED }, + { 0x00069 , 0x00302 , 0x000EE }, + { 0x00069 , 0x00303 , 0x00129 }, + { 0x00069 , 0x00304 , 0x0012B }, + { 0x00069 , 0x00306 , 0x0012D }, + { 0x00069 , 0x00308 , 0x000EF }, + { 0x00069 , 0x00309 , 0x01EC9 }, + { 0x00069 , 0x0030C , 0x001D0 }, + { 0x00069 , 0x0030F , 0x00209 }, + { 0x00069 , 0x00311 , 0x0020B }, + { 0x00069 , 0x00323 , 0x01ECB }, + { 0x00069 , 0x00328 , 0x0012F }, + { 0x00069 , 0x00330 , 0x01E2D }, + { 0x0006A , 0x00302 , 0x00135 }, + { 0x0006A , 0x0030C , 0x001F0 }, + { 0x0006B , 0x00301 , 0x01E31 }, + { 0x0006B , 0x0030C , 0x001E9 }, + { 0x0006B , 0x00323 , 0x01E33 }, + { 0x0006B , 0x00327 , 0x00137 }, + { 0x0006B , 0x00331 , 0x01E35 }, + { 0x0006C , 0x00301 , 0x0013A }, + { 0x0006C , 0x0030C , 0x0013E }, + { 0x0006C , 0x00323 , 0x01E37 }, + { 0x0006C , 0x00327 , 0x0013C }, + { 0x0006C , 0x0032D , 0x01E3D }, + { 0x0006C , 0x00331 , 0x01E3B }, + { 0x0006D , 0x00301 , 0x01E3F }, + { 0x0006D , 0x00307 , 0x01E41 }, + { 0x0006D , 0x00323 , 0x01E43 }, + { 0x0006E , 0x00300 , 0x001F9 }, + { 0x0006E , 0x00301 , 0x00144 }, + { 0x0006E , 0x00303 , 0x000F1 }, + { 0x0006E , 0x00307 , 0x01E45 }, + { 0x0006E , 0x0030C , 0x00148 }, + { 0x0006E , 0x00323 , 0x01E47 }, + { 0x0006E , 0x00327 , 0x00146 }, + { 0x0006E , 0x0032D , 0x01E4B }, + { 0x0006E , 0x00331 , 0x01E49 }, + { 0x0006F , 0x00300 , 0x000F2 }, + { 0x0006F , 0x00301 , 0x000F3 }, + { 0x0006F , 0x00302 , 0x000F4 }, + { 0x0006F , 0x00303 , 0x000F5 }, + { 0x0006F , 0x00304 , 0x0014D }, + { 0x0006F , 0x00306 , 0x0014F }, + { 0x0006F , 0x00307 , 0x0022F }, + { 0x0006F , 0x00308 , 0x000F6 }, + { 0x0006F , 0x00309 , 0x01ECF }, + { 0x0006F , 0x0030B , 0x00151 }, + { 0x0006F , 0x0030C , 0x001D2 }, + { 0x0006F , 0x0030F , 0x0020D }, + { 0x0006F , 0x00311 , 0x0020F }, + { 0x0006F , 0x0031B , 0x001A1 }, + { 0x0006F , 0x00323 , 0x01ECD }, + { 0x0006F , 0x00328 , 0x001EB }, + { 0x00070 , 0x00301 , 0x01E55 }, + { 0x00070 , 0x00307 , 0x01E57 }, + { 0x00072 , 0x00301 , 0x00155 }, + { 0x00072 , 0x00307 , 0x01E59 }, + { 0x00072 , 0x0030C , 0x00159 }, + { 0x00072 , 0x0030F , 0x00211 }, + { 0x00072 , 0x00311 , 0x00213 }, + { 0x00072 , 0x00323 , 0x01E5B }, + { 0x00072 , 0x00327 , 0x00157 }, + { 0x00072 , 0x00331 , 0x01E5F }, + { 0x00073 , 0x00301 , 0x0015B }, + { 0x00073 , 0x00302 , 0x0015D }, + { 0x00073 , 0x00307 , 0x01E61 }, + { 0x00073 , 0x0030C , 0x00161 }, + { 0x00073 , 0x00323 , 0x01E63 }, + { 0x00073 , 0x00326 , 0x00219 }, + { 0x00073 , 0x00327 , 0x0015F }, + { 0x00074 , 0x00307 , 0x01E6B }, + { 0x00074 , 0x00308 , 0x01E97 }, + { 0x00074 , 0x0030C , 0x00165 }, + { 0x00074 , 0x00323 , 0x01E6D }, + { 0x00074 , 0x00326 , 0x0021B }, + { 0x00074 , 0x00327 , 0x00163 }, + { 0x00074 , 0x0032D , 0x01E71 }, + { 0x00074 , 0x00331 , 0x01E6F }, + { 0x00075 , 0x00300 , 0x000F9 }, + { 0x00075 , 0x00301 , 0x000FA }, + { 0x00075 , 0x00302 , 0x000FB }, + { 0x00075 , 0x00303 , 0x00169 }, + { 0x00075 , 0x00304 , 0x0016B }, + { 0x00075 , 0x00306 , 0x0016D }, + { 0x00075 , 0x00308 , 0x000FC }, + { 0x00075 , 0x00309 , 0x01EE7 }, + { 0x00075 , 0x0030A , 0x0016F }, + { 0x00075 , 0x0030B , 0x00171 }, + { 0x00075 , 0x0030C , 0x001D4 }, + { 0x00075 , 0x0030F , 0x00215 }, + { 0x00075 , 0x00311 , 0x00217 }, + { 0x00075 , 0x0031B , 0x001B0 }, + { 0x00075 , 0x00323 , 0x01EE5 }, + { 0x00075 , 0x00324 , 0x01E73 }, + { 0x00075 , 0x00328 , 0x00173 }, + { 0x00075 , 0x0032D , 0x01E77 }, + { 0x00075 , 0x00330 , 0x01E75 }, + { 0x00076 , 0x00303 , 0x01E7D }, + { 0x00076 , 0x00323 , 0x01E7F }, + { 0x00077 , 0x00300 , 0x01E81 }, + { 0x00077 , 0x00301 , 0x01E83 }, + { 0x00077 , 0x00302 , 0x00175 }, + { 0x00077 , 0x00307 , 0x01E87 }, + { 0x00077 , 0x00308 , 0x01E85 }, + { 0x00077 , 0x0030A , 0x01E98 }, + { 0x00077 , 0x00323 , 0x01E89 }, + { 0x00078 , 0x00307 , 0x01E8B }, + { 0x00078 , 0x00308 , 0x01E8D }, + { 0x00079 , 0x00300 , 0x01EF3 }, + { 0x00079 , 0x00301 , 0x000FD }, + { 0x00079 , 0x00302 , 0x00177 }, + { 0x00079 , 0x00303 , 0x01EF9 }, + { 0x00079 , 0x00304 , 0x00233 }, + { 0x00079 , 0x00307 , 0x01E8F }, + { 0x00079 , 0x00308 , 0x000FF }, + { 0x00079 , 0x00309 , 0x01EF7 }, + { 0x00079 , 0x0030A , 0x01E99 }, + { 0x00079 , 0x00323 , 0x01EF5 }, + { 0x0007A , 0x00301 , 0x0017A }, + { 0x0007A , 0x00302 , 0x01E91 }, + { 0x0007A , 0x00307 , 0x0017C }, + { 0x0007A , 0x0030C , 0x0017E }, + { 0x0007A , 0x00323 , 0x01E93 }, + { 0x0007A , 0x00331 , 0x01E95 }, + { 0x000A8 , 0x00300 , 0x01FED }, + { 0x000A8 , 0x00301 , 0x00385 }, + { 0x000A8 , 0x00342 , 0x01FC1 }, + { 0x000C2 , 0x00300 , 0x01EA6 }, + { 0x000C2 , 0x00301 , 0x01EA4 }, + { 0x000C2 , 0x00303 , 0x01EAA }, + { 0x000C2 , 0x00309 , 0x01EA8 }, + { 0x000C4 , 0x00304 , 0x001DE }, + { 0x000C5 , 0x00301 , 0x001FA }, + { 0x000C6 , 0x00301 , 0x001FC }, + { 0x000C6 , 0x00304 , 0x001E2 }, + { 0x000C7 , 0x00301 , 0x01E08 }, + { 0x000CA , 0x00300 , 0x01EC0 }, + { 0x000CA , 0x00301 , 0x01EBE }, + { 0x000CA , 0x00303 , 0x01EC4 }, + { 0x000CA , 0x00309 , 0x01EC2 }, + { 0x000CF , 0x00301 , 0x01E2E }, + { 0x000D4 , 0x00300 , 0x01ED2 }, + { 0x000D4 , 0x00301 , 0x01ED0 }, + { 0x000D4 , 0x00303 , 0x01ED6 }, + { 0x000D4 , 0x00309 , 0x01ED4 }, + { 0x000D5 , 0x00301 , 0x01E4C }, + { 0x000D5 , 0x00304 , 0x0022C }, + { 0x000D5 , 0x00308 , 0x01E4E }, + { 0x000D6 , 0x00304 , 0x0022A }, + { 0x000D8 , 0x00301 , 0x001FE }, + { 0x000DC , 0x00300 , 0x001DB }, + { 0x000DC , 0x00301 , 0x001D7 }, + { 0x000DC , 0x00304 , 0x001D5 }, + { 0x000DC , 0x0030C , 0x001D9 }, + { 0x000E2 , 0x00300 , 0x01EA7 }, + { 0x000E2 , 0x00301 , 0x01EA5 }, + { 0x000E2 , 0x00303 , 0x01EAB }, + { 0x000E2 , 0x00309 , 0x01EA9 }, + { 0x000E4 , 0x00304 , 0x001DF }, + { 0x000E5 , 0x00301 , 0x001FB }, + { 0x000E6 , 0x00301 , 0x001FD }, + { 0x000E6 , 0x00304 , 0x001E3 }, + { 0x000E7 , 0x00301 , 0x01E09 }, + { 0x000EA , 0x00300 , 0x01EC1 }, + { 0x000EA , 0x00301 , 0x01EBF }, + { 0x000EA , 0x00303 , 0x01EC5 }, + { 0x000EA , 0x00309 , 0x01EC3 }, + { 0x000EF , 0x00301 , 0x01E2F }, + { 0x000F4 , 0x00300 , 0x01ED3 }, + { 0x000F4 , 0x00301 , 0x01ED1 }, + { 0x000F4 , 0x00303 , 0x01ED7 }, + { 0x000F4 , 0x00309 , 0x01ED5 }, + { 0x000F5 , 0x00301 , 0x01E4D }, + { 0x000F5 , 0x00304 , 0x0022D }, + { 0x000F5 , 0x00308 , 0x01E4F }, + { 0x000F6 , 0x00304 , 0x0022B }, + { 0x000F8 , 0x00301 , 0x001FF }, + { 0x000FC , 0x00300 , 0x001DC }, + { 0x000FC , 0x00301 , 0x001D8 }, + { 0x000FC , 0x00304 , 0x001D6 }, + { 0x000FC , 0x0030C , 0x001DA }, + { 0x00102 , 0x00300 , 0x01EB0 }, + { 0x00102 , 0x00301 , 0x01EAE }, + { 0x00102 , 0x00303 , 0x01EB4 }, + { 0x00102 , 0x00309 , 0x01EB2 }, + { 0x00103 , 0x00300 , 0x01EB1 }, + { 0x00103 , 0x00301 , 0x01EAF }, + { 0x00103 , 0x00303 , 0x01EB5 }, + { 0x00103 , 0x00309 , 0x01EB3 }, + { 0x00112 , 0x00300 , 0x01E14 }, + { 0x00112 , 0x00301 , 0x01E16 }, + { 0x00113 , 0x00300 , 0x01E15 }, + { 0x00113 , 0x00301 , 0x01E17 }, + { 0x0014C , 0x00300 , 0x01E50 }, + { 0x0014C , 0x00301 , 0x01E52 }, + { 0x0014D , 0x00300 , 0x01E51 }, + { 0x0014D , 0x00301 , 0x01E53 }, + { 0x0015A , 0x00307 , 0x01E64 }, + { 0x0015B , 0x00307 , 0x01E65 }, + { 0x00160 , 0x00307 , 0x01E66 }, + { 0x00161 , 0x00307 , 0x01E67 }, + { 0x00168 , 0x00301 , 0x01E78 }, + { 0x00169 , 0x00301 , 0x01E79 }, + { 0x0016A , 0x00308 , 0x01E7A }, + { 0x0016B , 0x00308 , 0x01E7B }, + { 0x0017F , 0x00307 , 0x01E9B }, + { 0x001A0 , 0x00300 , 0x01EDC }, + { 0x001A0 , 0x00301 , 0x01EDA }, + { 0x001A0 , 0x00303 , 0x01EE0 }, + { 0x001A0 , 0x00309 , 0x01EDE }, + { 0x001A0 , 0x00323 , 0x01EE2 }, + { 0x001A1 , 0x00300 , 0x01EDD }, + { 0x001A1 , 0x00301 , 0x01EDB }, + { 0x001A1 , 0x00303 , 0x01EE1 }, + { 0x001A1 , 0x00309 , 0x01EDF }, + { 0x001A1 , 0x00323 , 0x01EE3 }, + { 0x001AF , 0x00300 , 0x01EEA }, + { 0x001AF , 0x00301 , 0x01EE8 }, + { 0x001AF , 0x00303 , 0x01EEE }, + { 0x001AF , 0x00309 , 0x01EEC }, + { 0x001AF , 0x00323 , 0x01EF0 }, + { 0x001B0 , 0x00300 , 0x01EEB }, + { 0x001B0 , 0x00301 , 0x01EE9 }, + { 0x001B0 , 0x00303 , 0x01EEF }, + { 0x001B0 , 0x00309 , 0x01EED }, + { 0x001B0 , 0x00323 , 0x01EF1 }, + { 0x001B7 , 0x0030C , 0x001EE }, + { 0x001EA , 0x00304 , 0x001EC }, + { 0x001EB , 0x00304 , 0x001ED }, + { 0x00226 , 0x00304 , 0x001E0 }, + { 0x00227 , 0x00304 , 0x001E1 }, + { 0x00228 , 0x00306 , 0x01E1C }, + { 0x00229 , 0x00306 , 0x01E1D }, + { 0x0022E , 0x00304 , 0x00230 }, + { 0x0022F , 0x00304 , 0x00231 }, + { 0x00292 , 0x0030C , 0x001EF }, + { 0x00391 , 0x00300 , 0x01FBA }, + { 0x00391 , 0x00301 , 0x00386 }, + { 0x00391 , 0x00304 , 0x01FB9 }, + { 0x00391 , 0x00306 , 0x01FB8 }, + { 0x00391 , 0x00313 , 0x01F08 }, + { 0x00391 , 0x00314 , 0x01F09 }, + { 0x00391 , 0x00345 , 0x01FBC }, + { 0x00395 , 0x00300 , 0x01FC8 }, + { 0x00395 , 0x00301 , 0x00388 }, + { 0x00395 , 0x00313 , 0x01F18 }, + { 0x00395 , 0x00314 , 0x01F19 }, + { 0x00397 , 0x00300 , 0x01FCA }, + { 0x00397 , 0x00301 , 0x00389 }, + { 0x00397 , 0x00313 , 0x01F28 }, + { 0x00397 , 0x00314 , 0x01F29 }, + { 0x00397 , 0x00345 , 0x01FCC }, + { 0x00399 , 0x00300 , 0x01FDA }, + { 0x00399 , 0x00301 , 0x0038A }, + { 0x00399 , 0x00304 , 0x01FD9 }, + { 0x00399 , 0x00306 , 0x01FD8 }, + { 0x00399 , 0x00308 , 0x003AA }, + { 0x00399 , 0x00313 , 0x01F38 }, + { 0x00399 , 0x00314 , 0x01F39 }, + { 0x0039F , 0x00300 , 0x01FF8 }, + { 0x0039F , 0x00301 , 0x0038C }, + { 0x0039F , 0x00313 , 0x01F48 }, + { 0x0039F , 0x00314 , 0x01F49 }, + { 0x003A1 , 0x00314 , 0x01FEC }, + { 0x003A5 , 0x00300 , 0x01FEA }, + { 0x003A5 , 0x00301 , 0x0038E }, + { 0x003A5 , 0x00304 , 0x01FE9 }, + { 0x003A5 , 0x00306 , 0x01FE8 }, + { 0x003A5 , 0x00308 , 0x003AB }, + { 0x003A5 , 0x00314 , 0x01F59 }, + { 0x003A9 , 0x00300 , 0x01FFA }, + { 0x003A9 , 0x00301 , 0x0038F }, + { 0x003A9 , 0x00313 , 0x01F68 }, + { 0x003A9 , 0x00314 , 0x01F69 }, + { 0x003A9 , 0x00345 , 0x01FFC }, + { 0x003AC , 0x00345 , 0x01FB4 }, + { 0x003AE , 0x00345 , 0x01FC4 }, + { 0x003B1 , 0x00300 , 0x01F70 }, + { 0x003B1 , 0x00301 , 0x003AC }, + { 0x003B1 , 0x00304 , 0x01FB1 }, + { 0x003B1 , 0x00306 , 0x01FB0 }, + { 0x003B1 , 0x00313 , 0x01F00 }, + { 0x003B1 , 0x00314 , 0x01F01 }, + { 0x003B1 , 0x00342 , 0x01FB6 }, + { 0x003B1 , 0x00345 , 0x01FB3 }, + { 0x003B5 , 0x00300 , 0x01F72 }, + { 0x003B5 , 0x00301 , 0x003AD }, + { 0x003B5 , 0x00313 , 0x01F10 }, + { 0x003B5 , 0x00314 , 0x01F11 }, + { 0x003B7 , 0x00300 , 0x01F74 }, + { 0x003B7 , 0x00301 , 0x003AE }, + { 0x003B7 , 0x00313 , 0x01F20 }, + { 0x003B7 , 0x00314 , 0x01F21 }, + { 0x003B7 , 0x00342 , 0x01FC6 }, + { 0x003B7 , 0x00345 , 0x01FC3 }, + { 0x003B9 , 0x00300 , 0x01F76 }, + { 0x003B9 , 0x00301 , 0x003AF }, + { 0x003B9 , 0x00304 , 0x01FD1 }, + { 0x003B9 , 0x00306 , 0x01FD0 }, + { 0x003B9 , 0x00308 , 0x003CA }, + { 0x003B9 , 0x00313 , 0x01F30 }, + { 0x003B9 , 0x00314 , 0x01F31 }, + { 0x003B9 , 0x00342 , 0x01FD6 }, + { 0x003BF , 0x00300 , 0x01F78 }, + { 0x003BF , 0x00301 , 0x003CC }, + { 0x003BF , 0x00313 , 0x01F40 }, + { 0x003BF , 0x00314 , 0x01F41 }, + { 0x003C1 , 0x00313 , 0x01FE4 }, + { 0x003C1 , 0x00314 , 0x01FE5 }, + { 0x003C5 , 0x00300 , 0x01F7A }, + { 0x003C5 , 0x00301 , 0x003CD }, + { 0x003C5 , 0x00304 , 0x01FE1 }, + { 0x003C5 , 0x00306 , 0x01FE0 }, + { 0x003C5 , 0x00308 , 0x003CB }, + { 0x003C5 , 0x00313 , 0x01F50 }, + { 0x003C5 , 0x00314 , 0x01F51 }, + { 0x003C5 , 0x00342 , 0x01FE6 }, + { 0x003C9 , 0x00300 , 0x01F7C }, + { 0x003C9 , 0x00301 , 0x003CE }, + { 0x003C9 , 0x00313 , 0x01F60 }, + { 0x003C9 , 0x00314 , 0x01F61 }, + { 0x003C9 , 0x00342 , 0x01FF6 }, + { 0x003C9 , 0x00345 , 0x01FF3 }, + { 0x003CA , 0x00300 , 0x01FD2 }, + { 0x003CA , 0x00301 , 0x00390 }, + { 0x003CA , 0x00342 , 0x01FD7 }, + { 0x003CB , 0x00300 , 0x01FE2 }, + { 0x003CB , 0x00301 , 0x003B0 }, + { 0x003CB , 0x00342 , 0x01FE7 }, + { 0x003CE , 0x00345 , 0x01FF4 }, + { 0x003D2 , 0x00301 , 0x003D3 }, + { 0x003D2 , 0x00308 , 0x003D4 }, + { 0x00406 , 0x00308 , 0x00407 }, + { 0x00410 , 0x00306 , 0x004D0 }, + { 0x00410 , 0x00308 , 0x004D2 }, + { 0x00413 , 0x00301 , 0x00403 }, + { 0x00415 , 0x00300 , 0x00400 }, + { 0x00415 , 0x00306 , 0x004D6 }, + { 0x00415 , 0x00308 , 0x00401 }, + { 0x00416 , 0x00306 , 0x004C1 }, + { 0x00416 , 0x00308 , 0x004DC }, + { 0x00417 , 0x00308 , 0x004DE }, + { 0x00418 , 0x00300 , 0x0040D }, + { 0x00418 , 0x00304 , 0x004E2 }, + { 0x00418 , 0x00306 , 0x00419 }, + { 0x00418 , 0x00308 , 0x004E4 }, + { 0x0041A , 0x00301 , 0x0040C }, + { 0x0041E , 0x00308 , 0x004E6 }, + { 0x00423 , 0x00304 , 0x004EE }, + { 0x00423 , 0x00306 , 0x0040E }, + { 0x00423 , 0x00308 , 0x004F0 }, + { 0x00423 , 0x0030B , 0x004F2 }, + { 0x00427 , 0x00308 , 0x004F4 }, + { 0x0042B , 0x00308 , 0x004F8 }, + { 0x0042D , 0x00308 , 0x004EC }, + { 0x00430 , 0x00306 , 0x004D1 }, + { 0x00430 , 0x00308 , 0x004D3 }, + { 0x00433 , 0x00301 , 0x00453 }, + { 0x00435 , 0x00300 , 0x00450 }, + { 0x00435 , 0x00306 , 0x004D7 }, + { 0x00435 , 0x00308 , 0x00451 }, + { 0x00436 , 0x00306 , 0x004C2 }, + { 0x00436 , 0x00308 , 0x004DD }, + { 0x00437 , 0x00308 , 0x004DF }, + { 0x00438 , 0x00300 , 0x0045D }, + { 0x00438 , 0x00304 , 0x004E3 }, + { 0x00438 , 0x00306 , 0x00439 }, + { 0x00438 , 0x00308 , 0x004E5 }, + { 0x0043A , 0x00301 , 0x0045C }, + { 0x0043E , 0x00308 , 0x004E7 }, + { 0x00443 , 0x00304 , 0x004EF }, + { 0x00443 , 0x00306 , 0x0045E }, + { 0x00443 , 0x00308 , 0x004F1 }, + { 0x00443 , 0x0030B , 0x004F3 }, + { 0x00447 , 0x00308 , 0x004F5 }, + { 0x0044B , 0x00308 , 0x004F9 }, + { 0x0044D , 0x00308 , 0x004ED }, + { 0x00456 , 0x00308 , 0x00457 }, + { 0x00474 , 0x0030F , 0x00476 }, + { 0x00475 , 0x0030F , 0x00477 }, + { 0x004D8 , 0x00308 , 0x004DA }, + { 0x004D9 , 0x00308 , 0x004DB }, + { 0x004E8 , 0x00308 , 0x004EA }, + { 0x004E9 , 0x00308 , 0x004EB }, + { 0x00627 , 0x00653 , 0x00622 }, + { 0x00627 , 0x00654 , 0x00623 }, + { 0x00627 , 0x00655 , 0x00625 }, + { 0x00648 , 0x00654 , 0x00624 }, + { 0x0064A , 0x00654 , 0x00626 }, + { 0x006C1 , 0x00654 , 0x006C2 }, + { 0x006D2 , 0x00654 , 0x006D3 }, + { 0x006D5 , 0x00654 , 0x006C0 }, + { 0x00928 , 0x0093C , 0x00929 }, + { 0x00930 , 0x0093C , 0x00931 }, + { 0x00933 , 0x0093C , 0x00934 }, + { 0x009C7 , 0x009BE , 0x009CB }, + { 0x009C7 , 0x009D7 , 0x009CC }, + { 0x00B47 , 0x00B3E , 0x00B4B }, + { 0x00B47 , 0x00B56 , 0x00B48 }, + { 0x00B47 , 0x00B57 , 0x00B4C }, + { 0x00B92 , 0x00BD7 , 0x00B94 }, + { 0x00BC6 , 0x00BBE , 0x00BCA }, + { 0x00BC6 , 0x00BD7 , 0x00BCC }, + { 0x00BC7 , 0x00BBE , 0x00BCB }, + { 0x00C46 , 0x00C56 , 0x00C48 }, + { 0x00CBF , 0x00CD5 , 0x00CC0 }, + { 0x00CC6 , 0x00CC2 , 0x00CCA }, + { 0x00CC6 , 0x00CD5 , 0x00CC7 }, + { 0x00CC6 , 0x00CD6 , 0x00CC8 }, + { 0x00CCA , 0x00CD5 , 0x00CCB }, + { 0x00D46 , 0x00D3E , 0x00D4A }, + { 0x00D46 , 0x00D57 , 0x00D4C }, + { 0x00D47 , 0x00D3E , 0x00D4B }, + { 0x00DD9 , 0x00DCA , 0x00DDA }, + { 0x00DD9 , 0x00DCF , 0x00DDC }, + { 0x00DD9 , 0x00DDF , 0x00DDE }, + { 0x00DDC , 0x00DCA , 0x00DDD }, + { 0x01025 , 0x0102E , 0x01026 }, + { 0x01B05 , 0x01B35 , 0x01B06 }, + { 0x01B07 , 0x01B35 , 0x01B08 }, + { 0x01B09 , 0x01B35 , 0x01B0A }, + { 0x01B0B , 0x01B35 , 0x01B0C }, + { 0x01B0D , 0x01B35 , 0x01B0E }, + { 0x01B11 , 0x01B35 , 0x01B12 }, + { 0x01B3A , 0x01B35 , 0x01B3B }, + { 0x01B3C , 0x01B35 , 0x01B3D }, + { 0x01B3E , 0x01B35 , 0x01B40 }, + { 0x01B3F , 0x01B35 , 0x01B41 }, + { 0x01B42 , 0x01B35 , 0x01B43 }, + { 0x01E36 , 0x00304 , 0x01E38 }, + { 0x01E37 , 0x00304 , 0x01E39 }, + { 0x01E5A , 0x00304 , 0x01E5C }, + { 0x01E5B , 0x00304 , 0x01E5D }, + { 0x01E62 , 0x00307 , 0x01E68 }, + { 0x01E63 , 0x00307 , 0x01E69 }, + { 0x01EA0 , 0x00302 , 0x01EAC }, + { 0x01EA0 , 0x00306 , 0x01EB6 }, + { 0x01EA1 , 0x00302 , 0x01EAD }, + { 0x01EA1 , 0x00306 , 0x01EB7 }, + { 0x01EB8 , 0x00302 , 0x01EC6 }, + { 0x01EB9 , 0x00302 , 0x01EC7 }, + { 0x01ECC , 0x00302 , 0x01ED8 }, + { 0x01ECD , 0x00302 , 0x01ED9 }, + { 0x01F00 , 0x00300 , 0x01F02 }, + { 0x01F00 , 0x00301 , 0x01F04 }, + { 0x01F00 , 0x00342 , 0x01F06 }, + { 0x01F00 , 0x00345 , 0x01F80 }, + { 0x01F01 , 0x00300 , 0x01F03 }, + { 0x01F01 , 0x00301 , 0x01F05 }, + { 0x01F01 , 0x00342 , 0x01F07 }, + { 0x01F01 , 0x00345 , 0x01F81 }, + { 0x01F02 , 0x00345 , 0x01F82 }, + { 0x01F03 , 0x00345 , 0x01F83 }, + { 0x01F04 , 0x00345 , 0x01F84 }, + { 0x01F05 , 0x00345 , 0x01F85 }, + { 0x01F06 , 0x00345 , 0x01F86 }, + { 0x01F07 , 0x00345 , 0x01F87 }, + { 0x01F08 , 0x00300 , 0x01F0A }, + { 0x01F08 , 0x00301 , 0x01F0C }, + { 0x01F08 , 0x00342 , 0x01F0E }, + { 0x01F08 , 0x00345 , 0x01F88 }, + { 0x01F09 , 0x00300 , 0x01F0B }, + { 0x01F09 , 0x00301 , 0x01F0D }, + { 0x01F09 , 0x00342 , 0x01F0F }, + { 0x01F09 , 0x00345 , 0x01F89 }, + { 0x01F0A , 0x00345 , 0x01F8A }, + { 0x01F0B , 0x00345 , 0x01F8B }, + { 0x01F0C , 0x00345 , 0x01F8C }, + { 0x01F0D , 0x00345 , 0x01F8D }, + { 0x01F0E , 0x00345 , 0x01F8E }, + { 0x01F0F , 0x00345 , 0x01F8F }, + { 0x01F10 , 0x00300 , 0x01F12 }, + { 0x01F10 , 0x00301 , 0x01F14 }, + { 0x01F11 , 0x00300 , 0x01F13 }, + { 0x01F11 , 0x00301 , 0x01F15 }, + { 0x01F18 , 0x00300 , 0x01F1A }, + { 0x01F18 , 0x00301 , 0x01F1C }, + { 0x01F19 , 0x00300 , 0x01F1B }, + { 0x01F19 , 0x00301 , 0x01F1D }, + { 0x01F20 , 0x00300 , 0x01F22 }, + { 0x01F20 , 0x00301 , 0x01F24 }, + { 0x01F20 , 0x00342 , 0x01F26 }, + { 0x01F20 , 0x00345 , 0x01F90 }, + { 0x01F21 , 0x00300 , 0x01F23 }, + { 0x01F21 , 0x00301 , 0x01F25 }, + { 0x01F21 , 0x00342 , 0x01F27 }, + { 0x01F21 , 0x00345 , 0x01F91 }, + { 0x01F22 , 0x00345 , 0x01F92 }, + { 0x01F23 , 0x00345 , 0x01F93 }, + { 0x01F24 , 0x00345 , 0x01F94 }, + { 0x01F25 , 0x00345 , 0x01F95 }, + { 0x01F26 , 0x00345 , 0x01F96 }, + { 0x01F27 , 0x00345 , 0x01F97 }, + { 0x01F28 , 0x00300 , 0x01F2A }, + { 0x01F28 , 0x00301 , 0x01F2C }, + { 0x01F28 , 0x00342 , 0x01F2E }, + { 0x01F28 , 0x00345 , 0x01F98 }, + { 0x01F29 , 0x00300 , 0x01F2B }, + { 0x01F29 , 0x00301 , 0x01F2D }, + { 0x01F29 , 0x00342 , 0x01F2F }, + { 0x01F29 , 0x00345 , 0x01F99 }, + { 0x01F2A , 0x00345 , 0x01F9A }, + { 0x01F2B , 0x00345 , 0x01F9B }, + { 0x01F2C , 0x00345 , 0x01F9C }, + { 0x01F2D , 0x00345 , 0x01F9D }, + { 0x01F2E , 0x00345 , 0x01F9E }, + { 0x01F2F , 0x00345 , 0x01F9F }, + { 0x01F30 , 0x00300 , 0x01F32 }, + { 0x01F30 , 0x00301 , 0x01F34 }, + { 0x01F30 , 0x00342 , 0x01F36 }, + { 0x01F31 , 0x00300 , 0x01F33 }, + { 0x01F31 , 0x00301 , 0x01F35 }, + { 0x01F31 , 0x00342 , 0x01F37 }, + { 0x01F38 , 0x00300 , 0x01F3A }, + { 0x01F38 , 0x00301 , 0x01F3C }, + { 0x01F38 , 0x00342 , 0x01F3E }, + { 0x01F39 , 0x00300 , 0x01F3B }, + { 0x01F39 , 0x00301 , 0x01F3D }, + { 0x01F39 , 0x00342 , 0x01F3F }, + { 0x01F40 , 0x00300 , 0x01F42 }, + { 0x01F40 , 0x00301 , 0x01F44 }, + { 0x01F41 , 0x00300 , 0x01F43 }, + { 0x01F41 , 0x00301 , 0x01F45 }, + { 0x01F48 , 0x00300 , 0x01F4A }, + { 0x01F48 , 0x00301 , 0x01F4C }, + { 0x01F49 , 0x00300 , 0x01F4B }, + { 0x01F49 , 0x00301 , 0x01F4D }, + { 0x01F50 , 0x00300 , 0x01F52 }, + { 0x01F50 , 0x00301 , 0x01F54 }, + { 0x01F50 , 0x00342 , 0x01F56 }, + { 0x01F51 , 0x00300 , 0x01F53 }, + { 0x01F51 , 0x00301 , 0x01F55 }, + { 0x01F51 , 0x00342 , 0x01F57 }, + { 0x01F59 , 0x00300 , 0x01F5B }, + { 0x01F59 , 0x00301 , 0x01F5D }, + { 0x01F59 , 0x00342 , 0x01F5F }, + { 0x01F60 , 0x00300 , 0x01F62 }, + { 0x01F60 , 0x00301 , 0x01F64 }, + { 0x01F60 , 0x00342 , 0x01F66 }, + { 0x01F60 , 0x00345 , 0x01FA0 }, + { 0x01F61 , 0x00300 , 0x01F63 }, + { 0x01F61 , 0x00301 , 0x01F65 }, + { 0x01F61 , 0x00342 , 0x01F67 }, + { 0x01F61 , 0x00345 , 0x01FA1 }, + { 0x01F62 , 0x00345 , 0x01FA2 }, + { 0x01F63 , 0x00345 , 0x01FA3 }, + { 0x01F64 , 0x00345 , 0x01FA4 }, + { 0x01F65 , 0x00345 , 0x01FA5 }, + { 0x01F66 , 0x00345 , 0x01FA6 }, + { 0x01F67 , 0x00345 , 0x01FA7 }, + { 0x01F68 , 0x00300 , 0x01F6A }, + { 0x01F68 , 0x00301 , 0x01F6C }, + { 0x01F68 , 0x00342 , 0x01F6E }, + { 0x01F68 , 0x00345 , 0x01FA8 }, + { 0x01F69 , 0x00300 , 0x01F6B }, + { 0x01F69 , 0x00301 , 0x01F6D }, + { 0x01F69 , 0x00342 , 0x01F6F }, + { 0x01F69 , 0x00345 , 0x01FA9 }, + { 0x01F6A , 0x00345 , 0x01FAA }, + { 0x01F6B , 0x00345 , 0x01FAB }, + { 0x01F6C , 0x00345 , 0x01FAC }, + { 0x01F6D , 0x00345 , 0x01FAD }, + { 0x01F6E , 0x00345 , 0x01FAE }, + { 0x01F6F , 0x00345 , 0x01FAF }, + { 0x01F70 , 0x00345 , 0x01FB2 }, + { 0x01F74 , 0x00345 , 0x01FC2 }, + { 0x01F7C , 0x00345 , 0x01FF2 }, + { 0x01FB6 , 0x00345 , 0x01FB7 }, + { 0x01FBF , 0x00300 , 0x01FCD }, + { 0x01FBF , 0x00301 , 0x01FCE }, + { 0x01FBF , 0x00342 , 0x01FCF }, + { 0x01FC6 , 0x00345 , 0x01FC7 }, + { 0x01FF6 , 0x00345 , 0x01FF7 }, + { 0x01FFE , 0x00300 , 0x01FDD }, + { 0x01FFE , 0x00301 , 0x01FDE }, + { 0x01FFE , 0x00342 , 0x01FDF }, + { 0x02190 , 0x00338 , 0x0219A }, + { 0x02192 , 0x00338 , 0x0219B }, + { 0x02194 , 0x00338 , 0x021AE }, + { 0x021D0 , 0x00338 , 0x021CD }, + { 0x021D2 , 0x00338 , 0x021CF }, + { 0x021D4 , 0x00338 , 0x021CE }, + { 0x02203 , 0x00338 , 0x02204 }, + { 0x02208 , 0x00338 , 0x02209 }, + { 0x0220B , 0x00338 , 0x0220C }, + { 0x02223 , 0x00338 , 0x02224 }, + { 0x02225 , 0x00338 , 0x02226 }, + { 0x0223C , 0x00338 , 0x02241 }, + { 0x02243 , 0x00338 , 0x02244 }, + { 0x02245 , 0x00338 , 0x02247 }, + { 0x02248 , 0x00338 , 0x02249 }, + { 0x0224D , 0x00338 , 0x0226D }, + { 0x02261 , 0x00338 , 0x02262 }, + { 0x02264 , 0x00338 , 0x02270 }, + { 0x02265 , 0x00338 , 0x02271 }, + { 0x02272 , 0x00338 , 0x02274 }, + { 0x02273 , 0x00338 , 0x02275 }, + { 0x02276 , 0x00338 , 0x02278 }, + { 0x02277 , 0x00338 , 0x02279 }, + { 0x0227A , 0x00338 , 0x02280 }, + { 0x0227B , 0x00338 , 0x02281 }, + { 0x0227C , 0x00338 , 0x022E0 }, + { 0x0227D , 0x00338 , 0x022E1 }, + { 0x02282 , 0x00338 , 0x02284 }, + { 0x02283 , 0x00338 , 0x02285 }, + { 0x02286 , 0x00338 , 0x02288 }, + { 0x02287 , 0x00338 , 0x02289 }, + { 0x02291 , 0x00338 , 0x022E2 }, + { 0x02292 , 0x00338 , 0x022E3 }, + { 0x022A2 , 0x00338 , 0x022AC }, + { 0x022A8 , 0x00338 , 0x022AD }, + { 0x022A9 , 0x00338 , 0x022AE }, + { 0x022AB , 0x00338 , 0x022AF }, + { 0x022B2 , 0x00338 , 0x022EA }, + { 0x022B3 , 0x00338 , 0x022EB }, + { 0x022B4 , 0x00338 , 0x022EC }, + { 0x022B5 , 0x00338 , 0x022ED }, + { 0x03046 , 0x03099 , 0x03094 }, + { 0x0304B , 0x03099 , 0x0304C }, + { 0x0304D , 0x03099 , 0x0304E }, + { 0x0304F , 0x03099 , 0x03050 }, + { 0x03051 , 0x03099 , 0x03052 }, + { 0x03053 , 0x03099 , 0x03054 }, + { 0x03055 , 0x03099 , 0x03056 }, + { 0x03057 , 0x03099 , 0x03058 }, + { 0x03059 , 0x03099 , 0x0305A }, + { 0x0305B , 0x03099 , 0x0305C }, + { 0x0305D , 0x03099 , 0x0305E }, + { 0x0305F , 0x03099 , 0x03060 }, + { 0x03061 , 0x03099 , 0x03062 }, + { 0x03064 , 0x03099 , 0x03065 }, + { 0x03066 , 0x03099 , 0x03067 }, + { 0x03068 , 0x03099 , 0x03069 }, + { 0x0306F , 0x03099 , 0x03070 }, + { 0x0306F , 0x0309A , 0x03071 }, + { 0x03072 , 0x03099 , 0x03073 }, + { 0x03072 , 0x0309A , 0x03074 }, + { 0x03075 , 0x03099 , 0x03076 }, + { 0x03075 , 0x0309A , 0x03077 }, + { 0x03078 , 0x03099 , 0x03079 }, + { 0x03078 , 0x0309A , 0x0307A }, + { 0x0307B , 0x03099 , 0x0307C }, + { 0x0307B , 0x0309A , 0x0307D }, + { 0x0309D , 0x03099 , 0x0309E }, + { 0x030A6 , 0x03099 , 0x030F4 }, + { 0x030AB , 0x03099 , 0x030AC }, + { 0x030AD , 0x03099 , 0x030AE }, + { 0x030AF , 0x03099 , 0x030B0 }, + { 0x030B1 , 0x03099 , 0x030B2 }, + { 0x030B3 , 0x03099 , 0x030B4 }, + { 0x030B5 , 0x03099 , 0x030B6 }, + { 0x030B7 , 0x03099 , 0x030B8 }, + { 0x030B9 , 0x03099 , 0x030BA }, + { 0x030BB , 0x03099 , 0x030BC }, + { 0x030BD , 0x03099 , 0x030BE }, + { 0x030BF , 0x03099 , 0x030C0 }, + { 0x030C1 , 0x03099 , 0x030C2 }, + { 0x030C4 , 0x03099 , 0x030C5 }, + { 0x030C6 , 0x03099 , 0x030C7 }, + { 0x030C8 , 0x03099 , 0x030C9 }, + { 0x030CF , 0x03099 , 0x030D0 }, + { 0x030CF , 0x0309A , 0x030D1 }, + { 0x030D2 , 0x03099 , 0x030D3 }, + { 0x030D2 , 0x0309A , 0x030D4 }, + { 0x030D5 , 0x03099 , 0x030D6 }, + { 0x030D5 , 0x0309A , 0x030D7 }, + { 0x030D8 , 0x03099 , 0x030D9 }, + { 0x030D8 , 0x0309A , 0x030DA }, + { 0x030DB , 0x03099 , 0x030DC }, + { 0x030DB , 0x0309A , 0x030DD }, + { 0x030EF , 0x03099 , 0x030F7 }, + { 0x030F0 , 0x03099 , 0x030F8 }, + { 0x030F1 , 0x03099 , 0x030F9 }, + { 0x030F2 , 0x03099 , 0x030FA }, + { 0x030FD , 0x03099 , 0x030FE }, + { 0x11099 , 0x110BA , 0x1109A }, + { 0x1109B , 0x110BA , 0x1109C }, + { 0x110A5 , 0x110BA , 0x110AB }, +}; + +#define CANONICAL_CLASS_MIN 0x0300 +#define CANONICAL_CLASS_MAX 0x1D244 + +#define IS_DECOMPOSABLE_BLOCK(uc) \ + (((uc)>>8) <= 0x1D2 && u_decomposable_blocks[(uc)>>8]) +static const char u_decomposable_blocks[0x1D2+1] = { + 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, + 0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +}; + +/* Get Canonical Combining Class(CCC). */ +#define CCC(uc) \ + (((uc) > 0x1D244)?0:\ + ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F]) + +/* The table of the value of Canonical Combining Class */ +static const unsigned char ccc_val[][16] = { + /* idx=0: XXXX0 - XXXXF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=1: 00300 - 0030F */ + {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=2: 00310 - 0031F */ + {230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220 }, + /* idx=3: 00320 - 0032F */ + {220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220 }, + /* idx=4: 00330 - 0033F */ + {220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230 }, + /* idx=5: 00340 - 0034F */ + {230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0 }, + /* idx=6: 00350 - 0035F */ + {230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220, 230, 233, 234, 234, 233 }, + /* idx=7: 00360 - 0036F */ + {234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=8: 00480 - 0048F */ + {0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=9: 00590 - 0059F */ + {0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230 }, + /* idx=10: 005A0 - 005AF */ + {230, 230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230 }, + /* idx=11: 005B0 - 005BF */ + {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23 }, + /* idx=12: 005C0 - 005CF */ + {0, 24, 25, 0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=13: 00610 - 0061F */ + {230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, 0, 0 }, + /* idx=14: 00640 - 0064F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31 }, + /* idx=15: 00650 - 0065F */ + {32, 33, 34, 230, 230, 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 220 }, + /* idx=16: 00670 - 0067F */ + {35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=17: 006D0 - 006DF */ + {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230 }, + /* idx=18: 006E0 - 006EF */ + {230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0 }, + /* idx=19: 00710 - 0071F */ + {0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=20: 00730 - 0073F */ + {230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230 }, + /* idx=21: 00740 - 0074F */ + {230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, 0, 0 }, + /* idx=22: 007E0 - 007EF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230 }, + /* idx=23: 007F0 - 007FF */ + {230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=24: 00810 - 0081F */ + {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230 }, + /* idx=25: 00820 - 0082F */ + {230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0 }, + /* idx=26: 00850 - 0085F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0, 0, 0 }, + /* idx=27: 00930 - 0093F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=28: 00940 - 0094F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=29: 00950 - 0095F */ + {0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=30: 009B0 - 009BF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=31: 009C0 - 009CF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=32: 00A30 - 00A3F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=33: 00A40 - 00A4F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=34: 00AB0 - 00ABF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=35: 00AC0 - 00ACF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=36: 00B30 - 00B3F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=37: 00B40 - 00B4F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=38: 00BC0 - 00BCF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=39: 00C40 - 00C4F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=40: 00C50 - 00C5F */ + {0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=41: 00CB0 - 00CBF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 }, + /* idx=42: 00CC0 - 00CCF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=43: 00D40 - 00D4F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=44: 00DC0 - 00DCF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 }, + /* idx=45: 00E30 - 00E3F */ + {0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0 }, + /* idx=46: 00E40 - 00E4F */ + {0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0 }, + /* idx=47: 00EB0 - 00EBF */ + {0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0, 0, 0, 0, 0 }, + /* idx=48: 00EC0 - 00ECF */ + {0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0 }, + /* idx=49: 00F10 - 00F1F */ + {0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0 }, + /* idx=50: 00F30 - 00F3F */ + {0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0 }, + /* idx=51: 00F70 - 00F7F */ + {0, 129, 130, 0, 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0 }, + /* idx=52: 00F80 - 00F8F */ + {130, 0, 230, 230, 9, 0, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=53: 00FC0 - 00FCF */ + {0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=54: 01030 - 0103F */ + {0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0 }, + /* idx=55: 01080 - 0108F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, + /* idx=56: 01350 - 0135F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230 }, + /* idx=57: 01710 - 0171F */ + {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=58: 01730 - 0173F */ + {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=59: 017D0 - 017DF */ + {0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0 }, + /* idx=60: 018A0 - 018AF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0 }, + /* idx=61: 01930 - 0193F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0 }, + /* idx=62: 01A10 - 01A1F */ + {0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=63: 01A60 - 01A6F */ + {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=64: 01A70 - 01A7F */ + {0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 220 }, + /* idx=65: 01B30 - 01B3F */ + {0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=66: 01B40 - 01B4F */ + {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=67: 01B60 - 01B6F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230 }, + /* idx=68: 01B70 - 01B7F */ + {230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=69: 01BA0 - 01BAF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 }, + /* idx=70: 01BE0 - 01BEF */ + {0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=71: 01BF0 - 01BFF */ + {0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=72: 01C30 - 01C3F */ + {0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=73: 01CD0 - 01CDF */ + {230, 230, 230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220 }, + /* idx=74: 01CE0 - 01CEF */ + {230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0 }, + /* idx=75: 01DC0 - 01DCF */ + {230, 230, 220, 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220 }, + /* idx=76: 01DD0 - 01DDF */ + {202, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=77: 01DE0 - 01DEF */ + {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=78: 01DF0 - 01DFF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 220, 230, 220 }, + /* idx=79: 020D0 - 020DF */ + {230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0 }, + /* idx=80: 020E0 - 020EF */ + {0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220 }, + /* idx=81: 020F0 - 020FF */ + {230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=82: 02CE0 - 02CEF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 }, + /* idx=83: 02CF0 - 02CFF */ + {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=84: 02D70 - 02D7F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }, + /* idx=85: 02DE0 - 02DEF */ + {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=86: 02DF0 - 02DFF */ + {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=87: 03020 - 0302F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224 }, + /* idx=88: 03090 - 0309F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0 }, + /* idx=89: 0A660 - 0A66F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 }, + /* idx=90: 0A670 - 0A67F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0 }, + /* idx=91: 0A6F0 - 0A6FF */ + {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=92: 0A800 - 0A80F */ + {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=93: 0A8C0 - 0A8CF */ + {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=94: 0A8E0 - 0A8EF */ + {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 }, + /* idx=95: 0A8F0 - 0A8FF */ + {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=96: 0A920 - 0A92F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0 }, + /* idx=97: 0A950 - 0A95F */ + {0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=98: 0A9B0 - 0A9BF */ + {0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=99: 0A9C0 - 0A9CF */ + {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=100: 0AAB0 - 0AABF */ + {230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0, 230, 230 }, + /* idx=101: 0AAC0 - 0AACF */ + {0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=102: 0ABE0 - 0ABEF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 }, + /* idx=103: 0FB10 - 0FB1F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0 }, + /* idx=104: 0FE20 - 0FE2F */ + {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=105: 101F0 - 101FF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, + /* idx=106: 10A00 - 10A0F */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230 }, + /* idx=107: 10A30 - 10A3F */ + {0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, 0, 0, 0, 9 }, + /* idx=108: 11040 - 1104F */ + {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=109: 110B0 - 110BF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0 }, + /* idx=110: 1D160 - 1D16F */ + {0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216 }, + /* idx=111: 1D170 - 1D17F */ + {216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220 }, + /* idx=112: 1D180 - 1D18F */ + {220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0 }, + /* idx=113: 1D1A0 - 1D1AF */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0 }, + /* idx=114: 1D240 - 1D24F */ + {0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* The index table to ccc_val[*][16] */ +static const unsigned char ccc_val_index[][16] = { + /* idx=0: XXX00 - XXXFF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=1: 00300 - 003FF */ + { 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=2: 00400 - 004FF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=3: 00500 - 005FF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,10,11,12, 0, 0, 0 }, + /* idx=4: 00600 - 006FF */ + { 0,13, 0, 0,14,15, 0,16, 0, 0, 0, 0, 0,17,18, 0 }, + /* idx=5: 00700 - 007FF */ + { 0,19, 0,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0,22,23 }, + /* idx=6: 00800 - 008FF */ + { 0,24,25, 0, 0,26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=7: 00900 - 009FF */ + { 0, 0, 0,27,28,29, 0, 0, 0, 0, 0,30,31, 0, 0, 0 }, + /* idx=8: 00A00 - 00AFF */ + { 0, 0, 0,32,33, 0, 0, 0, 0, 0, 0,34,35, 0, 0, 0 }, + /* idx=9: 00B00 - 00BFF */ + { 0, 0, 0,36,37, 0, 0, 0, 0, 0, 0, 0,38, 0, 0, 0 }, + /* idx=10: 00C00 - 00CFF */ + { 0, 0, 0, 0,39,40, 0, 0, 0, 0, 0,41,42, 0, 0, 0 }, + /* idx=11: 00D00 - 00DFF */ + { 0, 0, 0, 0,43, 0, 0, 0, 0, 0, 0, 0,44, 0, 0, 0 }, + /* idx=12: 00E00 - 00EFF */ + { 0, 0, 0,45,46, 0, 0, 0, 0, 0, 0,47,48, 0, 0, 0 }, + /* idx=13: 00F00 - 00FFF */ + { 0,49, 0,50, 0, 0, 0,51,52, 0, 0, 0,53, 0, 0, 0 }, + /* idx=14: 01000 - 010FF */ + { 0, 0, 0,54, 0, 0, 0, 0,55, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=15: 01300 - 013FF */ + { 0, 0, 0, 0, 0,56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=16: 01700 - 017FF */ + { 0,57, 0,58, 0, 0, 0, 0, 0, 0, 0, 0, 0,59, 0, 0 }, + /* idx=17: 01800 - 018FF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,60, 0, 0, 0, 0, 0 }, + /* idx=18: 01900 - 019FF */ + { 0, 0, 0,61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=19: 01A00 - 01AFF */ + { 0,62, 0, 0, 0, 0,63,64, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=20: 01B00 - 01BFF */ + { 0, 0, 0,65,66, 0,67,68, 0, 0,69, 0, 0, 0,70,71 }, + /* idx=21: 01C00 - 01CFF */ + { 0, 0, 0,72, 0, 0, 0, 0, 0, 0, 0, 0, 0,73,74, 0 }, + /* idx=22: 01D00 - 01DFF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,75,76,77,78 }, + /* idx=23: 02000 - 020FF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,79,80,81 }, + /* idx=24: 02C00 - 02CFF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,82,83 }, + /* idx=25: 02D00 - 02DFF */ + { 0, 0, 0, 0, 0, 0, 0,84, 0, 0, 0, 0, 0, 0,85,86 }, + /* idx=26: 03000 - 030FF */ + { 0, 0,87, 0, 0, 0, 0, 0, 0,88, 0, 0, 0, 0, 0, 0 }, + /* idx=27: 0A600 - 0A6FF */ + { 0, 0, 0, 0, 0, 0,89,90, 0, 0, 0, 0, 0, 0, 0,91 }, + /* idx=28: 0A800 - 0A8FF */ + {92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,93, 0,94,95 }, + /* idx=29: 0A900 - 0A9FF */ + { 0, 0,96, 0, 0,97, 0, 0, 0, 0, 0,98,99, 0, 0, 0 }, + /* idx=30: 0AA00 - 0AAFF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,101, 0, 0, 0 }, + /* idx=31: 0AB00 - 0ABFF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0 }, + /* idx=32: 0FB00 - 0FBFF */ + { 0,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=33: 0FE00 - 0FEFF */ + { 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=34: 10100 - 101FF */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105 }, + /* idx=35: 10A00 - 10AFF */ + {106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* idx=36: 11000 - 110FF */ + { 0, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0 }, + /* idx=37: 1D100 - 1D1FF */ + { 0, 0, 0, 0, 0, 0,110,111,112, 0,113, 0, 0, 0, 0, 0 }, + /* idx=38: 1D200 - 1D2FF */ + { 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* The index table to ccc_val_index[*][16] */ +static const unsigned char ccc_index[] = { + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 0, 0,15, 0, 0, 0,16, + 17,18,19,20,21,22, 0, 0,23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,24,25, 0, 0, + 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,27, 0, + 28,29,30,31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0, 0,33, 0, 0,34, 0, 0, 0, 0, 0, 0, + 0, 0,35, 0, 0, 0, 0, 0,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,}; + +struct unicode_decomposition_table { + uint32_t nfc; + uint32_t cp1; + uint32_t cp2; +}; + +static const struct unicode_decomposition_table u_decomposition_table[] = { + { 0x000C0 , 0x00041 , 0x00300 }, + { 0x000C1 , 0x00041 , 0x00301 }, + { 0x000C2 , 0x00041 , 0x00302 }, + { 0x000C3 , 0x00041 , 0x00303 }, + { 0x000C4 , 0x00041 , 0x00308 }, + { 0x000C5 , 0x00041 , 0x0030A }, + { 0x000C7 , 0x00043 , 0x00327 }, + { 0x000C8 , 0x00045 , 0x00300 }, + { 0x000C9 , 0x00045 , 0x00301 }, + { 0x000CA , 0x00045 , 0x00302 }, + { 0x000CB , 0x00045 , 0x00308 }, + { 0x000CC , 0x00049 , 0x00300 }, + { 0x000CD , 0x00049 , 0x00301 }, + { 0x000CE , 0x00049 , 0x00302 }, + { 0x000CF , 0x00049 , 0x00308 }, + { 0x000D1 , 0x0004E , 0x00303 }, + { 0x000D2 , 0x0004F , 0x00300 }, + { 0x000D3 , 0x0004F , 0x00301 }, + { 0x000D4 , 0x0004F , 0x00302 }, + { 0x000D5 , 0x0004F , 0x00303 }, + { 0x000D6 , 0x0004F , 0x00308 }, + { 0x000D9 , 0x00055 , 0x00300 }, + { 0x000DA , 0x00055 , 0x00301 }, + { 0x000DB , 0x00055 , 0x00302 }, + { 0x000DC , 0x00055 , 0x00308 }, + { 0x000DD , 0x00059 , 0x00301 }, + { 0x000E0 , 0x00061 , 0x00300 }, + { 0x000E1 , 0x00061 , 0x00301 }, + { 0x000E2 , 0x00061 , 0x00302 }, + { 0x000E3 , 0x00061 , 0x00303 }, + { 0x000E4 , 0x00061 , 0x00308 }, + { 0x000E5 , 0x00061 , 0x0030A }, + { 0x000E7 , 0x00063 , 0x00327 }, + { 0x000E8 , 0x00065 , 0x00300 }, + { 0x000E9 , 0x00065 , 0x00301 }, + { 0x000EA , 0x00065 , 0x00302 }, + { 0x000EB , 0x00065 , 0x00308 }, + { 0x000EC , 0x00069 , 0x00300 }, + { 0x000ED , 0x00069 , 0x00301 }, + { 0x000EE , 0x00069 , 0x00302 }, + { 0x000EF , 0x00069 , 0x00308 }, + { 0x000F1 , 0x0006E , 0x00303 }, + { 0x000F2 , 0x0006F , 0x00300 }, + { 0x000F3 , 0x0006F , 0x00301 }, + { 0x000F4 , 0x0006F , 0x00302 }, + { 0x000F5 , 0x0006F , 0x00303 }, + { 0x000F6 , 0x0006F , 0x00308 }, + { 0x000F9 , 0x00075 , 0x00300 }, + { 0x000FA , 0x00075 , 0x00301 }, + { 0x000FB , 0x00075 , 0x00302 }, + { 0x000FC , 0x00075 , 0x00308 }, + { 0x000FD , 0x00079 , 0x00301 }, + { 0x000FF , 0x00079 , 0x00308 }, + { 0x00100 , 0x00041 , 0x00304 }, + { 0x00101 , 0x00061 , 0x00304 }, + { 0x00102 , 0x00041 , 0x00306 }, + { 0x00103 , 0x00061 , 0x00306 }, + { 0x00104 , 0x00041 , 0x00328 }, + { 0x00105 , 0x00061 , 0x00328 }, + { 0x00106 , 0x00043 , 0x00301 }, + { 0x00107 , 0x00063 , 0x00301 }, + { 0x00108 , 0x00043 , 0x00302 }, + { 0x00109 , 0x00063 , 0x00302 }, + { 0x0010A , 0x00043 , 0x00307 }, + { 0x0010B , 0x00063 , 0x00307 }, + { 0x0010C , 0x00043 , 0x0030C }, + { 0x0010D , 0x00063 , 0x0030C }, + { 0x0010E , 0x00044 , 0x0030C }, + { 0x0010F , 0x00064 , 0x0030C }, + { 0x00112 , 0x00045 , 0x00304 }, + { 0x00113 , 0x00065 , 0x00304 }, + { 0x00114 , 0x00045 , 0x00306 }, + { 0x00115 , 0x00065 , 0x00306 }, + { 0x00116 , 0x00045 , 0x00307 }, + { 0x00117 , 0x00065 , 0x00307 }, + { 0x00118 , 0x00045 , 0x00328 }, + { 0x00119 , 0x00065 , 0x00328 }, + { 0x0011A , 0x00045 , 0x0030C }, + { 0x0011B , 0x00065 , 0x0030C }, + { 0x0011C , 0x00047 , 0x00302 }, + { 0x0011D , 0x00067 , 0x00302 }, + { 0x0011E , 0x00047 , 0x00306 }, + { 0x0011F , 0x00067 , 0x00306 }, + { 0x00120 , 0x00047 , 0x00307 }, + { 0x00121 , 0x00067 , 0x00307 }, + { 0x00122 , 0x00047 , 0x00327 }, + { 0x00123 , 0x00067 , 0x00327 }, + { 0x00124 , 0x00048 , 0x00302 }, + { 0x00125 , 0x00068 , 0x00302 }, + { 0x00128 , 0x00049 , 0x00303 }, + { 0x00129 , 0x00069 , 0x00303 }, + { 0x0012A , 0x00049 , 0x00304 }, + { 0x0012B , 0x00069 , 0x00304 }, + { 0x0012C , 0x00049 , 0x00306 }, + { 0x0012D , 0x00069 , 0x00306 }, + { 0x0012E , 0x00049 , 0x00328 }, + { 0x0012F , 0x00069 , 0x00328 }, + { 0x00130 , 0x00049 , 0x00307 }, + { 0x00134 , 0x0004A , 0x00302 }, + { 0x00135 , 0x0006A , 0x00302 }, + { 0x00136 , 0x0004B , 0x00327 }, + { 0x00137 , 0x0006B , 0x00327 }, + { 0x00139 , 0x0004C , 0x00301 }, + { 0x0013A , 0x0006C , 0x00301 }, + { 0x0013B , 0x0004C , 0x00327 }, + { 0x0013C , 0x0006C , 0x00327 }, + { 0x0013D , 0x0004C , 0x0030C }, + { 0x0013E , 0x0006C , 0x0030C }, + { 0x00143 , 0x0004E , 0x00301 }, + { 0x00144 , 0x0006E , 0x00301 }, + { 0x00145 , 0x0004E , 0x00327 }, + { 0x00146 , 0x0006E , 0x00327 }, + { 0x00147 , 0x0004E , 0x0030C }, + { 0x00148 , 0x0006E , 0x0030C }, + { 0x0014C , 0x0004F , 0x00304 }, + { 0x0014D , 0x0006F , 0x00304 }, + { 0x0014E , 0x0004F , 0x00306 }, + { 0x0014F , 0x0006F , 0x00306 }, + { 0x00150 , 0x0004F , 0x0030B }, + { 0x00151 , 0x0006F , 0x0030B }, + { 0x00154 , 0x00052 , 0x00301 }, + { 0x00155 , 0x00072 , 0x00301 }, + { 0x00156 , 0x00052 , 0x00327 }, + { 0x00157 , 0x00072 , 0x00327 }, + { 0x00158 , 0x00052 , 0x0030C }, + { 0x00159 , 0x00072 , 0x0030C }, + { 0x0015A , 0x00053 , 0x00301 }, + { 0x0015B , 0x00073 , 0x00301 }, + { 0x0015C , 0x00053 , 0x00302 }, + { 0x0015D , 0x00073 , 0x00302 }, + { 0x0015E , 0x00053 , 0x00327 }, + { 0x0015F , 0x00073 , 0x00327 }, + { 0x00160 , 0x00053 , 0x0030C }, + { 0x00161 , 0x00073 , 0x0030C }, + { 0x00162 , 0x00054 , 0x00327 }, + { 0x00163 , 0x00074 , 0x00327 }, + { 0x00164 , 0x00054 , 0x0030C }, + { 0x00165 , 0x00074 , 0x0030C }, + { 0x00168 , 0x00055 , 0x00303 }, + { 0x00169 , 0x00075 , 0x00303 }, + { 0x0016A , 0x00055 , 0x00304 }, + { 0x0016B , 0x00075 , 0x00304 }, + { 0x0016C , 0x00055 , 0x00306 }, + { 0x0016D , 0x00075 , 0x00306 }, + { 0x0016E , 0x00055 , 0x0030A }, + { 0x0016F , 0x00075 , 0x0030A }, + { 0x00170 , 0x00055 , 0x0030B }, + { 0x00171 , 0x00075 , 0x0030B }, + { 0x00172 , 0x00055 , 0x00328 }, + { 0x00173 , 0x00075 , 0x00328 }, + { 0x00174 , 0x00057 , 0x00302 }, + { 0x00175 , 0x00077 , 0x00302 }, + { 0x00176 , 0x00059 , 0x00302 }, + { 0x00177 , 0x00079 , 0x00302 }, + { 0x00178 , 0x00059 , 0x00308 }, + { 0x00179 , 0x0005A , 0x00301 }, + { 0x0017A , 0x0007A , 0x00301 }, + { 0x0017B , 0x0005A , 0x00307 }, + { 0x0017C , 0x0007A , 0x00307 }, + { 0x0017D , 0x0005A , 0x0030C }, + { 0x0017E , 0x0007A , 0x0030C }, + { 0x001A0 , 0x0004F , 0x0031B }, + { 0x001A1 , 0x0006F , 0x0031B }, + { 0x001AF , 0x00055 , 0x0031B }, + { 0x001B0 , 0x00075 , 0x0031B }, + { 0x001CD , 0x00041 , 0x0030C }, + { 0x001CE , 0x00061 , 0x0030C }, + { 0x001CF , 0x00049 , 0x0030C }, + { 0x001D0 , 0x00069 , 0x0030C }, + { 0x001D1 , 0x0004F , 0x0030C }, + { 0x001D2 , 0x0006F , 0x0030C }, + { 0x001D3 , 0x00055 , 0x0030C }, + { 0x001D4 , 0x00075 , 0x0030C }, + { 0x001D5 , 0x000DC , 0x00304 }, + { 0x001D6 , 0x000FC , 0x00304 }, + { 0x001D7 , 0x000DC , 0x00301 }, + { 0x001D8 , 0x000FC , 0x00301 }, + { 0x001D9 , 0x000DC , 0x0030C }, + { 0x001DA , 0x000FC , 0x0030C }, + { 0x001DB , 0x000DC , 0x00300 }, + { 0x001DC , 0x000FC , 0x00300 }, + { 0x001DE , 0x000C4 , 0x00304 }, + { 0x001DF , 0x000E4 , 0x00304 }, + { 0x001E0 , 0x00226 , 0x00304 }, + { 0x001E1 , 0x00227 , 0x00304 }, + { 0x001E2 , 0x000C6 , 0x00304 }, + { 0x001E3 , 0x000E6 , 0x00304 }, + { 0x001E6 , 0x00047 , 0x0030C }, + { 0x001E7 , 0x00067 , 0x0030C }, + { 0x001E8 , 0x0004B , 0x0030C }, + { 0x001E9 , 0x0006B , 0x0030C }, + { 0x001EA , 0x0004F , 0x00328 }, + { 0x001EB , 0x0006F , 0x00328 }, + { 0x001EC , 0x001EA , 0x00304 }, + { 0x001ED , 0x001EB , 0x00304 }, + { 0x001EE , 0x001B7 , 0x0030C }, + { 0x001EF , 0x00292 , 0x0030C }, + { 0x001F0 , 0x0006A , 0x0030C }, + { 0x001F4 , 0x00047 , 0x00301 }, + { 0x001F5 , 0x00067 , 0x00301 }, + { 0x001F8 , 0x0004E , 0x00300 }, + { 0x001F9 , 0x0006E , 0x00300 }, + { 0x001FA , 0x000C5 , 0x00301 }, + { 0x001FB , 0x000E5 , 0x00301 }, + { 0x001FC , 0x000C6 , 0x00301 }, + { 0x001FD , 0x000E6 , 0x00301 }, + { 0x001FE , 0x000D8 , 0x00301 }, + { 0x001FF , 0x000F8 , 0x00301 }, + { 0x00200 , 0x00041 , 0x0030F }, + { 0x00201 , 0x00061 , 0x0030F }, + { 0x00202 , 0x00041 , 0x00311 }, + { 0x00203 , 0x00061 , 0x00311 }, + { 0x00204 , 0x00045 , 0x0030F }, + { 0x00205 , 0x00065 , 0x0030F }, + { 0x00206 , 0x00045 , 0x00311 }, + { 0x00207 , 0x00065 , 0x00311 }, + { 0x00208 , 0x00049 , 0x0030F }, + { 0x00209 , 0x00069 , 0x0030F }, + { 0x0020A , 0x00049 , 0x00311 }, + { 0x0020B , 0x00069 , 0x00311 }, + { 0x0020C , 0x0004F , 0x0030F }, + { 0x0020D , 0x0006F , 0x0030F }, + { 0x0020E , 0x0004F , 0x00311 }, + { 0x0020F , 0x0006F , 0x00311 }, + { 0x00210 , 0x00052 , 0x0030F }, + { 0x00211 , 0x00072 , 0x0030F }, + { 0x00212 , 0x00052 , 0x00311 }, + { 0x00213 , 0x00072 , 0x00311 }, + { 0x00214 , 0x00055 , 0x0030F }, + { 0x00215 , 0x00075 , 0x0030F }, + { 0x00216 , 0x00055 , 0x00311 }, + { 0x00217 , 0x00075 , 0x00311 }, + { 0x00218 , 0x00053 , 0x00326 }, + { 0x00219 , 0x00073 , 0x00326 }, + { 0x0021A , 0x00054 , 0x00326 }, + { 0x0021B , 0x00074 , 0x00326 }, + { 0x0021E , 0x00048 , 0x0030C }, + { 0x0021F , 0x00068 , 0x0030C }, + { 0x00226 , 0x00041 , 0x00307 }, + { 0x00227 , 0x00061 , 0x00307 }, + { 0x00228 , 0x00045 , 0x00327 }, + { 0x00229 , 0x00065 , 0x00327 }, + { 0x0022A , 0x000D6 , 0x00304 }, + { 0x0022B , 0x000F6 , 0x00304 }, + { 0x0022C , 0x000D5 , 0x00304 }, + { 0x0022D , 0x000F5 , 0x00304 }, + { 0x0022E , 0x0004F , 0x00307 }, + { 0x0022F , 0x0006F , 0x00307 }, + { 0x00230 , 0x0022E , 0x00304 }, + { 0x00231 , 0x0022F , 0x00304 }, + { 0x00232 , 0x00059 , 0x00304 }, + { 0x00233 , 0x00079 , 0x00304 }, + { 0x00385 , 0x000A8 , 0x00301 }, + { 0x00386 , 0x00391 , 0x00301 }, + { 0x00388 , 0x00395 , 0x00301 }, + { 0x00389 , 0x00397 , 0x00301 }, + { 0x0038A , 0x00399 , 0x00301 }, + { 0x0038C , 0x0039F , 0x00301 }, + { 0x0038E , 0x003A5 , 0x00301 }, + { 0x0038F , 0x003A9 , 0x00301 }, + { 0x00390 , 0x003CA , 0x00301 }, + { 0x003AA , 0x00399 , 0x00308 }, + { 0x003AB , 0x003A5 , 0x00308 }, + { 0x003AC , 0x003B1 , 0x00301 }, + { 0x003AD , 0x003B5 , 0x00301 }, + { 0x003AE , 0x003B7 , 0x00301 }, + { 0x003AF , 0x003B9 , 0x00301 }, + { 0x003B0 , 0x003CB , 0x00301 }, + { 0x003CA , 0x003B9 , 0x00308 }, + { 0x003CB , 0x003C5 , 0x00308 }, + { 0x003CC , 0x003BF , 0x00301 }, + { 0x003CD , 0x003C5 , 0x00301 }, + { 0x003CE , 0x003C9 , 0x00301 }, + { 0x003D3 , 0x003D2 , 0x00301 }, + { 0x003D4 , 0x003D2 , 0x00308 }, + { 0x00400 , 0x00415 , 0x00300 }, + { 0x00401 , 0x00415 , 0x00308 }, + { 0x00403 , 0x00413 , 0x00301 }, + { 0x00407 , 0x00406 , 0x00308 }, + { 0x0040C , 0x0041A , 0x00301 }, + { 0x0040D , 0x00418 , 0x00300 }, + { 0x0040E , 0x00423 , 0x00306 }, + { 0x00419 , 0x00418 , 0x00306 }, + { 0x00439 , 0x00438 , 0x00306 }, + { 0x00450 , 0x00435 , 0x00300 }, + { 0x00451 , 0x00435 , 0x00308 }, + { 0x00453 , 0x00433 , 0x00301 }, + { 0x00457 , 0x00456 , 0x00308 }, + { 0x0045C , 0x0043A , 0x00301 }, + { 0x0045D , 0x00438 , 0x00300 }, + { 0x0045E , 0x00443 , 0x00306 }, + { 0x00476 , 0x00474 , 0x0030F }, + { 0x00477 , 0x00475 , 0x0030F }, + { 0x004C1 , 0x00416 , 0x00306 }, + { 0x004C2 , 0x00436 , 0x00306 }, + { 0x004D0 , 0x00410 , 0x00306 }, + { 0x004D1 , 0x00430 , 0x00306 }, + { 0x004D2 , 0x00410 , 0x00308 }, + { 0x004D3 , 0x00430 , 0x00308 }, + { 0x004D6 , 0x00415 , 0x00306 }, + { 0x004D7 , 0x00435 , 0x00306 }, + { 0x004DA , 0x004D8 , 0x00308 }, + { 0x004DB , 0x004D9 , 0x00308 }, + { 0x004DC , 0x00416 , 0x00308 }, + { 0x004DD , 0x00436 , 0x00308 }, + { 0x004DE , 0x00417 , 0x00308 }, + { 0x004DF , 0x00437 , 0x00308 }, + { 0x004E2 , 0x00418 , 0x00304 }, + { 0x004E3 , 0x00438 , 0x00304 }, + { 0x004E4 , 0x00418 , 0x00308 }, + { 0x004E5 , 0x00438 , 0x00308 }, + { 0x004E6 , 0x0041E , 0x00308 }, + { 0x004E7 , 0x0043E , 0x00308 }, + { 0x004EA , 0x004E8 , 0x00308 }, + { 0x004EB , 0x004E9 , 0x00308 }, + { 0x004EC , 0x0042D , 0x00308 }, + { 0x004ED , 0x0044D , 0x00308 }, + { 0x004EE , 0x00423 , 0x00304 }, + { 0x004EF , 0x00443 , 0x00304 }, + { 0x004F0 , 0x00423 , 0x00308 }, + { 0x004F1 , 0x00443 , 0x00308 }, + { 0x004F2 , 0x00423 , 0x0030B }, + { 0x004F3 , 0x00443 , 0x0030B }, + { 0x004F4 , 0x00427 , 0x00308 }, + { 0x004F5 , 0x00447 , 0x00308 }, + { 0x004F8 , 0x0042B , 0x00308 }, + { 0x004F9 , 0x0044B , 0x00308 }, + { 0x00622 , 0x00627 , 0x00653 }, + { 0x00623 , 0x00627 , 0x00654 }, + { 0x00624 , 0x00648 , 0x00654 }, + { 0x00625 , 0x00627 , 0x00655 }, + { 0x00626 , 0x0064A , 0x00654 }, + { 0x006C0 , 0x006D5 , 0x00654 }, + { 0x006C2 , 0x006C1 , 0x00654 }, + { 0x006D3 , 0x006D2 , 0x00654 }, + { 0x00929 , 0x00928 , 0x0093C }, + { 0x00931 , 0x00930 , 0x0093C }, + { 0x00934 , 0x00933 , 0x0093C }, + { 0x009CB , 0x009C7 , 0x009BE }, + { 0x009CC , 0x009C7 , 0x009D7 }, + { 0x00B48 , 0x00B47 , 0x00B56 }, + { 0x00B4B , 0x00B47 , 0x00B3E }, + { 0x00B4C , 0x00B47 , 0x00B57 }, + { 0x00B94 , 0x00B92 , 0x00BD7 }, + { 0x00BCA , 0x00BC6 , 0x00BBE }, + { 0x00BCB , 0x00BC7 , 0x00BBE }, + { 0x00BCC , 0x00BC6 , 0x00BD7 }, + { 0x00C48 , 0x00C46 , 0x00C56 }, + { 0x00CC0 , 0x00CBF , 0x00CD5 }, + { 0x00CC7 , 0x00CC6 , 0x00CD5 }, + { 0x00CC8 , 0x00CC6 , 0x00CD6 }, + { 0x00CCA , 0x00CC6 , 0x00CC2 }, + { 0x00CCB , 0x00CCA , 0x00CD5 }, + { 0x00D4A , 0x00D46 , 0x00D3E }, + { 0x00D4B , 0x00D47 , 0x00D3E }, + { 0x00D4C , 0x00D46 , 0x00D57 }, + { 0x00DDA , 0x00DD9 , 0x00DCA }, + { 0x00DDC , 0x00DD9 , 0x00DCF }, + { 0x00DDD , 0x00DDC , 0x00DCA }, + { 0x00DDE , 0x00DD9 , 0x00DDF }, + { 0x01026 , 0x01025 , 0x0102E }, + { 0x01B06 , 0x01B05 , 0x01B35 }, + { 0x01B08 , 0x01B07 , 0x01B35 }, + { 0x01B0A , 0x01B09 , 0x01B35 }, + { 0x01B0C , 0x01B0B , 0x01B35 }, + { 0x01B0E , 0x01B0D , 0x01B35 }, + { 0x01B12 , 0x01B11 , 0x01B35 }, + { 0x01B3B , 0x01B3A , 0x01B35 }, + { 0x01B3D , 0x01B3C , 0x01B35 }, + { 0x01B40 , 0x01B3E , 0x01B35 }, + { 0x01B41 , 0x01B3F , 0x01B35 }, + { 0x01B43 , 0x01B42 , 0x01B35 }, + { 0x01E00 , 0x00041 , 0x00325 }, + { 0x01E01 , 0x00061 , 0x00325 }, + { 0x01E02 , 0x00042 , 0x00307 }, + { 0x01E03 , 0x00062 , 0x00307 }, + { 0x01E04 , 0x00042 , 0x00323 }, + { 0x01E05 , 0x00062 , 0x00323 }, + { 0x01E06 , 0x00042 , 0x00331 }, + { 0x01E07 , 0x00062 , 0x00331 }, + { 0x01E08 , 0x000C7 , 0x00301 }, + { 0x01E09 , 0x000E7 , 0x00301 }, + { 0x01E0A , 0x00044 , 0x00307 }, + { 0x01E0B , 0x00064 , 0x00307 }, + { 0x01E0C , 0x00044 , 0x00323 }, + { 0x01E0D , 0x00064 , 0x00323 }, + { 0x01E0E , 0x00044 , 0x00331 }, + { 0x01E0F , 0x00064 , 0x00331 }, + { 0x01E10 , 0x00044 , 0x00327 }, + { 0x01E11 , 0x00064 , 0x00327 }, + { 0x01E12 , 0x00044 , 0x0032D }, + { 0x01E13 , 0x00064 , 0x0032D }, + { 0x01E14 , 0x00112 , 0x00300 }, + { 0x01E15 , 0x00113 , 0x00300 }, + { 0x01E16 , 0x00112 , 0x00301 }, + { 0x01E17 , 0x00113 , 0x00301 }, + { 0x01E18 , 0x00045 , 0x0032D }, + { 0x01E19 , 0x00065 , 0x0032D }, + { 0x01E1A , 0x00045 , 0x00330 }, + { 0x01E1B , 0x00065 , 0x00330 }, + { 0x01E1C , 0x00228 , 0x00306 }, + { 0x01E1D , 0x00229 , 0x00306 }, + { 0x01E1E , 0x00046 , 0x00307 }, + { 0x01E1F , 0x00066 , 0x00307 }, + { 0x01E20 , 0x00047 , 0x00304 }, + { 0x01E21 , 0x00067 , 0x00304 }, + { 0x01E22 , 0x00048 , 0x00307 }, + { 0x01E23 , 0x00068 , 0x00307 }, + { 0x01E24 , 0x00048 , 0x00323 }, + { 0x01E25 , 0x00068 , 0x00323 }, + { 0x01E26 , 0x00048 , 0x00308 }, + { 0x01E27 , 0x00068 , 0x00308 }, + { 0x01E28 , 0x00048 , 0x00327 }, + { 0x01E29 , 0x00068 , 0x00327 }, + { 0x01E2A , 0x00048 , 0x0032E }, + { 0x01E2B , 0x00068 , 0x0032E }, + { 0x01E2C , 0x00049 , 0x00330 }, + { 0x01E2D , 0x00069 , 0x00330 }, + { 0x01E2E , 0x000CF , 0x00301 }, + { 0x01E2F , 0x000EF , 0x00301 }, + { 0x01E30 , 0x0004B , 0x00301 }, + { 0x01E31 , 0x0006B , 0x00301 }, + { 0x01E32 , 0x0004B , 0x00323 }, + { 0x01E33 , 0x0006B , 0x00323 }, + { 0x01E34 , 0x0004B , 0x00331 }, + { 0x01E35 , 0x0006B , 0x00331 }, + { 0x01E36 , 0x0004C , 0x00323 }, + { 0x01E37 , 0x0006C , 0x00323 }, + { 0x01E38 , 0x01E36 , 0x00304 }, + { 0x01E39 , 0x01E37 , 0x00304 }, + { 0x01E3A , 0x0004C , 0x00331 }, + { 0x01E3B , 0x0006C , 0x00331 }, + { 0x01E3C , 0x0004C , 0x0032D }, + { 0x01E3D , 0x0006C , 0x0032D }, + { 0x01E3E , 0x0004D , 0x00301 }, + { 0x01E3F , 0x0006D , 0x00301 }, + { 0x01E40 , 0x0004D , 0x00307 }, + { 0x01E41 , 0x0006D , 0x00307 }, + { 0x01E42 , 0x0004D , 0x00323 }, + { 0x01E43 , 0x0006D , 0x00323 }, + { 0x01E44 , 0x0004E , 0x00307 }, + { 0x01E45 , 0x0006E , 0x00307 }, + { 0x01E46 , 0x0004E , 0x00323 }, + { 0x01E47 , 0x0006E , 0x00323 }, + { 0x01E48 , 0x0004E , 0x00331 }, + { 0x01E49 , 0x0006E , 0x00331 }, + { 0x01E4A , 0x0004E , 0x0032D }, + { 0x01E4B , 0x0006E , 0x0032D }, + { 0x01E4C , 0x000D5 , 0x00301 }, + { 0x01E4D , 0x000F5 , 0x00301 }, + { 0x01E4E , 0x000D5 , 0x00308 }, + { 0x01E4F , 0x000F5 , 0x00308 }, + { 0x01E50 , 0x0014C , 0x00300 }, + { 0x01E51 , 0x0014D , 0x00300 }, + { 0x01E52 , 0x0014C , 0x00301 }, + { 0x01E53 , 0x0014D , 0x00301 }, + { 0x01E54 , 0x00050 , 0x00301 }, + { 0x01E55 , 0x00070 , 0x00301 }, + { 0x01E56 , 0x00050 , 0x00307 }, + { 0x01E57 , 0x00070 , 0x00307 }, + { 0x01E58 , 0x00052 , 0x00307 }, + { 0x01E59 , 0x00072 , 0x00307 }, + { 0x01E5A , 0x00052 , 0x00323 }, + { 0x01E5B , 0x00072 , 0x00323 }, + { 0x01E5C , 0x01E5A , 0x00304 }, + { 0x01E5D , 0x01E5B , 0x00304 }, + { 0x01E5E , 0x00052 , 0x00331 }, + { 0x01E5F , 0x00072 , 0x00331 }, + { 0x01E60 , 0x00053 , 0x00307 }, + { 0x01E61 , 0x00073 , 0x00307 }, + { 0x01E62 , 0x00053 , 0x00323 }, + { 0x01E63 , 0x00073 , 0x00323 }, + { 0x01E64 , 0x0015A , 0x00307 }, + { 0x01E65 , 0x0015B , 0x00307 }, + { 0x01E66 , 0x00160 , 0x00307 }, + { 0x01E67 , 0x00161 , 0x00307 }, + { 0x01E68 , 0x01E62 , 0x00307 }, + { 0x01E69 , 0x01E63 , 0x00307 }, + { 0x01E6A , 0x00054 , 0x00307 }, + { 0x01E6B , 0x00074 , 0x00307 }, + { 0x01E6C , 0x00054 , 0x00323 }, + { 0x01E6D , 0x00074 , 0x00323 }, + { 0x01E6E , 0x00054 , 0x00331 }, + { 0x01E6F , 0x00074 , 0x00331 }, + { 0x01E70 , 0x00054 , 0x0032D }, + { 0x01E71 , 0x00074 , 0x0032D }, + { 0x01E72 , 0x00055 , 0x00324 }, + { 0x01E73 , 0x00075 , 0x00324 }, + { 0x01E74 , 0x00055 , 0x00330 }, + { 0x01E75 , 0x00075 , 0x00330 }, + { 0x01E76 , 0x00055 , 0x0032D }, + { 0x01E77 , 0x00075 , 0x0032D }, + { 0x01E78 , 0x00168 , 0x00301 }, + { 0x01E79 , 0x00169 , 0x00301 }, + { 0x01E7A , 0x0016A , 0x00308 }, + { 0x01E7B , 0x0016B , 0x00308 }, + { 0x01E7C , 0x00056 , 0x00303 }, + { 0x01E7D , 0x00076 , 0x00303 }, + { 0x01E7E , 0x00056 , 0x00323 }, + { 0x01E7F , 0x00076 , 0x00323 }, + { 0x01E80 , 0x00057 , 0x00300 }, + { 0x01E81 , 0x00077 , 0x00300 }, + { 0x01E82 , 0x00057 , 0x00301 }, + { 0x01E83 , 0x00077 , 0x00301 }, + { 0x01E84 , 0x00057 , 0x00308 }, + { 0x01E85 , 0x00077 , 0x00308 }, + { 0x01E86 , 0x00057 , 0x00307 }, + { 0x01E87 , 0x00077 , 0x00307 }, + { 0x01E88 , 0x00057 , 0x00323 }, + { 0x01E89 , 0x00077 , 0x00323 }, + { 0x01E8A , 0x00058 , 0x00307 }, + { 0x01E8B , 0x00078 , 0x00307 }, + { 0x01E8C , 0x00058 , 0x00308 }, + { 0x01E8D , 0x00078 , 0x00308 }, + { 0x01E8E , 0x00059 , 0x00307 }, + { 0x01E8F , 0x00079 , 0x00307 }, + { 0x01E90 , 0x0005A , 0x00302 }, + { 0x01E91 , 0x0007A , 0x00302 }, + { 0x01E92 , 0x0005A , 0x00323 }, + { 0x01E93 , 0x0007A , 0x00323 }, + { 0x01E94 , 0x0005A , 0x00331 }, + { 0x01E95 , 0x0007A , 0x00331 }, + { 0x01E96 , 0x00068 , 0x00331 }, + { 0x01E97 , 0x00074 , 0x00308 }, + { 0x01E98 , 0x00077 , 0x0030A }, + { 0x01E99 , 0x00079 , 0x0030A }, + { 0x01E9B , 0x0017F , 0x00307 }, + { 0x01EA0 , 0x00041 , 0x00323 }, + { 0x01EA1 , 0x00061 , 0x00323 }, + { 0x01EA2 , 0x00041 , 0x00309 }, + { 0x01EA3 , 0x00061 , 0x00309 }, + { 0x01EA4 , 0x000C2 , 0x00301 }, + { 0x01EA5 , 0x000E2 , 0x00301 }, + { 0x01EA6 , 0x000C2 , 0x00300 }, + { 0x01EA7 , 0x000E2 , 0x00300 }, + { 0x01EA8 , 0x000C2 , 0x00309 }, + { 0x01EA9 , 0x000E2 , 0x00309 }, + { 0x01EAA , 0x000C2 , 0x00303 }, + { 0x01EAB , 0x000E2 , 0x00303 }, + { 0x01EAC , 0x01EA0 , 0x00302 }, + { 0x01EAD , 0x01EA1 , 0x00302 }, + { 0x01EAE , 0x00102 , 0x00301 }, + { 0x01EAF , 0x00103 , 0x00301 }, + { 0x01EB0 , 0x00102 , 0x00300 }, + { 0x01EB1 , 0x00103 , 0x00300 }, + { 0x01EB2 , 0x00102 , 0x00309 }, + { 0x01EB3 , 0x00103 , 0x00309 }, + { 0x01EB4 , 0x00102 , 0x00303 }, + { 0x01EB5 , 0x00103 , 0x00303 }, + { 0x01EB6 , 0x01EA0 , 0x00306 }, + { 0x01EB7 , 0x01EA1 , 0x00306 }, + { 0x01EB8 , 0x00045 , 0x00323 }, + { 0x01EB9 , 0x00065 , 0x00323 }, + { 0x01EBA , 0x00045 , 0x00309 }, + { 0x01EBB , 0x00065 , 0x00309 }, + { 0x01EBC , 0x00045 , 0x00303 }, + { 0x01EBD , 0x00065 , 0x00303 }, + { 0x01EBE , 0x000CA , 0x00301 }, + { 0x01EBF , 0x000EA , 0x00301 }, + { 0x01EC0 , 0x000CA , 0x00300 }, + { 0x01EC1 , 0x000EA , 0x00300 }, + { 0x01EC2 , 0x000CA , 0x00309 }, + { 0x01EC3 , 0x000EA , 0x00309 }, + { 0x01EC4 , 0x000CA , 0x00303 }, + { 0x01EC5 , 0x000EA , 0x00303 }, + { 0x01EC6 , 0x01EB8 , 0x00302 }, + { 0x01EC7 , 0x01EB9 , 0x00302 }, + { 0x01EC8 , 0x00049 , 0x00309 }, + { 0x01EC9 , 0x00069 , 0x00309 }, + { 0x01ECA , 0x00049 , 0x00323 }, + { 0x01ECB , 0x00069 , 0x00323 }, + { 0x01ECC , 0x0004F , 0x00323 }, + { 0x01ECD , 0x0006F , 0x00323 }, + { 0x01ECE , 0x0004F , 0x00309 }, + { 0x01ECF , 0x0006F , 0x00309 }, + { 0x01ED0 , 0x000D4 , 0x00301 }, + { 0x01ED1 , 0x000F4 , 0x00301 }, + { 0x01ED2 , 0x000D4 , 0x00300 }, + { 0x01ED3 , 0x000F4 , 0x00300 }, + { 0x01ED4 , 0x000D4 , 0x00309 }, + { 0x01ED5 , 0x000F4 , 0x00309 }, + { 0x01ED6 , 0x000D4 , 0x00303 }, + { 0x01ED7 , 0x000F4 , 0x00303 }, + { 0x01ED8 , 0x01ECC , 0x00302 }, + { 0x01ED9 , 0x01ECD , 0x00302 }, + { 0x01EDA , 0x001A0 , 0x00301 }, + { 0x01EDB , 0x001A1 , 0x00301 }, + { 0x01EDC , 0x001A0 , 0x00300 }, + { 0x01EDD , 0x001A1 , 0x00300 }, + { 0x01EDE , 0x001A0 , 0x00309 }, + { 0x01EDF , 0x001A1 , 0x00309 }, + { 0x01EE0 , 0x001A0 , 0x00303 }, + { 0x01EE1 , 0x001A1 , 0x00303 }, + { 0x01EE2 , 0x001A0 , 0x00323 }, + { 0x01EE3 , 0x001A1 , 0x00323 }, + { 0x01EE4 , 0x00055 , 0x00323 }, + { 0x01EE5 , 0x00075 , 0x00323 }, + { 0x01EE6 , 0x00055 , 0x00309 }, + { 0x01EE7 , 0x00075 , 0x00309 }, + { 0x01EE8 , 0x001AF , 0x00301 }, + { 0x01EE9 , 0x001B0 , 0x00301 }, + { 0x01EEA , 0x001AF , 0x00300 }, + { 0x01EEB , 0x001B0 , 0x00300 }, + { 0x01EEC , 0x001AF , 0x00309 }, + { 0x01EED , 0x001B0 , 0x00309 }, + { 0x01EEE , 0x001AF , 0x00303 }, + { 0x01EEF , 0x001B0 , 0x00303 }, + { 0x01EF0 , 0x001AF , 0x00323 }, + { 0x01EF1 , 0x001B0 , 0x00323 }, + { 0x01EF2 , 0x00059 , 0x00300 }, + { 0x01EF3 , 0x00079 , 0x00300 }, + { 0x01EF4 , 0x00059 , 0x00323 }, + { 0x01EF5 , 0x00079 , 0x00323 }, + { 0x01EF6 , 0x00059 , 0x00309 }, + { 0x01EF7 , 0x00079 , 0x00309 }, + { 0x01EF8 , 0x00059 , 0x00303 }, + { 0x01EF9 , 0x00079 , 0x00303 }, + { 0x01F00 , 0x003B1 , 0x00313 }, + { 0x01F01 , 0x003B1 , 0x00314 }, + { 0x01F02 , 0x01F00 , 0x00300 }, + { 0x01F03 , 0x01F01 , 0x00300 }, + { 0x01F04 , 0x01F00 , 0x00301 }, + { 0x01F05 , 0x01F01 , 0x00301 }, + { 0x01F06 , 0x01F00 , 0x00342 }, + { 0x01F07 , 0x01F01 , 0x00342 }, + { 0x01F08 , 0x00391 , 0x00313 }, + { 0x01F09 , 0x00391 , 0x00314 }, + { 0x01F0A , 0x01F08 , 0x00300 }, + { 0x01F0B , 0x01F09 , 0x00300 }, + { 0x01F0C , 0x01F08 , 0x00301 }, + { 0x01F0D , 0x01F09 , 0x00301 }, + { 0x01F0E , 0x01F08 , 0x00342 }, + { 0x01F0F , 0x01F09 , 0x00342 }, + { 0x01F10 , 0x003B5 , 0x00313 }, + { 0x01F11 , 0x003B5 , 0x00314 }, + { 0x01F12 , 0x01F10 , 0x00300 }, + { 0x01F13 , 0x01F11 , 0x00300 }, + { 0x01F14 , 0x01F10 , 0x00301 }, + { 0x01F15 , 0x01F11 , 0x00301 }, + { 0x01F18 , 0x00395 , 0x00313 }, + { 0x01F19 , 0x00395 , 0x00314 }, + { 0x01F1A , 0x01F18 , 0x00300 }, + { 0x01F1B , 0x01F19 , 0x00300 }, + { 0x01F1C , 0x01F18 , 0x00301 }, + { 0x01F1D , 0x01F19 , 0x00301 }, + { 0x01F20 , 0x003B7 , 0x00313 }, + { 0x01F21 , 0x003B7 , 0x00314 }, + { 0x01F22 , 0x01F20 , 0x00300 }, + { 0x01F23 , 0x01F21 , 0x00300 }, + { 0x01F24 , 0x01F20 , 0x00301 }, + { 0x01F25 , 0x01F21 , 0x00301 }, + { 0x01F26 , 0x01F20 , 0x00342 }, + { 0x01F27 , 0x01F21 , 0x00342 }, + { 0x01F28 , 0x00397 , 0x00313 }, + { 0x01F29 , 0x00397 , 0x00314 }, + { 0x01F2A , 0x01F28 , 0x00300 }, + { 0x01F2B , 0x01F29 , 0x00300 }, + { 0x01F2C , 0x01F28 , 0x00301 }, + { 0x01F2D , 0x01F29 , 0x00301 }, + { 0x01F2E , 0x01F28 , 0x00342 }, + { 0x01F2F , 0x01F29 , 0x00342 }, + { 0x01F30 , 0x003B9 , 0x00313 }, + { 0x01F31 , 0x003B9 , 0x00314 }, + { 0x01F32 , 0x01F30 , 0x00300 }, + { 0x01F33 , 0x01F31 , 0x00300 }, + { 0x01F34 , 0x01F30 , 0x00301 }, + { 0x01F35 , 0x01F31 , 0x00301 }, + { 0x01F36 , 0x01F30 , 0x00342 }, + { 0x01F37 , 0x01F31 , 0x00342 }, + { 0x01F38 , 0x00399 , 0x00313 }, + { 0x01F39 , 0x00399 , 0x00314 }, + { 0x01F3A , 0x01F38 , 0x00300 }, + { 0x01F3B , 0x01F39 , 0x00300 }, + { 0x01F3C , 0x01F38 , 0x00301 }, + { 0x01F3D , 0x01F39 , 0x00301 }, + { 0x01F3E , 0x01F38 , 0x00342 }, + { 0x01F3F , 0x01F39 , 0x00342 }, + { 0x01F40 , 0x003BF , 0x00313 }, + { 0x01F41 , 0x003BF , 0x00314 }, + { 0x01F42 , 0x01F40 , 0x00300 }, + { 0x01F43 , 0x01F41 , 0x00300 }, + { 0x01F44 , 0x01F40 , 0x00301 }, + { 0x01F45 , 0x01F41 , 0x00301 }, + { 0x01F48 , 0x0039F , 0x00313 }, + { 0x01F49 , 0x0039F , 0x00314 }, + { 0x01F4A , 0x01F48 , 0x00300 }, + { 0x01F4B , 0x01F49 , 0x00300 }, + { 0x01F4C , 0x01F48 , 0x00301 }, + { 0x01F4D , 0x01F49 , 0x00301 }, + { 0x01F50 , 0x003C5 , 0x00313 }, + { 0x01F51 , 0x003C5 , 0x00314 }, + { 0x01F52 , 0x01F50 , 0x00300 }, + { 0x01F53 , 0x01F51 , 0x00300 }, + { 0x01F54 , 0x01F50 , 0x00301 }, + { 0x01F55 , 0x01F51 , 0x00301 }, + { 0x01F56 , 0x01F50 , 0x00342 }, + { 0x01F57 , 0x01F51 , 0x00342 }, + { 0x01F59 , 0x003A5 , 0x00314 }, + { 0x01F5B , 0x01F59 , 0x00300 }, + { 0x01F5D , 0x01F59 , 0x00301 }, + { 0x01F5F , 0x01F59 , 0x00342 }, + { 0x01F60 , 0x003C9 , 0x00313 }, + { 0x01F61 , 0x003C9 , 0x00314 }, + { 0x01F62 , 0x01F60 , 0x00300 }, + { 0x01F63 , 0x01F61 , 0x00300 }, + { 0x01F64 , 0x01F60 , 0x00301 }, + { 0x01F65 , 0x01F61 , 0x00301 }, + { 0x01F66 , 0x01F60 , 0x00342 }, + { 0x01F67 , 0x01F61 , 0x00342 }, + { 0x01F68 , 0x003A9 , 0x00313 }, + { 0x01F69 , 0x003A9 , 0x00314 }, + { 0x01F6A , 0x01F68 , 0x00300 }, + { 0x01F6B , 0x01F69 , 0x00300 }, + { 0x01F6C , 0x01F68 , 0x00301 }, + { 0x01F6D , 0x01F69 , 0x00301 }, + { 0x01F6E , 0x01F68 , 0x00342 }, + { 0x01F6F , 0x01F69 , 0x00342 }, + { 0x01F70 , 0x003B1 , 0x00300 }, + { 0x01F72 , 0x003B5 , 0x00300 }, + { 0x01F74 , 0x003B7 , 0x00300 }, + { 0x01F76 , 0x003B9 , 0x00300 }, + { 0x01F78 , 0x003BF , 0x00300 }, + { 0x01F7A , 0x003C5 , 0x00300 }, + { 0x01F7C , 0x003C9 , 0x00300 }, + { 0x01F80 , 0x01F00 , 0x00345 }, + { 0x01F81 , 0x01F01 , 0x00345 }, + { 0x01F82 , 0x01F02 , 0x00345 }, + { 0x01F83 , 0x01F03 , 0x00345 }, + { 0x01F84 , 0x01F04 , 0x00345 }, + { 0x01F85 , 0x01F05 , 0x00345 }, + { 0x01F86 , 0x01F06 , 0x00345 }, + { 0x01F87 , 0x01F07 , 0x00345 }, + { 0x01F88 , 0x01F08 , 0x00345 }, + { 0x01F89 , 0x01F09 , 0x00345 }, + { 0x01F8A , 0x01F0A , 0x00345 }, + { 0x01F8B , 0x01F0B , 0x00345 }, + { 0x01F8C , 0x01F0C , 0x00345 }, + { 0x01F8D , 0x01F0D , 0x00345 }, + { 0x01F8E , 0x01F0E , 0x00345 }, + { 0x01F8F , 0x01F0F , 0x00345 }, + { 0x01F90 , 0x01F20 , 0x00345 }, + { 0x01F91 , 0x01F21 , 0x00345 }, + { 0x01F92 , 0x01F22 , 0x00345 }, + { 0x01F93 , 0x01F23 , 0x00345 }, + { 0x01F94 , 0x01F24 , 0x00345 }, + { 0x01F95 , 0x01F25 , 0x00345 }, + { 0x01F96 , 0x01F26 , 0x00345 }, + { 0x01F97 , 0x01F27 , 0x00345 }, + { 0x01F98 , 0x01F28 , 0x00345 }, + { 0x01F99 , 0x01F29 , 0x00345 }, + { 0x01F9A , 0x01F2A , 0x00345 }, + { 0x01F9B , 0x01F2B , 0x00345 }, + { 0x01F9C , 0x01F2C , 0x00345 }, + { 0x01F9D , 0x01F2D , 0x00345 }, + { 0x01F9E , 0x01F2E , 0x00345 }, + { 0x01F9F , 0x01F2F , 0x00345 }, + { 0x01FA0 , 0x01F60 , 0x00345 }, + { 0x01FA1 , 0x01F61 , 0x00345 }, + { 0x01FA2 , 0x01F62 , 0x00345 }, + { 0x01FA3 , 0x01F63 , 0x00345 }, + { 0x01FA4 , 0x01F64 , 0x00345 }, + { 0x01FA5 , 0x01F65 , 0x00345 }, + { 0x01FA6 , 0x01F66 , 0x00345 }, + { 0x01FA7 , 0x01F67 , 0x00345 }, + { 0x01FA8 , 0x01F68 , 0x00345 }, + { 0x01FA9 , 0x01F69 , 0x00345 }, + { 0x01FAA , 0x01F6A , 0x00345 }, + { 0x01FAB , 0x01F6B , 0x00345 }, + { 0x01FAC , 0x01F6C , 0x00345 }, + { 0x01FAD , 0x01F6D , 0x00345 }, + { 0x01FAE , 0x01F6E , 0x00345 }, + { 0x01FAF , 0x01F6F , 0x00345 }, + { 0x01FB0 , 0x003B1 , 0x00306 }, + { 0x01FB1 , 0x003B1 , 0x00304 }, + { 0x01FB2 , 0x01F70 , 0x00345 }, + { 0x01FB3 , 0x003B1 , 0x00345 }, + { 0x01FB4 , 0x003AC , 0x00345 }, + { 0x01FB6 , 0x003B1 , 0x00342 }, + { 0x01FB7 , 0x01FB6 , 0x00345 }, + { 0x01FB8 , 0x00391 , 0x00306 }, + { 0x01FB9 , 0x00391 , 0x00304 }, + { 0x01FBA , 0x00391 , 0x00300 }, + { 0x01FBC , 0x00391 , 0x00345 }, + { 0x01FC1 , 0x000A8 , 0x00342 }, + { 0x01FC2 , 0x01F74 , 0x00345 }, + { 0x01FC3 , 0x003B7 , 0x00345 }, + { 0x01FC4 , 0x003AE , 0x00345 }, + { 0x01FC6 , 0x003B7 , 0x00342 }, + { 0x01FC7 , 0x01FC6 , 0x00345 }, + { 0x01FC8 , 0x00395 , 0x00300 }, + { 0x01FCA , 0x00397 , 0x00300 }, + { 0x01FCC , 0x00397 , 0x00345 }, + { 0x01FCD , 0x01FBF , 0x00300 }, + { 0x01FCE , 0x01FBF , 0x00301 }, + { 0x01FCF , 0x01FBF , 0x00342 }, + { 0x01FD0 , 0x003B9 , 0x00306 }, + { 0x01FD1 , 0x003B9 , 0x00304 }, + { 0x01FD2 , 0x003CA , 0x00300 }, + { 0x01FD6 , 0x003B9 , 0x00342 }, + { 0x01FD7 , 0x003CA , 0x00342 }, + { 0x01FD8 , 0x00399 , 0x00306 }, + { 0x01FD9 , 0x00399 , 0x00304 }, + { 0x01FDA , 0x00399 , 0x00300 }, + { 0x01FDD , 0x01FFE , 0x00300 }, + { 0x01FDE , 0x01FFE , 0x00301 }, + { 0x01FDF , 0x01FFE , 0x00342 }, + { 0x01FE0 , 0x003C5 , 0x00306 }, + { 0x01FE1 , 0x003C5 , 0x00304 }, + { 0x01FE2 , 0x003CB , 0x00300 }, + { 0x01FE4 , 0x003C1 , 0x00313 }, + { 0x01FE5 , 0x003C1 , 0x00314 }, + { 0x01FE6 , 0x003C5 , 0x00342 }, + { 0x01FE7 , 0x003CB , 0x00342 }, + { 0x01FE8 , 0x003A5 , 0x00306 }, + { 0x01FE9 , 0x003A5 , 0x00304 }, + { 0x01FEA , 0x003A5 , 0x00300 }, + { 0x01FEC , 0x003A1 , 0x00314 }, + { 0x01FED , 0x000A8 , 0x00300 }, + { 0x01FF2 , 0x01F7C , 0x00345 }, + { 0x01FF3 , 0x003C9 , 0x00345 }, + { 0x01FF4 , 0x003CE , 0x00345 }, + { 0x01FF6 , 0x003C9 , 0x00342 }, + { 0x01FF7 , 0x01FF6 , 0x00345 }, + { 0x01FF8 , 0x0039F , 0x00300 }, + { 0x01FFA , 0x003A9 , 0x00300 }, + { 0x01FFC , 0x003A9 , 0x00345 }, + { 0x0219A , 0x02190 , 0x00338 }, + { 0x0219B , 0x02192 , 0x00338 }, + { 0x021AE , 0x02194 , 0x00338 }, + { 0x021CD , 0x021D0 , 0x00338 }, + { 0x021CE , 0x021D4 , 0x00338 }, + { 0x021CF , 0x021D2 , 0x00338 }, + { 0x02204 , 0x02203 , 0x00338 }, + { 0x02209 , 0x02208 , 0x00338 }, + { 0x0220C , 0x0220B , 0x00338 }, + { 0x02224 , 0x02223 , 0x00338 }, + { 0x02226 , 0x02225 , 0x00338 }, + { 0x02241 , 0x0223C , 0x00338 }, + { 0x02244 , 0x02243 , 0x00338 }, + { 0x02247 , 0x02245 , 0x00338 }, + { 0x02249 , 0x02248 , 0x00338 }, + { 0x02260 , 0x0003D , 0x00338 }, + { 0x02262 , 0x02261 , 0x00338 }, + { 0x0226D , 0x0224D , 0x00338 }, + { 0x0226E , 0x0003C , 0x00338 }, + { 0x0226F , 0x0003E , 0x00338 }, + { 0x02270 , 0x02264 , 0x00338 }, + { 0x02271 , 0x02265 , 0x00338 }, + { 0x02274 , 0x02272 , 0x00338 }, + { 0x02275 , 0x02273 , 0x00338 }, + { 0x02278 , 0x02276 , 0x00338 }, + { 0x02279 , 0x02277 , 0x00338 }, + { 0x02280 , 0x0227A , 0x00338 }, + { 0x02281 , 0x0227B , 0x00338 }, + { 0x02284 , 0x02282 , 0x00338 }, + { 0x02285 , 0x02283 , 0x00338 }, + { 0x02288 , 0x02286 , 0x00338 }, + { 0x02289 , 0x02287 , 0x00338 }, + { 0x022AC , 0x022A2 , 0x00338 }, + { 0x022AD , 0x022A8 , 0x00338 }, + { 0x022AE , 0x022A9 , 0x00338 }, + { 0x022AF , 0x022AB , 0x00338 }, + { 0x022E0 , 0x0227C , 0x00338 }, + { 0x022E1 , 0x0227D , 0x00338 }, + { 0x022E2 , 0x02291 , 0x00338 }, + { 0x022E3 , 0x02292 , 0x00338 }, + { 0x022EA , 0x022B2 , 0x00338 }, + { 0x022EB , 0x022B3 , 0x00338 }, + { 0x022EC , 0x022B4 , 0x00338 }, + { 0x022ED , 0x022B5 , 0x00338 }, + { 0x0304C , 0x0304B , 0x03099 }, + { 0x0304E , 0x0304D , 0x03099 }, + { 0x03050 , 0x0304F , 0x03099 }, + { 0x03052 , 0x03051 , 0x03099 }, + { 0x03054 , 0x03053 , 0x03099 }, + { 0x03056 , 0x03055 , 0x03099 }, + { 0x03058 , 0x03057 , 0x03099 }, + { 0x0305A , 0x03059 , 0x03099 }, + { 0x0305C , 0x0305B , 0x03099 }, + { 0x0305E , 0x0305D , 0x03099 }, + { 0x03060 , 0x0305F , 0x03099 }, + { 0x03062 , 0x03061 , 0x03099 }, + { 0x03065 , 0x03064 , 0x03099 }, + { 0x03067 , 0x03066 , 0x03099 }, + { 0x03069 , 0x03068 , 0x03099 }, + { 0x03070 , 0x0306F , 0x03099 }, + { 0x03071 , 0x0306F , 0x0309A }, + { 0x03073 , 0x03072 , 0x03099 }, + { 0x03074 , 0x03072 , 0x0309A }, + { 0x03076 , 0x03075 , 0x03099 }, + { 0x03077 , 0x03075 , 0x0309A }, + { 0x03079 , 0x03078 , 0x03099 }, + { 0x0307A , 0x03078 , 0x0309A }, + { 0x0307C , 0x0307B , 0x03099 }, + { 0x0307D , 0x0307B , 0x0309A }, + { 0x03094 , 0x03046 , 0x03099 }, + { 0x0309E , 0x0309D , 0x03099 }, + { 0x030AC , 0x030AB , 0x03099 }, + { 0x030AE , 0x030AD , 0x03099 }, + { 0x030B0 , 0x030AF , 0x03099 }, + { 0x030B2 , 0x030B1 , 0x03099 }, + { 0x030B4 , 0x030B3 , 0x03099 }, + { 0x030B6 , 0x030B5 , 0x03099 }, + { 0x030B8 , 0x030B7 , 0x03099 }, + { 0x030BA , 0x030B9 , 0x03099 }, + { 0x030BC , 0x030BB , 0x03099 }, + { 0x030BE , 0x030BD , 0x03099 }, + { 0x030C0 , 0x030BF , 0x03099 }, + { 0x030C2 , 0x030C1 , 0x03099 }, + { 0x030C5 , 0x030C4 , 0x03099 }, + { 0x030C7 , 0x030C6 , 0x03099 }, + { 0x030C9 , 0x030C8 , 0x03099 }, + { 0x030D0 , 0x030CF , 0x03099 }, + { 0x030D1 , 0x030CF , 0x0309A }, + { 0x030D3 , 0x030D2 , 0x03099 }, + { 0x030D4 , 0x030D2 , 0x0309A }, + { 0x030D6 , 0x030D5 , 0x03099 }, + { 0x030D7 , 0x030D5 , 0x0309A }, + { 0x030D9 , 0x030D8 , 0x03099 }, + { 0x030DA , 0x030D8 , 0x0309A }, + { 0x030DC , 0x030DB , 0x03099 }, + { 0x030DD , 0x030DB , 0x0309A }, + { 0x030F4 , 0x030A6 , 0x03099 }, + { 0x030F7 , 0x030EF , 0x03099 }, + { 0x030F8 , 0x030F0 , 0x03099 }, + { 0x030F9 , 0x030F1 , 0x03099 }, + { 0x030FA , 0x030F2 , 0x03099 }, + { 0x030FE , 0x030FD , 0x03099 }, + { 0x1109A , 0x11099 , 0x110BA }, + { 0x1109C , 0x1109B , 0x110BA }, + { 0x110AB , 0x110A5 , 0x110BA }, +}; + +#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */ + diff --git a/src/3rdparty/libarchive/libarchive/archive_string_sprintf.c b/src/3rdparty/libarchive/libarchive/archive_string_sprintf.c new file mode 100644 index 00000000..969a5603 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_string_sprintf.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03-06 05:14:55Z kientzle $"); + +/* + * The use of printf()-family functions can be troublesome + * for space-constrained applications. In addition, correctly + * implementing this function in terms of vsnprintf() requires + * two calls (one to determine the size, another to format the + * result), which in turn requires duplicating the argument list + * using va_copy, which isn't yet universally available. + * + * So, I've implemented a bare minimum of printf()-like capability + * here. This is only used to format error messages, so doesn't + * require any floating-point support or field-width handling. + */ +#ifdef HAVE_ERRNO_H +#include +#endif +#include + +#include "archive_string.h" +#include "archive_private.h" + +/* + * Utility functions to format signed/unsigned integers and append + * them to an archive_string. + */ +static void +append_uint(struct archive_string *as, uintmax_t d, unsigned base) +{ + static const char digits[] = "0123456789abcdef"; + if (d >= base) + append_uint(as, d/base, base); + archive_strappend_char(as, digits[d % base]); +} + +static void +append_int(struct archive_string *as, intmax_t d, unsigned base) +{ + uintmax_t ud; + + if (d < 0) { + archive_strappend_char(as, '-'); + ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d); + } else + ud = d; + append_uint(as, ud, base); +} + + +void +archive_string_sprintf(struct archive_string *as, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + archive_string_vsprintf(as, fmt, ap); + va_end(ap); +} + +/* + * Like 'vsprintf', but ensures the target is big enough, resizing if + * necessary. + */ +void +archive_string_vsprintf(struct archive_string *as, const char *fmt, + va_list ap) +{ + char long_flag; + intmax_t s; /* Signed integer temp. */ + uintmax_t u; /* Unsigned integer temp. */ + const char *p, *p2; + const wchar_t *pw; + + if (archive_string_ensure(as, 64) == NULL) + __archive_errx(1, "Out of memory"); + + if (fmt == NULL) { + as->s[0] = 0; + return; + } + + for (p = fmt; *p != '\0'; p++) { + const char *saved_p = p; + + if (*p != '%') { + archive_strappend_char(as, *p); + continue; + } + + p++; + + long_flag = '\0'; + switch(*p) { + case 'j': + case 'l': + case 'z': + long_flag = *p; + p++; + break; + } + + switch (*p) { + case '%': + archive_strappend_char(as, '%'); + break; + case 'c': + s = va_arg(ap, int); + archive_strappend_char(as, (char)s); + break; + case 'd': + switch(long_flag) { + case 'j': s = va_arg(ap, intmax_t); break; + case 'l': s = va_arg(ap, long); break; + case 'z': s = va_arg(ap, ssize_t); break; + default: s = va_arg(ap, int); break; + } + append_int(as, s, 10); + break; + case 's': + switch(long_flag) { + case 'l': + pw = va_arg(ap, wchar_t *); + if (pw == NULL) + pw = L"(null)"; + if (archive_string_append_from_wcs(as, pw, + wcslen(pw)) != 0 && errno == ENOMEM) + __archive_errx(1, "Out of memory"); + break; + default: + p2 = va_arg(ap, char *); + if (p2 == NULL) + p2 = "(null)"; + archive_strcat(as, p2); + break; + } + break; + case 'S': + pw = va_arg(ap, wchar_t *); + if (pw == NULL) + pw = L"(null)"; + if (archive_string_append_from_wcs(as, pw, + wcslen(pw)) != 0 && errno == ENOMEM) + __archive_errx(1, "Out of memory"); + break; + case 'o': case 'u': case 'x': case 'X': + /* Common handling for unsigned integer formats. */ + switch(long_flag) { + case 'j': u = va_arg(ap, uintmax_t); break; + case 'l': u = va_arg(ap, unsigned long); break; + case 'z': u = va_arg(ap, size_t); break; + default: u = va_arg(ap, unsigned int); break; + } + /* Format it in the correct base. */ + switch (*p) { + case 'o': append_uint(as, u, 8); break; + case 'u': append_uint(as, u, 10); break; + default: append_uint(as, u, 16); break; + } + break; + default: + /* Rewind and print the initial '%' literally. */ + p = saved_p; + archive_strappend_char(as, *p); + } + } +} diff --git a/src/3rdparty/libarchive/libarchive/archive_util.c b/src/3rdparty/libarchive/libarchive/archive_util.c new file mode 100644 index 00000000..bac9ba1c --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_util.c @@ -0,0 +1,585 @@ +/*- + * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_LZMA_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif +#ifdef HAVE_LZ4_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_random_private.h" +#include "archive_string.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +static int archive_utility_string_sort_helper(char **, unsigned int); + +/* Generic initialization of 'struct archive' objects. */ +int +__archive_clean(struct archive *a) +{ + archive_string_conversion_free(a); + return (ARCHIVE_OK); +} + +int +archive_version_number(void) +{ + return (ARCHIVE_VERSION_NUMBER); +} + +const char * +archive_version_string(void) +{ + return (ARCHIVE_VERSION_STRING); +} + +int +archive_errno(struct archive *a) +{ + return (a->archive_error_number); +} + +const char * +archive_error_string(struct archive *a) +{ + + if (a->error != NULL && *a->error != '\0') + return (a->error); + else + return (NULL); +} + +int +archive_file_count(struct archive *a) +{ + return (a->file_count); +} + +int +archive_format(struct archive *a) +{ + return (a->archive_format); +} + +const char * +archive_format_name(struct archive *a) +{ + return (a->archive_format_name); +} + + +int +archive_compression(struct archive *a) +{ + return archive_filter_code(a, 0); +} + +const char * +archive_compression_name(struct archive *a) +{ + return archive_filter_name(a, 0); +} + + +/* + * Return a count of the number of compressed bytes processed. + */ +int64_t +archive_position_compressed(struct archive *a) +{ + return archive_filter_bytes(a, -1); +} + +/* + * Return a count of the number of uncompressed bytes processed. + */ +int64_t +archive_position_uncompressed(struct archive *a) +{ + return archive_filter_bytes(a, 0); +} + +void +archive_clear_error(struct archive *a) +{ + archive_string_empty(&a->error_string); + a->error = NULL; + a->archive_error_number = 0; +} + +void +archive_set_error(struct archive *a, int error_number, const char *fmt, ...) +{ + va_list ap; + + a->archive_error_number = error_number; + if (fmt == NULL) { + a->error = NULL; + return; + } + + archive_string_empty(&(a->error_string)); + va_start(ap, fmt); + archive_string_vsprintf(&(a->error_string), fmt, ap); + va_end(ap); + a->error = a->error_string.s; +} + +void +archive_copy_error(struct archive *dest, struct archive *src) +{ + dest->archive_error_number = src->archive_error_number; + + archive_string_copy(&dest->error_string, &src->error_string); + dest->error = dest->error_string.s; +} + +void +__archive_errx(int retvalue, const char *msg) +{ + static const char msg1[] = "Fatal Internal Error in libarchive: "; + size_t s; + + s = write(2, msg1, strlen(msg1)); + (void)s; /* UNUSED */ + s = write(2, msg, strlen(msg)); + (void)s; /* UNUSED */ + s = write(2, "\n", 1); + (void)s; /* UNUSED */ + exit(retvalue); +} + +/* + * Create a temporary file + */ +#if defined(_WIN32) && !defined(__CYGWIN__) + +/* + * Do not use Windows tmpfile() function. + * It will make a temporary file under the root directory + * and it'll cause permission error if a user who is + * non-Administrator creates temporary files. + * Also Windows version of mktemp family including _mktemp_s + * are not secure. + */ +int +__archive_mktemp(const char *tmpdir) +{ + static const wchar_t prefix[] = L"libarchive_"; + static const wchar_t suffix[] = L"XXXXXXXXXX"; + static const wchar_t num[] = { + L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', + L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', + L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', + L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', + L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', + L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', + L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', + L'u', L'v', L'w', L'x', L'y', L'z' + }; + HCRYPTPROV hProv; + struct archive_wstring temp_name; + wchar_t *ws; + DWORD attr; + wchar_t *xp, *ep; + int fd; + + hProv = (HCRYPTPROV)NULL; + fd = -1; + ws = NULL; + archive_string_init(&temp_name); + + /* Get a temporary directory. */ + if (tmpdir == NULL) { + size_t l; + wchar_t *tmp; + + l = GetTempPathW(0, NULL); + if (l == 0) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + tmp = malloc(l*sizeof(wchar_t)); + if (tmp == NULL) { + errno = ENOMEM; + goto exit_tmpfile; + } + GetTempPathW((DWORD)l, tmp); + archive_wstrcpy(&temp_name, tmp); + free(tmp); + } else { + if (archive_wstring_append_from_mbs(&temp_name, tmpdir, + strlen(tmpdir)) < 0) + goto exit_tmpfile; + if (temp_name.s[temp_name.length-1] != L'/') + archive_wstrappend_wchar(&temp_name, L'/'); + } + + /* Check if temp_name is a directory. */ + attr = GetFileAttributesW(temp_name.s); + if (attr == (DWORD)-1) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + ws = __la_win_permissive_name_w(temp_name.s); + if (ws == NULL) { + errno = EINVAL; + goto exit_tmpfile; + } + attr = GetFileAttributesW(ws); + if (attr == (DWORD)-1) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + } + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { + errno = ENOTDIR; + goto exit_tmpfile; + } + + /* + * Create a temporary file. + */ + archive_wstrcat(&temp_name, prefix); + archive_wstrcat(&temp_name, suffix); + ep = temp_name.s + archive_strlen(&temp_name); + xp = ep - wcslen(suffix); + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + + for (;;) { + wchar_t *p; + HANDLE h; + + /* Generate a random file name through CryptGenRandom(). */ + p = xp; + if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), + (BYTE*)p)) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + for (; p < ep; p++) + *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; + + free(ws); + ws = __la_win_permissive_name_w(temp_name.s); + if (ws == NULL) { + errno = EINVAL; + goto exit_tmpfile; + } + /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to + * delete this temporary file immediately when this + * file closed. */ + h = CreateFileW(ws, + GENERIC_READ | GENERIC_WRITE | DELETE, + 0,/* Not share */ + NULL, + CREATE_NEW,/* Create a new file only */ + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (h == INVALID_HANDLE_VALUE) { + /* The same file already exists. retry with + * a new filename. */ + if (GetLastError() == ERROR_FILE_EXISTS) + continue; + /* Otherwise, fail creation temporary file. */ + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); + if (fd == -1) { + CloseHandle(h); + goto exit_tmpfile; + } else + break;/* success! */ + } +exit_tmpfile: + if (hProv != (HCRYPTPROV)NULL) + CryptReleaseContext(hProv, 0); + free(ws); + archive_wstring_free(&temp_name); + return (fd); +} + +#else + +static int +get_tempdir(struct archive_string *temppath) +{ + const char *tmp; + + tmp = getenv("TMPDIR"); + if (tmp == NULL) +#ifdef _PATH_TMP + tmp = _PATH_TMP; +#else + tmp = "/tmp"; +#endif + archive_strcpy(temppath, tmp); + if (temppath->s[temppath->length-1] != '/') + archive_strappend_char(temppath, '/'); + return (ARCHIVE_OK); +} + +#if defined(HAVE_MKSTEMP) + +/* + * We can use mkstemp(). + */ + +int +__archive_mktemp(const char *tmpdir) +{ + struct archive_string temp_name; + int fd = -1; + + archive_string_init(&temp_name); + if (tmpdir == NULL) { + if (get_tempdir(&temp_name) != ARCHIVE_OK) + goto exit_tmpfile; + } else { + archive_strcpy(&temp_name, tmpdir); + if (temp_name.s[temp_name.length-1] != '/') + archive_strappend_char(&temp_name, '/'); + } + archive_strcat(&temp_name, "libarchive_XXXXXX"); + fd = mkstemp(temp_name.s); + if (fd < 0) + goto exit_tmpfile; + __archive_ensure_cloexec_flag(fd); + unlink(temp_name.s); +exit_tmpfile: + archive_string_free(&temp_name); + return (fd); +} + +#else + +/* + * We use a private routine. + */ + +int +__archive_mktemp(const char *tmpdir) +{ + static const char num[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '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' + }; + struct archive_string temp_name; + struct stat st; + int fd; + char *tp, *ep; + + fd = -1; + archive_string_init(&temp_name); + if (tmpdir == NULL) { + if (get_tempdir(&temp_name) != ARCHIVE_OK) + goto exit_tmpfile; + } else + archive_strcpy(&temp_name, tmpdir); + if (temp_name.s[temp_name.length-1] == '/') { + temp_name.s[temp_name.length-1] = '\0'; + temp_name.length --; + } + if (stat(temp_name.s, &st) < 0) + goto exit_tmpfile; + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + goto exit_tmpfile; + } + archive_strcat(&temp_name, "/libarchive_"); + tp = temp_name.s + archive_strlen(&temp_name); + archive_strcat(&temp_name, "XXXXXXXXXX"); + ep = temp_name.s + archive_strlen(&temp_name); + + do { + char *p; + + p = tp; + archive_random(p, ep - p); + while (p < ep) { + int d = *((unsigned char *)p) % sizeof(num); + *p++ = num[d]; + } + fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, + 0600); + } while (fd < 0 && errno == EEXIST); + if (fd < 0) + goto exit_tmpfile; + __archive_ensure_cloexec_flag(fd); + unlink(temp_name.s); +exit_tmpfile: + archive_string_free(&temp_name); + return (fd); +} + +#endif /* HAVE_MKSTEMP */ +#endif /* !_WIN32 || __CYGWIN__ */ + +/* + * Set FD_CLOEXEC flag to a file descriptor if it is not set. + * We have to set the flag if the platform does not provide O_CLOEXEC + * or F_DUPFD_CLOEXEC flags. + * + * Note: This function is absolutely called after creating a new file + * descriptor even if the platform seemingly provides O_CLOEXEC or + * F_DUPFD_CLOEXEC macros because it is possible that the platform + * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. + */ +void +__archive_ensure_cloexec_flag(int fd) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + (void)fd; /* UNUSED */ +#else + int flags; + + if (fd >= 0) { + flags = fcntl(fd, F_GETFD); + if (flags != -1 && (flags & FD_CLOEXEC) == 0) + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } +#endif +} + +/* + * Utility function to sort a group of strings using quicksort. + */ +static int +archive_utility_string_sort_helper(char **strings, unsigned int n) +{ + unsigned int i, lesser_count, greater_count; + char **lesser, **greater, **tmp, *pivot; + int retval1, retval2; + + /* A list of 0 or 1 elements is already sorted */ + if (n <= 1) + return (ARCHIVE_OK); + + lesser_count = greater_count = 0; + lesser = greater = NULL; + pivot = strings[0]; + for (i = 1; i < n; i++) + { + if (strcmp(strings[i], pivot) < 0) + { + lesser_count++; + tmp = (char **)realloc(lesser, + lesser_count * sizeof(char *)); + if (!tmp) { + free(greater); + free(lesser); + return (ARCHIVE_FATAL); + } + lesser = tmp; + lesser[lesser_count - 1] = strings[i]; + } + else + { + greater_count++; + tmp = (char **)realloc(greater, + greater_count * sizeof(char *)); + if (!tmp) { + free(greater); + free(lesser); + return (ARCHIVE_FATAL); + } + greater = tmp; + greater[greater_count - 1] = strings[i]; + } + } + + /* quicksort(lesser) */ + retval1 = archive_utility_string_sort_helper(lesser, lesser_count); + for (i = 0; i < lesser_count; i++) + strings[i] = lesser[i]; + free(lesser); + + /* pivot */ + strings[lesser_count] = pivot; + + /* quicksort(greater) */ + retval2 = archive_utility_string_sort_helper(greater, greater_count); + for (i = 0; i < greater_count; i++) + strings[lesser_count + 1 + i] = greater[i]; + free(greater); + + return (retval1 < retval2) ? retval1 : retval2; +} + +int +archive_utility_string_sort(char **strings) +{ + unsigned int size = 0; + while (strings[size] != NULL) + size++; + return archive_utility_string_sort_helper(strings, size); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_virtual.c b/src/3rdparty/libarchive/libarchive/archive_virtual.c new file mode 100644 index 00000000..de2595a9 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_virtual.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_virtual.c 201098 2009-12-28 02:58:14Z kientzle $"); + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" + +int +archive_filter_code(struct archive *a, int n) +{ + return ((a->vtable->archive_filter_code)(a, n)); +} + +int +archive_filter_count(struct archive *a) +{ + return ((a->vtable->archive_filter_count)(a)); +} + +const char * +archive_filter_name(struct archive *a, int n) +{ + return ((a->vtable->archive_filter_name)(a, n)); +} + +int64_t +archive_filter_bytes(struct archive *a, int n) +{ + return ((a->vtable->archive_filter_bytes)(a, n)); +} + +int +archive_free(struct archive *a) +{ + if (a == NULL) + return (ARCHIVE_OK); + return ((a->vtable->archive_free)(a)); +} + +int +archive_write_close(struct archive *a) +{ + return ((a->vtable->archive_close)(a)); +} + +int +archive_read_close(struct archive *a) +{ + return ((a->vtable->archive_close)(a)); +} + +int +archive_write_fail(struct archive *a) +{ + a->state = ARCHIVE_STATE_FATAL; + return a->state; +} + +int +archive_write_free(struct archive *a) +{ + return archive_free(a); +} + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* For backwards compatibility; will be removed with libarchive 4.0. */ +int +archive_write_finish(struct archive *a) +{ + return archive_write_free(a); +} +#endif + +int +archive_read_free(struct archive *a) +{ + return archive_free(a); +} + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* For backwards compatibility; will be removed with libarchive 4.0. */ +int +archive_read_finish(struct archive *a) +{ + return archive_read_free(a); +} +#endif + +int +archive_write_header(struct archive *a, struct archive_entry *entry) +{ + ++a->file_count; + return ((a->vtable->archive_write_header)(a, entry)); +} + +int +archive_write_finish_entry(struct archive *a) +{ + return ((a->vtable->archive_write_finish_entry)(a)); +} + +ssize_t +archive_write_data(struct archive *a, const void *buff, size_t s) +{ + return ((a->vtable->archive_write_data)(a, buff, s)); +} + +ssize_t +archive_write_data_block(struct archive *a, const void *buff, size_t s, int64_t o) +{ + if (a->vtable->archive_write_data_block == NULL) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "archive_write_data_block not supported"); + a->state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + return ((a->vtable->archive_write_data_block)(a, buff, s, o)); +} + +int +archive_read_next_header(struct archive *a, struct archive_entry **entry) +{ + return ((a->vtable->archive_read_next_header)(a, entry)); +} + +int +archive_read_next_header2(struct archive *a, struct archive_entry *entry) +{ + return ((a->vtable->archive_read_next_header2)(a, entry)); +} + +int +archive_read_data_block(struct archive *a, + const void **buff, size_t *s, int64_t *o) +{ + return ((a->vtable->archive_read_data_block)(a, buff, s, o)); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_windows.c b/src/3rdparty/libarchive/libarchive/archive_windows.c new file mode 100644 index 00000000..6ff8749a --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_windows.c @@ -0,0 +1,908 @@ +/*- + * Copyright (c) 2009-2011 Michihiro NAKAJIMA + * Copyright (c) 2003-2007 Kees Zeelenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * A set of compatibility glue for building libarchive on Windows platforms. + * + * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg + * for the GnuWin32 project, trimmed significantly by Tim Kientzle. + * + * Much of the original file was unnecessary for libarchive, because + * many of the features it emulated were not strictly necessary for + * libarchive. I hope for this to shrink further as libarchive + * internals are gradually reworked to sit more naturally on both + * POSIX and Windows. Any ideas for this are greatly appreciated. + * + * The biggest remaining issue is the dev/ino emulation; libarchive + * has a couple of public APIs that rely on dev/ino uniquely + * identifying a file. This doesn't match well with Windows. I'm + * considering alternative APIs. + */ + +#if defined(_WIN32) && !defined(__CYGWIN__) + +#include "archive_platform.h" +#include "archive_private.h" +#include "archive_entry.h" +#include +#include +#include +#ifdef HAVE_SYS_UTIME_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) + +#if defined(__LA_LSEEK_NEEDED) +static BOOL SetFilePointerEx_perso(HANDLE hFile, + LARGE_INTEGER liDistanceToMove, + PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod) +{ + LARGE_INTEGER li; + li.QuadPart = liDistanceToMove.QuadPart; + li.LowPart = SetFilePointer( + hFile, li.LowPart, &li.HighPart, dwMoveMethod); + if(lpNewFilePointer) { + lpNewFilePointer->QuadPart = li.QuadPart; + } + return li.LowPart != -1 || GetLastError() == NO_ERROR; +} +#endif + +struct ustat { + int64_t st_atime; + uint32_t st_atime_nsec; + int64_t st_ctime; + uint32_t st_ctime_nsec; + int64_t st_mtime; + uint32_t st_mtime_nsec; + gid_t st_gid; + /* 64bits ino */ + int64_t st_ino; + mode_t st_mode; + uint32_t st_nlink; + uint64_t st_size; + uid_t st_uid; + dev_t st_dev; + dev_t st_rdev; +}; + +/* Transform 64-bits ino into 32-bits by hashing. + * You do not forget that really unique number size is 64-bits. + */ +#define INOSIZE (8*sizeof(ino_t)) /* 32 */ +static __inline ino_t +getino(struct ustat *ub) +{ + ULARGE_INTEGER ino64; + ino64.QuadPart = ub->st_ino; + /* I don't know this hashing is correct way */ + return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE))); +} + +/* + * Prepend "\\?\" to the path name and convert it to unicode to permit + * an extended-length path for a maximum total path length of 32767 + * characters. + * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx + */ +wchar_t * +__la_win_permissive_name(const char *name) +{ + wchar_t *wn; + wchar_t *ws; + size_t ll; + + ll = strlen(name); + wn = malloc((ll + 1) * sizeof(wchar_t)); + if (wn == NULL) + return (NULL); + ll = mbstowcs(wn, name, ll); + if (ll == (size_t)-1) { + free(wn); + return (NULL); + } + wn[ll] = L'\0'; + ws = __la_win_permissive_name_w(wn); + free(wn); + return (ws); +} + +wchar_t * +__la_win_permissive_name_w(const wchar_t *wname) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + DWORD l, len, slen; + int unc; + + /* Get a full-pathname. */ + l = GetFullPathNameW(wname, 0, NULL, NULL); + if (l == 0) + return (NULL); + /* NOTE: GetFullPathNameW has a bug that if the length of the file + * name is just 1 then it returns incomplete buffer size. Thus, we + * have to add three to the size to allocate a sufficient buffer + * size for the full-pathname of the file name. */ + l += 3; + wnp = malloc(l * sizeof(wchar_t)); + if (wnp == NULL) + return (NULL); + len = GetFullPathNameW(wname, l, wnp, NULL); + wn = wnp; + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'?' && wnp[3] == L'\\') + /* We have already a permissive name. */ + return (wn); + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'.' && wnp[3] == L'\\') { + /* This is a device name */ + if (((wnp[4] >= L'a' && wnp[4] <= L'z') || + (wnp[4] >= L'A' && wnp[4] <= L'Z')) && + wnp[5] == L':' && wnp[6] == L'\\') + wnp[2] = L'?';/* Not device name. */ + return (wn); + } + + unc = 0; + if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { + wchar_t *p = &wnp[2]; + + /* Skip server-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\') { + wchar_t *rp = ++p; + /* Skip share-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\' && p != rp) { + /* Now, match patterns such as + * "\\server-name\share-name\" */ + wnp += 2; + len -= 2; + unc = 1; + } + } + } + + slen = 4 + (unc * 4) + len + 1; + ws = wsp = malloc(slen * sizeof(wchar_t)); + if (ws == NULL) { + free(wn); + return (NULL); + } + /* prepend "\\?\" */ + wcsncpy(wsp, L"\\\\?\\", 4); + wsp += 4; + slen -= 4; + if (unc) { + /* append "UNC\" ---> "\\?\UNC\" */ + wcsncpy(wsp, L"UNC\\", 4); + wsp += 4; + slen -= 4; + } + wcsncpy(wsp, wnp, slen); + wsp[slen - 1] = L'\0'; /* Ensure null termination. */ + free(wn); + return (ws); +} + +/* + * Create a file handle. + * This can exceed MAX_PATH limitation. + */ +static HANDLE +la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + wchar_t *wpath; + HANDLE handle; + + handle = CreateFileA(path, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + if (handle != INVALID_HANDLE_VALUE) + return (handle); + if (GetLastError() != ERROR_PATH_NOT_FOUND) + return (handle); + wpath = __la_win_permissive_name(path); + if (wpath == NULL) + return (handle); + handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + free(wpath); + return (handle); +} + +#if defined(__LA_LSEEK_NEEDED) +__int64 +__la_lseek(int fd, __int64 offset, int whence) +{ + LARGE_INTEGER distance; + LARGE_INTEGER newpointer; + HANDLE handle; + + if (fd < 0) { + errno = EBADF; + return (-1); + } + handle = (HANDLE)_get_osfhandle(fd); + if (GetFileType(handle) != FILE_TYPE_DISK) { + errno = EBADF; + return (-1); + } + distance.QuadPart = offset; + if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_BROKEN_PIPE) + return (0); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + la_dosmaperr(lasterr); + return (-1); + } + return (newpointer.QuadPart); +} +#endif + +/* This can exceed MAX_PATH limitation. */ +int +__la_open(const char *path, int flags, ...) +{ + va_list ap; + wchar_t *ws; + int r, pmode; + DWORD attr; + + va_start(ap, flags); + pmode = va_arg(ap, int); + va_end(ap); + ws = NULL; + if ((flags & ~O_BINARY) == O_RDONLY) { + /* + * When we open a directory, _open function returns + * "Permission denied" error. + */ + attr = GetFileAttributesA(path); + if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) { + ws = __la_win_permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + attr = GetFileAttributesW(ws); + } + if (attr == (DWORD)-1) { + la_dosmaperr(GetLastError()); + free(ws); + return (-1); + } + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + HANDLE handle; + + if (ws != NULL) + handle = CreateFileW(ws, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + else + handle = CreateFileA(path, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + free(ws); + if (handle == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + r = _open_osfhandle((intptr_t)handle, _O_RDONLY); + return (r); + } + } + if (ws == NULL) { +#if defined(__BORLANDC__) + /* Borland has no mode argument. + TODO: Fix mode of new file. */ + r = _open(path, flags); +#else + r = _open(path, flags, pmode); +#endif + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* Simulate other POSIX system action to pass our test suite. */ + attr = GetFileAttributesA(path); + if (attr == (DWORD)-1) + la_dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + return (-1); + } + if (r >= 0 || errno != ENOENT) + return (r); + ws = __la_win_permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + } + r = _wopen(ws, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* Simulate other POSIX system action to pass our test suite. */ + attr = GetFileAttributesW(ws); + if (attr == (DWORD)-1) + la_dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } + free(ws); + return (r); +} + +ssize_t +__la_read(int fd, void *buf, size_t nbytes) +{ + HANDLE handle; + DWORD bytes_read, lasterr; + int r; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + /* Do not pass 0 to third parameter of ReadFile(), read bytes. + * This will not return to application side. */ + if (nbytes == 0) + return (0); + handle = (HANDLE)_get_osfhandle(fd); + r = ReadFile(handle, buf, (uint32_t)nbytes, + &bytes_read, NULL); + if (r == 0) { + lasterr = GetLastError(); + if (lasterr == ERROR_NO_DATA) { + errno = EAGAIN; + return (-1); + } + if (lasterr == ERROR_BROKEN_PIPE) + return (0); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + la_dosmaperr(lasterr); + return (-1); + } + return ((ssize_t)bytes_read); +} + +/* Convert Windows FILETIME to UTC */ +__inline static void +fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ + } else { + *t = 0; + *ns = 0; + } +} + +/* Stat by handle + * Windows' stat() does not accept the path added "\\?\" especially "?" + * character. + * It means we cannot access the long name path longer than MAX_PATH. + * So I've implemented simular Windows' stat() to access the long name path. + * And I've added some feature. + * 1. set st_ino by nFileIndexHigh and nFileIndexLow of + * BY_HANDLE_FILE_INFORMATION. + * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. + * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. + */ +static int +__hstat(HANDLE handle, struct ustat *st) +{ + BY_HANDLE_FILE_INFORMATION info; + ULARGE_INTEGER ino64; + DWORD ftype; + mode_t mode; + time_t t; + long ns; + + switch (ftype = GetFileType(handle)) { + case FILE_TYPE_UNKNOWN: + errno = EBADF; + return (-1); + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + if (ftype == FILE_TYPE_CHAR) { + st->st_mode = S_IFCHR; + st->st_size = 0; + } else { + DWORD avail; + + st->st_mode = S_IFIFO; + if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) + st->st_size = avail; + else + st->st_size = 0; + } + st->st_atime = 0; + st->st_atime_nsec = 0; + st->st_mtime = 0; + st->st_mtime_nsec = 0; + st->st_ctime = 0; + st->st_ctime_nsec = 0; + st->st_ino = 0; + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_dev = 0; + return (0); + case FILE_TYPE_DISK: + break; + default: + /* This ftype is undocumented type. */ + la_dosmaperr(GetLastError()); + return (-1); + } + + ZeroMemory(&info, sizeof(info)); + if (!GetFileInformationByHandle (handle, &info)) { + la_dosmaperr(GetLastError()); + return (-1); + } + + mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else + mode |= S_IFREG; + st->st_mode = mode; + + fileTimeToUTC(&info.ftLastAccessTime, &t, &ns); + st->st_atime = t; + st->st_atime_nsec = ns; + fileTimeToUTC(&info.ftLastWriteTime, &t, &ns); + st->st_mtime = t; + st->st_mtime_nsec = ns; + fileTimeToUTC(&info.ftCreationTime, &t, &ns); + st->st_ctime = t; + st->st_ctime_nsec = ns; + st->st_size = + ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + + (int64_t)(info.nFileSizeLow); +#ifdef SIMULATE_WIN_STAT + st->st_ino = 0; + st->st_nlink = 1; + st->st_dev = 0; +#else + /* Getting FileIndex as i-node. We should remove a sequence which + * is high-16-bits of nFileIndexHigh. */ + ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; + ino64.LowPart = info.nFileIndexLow; + st->st_ino = ino64.QuadPart; + st->st_nlink = info.nNumberOfLinks; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ++st->st_nlink;/* Add parent directory. */ + st->st_dev = info.dwVolumeSerialNumber; +#endif + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + return (0); +} + +static void +copy_stat(struct stat *st, struct ustat *us) +{ + st->st_atime = us->st_atime; + st->st_ctime = us->st_ctime; + st->st_mtime = us->st_mtime; + st->st_gid = us->st_gid; + st->st_ino = getino(us); + st->st_mode = us->st_mode; + st->st_nlink = us->st_nlink; + st->st_size = (off_t)us->st_size; + st->st_uid = us->st_uid; + st->st_dev = us->st_dev; + st->st_rdev = us->st_rdev; +} + +/* + * TODO: Remove a use of __la_fstat and __la_stat. + * We should use GetFileInformationByHandle in place + * where We still use the *stat functions. + */ +int +__la_fstat(int fd, struct stat *st) +{ + struct ustat u; + int ret; + + if (fd < 0) { + errno = EBADF; + return (-1); + } + ret = __hstat((HANDLE)_get_osfhandle(fd), &u); + if (ret >= 0) { + copy_stat(st, &u); + if (u.st_mode & (S_IFCHR | S_IFIFO)) { + st->st_dev = fd; + st->st_rdev = fd; + } + } + return (ret); +} + +/* This can exceed MAX_PATH limitation. */ +int +__la_stat(const char *path, struct stat *st) +{ + HANDLE handle; + struct ustat u; + int ret; + + handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + ret = __hstat(handle, &u); + CloseHandle(handle); + if (ret >= 0) { + char *p; + + copy_stat(st, &u); + p = strrchr(path, '.'); + if (p != NULL && strlen(p) == 4) { + char exttype[4]; + + ++ p; + exttype[0] = toupper(*p++); + exttype[1] = toupper(*p++); + exttype[2] = toupper(*p++); + exttype[3] = '\0'; + if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || + !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + } + } + return (ret); +} + +/* + * This waitpid is limited implementation. + */ +pid_t +__la_waitpid(HANDLE child, int *status, int option) +{ + DWORD cs; + + (void)option;/* UNUSED */ + do { + if (GetExitCodeProcess(child, &cs) == 0) { + CloseHandle(child); + la_dosmaperr(GetLastError()); + *status = 0; + return (-1); + } + } while (cs == STILL_ACTIVE); + + *status = (int)(cs & 0xff); + return (0); +} + +ssize_t +__la_write(int fd, const void *buf, size_t nbytes) +{ + DWORD bytes_written; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, + &bytes_written, NULL)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + la_dosmaperr(lasterr); + return (-1); + } + return (bytes_written); +} + +/* + * Replace the Windows path separator '\' with '/'. + */ +static int +replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp) +{ + wchar_t *w; + size_t path_length; + + if (wp == NULL) + return(0); + if (wcschr(wp, L'\\') == NULL) + return(0); + path_length = wcslen(wp); + if (archive_wstring_ensure(ws, path_length) == NULL) + return(-1); + archive_wstrncpy(ws, wp, path_length); + for (w = ws->s; *w; w++) { + if (*w == L'\\') + *w = L'/'; + } + return(1); +} + +static int +fix_pathseparator(struct archive_entry *entry) +{ + struct archive_wstring ws; + const wchar_t *wp; + int ret = ARCHIVE_OK; + + archive_string_init(&ws); + wp = archive_entry_pathname_w(entry); + switch (replace_pathseparator(&ws, wp)) { + case 0: /* Not replaced. */ + break; + case 1: /* Replaced. */ + archive_entry_copy_pathname_w(entry, ws.s); + break; + default: + ret = ARCHIVE_FAILED; + } + wp = archive_entry_hardlink_w(entry); + switch (replace_pathseparator(&ws, wp)) { + case 0: /* Not replaced. */ + break; + case 1: /* Replaced. */ + archive_entry_copy_hardlink_w(entry, ws.s); + break; + default: + ret = ARCHIVE_FAILED; + } + wp = archive_entry_symlink_w(entry); + switch (replace_pathseparator(&ws, wp)) { + case 0: /* Not replaced. */ + break; + case 1: /* Replaced. */ + archive_entry_copy_symlink_w(entry, ws.s); + break; + default: + ret = ARCHIVE_FAILED; + } + archive_wstring_free(&ws); + return(ret); +} + +struct archive_entry * +__la_win_entry_in_posix_pathseparator(struct archive_entry *entry) +{ + struct archive_entry *entry_main; + const wchar_t *wp; + int has_backslash = 0; + int ret; + + wp = archive_entry_pathname_w(entry); + if (wp != NULL && wcschr(wp, L'\\') != NULL) + has_backslash = 1; + if (!has_backslash) { + wp = archive_entry_hardlink_w(entry); + if (wp != NULL && wcschr(wp, L'\\') != NULL) + has_backslash = 1; + } + if (!has_backslash) { + wp = archive_entry_symlink_w(entry); + if (wp != NULL && wcschr(wp, L'\\') != NULL) + has_backslash = 1; + } + /* + * If there is no backslash chars, return the original. + */ + if (!has_backslash) + return (entry); + + /* Copy entry so we can modify it as needed. */ + entry_main = archive_entry_clone(entry); + if (entry_main == NULL) + return (NULL); + /* Replace the Windows path-separator '\' with '/'. */ + ret = fix_pathseparator(entry_main); + if (ret < ARCHIVE_WARN) { + archive_entry_free(entry_main); + return (NULL); + } + return (entry_main); +} + + +/* + * The following function was modified from PostgreSQL sources and is + * subject to the copyright below. + */ +/*------------------------------------------------------------------------- + * + * win32error.c + * Map win32 error codes to errno values + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +*/ + +static const struct { + DWORD winerr; + int doserr; +} doserrors[] = +{ + { ERROR_INVALID_FUNCTION, EINVAL }, + { ERROR_FILE_NOT_FOUND, ENOENT }, + { ERROR_PATH_NOT_FOUND, ENOENT }, + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, + { ERROR_ACCESS_DENIED, EACCES }, + { ERROR_INVALID_HANDLE, EBADF }, + { ERROR_ARENA_TRASHED, ENOMEM }, + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, + { ERROR_INVALID_BLOCK, ENOMEM }, + { ERROR_BAD_ENVIRONMENT, E2BIG }, + { ERROR_BAD_FORMAT, ENOEXEC }, + { ERROR_INVALID_ACCESS, EINVAL }, + { ERROR_INVALID_DATA, EINVAL }, + { ERROR_INVALID_DRIVE, ENOENT }, + { ERROR_CURRENT_DIRECTORY, EACCES }, + { ERROR_NOT_SAME_DEVICE, EXDEV }, + { ERROR_NO_MORE_FILES, ENOENT }, + { ERROR_LOCK_VIOLATION, EACCES }, + { ERROR_SHARING_VIOLATION, EACCES }, + { ERROR_BAD_NETPATH, ENOENT }, + { ERROR_NETWORK_ACCESS_DENIED, EACCES }, + { ERROR_BAD_NET_NAME, ENOENT }, + { ERROR_FILE_EXISTS, EEXIST }, + { ERROR_CANNOT_MAKE, EACCES }, + { ERROR_FAIL_I24, EACCES }, + { ERROR_INVALID_PARAMETER, EINVAL }, + { ERROR_NO_PROC_SLOTS, EAGAIN }, + { ERROR_DRIVE_LOCKED, EACCES }, + { ERROR_BROKEN_PIPE, EPIPE }, + { ERROR_DISK_FULL, ENOSPC }, + { ERROR_INVALID_TARGET_HANDLE, EBADF }, + { ERROR_INVALID_HANDLE, EINVAL }, + { ERROR_WAIT_NO_CHILDREN, ECHILD }, + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, + { ERROR_NEGATIVE_SEEK, EINVAL }, + { ERROR_SEEK_ON_DEVICE, EACCES }, + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, + { ERROR_NOT_LOCKED, EACCES }, + { ERROR_BAD_PATHNAME, ENOENT }, + { ERROR_MAX_THRDS_REACHED, EAGAIN }, + { ERROR_LOCK_FAILED, EACCES }, + { ERROR_ALREADY_EXISTS, EEXIST }, + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } +}; + +void +__la_dosmaperr(unsigned long e) +{ + int i; + + if (e == 0) + { + errno = 0; + return; + } + + for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++) + { + if (doserrors[i].winerr == e) + { + errno = doserrors[i].doserr; + return; + } + } + + /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */ + errno = EINVAL; + return; +} + +#endif /* _WIN32 && !__CYGWIN__ */ diff --git a/src/3rdparty/libarchive/libarchive/archive_windows.h b/src/3rdparty/libarchive/libarchive/archive_windows.h new file mode 100644 index 00000000..e77cd08f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_windows.h @@ -0,0 +1,318 @@ +/*- + * Copyright (c) 2009-2011 Michihiro NAKAJIMA + * Copyright (c) 2003-2006 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +/* + * TODO: A lot of stuff in here isn't actually used by libarchive and + * can be trimmed out. Note that this file is used by libarchive and + * libarchive_test but nowhere else. (But note that it gets compiled + * with many different Windows environments, including MinGW, Visual + * Studio, and Cygwin. Significant changes should be tested in all three.) + */ + +/* + * TODO: Don't use off_t in here. Use __int64 instead. Note that + * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's + * more modern file handling APIs all use __int64 instead of off_t. + */ + +#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED +#define LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED + +/* Start of configuration for native Win32 */ +#ifndef MINGW_HAS_SECURE_API +#define MINGW_HAS_SECURE_API 1 +#endif + +#include +#define set_errno(val) ((errno)=val) +#include +#include //brings in NULL +#if defined(HAVE_STDINT_H) +#include +#endif +#include +#include +#include +#include +#include +#if defined(__MINGW32__) && defined(HAVE_UNISTD_H) +/* Prevent build error from a type mismatch of ftruncate(). + * This unistd.h defines it as ftruncate(int, off_t). */ +#include +#endif +#define NOCRYPT +#include +//#define EFTYPE 7 + +#if defined(__BORLANDC__) +#pragma warn -8068 /* Constant out of range in comparison. */ +#pragma warn -8072 /* Suspicious pointer arithmetic. */ +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/* Alias the Windows _function to the POSIX equivalent. */ +#define close _close +#define fcntl(fd, cmd, flg) /* No operation. */ +#ifndef fileno +#define fileno _fileno +#endif +#ifdef fstat +#undef fstat +#endif +#define fstat __la_fstat +#if !defined(__BORLANDC__) +#ifdef lseek +#undef lseek +#endif +#define lseek _lseeki64 +#else +#define lseek __la_lseek +#define __LA_LSEEK_NEEDED +#endif +#define lstat __la_stat +#define open __la_open +#define read __la_read +#if !defined(__BORLANDC__) && !defined(__WATCOMC__) +#define setmode _setmode +#endif +#ifdef stat +#undef stat +#endif +#define stat(path,stref) __la_stat(path,stref) +#if !defined(__WATCOMC__) +#if !defined(__BORLANDC__) +#define strdup _strdup +#endif +#define tzset _tzset +#if !defined(__BORLANDC__) +#define umask _umask +#endif +#endif +#define waitpid __la_waitpid +#define write __la_write + +#if !defined(__WATCOMC__) + +#ifndef O_RDONLY +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_TRUNC _O_TRUNC +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL +#define O_BINARY _O_BINARY +#endif + +#ifndef _S_IFIFO + #define _S_IFIFO 0010000 /* pipe */ +#endif +#ifndef _S_IFCHR + #define _S_IFCHR 0020000 /* character special */ +#endif +#ifndef _S_IFDIR + #define _S_IFDIR 0040000 /* directory */ +#endif +#ifndef _S_IFBLK + #define _S_IFBLK 0060000 /* block special */ +#endif +#ifndef _S_IFLNK + #define _S_IFLNK 0120000 /* symbolic link */ +#endif +#ifndef _S_IFSOCK + #define _S_IFSOCK 0140000 /* socket */ +#endif +#ifndef _S_IFREG + #define _S_IFREG 0100000 /* regular */ +#endif +#ifndef _S_IFMT + #define _S_IFMT 0170000 /* file type mask */ +#endif + +#ifndef S_IFIFO +#define S_IFIFO _S_IFIFO +#endif +//#define S_IFCHR _S_IFCHR +//#define S_IFDIR _S_IFDIR +#ifndef S_IFBLK +#define S_IFBLK _S_IFBLK +#endif +#ifndef S_IFLNK +#define S_IFLNK _S_IFLNK +#endif +#ifndef S_IFSOCK +#define S_IFSOCK _S_IFSOCK +#endif +//#define S_IFREG _S_IFREG +//#define S_IFMT _S_IFMT + +#ifndef S_ISBLK +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */ +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */ +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */ +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */ +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */ +#endif +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */ +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */ + +#define _S_ISUID 0004000 /* set user id on execution */ +#define _S_ISGID 0002000 /* set group id on execution */ +#define _S_ISVTX 0001000 /* save swapped text even after use */ + +#define S_ISUID _S_ISUID +#define S_ISGID _S_ISGID +#define S_ISVTX _S_ISVTX + +#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) +#define _S_IXUSR _S_IEXEC /* read permission, user */ +#define _S_IWUSR _S_IWRITE /* write permission, user */ +#define _S_IRUSR _S_IREAD /* execute/search permission, user */ +#define _S_IRWXG (_S_IRWXU >> 3) +#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */ +#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */ +#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */ +#define _S_IRWXO (_S_IRWXG >> 3) +#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */ +#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */ +#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */ + +#ifndef S_IRWXU +#define S_IRWXU _S_IRWXU +#define S_IXUSR _S_IXUSR +#define S_IWUSR _S_IWUSR +#define S_IRUSR _S_IRUSR +#endif +#ifndef S_IRWXG +#define S_IRWXG _S_IRWXG +#define S_IXGRP _S_IXGRP +#define S_IWGRP _S_IWGRP +#endif +#ifndef S_IRGRP +#define S_IRGRP _S_IRGRP +#endif +#ifndef S_IRWXO +#define S_IRWXO _S_IRWXO +#define S_IXOTH _S_IXOTH +#define S_IWOTH _S_IWOTH +#define S_IROTH _S_IROTH +#endif + +#endif + +#define F_DUPFD 0 /* Duplicate file descriptor. */ +#define F_GETFD 1 /* Get file descriptor flags. */ +#define F_SETFD 2 /* Set file descriptor flags. */ +#define F_GETFL 3 /* Get file status flags. */ +#define F_SETFL 4 /* Set file status flags. */ +#define F_GETOWN 5 /* Get owner (receiver of SIGIO). */ +#define F_SETOWN 6 /* Set owner (receiver of SIGIO). */ +#define F_GETLK 7 /* Get record locking info. */ +#define F_SETLK 8 /* Set record locking info (non-blocking). */ +#define F_SETLKW 9 /* Set record locking info (blocking). */ + +/* XXX missing */ +#define F_GETLK64 7 /* Get record locking info. */ +#define F_SETLK64 8 /* Set record locking info (non-blocking). */ +#define F_SETLKW64 9 /* Set record locking info (blocking). */ + +/* File descriptor flags used with F_GETFD and F_SETFD. */ +#define FD_CLOEXEC 1 /* Close on exec. */ + +//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else... +#define O_NONBLOCK 0x0004 /* Non-blocking I/O. */ +//#define O_NDELAY O_NONBLOCK + +/* Symbolic constants for the access() function */ +#if !defined(F_OK) + #define R_OK 4 /* Test for read permission */ + #define W_OK 2 /* Test for write permission */ + #define X_OK 1 /* Test for execute permission */ + #define F_OK 0 /* Test for existence of file */ +#endif + + +/* Replacement POSIX function */ +extern int __la_fstat(int fd, struct stat *st); +extern int __la_lstat(const char *path, struct stat *st); +#if defined(__LA_LSEEK_NEEDED) +extern __int64 __la_lseek(int fd, __int64 offset, int whence); +#endif +extern int __la_open(const char *path, int flags, ...); +extern ssize_t __la_read(int fd, void *buf, size_t nbytes); +extern int __la_stat(const char *path, struct stat *st); +extern pid_t __la_waitpid(HANDLE child, int *status, int option); +extern ssize_t __la_write(int fd, const void *buf, size_t nbytes); + +#define _stat64i32(path, st) __la_stat(path, st) +#define _stat64(path, st) __la_stat(path, st) +/* for status returned by la_waitpid */ +#define WIFEXITED(sts) ((sts & 0x100) == 0) +#define WEXITSTATUS(sts) (sts & 0x0FF) + +extern wchar_t *__la_win_permissive_name(const char *name); +extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname); +extern void __la_dosmaperr(unsigned long e); +#define la_dosmaperr(e) __la_dosmaperr(e) +extern struct archive_entry *__la_win_entry_in_posix_pathseparator( + struct archive_entry *); + +#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__) +typedef int mbstate_t; +size_t wcrtomb(char *, wchar_t, mbstate_t *); +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 +WINBASEAPI BOOL WINAPI GetVolumePathNameW( + LPCWSTR lpszFileName, + LPWSTR lpszVolumePathName, + DWORD cchBufferLength + ); +# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */ +typedef struct _FILE_ALLOCATED_RANGE_BUFFER { + LARGE_INTEGER FileOffset; + LARGE_INTEGER Length; +} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER; +# define FSCTL_SET_SPARSE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA) +# define FSCTL_QUERY_ALLOCATED_RANGES \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA) +# endif +#endif + +#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */ diff --git a/src/3rdparty/libarchive/libarchive/archive_write.c b/src/3rdparty/libarchive/libarchive/archive_write.c new file mode 100644 index 00000000..0634a229 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write.c @@ -0,0 +1,734 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03:00Z kientzle $"); + +/* + * This file contains the "essential" portions of the write API, that + * is, stuff that will essentially always be used by any client that + * actually needs to write an archive. Optional pieces have been, as + * far as possible, separated out into separate files to reduce + * needlessly bloating statically-linked clients. + */ + +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_write_private.h" + +static struct archive_vtable *archive_write_vtable(void); + +static int _archive_filter_code(struct archive *, int); +static const char *_archive_filter_name(struct archive *, int); +static int64_t _archive_filter_bytes(struct archive *, int); +static int _archive_write_filter_count(struct archive *); +static int _archive_write_close(struct archive *); +static int _archive_write_free(struct archive *); +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 { + size_t buffer_size; + size_t avail; + char *buffer; + char *next; +}; + +static struct archive_vtable * +archive_write_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_close = _archive_write_close; + av.archive_filter_bytes = _archive_filter_bytes; + av.archive_filter_code = _archive_filter_code; + av.archive_filter_name = _archive_filter_name; + av.archive_filter_count = _archive_write_filter_count; + av.archive_free = _archive_write_free; + av.archive_write_header = _archive_write_header; + av.archive_write_finish_entry = _archive_write_finish_entry; + av.archive_write_data = _archive_write_data; + inited = 1; + } + return (&av); +} + +/* + * Allocate, initialize and return an archive object. + */ +struct archive * +archive_write_new(void) +{ + struct archive_write *a; + unsigned char *nulls; + + a = (struct archive_write *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_WRITE_MAGIC; + a->archive.state = ARCHIVE_STATE_NEW; + a->archive.vtable = archive_write_vtable(); + /* + * The value 10240 here matches the traditional tar default, + * but is otherwise arbitrary. + * TODO: Set the default block size from the format selected. + */ + a->bytes_per_block = 10240; + a->bytes_in_last_block = -1; /* Default */ + + /* Initialize a block of nulls for padding purposes. */ + a->null_length = 1024; + nulls = (unsigned char *)calloc(1, a->null_length); + if (nulls == NULL) { + free(a); + return (NULL); + } + a->nulls = nulls; + return (&a->archive); +} + +/* + * Set the block size. Returns 0 if successful. + */ +int +archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block) +{ + struct archive_write *a = (struct archive_write *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block"); + a->bytes_per_block = bytes_per_block; + return (ARCHIVE_OK); +} + +/* + * Get the current block size. -1 if it has never been set. + */ +int +archive_write_get_bytes_per_block(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block"); + return (a->bytes_per_block); +} + +/* + * Set the size for the last block. + * Returns 0 if successful. + */ +int +archive_write_set_bytes_in_last_block(struct archive *_a, int bytes) +{ + struct archive_write *a = (struct archive_write *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block"); + a->bytes_in_last_block = bytes; + return (ARCHIVE_OK); +} + +/* + * Return the value set above. -1 indicates it has not been set. + */ +int +archive_write_get_bytes_in_last_block(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block"); + return (a->bytes_in_last_block); +} + +/* + * dev/ino of a file to be rejected. Used to prevent adding + * an archive to itself recursively. + */ +int +archive_write_set_skip_file(struct archive *_a, int64_t d, int64_t i) +{ + struct archive_write *a = (struct archive_write *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_set_skip_file"); + a->skip_file_set = 1; + a->skip_file_dev = d; + a->skip_file_ino = i; + return (ARCHIVE_OK); +} + +/* + * Allocate and return the next filter structure. + */ +struct archive_write_filter * +__archive_write_allocate_filter(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct archive_write_filter *f; + + f = calloc(1, sizeof(*f)); + f->archive = _a; + if (a->filter_first == NULL) + a->filter_first = f; + else + a->filter_last->next_filter = f; + a->filter_last = f; + return f; +} + +/* + * Write data to a particular filter. + */ +int +__archive_write_filter(struct archive_write_filter *f, + const void *buff, size_t length) +{ + int r; + if (length == 0) + return(ARCHIVE_OK); + if (f->write == NULL) + /* If unset, a fatal error has already occurred, so this filter + * didn't open. We cannot write anything. */ + return(ARCHIVE_FATAL); + r = (f->write)(f, buff, length); + f->bytes_written += length; + return (r); +} + +/* + * Open a filter. + */ +int +__archive_write_open_filter(struct archive_write_filter *f) +{ + if (f->open == NULL) + return (ARCHIVE_OK); + return (f->open)(f); +} + +/* + * Close a filter. + */ +int +__archive_write_close_filter(struct archive_write_filter *f) +{ + if (f->close != NULL) + return (f->close)(f); + if (f->next_filter != NULL) + return (__archive_write_close_filter(f->next_filter)); + return (ARCHIVE_OK); +} + +int +__archive_write_output(struct archive_write *a, const void *buff, size_t length) +{ + return (__archive_write_filter(a->filter_first, buff, length)); +} + +int +__archive_write_nulls(struct archive_write *a, size_t length) +{ + if (length == 0) + return (ARCHIVE_OK); + + while (length > 0) { + size_t to_write = length < a->null_length ? length : a->null_length; + int r = __archive_write_output(a, a->nulls, to_write); + if (r < ARCHIVE_OK) + return (r); + length -= to_write; + } + return (ARCHIVE_OK); +} + +static int +archive_write_client_open(struct archive_write_filter *f) +{ + struct archive_write *a = (struct archive_write *)f->archive; + struct archive_none *state; + void *buffer; + size_t buffer_size; + + f->bytes_per_block = archive_write_get_bytes_per_block(f->archive); + f->bytes_in_last_block = + archive_write_get_bytes_in_last_block(f->archive); + buffer_size = f->bytes_per_block; + + state = (struct archive_none *)calloc(1, sizeof(*state)); + buffer = (char *)malloc(buffer_size); + if (state == NULL || buffer == NULL) { + free(state); + 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; + + if (a->client_opener == NULL) + return (ARCHIVE_OK); + return (a->client_opener(f->archive, a->client_data)); +} + +static int +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; + const char *buff = (const char *)_buff; + ssize_t remaining, to_copy; + ssize_t bytes_written; + + remaining = length; + + /* + * If there is no buffer for blocking, just pass the data + * straight through to the client write callback. In + * particular, this supports "no write delay" operation for + * special applications. Just set the block size to zero. + */ + if (state->buffer_size == 0) { + while (remaining > 0) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, buff, remaining); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + remaining -= bytes_written; + buff += bytes_written; + } + return (ARCHIVE_OK); + } + + /* If the copy buffer isn't empty, try to fill it. */ + if (state->avail < state->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; + 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; + while (to_write > 0) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, p, to_write); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + if ((size_t)bytes_written > to_write) { + archive_set_error(&(a->archive), + -1, "write overrun"); + return (ARCHIVE_FATAL); + } + p += bytes_written; + to_write -= bytes_written; + } + state->next = state->buffer; + state->avail = state->buffer_size; + } + } + + while ((size_t)remaining >= state->buffer_size) { + /* Write out full blocks directly to client. */ + bytes_written = (a->client_writer)(&a->archive, + a->client_data, buff, state->buffer_size); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + buff += bytes_written; + remaining -= bytes_written; + } + + if (remaining > 0) { + /* Copy last bit into copy buffer. */ + memcpy(state->next, buff, remaining); + state->next += remaining; + state->avail -= remaining; + } + return (ARCHIVE_OK); +} + +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; + ssize_t block_length; + ssize_t target_block_length; + ssize_t bytes_written; + 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; + + /* Tricky calculation to determine size of last block */ + if (a->bytes_in_last_block <= 0) + /* Default or Zero: pad to full block */ + target_block_length = a->bytes_per_block; + else + /* Round to next multiple of bytes_in_last_block. */ + target_block_length = a->bytes_in_last_block * + ( (block_length + a->bytes_in_last_block - 1) / + a->bytes_in_last_block); + 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, + target_block_length - block_length); + block_length = target_block_length; + } + bytes_written = (a->client_writer)(&a->archive, + a->client_data, state->buffer, block_length); + ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK; + } + if (a->client_closer) + (*a->client_closer)(&a->archive, a->client_data); + free(state->buffer); + free(state); + /* Clear the close handler myself not to be called again. */ + f->close = NULL; + a->client_data = NULL; + /* Clear passphrase. */ + if (a->passphrase != NULL) { + memset(a->passphrase, 0, strlen(a->passphrase)); + free(a->passphrase); + a->passphrase = NULL; + } + return (ret); +} + +/* + * Open the archive using the current settings. + */ +int +archive_write_open(struct archive *_a, void *client_data, + archive_open_callback *opener, archive_write_callback *writer, + archive_close_callback *closer) +{ + struct archive_write *a = (struct archive_write *)_a; + struct archive_write_filter *client_filter; + int ret, r1; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_open"); + archive_clear_error(&a->archive); + + a->client_writer = writer; + a->client_opener = opener; + a->client_closer = closer; + a->client_data = client_data; + + client_filter = __archive_write_allocate_filter(_a); + client_filter->open = archive_write_client_open; + client_filter->write = archive_write_client_write; + client_filter->close = archive_write_client_close; + + ret = __archive_write_open_filter(a->filter_first); + if (ret < ARCHIVE_WARN) { + r1 = __archive_write_close_filter(a->filter_first); + return (r1 < ret ? r1 : ret); + } + + a->archive.state = ARCHIVE_STATE_HEADER; + if (a->format_init) + ret = (a->format_init)(a); + return (ret); +} + +/* + * Close out the archive. + */ +static int +_archive_write_close(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int r = ARCHIVE_OK, r1 = ARCHIVE_OK; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, + "archive_write_close"); + if (a->archive.state == ARCHIVE_STATE_NEW + || a->archive.state == ARCHIVE_STATE_CLOSED) + return (ARCHIVE_OK); /* Okay to close() when not open. */ + + archive_clear_error(&a->archive); + + /* Finish the last entry if a finish callback is specified */ + if (a->archive.state == ARCHIVE_STATE_DATA + && a->format_finish_entry != NULL) + r = ((a->format_finish_entry)(a)); + + /* Finish off the archive. */ + /* TODO: have format closers invoke compression close. */ + if (a->format_close != NULL) { + r1 = (a->format_close)(a); + if (r1 < r) + r = r1; + } + + /* Finish the compression and close the stream. */ + r1 = __archive_write_close_filter(a->filter_first); + if (r1 < r) + r = r1; + + if (a->archive.state != ARCHIVE_STATE_FATAL) + a->archive.state = ARCHIVE_STATE_CLOSED; + return (r); +} + +static int +_archive_write_filter_count(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct archive_write_filter *p = a->filter_first; + int count = 0; + while(p) { + count++; + p = p->next_filter; + } + return count; +} + +void +__archive_write_filters_free(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int r = ARCHIVE_OK, r1; + + while (a->filter_first != NULL) { + struct archive_write_filter *next + = a->filter_first->next_filter; + if (a->filter_first->free != NULL) { + r1 = (*a->filter_first->free)(a->filter_first); + if (r > r1) + r = r1; + } + free(a->filter_first); + a->filter_first = next; + } + a->filter_last = NULL; +} + +/* + * Destroy the archive structure. + * + * Be careful: user might just call write_new and then write_free. + * Don't assume we actually wrote anything or performed any non-trivial + * initialization. + */ +static int +_archive_write_free(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int r = ARCHIVE_OK, r1; + + if (_a == NULL) + return (ARCHIVE_OK); + /* It is okay to call free() in state FATAL. */ + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_free"); + if (a->archive.state != ARCHIVE_STATE_FATAL) + r = archive_write_close(&a->archive); + + /* Release format resources. */ + if (a->format_free != NULL) { + r1 = (a->format_free)(a); + if (r1 < r) + r = r1; + } + + __archive_write_filters_free(_a); + + /* Release various dynamic buffers. */ + free((void *)(uintptr_t)(const void *)a->nulls); + archive_string_free(&a->archive.error_string); + if (a->passphrase != NULL) { + /* A passphrase should be cleaned. */ + memset(a->passphrase, 0, strlen(a->passphrase)); + free(a->passphrase); + } + a->archive.magic = 0; + __archive_clean(&a->archive); + free(a); + return (r); +} + +/* + * Write the appropriate header. + */ +static int +_archive_write_header(struct archive *_a, struct archive_entry *entry) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret, r2; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header"); + archive_clear_error(&a->archive); + + if (a->format_write_header == NULL) { + archive_set_error(&(a->archive), -1, + "Format must be set before you can write to an archive."); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + + /* In particular, "retry" and "fatal" get returned immediately. */ + ret = archive_write_finish_entry(&a->archive); + if (ret == ARCHIVE_FATAL) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN) + return (ret); + + if (a->skip_file_set && + archive_entry_dev_is_set(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, + "Can't add archive to itself"); + return (ARCHIVE_FAILED); + } + + /* Format and write header. */ + r2 = ((a->format_write_header)(a, entry)); + if (r2 == ARCHIVE_FAILED) { + return (ARCHIVE_FAILED); + } + if (r2 == ARCHIVE_FATAL) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + if (r2 < ret) + ret = r2; + + a->archive.state = ARCHIVE_STATE_DATA; + return (ret); +} + +static int +_archive_write_finish_entry(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret = ARCHIVE_OK; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_finish_entry"); + if (a->archive.state & ARCHIVE_STATE_DATA + && a->format_finish_entry != NULL) + ret = (a->format_finish_entry)(a); + a->archive.state = ARCHIVE_STATE_HEADER; + return (ret); +} + +/* + * Note that the compressor is responsible for blocking. + */ +static ssize_t +_archive_write_data(struct archive *_a, const void *buff, size_t s) +{ + struct archive_write *a = (struct archive_write *)_a; + const size_t max_write = INT_MAX; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data"); + /* In particular, this catches attempts to pass negative values. */ + if (s > max_write) + s = max_write; + archive_clear_error(&a->archive); + return ((a->format_write_data)(a, buff, s)); +} + +static struct archive_write_filter * +filter_lookup(struct archive *_a, int n) +{ + struct archive_write *a = (struct archive_write *)_a; + struct archive_write_filter *f = a->filter_first; + if (n == -1) + return a->filter_last; + if (n < 0) + return NULL; + while (n > 0 && f != NULL) { + f = f->next_filter; + --n; + } + return f; +} + +static int +_archive_filter_code(struct archive *_a, int n) +{ + struct archive_write_filter *f = filter_lookup(_a, n); + return f == NULL ? -1 : f->code; +} + +static const char * +_archive_filter_name(struct archive *_a, int n) +{ + struct archive_write_filter *f = filter_lookup(_a, n); + return f != NULL ? f->name : NULL; +} + +static int64_t +_archive_filter_bytes(struct archive *_a, int n) +{ + struct archive_write_filter *f = filter_lookup(_a, n); + return f == NULL ? -1 : f->bytes_written; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter.c new file mode 100644 index 00000000..08f518ad --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter.c @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2012 Ondrej Holy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" + +/* A table that maps filter codes to functions. */ +static const +struct { int code; int (*setter)(struct archive *); } codes[] = +{ + { ARCHIVE_FILTER_NONE, archive_write_add_filter_none }, + { ARCHIVE_FILTER_GZIP, archive_write_add_filter_gzip }, + { ARCHIVE_FILTER_BZIP2, archive_write_add_filter_bzip2 }, + { ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress }, + { ARCHIVE_FILTER_GRZIP, archive_write_add_filter_grzip }, + { ARCHIVE_FILTER_LRZIP, archive_write_add_filter_lrzip }, + { ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 }, + { ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip }, + { ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma }, + { ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip }, + { ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode }, + { ARCHIVE_FILTER_XZ, archive_write_add_filter_xz }, + { -1, NULL } +}; + +int +archive_write_add_filter(struct archive *a, int code) +{ + int i; + + for (i = 0; codes[i].code != -1; i++) { + if (code == codes[i].code) + return ((codes[i].setter)(a)); + } + + archive_set_error(a, EINVAL, "No such filter"); + return (ARCHIVE_FATAL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c new file mode 100644 index 00000000..85eb087b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_b64encode.c @@ -0,0 +1,314 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" +#include "archive_write_private.h" + +#define LBYTES 57 + +struct private_b64encode { + int mode; + struct archive_string name; + struct archive_string encoded_buff; + size_t bs; + size_t hold_len; + unsigned char hold[LBYTES]; +}; + +static int archive_filter_b64encode_options(struct archive_write_filter *, + const char *, const char *); +static int archive_filter_b64encode_open(struct archive_write_filter *); +static int archive_filter_b64encode_write(struct archive_write_filter *, + const void *, size_t); +static int archive_filter_b64encode_close(struct archive_write_filter *); +static int archive_filter_b64encode_free(struct archive_write_filter *); +static void b64_encode(struct archive_string *, const unsigned char *, size_t); +static int64_t atol8(const char *, size_t); + +static const char base64[] = { + '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', '+', '/' +}; + +/* + * Add a compress filter to this write handle. + */ +int +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; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_add_filter_uu"); + + state = (struct private_b64encode *)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; + + f->data = state; + f->name = "b64encode"; + f->code = ARCHIVE_FILTER_UU; + f->open = archive_filter_b64encode_open; + f->options = archive_filter_b64encode_options; + f->write = archive_filter_b64encode_write; + f->close = archive_filter_b64encode_close; + f->free = archive_filter_b64encode_free; + + return (ARCHIVE_OK); +} + +/* + * Set write options. + */ +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; + + if (strcmp(key, "mode") == 0) { + if (value == NULL) { + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "mode option requires octal digits"); + return (ARCHIVE_FAILED); + } + state->mode = (int)atol8(value, strlen(value)) & 0777; + return (ARCHIVE_OK); + } else if (strcmp(key, "name") == 0) { + if (value == NULL) { + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "name option requires a string"); + return (ARCHIVE_FAILED); + } + archive_strcpy(&state->name, value); + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +/* + * Setup callback. + */ +static int +archive_filter_b64encode_open(struct archive_write_filter *f) +{ + struct private_b64encode *state = (struct private_b64encode *)f->data; + size_t bs = 65536, bpb; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != ARCHIVE_OK) + return (ret); + + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + + state->bs = bs; + if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for b64encode buffer"); + return (ARCHIVE_FATAL); + } + + archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n", + state->mode, state->name.s); + + f->data = state; + return (0); +} + +static void +b64_encode(struct archive_string *as, const unsigned char *p, size_t len) +{ + int c; + + for (; len >= 3; p += 3, len -= 3) { + c = p[0] >> 2; + archive_strappend_char(as, base64[c]); + c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4); + archive_strappend_char(as, base64[c]); + c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6); + archive_strappend_char(as, base64[c]); + c = p[2] & 0x3f; + archive_strappend_char(as, base64[c]); + } + if (len > 0) { + c = p[0] >> 2; + archive_strappend_char(as, base64[c]); + c = (p[0] & 0x03) << 4; + if (len == 1) { + archive_strappend_char(as, base64[c]); + archive_strappend_char(as, '='); + archive_strappend_char(as, '='); + } else { + c |= (p[1] & 0xf0) >> 4; + archive_strappend_char(as, base64[c]); + c = (p[1] & 0x0f) << 2; + archive_strappend_char(as, base64[c]); + archive_strappend_char(as, '='); + } + } + archive_strappend_char(as, '\n'); +} + +/* + * Write data to the encoded stream. + */ +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; + const unsigned char *p = buff; + int ret = ARCHIVE_OK; + + if (length == 0) + return (ret); + + if (state->hold_len) { + while (state->hold_len < LBYTES && length > 0) { + state->hold[state->hold_len++] = *p++; + length--; + } + if (state->hold_len < LBYTES) + return (ret); + b64_encode(&state->encoded_buff, state->hold, LBYTES); + state->hold_len = 0; + } + + for (; length >= LBYTES; length -= LBYTES, p += LBYTES) + b64_encode(&state->encoded_buff, p, LBYTES); + + /* Save remaining bytes. */ + if (length > 0) { + memcpy(state->hold, p, length); + state->hold_len = length; + } + while (archive_strlen(&state->encoded_buff) >= state->bs) { + ret = __archive_write_filter(f->next_filter, + state->encoded_buff.s, state->bs); + memmove(state->encoded_buff.s, + state->encoded_buff.s + state->bs, + state->encoded_buff.length - state->bs); + state->encoded_buff.length -= state->bs; + } + + return (ret); +} + + +/* + * Finish the compression... + */ +static int +archive_filter_b64encode_close(struct archive_write_filter *f) +{ + struct private_b64encode *state = (struct private_b64encode *)f->data; + int ret, ret2; + + /* Flush remaining bytes. */ + if (state->hold_len != 0) + b64_encode(&state->encoded_buff, state->hold, state->hold_len); + archive_string_sprintf(&state->encoded_buff, "====\n"); + /* Write the last block */ + archive_write_set_bytes_in_last_block(f->archive, 1); + ret = __archive_write_filter(f->next_filter, + state->encoded_buff.s, archive_strlen(&state->encoded_buff)); + ret2 = __archive_write_close_filter(f->next_filter); + if (ret > ret2) + ret = ret2; + return (ret); +} + +static int +archive_filter_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); + return (ARCHIVE_OK); +} + +static int64_t +atol8(const char *p, size_t char_cnt) +{ + int64_t l; + int digit; + + l = 0; + while (char_cnt-- > 0) { + if (*p >= '0' && *p <= '7') + digit = *p - '0'; + else + break; + p++; + l <<= 3; + l |= digit; + } + return (l); +} + diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c new file mode 100644 index 00000000..85a8d475 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" + +/* A table that maps names to functions. */ +static const +struct { const char *name; int (*setter)(struct archive *); } names[] = +{ + { "b64encode", archive_write_add_filter_b64encode }, + { "bzip2", archive_write_add_filter_bzip2 }, + { "compress", archive_write_add_filter_compress }, + { "grzip", archive_write_add_filter_grzip }, + { "gzip", archive_write_add_filter_gzip }, + { "lrzip", archive_write_add_filter_lrzip }, + { "lz4", archive_write_add_filter_lz4 }, + { "lzip", archive_write_add_filter_lzip }, + { "lzma", archive_write_add_filter_lzma }, + { "lzop", archive_write_add_filter_lzop }, + { "uuencode", archive_write_add_filter_uuencode }, + { "xz", archive_write_add_filter_xz }, + { NULL, NULL } +}; + +int +archive_write_add_filter_by_name(struct archive *a, const char *name) +{ + int i; + + for (i = 0; names[i].name != NULL; i++) { + if (strcmp(name, names[i].name) == 0) + return ((names[i].setter)(a)); + } + + archive_set_error(a, EINVAL, "No such filter '%s'", name); + a->state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c new file mode 100644 index 00000000..68ed9579 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c @@ -0,0 +1,407 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_write_private.h" + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_write_set_compression_bzip2(struct archive *a) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_bzip2(a)); +} +#endif + +struct private_data { + 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 + struct archive_write_program_data *pdata; +#endif +}; + +static int archive_compressor_bzip2_close(struct archive_write_filter *); +static int archive_compressor_bzip2_free(struct archive_write_filter *); +static int archive_compressor_bzip2_open(struct archive_write_filter *); +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); + +/* + * Add a bzip2 compression filter to this write handle. + */ +int +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; + + archive_check_magic(&a->archive, 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"; +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) + return (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, + "Using external bzip2 program"); + return (ARCHIVE_WARN); +#endif +} + +/* + * Set write options. + */ +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; + + if (strcmp(key, "compression-level") == 0) { + if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || + value[1] != '\0') + return (ARCHIVE_WARN); + data->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; + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) +/* Don't compile this if we don't have bzlib. */ + +/* + * Yuck. bzlib.h is not const-correct, so I need this one bit + * of ugly hackery to convert a const * pointer to a non-const pointer. + */ +#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); + +/* + * Setup callback. + */ +static int +archive_compressor_bzip2_open(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != 0) + return (ret); + + if (data->compressed == NULL) { + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; + data->compressed + = (char *)malloc(data->compressed_buffer_size); + if (data->compressed == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + } + + memset(&data->stream, 0, sizeof(data->stream)); + data->stream.next_out = data->compressed; + data->stream.avail_out = data->compressed_buffer_size; + f->write = archive_compressor_bzip2_write; + + /* Initialize compression library */ + ret = BZ2_bzCompressInit(&(data->stream), + data->compression_level, 0, 30); + if (ret == BZ_OK) { + f->data = data; + return (ARCHIVE_OK); + } + + /* Library setup failed: clean up. */ + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library"); + + /* Override the error message if we know what really went wrong. */ + switch (ret) { + case BZ_PARAM_ERROR: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + "invalid setup parameter"); + break; + case BZ_MEM_ERROR: + archive_set_error(f->archive, ENOMEM, + "Internal error initializing compression library: " + "out of memory"); + break; + case BZ_CONFIG_ERROR: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + "mis-compiled library"); + break; + } + + return (ARCHIVE_FATAL); + +} + +/* + * Write data to the compressed stream. + * + * Returns ARCHIVE_OK if all data written, error otherwise. + */ +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; + + /* Compress input data to output buffer */ + SET_NEXT_IN(data, buff); + data->stream.avail_in = length; + if (drive_compressor(f, data, 0)) + return (ARCHIVE_FATAL); + return (ARCHIVE_OK); +} + + +/* + * Finish the compression. + */ +static int +archive_compressor_bzip2_close(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + int ret, r1; + + /* Finish compression cycle. */ + ret = drive_compressor(f, data, 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); + } + + switch (BZ2_bzCompressEnd(&(data->stream))) { + case BZ_OK: + break; + default: + archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; + } + + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); +} + +static int +archive_compressor_bzip2_free(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + 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. + * + * Note that this handles both the regular write case (finishing == + * false) and the end-of-archive case (finishing == true). + */ +static int +drive_compressor(struct archive_write_filter *f, + struct private_data *data, int finishing) +{ + int ret; + + for (;;) { + if (data->stream.avail_out == 0) { + ret = __archive_write_filter(f->next_filter, + data->compressed, + data->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 = data->compressed_buffer_size; + } + + /* If there's nothing to do, we're done. */ + if (!finishing && data->stream.avail_in == 0) + return (ARCHIVE_OK); + + ret = BZ2_bzCompress(&(data->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) + return (ARCHIVE_OK); + break; + case BZ_FINISH_OK: /* Finishing: There's more work to do */ + break; + case BZ_STREAM_END: /* Finishing: all done */ + /* Only occurs in finishing case */ + return (ARCHIVE_OK); + default: + /* Any other return value indicates an error */ + archive_set_error(f->archive, + ARCHIVE_ERRNO_PROGRAMMER, + "Bzip2 compression failed;" + " BZ2_bzCompress() returned %d", + ret); + return (ARCHIVE_FATAL); + } + } +} + +#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 archive_string as; + int r; + + archive_string_init(&as); + archive_strcpy(&as, "bzip2"); + + /* Specify compression level. */ + if (data->compression_level > 0) { + archive_strcat(&as, " -"); + archive_strappend_char(&as, '0' + data->compression_level); + } + f->write = archive_compressor_bzip2_write; + + r = __archive_write_program_open(f, data->pdata, as.s); + archive_string_free(&as); + return (r); +} + +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; + + return __archive_write_program_write(f, data->pdata, buff, length); +} + +static int +archive_compressor_bzip2_close(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + + return __archive_write_program_close(f, data->pdata); +} + +static int +archive_compressor_bzip2_free(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + + __archive_write_program_free(data->pdata); + free(data); + return (ARCHIVE_OK); +} + +#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */ diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c new file mode 100644 index 00000000..04eb06c1 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c @@ -0,0 +1,442 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_ZLIB_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" +#include "archive_write_private.h" + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_write_set_compression_gzip(struct archive *a) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_gzip(a)); +} +#endif + +/* Don't compile this if we don't have zlib. */ + +struct private_data { + int compression_level; + int timestamp; +#ifdef HAVE_ZLIB_H + z_stream stream; + int64_t total_in; + unsigned char *compressed; + size_t compressed_buffer_size; + unsigned long crc; +#else + struct archive_write_program_data *pdata; +#endif +}; + +/* + * Yuck. zlib.h is not const-correct, so I need this one bit + * of ugly hackery to convert a const * pointer to a non-const pointer. + */ +#define SET_NEXT_IN(st,src) \ + (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src) + +static int archive_compressor_gzip_options(struct archive_write_filter *, + const char *, const char *); +static int archive_compressor_gzip_open(struct archive_write_filter *); +static int archive_compressor_gzip_write(struct archive_write_filter *, + const void *, size_t); +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); +#endif + + +/* + * Add a gzip compression filter to this write handle. + */ +int +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"); + + 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"; +#ifdef HAVE_ZLIB_H + data->compression_level = Z_DEFAULT_COMPRESSION; + return (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, + "Using external gzip program"); + return (ARCHIVE_WARN); +#endif +} + +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(data); + f->data = NULL; + return (ARCHIVE_OK); +} + +/* + * Set write options. + */ +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; + + if (strcmp(key, "compression-level") == 0) { + if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || + value[1] != '\0') + return (ARCHIVE_WARN); + data->compression_level = value[0] - '0'; + return (ARCHIVE_OK); + } + if (strcmp(key, "timestamp") == 0) { + data->timestamp = (value == NULL)?-1:1; + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +#ifdef HAVE_ZLIB_H +/* + * Setup callback. + */ +static int +archive_compressor_gzip_open(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != ARCHIVE_OK) + return (ret); + + if (data->compressed == NULL) { + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of + * the of bytes per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; + data->compressed + = (unsigned char *)malloc(data->compressed_buffer_size); + if (data->compressed == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + } + + data->crc = crc32(0L, NULL, 0); + data->stream.next_out = data->compressed; + data->stream.avail_out = (uInt)data->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] = 0; /* No options */ + 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; + } else + memset(&data->compressed[4], 0, 4); + data->compressed[8] = 0; /* No deflate options */ + data->compressed[9] = 3; /* OS=Unix */ + data->stream.next_out += 10; + data->stream.avail_out -= 10; + + f->write = archive_compressor_gzip_write; + + /* Initialize compression library. */ + ret = deflateInit2(&(data->stream), + data->compression_level, + Z_DEFLATED, + -15 /* < 0 to suppress zlib header */, + 8, + Z_DEFAULT_STRATEGY); + + if (ret == Z_OK) { + f->data = data; + return (ARCHIVE_OK); + } + + /* Library setup failed: clean up. */ + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error " + "initializing compression library"); + + /* Override the error message if we know what really went wrong. */ + switch (ret) { + case Z_STREAM_ERROR: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing " + "compression library: invalid setup parameter"); + break; + case Z_MEM_ERROR: + archive_set_error(f->archive, ENOMEM, + "Internal error initializing compression library"); + break; + case Z_VERSION_ERROR: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing " + "compression library: invalid library version"); + break; + } + + return (ARCHIVE_FATAL); +} + +/* + * Write data to the compressed stream. + */ +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; + int ret; + + /* Update statistics */ + data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length); + data->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) + return (ret); + + return (ARCHIVE_OK); +} + +/* + * Finish the compression... + */ +static int +archive_compressor_gzip_close(struct archive_write_filter *f) +{ + unsigned char trailer[8]; + struct private_data *data = (struct private_data *)f->data; + int ret, r1; + + /* Finish compression cycle */ + ret = drive_compressor(f, data, 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); + } + 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; + ret = __archive_write_filter(f->next_filter, trailer, 8); + } + + switch (deflateEnd(&(data->stream))) { + case Z_OK: + break; + default: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; + } + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); +} + +/* + * Utility function to push input data through compressor, + * writing full output blocks as necessary. + * + * Note that this handles both the regular write case (finishing == + * false) and the end-of-archive case (finishing == true). + */ +static int +drive_compressor(struct archive_write_filter *f, + struct private_data *data, int finishing) +{ + int ret; + + for (;;) { + if (data->stream.avail_out == 0) { + ret = __archive_write_filter(f->next_filter, + data->compressed, + data->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; + } + + /* If there's nothing to do, we're done. */ + if (!finishing && data->stream.avail_in == 0) + return (ARCHIVE_OK); + + ret = deflate(&(data->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) + return (ARCHIVE_OK); + /* In finishing case, this return always means + * there's more work */ + break; + case Z_STREAM_END: + /* This return can only occur in finishing case. */ + return (ARCHIVE_OK); + default: + /* Any other return value indicates an error. */ + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "GZip compression failed:" + " deflate() call returned status %d", + ret); + return (ARCHIVE_FATAL); + } + } +} + +#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 archive_string as; + int r; + + archive_string_init(&as); + archive_strcpy(&as, "gzip"); + + /* Specify compression level. */ + if (data->compression_level > 0) { + archive_strcat(&as, " -"); + archive_strappend_char(&as, '0' + data->compression_level); + } + if (data->timestamp < 0) + /* Do not save timestamp. */ + archive_strcat(&as, " -n"); + else if (data->timestamp > 0) + /* Save timestamp. */ + archive_strcat(&as, " -N"); + + f->write = archive_compressor_gzip_write; + r = __archive_write_program_open(f, data->pdata, as.s); + archive_string_free(&as); + return (r); +} + +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; + + return __archive_write_program_write(f, data->pdata, buff, length); +} + +static int +archive_compressor_gzip_close(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + + return __archive_write_program_close(f, data->pdata); +} + +#endif /* HAVE_ZLIB_H */ diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c new file mode 100644 index 00000000..3c06c642 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_none.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_none.c 201080 2009-12-28 02:03:54Z kientzle $"); + +#include "archive.h" + +int +archive_write_set_compression_none(struct archive *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} + +int +archive_write_add_filter_none(struct archive *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c new file mode 100644 index 00000000..660f693f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c @@ -0,0 +1,415 @@ +/*- + * Copyright (c) 2007 Joerg Sonnenberger + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $"); + +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" +#include "archive_write_private.h" +#include "filter_fork.h" + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_write_set_compression_program(struct archive *a, const char *cmd) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_program(a, cmd)); +} +#endif + +struct archive_write_program_data { +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE child; +#else + pid_t child; +#endif + int child_stdin, child_stdout; + + char *child_buf; + size_t child_buf_len, child_buf_avail; + char *program_name; +}; + +struct private_data { + struct archive_write_program_data *pdata; + struct archive_string description; + char *cmd; +}; + +static int archive_compressor_program_open(struct archive_write_filter *); +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 *); + +/* + * 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) +{ + struct archive_write_filter *f = __archive_write_allocate_filter(_a); + struct private_data *data; + static const char prefix[] = "Program: "; + + 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) + goto memerr; + data = (struct private_data *)f->data; + + data->cmd = strdup(cmd); + if (data->cmd == NULL) + goto memerr; + + data->pdata = __archive_write_program_allocate(cmd); + if (data->pdata == NULL) + goto memerr; + + /* Make up a description string. */ + if (archive_string_ensure(&data->description, + strlen(prefix) + strlen(cmd) + 1) == NULL) + goto memerr; + archive_strcpy(&data->description, prefix); + archive_strcat(&data->description, cmd); + + f->name = data->description.s; + f->code = ARCHIVE_FILTER_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, + "Can't allocate memory for filter program"); + return (ARCHIVE_FATAL); +} + +static int +archive_compressor_program_open(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + + return __archive_write_program_open(f, data->pdata, data->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; + + return __archive_write_program_write(f, data->pdata, buff, length); +} + +static int +archive_compressor_program_close(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + + return __archive_write_program_close(f, data->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; + } + return (ARCHIVE_OK); +} + +/* + * Allocate resources for executing an external program. + */ +struct archive_write_program_data * +__archive_write_program_allocate(const char *program) +{ + struct archive_write_program_data *data; + + data = calloc(1, sizeof(struct archive_write_program_data)); + if (data == NULL) + return (data); + data->child_stdin = -1; + data->child_stdout = -1; + data->program_name = strdup(program); + return (data); +} + +/* + * Release the resources. + */ +int +__archive_write_program_free(struct archive_write_program_data *data) +{ + + if (data) { +#if defined(_WIN32) && !defined(__CYGWIN__) + if (data->child) + CloseHandle(data->child); +#endif + free(data->program_name); + free(data->child_buf); + free(data); + } + return (ARCHIVE_OK); +} + +int +__archive_write_program_open(struct archive_write_filter *f, + struct archive_write_program_data *data, const char *cmd) +{ + pid_t child; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != ARCHIVE_OK) + return (ret); + + if (data->child_buf == NULL) { + data->child_buf_len = 65536; + data->child_buf_avail = 0; + data->child_buf = malloc(data->child_buf_len); + + if (data->child_buf == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate compression buffer"); + return (ARCHIVE_FATAL); + } + } + + child = __archive_create_child(cmd, &data->child_stdin, + &data->child_stdout); + if (child == -1) { + archive_set_error(f->archive, EINVAL, + "Can't launch external program: %s", cmd); + return (ARCHIVE_FATAL); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child); + if (data->child == NULL) { + close(data->child_stdin); + data->child_stdin = -1; + close(data->child_stdout); + data->child_stdout = -1; + archive_set_error(f->archive, EINVAL, + "Can't launch external program: %s", cmd); + return (ARCHIVE_FATAL); + } +#else + data->child = child; +#endif + return (ARCHIVE_OK); +} + +static ssize_t +child_write(struct archive_write_filter *f, + struct archive_write_program_data *data, const char *buf, size_t buf_len) +{ + ssize_t ret; + + if (data->child_stdin == -1) + return (-1); + + if (buf_len == 0) + return (-1); + + for (;;) { + do { + ret = write(data->child_stdin, buf, buf_len); + } while (ret == -1 && errno == EINTR); + + if (ret > 0) + return (ret); + if (ret == 0) { + close(data->child_stdin); + data->child_stdin = -1; + fcntl(data->child_stdout, F_SETFL, 0); + return (0); + } + if (ret == -1 && errno != EAGAIN) + return (-1); + + if (data->child_stdout == -1) { + fcntl(data->child_stdin, F_SETFL, 0); + __archive_check_child(data->child_stdin, + data->child_stdout); + continue; + } + + do { + ret = read(data->child_stdout, + data->child_buf + data->child_buf_avail, + data->child_buf_len - data->child_buf_avail); + } while (ret == -1 && errno == EINTR); + + if (ret == 0 || (ret == -1 && errno == EPIPE)) { + close(data->child_stdout); + data->child_stdout = -1; + fcntl(data->child_stdin, F_SETFL, 0); + continue; + } + if (ret == -1 && errno == EAGAIN) { + __archive_check_child(data->child_stdin, + data->child_stdout); + continue; + } + if (ret == -1) + return (-1); + + data->child_buf_avail += ret; + + ret = __archive_write_filter(f->next_filter, + data->child_buf, data->child_buf_avail); + if (ret != ARCHIVE_OK) + return (-1); + data->child_buf_avail = 0; + } +} + +/* + * Write data to the filter stream. + */ +int +__archive_write_program_write(struct archive_write_filter *f, + struct archive_write_program_data *data, const void *buff, size_t length) +{ + ssize_t ret; + const char *buf; + + if (data->child == 0) + return (ARCHIVE_OK); + + buf = buff; + while (length > 0) { + ret = child_write(f, data, buf, length); + if (ret == -1 || ret == 0) { + archive_set_error(f->archive, EIO, + "Can't write to program: %s", data->program_name); + return (ARCHIVE_FATAL); + } + length -= ret; + buf += ret; + } + return (ARCHIVE_OK); +} + +/* + * Finish the filtering... + */ +int +__archive_write_program_close(struct archive_write_filter *f, + struct archive_write_program_data *data) +{ + int ret, r1, status; + ssize_t bytes_read; + + if (data->child == 0) + return __archive_write_close_filter(f->next_filter); + + ret = 0; + close(data->child_stdin); + data->child_stdin = -1; + fcntl(data->child_stdout, F_SETFL, 0); + + for (;;) { + do { + bytes_read = read(data->child_stdout, + data->child_buf + data->child_buf_avail, + data->child_buf_len - data->child_buf_avail); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE)) + break; + + if (bytes_read == -1) { + archive_set_error(f->archive, errno, + "Error reading from program: %s", data->program_name); + ret = ARCHIVE_FATAL; + goto cleanup; + } + data->child_buf_avail += bytes_read; + + ret = __archive_write_filter(f->next_filter, + data->child_buf, data->child_buf_avail); + if (ret != ARCHIVE_OK) { + ret = ARCHIVE_FATAL; + goto cleanup; + } + data->child_buf_avail = 0; + } + +cleanup: + /* Shut down the child. */ + if (data->child_stdin != -1) + close(data->child_stdin); + if (data->child_stdout != -1) + close(data->child_stdout); + while (waitpid(data->child, &status, 0) == -1 && errno == EINTR) + continue; +#if defined(_WIN32) && !defined(__CYGWIN__) + CloseHandle(data->child); +#endif + data->child = 0; + + if (status != 0) { + archive_set_error(f->archive, EIO, + "Error closing program: %s", data->program_name); + ret = ARCHIVE_FATAL; + } + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); +} + diff --git a/src/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c new file mode 100644 index 00000000..b0f25a6e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c @@ -0,0 +1,547 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * Copyright (c) 2009-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_LZMA_H +#include +#endif + +#include "archive.h" +#include "archive_endian.h" +#include "archive_private.h" +#include "archive_write_private.h" + +#if ARCHIVE_VERSION_NUMBER < 4000000 +int +archive_write_set_compression_lzip(struct archive *a) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_lzip(a)); +} + +int +archive_write_set_compression_lzma(struct archive *a) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_lzma(a)); +} + +int +archive_write_set_compression_xz(struct archive *a) +{ + __archive_write_filters_free(a); + return (archive_write_add_filter_xz(a)); +} + +#endif + +#ifndef HAVE_LZMA_H +int +archive_write_add_filter_xz(struct archive *a) +{ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "xz compression not supported on this platform"); + return (ARCHIVE_FATAL); +} + +int +archive_write_add_filter_lzma(struct archive *a) +{ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "lzma compression not supported on this platform"); + return (ARCHIVE_FATAL); +} + +int +archive_write_add_filter_lzip(struct archive *a) +{ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "lzma compression not supported on this platform"); + return (ARCHIVE_FATAL); +} +#else +/* Don't compile this if we don't have liblzma. */ + +struct private_data { + int compression_level; + uint32_t threads; + lzma_stream stream; + lzma_filter lzmafilters[2]; + lzma_options_lzma lzma_opt; + int64_t total_in; + unsigned char *compressed; + size_t compressed_buffer_size; + int64_t total_out; + /* the CRC32 value of uncompressed data for lzip */ + uint32_t crc32; +}; + +static int archive_compressor_xz_options(struct archive_write_filter *, + const char *, const char *); +static int archive_compressor_xz_open(struct archive_write_filter *); +static int archive_compressor_xz_write(struct archive_write_filter *, + const void *, size_t); +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 option_value { + uint32_t dict_size; + uint32_t nice_len; + lzma_match_finder mf; +}; +static const struct option_value option_values[] = { + { 1 << 16, 32, LZMA_MF_HC3}, + { 1 << 20, 32, LZMA_MF_HC3}, + { 3 << 19, 32, LZMA_MF_HC4}, + { 1 << 21, 32, LZMA_MF_BT4}, + { 3 << 20, 32, LZMA_MF_BT4}, + { 1 << 22, 32, LZMA_MF_BT4}, + { 1 << 23, 64, LZMA_MF_BT4}, + { 1 << 24, 64, LZMA_MF_BT4}, + { 3 << 23, 64, LZMA_MF_BT4}, + { 1 << 25, 64, LZMA_MF_BT4} +}; + +static int +common_setup(struct archive_write_filter *f) +{ + 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; + f->close = archive_compressor_xz_close; + f->free = archive_compressor_xz_free; + f->options = &archive_compressor_xz_options; + return (ARCHIVE_OK); +} + +/* + * Add an xz compression filter to this write handle. + */ +int +archive_write_add_filter_xz(struct archive *_a) +{ + struct archive_write_filter *f; + int r; + + 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); +} + +/* 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) +{ + struct archive_write_filter *f; + int r; + + 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); +} + +int +archive_write_add_filter_lzip(struct archive *_a) +{ + struct archive_write_filter *f; + int r; + + 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); +} + +static int +archive_compressor_xz_init_stream(struct archive_write_filter *f, + struct private_data *data) +{ + static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT; + int ret; +#ifdef HAVE_LZMA_STREAM_ENCODER_MT + lzma_mt mt_options; +#endif + + data->stream = lzma_stream_init_data; + data->stream.next_out = data->compressed; + data->stream.avail_out = data->compressed_buffer_size; + if (f->code == ARCHIVE_FILTER_XZ) { +#ifdef HAVE_LZMA_STREAM_ENCODER_MT + if (data->threads != 1) { + memset(&mt_options, 0, sizeof(mt_options)); + mt_options.threads = data->threads; + mt_options.timeout = 300; + mt_options.filters = data->lzmafilters; + mt_options.check = LZMA_CHECK_CRC64; + ret = lzma_stream_encoder_mt(&(data->stream), + &mt_options); + } else +#endif + ret = lzma_stream_encoder(&(data->stream), + data->lzmafilters, LZMA_CHECK_CRC64); + } else if (f->code == ARCHIVE_FILTER_LZMA) { + ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt); + } else { /* ARCHIVE_FILTER_LZIP */ + int dict_size = data->lzma_opt.dict_size; + int ds, log2dic, wedges; + + /* Calculate a coded dictionary size */ + if (dict_size < (1 << 12) || dict_size > (1 << 27)) { + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Unacceptable dictionary size for lzip: %d", + dict_size); + return (ARCHIVE_FATAL); + } + for (log2dic = 27; log2dic >= 12; log2dic--) { + if (dict_size & (1 << log2dic)) + break; + } + if (dict_size > (1 << log2dic)) { + log2dic++; + wedges = + ((1 << log2dic) - dict_size) / (1 << (log2dic - 4)); + } else + wedges = 0; + ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f); + + data->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; + + ret = lzma_raw_encoder(&(data->stream), data->lzmafilters); + } + if (ret == LZMA_OK) + return (ARCHIVE_OK); + + switch (ret) { + case LZMA_MEM_ERROR: + archive_set_error(f->archive, ENOMEM, + "Internal error initializing compression library: " + "Cannot allocate memory"); + break; + default: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + "It's a bug in liblzma"); + break; + } + return (ARCHIVE_FATAL); +} + +/* + * Setup callback. + */ +static int +archive_compressor_xz_open(struct archive_write_filter *f) +{ + struct private_data *data = f->data; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != ARCHIVE_OK) + return (ret); + + if (data->compressed == NULL) { + size_t bs = 65536, bpb; + if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { + /* Buffer size should be a multiple number of the of bytes + * per block for performance. */ + bpb = archive_write_get_bytes_per_block(f->archive); + if (bpb > bs) + bs = bpb; + else if (bpb != 0) + bs -= bs % bpb; + } + data->compressed_buffer_size = bs; + data->compressed + = (unsigned char *)malloc(data->compressed_buffer_size); + if (data->compressed == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + } + + 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]; + + 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 */ + } else { + if (lzma_lzma_preset(&data->lzma_opt, data->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 */ + } + ret = archive_compressor_xz_init_stream(f, data); + if (ret == LZMA_OK) { + f->data = data; + return (0); + } + return (ARCHIVE_FATAL); +} + +/* + * Set write options. + */ +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; + + if (strcmp(key, "compression-level") == 0) { + if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || + value[1] != '\0') + return (ARCHIVE_WARN); + data->compression_level = value[0] - '0'; + if (data->compression_level > 6) + data->compression_level = 6; + return (ARCHIVE_OK); + } else if (strcmp(key, "threads") == 0) { + if (value == NULL) + return (ARCHIVE_WARN); + data->threads = (int)strtoul(value, NULL, 10); + if (data->threads == 0 && errno != 0) { + data->threads = 1; + return (ARCHIVE_WARN); + } + if (data->threads == 0) { +#ifdef HAVE_LZMA_STREAM_ENCODER_MT + data->threads = lzma_cputhreads(); +#else + data->threads = 1; +#endif + } + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +/* + * Write data to the compressed stream. + */ +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; + int ret; + + /* Update statistics */ + data->total_in += length; + if (f->code == ARCHIVE_FILTER_LZIP) + data->crc32 = lzma_crc32(buff, length, data->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) + return (ret); + + return (ARCHIVE_OK); +} + + +/* + * Finish the compression... + */ +static int +archive_compressor_xz_close(struct archive_write_filter *f) +{ + struct private_data *data = (struct private_data *)f->data; + int ret, r1; + + ret = drive_compressor(f, data, 1); + if (ret == ARCHIVE_OK) { + data->total_out += + data->compressed_buffer_size - data->stream.avail_out; + ret = __archive_write_filter(f->next_filter, + data->compressed, + data->compressed_buffer_size - data->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); + ret = __archive_write_filter(f->next_filter, + data->compressed, 20); + } + } + lzma_end(&(data->stream)); + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : 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); + f->data = NULL; + return (ARCHIVE_OK); +} + +/* + * Utility function to push input data through compressor, + * writing full output blocks as necessary. + * + * Note that this handles both the regular write case (finishing == + * false) and the end-of-archive case (finishing == true). + */ +static int +drive_compressor(struct archive_write_filter *f, + struct private_data *data, int finishing) +{ + int ret; + + for (;;) { + if (data->stream.avail_out == 0) { + data->total_out += data->compressed_buffer_size; + ret = __archive_write_filter(f->next_filter, + data->compressed, + data->compressed_buffer_size); + if (ret != ARCHIVE_OK) + return (ARCHIVE_FATAL); + data->stream.next_out = data->compressed; + data->stream.avail_out = data->compressed_buffer_size; + } + + /* If there's nothing to do, we're done. */ + if (!finishing && data->stream.avail_in == 0) + return (ARCHIVE_OK); + + ret = lzma_code(&(data->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) + return (ARCHIVE_OK); + /* In finishing case, this return always means + * there's more work */ + break; + case LZMA_STREAM_END: + /* This return can only occur in finishing case. */ + if (finishing) + return (ARCHIVE_OK); + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "lzma compression data error"); + return (ARCHIVE_FATAL); + case LZMA_MEMLIMIT_ERROR: + archive_set_error(f->archive, ENOMEM, + "lzma compression error: " + "%ju MiB would have been needed", + (uintmax_t)((lzma_memusage(&(data->stream)) + + 1024 * 1024 -1) + / (1024 * 1024))); + return (ARCHIVE_FATAL); + default: + /* Any other return value indicates an error. */ + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "lzma compression failed:" + " lzma_code() call returned status %d", + ret); + return (ARCHIVE_FATAL); + } + } +} + +#endif /* HAVE_LZMA_H */ diff --git a/src/3rdparty/libarchive/libarchive/archive_write_disk_posix.c b/src/3rdparty/libarchive/libarchive/archive_write_disk_posix.c new file mode 100644 index 00000000..6ad53992 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_disk_posix.c @@ -0,0 +1,4327 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#if !defined(_WIN32) || defined(__CYGWIN__) + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#include +#endif +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif +#if HAVE_SYS_XATTR_H +#include +#elif HAVE_ATTR_XATTR_H +#include +#endif +#ifdef HAVE_SYS_EA_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_UTIME_H +#include +#endif +#ifdef HAVE_COPYFILE_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_LANGINFO_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include /* for Linux file flags */ +#endif +/* + * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. + * As the include guards don't agree, the order of include is important. + */ +#ifdef HAVE_LINUX_EXT2_FS_H +#include /* for Linux file flags */ +#endif +#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) +#include /* Linux file flags, broken on Cygwin */ +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_UTIME_H +#include +#endif +#ifdef F_GETTIMES /* Tru64 specific */ +#include +#endif + +/* + * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared. + * + * It assumes that the input is an integer type of no more than 64 bits. + * If the number is less than zero, t must be a signed type, so it fits in + * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t + * without loss. But it could be a large unsigned value, so we have to clip it + * to INT64_MAX.* + */ +#define to_int64_time(t) \ + ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t)) + +#if __APPLE__ +#include +#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H +#include +#define HAVE_QUARANTINE 1 +#endif +#endif + +#ifdef HAVE_ZLIB_H +#include +#endif + +/* TODO: Support Mac OS 'quarantine' feature. This is really just a + * standard tag to mark files that have been downloaded as "tainted". + * On Mac OS, we should mark the extracted files as tainted if the + * archive being read was tainted. Windows has a similar feature; we + * should investigate ways to support this generically. */ + +#include "archive.h" +#include "archive_acl_private.h" +#include "archive_string.h" +#include "archive_endian.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_write_disk_private.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* Ignore non-int O_NOFOLLOW constant. */ +/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ +#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) +#undef O_NOFOLLOW +#endif + +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +struct fixup_entry { + struct fixup_entry *next; + struct archive_acl acl; + mode_t mode; + int64_t atime; + int64_t birthtime; + int64_t mtime; + int64_t ctime; + unsigned long atime_nanos; + unsigned long birthtime_nanos; + unsigned long mtime_nanos; + unsigned long ctime_nanos; + unsigned long fflags_set; + size_t mac_metadata_size; + void *mac_metadata; + int fixup; /* bitmask of what needs fixing */ + char *name; +}; + +/* + * We use a bitmask to track which operations remain to be done for + * this file. In particular, this helps us avoid unnecessary + * operations when it's possible to take care of one step as a + * side-effect of another. For example, mkdir() can specify the mode + * for the newly-created object but symlink() cannot. This means we + * can skip chmod() if mkdir() succeeded, but we must explicitly + * chmod() if we're trying to create a directory that already exists + * (mkdir() failed) or if we're restoring a symlink. Similarly, we + * need to verify UID/GID before trying to restore SUID/SGID bits; + * that verification can occur explicitly through a stat() call or + * implicitly because of a successful chown() call. + */ +#define TODO_MODE_FORCE 0x40000000 +#define TODO_MODE_BASE 0x20000000 +#define TODO_SUID 0x10000000 +#define TODO_SUID_CHECK 0x08000000 +#define TODO_SGID 0x04000000 +#define TODO_SGID_CHECK 0x02000000 +#define TODO_APPLEDOUBLE 0x01000000 +#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) +#define TODO_TIMES ARCHIVE_EXTRACT_TIME +#define TODO_OWNER ARCHIVE_EXTRACT_OWNER +#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS +#define TODO_ACLS ARCHIVE_EXTRACT_ACL +#define TODO_XATTR ARCHIVE_EXTRACT_XATTR +#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA +#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED + +struct archive_write_disk { + struct archive archive; + + mode_t user_umask; + struct fixup_entry *fixup_list; + struct fixup_entry *current_fixup; + int64_t user_uid; + int skip_file_set; + int64_t skip_file_dev; + int64_t skip_file_ino; + time_t start_time; + + int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); + void (*cleanup_gid)(void *private); + void *lookup_gid_data; + int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); + void (*cleanup_uid)(void *private); + void *lookup_uid_data; + + /* + * Full path of last file to satisfy symlink checks. + */ + struct archive_string path_safe; + + /* + * Cached stat data from disk for the current entry. + * If this is valid, pst points to st. Otherwise, + * pst is null. + */ + struct stat st; + struct stat *pst; + + /* Information about the object being restored right now. */ + struct archive_entry *entry; /* Entry being extracted. */ + char *name; /* Name of entry, possibly edited. */ + struct archive_string _name_data; /* backing store for 'name' */ + /* Tasks remaining for this object. */ + int todo; + /* Tasks deferred until end-of-archive. */ + int deferred; + /* Options requested by the client. */ + int flags; + /* Handle for the file we're restoring. */ + int fd; + /* Current offset for writing data to the file. */ + int64_t offset; + /* Last offset actually written to disk. */ + int64_t fd_offset; + /* Total bytes actually written to files. */ + int64_t total_bytes_written; + /* Maximum size of file, -1 if unknown. */ + int64_t filesize; + /* Dir we were in before this restore; only for deep paths. */ + int restore_pwd; + /* Mode we should use for this entry; affected by _PERM and umask. */ + mode_t mode; + /* UID/GID to use in restoring this entry. */ + int64_t uid; + int64_t gid; + /* + * HFS+ Compression. + */ + /* Xattr "com.apple.decmpfs". */ + uint32_t decmpfs_attr_size; + unsigned char *decmpfs_header_p; + /* ResourceFork set options used for fsetxattr. */ + int rsrc_xattr_options; + /* Xattr "com.apple.ResourceFork". */ + unsigned char *resource_fork; + size_t resource_fork_allocated_size; + unsigned int decmpfs_block_count; + uint32_t *decmpfs_block_info; + /* Buffer for compressed data. */ + unsigned char *compressed_buffer; + size_t compressed_buffer_size; + size_t compressed_buffer_remaining; + /* The offset of the ResourceFork where compressed data will + * be placed. */ + uint32_t compressed_rsrc_position; + uint32_t compressed_rsrc_position_v; + /* Buffer for uncompressed data. */ + char *uncompressed_buffer; + size_t block_remaining_bytes; + size_t file_remaining_bytes; +#ifdef HAVE_ZLIB_H + z_stream stream; + int stream_valid; + int decmpfs_compression_level; +#endif +}; + +/* + * Default mode for dirs created automatically (will be modified by umask). + * Note that POSIX specifies 0777 for implicitly-created dirs, "modified + * by the process' file creation mask." + */ +#define DEFAULT_DIR_MODE 0777 +/* + * Dir modes are restored in two steps: During the extraction, the permissions + * in the archive are modified to match the following limits. During + * the post-extract fixup pass, the permissions from the archive are + * applied. + */ +#define MINIMUM_DIR_MODE 0700 +#define MAXIMUM_DIR_MODE 0775 + +/* + * Maximum uncompressed size of a decmpfs block. + */ +#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) +/* + * HFS+ compression type. + */ +#define CMP_XATTR 3/* Compressed data in xattr. */ +#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ +/* + * HFS+ compression resource fork. + */ +#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ +#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ +/* Size to write compressed data to resource fork. */ +#define COMPRESSED_W_SIZE (64 * 1024) +/* decmpfs definitions. */ +#define MAX_DECMPFS_XATTR_SIZE 3802 +#ifndef DECMPFS_XATTR_NAME +#define DECMPFS_XATTR_NAME "com.apple.decmpfs" +#endif +#define DECMPFS_MAGIC 0x636d7066 +#define DECMPFS_COMPRESSION_MAGIC 0 +#define DECMPFS_COMPRESSION_TYPE 4 +#define DECMPFS_UNCOMPRESSED_SIZE 8 +#define DECMPFS_HEADER_SIZE 16 + +#define HFS_BLOCKS(s) ((s) >> 12) + +static void fsobj_error(int *, struct archive_string *, int, const char *, + const char *); +static int check_symlinks_fsobj(char *, int *, struct archive_string *, + int); +static int check_symlinks(struct archive_write_disk *); +static int create_filesystem_object(struct archive_write_disk *); +static struct fixup_entry *current_fixup(struct archive_write_disk *, + const char *pathname); +#if defined(HAVE_FCHDIR) && defined(PATH_MAX) +static void edit_deep_directories(struct archive_write_disk *ad); +#endif +static int cleanup_pathname_fsobj(char *, int *, struct archive_string *, + int); +static int cleanup_pathname(struct archive_write_disk *); +static int create_dir(struct archive_write_disk *, char *); +static int create_parent_dir(struct archive_write_disk *, char *); +static ssize_t hfs_write_data_block(struct archive_write_disk *, + const char *, size_t); +static int fixup_appledouble(struct archive_write_disk *, const char *); +static int older(struct stat *, struct archive_entry *); +static int restore_entry(struct archive_write_disk *); +static int set_mac_metadata(struct archive_write_disk *, const char *, + const void *, size_t); +static int set_xattrs(struct archive_write_disk *); +static int clear_nochange_fflags(struct archive_write_disk *); +static int set_fflags(struct archive_write_disk *); +static int set_fflags_platform(struct archive_write_disk *, int fd, + const char *name, mode_t mode, + unsigned long fflags_set, unsigned long fflags_clear); +static int set_ownership(struct archive_write_disk *); +static int set_mode(struct archive_write_disk *, int mode); +static int set_time(int, int, const char *, time_t, long, time_t, long); +static int set_times(struct archive_write_disk *, int, int, const char *, + time_t, long, time_t, long, time_t, long, time_t, long); +static int set_times_from_entry(struct archive_write_disk *); +static struct fixup_entry *sort_dir_list(struct fixup_entry *p); +static ssize_t write_data_block(struct archive_write_disk *, + const char *, size_t); + +static struct archive_vtable *archive_write_disk_vtable(void); + +static int _archive_write_disk_close(struct archive *); +static int _archive_write_disk_free(struct archive *); +static int _archive_write_disk_header(struct archive *, + struct archive_entry *); +static int64_t _archive_write_disk_filter_bytes(struct archive *, int); +static int _archive_write_disk_finish_entry(struct archive *); +static ssize_t _archive_write_disk_data(struct archive *, const void *, + size_t); +static ssize_t _archive_write_disk_data_block(struct archive *, const void *, + size_t, int64_t); + +static int +lazy_stat(struct archive_write_disk *a) +{ + if (a->pst != NULL) { + /* Already have stat() data available. */ + return (ARCHIVE_OK); + } +#ifdef HAVE_FSTAT + if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } +#endif + /* + * XXX At this point, symlinks should not be hit, otherwise + * XXX a race occurred. Do we want to check explicitly for that? + */ + if (lstat(a->name, &a->st) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } + archive_set_error(&a->archive, errno, "Couldn't stat file"); + return (ARCHIVE_WARN); +} + +static struct archive_vtable * +archive_write_disk_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_close = _archive_write_disk_close; + av.archive_filter_bytes = _archive_write_disk_filter_bytes; + av.archive_free = _archive_write_disk_free; + av.archive_write_header = _archive_write_disk_header; + av.archive_write_finish_entry + = _archive_write_disk_finish_entry; + av.archive_write_data = _archive_write_disk_data; + av.archive_write_data_block = _archive_write_disk_data_block; + inited = 1; + } + return (&av); +} + +static int64_t +_archive_write_disk_filter_bytes(struct archive *_a, int n) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + (void)n; /* UNUSED */ + if (n == -1 || n == 0) + return (a->total_bytes_written); + return (-1); +} + + +int +archive_write_disk_set_options(struct archive *_a, int flags) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + + a->flags = flags; + return (ARCHIVE_OK); +} + + +/* + * Extract this entry to disk. + * + * TODO: Validate hardlinks. According to the standards, we're + * supposed to check each extracted hardlink and squawk if it refers + * to a file that we didn't restore. I'm not entirely convinced this + * is a good idea, but more importantly: Is there any way to validate + * hardlinks without keeping a complete list of filenames from the + * entire archive?? Ugh. + * + */ +static int +_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *fe; + int ret, r; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_disk_header"); + archive_clear_error(&a->archive); + if (a->archive.state & ARCHIVE_STATE_DATA) { + r = _archive_write_disk_finish_entry(&a->archive); + if (r == ARCHIVE_FATAL) + return (r); + } + + /* Set up for this particular entry. */ + a->pst = NULL; + a->current_fixup = NULL; + a->deferred = 0; + if (a->entry) { + archive_entry_free(a->entry); + a->entry = NULL; + } + a->entry = archive_entry_clone(entry); + a->fd = -1; + a->fd_offset = 0; + a->offset = 0; + a->restore_pwd = -1; + a->uid = a->user_uid; + a->mode = archive_entry_mode(a->entry); + if (archive_entry_size_is_set(a->entry)) + a->filesize = archive_entry_size(a->entry); + else + a->filesize = -1; + archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); + a->name = a->_name_data.s; + archive_clear_error(&a->archive); + + /* + * Clean up the requested path. This is necessary for correct + * dir restores; the dir restore logic otherwise gets messed + * up by nonsense like "dir/.". + */ + ret = cleanup_pathname(a); + if (ret != ARCHIVE_OK) + return (ret); + + /* + * Query the umask so we get predictable mode settings. + * This gets done on every call to _write_header in case the + * user edits their umask during the extraction for some + * reason. + */ + umask(a->user_umask = umask(0)); + + /* Figure out what we need to do for this entry. */ + a->todo = TODO_MODE_BASE; + if (a->flags & ARCHIVE_EXTRACT_PERM) { + a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ + /* + * SGID requires an extra "check" step because we + * cannot easily predict the GID that the system will + * assign. (Different systems assign GIDs to files + * based on a variety of criteria, including process + * credentials and the gid of the enclosing + * directory.) We can only restore the SGID bit if + * the file has the right GID, and we only know the + * GID if we either set it (see set_ownership) or if + * we've actually called stat() on the file after it + * was restored. Since there are several places at + * which we might verify the GID, we need a TODO bit + * to keep track. + */ + if (a->mode & S_ISGID) + a->todo |= TODO_SGID | TODO_SGID_CHECK; + /* + * Verifying the SUID is simpler, but can still be + * done in multiple ways, hence the separate "check" bit. + */ + if (a->mode & S_ISUID) + a->todo |= TODO_SUID | TODO_SUID_CHECK; + } else { + /* + * User didn't request full permissions, so don't + * restore SUID, SGID bits and obey umask. + */ + a->mode &= ~S_ISUID; + a->mode &= ~S_ISGID; + a->mode &= ~S_ISVTX; + a->mode &= ~a->user_umask; + } + if (a->flags & ARCHIVE_EXTRACT_OWNER) + a->todo |= TODO_OWNER; + if (a->flags & ARCHIVE_EXTRACT_TIME) + a->todo |= TODO_TIMES; + if (a->flags & ARCHIVE_EXTRACT_ACL) { +#if ARCHIVE_ACL_DARWIN + /* + * On MacOS, platform ACLs get stored in mac_metadata, too. + * If we intend to extract mac_metadata and it is present + * we skip extracting libarchive NFSv4 ACLs. + */ + size_t metadata_size; + + if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || + archive_entry_mac_metadata(a->entry, + &metadata_size) == NULL || metadata_size == 0) +#endif +#if ARCHIVE_ACL_LIBRICHACL + /* + * RichACLs are stored in an extended attribute. + * If we intend to extract extended attributes and have this + * attribute we skip extracting libarchive NFSv4 ACLs. + */ + short extract_acls = 1; + if (a->flags & ARCHIVE_EXTRACT_XATTR && ( + archive_entry_acl_types(a->entry) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4)) { + const char *attr_name; + const void *attr_value; + size_t attr_size; + int i = archive_entry_xattr_reset(a->entry); + while (i--) { + archive_entry_xattr_next(a->entry, &attr_name, + &attr_value, &attr_size); + if (attr_name != NULL && attr_value != NULL && + attr_size > 0 && strcmp(attr_name, + "trusted.richacl") == 0) { + extract_acls = 0; + break; + } + } + } + if (extract_acls) +#endif +#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL + { +#endif + if (archive_entry_filetype(a->entry) == AE_IFDIR) + a->deferred |= TODO_ACLS; + else + a->todo |= TODO_ACLS; +#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL + } +#endif + } + if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { + if (archive_entry_filetype(a->entry) == AE_IFDIR) + a->deferred |= TODO_MAC_METADATA; + else + a->todo |= TODO_MAC_METADATA; + } +#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) + if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { + unsigned long set, clear; + archive_entry_fflags(a->entry, &set, &clear); + if ((set & ~clear) & UF_COMPRESSED) { + a->todo |= TODO_HFS_COMPRESSION; + a->decmpfs_block_count = (unsigned)-1; + } + } + if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && + (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { + a->todo |= TODO_HFS_COMPRESSION; + a->decmpfs_block_count = (unsigned)-1; + } + { + const char *p; + + /* Check if the current file name is a type of the + * resource fork file. */ + p = strrchr(a->name, '/'); + if (p == NULL) + p = a->name; + else + p++; + if (p[0] == '.' && p[1] == '_') { + /* Do not compress "._XXX" files. */ + a->todo &= ~TODO_HFS_COMPRESSION; + if (a->filesize > 0) + a->todo |= TODO_APPLEDOUBLE; + } + } +#endif + + if (a->flags & ARCHIVE_EXTRACT_XATTR) { +#if ARCHIVE_XATTR_DARWIN + /* + * On MacOS, extended attributes get stored in mac_metadata, + * too. If we intend to extract mac_metadata and it is present + * we skip extracting extended attributes. + */ + size_t metadata_size; + + if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || + archive_entry_mac_metadata(a->entry, + &metadata_size) == NULL || metadata_size == 0) +#endif + a->todo |= TODO_XATTR; + } + if (a->flags & ARCHIVE_EXTRACT_FFLAGS) + a->todo |= TODO_FFLAGS; + if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { + ret = check_symlinks(a); + if (ret != ARCHIVE_OK) + return (ret); + } +#if defined(HAVE_FCHDIR) && defined(PATH_MAX) + /* If path exceeds PATH_MAX, shorten the path. */ + edit_deep_directories(a); +#endif + + ret = restore_entry(a); + +#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) + /* + * Check if the filesystem the file is restoring on supports + * HFS+ Compression. If not, cancel HFS+ Compression. + */ + if (a->todo | TODO_HFS_COMPRESSION) { + /* + * NOTE: UF_COMPRESSED is ignored even if the filesystem + * supports HFS+ Compression because the file should + * have at least an extended attribute "com.apple.decmpfs" + * before the flag is set to indicate that the file have + * been compressed. If the filesystem does not support + * HFS+ Compression the system call will fail. + */ + if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) + a->todo &= ~TODO_HFS_COMPRESSION; + } +#endif + + /* + * TODO: There are rumours that some extended attributes must + * be restored before file data is written. If this is true, + * then we either need to write all extended attributes both + * before and after restoring the data, or find some rule for + * determining which must go first and which last. Due to the + * many ways people are using xattrs, this may prove to be an + * intractable problem. + */ + +#ifdef HAVE_FCHDIR + /* If we changed directory above, restore it here. */ + if (a->restore_pwd >= 0) { + r = fchdir(a->restore_pwd); + if (r != 0) { + archive_set_error(&a->archive, errno, + "chdir() failure"); + ret = ARCHIVE_FATAL; + } + close(a->restore_pwd); + a->restore_pwd = -1; + } +#endif + + /* + * Fixup uses the unedited pathname from archive_entry_pathname(), + * because it is relative to the base dir and the edited path + * might be relative to some intermediate dir as a result of the + * deep restore logic. + */ + if (a->deferred & TODO_MODE) { + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); + fe->fixup |= TODO_MODE_BASE; + fe->mode = a->mode; + } + + if ((a->deferred & TODO_TIMES) + && (archive_entry_mtime_is_set(entry) + || archive_entry_atime_is_set(entry))) { + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); + fe->mode = a->mode; + fe->fixup |= TODO_TIMES; + if (archive_entry_atime_is_set(entry)) { + fe->atime = archive_entry_atime(entry); + fe->atime_nanos = archive_entry_atime_nsec(entry); + } else { + /* If atime is unset, use start time. */ + fe->atime = a->start_time; + fe->atime_nanos = 0; + } + if (archive_entry_mtime_is_set(entry)) { + fe->mtime = archive_entry_mtime(entry); + fe->mtime_nanos = archive_entry_mtime_nsec(entry); + } else { + /* If mtime is unset, use start time. */ + fe->mtime = a->start_time; + fe->mtime_nanos = 0; + } + if (archive_entry_birthtime_is_set(entry)) { + fe->birthtime = archive_entry_birthtime(entry); + fe->birthtime_nanos = archive_entry_birthtime_nsec( + entry); + } else { + /* If birthtime is unset, use mtime. */ + fe->birthtime = fe->mtime; + fe->birthtime_nanos = fe->mtime_nanos; + } + } + + if (a->deferred & TODO_ACLS) { + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); + fe->fixup |= TODO_ACLS; + archive_acl_copy(&fe->acl, archive_entry_acl(entry)); + } + + if (a->deferred & TODO_MAC_METADATA) { + const void *metadata; + size_t metadata_size; + metadata = archive_entry_mac_metadata(a->entry, &metadata_size); + if (metadata != NULL && metadata_size > 0) { + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); + fe->mac_metadata = malloc(metadata_size); + if (fe->mac_metadata != NULL) { + memcpy(fe->mac_metadata, metadata, + metadata_size); + fe->mac_metadata_size = metadata_size; + fe->fixup |= TODO_MAC_METADATA; + } + } + } + + if (a->deferred & TODO_FFLAGS) { + fe = current_fixup(a, archive_entry_pathname(entry)); + if (fe == NULL) + return (ARCHIVE_FATAL); + fe->fixup |= TODO_FFLAGS; + /* TODO: Complete this.. defer fflags from below. */ + } + + /* We've created the object and are ready to pour data into it. */ + if (ret >= ARCHIVE_WARN) + a->archive.state = ARCHIVE_STATE_DATA; + /* + * If it's not open, tell our client not to try writing. + * In particular, dirs, links, etc, don't get written to. + */ + if (a->fd < 0) { + archive_entry_set_size(entry, 0); + a->filesize = 0; + } + + return (ret); +} + +int +archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); + a->skip_file_set = 1; + a->skip_file_dev = d; + a->skip_file_ino = i; + return (ARCHIVE_OK); +} + +static ssize_t +write_data_block(struct archive_write_disk *a, const char *buff, size_t size) +{ + uint64_t start_size = size; + ssize_t bytes_written = 0; + ssize_t block_size = 0, bytes_to_write; + + if (size == 0) + return (ARCHIVE_OK); + + if (a->filesize == 0 || a->fd < 0) { + archive_set_error(&a->archive, 0, + "Attempt to write to an empty file"); + return (ARCHIVE_WARN); + } + + if (a->flags & ARCHIVE_EXTRACT_SPARSE) { +#if HAVE_STRUCT_STAT_ST_BLKSIZE + int r; + if ((r = lazy_stat(a)) != ARCHIVE_OK) + return (r); + block_size = a->pst->st_blksize; +#else + /* XXX TODO XXX Is there a more appropriate choice here ? */ + /* This needn't match the filesystem allocation size. */ + block_size = 16*1024; +#endif + } + + /* If this write would run beyond the file size, truncate it. */ + if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) + start_size = size = (size_t)(a->filesize - a->offset); + + /* Write the data. */ + while (size > 0) { + if (block_size == 0) { + bytes_to_write = size; + } else { + /* We're sparsifying the file. */ + const char *p, *end; + int64_t block_end; + + /* Skip leading zero bytes. */ + for (p = buff, end = buff + size; p < end; ++p) { + if (*p != '\0') + break; + } + a->offset += p - buff; + size -= p - buff; + buff = p; + if (size == 0) + break; + + /* Calculate next block boundary after offset. */ + block_end + = (a->offset / block_size + 1) * block_size; + + /* If the adjusted write would cross block boundary, + * truncate it to the block boundary. */ + bytes_to_write = size; + if (a->offset + bytes_to_write > block_end) + bytes_to_write = block_end - a->offset; + } + /* Seek if necessary to the specified offset. */ + if (a->offset != a->fd_offset) { + if (lseek(a->fd, a->offset, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, + "Seek failed"); + return (ARCHIVE_FATAL); + } + a->fd_offset = a->offset; + } + bytes_written = write(a->fd, buff, bytes_to_write); + if (bytes_written < 0) { + archive_set_error(&a->archive, errno, "Write failed"); + return (ARCHIVE_WARN); + } + buff += bytes_written; + size -= bytes_written; + a->total_bytes_written += bytes_written; + a->offset += bytes_written; + a->fd_offset = a->offset; + } + return (start_size - size); +} + +#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ + && defined(HAVE_ZLIB_H) + +/* + * Set UF_COMPRESSED file flag. + * This have to be called after hfs_write_decmpfs() because if the + * file does not have "com.apple.decmpfs" xattr the flag is ignored. + */ +static int +hfs_set_compressed_fflag(struct archive_write_disk *a) +{ + int r; + + if ((r = lazy_stat(a)) != ARCHIVE_OK) + return (r); + + a->st.st_flags |= UF_COMPRESSED; + if (fchflags(a->fd, a->st.st_flags) != 0) { + archive_set_error(&a->archive, errno, + "Failed to set UF_COMPRESSED file flag"); + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); +} + +/* + * HFS+ Compression decmpfs + * + * +------------------------------+ +0 + * | Magic(LE 4 bytes) | + * +------------------------------+ + * | Type(LE 4 bytes) | + * +------------------------------+ + * | Uncompressed size(LE 8 bytes)| + * +------------------------------+ +16 + * | | + * | Compressed data | + * | (Placed only if Type == 3) | + * | | + * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE + * + * Type is 3: decmpfs has compressed data. + * Type is 4: Resource Fork has compressed data. + */ +/* + * Write "com.apple.decmpfs" + */ +static int +hfs_write_decmpfs(struct archive_write_disk *a) +{ + int r; + uint32_t compression_type; + + r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, + a->decmpfs_attr_size, 0, 0); + if (r < 0) { + archive_set_error(&a->archive, errno, + "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); + compression_type = archive_le32dec( + &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); + if (compression_type == CMP_RESOURCE_FORK) + fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, + XATTR_SHOWCOMPRESSION); + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); +} + +/* + * HFS+ Compression Resource Fork + * + * +-----------------------------+ + * | Header(260 bytes) | + * +-----------------------------+ + * | Block count(LE 4 bytes) | + * +-----------------------------+ --+ + * +-- | Offset (LE 4 bytes) | | + * | | [distance from Block count] | | Block 0 + * | +-----------------------------+ | + * | | Compressed size(LE 4 bytes) | | + * | +-----------------------------+ --+ + * | | | + * | | .................. | + * | | | + * | +-----------------------------+ --+ + * | | Offset (LE 4 bytes) | | + * | +-----------------------------+ | Block (Block count -1) + * | | Compressed size(LE 4 bytes) | | + * +-> +-----------------------------+ --+ + * | Compressed data(n bytes) | Block 0 + * +-----------------------------+ + * | | + * | .................. | + * | | + * +-----------------------------+ + * | Compressed data(n bytes) | Block (Block count -1) + * +-----------------------------+ + * | Footer(50 bytes) | + * +-----------------------------+ + * + */ +/* + * Write the header of "com.apple.ResourceFork" + */ +static int +hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, + size_t bytes, uint32_t position) +{ + int ret; + + ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, + position, a->rsrc_xattr_options); + if (ret < 0) { + archive_set_error(&a->archive, errno, + "Cannot restore xattr: %s at %u pos %u bytes", + XATTR_RESOURCEFORK_NAME, + (unsigned)position, + (unsigned)bytes); + return (ARCHIVE_WARN); + } + a->rsrc_xattr_options &= ~XATTR_CREATE; + return (ARCHIVE_OK); +} + +static int +hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) +{ + int ret; + + ret = hfs_write_resource_fork(a, a->compressed_buffer, + bytes_compressed, a->compressed_rsrc_position); + if (ret == ARCHIVE_OK) + a->compressed_rsrc_position += bytes_compressed; + return (ret); +} + +static int +hfs_write_resource_fork_header(struct archive_write_disk *a) +{ + unsigned char *buff; + uint32_t rsrc_bytes; + uint32_t rsrc_header_bytes; + + /* + * Write resource fork header + block info. + */ + buff = a->resource_fork; + rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; + rsrc_header_bytes = + RSRC_H_SIZE + /* Header base size. */ + 4 + /* Block count. */ + (a->decmpfs_block_count * 8);/* Block info */ + archive_be32enc(buff, 0x100); + archive_be32enc(buff + 4, rsrc_bytes); + archive_be32enc(buff + 8, rsrc_bytes - 256); + archive_be32enc(buff + 12, 0x32); + memset(buff + 16, 0, 240); + archive_be32enc(buff + 256, rsrc_bytes - 260); + return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); +} + +static size_t +hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) +{ + static const char rsrc_footer[RSRC_F_SIZE] = { + 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, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', + 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + if (buff_size < sizeof(rsrc_footer)) + return (0); + memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); + return (sizeof(rsrc_footer)); +} + +static int +hfs_reset_compressor(struct archive_write_disk *a) +{ + int ret; + + if (a->stream_valid) + ret = deflateReset(&a->stream); + else + ret = deflateInit(&a->stream, a->decmpfs_compression_level); + + if (ret != Z_OK) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Failed to initialize compressor"); + return (ARCHIVE_FATAL); + } else + a->stream_valid = 1; + + return (ARCHIVE_OK); +} + +static int +hfs_decompress(struct archive_write_disk *a) +{ + uint32_t *block_info; + unsigned int block_count; + uint32_t data_pos, data_size; + ssize_t r; + ssize_t bytes_written, bytes_to_write; + unsigned char *b; + + block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); + block_count = archive_le32dec(block_info++); + while (block_count--) { + data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); + data_size = archive_le32dec(block_info++); + r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, + a->compressed_buffer, data_size, data_pos, 0); + if (r != data_size) { + archive_set_error(&a->archive, + (r < 0)?errno:ARCHIVE_ERRNO_MISC, + "Failed to read resource fork"); + return (ARCHIVE_WARN); + } + if (a->compressed_buffer[0] == 0xff) { + bytes_to_write = data_size -1; + b = a->compressed_buffer + 1; + } else { + uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; + int zr; + + zr = uncompress((Bytef *)a->uncompressed_buffer, + &dest_len, a->compressed_buffer, data_size); + if (zr != Z_OK) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to decompress resource fork"); + return (ARCHIVE_WARN); + } + bytes_to_write = dest_len; + b = (unsigned char *)a->uncompressed_buffer; + } + do { + bytes_written = write(a->fd, b, bytes_to_write); + if (bytes_written < 0) { + archive_set_error(&a->archive, errno, + "Write failed"); + return (ARCHIVE_WARN); + } + bytes_to_write -= bytes_written; + b += bytes_written; + } while (bytes_to_write > 0); + } + r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to remove resource fork"); + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); +} + +static int +hfs_drive_compressor(struct archive_write_disk *a, const char *buff, + size_t size) +{ + unsigned char *buffer_compressed; + size_t bytes_compressed; + size_t bytes_used; + int ret; + + ret = hfs_reset_compressor(a); + if (ret != ARCHIVE_OK) + return (ret); + + if (a->compressed_buffer == NULL) { + size_t block_size; + + block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + + + compressBound(MAX_DECMPFS_BLOCK_SIZE); + a->compressed_buffer = malloc(block_size); + if (a->compressed_buffer == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Resource Fork"); + return (ARCHIVE_FATAL); + } + a->compressed_buffer_size = block_size; + a->compressed_buffer_remaining = block_size; + } + + buffer_compressed = a->compressed_buffer + + a->compressed_buffer_size - a->compressed_buffer_remaining; + a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; + a->stream.avail_in = size; + a->stream.next_out = buffer_compressed; + a->stream.avail_out = a->compressed_buffer_remaining; + do { + ret = deflate(&a->stream, Z_FINISH); + switch (ret) { + case Z_OK: + case Z_STREAM_END: + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Failed to compress data"); + return (ARCHIVE_FAILED); + } + } while (ret == Z_OK); + bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; + + /* + * If the compressed size is larger than the original size, + * throw away compressed data, use uncompressed data instead. + */ + if (bytes_compressed > size) { + buffer_compressed[0] = 0xFF;/* uncompressed marker. */ + memcpy(buffer_compressed + 1, buff, size); + bytes_compressed = size + 1; + } + a->compressed_buffer_remaining -= bytes_compressed; + + /* + * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE + * and the block count in the file is only one, store compressed + * data to decmpfs xattr instead of the resource fork. + */ + if (a->decmpfs_block_count == 1 && + (a->decmpfs_attr_size + bytes_compressed) + <= MAX_DECMPFS_XATTR_SIZE) { + archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], + CMP_XATTR); + memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, + buffer_compressed, bytes_compressed); + a->decmpfs_attr_size += bytes_compressed; + a->compressed_buffer_remaining = a->compressed_buffer_size; + /* + * Finish HFS+ Compression. + * - Write the decmpfs xattr. + * - Set the UF_COMPRESSED file flag. + */ + ret = hfs_write_decmpfs(a); + if (ret == ARCHIVE_OK) + ret = hfs_set_compressed_fflag(a); + return (ret); + } + + /* Update block info. */ + archive_le32enc(a->decmpfs_block_info++, + a->compressed_rsrc_position_v - RSRC_H_SIZE); + archive_le32enc(a->decmpfs_block_info++, bytes_compressed); + a->compressed_rsrc_position_v += bytes_compressed; + + /* + * Write the compressed data to the resource fork. + */ + bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; + while (bytes_used >= COMPRESSED_W_SIZE) { + ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); + if (ret != ARCHIVE_OK) + return (ret); + bytes_used -= COMPRESSED_W_SIZE; + if (bytes_used > COMPRESSED_W_SIZE) + memmove(a->compressed_buffer, + a->compressed_buffer + COMPRESSED_W_SIZE, + bytes_used); + else + memcpy(a->compressed_buffer, + a->compressed_buffer + COMPRESSED_W_SIZE, + bytes_used); + } + a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; + + /* + * If the current block is the last block, write the remaining + * compressed data and the resource fork footer. + */ + if (a->file_remaining_bytes == 0) { + size_t rsrc_size; + int64_t bk; + + /* Append the resource footer. */ + rsrc_size = hfs_set_resource_fork_footer( + a->compressed_buffer + bytes_used, + a->compressed_buffer_remaining); + ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); + a->compressed_buffer_remaining = a->compressed_buffer_size; + + /* If the compressed size is not enough smaller than + * the uncompressed size. cancel HFS+ compression. + * TODO: study a behavior of ditto utility and improve + * the condition to fall back into no HFS+ compression. */ + bk = HFS_BLOCKS(a->compressed_rsrc_position); + bk += bk >> 7; + if (bk > HFS_BLOCKS(a->filesize)) + return hfs_decompress(a); + /* + * Write the resourcefork header. + */ + if (ret == ARCHIVE_OK) + ret = hfs_write_resource_fork_header(a); + /* + * Finish HFS+ Compression. + * - Write the decmpfs xattr. + * - Set the UF_COMPRESSED file flag. + */ + if (ret == ARCHIVE_OK) + ret = hfs_write_decmpfs(a); + if (ret == ARCHIVE_OK) + ret = hfs_set_compressed_fflag(a); + } + return (ret); +} + +static ssize_t +hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, + size_t size) +{ + const char *buffer_to_write; + size_t bytes_to_write; + int ret; + + if (a->decmpfs_block_count == (unsigned)-1) { + void *new_block; + size_t new_size; + unsigned int block_count; + + if (a->decmpfs_header_p == NULL) { + new_block = malloc(MAX_DECMPFS_XATTR_SIZE + + sizeof(uint32_t)); + if (new_block == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for decmpfs"); + return (ARCHIVE_FATAL); + } + a->decmpfs_header_p = new_block; + } + a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; + archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], + DECMPFS_MAGIC); + archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], + CMP_RESOURCE_FORK); + 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; + /* + * Allocate buffer for resource fork. + * Set up related pointers; + */ + new_size = + RSRC_H_SIZE + /* header */ + 4 + /* Block count */ + (block_count * sizeof(uint32_t) * 2) + + RSRC_F_SIZE; /* footer */ + if (new_size > a->resource_fork_allocated_size) { + new_block = realloc(a->resource_fork, new_size); + if (new_block == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for ResourceFork"); + return (ARCHIVE_FATAL); + } + a->resource_fork_allocated_size = new_size; + a->resource_fork = new_block; + } + + /* Allocate uncompressed buffer */ + if (a->uncompressed_buffer == NULL) { + new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); + if (new_block == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for decmpfs"); + return (ARCHIVE_FATAL); + } + a->uncompressed_buffer = new_block; + } + a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; + a->file_remaining_bytes = a->filesize; + a->compressed_buffer_remaining = a->compressed_buffer_size; + + /* + * Set up a resource fork. + */ + a->rsrc_xattr_options = XATTR_CREATE; + /* Get the position where we are going to set a bunch + * of block info. */ + 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); + /* Get the position where we are going to set compressed + * data. */ + a->compressed_rsrc_position = + RSRC_H_SIZE + 4 + (block_count * 8); + a->compressed_rsrc_position_v = a->compressed_rsrc_position; + a->decmpfs_block_count = block_count; + } + + /* Ignore redundant bytes. */ + if (a->file_remaining_bytes == 0) + return ((ssize_t)size); + + /* Do not overrun a block size. */ + if (size > a->block_remaining_bytes) + bytes_to_write = a->block_remaining_bytes; + else + bytes_to_write = size; + /* Do not overrun the file size. */ + if (bytes_to_write > a->file_remaining_bytes) + bytes_to_write = a->file_remaining_bytes; + + /* For efficiency, if a copy length is full of the uncompressed + * buffer size, do not copy writing data to it. */ + if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) + buffer_to_write = buff; + else { + memcpy(a->uncompressed_buffer + + MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, + buff, bytes_to_write); + buffer_to_write = a->uncompressed_buffer; + } + a->block_remaining_bytes -= bytes_to_write; + a->file_remaining_bytes -= bytes_to_write; + + if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { + ret = hfs_drive_compressor(a, buffer_to_write, + MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); + if (ret < 0) + return (ret); + a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; + } + /* Ignore redundant bytes. */ + if (a->file_remaining_bytes == 0) + return ((ssize_t)size); + return (bytes_to_write); +} + +static ssize_t +hfs_write_data_block(struct archive_write_disk *a, const char *buff, + size_t size) +{ + uint64_t start_size = size; + ssize_t bytes_written = 0; + ssize_t bytes_to_write; + + if (size == 0) + return (ARCHIVE_OK); + + if (a->filesize == 0 || a->fd < 0) { + archive_set_error(&a->archive, 0, + "Attempt to write to an empty file"); + return (ARCHIVE_WARN); + } + + /* If this write would run beyond the file size, truncate it. */ + if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) + start_size = size = (size_t)(a->filesize - a->offset); + + /* Write the data. */ + while (size > 0) { + bytes_to_write = size; + /* Seek if necessary to the specified offset. */ + if (a->offset < a->fd_offset) { + /* Can't support backward move. */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Seek failed"); + return (ARCHIVE_FATAL); + } else if (a->offset > a->fd_offset) { + int64_t skip = a->offset - a->fd_offset; + char nullblock[1024]; + + memset(nullblock, 0, sizeof(nullblock)); + while (skip > 0) { + if (skip > (int64_t)sizeof(nullblock)) + bytes_written = hfs_write_decmpfs_block( + a, nullblock, sizeof(nullblock)); + else + bytes_written = hfs_write_decmpfs_block( + a, nullblock, skip); + if (bytes_written < 0) { + archive_set_error(&a->archive, errno, + "Write failed"); + return (ARCHIVE_WARN); + } + skip -= bytes_written; + } + + a->fd_offset = a->offset; + } + bytes_written = + hfs_write_decmpfs_block(a, buff, bytes_to_write); + if (bytes_written < 0) + return (bytes_written); + buff += bytes_written; + size -= bytes_written; + a->total_bytes_written += bytes_written; + a->offset += bytes_written; + a->fd_offset = a->offset; + } + return (start_size - size); +} +#else +static ssize_t +hfs_write_data_block(struct archive_write_disk *a, const char *buff, + size_t size) +{ + return (write_data_block(a, buff, size)); +} +#endif + +static ssize_t +_archive_write_disk_data_block(struct archive *_a, + const void *buff, size_t size, int64_t offset) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + ssize_t r; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data_block"); + + a->offset = offset; + if (a->todo & TODO_HFS_COMPRESSION) + r = hfs_write_data_block(a, buff, size); + else + r = write_data_block(a, buff, size); + if (r < ARCHIVE_OK) + return (r); + if ((size_t)r < size) { + archive_set_error(&a->archive, 0, + "Too much data: Truncating file at %ju bytes", + (uintmax_t)a->filesize); + return (ARCHIVE_WARN); + } +#if ARCHIVE_VERSION_NUMBER < 3999000 + return (ARCHIVE_OK); +#else + return (size); +#endif +} + +static ssize_t +_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data"); + + if (a->todo & TODO_HFS_COMPRESSION) + return (hfs_write_data_block(a, buff, size)); + return (write_data_block(a, buff, size)); +} + +static int +_archive_write_disk_finish_entry(struct archive *_a) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + int ret = ARCHIVE_OK; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_finish_entry"); + if (a->archive.state & ARCHIVE_STATE_HEADER) + return (ARCHIVE_OK); + archive_clear_error(&a->archive); + + /* Pad or truncate file to the right size. */ + if (a->fd < 0) { + /* There's no file. */ + } else if (a->filesize < 0) { + /* File size is unknown, so we can't set the size. */ + } else if (a->fd_offset == a->filesize) { + /* Last write ended at exactly the filesize; we're done. */ + /* Hopefully, this is the common case. */ +#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) + } else if (a->todo & TODO_HFS_COMPRESSION) { + char null_d[1024]; + ssize_t r; + + if (a->file_remaining_bytes) + memset(null_d, 0, sizeof(null_d)); + while (a->file_remaining_bytes) { + if (a->file_remaining_bytes > sizeof(null_d)) + r = hfs_write_data_block( + a, null_d, sizeof(null_d)); + else + r = hfs_write_data_block( + a, null_d, a->file_remaining_bytes); + if (r < 0) + return ((int)r); + } +#endif + } else { +#if HAVE_FTRUNCATE + if (ftruncate(a->fd, a->filesize) == -1 && + a->filesize == 0) { + archive_set_error(&a->archive, errno, + "File size could not be restored"); + return (ARCHIVE_FAILED); + } +#endif + /* + * Not all platforms implement the XSI option to + * extend files via ftruncate. Stat() the file again + * to see what happened. + */ + a->pst = NULL; + if ((ret = lazy_stat(a)) != ARCHIVE_OK) + return (ret); + /* We can use lseek()/write() to extend the file if + * ftruncate didn't work or isn't available. */ + if (a->st.st_size < a->filesize) { + const char nul = '\0'; + if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, + "Seek failed"); + return (ARCHIVE_FATAL); + } + if (write(a->fd, &nul, 1) < 0) { + archive_set_error(&a->archive, errno, + "Write to restore size failed"); + return (ARCHIVE_FATAL); + } + a->pst = NULL; + } + } + + /* Restore metadata. */ + + /* + * This is specific to Mac OS X. + * If the current file is an AppleDouble file, it should be + * linked with the data fork file and remove it. + */ + if (a->todo & TODO_APPLEDOUBLE) { + int r2 = fixup_appledouble(a, a->name); + if (r2 == ARCHIVE_EOF) { + /* The current file has been successfully linked + * with the data fork file and removed. So there + * is nothing to do on the current file. */ + goto finish_metadata; + } + if (r2 < ret) ret = r2; + } + + /* + * Look up the "real" UID only if we're going to need it. + * TODO: the TODO_SGID condition can be dropped here, can't it? + */ + if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { + a->uid = archive_write_disk_uid(&a->archive, + archive_entry_uname(a->entry), + archive_entry_uid(a->entry)); + } + /* Look up the "real" GID only if we're going to need it. */ + /* TODO: the TODO_SUID condition can be dropped here, can't it? */ + if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { + a->gid = archive_write_disk_gid(&a->archive, + archive_entry_gname(a->entry), + archive_entry_gid(a->entry)); + } + + /* + * Restore ownership before set_mode tries to restore suid/sgid + * bits. If we set the owner, we know what it is and can skip + * a stat() call to examine the ownership of the file on disk. + */ + if (a->todo & TODO_OWNER) { + int r2 = set_ownership(a); + if (r2 < ret) ret = r2; + } + + /* + * set_mode must precede ACLs on systems such as Solaris and + * FreeBSD where setting the mode implicitly clears extended ACLs + */ + if (a->todo & TODO_MODE) { + int r2 = set_mode(a, a->mode); + if (r2 < ret) ret = r2; + } + + /* + * Security-related extended attributes (such as + * security.capability on Linux) have to be restored last, + * since they're implicitly removed by other file changes. + */ + if (a->todo & TODO_XATTR) { + int r2 = set_xattrs(a); + if (r2 < ret) ret = r2; + } + + /* + * Some flags prevent file modification; they must be restored after + * file contents are written. + */ + if (a->todo & TODO_FFLAGS) { + int r2 = set_fflags(a); + if (r2 < ret) ret = r2; + } + + /* + * Time must follow most other metadata; + * otherwise atime will get changed. + */ + if (a->todo & TODO_TIMES) { + int r2 = set_times_from_entry(a); + if (r2 < ret) ret = r2; + } + + /* + * Mac extended metadata includes ACLs. + */ + if (a->todo & TODO_MAC_METADATA) { + const void *metadata; + size_t metadata_size; + metadata = archive_entry_mac_metadata(a->entry, &metadata_size); + if (metadata != NULL && metadata_size > 0) { + int r2 = set_mac_metadata(a, archive_entry_pathname( + a->entry), metadata, metadata_size); + if (r2 < ret) ret = r2; + } + } + + /* + * ACLs must be restored after timestamps because there are + * ACLs that prevent attribute changes (including time). + */ + if (a->todo & TODO_ACLS) { + int r2; + r2 = archive_write_disk_set_acls(&a->archive, a->fd, + archive_entry_pathname(a->entry), + archive_entry_acl(a->entry), + archive_entry_mode(a->entry)); + if (r2 < ret) ret = r2; + } + +finish_metadata: + /* If there's an fd, we can close it now. */ + if (a->fd >= 0) { + close(a->fd); + a->fd = -1; + } + /* If there's an entry, we can release it now. */ + if (a->entry) { + archive_entry_free(a->entry); + a->entry = NULL; + } + a->archive.state = ARCHIVE_STATE_HEADER; + return (ret); +} + +int +archive_write_disk_set_group_lookup(struct archive *_a, + void *private_data, + int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), + void (*cleanup_gid)(void *private)) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); + + if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) + (a->cleanup_gid)(a->lookup_gid_data); + + a->lookup_gid = lookup_gid; + a->cleanup_gid = cleanup_gid; + a->lookup_gid_data = private_data; + return (ARCHIVE_OK); +} + +int +archive_write_disk_set_user_lookup(struct archive *_a, + void *private_data, + int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), + void (*cleanup_uid)(void *private)) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); + + if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) + (a->cleanup_uid)(a->lookup_uid_data); + + a->lookup_uid = lookup_uid; + a->cleanup_uid = cleanup_uid; + a->lookup_uid_data = private_data; + return (ARCHIVE_OK); +} + +int64_t +archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_gid"); + if (a->lookup_gid) + return (a->lookup_gid)(a->lookup_gid_data, name, id); + return (id); +} + +int64_t +archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_uid"); + if (a->lookup_uid) + return (a->lookup_uid)(a->lookup_uid_data, name, id); + return (id); +} + +/* + * Create a new archive_write_disk object and initialize it with global state. + */ +struct archive * +archive_write_disk_new(void) +{ + struct archive_write_disk *a; + + a = (struct archive_write_disk *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; + /* We're ready to write a header immediately. */ + a->archive.state = ARCHIVE_STATE_HEADER; + a->archive.vtable = archive_write_disk_vtable(); + a->start_time = time(NULL); + /* Query and restore the umask. */ + umask(a->user_umask = umask(0)); +#ifdef HAVE_GETEUID + a->user_uid = geteuid(); +#endif /* HAVE_GETEUID */ + if (archive_string_ensure(&a->path_safe, 512) == NULL) { + free(a); + return (NULL); + } +#ifdef HAVE_ZLIB_H + a->decmpfs_compression_level = 5; +#endif + return (&a->archive); +} + + +/* + * If pathname is longer than PATH_MAX, chdir to a suitable + * intermediate dir and edit the path down to a shorter suffix. Note + * that this routine never returns an error; if the chdir() attempt + * fails for any reason, we just go ahead with the long pathname. The + * object creation is likely to fail, but any error will get handled + * at that time. + */ +#if defined(HAVE_FCHDIR) && defined(PATH_MAX) +static void +edit_deep_directories(struct archive_write_disk *a) +{ + int ret; + char *tail = a->name; + + /* If path is short, avoid the open() below. */ + if (strlen(tail) < PATH_MAX) + return; + + /* Try to record our starting dir. */ + a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(a->restore_pwd); + if (a->restore_pwd < 0) + return; + + /* As long as the path is too long... */ + while (strlen(tail) >= PATH_MAX) { + /* Locate a dir prefix shorter than PATH_MAX. */ + tail += PATH_MAX - 8; + while (tail > a->name && *tail != '/') + tail--; + /* Exit if we find a too-long path component. */ + if (tail <= a->name) + return; + /* Create the intermediate dir and chdir to it. */ + *tail = '\0'; /* Terminate dir portion */ + ret = create_dir(a, a->name); + if (ret == ARCHIVE_OK && chdir(a->name) != 0) + ret = ARCHIVE_FAILED; + *tail = '/'; /* Restore the / we removed. */ + if (ret != ARCHIVE_OK) + return; + tail++; + /* The chdir() succeeded; we've now shortened the path. */ + a->name = tail; + } + return; +} +#endif + +/* + * The main restore function. + */ +static int +restore_entry(struct archive_write_disk *a) +{ + int ret = ARCHIVE_OK, en; + + if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { + /* + * TODO: Fix this. Apparently, there are platforms + * that still allow root to hose the entire filesystem + * by unlinking a dir. The S_ISDIR() test above + * prevents us from using unlink() here if the new + * object is a dir, but that doesn't mean the old + * object isn't a dir. + */ + if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) + (void)clear_nochange_fflags(a); + if (unlink(a->name) == 0) { + /* We removed it, reset cached stat. */ + a->pst = NULL; + } else if (errno == ENOENT) { + /* File didn't exist, that's just as good. */ + } else if (rmdir(a->name) == 0) { + /* It was a dir, but now it's gone. */ + a->pst = NULL; + } else { + /* We tried, but couldn't get rid of it. */ + archive_set_error(&a->archive, errno, + "Could not unlink"); + return(ARCHIVE_FAILED); + } + } + + /* Try creating it first; if this fails, we'll try to recover. */ + en = create_filesystem_object(a); + + if ((en == ENOTDIR || en == ENOENT) + && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { + /* If the parent dir doesn't exist, try creating it. */ + create_parent_dir(a, a->name); + /* Now try to create the object again. */ + en = create_filesystem_object(a); + } + + if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) { + archive_set_error(&a->archive, en, + "Hard-link target '%s' does not exist.", + archive_entry_hardlink(a->entry)); + return (ARCHIVE_FAILED); + } + + if ((en == EISDIR || en == EEXIST) + && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { + /* If we're not overwriting, we're done. */ + archive_entry_unset_size(a->entry); + return (ARCHIVE_OK); + } + + /* + * Some platforms return EISDIR if you call + * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some + * return EEXIST. POSIX is ambiguous, requiring EISDIR + * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) + * on an existing item. + */ + if (en == EISDIR) { + /* A dir is in the way of a non-dir, rmdir it. */ + if (rmdir(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't remove already-existing dir"); + return (ARCHIVE_FAILED); + } + a->pst = NULL; + /* Try again. */ + en = create_filesystem_object(a); + } else if (en == EEXIST) { + /* + * We know something is in the way, but we don't know what; + * we need to find out before we go any further. + */ + int r = 0; + /* + * The SECURE_SYMLINKS logic has already removed a + * symlink to a dir if the client wants that. So + * follow the symlink if we're creating a dir. + */ + if (S_ISDIR(a->mode)) + r = stat(a->name, &a->st); + /* + * If it's not a dir (or it's a broken symlink), + * then don't follow it. + */ + if (r != 0 || !S_ISDIR(a->mode)) + r = lstat(a->name, &a->st); + if (r != 0) { + archive_set_error(&a->archive, errno, + "Can't stat existing object"); + return (ARCHIVE_FAILED); + } + + /* + * NO_OVERWRITE_NEWER doesn't apply to directories. + */ + if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) + && !S_ISDIR(a->st.st_mode)) { + if (!older(&(a->st), a->entry)) { + archive_entry_unset_size(a->entry); + return (ARCHIVE_OK); + } + } + + /* If it's our archive, we're done. */ + 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, + "Refusing to overwrite archive"); + return (ARCHIVE_FAILED); + } + + if (!S_ISDIR(a->st.st_mode)) { + /* A non-dir is in the way, unlink it. */ + if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) + (void)clear_nochange_fflags(a); + if (unlink(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't unlink already-existing object"); + return (ARCHIVE_FAILED); + } + a->pst = NULL; + /* Try again. */ + en = create_filesystem_object(a); + } else if (!S_ISDIR(a->mode)) { + /* A dir is in the way of a non-dir, rmdir it. */ + if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) + (void)clear_nochange_fflags(a); + if (rmdir(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't replace existing directory with non-directory"); + return (ARCHIVE_FAILED); + } + /* Try again. */ + en = create_filesystem_object(a); + } else { + /* + * There's a dir in the way of a dir. Don't + * waste time with rmdir()/mkdir(), just fix + * up the permissions on the existing dir. + * Note that we don't change perms on existing + * dirs unless _EXTRACT_PERM is specified. + */ + if ((a->mode != a->st.st_mode) + && (a->todo & TODO_MODE_FORCE)) + a->deferred |= (a->todo & TODO_MODE); + /* Ownership doesn't need deferred fixup. */ + en = 0; /* Forget the EEXIST. */ + } + } + + if (en) { + /* Everything failed; give up here. */ + if ((&a->archive)->error == NULL) + archive_set_error(&a->archive, en, "Can't create '%s'", + a->name); + return (ARCHIVE_FAILED); + } + + a->pst = NULL; /* Cached stat data no longer valid. */ + return (ret); +} + +/* + * Returns 0 if creation succeeds, or else returns errno value from + * the failed system call. Note: This function should only ever perform + * a single system call. + */ +static int +create_filesystem_object(struct archive_write_disk *a) +{ + /* Create the entry. */ + const char *linkname; + mode_t final_mode, mode; + int r; + /* these for check_symlinks_fsobj */ + char *linkname_copy; /* non-const copy of linkname */ + struct stat st; + struct archive_string error_string; + int error_number; + + /* We identify hard/symlinks according to the link names. */ + /* Since link(2) and symlink(2) don't handle modes, we're done here. */ + linkname = archive_entry_hardlink(a->entry); + if (linkname != NULL) { +#if !HAVE_LINK + return (EPERM); +#else + archive_string_init(&error_string); + linkname_copy = strdup(linkname); + if (linkname_copy == NULL) { + return (EPERM); + } + /* + * TODO: consider using the cleaned-up path as the link + * target? + */ + r = cleanup_pathname_fsobj(linkname_copy, &error_number, + &error_string, a->flags); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + free(linkname_copy); + archive_string_free(&error_string); + /* + * EPERM is more appropriate than error_number for our + * callers + */ + return (EPERM); + } + r = check_symlinks_fsobj(linkname_copy, &error_number, + &error_string, a->flags); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + free(linkname_copy); + archive_string_free(&error_string); + /* + * EPERM is more appropriate than error_number for our + * callers + */ + return (EPERM); + } + free(linkname_copy); + archive_string_free(&error_string); + r = link(linkname, a->name) ? errno : 0; + /* + * New cpio and pax formats allow hardlink entries + * to carry data, so we may have to open the file + * for hardlink entries. + * + * If the hardlink was successfully created and + * the archive doesn't have carry data for it, + * consider it to be non-authoritative for meta data. + * This is consistent with GNU tar and BSD pax. + * If the hardlink does carry data, let the last + * archive entry decide ownership. + */ + if (r == 0 && a->filesize <= 0) { + a->todo = 0; + a->deferred = 0; + } else if (r == 0 && a->filesize > 0) { +#ifdef HAVE_LSTAT + r = lstat(a->name, &st); +#else + r = stat(a->name, &st); +#endif + if (r != 0) + r = errno; + else if ((st.st_mode & AE_IFMT) == AE_IFREG) { + a->fd = open(a->name, O_WRONLY | O_TRUNC | + O_BINARY | O_CLOEXEC | O_NOFOLLOW); + __archive_ensure_cloexec_flag(a->fd); + if (a->fd < 0) + r = errno; + } + } + return (r); +#endif + } + linkname = archive_entry_symlink(a->entry); + if (linkname != NULL) { +#if HAVE_SYMLINK + return symlink(linkname, a->name) ? errno : 0; +#else + return (EPERM); +#endif + } + + /* + * The remaining system calls all set permissions, so let's + * try to take advantage of that to avoid an extra chmod() + * call. (Recall that umask is set to zero right now!) + */ + + /* Mode we want for the final restored object (w/o file type bits). */ + final_mode = a->mode & 07777; + /* + * The mode that will actually be restored in this step. Note + * that SUID, SGID, etc, require additional work to ensure + * security, so we never restore them at this point. + */ + mode = final_mode & 0777 & ~a->user_umask; + + switch (a->mode & AE_IFMT) { + default: + /* POSIX requires that we fall through here. */ + /* FALLTHROUGH */ + case AE_IFREG: + a->fd = open(a->name, + O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); + __archive_ensure_cloexec_flag(a->fd); + r = (a->fd < 0); + break; + case AE_IFCHR: +#ifdef HAVE_MKNOD + /* Note: we use AE_IFCHR for the case label, and + * S_IFCHR for the mknod() call. This is correct. */ + r = mknod(a->name, mode | S_IFCHR, + archive_entry_rdev(a->entry)); + break; +#else + /* TODO: Find a better way to warn about our inability + * to restore a char device node. */ + return (EINVAL); +#endif /* HAVE_MKNOD */ + case AE_IFBLK: +#ifdef HAVE_MKNOD + r = mknod(a->name, mode | S_IFBLK, + archive_entry_rdev(a->entry)); + break; +#else + /* TODO: Find a better way to warn about our inability + * to restore a block device node. */ + return (EINVAL); +#endif /* HAVE_MKNOD */ + case AE_IFDIR: + mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; + r = mkdir(a->name, mode); + if (r == 0) { + /* Defer setting dir times. */ + a->deferred |= (a->todo & TODO_TIMES); + a->todo &= ~TODO_TIMES; + /* Never use an immediate chmod(). */ + /* We can't avoid the chmod() entirely if EXTRACT_PERM + * because of SysV SGID inheritance. */ + if ((mode != final_mode) + || (a->flags & ARCHIVE_EXTRACT_PERM)) + a->deferred |= (a->todo & TODO_MODE); + a->todo &= ~TODO_MODE; + } + break; + case AE_IFIFO: +#ifdef HAVE_MKFIFO + r = mkfifo(a->name, mode); + break; +#else + /* TODO: Find a better way to warn about our inability + * to restore a fifo. */ + return (EINVAL); +#endif /* HAVE_MKFIFO */ + } + + /* All the system calls above set errno on failure. */ + if (r) + return (errno); + + /* If we managed to set the final mode, we've avoided a chmod(). */ + if (mode == final_mode) + a->todo &= ~TODO_MODE; + return (0); +} + +/* + * Cleanup function for archive_extract. Mostly, this involves processing + * the fixup list, which is used to address a number of problems: + * * Dir permissions might prevent us from restoring a file in that + * dir, so we restore the dir with minimum 0700 permissions first, + * then correct the mode at the end. + * * Similarly, the act of restoring a file touches the directory + * and changes the timestamp on the dir, so we have to touch-up dir + * timestamps at the end as well. + * * Some file flags can interfere with the restore by, for example, + * preventing the creation of hardlinks to those files. + * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. + * + * Note that tar/cpio do not require that archives be in a particular + * order; there is no way to know when the last file has been restored + * within a directory, so there's no way to optimize the memory usage + * here by fixing up the directory any earlier than the + * end-of-archive. + * + * XXX TODO: Directory ACLs should be restored here, for the same + * reason we set directory perms here. XXX + */ +static int +_archive_write_disk_close(struct archive *_a) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *next, *p; + int ret; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_disk_close"); + ret = _archive_write_disk_finish_entry(&a->archive); + + /* Sort dir list so directories are fixed up in depth-first order. */ + p = sort_dir_list(a->fixup_list); + + while (p != NULL) { + a->pst = NULL; /* Mark stat cache as out-of-date. */ + if (p->fixup & TODO_TIMES) { + set_times(a, -1, p->mode, p->name, + p->atime, p->atime_nanos, + p->birthtime, p->birthtime_nanos, + p->mtime, p->mtime_nanos, + p->ctime, p->ctime_nanos); + } + if (p->fixup & TODO_MODE_BASE) + chmod(p->name, p->mode); + if (p->fixup & TODO_ACLS) + archive_write_disk_set_acls(&a->archive, -1, p->name, + &p->acl, p->mode); + if (p->fixup & TODO_FFLAGS) + set_fflags_platform(a, -1, p->name, + p->mode, p->fflags_set, 0); + if (p->fixup & TODO_MAC_METADATA) + set_mac_metadata(a, p->name, p->mac_metadata, + p->mac_metadata_size); + next = p->next; + archive_acl_clear(&p->acl); + free(p->mac_metadata); + free(p->name); + free(p); + p = next; + } + a->fixup_list = NULL; + return (ret); +} + +static int +_archive_write_disk_free(struct archive *_a) +{ + struct archive_write_disk *a; + int ret; + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); + a = (struct archive_write_disk *)_a; + ret = _archive_write_disk_close(&a->archive); + archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); + archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); + if (a->entry) + archive_entry_free(a->entry); + archive_string_free(&a->_name_data); + archive_string_free(&a->archive.error_string); + archive_string_free(&a->path_safe); + a->archive.magic = 0; + __archive_clean(&a->archive); + free(a->decmpfs_header_p); + free(a->resource_fork); + free(a->compressed_buffer); + free(a->uncompressed_buffer); +#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ + && defined(HAVE_ZLIB_H) + if (a->stream_valid) { + switch (deflateEnd(&a->stream)) { + case Z_OK: + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; + break; + } + } +#endif + free(a); + return (ret); +} + +/* + * Simple O(n log n) merge sort to order the fixup list. In + * particular, we want to restore dir timestamps depth-first. + */ +static struct fixup_entry * +sort_dir_list(struct fixup_entry *p) +{ + struct fixup_entry *a, *b, *t; + + if (p == NULL) + return (NULL); + /* A one-item list is already sorted. */ + if (p->next == NULL) + return (p); + + /* Step 1: split the list. */ + t = p; + a = p->next->next; + while (a != NULL) { + /* Step a twice, t once. */ + a = a->next; + if (a != NULL) + a = a->next; + t = t->next; + } + /* Now, t is at the mid-point, so break the list here. */ + b = t->next; + t->next = NULL; + a = p; + + /* Step 2: Recursively sort the two sub-lists. */ + a = sort_dir_list(a); + b = sort_dir_list(b); + + /* Step 3: Merge the returned lists. */ + /* Pick the first element for the merged list. */ + if (strcmp(a->name, b->name) > 0) { + t = p = a; + a = a->next; + } else { + t = p = b; + b = b->next; + } + + /* Always put the later element on the list first. */ + while (a != NULL && b != NULL) { + if (strcmp(a->name, b->name) > 0) { + t->next = a; + a = a->next; + } else { + t->next = b; + b = b->next; + } + t = t->next; + } + + /* Only one list is non-empty, so just splice it on. */ + if (a != NULL) + t->next = a; + if (b != NULL) + t->next = b; + + return (p); +} + +/* + * Returns a new, initialized fixup entry. + * + * TODO: Reduce the memory requirements for this list by using a tree + * structure rather than a simple list of names. + */ +static struct fixup_entry * +new_fixup(struct archive_write_disk *a, const char *pathname) +{ + struct fixup_entry *fe; + + fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); + if (fe == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for a fixup"); + return (NULL); + } + fe->next = a->fixup_list; + a->fixup_list = fe; + fe->fixup = 0; + fe->name = strdup(pathname); + return (fe); +} + +/* + * Returns a fixup structure for the current entry. + */ +static struct fixup_entry * +current_fixup(struct archive_write_disk *a, const char *pathname) +{ + if (a->current_fixup == NULL) + a->current_fixup = new_fixup(a, pathname); + return (a->current_fixup); +} + +/* Error helper for new *_fsobj functions */ +static void +fsobj_error(int *a_eno, struct archive_string *a_estr, + int err, const char *errstr, const char *path) +{ + if (a_eno) + *a_eno = err; + if (a_estr) + archive_string_sprintf(a_estr, "%s%s", errstr, path); +} + +/* + * TODO: Someday, integrate this with the deep dir support; they both + * scan the path and both can be optimized by comparing against other + * recent paths. + */ +/* TODO: Extend this to support symlinks on Windows Vista and later. */ + +/* + * Checks the given path to see if any elements along it are symlinks. Returns + * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. + */ +static int +check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, + int flags) +{ +#if !defined(HAVE_LSTAT) + /* Platform doesn't have lstat, so we can't look for symlinks. */ + (void)path; /* UNUSED */ + (void)error_number; /* UNUSED */ + (void)error_string; /* UNUSED */ + (void)flags; /* UNUSED */ + return (ARCHIVE_OK); +#else + int res = ARCHIVE_OK; + char *tail; + char *head; + int last; + char c; + int r; + struct stat st; + int restore_pwd; + + /* Nothing to do here if name is empty */ + if(path[0] == '\0') + return (ARCHIVE_OK); + + /* + * Guard against symlink tricks. Reject any archive entry whose + * destination would be altered by a symlink. + * + * Walk the filename in chunks separated by '/'. For each segment: + * - if it doesn't exist, continue + * - if it's symlink, abort or remove it + * - if it's a directory and it's not the last chunk, cd into it + * As we go: + * head points to the current (relative) path + * tail points to the temporary \0 terminating the segment we're + * currently examining + * c holds what used to be in *tail + * last is 1 if this is the last tail + */ + restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(restore_pwd); + if (restore_pwd < 0) + return (ARCHIVE_FATAL); + head = path; + tail = path; + last = 0; + /* TODO: reintroduce a safe cache here? */ + /* Skip the root directory if the path is absolute. */ + if(tail == path && tail[0] == '/') + ++tail; + /* Keep going until we've checked the entire name. + * head, tail, path all alias the same string, which is + * temporarily zeroed at tail, so be careful restoring the + * stashed (c=tail[0]) for error messages. + * Exiting the loop with break is okay; continue is not. + */ + while (!last) { + /* + * Skip the separator we just consumed, plus any adjacent ones + */ + while (*tail == '/') + ++tail; + /* Skip the next path element. */ + while (*tail != '\0' && *tail != '/') + ++tail; + /* is this the last path component? */ + last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); + /* temporarily truncate the string here */ + c = tail[0]; + tail[0] = '\0'; + /* Check that we haven't hit a symlink. */ + r = lstat(head, &st); + if (r != 0) { + tail[0] = c; + /* We've hit a dir that doesn't exist; stop now. */ + if (errno == ENOENT) { + break; + } else { + /* + * Treat any other error as fatal - best to be + * paranoid here. + * Note: This effectively disables deep + * directory support when security checks are + * enabled. Otherwise, very long pathnames that + * trigger an error here could evade the + * sandbox. + * TODO: We could do better, but it would + * probably require merging the symlink checks + * with the deep-directory editing. + */ + fsobj_error(a_eno, a_estr, errno, + "Could not stat ", path); + res = ARCHIVE_FAILED; + break; + } + } else if (S_ISDIR(st.st_mode)) { + if (!last) { + if (chdir(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, errno, + "Could not chdir ", path); + res = (ARCHIVE_FATAL); + break; + } + /* Our view is now from inside this dir: */ + head = tail + 1; + } + } else if (S_ISLNK(st.st_mode)) { + if (last) { + /* + * Last element is symlink; remove it + * so we can overwrite it with the + * item being extracted. + */ + if (unlink(head)) { + tail[0] = c; + fsobj_error(a_eno, a_estr, errno, + "Could not remove symlink ", + path); + res = ARCHIVE_FAILED; + break; + } + /* + * Even if we did remove it, a warning + * is in order. The warning is silly, + * though, if we're just replacing one + * symlink with another symlink. + */ + tail[0] = c; + /* + * FIXME: not sure how important this is to + * restore + */ + /* + if (!S_ISLNK(path)) { + fsobj_error(a_eno, a_estr, 0, + "Removing symlink ", path); + } + */ + /* Symlink gone. No more problem! */ + res = ARCHIVE_OK; + break; + } else if (flags & ARCHIVE_EXTRACT_UNLINK) { + /* User asked us to remove problems. */ + if (unlink(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot remove intervening " + "symlink ", path); + res = ARCHIVE_FAILED; + break; + } + tail[0] = c; + } else if ((flags & + ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) { + /* + * We are not the last element and we want to + * follow symlinks if they are a directory. + * + * This is needed to extract hardlinks over + * symlinks. + */ + r = stat(head, &st); + if (r != 0) { + tail[0] = c; + if (errno == ENOENT) { + break; + } else { + fsobj_error(a_eno, a_estr, + errno, + "Could not stat ", path); + res = (ARCHIVE_FAILED); + break; + } + } else if (S_ISDIR(st.st_mode)) { + if (chdir(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, + errno, + "Could not chdir ", path); + res = (ARCHIVE_FATAL); + break; + } + /* + * Our view is now from inside + * this dir: + */ + head = tail + 1; + } else { + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot extract through " + "symlink ", path); + res = ARCHIVE_FAILED; + break; + } + } else { + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot extract through symlink ", path); + res = ARCHIVE_FAILED; + break; + } + } + /* be sure to always maintain this */ + tail[0] = c; + if (tail[0] != '\0') + tail++; /* Advance to the next segment. */ + } + /* Catches loop exits via break */ + tail[0] = c; +#ifdef HAVE_FCHDIR + /* If we changed directory above, restore it here. */ + if (restore_pwd >= 0) { + r = fchdir(restore_pwd); + if (r != 0) { + fsobj_error(a_eno, a_estr, errno, + "chdir() failure", ""); + } + close(restore_pwd); + restore_pwd = -1; + if (r != 0) { + res = (ARCHIVE_FATAL); + } + } +#endif + /* TODO: reintroduce a safe cache here? */ + return res; +#endif +} + +/* + * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise + * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} + */ +static int +check_symlinks(struct archive_write_disk *a) +{ + struct archive_string error_string; + int error_number; + int rc; + archive_string_init(&error_string); + rc = check_symlinks_fsobj(a->name, &error_number, &error_string, + a->flags); + if (rc != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + } + archive_string_free(&error_string); + a->pst = NULL; /* to be safe */ + return rc; +} + + +#if defined(__CYGWIN__) +/* + * 1. Convert a path separator from '\' to '/' . + * We shouldn't check multibyte character directly because some + * character-set have been using the '\' character for a part of + * its multibyte character code. + * 2. Replace unusable characters in Windows with underscore('_'). + * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx + */ +static void +cleanup_pathname_win(char *path) +{ + wchar_t wc; + char *p; + size_t alen, l; + int mb, complete, utf8; + + alen = 0; + mb = 0; + complete = 1; + utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; + for (p = path; *p != '\0'; p++) { + ++alen; + if (*p == '\\') { + /* If previous byte is smaller than 128, + * this is not second byte of multibyte characters, + * so we can replace '\' with '/'. */ + if (utf8 || !mb) + *p = '/'; + else + complete = 0;/* uncompleted. */ + } else if (*(unsigned char *)p > 127) + mb = 1; + else + mb = 0; + /* Rewrite the path name if its next character is unusable. */ + if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || + *p == '<' || *p == '>' || *p == '|') + *p = '_'; + } + if (complete) + return; + + /* + * Convert path separator in wide-character. + */ + p = path; + while (*p != '\0' && alen) { + l = mbtowc(&wc, p, alen); + if (l == (size_t)-1) { + while (*p != '\0') { + if (*p == '\\') + *p = '/'; + ++p; + } + break; + } + if (l == 1 && wc == L'\\') + *p = '/'; + p += l; + alen -= l; + } +} +#endif + +/* + * Canonicalize the pathname. In particular, this strips duplicate + * '/' characters, '.' elements, and trailing '/'. It also raises an + * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is + * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS + * is set) if the path is absolute. + */ +static int +cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr, + int flags) +{ + char *dest, *src; + char separator = '\0'; + + dest = src = path; + if (*src == '\0') { + fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, + "Invalid empty ", "pathname"); + return (ARCHIVE_FAILED); + } + +#if defined(__CYGWIN__) + cleanup_pathname_win(path); +#endif + /* Skip leading '/'. */ + if (*src == '/') { + if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { + fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, + "Path is ", "absolute"); + return (ARCHIVE_FAILED); + } + + separator = *src++; + } + + /* Scan the pathname one element at a time. */ + for (;;) { + /* src points to first char after '/' */ + if (src[0] == '\0') { + break; + } else if (src[0] == '/') { + /* Found '//', ignore second one. */ + src++; + continue; + } else if (src[0] == '.') { + if (src[1] == '\0') { + /* Ignore trailing '.' */ + break; + } else if (src[1] == '/') { + /* Skip './'. */ + src += 2; + continue; + } else if (src[1] == '.') { + if (src[2] == '/' || src[2] == '\0') { + /* Conditionally warn about '..' */ + if (flags + & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { + fsobj_error(a_eno, a_estr, + ARCHIVE_ERRNO_MISC, + "Path contains ", "'..'"); + return (ARCHIVE_FAILED); + } + } + /* + * Note: Under no circumstances do we + * remove '..' elements. In + * particular, restoring + * '/foo/../bar/' should create the + * 'foo' dir as a side-effect. + */ + } + } + + /* Copy current element, including leading '/'. */ + if (separator) + *dest++ = '/'; + while (*src != '\0' && *src != '/') { + *dest++ = *src++; + } + + if (*src == '\0') + break; + + /* Skip '/' separator. */ + separator = *src++; + } + /* + * We've just copied zero or more path elements, not including the + * final '/'. + */ + if (dest == path) { + /* + * Nothing got copied. The path must have been something + * like '.' or '/' or './' or '/././././/./'. + */ + if (separator) + *dest++ = '/'; + else + *dest++ = '.'; + } + /* Terminate the result. */ + *dest = '\0'; + return (ARCHIVE_OK); +} + +static int +cleanup_pathname(struct archive_write_disk *a) +{ + struct archive_string error_string; + int error_number; + int rc; + archive_string_init(&error_string); + rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, + a->flags); + if (rc != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + } + archive_string_free(&error_string); + return rc; +} + +/* + * Create the parent directory of the specified path, assuming path + * is already in mutable storage. + */ +static int +create_parent_dir(struct archive_write_disk *a, char *path) +{ + char *slash; + int r; + + /* Remove tail element to obtain parent name. */ + slash = strrchr(path, '/'); + if (slash == NULL) + return (ARCHIVE_OK); + *slash = '\0'; + r = create_dir(a, path); + *slash = '/'; + return (r); +} + +/* + * Create the specified dir, recursing to create parents as necessary. + * + * Returns ARCHIVE_OK if the path exists when we're done here. + * Otherwise, returns ARCHIVE_FAILED. + * Assumes path is in mutable storage; path is unchanged on exit. + */ +static int +create_dir(struct archive_write_disk *a, char *path) +{ + struct stat st; + struct fixup_entry *le; + char *slash, *base; + mode_t mode_final, mode; + int r; + + /* Check for special names and just skip them. */ + slash = strrchr(path, '/'); + if (slash == NULL) + base = path; + else + base = slash + 1; + + if (base[0] == '\0' || + (base[0] == '.' && base[1] == '\0') || + (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { + /* Don't bother trying to create null path, '.', or '..'. */ + if (slash != NULL) { + *slash = '\0'; + r = create_dir(a, path); + *slash = '/'; + return (r); + } + return (ARCHIVE_OK); + } + + /* + * Yes, this should be stat() and not lstat(). Using lstat() + * here loses the ability to extract through symlinks. Also note + * that this should not use the a->st cache. + */ + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) + return (ARCHIVE_OK); + if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { + archive_set_error(&a->archive, EEXIST, + "Can't create directory '%s'", path); + return (ARCHIVE_FAILED); + } + if (unlink(path) != 0) { + archive_set_error(&a->archive, errno, + "Can't create directory '%s': " + "Conflicting file cannot be removed", + path); + return (ARCHIVE_FAILED); + } + } else if (errno != ENOENT && errno != ENOTDIR) { + /* Stat failed? */ + archive_set_error(&a->archive, errno, + "Can't test directory '%s'", path); + return (ARCHIVE_FAILED); + } else if (slash != NULL) { + *slash = '\0'; + r = create_dir(a, path); + *slash = '/'; + if (r != ARCHIVE_OK) + return (r); + } + + /* + * Mode we want for the final restored directory. Per POSIX, + * implicitly-created dirs must be created obeying the umask. + * There's no mention whether this is different for privileged + * restores (which the rest of this code handles by pretending + * umask=0). I've chosen here to always obey the user's umask for + * implicit dirs, even if _EXTRACT_PERM was specified. + */ + mode_final = DEFAULT_DIR_MODE & ~a->user_umask; + /* Mode we want on disk during the restore process. */ + mode = mode_final; + mode |= MINIMUM_DIR_MODE; + mode &= MAXIMUM_DIR_MODE; + if (mkdir(path, mode) == 0) { + if (mode != mode_final) { + le = new_fixup(a, path); + if (le == NULL) + return (ARCHIVE_FATAL); + le->fixup |=TODO_MODE_BASE; + le->mode = mode_final; + } + return (ARCHIVE_OK); + } + + /* + * Without the following check, a/b/../b/c/d fails at the + * second visit to 'b', so 'd' can't be created. Note that we + * don't add it to the fixup list here, as it's already been + * added. + */ + if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) + return (ARCHIVE_OK); + + archive_set_error(&a->archive, errno, "Failed to create dir '%s'", + path); + return (ARCHIVE_FAILED); +} + +/* + * Note: Although we can skip setting the user id if the desired user + * id matches the current user, we cannot skip setting the group, as + * many systems set the gid based on the containing directory. So + * we have to perform a chown syscall if we want to set the SGID + * bit. (The alternative is to stat() and then possibly chown(); it's + * more efficient to skip the stat() and just always chown().) Note + * that a successful chown() here clears the TODO_SGID_CHECK bit, which + * allows set_mode to skip the stat() check for the GID. + */ +static int +set_ownership(struct archive_write_disk *a) +{ +#ifndef __CYGWIN__ +/* unfortunately, on win32 there is no 'root' user with uid 0, + so we just have to try the chown and see if it works */ + + /* If we know we can't change it, don't bother trying. */ + if (a->user_uid != 0 && a->user_uid != a->uid) { + archive_set_error(&a->archive, errno, + "Can't set UID=%jd", (intmax_t)a->uid); + return (ARCHIVE_WARN); + } +#endif + +#ifdef HAVE_FCHOWN + /* If we have an fd, we can avoid a race. */ + if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } +#endif + + /* We prefer lchown() but will use chown() if that's all we have. */ + /* Of course, if we have neither, this will always fail. */ +#ifdef HAVE_LCHOWN + if (lchown(a->name, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } +#elif HAVE_CHOWN + if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } +#endif + + archive_set_error(&a->archive, errno, + "Can't set user=%jd/group=%jd for %s", + (intmax_t)a->uid, (intmax_t)a->gid, a->name); + return (ARCHIVE_WARN); +} + +/* + * Note: Returns 0 on success, non-zero on failure. + */ +static int +set_time(int fd, int mode, const char *name, + time_t atime, long atime_nsec, + time_t mtime, long mtime_nsec) +{ + /* Select the best implementation for this platform. */ +#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) + /* + * utimensat() and futimens() are defined in + * POSIX.1-2008. They support ns resolution and setting times + * on fds and symlinks. + */ + struct timespec ts[2]; + (void)mode; /* UNUSED */ + ts[0].tv_sec = atime; + ts[0].tv_nsec = atime_nsec; + ts[1].tv_sec = mtime; + ts[1].tv_nsec = mtime_nsec; + if (fd >= 0) + return futimens(fd, ts); + return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); + +#elif HAVE_UTIMES + /* + * The utimes()-family functions support µs-resolution and + * setting times fds and symlinks. utimes() is documented as + * LEGACY by POSIX, futimes() and lutimes() are not described + * in POSIX. + */ + struct timeval times[2]; + + times[0].tv_sec = atime; + times[0].tv_usec = atime_nsec / 1000; + times[1].tv_sec = mtime; + times[1].tv_usec = mtime_nsec / 1000; + +#ifdef HAVE_FUTIMES + if (fd >= 0) + return (futimes(fd, times)); +#else + (void)fd; /* UNUSED */ +#endif +#ifdef HAVE_LUTIMES + (void)mode; /* UNUSED */ + return (lutimes(name, times)); +#else + if (S_ISLNK(mode)) + return (0); + return (utimes(name, times)); +#endif + +#elif defined(HAVE_UTIME) + /* + * utime() is POSIX-standard but only supports 1s resolution and + * does not support fds or symlinks. + */ + struct utimbuf times; + (void)fd; /* UNUSED */ + (void)name; /* UNUSED */ + (void)atime_nsec; /* UNUSED */ + (void)mtime_nsec; /* UNUSED */ + times.actime = atime; + times.modtime = mtime; + if (S_ISLNK(mode)) + return (ARCHIVE_OK); + return (utime(name, ×)); + +#else + /* + * We don't know how to set the time on this platform. + */ + (void)fd; /* UNUSED */ + (void)mode; /* UNUSED */ + (void)name; /* UNUSED */ + (void)atime_nsec; /* UNUSED */ + (void)mtime_nsec; /* UNUSED */ + return (ARCHIVE_WARN); +#endif +} + +#ifdef F_SETTIMES +static int +set_time_tru64(int fd, int mode, const char *name, + time_t atime, long atime_nsec, + time_t mtime, long mtime_nsec, + time_t ctime, long ctime_nsec) +{ + struct attr_timbuf tstamp; + tstamp.atime.tv_sec = atime; + tstamp.mtime.tv_sec = mtime; + tstamp.ctime.tv_sec = ctime; +#if defined (__hpux) && defined (__ia64) + tstamp.atime.tv_nsec = atime_nsec; + tstamp.mtime.tv_nsec = mtime_nsec; + tstamp.ctime.tv_nsec = ctime_nsec; +#else + tstamp.atime.tv_usec = atime_nsec / 1000; + tstamp.mtime.tv_usec = mtime_nsec / 1000; + tstamp.ctime.tv_usec = ctime_nsec / 1000; +#endif + return (fcntl(fd,F_SETTIMES,&tstamp)); +} +#endif /* F_SETTIMES */ + +static int +set_times(struct archive_write_disk *a, + int fd, int mode, const char *name, + time_t atime, long atime_nanos, + time_t birthtime, long birthtime_nanos, + time_t mtime, long mtime_nanos, + time_t cctime, long ctime_nanos) +{ + /* Note: set_time doesn't use libarchive return conventions! + * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ + int r1 = 0, r2 = 0; + +#ifdef F_SETTIMES + /* + * on Tru64 try own fcntl first which can restore even the + * ctime, fall back to default code path below if it fails + * or if we are not running as root + */ + if (a->user_uid == 0 && + set_time_tru64(fd, mode, name, + atime, atime_nanos, mtime, + mtime_nanos, cctime, ctime_nanos) == 0) { + return (ARCHIVE_OK); + } +#else /* Tru64 */ + (void)cctime; /* UNUSED */ + (void)ctime_nanos; /* UNUSED */ +#endif /* Tru64 */ + +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + /* + * If you have struct stat.st_birthtime, we assume BSD + * birthtime semantics, in which {f,l,}utimes() updates + * birthtime to earliest mtime. So we set the time twice, + * first using the birthtime, then using the mtime. If + * birthtime == mtime, this isn't necessary, so we skip it. + * If birthtime > mtime, then this won't work, so we skip it. + */ + if (birthtime < mtime + || (birthtime == mtime && birthtime_nanos < mtime_nanos)) + r1 = set_time(fd, mode, name, + atime, atime_nanos, + birthtime, birthtime_nanos); +#else + (void)birthtime; /* UNUSED */ + (void)birthtime_nanos; /* UNUSED */ +#endif + r2 = set_time(fd, mode, name, + atime, atime_nanos, + mtime, mtime_nanos); + if (r1 != 0 || r2 != 0) { + archive_set_error(&a->archive, errno, + "Can't restore time"); + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); +} + +static int +set_times_from_entry(struct archive_write_disk *a) +{ + time_t atime, birthtime, mtime, cctime; + long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; + + /* Suitable defaults. */ + atime = birthtime = mtime = cctime = a->start_time; + atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; + + /* If no time was provided, we're done. */ + if (!archive_entry_atime_is_set(a->entry) +#if HAVE_STRUCT_STAT_ST_BIRTHTIME + && !archive_entry_birthtime_is_set(a->entry) +#endif + && !archive_entry_mtime_is_set(a->entry)) + return (ARCHIVE_OK); + + if (archive_entry_atime_is_set(a->entry)) { + atime = archive_entry_atime(a->entry); + atime_nsec = archive_entry_atime_nsec(a->entry); + } + if (archive_entry_birthtime_is_set(a->entry)) { + birthtime = archive_entry_birthtime(a->entry); + birthtime_nsec = archive_entry_birthtime_nsec(a->entry); + } + if (archive_entry_mtime_is_set(a->entry)) { + mtime = archive_entry_mtime(a->entry); + mtime_nsec = archive_entry_mtime_nsec(a->entry); + } + if (archive_entry_ctime_is_set(a->entry)) { + cctime = archive_entry_ctime(a->entry); + ctime_nsec = archive_entry_ctime_nsec(a->entry); + } + + return set_times(a, a->fd, a->mode, a->name, + atime, atime_nsec, + birthtime, birthtime_nsec, + mtime, mtime_nsec, + cctime, ctime_nsec); +} + +static int +set_mode(struct archive_write_disk *a, int mode) +{ + int r = ARCHIVE_OK; + mode &= 07777; /* Strip off file type bits. */ + + if (a->todo & TODO_SGID_CHECK) { + /* + * If we don't know the GID is right, we must stat() + * to verify it. We can't just check the GID of this + * process, since systems sometimes set GID from + * the enclosing dir or based on ACLs. + */ + if ((r = lazy_stat(a)) != ARCHIVE_OK) + return (r); + if (a->pst->st_gid != a->gid) { + mode &= ~ S_ISGID; + if (a->flags & ARCHIVE_EXTRACT_OWNER) { + /* + * This is only an error if you + * requested owner restore. If you + * didn't, we'll try to restore + * sgid/suid, but won't consider it a + * problem if we can't. + */ + archive_set_error(&a->archive, -1, + "Can't restore SGID bit"); + r = ARCHIVE_WARN; + } + } + /* While we're here, double-check the UID. */ + if (a->pst->st_uid != a->uid + && (a->todo & TODO_SUID)) { + mode &= ~ S_ISUID; + if (a->flags & ARCHIVE_EXTRACT_OWNER) { + archive_set_error(&a->archive, -1, + "Can't restore SUID bit"); + r = ARCHIVE_WARN; + } + } + a->todo &= ~TODO_SGID_CHECK; + a->todo &= ~TODO_SUID_CHECK; + } else if (a->todo & TODO_SUID_CHECK) { + /* + * If we don't know the UID is right, we can just check + * the user, since all systems set the file UID from + * the process UID. + */ + if (a->user_uid != a->uid) { + mode &= ~ S_ISUID; + if (a->flags & ARCHIVE_EXTRACT_OWNER) { + archive_set_error(&a->archive, -1, + "Can't make file SUID"); + r = ARCHIVE_WARN; + } + } + a->todo &= ~TODO_SUID_CHECK; + } + + if (S_ISLNK(a->mode)) { +#ifdef HAVE_LCHMOD + /* + * If this is a symlink, use lchmod(). If the + * platform doesn't support lchmod(), just skip it. A + * platform that doesn't provide a way to set + * permissions on symlinks probably ignores + * permissions on symlinks, so a failure here has no + * impact. + */ + if (lchmod(a->name, mode) != 0) { + switch (errno) { + case ENOTSUP: + case ENOSYS: +#if ENOTSUP != EOPNOTSUPP + case EOPNOTSUPP: +#endif + /* + * if lchmod is defined but the platform + * doesn't support it, silently ignore + * error + */ + break; + default: + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } + } +#endif + } else if (!S_ISDIR(a->mode)) { + /* + * If it's not a symlink and not a dir, then use + * fchmod() or chmod(), depending on whether we have + * an fd. Dirs get their perms set during the + * post-extract fixup, which is handled elsewhere. + */ +#ifdef HAVE_FCHMOD + if (a->fd >= 0) { + if (fchmod(a->fd, mode) != 0) { + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } + } else +#endif + /* If this platform lacks fchmod(), then + * we'll just use chmod(). */ + if (chmod(a->name, mode) != 0) { + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } + } + return (r); +} + +static int +set_fflags(struct archive_write_disk *a) +{ + struct fixup_entry *le; + unsigned long set, clear; + int r; + int critical_flags; + mode_t mode = archive_entry_mode(a->entry); + + /* + * Make 'critical_flags' hold all file flags that can't be + * immediately restored. For example, on BSD systems, + * SF_IMMUTABLE prevents hardlinks from being created, so + * should not be set until after any hardlinks are created. To + * preserve some semblance of portability, this uses #ifdef + * extensively. Ugly, but it works. + * + * Yes, Virginia, this does create a security race. It's mitigated + * somewhat by the practice of creating dirs 0700 until the extract + * is done, but it would be nice if we could do more than that. + * People restoring critical file systems should be wary of + * other programs that might try to muck with files as they're + * being restored. + */ + /* Hopefully, the compiler will optimize this mess into a constant. */ + critical_flags = 0; +#ifdef SF_IMMUTABLE + critical_flags |= SF_IMMUTABLE; +#endif +#ifdef UF_IMMUTABLE + critical_flags |= UF_IMMUTABLE; +#endif +#ifdef SF_APPEND + critical_flags |= SF_APPEND; +#endif +#ifdef UF_APPEND + critical_flags |= UF_APPEND; +#endif +#if defined(FS_APPEND_FL) + critical_flags |= FS_APPEND_FL; +#elif defined(EXT2_APPEND_FL) + critical_flags |= EXT2_APPEND_FL; +#endif +#if defined(FS_IMMUTABLE_FL) + critical_flags |= FS_IMMUTABLE_FL; +#elif defined(EXT2_IMMUTABLE_FL) + critical_flags |= EXT2_IMMUTABLE_FL; +#endif +#ifdef FS_JOURNAL_DATA_FL + critical_flags |= FS_JOURNAL_DATA_FL; +#endif + + if (a->todo & TODO_FFLAGS) { + archive_entry_fflags(a->entry, &set, &clear); + + /* + * The first test encourages the compiler to eliminate + * all of this if it's not necessary. + */ + if ((critical_flags != 0) && (set & critical_flags)) { + le = current_fixup(a, a->name); + if (le == NULL) + return (ARCHIVE_FATAL); + le->fixup |= TODO_FFLAGS; + le->fflags_set = set; + /* Store the mode if it's not already there. */ + if ((le->fixup & TODO_MODE) == 0) + le->mode = mode; + } else { + r = set_fflags_platform(a, a->fd, + a->name, mode, set, clear); + if (r != ARCHIVE_OK) + return (r); + } + } + return (ARCHIVE_OK); +} + +static int +clear_nochange_fflags(struct archive_write_disk *a) +{ + int nochange_flags; + mode_t mode = archive_entry_mode(a->entry); + + /* Hopefully, the compiler will optimize this mess into a constant. */ + nochange_flags = 0; +#ifdef SF_IMMUTABLE + nochange_flags |= SF_IMMUTABLE; +#endif +#ifdef UF_IMMUTABLE + nochange_flags |= UF_IMMUTABLE; +#endif +#ifdef SF_APPEND + nochange_flags |= SF_APPEND; +#endif +#ifdef UF_APPEND + nochange_flags |= UF_APPEND; +#endif +#ifdef EXT2_APPEND_FL + nochange_flags |= EXT2_APPEND_FL; +#endif +#ifdef EXT2_IMMUTABLE_FL + nochange_flags |= EXT2_IMMUTABLE_FL; +#endif + + return (set_fflags_platform(a, a->fd, a->name, mode, 0, + nochange_flags)); +} + + +#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) +/* + * BSD reads flags using stat() and sets them with one of {f,l,}chflags() + */ +static int +set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, + mode_t mode, unsigned long set, unsigned long clear) +{ + int r; + + (void)mode; /* UNUSED */ + if (set == 0 && clear == 0) + return (ARCHIVE_OK); + + /* + * XXX Is the stat here really necessary? Or can I just use + * the 'set' flags directly? In particular, I'm not sure + * about the correct approach if we're overwriting an existing + * file that already has flags on it. XXX + */ + if ((r = lazy_stat(a)) != ARCHIVE_OK) + return (r); + + a->st.st_flags &= ~clear; + a->st.st_flags |= set; +#ifdef HAVE_FCHFLAGS + /* If platform has fchflags() and we were given an fd, use it. */ + if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) + return (ARCHIVE_OK); +#endif + /* + * If we can't use the fd to set the flags, we'll use the + * pathname to set flags. We prefer lchflags() but will use + * chflags() if we must. + */ +#ifdef HAVE_LCHFLAGS + if (lchflags(name, a->st.st_flags) == 0) + return (ARCHIVE_OK); +#elif defined(HAVE_CHFLAGS) + if (S_ISLNK(a->st.st_mode)) { + archive_set_error(&a->archive, errno, + "Can't set file flags on symlink."); + return (ARCHIVE_WARN); + } + if (chflags(name, a->st.st_flags) == 0) + return (ARCHIVE_OK); +#endif + archive_set_error(&a->archive, errno, + "Failed to set file flags"); + return (ARCHIVE_WARN); +} + +#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \ + defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ + (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \ + defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) +/* + * Linux uses ioctl() to read and write file flags. + */ +static int +set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, + mode_t mode, unsigned long set, unsigned long clear) +{ + int ret; + int myfd = fd; + int newflags, oldflags; + int sf_mask = 0; + + if (set == 0 && clear == 0) + return (ARCHIVE_OK); + /* Only regular files and dirs can have flags. */ + if (!S_ISREG(mode) && !S_ISDIR(mode)) + return (ARCHIVE_OK); + + /* If we weren't given an fd, open it ourselves. */ + if (myfd < 0) { + myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(myfd); + } + if (myfd < 0) + return (ARCHIVE_OK); + + /* + * Linux has no define for the flags that are only settable by + * the root user. This code may seem a little complex, but + * there seem to be some Linux systems that lack these + * defines. (?) The code below degrades reasonably gracefully + * if sf_mask is incomplete. + */ +#if defined(FS_IMMUTABLE_FL) + sf_mask |= FS_IMMUTABLE_FL; +#elif defined(EXT2_IMMUTABLE_FL) + sf_mask |= EXT2_IMMUTABLE_FL; +#endif +#if defined(FS_APPEND_FL) + sf_mask |= FS_APPEND_FL; +#elif defined(EXT2_APPEND_FL) + sf_mask |= EXT2_APPEND_FL; +#endif +#if defined(FS_JOURNAL_DATA_FL) + sf_mask |= FS_JOURNAL_DATA_FL; +#endif + /* + * XXX As above, this would be way simpler if we didn't have + * to read the current flags from disk. XXX + */ + ret = ARCHIVE_OK; + + /* Read the current file flags. */ + if (ioctl(myfd, +#ifdef FS_IOC_GETFLAGS + FS_IOC_GETFLAGS, +#else + EXT2_IOC_GETFLAGS, +#endif + &oldflags) < 0) + goto fail; + + /* Try setting the flags as given. */ + newflags = (oldflags & ~clear) | set; + if (ioctl(myfd, +#ifdef FS_IOC_SETFLAGS + FS_IOC_SETFLAGS, +#else + EXT2_IOC_SETFLAGS, +#endif + &newflags) >= 0) + goto cleanup; + if (errno != EPERM) + goto fail; + + /* If we couldn't set all the flags, try again with a subset. */ + newflags &= ~sf_mask; + oldflags &= sf_mask; + newflags |= oldflags; + if (ioctl(myfd, +#ifdef FS_IOC_SETFLAGS + FS_IOC_SETFLAGS, +#else + EXT2_IOC_SETFLAGS, +#endif + &newflags) >= 0) + goto cleanup; + + /* We couldn't set the flags, so report the failure. */ +fail: + archive_set_error(&a->archive, errno, + "Failed to set file flags"); + ret = ARCHIVE_WARN; +cleanup: + if (fd < 0) + close(myfd); + return (ret); +} + +#else + +/* + * Of course, some systems have neither BSD chflags() nor Linux' flags + * support through ioctl(). + */ +static int +set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, + mode_t mode, unsigned long set, unsigned long clear) +{ + (void)a; /* UNUSED */ + (void)fd; /* UNUSED */ + (void)name; /* UNUSED */ + (void)mode; /* UNUSED */ + (void)set; /* UNUSED */ + (void)clear; /* UNUSED */ + return (ARCHIVE_OK); +} + +#endif /* __linux */ + +#ifndef HAVE_COPYFILE_H +/* Default is to simply drop Mac extended metadata. */ +static int +set_mac_metadata(struct archive_write_disk *a, const char *pathname, + const void *metadata, size_t metadata_size) +{ + (void)a; /* UNUSED */ + (void)pathname; /* UNUSED */ + (void)metadata; /* UNUSED */ + (void)metadata_size; /* UNUSED */ + return (ARCHIVE_OK); +} + +static int +fixup_appledouble(struct archive_write_disk *a, const char *pathname) +{ + (void)a; /* UNUSED */ + (void)pathname; /* UNUSED */ + return (ARCHIVE_OK); +} +#else + +/* + * On Mac OS, we use copyfile() to unpack the metadata and + * apply it to the target file. + */ + +#if defined(HAVE_SYS_XATTR_H) +static int +copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) +{ + ssize_t xattr_size; + char *xattr_names = NULL, *xattr_val = NULL; + int ret = ARCHIVE_OK, xattr_i; + + xattr_size = flistxattr(tmpfd, NULL, 0, 0); + if (xattr_size == -1) { + archive_set_error(&a->archive, errno, + "Failed to read metadata(xattr)"); + ret = ARCHIVE_WARN; + goto exit_xattr; + } + xattr_names = malloc(xattr_size); + if (xattr_names == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for metadata(xattr)"); + ret = ARCHIVE_FATAL; + goto exit_xattr; + } + xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); + if (xattr_size == -1) { + archive_set_error(&a->archive, errno, + "Failed to read metadata(xattr)"); + ret = ARCHIVE_WARN; + goto exit_xattr; + } + for (xattr_i = 0; xattr_i < xattr_size; + xattr_i += strlen(xattr_names + xattr_i) + 1) { + char *xattr_val_saved; + ssize_t s; + int f; + + s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get metadata(xattr)"); + ret = ARCHIVE_WARN; + goto exit_xattr; + } + xattr_val_saved = xattr_val; + xattr_val = realloc(xattr_val, s); + if (xattr_val == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Failed to get metadata(xattr)"); + ret = ARCHIVE_WARN; + free(xattr_val_saved); + goto exit_xattr; + } + s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get metadata(xattr)"); + ret = ARCHIVE_WARN; + goto exit_xattr; + } + f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); + if (f == -1) { + archive_set_error(&a->archive, errno, + "Failed to get metadata(xattr)"); + ret = ARCHIVE_WARN; + goto exit_xattr; + } + } +exit_xattr: + free(xattr_names); + free(xattr_val); + return (ret); +} +#endif + +static int +copy_acls(struct archive_write_disk *a, int tmpfd, int dffd) +{ +#ifndef HAVE_SYS_ACL_H + return 0; +#else + acl_t acl, dfacl = NULL; + int acl_r, ret = ARCHIVE_OK; + + acl = acl_get_fd(tmpfd); + if (acl == NULL) { + if (errno == ENOENT) + /* There are not any ACLs. */ + return (ret); + archive_set_error(&a->archive, errno, + "Failed to get metadata(acl)"); + ret = ARCHIVE_WARN; + goto exit_acl; + } + dfacl = acl_dup(acl); + acl_r = acl_set_fd(dffd, dfacl); + if (acl_r == -1) { + archive_set_error(&a->archive, errno, + "Failed to get metadata(acl)"); + ret = ARCHIVE_WARN; + goto exit_acl; + } +exit_acl: + if (acl) + acl_free(acl); + if (dfacl) + acl_free(dfacl); + return (ret); +#endif +} + +static int +create_tempdatafork(struct archive_write_disk *a, const char *pathname) +{ + struct archive_string tmpdatafork; + int tmpfd; + + archive_string_init(&tmpdatafork); + archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); + tmpfd = mkstemp(tmpdatafork.s); + if (tmpfd < 0) { + archive_set_error(&a->archive, errno, + "Failed to mkstemp"); + archive_string_free(&tmpdatafork); + return (-1); + } + if (copyfile(pathname, tmpdatafork.s, 0, + COPYFILE_UNPACK | COPYFILE_NOFOLLOW + | COPYFILE_ACL | COPYFILE_XATTR) < 0) { + archive_set_error(&a->archive, errno, + "Failed to restore metadata"); + close(tmpfd); + tmpfd = -1; + } + unlink(tmpdatafork.s); + archive_string_free(&tmpdatafork); + return (tmpfd); +} + +static int +copy_metadata(struct archive_write_disk *a, const char *metadata, + const char *datafork, int datafork_compressed) +{ + int ret = ARCHIVE_OK; + + if (datafork_compressed) { + int dffd, tmpfd; + + tmpfd = create_tempdatafork(a, metadata); + if (tmpfd == -1) + return (ARCHIVE_WARN); + + /* + * Do not open the data fork compressed by HFS+ compression + * with at least a writing mode(O_RDWR or O_WRONLY). it + * makes the data fork uncompressed. + */ + dffd = open(datafork, 0); + if (dffd == -1) { + archive_set_error(&a->archive, errno, + "Failed to open the data fork for metadata"); + close(tmpfd); + return (ARCHIVE_WARN); + } + +#if defined(HAVE_SYS_XATTR_H) + ret = copy_xattrs(a, tmpfd, dffd); + if (ret == ARCHIVE_OK) +#endif + ret = copy_acls(a, tmpfd, dffd); + close(tmpfd); + close(dffd); + } else { + if (copyfile(metadata, datafork, 0, + COPYFILE_UNPACK | COPYFILE_NOFOLLOW + | COPYFILE_ACL | COPYFILE_XATTR) < 0) { + archive_set_error(&a->archive, errno, + "Failed to restore metadata"); + ret = ARCHIVE_WARN; + } + } + return (ret); +} + +static int +set_mac_metadata(struct archive_write_disk *a, const char *pathname, + const void *metadata, size_t metadata_size) +{ + struct archive_string tmp; + ssize_t written; + int fd; + int ret = ARCHIVE_OK; + + /* This would be simpler if copyfile() could just accept the + * metadata as a block of memory; then we could sidestep this + * silly dance of writing the data to disk just so that + * copyfile() can read it back in again. */ + archive_string_init(&tmp); + archive_strcpy(&tmp, pathname); + archive_strcat(&tmp, ".XXXXXX"); + fd = mkstemp(tmp.s); + + if (fd < 0) { + archive_set_error(&a->archive, errno, + "Failed to restore metadata"); + archive_string_free(&tmp); + return (ARCHIVE_WARN); + } + written = write(fd, metadata, metadata_size); + close(fd); + if ((size_t)written != metadata_size) { + archive_set_error(&a->archive, errno, + "Failed to restore metadata"); + ret = ARCHIVE_WARN; + } else { + int compressed; + +#if defined(UF_COMPRESSED) + if ((a->todo & TODO_HFS_COMPRESSION) != 0 && + (ret = lazy_stat(a)) == ARCHIVE_OK) + compressed = a->st.st_flags & UF_COMPRESSED; + else +#endif + compressed = 0; + ret = copy_metadata(a, tmp.s, pathname, compressed); + } + unlink(tmp.s); + archive_string_free(&tmp); + return (ret); +} + +static int +fixup_appledouble(struct archive_write_disk *a, const char *pathname) +{ + char buff[8]; + struct stat st; + const char *p; + struct archive_string datafork; + int fd = -1, ret = ARCHIVE_OK; + + archive_string_init(&datafork); + /* Check if the current file name is a type of the resource + * fork file. */ + p = strrchr(pathname, '/'); + if (p == NULL) + p = pathname; + else + p++; + if (p[0] != '.' || p[1] != '_') + goto skip_appledouble; + + /* + * Check if the data fork file exists. + * + * TODO: Check if this write disk object has handled it. + */ + archive_strncpy(&datafork, pathname, p - pathname); + archive_strcat(&datafork, p + 2); + if (lstat(datafork.s, &st) == -1 || + (st.st_mode & AE_IFMT) != AE_IFREG) + goto skip_appledouble; + + /* + * Check if the file is in the AppleDouble form. + */ + fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(fd); + if (fd == -1) { + archive_set_error(&a->archive, errno, + "Failed to open a restoring file"); + ret = ARCHIVE_WARN; + goto skip_appledouble; + } + if (read(fd, buff, 8) == -1) { + archive_set_error(&a->archive, errno, + "Failed to read a restoring file"); + close(fd); + ret = ARCHIVE_WARN; + goto skip_appledouble; + } + close(fd); + /* Check AppleDouble Magic Code. */ + if (archive_be32dec(buff) != 0x00051607) + goto skip_appledouble; + /* Check AppleDouble Version. */ + if (archive_be32dec(buff+4) != 0x00020000) + goto skip_appledouble; + + ret = copy_metadata(a, pathname, datafork.s, +#if defined(UF_COMPRESSED) + st.st_flags & UF_COMPRESSED); +#else + 0); +#endif + if (ret == ARCHIVE_OK) { + unlink(pathname); + ret = ARCHIVE_EOF; + } +skip_appledouble: + archive_string_free(&datafork); + return (ret); +} +#endif + +#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX +/* + * Restore extended attributes - Linux, Darwin and AIX implementations: + * AIX' ea interface is syntaxwise identical to the Linux xattr interface. + */ +static int +set_xattrs(struct archive_write_disk *a) +{ + struct archive_entry *entry = a->entry; + struct archive_string errlist; + int ret = ARCHIVE_OK; + int i = archive_entry_xattr_reset(entry); + short fail = 0; + + archive_string_init(&errlist); + + while (i--) { + const char *name; + const void *value; + size_t size; + int e; + + archive_entry_xattr_next(entry, &name, &value, &size); + + if (name == NULL) + continue; +#if ARCHIVE_XATTR_LINUX + /* Linux: quietly skip POSIX.1e ACL extended attributes */ + if (strncmp(name, "system.", 7) == 0 && + (strcmp(name + 7, "posix_acl_access") == 0 || + strcmp(name + 7, "posix_acl_default") == 0)) + continue; + if (strncmp(name, "trusted.SGI_", 12) == 0 && + (strcmp(name + 12, "ACL_DEFAULT") == 0 || + strcmp(name + 12, "ACL_FILE") == 0)) + continue; + + /* Linux: xfsroot namespace is obsolete and unsupported */ + if (strncmp(name, "xfsroot.", 8) == 0) { + fail = 1; + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + continue; + } +#endif + + if (a->fd >= 0) { +#if ARCHIVE_XATTR_LINUX + e = fsetxattr(a->fd, name, value, size, 0); +#elif ARCHIVE_XATTR_DARWIN + e = fsetxattr(a->fd, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX + e = fsetea(a->fd, name, value, size, 0); +#endif + } else { +#if ARCHIVE_XATTR_LINUX + e = lsetxattr(archive_entry_pathname(entry), + name, value, size, 0); +#elif ARCHIVE_XATTR_DARWIN + e = setxattr(archive_entry_pathname(entry), + name, value, size, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + e = lsetea(archive_entry_pathname(entry), + name, value, size, 0); +#endif + } + if (e == -1) { + ret = ARCHIVE_WARN; + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + if (errno != ENOTSUP && errno != ENOSYS) + fail = 1; + } + } + + if (ret == ARCHIVE_WARN) { + if (fail && errlist.length > 0) { + errlist.length--; + errlist.s[errlist.length] = '\0'; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended attributes: %s", + errlist.s); + } else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended " + "attributes on this file system."); + } + + archive_string_free(&errlist); + return (ret); +} +#elif ARCHIVE_XATTR_FREEBSD +/* + * Restore extended attributes - FreeBSD implementation + */ +static int +set_xattrs(struct archive_write_disk *a) +{ + struct archive_entry *entry = a->entry; + struct archive_string errlist; + int ret = ARCHIVE_OK; + int i = archive_entry_xattr_reset(entry); + short fail = 0; + + archive_string_init(&errlist); + + while (i--) { + const char *name; + const void *value; + size_t size; + archive_entry_xattr_next(entry, &name, &value, &size); + if (name != NULL) { + int e; + int namespace; + + if (strncmp(name, "user.", 5) == 0) { + /* "user." attributes go to user namespace */ + name += 5; + namespace = EXTATTR_NAMESPACE_USER; + } else { + /* Other namespaces are unsupported */ + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + fail = 1; + ret = ARCHIVE_WARN; + continue; + } + + if (a->fd >= 0) { + e = extattr_set_fd(a->fd, namespace, name, + value, size); + } else { + e = extattr_set_link( + archive_entry_pathname(entry), namespace, + name, value, size); + } + if (e != (int)size) { + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + ret = ARCHIVE_WARN; + if (errno != ENOTSUP && errno != ENOSYS) + fail = 1; + } + } + } + + if (ret == ARCHIVE_WARN) { + if (fail && errlist.length > 0) { + errlist.length--; + errlist.s[errlist.length] = '\0'; + + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended attributes: %s", + errlist.s); + } else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended " + "attributes on this file system."); + } + + archive_string_free(&errlist); + return (ret); +} +#else +/* + * Restore extended attributes - stub implementation for unsupported systems + */ +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; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Cannot restore extended attributes on this system"); + return (ARCHIVE_WARN); + } + /* Warning was already emitted; suppress further warnings. */ + return (ARCHIVE_OK); +} +#endif + +/* + * Test if file on disk is older than entry. + */ +static int +older(struct stat *st, struct archive_entry *entry) +{ + /* First, test the seconds and return if we have a definite answer. */ + /* Definitely older. */ + if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry))) + return (1); + /* Definitely younger. */ + if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry))) + return (0); + /* If this platform supports fractional seconds, try those. */ +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + /* Definitely older. */ + if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) + return (1); +#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + /* Definitely older. */ + if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) + return (1); +#elif HAVE_STRUCT_STAT_ST_MTIME_N + /* older. */ + if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) + return (1); +#elif HAVE_STRUCT_STAT_ST_UMTIME + /* older. */ + if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) + return (1); +#elif HAVE_STRUCT_STAT_ST_MTIME_USEC + /* older. */ + if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) + return (1); +#else + /* This system doesn't have high-res timestamps. */ +#endif + /* Same age or newer, so not older. */ + return (0); +} + +#ifndef ARCHIVE_ACL_SUPPORT +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + (void)a; /* UNUSED */ + (void)fd; /* UNUSED */ + (void)name; /* UNUSED */ + (void)abstract_acl; /* UNUSED */ + (void)mode; /* UNUSED */ + return (ARCHIVE_OK); +} +#endif + +#endif /* !_WIN32 || __CYGWIN__ */ + diff --git a/src/3rdparty/libarchive/libarchive/archive_write_disk_private.h b/src/3rdparty/libarchive/libarchive/archive_write_disk_private.h new file mode 100644 index 00000000..b655dea2 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_disk_private.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_write_disk_private.h 201086 2009-12-28 02:17:53Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED +#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED + +#include "archive_platform_acl.h" +#include "archive_acl_private.h" +#include "archive_entry.h" + +struct archive_write_disk; + +int archive_write_disk_set_acls(struct archive *, int, const char *, + struct archive_acl *, __LA_MODE_T); + +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c b/src/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c new file mode 100644 index 00000000..5c766d75 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk_set_standard_lookup.c 201083 2009-12-28 02:09:57Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_read_private.h" +#include "archive_write_disk_private.h" + +struct bucket { + char *name; + int hash; + id_t id; +}; + +static const size_t cache_size = 127; +static unsigned int hash(const char *); +static int64_t lookup_gid(void *, const char *uname, int64_t); +static int64_t lookup_uid(void *, const char *uname, int64_t); +static void cleanup(void *); + +/* + * Installs functions that use getpwnam()/getgrnam()---along with + * a simple cache to accelerate such lookups---into the archive_write_disk + * object. This is in a separate file because getpwnam()/getgrnam() + * can pull in a LOT of library code (including NIS/LDAP functions, which + * pull in DNS resolvers, etc). This can easily top 500kB, which makes + * it inappropriate for some space-constrained applications. + * + * Applications that are size-sensitive may want to just use the + * real default functions (defined in archive_write_disk.c) that just + * use the uid/gid without the lookup. Or define your own custom functions + * if you prefer. + * + * TODO: Replace these hash tables with simpler move-to-front LRU + * lists with a bounded size (128 items?). The hash is a bit faster, + * but has a bad pathology in which it thrashes a single bucket. Even + * walking a list of 128 items is a lot faster than calling + * getpwnam()! + */ +int +archive_write_disk_set_standard_lookup(struct archive *a) +{ + struct bucket *ucache = calloc(cache_size, sizeof(struct bucket)); + struct bucket *gcache = calloc(cache_size, sizeof(struct bucket)); + if (ucache == NULL || gcache == NULL) { + free(ucache); + free(gcache); + return (ARCHIVE_FATAL); + } + archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup); + archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup); + return (ARCHIVE_OK); +} + +static int64_t +lookup_gid(void *private_data, const char *gname, int64_t gid) +{ + int h; + struct bucket *b; + struct bucket *gcache = (struct bucket *)private_data; + + /* If no gname, just use the gid provided. */ + if (gname == NULL || *gname == '\0') + return (gid); + + /* Try to find gname in the cache. */ + h = hash(gname); + b = &gcache[h % cache_size ]; + if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0) + return ((gid_t)b->id); + + /* Free the cache slot for a new entry. */ + if (b->name != NULL) + free(b->name); + b->name = strdup(gname); + /* Note: If strdup fails, that's okay; we just won't cache. */ + b->hash = h; +#if HAVE_GRP_H +# if HAVE_GETGRNAM_R + { + char _buffer[128]; + size_t bufsize = 128; + char *buffer = _buffer; + char *allocated = NULL; + struct group grent, *result; + int r; + + for (;;) { + result = &grent; /* Old getgrnam_r ignores last arg. */ + r = getgrnam_r(gname, &grent, buffer, bufsize, &result); + if (r == 0) + break; + if (r != ERANGE) + break; + bufsize *= 2; + free(allocated); + allocated = malloc(bufsize); + if (allocated == NULL) + break; + buffer = allocated; + } + if (result != NULL) + gid = result->gr_gid; + free(allocated); + } +# else /* HAVE_GETGRNAM_R */ + { + struct group *result; + + result = getgrnam(gname); + if (result != NULL) + gid = result->gr_gid; + } +# endif /* HAVE_GETGRNAM_R */ +#elif defined(_WIN32) && !defined(__CYGWIN__) + /* TODO: do a gname->gid lookup for Windows. */ +#else + #error No way to perform gid lookups on this platform +#endif + b->id = (gid_t)gid; + + return (gid); +} + +static int64_t +lookup_uid(void *private_data, const char *uname, int64_t uid) +{ + int h; + struct bucket *b; + struct bucket *ucache = (struct bucket *)private_data; + + /* If no uname, just use the uid provided. */ + if (uname == NULL || *uname == '\0') + return (uid); + + /* Try to find uname in the cache. */ + h = hash(uname); + b = &ucache[h % cache_size ]; + if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0) + return ((uid_t)b->id); + + /* Free the cache slot for a new entry. */ + if (b->name != NULL) + free(b->name); + b->name = strdup(uname); + /* Note: If strdup fails, that's okay; we just won't cache. */ + b->hash = h; +#if HAVE_PWD_H +# if HAVE_GETPWNAM_R + { + char _buffer[128]; + size_t bufsize = 128; + char *buffer = _buffer; + char *allocated = NULL; + struct passwd pwent, *result; + int r; + + for (;;) { + result = &pwent; /* Old getpwnam_r ignores last arg. */ + r = getpwnam_r(uname, &pwent, buffer, bufsize, &result); + if (r == 0) + break; + if (r != ERANGE) + break; + bufsize *= 2; + free(allocated); + allocated = malloc(bufsize); + if (allocated == NULL) + break; + buffer = allocated; + } + if (result != NULL) + uid = result->pw_uid; + free(allocated); + } +# else /* HAVE_GETPWNAM_R */ + { + struct passwd *result; + + result = getpwnam(uname); + if (result != NULL) + uid = result->pw_uid; + } +#endif /* HAVE_GETPWNAM_R */ +#elif defined(_WIN32) && !defined(__CYGWIN__) + /* TODO: do a uname->uid lookup for Windows. */ +#else + #error No way to look up uids on this platform +#endif + b->id = (uid_t)uid; + + return (uid); +} + +static void +cleanup(void *private) +{ + size_t i; + struct bucket *cache = (struct bucket *)private; + + for (i = 0; i < cache_size; i++) + free(cache[i].name); + free(cache); +} + + +static unsigned int +hash(const char *p) +{ + /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm, + as used by ELF for hashing function names. */ + unsigned g, h = 0; + while (*p != '\0') { + h = (h << 4) + *p++; + if ((g = h & 0xF0000000) != 0) { + h ^= g >> 24; + h &= 0x0FFFFFFF; + } + } + return h; +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_disk_windows.c b/src/3rdparty/libarchive/libarchive/archive_write_disk_windows.c new file mode 100644 index 00000000..94b016ed --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_disk_windows.c @@ -0,0 +1,2511 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_UTIME_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +/* TODO: Support Mac OS 'quarantine' feature. This is really just a + * standard tag to mark files that have been downloaded as "tainted". + * On Mac OS, we should mark the extracted files as tainted if the + * archive being read was tainted. Windows has a similar feature; we + * should investigate ways to support this generically. */ + +#include "archive.h" +#include "archive_acl_private.h" +#include "archive_string.h" +#include "archive_entry.h" +#include "archive_private.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef IO_REPARSE_TAG_SYMLINK +/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ +#define IO_REPARSE_TAG_SYMLINK 0xA000000CL +#endif + +static BOOL SetFilePointerEx_perso(HANDLE hFile, + LARGE_INTEGER liDistanceToMove, + PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod) +{ + LARGE_INTEGER li; + li.QuadPart = liDistanceToMove.QuadPart; + li.LowPart = SetFilePointer( + hFile, li.LowPart, &li.HighPart, dwMoveMethod); + if(lpNewFilePointer) { + lpNewFilePointer->QuadPart = li.QuadPart; + } + return li.LowPart != (DWORD)-1 || GetLastError() == NO_ERROR; +} + +struct fixup_entry { + struct fixup_entry *next; + struct archive_acl acl; + mode_t mode; + int64_t atime; + int64_t birthtime; + int64_t mtime; + int64_t ctime; + unsigned long atime_nanos; + unsigned long birthtime_nanos; + unsigned long mtime_nanos; + unsigned long ctime_nanos; + unsigned long fflags_set; + int fixup; /* bitmask of what needs fixing */ + wchar_t *name; +}; + +/* + * We use a bitmask to track which operations remain to be done for + * this file. In particular, this helps us avoid unnecessary + * operations when it's possible to take care of one step as a + * side-effect of another. For example, mkdir() can specify the mode + * for the newly-created object but symlink() cannot. This means we + * can skip chmod() if mkdir() succeeded, but we must explicitly + * chmod() if we're trying to create a directory that already exists + * (mkdir() failed) or if we're restoring a symlink. Similarly, we + * need to verify UID/GID before trying to restore SUID/SGID bits; + * that verification can occur explicitly through a stat() call or + * implicitly because of a successful chown() call. + */ +#define TODO_MODE_FORCE 0x40000000 +#define TODO_MODE_BASE 0x20000000 +#define TODO_SUID 0x10000000 +#define TODO_SUID_CHECK 0x08000000 +#define TODO_SGID 0x04000000 +#define TODO_SGID_CHECK 0x02000000 +#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) +#define TODO_TIMES ARCHIVE_EXTRACT_TIME +#define TODO_OWNER ARCHIVE_EXTRACT_OWNER +#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS +#define TODO_ACLS ARCHIVE_EXTRACT_ACL +#define TODO_XATTR ARCHIVE_EXTRACT_XATTR +#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA + +struct archive_write_disk { + struct archive archive; + + mode_t user_umask; + struct fixup_entry *fixup_list; + struct fixup_entry *current_fixup; + int64_t user_uid; + int skip_file_set; + int64_t skip_file_dev; + int64_t skip_file_ino; + time_t start_time; + + int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); + void (*cleanup_gid)(void *private); + void *lookup_gid_data; + int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); + void (*cleanup_uid)(void *private); + void *lookup_uid_data; + + /* + * Full path of last file to satisfy symlink checks. + */ + struct archive_wstring path_safe; + + /* + * Cached stat data from disk for the current entry. + * If this is valid, pst points to st. Otherwise, + * pst is null. + */ + BY_HANDLE_FILE_INFORMATION st; + BY_HANDLE_FILE_INFORMATION *pst; + + /* Information about the object being restored right now. */ + struct archive_entry *entry; /* Entry being extracted. */ + wchar_t *name; /* Name of entry, possibly edited. */ + struct archive_wstring _name_data; /* backing store for 'name' */ + /* Tasks remaining for this object. */ + int todo; + /* Tasks deferred until end-of-archive. */ + int deferred; + /* Options requested by the client. */ + int flags; + /* Handle for the file we're restoring. */ + HANDLE fh; + /* Current offset for writing data to the file. */ + int64_t offset; + /* Last offset actually written to disk. */ + int64_t fd_offset; + /* Total bytes actually written to files. */ + int64_t total_bytes_written; + /* Maximum size of file, -1 if unknown. */ + int64_t filesize; + /* Dir we were in before this restore; only for deep paths. */ + int restore_pwd; + /* Mode we should use for this entry; affected by _PERM and umask. */ + mode_t mode; + /* UID/GID to use in restoring this entry. */ + int64_t uid; + int64_t gid; +}; + +/* + * Default mode for dirs created automatically (will be modified by umask). + * Note that POSIX specifies 0777 for implicitly-created dirs, "modified + * by the process' file creation mask." + */ +#define DEFAULT_DIR_MODE 0777 +/* + * Dir modes are restored in two steps: During the extraction, the permissions + * in the archive are modified to match the following limits. During + * the post-extract fixup pass, the permissions from the archive are + * applied. + */ +#define MINIMUM_DIR_MODE 0700 +#define MAXIMUM_DIR_MODE 0775 + +static int check_symlinks(struct archive_write_disk *); +static int create_filesystem_object(struct archive_write_disk *); +static struct fixup_entry *current_fixup(struct archive_write_disk *, + const wchar_t *pathname); +static int cleanup_pathname(struct archive_write_disk *); +static int create_dir(struct archive_write_disk *, wchar_t *); +static int create_parent_dir(struct archive_write_disk *, wchar_t *); +static int la_chmod(const wchar_t *, mode_t); +static int older(BY_HANDLE_FILE_INFORMATION *, struct archive_entry *); +static int permissive_name_w(struct archive_write_disk *); +static int restore_entry(struct archive_write_disk *); +static int set_acls(struct archive_write_disk *, HANDLE h, + const wchar_t *, struct archive_acl *); +static int set_xattrs(struct archive_write_disk *); +static int set_fflags(struct archive_write_disk *); +static int set_ownership(struct archive_write_disk *); +static int set_mode(struct archive_write_disk *, int mode); +static int set_times(struct archive_write_disk *, HANDLE, int, + const wchar_t *, time_t, long, time_t, long, time_t, + long, time_t, long); +static int set_times_from_entry(struct archive_write_disk *); +static struct fixup_entry *sort_dir_list(struct fixup_entry *p); +static ssize_t write_data_block(struct archive_write_disk *, + const char *, size_t); + +static struct archive_vtable *archive_write_disk_vtable(void); + +static int _archive_write_disk_close(struct archive *); +static int _archive_write_disk_free(struct archive *); +static int _archive_write_disk_header(struct archive *, + struct archive_entry *); +static int64_t _archive_write_disk_filter_bytes(struct archive *, int); +static int _archive_write_disk_finish_entry(struct archive *); +static ssize_t _archive_write_disk_data(struct archive *, const void *, + size_t); +static ssize_t _archive_write_disk_data_block(struct archive *, const void *, + size_t, int64_t); + +#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber) +/* Treat FileIndex as i-node. We should remove a sequence number + * which is high-16-bits of nFileIndexHigh. */ +#define bhfi_ino(bhfi) \ + ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \ + + (bhfi)->nFileIndexLow) +#define bhfi_size(bhfi) \ + ((((int64_t)(bhfi)->nFileSizeHigh) << 32) + (bhfi)->nFileSizeLow) + +static int +file_information(struct archive_write_disk *a, wchar_t *path, + BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat) +{ + HANDLE h; + int r; + DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; + WIN32_FIND_DATAW findData; + + if (sim_lstat || mode != NULL) { + h = FindFirstFileW(path, &findData); + if (h == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_NAME) { + wchar_t *full; + full = __la_win_permissive_name_w(path); + h = FindFirstFileW(full, &findData); + free(full); + } + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + FindClose(h); + } + + /* Is symlink file ? */ + if (sim_lstat && + ((findData.dwFileAttributes + & FILE_ATTRIBUTE_REPARSE_POINT) && + (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))) + flag |= FILE_FLAG_OPEN_REPARSE_POINT; + + h = CreateFileW(a->name, 0, 0, NULL, + OPEN_EXISTING, flag, NULL); + if (h == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_NAME) { + wchar_t *full; + full = __la_win_permissive_name_w(path); + h = CreateFileW(full, 0, 0, NULL, + OPEN_EXISTING, flag, NULL); + free(full); + } + if (h == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + r = GetFileInformationByHandle(h, st); + CloseHandle(h); + if (r == 0) { + la_dosmaperr(GetLastError()); + return (-1); + } + + if (mode == NULL) + return (0); + + *mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((st->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + *mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if ((st->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) + *mode |= S_IFLNK; + else if (st->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + *mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else { + const wchar_t *p; + + *mode |= S_IFREG; + p = wcsrchr(path, L'.'); + if (p != NULL && wcslen(p) == 4) { + switch (p[1]) { + case L'B': case L'b': + if ((p[2] == L'A' || p[2] == L'a' ) && + (p[3] == L'T' || p[3] == L't' )) + *mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + case L'C': case L'c': + if (((p[2] == L'M' || p[2] == L'm' ) && + (p[3] == L'D' || p[3] == L'd' ))) + *mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + case L'E': case L'e': + if ((p[2] == L'X' || p[2] == L'x' ) && + (p[3] == L'E' || p[3] == L'e' )) + *mode |= S_IXUSR | S_IXGRP | S_IXOTH; + break; + default: + break; + } + } + } + return (0); +} + +/* + * Note: The path, for example, "aa/a/../b../c" will be converted to "aa/c" + * by GetFullPathNameW() W32 API, which __la_win_permissive_name_w uses. + * It means we cannot handle multiple dirs in one archive_entry. + * So we have to make the full-pathname in another way, which does not + * break "../" path string. + */ +static int +permissive_name_w(struct archive_write_disk *a) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + DWORD l; + + wnp = a->name; + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'?' && wnp[3] == L'\\') + /* We have already a permissive name. */ + return (0); + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'.' && wnp[3] == L'\\') { + /* This is a device name */ + if (((wnp[4] >= L'a' && wnp[4] <= L'z') || + (wnp[4] >= L'A' && wnp[4] <= L'Z')) && + wnp[5] == L':' && wnp[6] == L'\\') { + wnp[2] = L'?';/* Not device name. */ + return (0); + } + } + + /* + * A full-pathname starting with a drive name like "C:\abc". + */ + if (((wnp[0] >= L'a' && wnp[0] <= L'z') || + (wnp[0] >= L'A' && wnp[0] <= L'Z')) && + wnp[1] == L':' && wnp[2] == L'\\') { + wn = _wcsdup(wnp); + if (wn == NULL) + return (-1); + archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1); + a->name = a->_name_data.s; + /* Prepend "\\?\" */ + archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); + archive_wstrcat(&(a->_name_data), wn); + free(wn); + return (0); + } + + /* + * A full-pathname pointing to a network drive + * like "\\\\file". + */ + if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { + const wchar_t *p = &wnp[2]; + + /* Skip server-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\') { + const wchar_t *rp = ++p; + /* Skip share-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\' && p != rp) { + /* Now, match patterns such as + * "\\server-name\share-name\" */ + wn = _wcsdup(wnp); + if (wn == NULL) + return (-1); + archive_wstring_ensure(&(a->_name_data), + 8 + wcslen(wn) + 1); + a->name = a->_name_data.s; + /* Prepend "\\?\UNC\" */ + archive_wstrncpy(&(a->_name_data), + L"\\\\?\\UNC\\", 8); + archive_wstrcat(&(a->_name_data), wn+2); + free(wn); + return (0); + } + } + return (0); + } + + /* + * Get current working directory. + */ + l = GetCurrentDirectoryW(0, NULL); + if (l == 0) + return (-1); + ws = malloc(l * sizeof(wchar_t)); + l = GetCurrentDirectoryW(l, ws); + if (l == 0) { + free(ws); + return (-1); + } + wsp = ws; + + /* + * A full-pathname starting without a drive name like "\abc". + */ + if (wnp[0] == L'\\') { + wn = _wcsdup(wnp); + if (wn == NULL) + return (-1); + archive_wstring_ensure(&(a->_name_data), + 4 + 2 + wcslen(wn) + 1); + a->name = a->_name_data.s; + /* Prepend "\\?\" and drive name. */ + archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); + archive_wstrncat(&(a->_name_data), wsp, 2); + archive_wstrcat(&(a->_name_data), wn); + free(wsp); + free(wn); + return (0); + } + + wn = _wcsdup(wnp); + if (wn == NULL) + return (-1); + archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1); + a->name = a->_name_data.s; + /* Prepend "\\?\" and drive name if not already added. */ + if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' && + wsp[2] == L'?' && wsp[3] == L'\\') + { + archive_wstrncpy(&(a->_name_data), wsp, l); + } + else + { + archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); + archive_wstrncat(&(a->_name_data), wsp, l); + } + archive_wstrncat(&(a->_name_data), L"\\", 1); + archive_wstrcat(&(a->_name_data), wn); + a->name = a->_name_data.s; + free(wsp); + free(wn); + return (0); +} + +static int +la_chmod(const wchar_t *path, mode_t mode) +{ + DWORD attr; + BOOL r; + wchar_t *fullname; + int ret = 0; + + fullname = NULL; + attr = GetFileAttributesW(path); + if (attr == (DWORD)-1 && + GetLastError() == ERROR_INVALID_NAME) { + fullname = __la_win_permissive_name_w(path); + attr = GetFileAttributesW(fullname); + } + if (attr == (DWORD)-1) { + la_dosmaperr(GetLastError()); + ret = -1; + goto exit_chmode; + } + if (mode & _S_IWRITE) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + if (fullname != NULL) + r = SetFileAttributesW(fullname, attr); + else + r = SetFileAttributesW(path, attr); + if (r == 0) { + la_dosmaperr(GetLastError()); + ret = -1; + } +exit_chmode: + free(fullname); + return (ret); +} + +static void * +la_GetFunctionKernel32(const char *name) +{ + static HINSTANCE lib; + static int set; + if (!set) { + set = 1; + lib = LoadLibrary(TEXT("kernel32.dll")); + } + if (lib == NULL) { + fprintf(stderr, "Can't load kernel32.dll?!\n"); + exit(1); + } + return (void *)GetProcAddress(lib, name); +} + +static int +la_CreateHardLinkW(wchar_t *linkname, wchar_t *target) +{ + static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES); + static int set; + BOOL ret; + + if (!set) { + set = 1; + f = la_GetFunctionKernel32("CreateHardLinkW"); + } + if (!f) + return (0); + ret = (*f)(linkname, target, NULL); + if (!ret) { + /* Under windows 2000, it is necessary to remove + * the "\\?\" prefix. */ +#define IS_UNC(name) ((name[0] == L'U' || name[0] == L'u') && \ + (name[1] == L'N' || name[1] == L'n') && \ + (name[2] == L'C' || name[2] == L'c') && \ + name[3] == L'\\') + if (!wcsncmp(linkname,L"\\\\?\\", 4)) { + linkname += 4; + if (IS_UNC(linkname)) + linkname += 4; + } + if (!wcsncmp(target,L"\\\\?\\", 4)) { + target += 4; + if (IS_UNC(target)) + target += 4; + } +#undef IS_UNC + ret = (*f)(linkname, target, NULL); + } + return (ret); +} + +static int +la_ftruncate(HANDLE handle, int64_t length) +{ + LARGE_INTEGER distance; + + if (GetFileType(handle) != FILE_TYPE_DISK) { + errno = EBADF; + return (-1); + } + distance.QuadPart = length; + if (!SetFilePointerEx_perso(handle, distance, NULL, FILE_BEGIN)) { + la_dosmaperr(GetLastError()); + return (-1); + } + if (!SetEndOfFile(handle)) { + la_dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +static int +lazy_stat(struct archive_write_disk *a) +{ + if (a->pst != NULL) { + /* Already have stat() data available. */ + return (ARCHIVE_OK); + } + if (a->fh != INVALID_HANDLE_VALUE && + GetFileInformationByHandle(a->fh, &a->st) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } + + /* + * XXX At this point, symlinks should not be hit, otherwise + * XXX a race occurred. Do we want to check explicitly for that? + */ + if (file_information(a, a->name, &a->st, NULL, 1) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } + archive_set_error(&a->archive, errno, "Couldn't stat file"); + return (ARCHIVE_WARN); +} + +static struct archive_vtable * +archive_write_disk_vtable(void) +{ + static struct archive_vtable av; + static int inited = 0; + + if (!inited) { + av.archive_close = _archive_write_disk_close; + av.archive_filter_bytes = _archive_write_disk_filter_bytes; + av.archive_free = _archive_write_disk_free; + av.archive_write_header = _archive_write_disk_header; + av.archive_write_finish_entry + = _archive_write_disk_finish_entry; + av.archive_write_data = _archive_write_disk_data; + av.archive_write_data_block = _archive_write_disk_data_block; + inited = 1; + } + return (&av); +} + +static int64_t +_archive_write_disk_filter_bytes(struct archive *_a, int n) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + (void)n; /* UNUSED */ + if (n == -1 || n == 0) + return (a->total_bytes_written); + return (-1); +} + + +int +archive_write_disk_set_options(struct archive *_a, int flags) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + + a->flags = flags; + return (ARCHIVE_OK); +} + + +/* + * Extract this entry to disk. + * + * TODO: Validate hardlinks. According to the standards, we're + * supposed to check each extracted hardlink and squawk if it refers + * to a file that we didn't restore. I'm not entirely convinced this + * is a good idea, but more importantly: Is there any way to validate + * hardlinks without keeping a complete list of filenames from the + * entire archive?? Ugh. + * + */ +static int +_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *fe; + int ret, r; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_disk_header"); + archive_clear_error(&a->archive); + if (a->archive.state & ARCHIVE_STATE_DATA) { + r = _archive_write_disk_finish_entry(&a->archive); + if (r == ARCHIVE_FATAL) + return (r); + } + + /* Set up for this particular entry. */ + a->pst = NULL; + a->current_fixup = NULL; + a->deferred = 0; + if (a->entry) { + archive_entry_free(a->entry); + a->entry = NULL; + } + a->entry = archive_entry_clone(entry); + a->fh = INVALID_HANDLE_VALUE; + a->fd_offset = 0; + a->offset = 0; + a->restore_pwd = -1; + a->uid = a->user_uid; + a->mode = archive_entry_mode(a->entry); + if (archive_entry_size_is_set(a->entry)) + a->filesize = archive_entry_size(a->entry); + else + a->filesize = -1; + archive_wstrcpy(&(a->_name_data), archive_entry_pathname_w(a->entry)); + a->name = a->_name_data.s; + archive_clear_error(&a->archive); + + /* + * Clean up the requested path. This is necessary for correct + * dir restores; the dir restore logic otherwise gets messed + * up by nonsense like "dir/.". + */ + ret = cleanup_pathname(a); + if (ret != ARCHIVE_OK) + return (ret); + + /* + * Generate a full-pathname and use it from here. + */ + if (permissive_name_w(a) < 0) { + errno = EINVAL; + return (ARCHIVE_FAILED); + } + + /* + * Query the umask so we get predictable mode settings. + * This gets done on every call to _write_header in case the + * user edits their umask during the extraction for some + * reason. + */ + umask(a->user_umask = umask(0)); + + /* Figure out what we need to do for this entry. */ + a->todo = TODO_MODE_BASE; + if (a->flags & ARCHIVE_EXTRACT_PERM) { + a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ + /* + * SGID requires an extra "check" step because we + * cannot easily predict the GID that the system will + * assign. (Different systems assign GIDs to files + * based on a variety of criteria, including process + * credentials and the gid of the enclosing + * directory.) We can only restore the SGID bit if + * the file has the right GID, and we only know the + * GID if we either set it (see set_ownership) or if + * we've actually called stat() on the file after it + * was restored. Since there are several places at + * which we might verify the GID, we need a TODO bit + * to keep track. + */ + if (a->mode & S_ISGID) + a->todo |= TODO_SGID | TODO_SGID_CHECK; + /* + * Verifying the SUID is simpler, but can still be + * done in multiple ways, hence the separate "check" bit. + */ + if (a->mode & S_ISUID) + a->todo |= TODO_SUID | TODO_SUID_CHECK; + } else { + /* + * User didn't request full permissions, so don't + * restore SUID, SGID bits and obey umask. + */ + a->mode &= ~S_ISUID; + a->mode &= ~S_ISGID; + a->mode &= ~S_ISVTX; + a->mode &= ~a->user_umask; + } +#if 0 + if (a->flags & ARCHIVE_EXTRACT_OWNER) + a->todo |= TODO_OWNER; +#endif + if (a->flags & ARCHIVE_EXTRACT_TIME) + a->todo |= TODO_TIMES; + if (a->flags & ARCHIVE_EXTRACT_ACL) { + if (archive_entry_filetype(a->entry) == AE_IFDIR) + a->deferred |= TODO_ACLS; + else + a->todo |= TODO_ACLS; + } + if (a->flags & ARCHIVE_EXTRACT_XATTR) + a->todo |= TODO_XATTR; + if (a->flags & ARCHIVE_EXTRACT_FFLAGS) + a->todo |= TODO_FFLAGS; + if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { + ret = check_symlinks(a); + if (ret != ARCHIVE_OK) + return (ret); + } + + ret = restore_entry(a); + + /* + * TODO: There are rumours that some extended attributes must + * be restored before file data is written. If this is true, + * then we either need to write all extended attributes both + * before and after restoring the data, or find some rule for + * determining which must go first and which last. Due to the + * many ways people are using xattrs, this may prove to be an + * intractable problem. + */ + + /* + * Fixup uses the unedited pathname from archive_entry_pathname(), + * because it is relative to the base dir and the edited path + * might be relative to some intermediate dir as a result of the + * deep restore logic. + */ + if (a->deferred & TODO_MODE) { + fe = current_fixup(a, archive_entry_pathname_w(entry)); + fe->fixup |= TODO_MODE_BASE; + fe->mode = a->mode; + } + + if ((a->deferred & TODO_TIMES) + && (archive_entry_mtime_is_set(entry) + || archive_entry_atime_is_set(entry))) { + fe = current_fixup(a, archive_entry_pathname_w(entry)); + fe->mode = a->mode; + fe->fixup |= TODO_TIMES; + if (archive_entry_atime_is_set(entry)) { + fe->atime = archive_entry_atime(entry); + fe->atime_nanos = archive_entry_atime_nsec(entry); + } else { + /* If atime is unset, use start time. */ + fe->atime = a->start_time; + fe->atime_nanos = 0; + } + if (archive_entry_mtime_is_set(entry)) { + fe->mtime = archive_entry_mtime(entry); + fe->mtime_nanos = archive_entry_mtime_nsec(entry); + } else { + /* If mtime is unset, use start time. */ + fe->mtime = a->start_time; + fe->mtime_nanos = 0; + } + if (archive_entry_birthtime_is_set(entry)) { + fe->birthtime = archive_entry_birthtime(entry); + fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); + } else { + /* If birthtime is unset, use mtime. */ + fe->birthtime = fe->mtime; + fe->birthtime_nanos = fe->mtime_nanos; + } + } + + if (a->deferred & TODO_ACLS) { + fe = current_fixup(a, archive_entry_pathname_w(entry)); + archive_acl_copy(&fe->acl, archive_entry_acl(entry)); + } + + if (a->deferred & TODO_FFLAGS) { + fe = current_fixup(a, archive_entry_pathname_w(entry)); + fe->fixup |= TODO_FFLAGS; + /* TODO: Complete this.. defer fflags from below. */ + } + + /* + * On Windows, A creating sparse file requires a special mark. + */ + if (a->fh != INVALID_HANDLE_VALUE && + archive_entry_sparse_count(entry) > 0) { + int64_t base = 0, offset, length; + int i, cnt = archive_entry_sparse_reset(entry); + int sparse = 0; + + for (i = 0; i < cnt; i++) { + archive_entry_sparse_next(entry, &offset, &length); + if (offset - base >= 4096) { + sparse = 1;/* we have a hole. */ + break; + } + base = offset + length; + } + if (sparse) { + DWORD dmy; + /* Mark this file as sparse. */ + DeviceIoControl(a->fh, FSCTL_SET_SPARSE, + NULL, 0, NULL, 0, &dmy, NULL); + } + } + + /* We've created the object and are ready to pour data into it. */ + if (ret >= ARCHIVE_WARN) + a->archive.state = ARCHIVE_STATE_DATA; + /* + * If it's not open, tell our client not to try writing. + * In particular, dirs, links, etc, don't get written to. + */ + if (a->fh == INVALID_HANDLE_VALUE) { + archive_entry_set_size(entry, 0); + a->filesize = 0; + } + + return (ret); +} + +int +archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); + a->skip_file_set = 1; + a->skip_file_dev = d; + a->skip_file_ino = i; + return (ARCHIVE_OK); +} + +static ssize_t +write_data_block(struct archive_write_disk *a, const char *buff, size_t size) +{ + OVERLAPPED ol; + uint64_t start_size = size; + DWORD bytes_written = 0; + ssize_t block_size = 0, bytes_to_write; + + if (size == 0) + return (ARCHIVE_OK); + + if (a->filesize == 0 || a->fh == INVALID_HANDLE_VALUE) { + archive_set_error(&a->archive, 0, + "Attempt to write to an empty file"); + return (ARCHIVE_WARN); + } + + if (a->flags & ARCHIVE_EXTRACT_SPARSE) { + /* XXX TODO XXX Is there a more appropriate choice here ? */ + /* This needn't match the filesystem allocation size. */ + block_size = 16*1024; + } + + /* If this write would run beyond the file size, truncate it. */ + if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) + start_size = size = (size_t)(a->filesize - a->offset); + + /* Write the data. */ + while (size > 0) { + if (block_size == 0) { + bytes_to_write = size; + } else { + /* We're sparsifying the file. */ + const char *p, *end; + int64_t block_end; + + /* Skip leading zero bytes. */ + for (p = buff, end = buff + size; p < end; ++p) { + if (*p != '\0') + break; + } + a->offset += p - buff; + size -= p - buff; + buff = p; + if (size == 0) + break; + + /* Calculate next block boundary after offset. */ + block_end + = (a->offset / block_size + 1) * block_size; + + /* If the adjusted write would cross block boundary, + * truncate it to the block boundary. */ + bytes_to_write = size; + if (a->offset + bytes_to_write > block_end) + bytes_to_write = (DWORD)(block_end - a->offset); + } + memset(&ol, 0, sizeof(ol)); + ol.Offset = (DWORD)(a->offset & 0xFFFFFFFF); + ol.OffsetHigh = (DWORD)(a->offset >> 32); + if (!WriteFile(a->fh, buff, (uint32_t)bytes_to_write, + &bytes_written, &ol)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + la_dosmaperr(lasterr); + archive_set_error(&a->archive, errno, "Write failed"); + return (ARCHIVE_WARN); + } + buff += bytes_written; + size -= bytes_written; + a->total_bytes_written += bytes_written; + a->offset += bytes_written; + a->fd_offset = a->offset; + } + return ((ssize_t)(start_size - size)); +} + +static ssize_t +_archive_write_disk_data_block(struct archive *_a, + const void *buff, size_t size, int64_t offset) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + ssize_t r; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data_block"); + + a->offset = offset; + r = write_data_block(a, buff, size); + if (r < ARCHIVE_OK) + return (r); + if ((size_t)r < size) { + archive_set_error(&a->archive, 0, + "Write request too large"); + return (ARCHIVE_WARN); + } +#if ARCHIVE_VERSION_NUMBER < 3999000 + return (ARCHIVE_OK); +#else + return (size); +#endif +} + +static ssize_t +_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_DATA, "archive_write_data"); + + return (write_data_block(a, buff, size)); +} + +static int +_archive_write_disk_finish_entry(struct archive *_a) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + int ret = ARCHIVE_OK; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_finish_entry"); + if (a->archive.state & ARCHIVE_STATE_HEADER) + return (ARCHIVE_OK); + archive_clear_error(&a->archive); + + /* Pad or truncate file to the right size. */ + if (a->fh == INVALID_HANDLE_VALUE) { + /* There's no file. */ + } else if (a->filesize < 0) { + /* File size is unknown, so we can't set the size. */ + } else if (a->fd_offset == a->filesize) { + /* Last write ended at exactly the filesize; we're done. */ + /* Hopefully, this is the common case. */ + } else { + if (la_ftruncate(a->fh, a->filesize) == -1) { + archive_set_error(&a->archive, errno, + "File size could not be restored"); + return (ARCHIVE_FAILED); + } + } + + /* Restore metadata. */ + + /* + * Look up the "real" UID only if we're going to need it. + * TODO: the TODO_SGID condition can be dropped here, can't it? + */ + if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { + a->uid = archive_write_disk_uid(&a->archive, + archive_entry_uname(a->entry), + archive_entry_uid(a->entry)); + } + /* Look up the "real" GID only if we're going to need it. */ + /* TODO: the TODO_SUID condition can be dropped here, can't it? */ + if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { + a->gid = archive_write_disk_gid(&a->archive, + archive_entry_gname(a->entry), + archive_entry_gid(a->entry)); + } + + /* + * Restore ownership before set_mode tries to restore suid/sgid + * bits. If we set the owner, we know what it is and can skip + * a stat() call to examine the ownership of the file on disk. + */ + if (a->todo & TODO_OWNER) + ret = set_ownership(a); + + /* + * set_mode must precede ACLs on systems such as Solaris and + * FreeBSD where setting the mode implicitly clears extended ACLs + */ + if (a->todo & TODO_MODE) { + int r2 = set_mode(a, a->mode); + if (r2 < ret) ret = r2; + } + + /* + * Security-related extended attributes (such as + * security.capability on Linux) have to be restored last, + * since they're implicitly removed by other file changes. + */ + if (a->todo & TODO_XATTR) { + int r2 = set_xattrs(a); + if (r2 < ret) ret = r2; + } + + /* + * Some flags prevent file modification; they must be restored after + * file contents are written. + */ + if (a->todo & TODO_FFLAGS) { + int r2 = set_fflags(a); + if (r2 < ret) ret = r2; + } + + /* + * Time must follow most other metadata; + * otherwise atime will get changed. + */ + if (a->todo & TODO_TIMES) { + int r2 = set_times_from_entry(a); + if (r2 < ret) ret = r2; + } + + /* + * ACLs must be restored after timestamps because there are + * ACLs that prevent attribute changes (including time). + */ + if (a->todo & TODO_ACLS) { + int r2 = set_acls(a, a->fh, + archive_entry_pathname_w(a->entry), + archive_entry_acl(a->entry)); + if (r2 < ret) ret = r2; + } + + /* If there's an fd, we can close it now. */ + if (a->fh != INVALID_HANDLE_VALUE) { + CloseHandle(a->fh); + a->fh = INVALID_HANDLE_VALUE; + } + /* If there's an entry, we can release it now. */ + if (a->entry) { + archive_entry_free(a->entry); + a->entry = NULL; + } + a->archive.state = ARCHIVE_STATE_HEADER; + return (ret); +} + +int +archive_write_disk_set_group_lookup(struct archive *_a, + void *private_data, + int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), + void (*cleanup_gid)(void *private)) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); + + if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) + (a->cleanup_gid)(a->lookup_gid_data); + + a->lookup_gid = lookup_gid; + a->cleanup_gid = cleanup_gid; + a->lookup_gid_data = private_data; + return (ARCHIVE_OK); +} + +int +archive_write_disk_set_user_lookup(struct archive *_a, + void *private_data, + int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), + void (*cleanup_uid)(void *private)) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); + + if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) + (a->cleanup_uid)(a->lookup_uid_data); + + a->lookup_uid = lookup_uid; + a->cleanup_uid = cleanup_uid; + a->lookup_uid_data = private_data; + return (ARCHIVE_OK); +} + +int64_t +archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_gid"); + if (a->lookup_gid) + return (a->lookup_gid)(a->lookup_gid_data, name, id); + return (id); +} + +int64_t +archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_uid"); + if (a->lookup_uid) + return (a->lookup_uid)(a->lookup_uid_data, name, id); + return (id); +} + +/* + * Create a new archive_write_disk object and initialize it with global state. + */ +struct archive * +archive_write_disk_new(void) +{ + struct archive_write_disk *a; + + a = (struct archive_write_disk *)calloc(1, sizeof(*a)); + if (a == NULL) + return (NULL); + a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; + /* We're ready to write a header immediately. */ + a->archive.state = ARCHIVE_STATE_HEADER; + a->archive.vtable = archive_write_disk_vtable(); + a->start_time = time(NULL); + /* Query and restore the umask. */ + umask(a->user_umask = umask(0)); + if (archive_wstring_ensure(&a->path_safe, 512) == NULL) { + free(a); + return (NULL); + } + return (&a->archive); +} + +static int +disk_unlink(wchar_t *path) +{ + wchar_t *fullname; + int r; + + r = _wunlink(path); + if (r != 0 && GetLastError() == ERROR_INVALID_NAME) { + fullname = __la_win_permissive_name_w(path); + r = _wunlink(fullname); + free(fullname); + } + return (r); +} + +static int +disk_rmdir(wchar_t *path) +{ + wchar_t *fullname; + int r; + + r = _wrmdir(path); + if (r != 0 && GetLastError() == ERROR_INVALID_NAME) { + fullname = __la_win_permissive_name_w(path); + r = _wrmdir(fullname); + free(fullname); + } + return (r); +} + +/* + * The main restore function. + */ +static int +restore_entry(struct archive_write_disk *a) +{ + int ret = ARCHIVE_OK, en; + + if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { + /* + * TODO: Fix this. Apparently, there are platforms + * that still allow root to hose the entire filesystem + * by unlinking a dir. The S_ISDIR() test above + * prevents us from using unlink() here if the new + * object is a dir, but that doesn't mean the old + * object isn't a dir. + */ + if (disk_unlink(a->name) == 0) { + /* We removed it, reset cached stat. */ + a->pst = NULL; + } else if (errno == ENOENT) { + /* File didn't exist, that's just as good. */ + } else if (disk_rmdir(a->name) == 0) { + /* It was a dir, but now it's gone. */ + a->pst = NULL; + } else { + /* We tried, but couldn't get rid of it. */ + archive_set_error(&a->archive, errno, + "Could not unlink"); + return(ARCHIVE_FAILED); + } + } + + /* Try creating it first; if this fails, we'll try to recover. */ + en = create_filesystem_object(a); + + if ((en == ENOTDIR || en == ENOENT) + && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { + wchar_t *full; + /* If the parent dir doesn't exist, try creating it. */ + create_parent_dir(a, a->name); + /* Now try to create the object again. */ + full = __la_win_permissive_name_w(a->name); + if (full == NULL) { + en = EINVAL; + } else { + /* Remove multiple directories such as "a/../b../c" */ + archive_wstrcpy(&(a->_name_data), full); + a->name = a->_name_data.s; + free(full); + en = create_filesystem_object(a); + } + } + + if ((en == EISDIR || en == EEXIST) + && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { + /* If we're not overwriting, we're done. */ + archive_entry_unset_size(a->entry); + return (ARCHIVE_OK); + } + + /* + * Some platforms return EISDIR if you call + * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some + * return EEXIST. POSIX is ambiguous, requiring EISDIR + * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) + * on an existing item. + */ + if (en == EISDIR) { + /* A dir is in the way of a non-dir, rmdir it. */ + if (disk_rmdir(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't remove already-existing dir"); + return (ARCHIVE_FAILED); + } + a->pst = NULL; + /* Try again. */ + en = create_filesystem_object(a); + } else if (en == EEXIST) { + mode_t st_mode; + /* + * We know something is in the way, but we don't know what; + * we need to find out before we go any further. + */ + int r = 0; + /* + * The SECURE_SYMLINK logic has already removed a + * symlink to a dir if the client wants that. So + * follow the symlink if we're creating a dir. + */ + if (S_ISDIR(a->mode)) + r = file_information(a, a->name, &a->st, &st_mode, 0); + /* + * If it's not a dir (or it's a broken symlink), + * then don't follow it. + */ + if (r != 0 || !S_ISDIR(a->mode)) + r = file_information(a, a->name, &a->st, &st_mode, 1); + if (r != 0) { + archive_set_error(&a->archive, errno, + "Can't stat existing object"); + return (ARCHIVE_FAILED); + } + + /* + * NO_OVERWRITE_NEWER doesn't apply to directories. + */ + if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) + && !S_ISDIR(st_mode)) { + if (!older(&(a->st), a->entry)) { + archive_entry_unset_size(a->entry); + return (ARCHIVE_OK); + } + } + + /* If it's our archive, we're done. */ + if (a->skip_file_set && + bhfi_dev(&a->st) == a->skip_file_dev && + bhfi_ino(&a->st) == a->skip_file_ino) { + archive_set_error(&a->archive, 0, + "Refusing to overwrite archive"); + return (ARCHIVE_FAILED); + } + + if (!S_ISDIR(st_mode)) { + /* A non-dir is in the way, unlink it. */ + if (disk_unlink(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't unlink already-existing object"); + return (ARCHIVE_FAILED); + } + a->pst = NULL; + /* Try again. */ + en = create_filesystem_object(a); + } else if (!S_ISDIR(a->mode)) { + /* A dir is in the way of a non-dir, rmdir it. */ + if (disk_rmdir(a->name) != 0) { + archive_set_error(&a->archive, errno, + "Can't remove already-existing dir"); + return (ARCHIVE_FAILED); + } + /* Try again. */ + en = create_filesystem_object(a); + } else { + /* + * There's a dir in the way of a dir. Don't + * waste time with rmdir()/mkdir(), just fix + * up the permissions on the existing dir. + * Note that we don't change perms on existing + * dirs unless _EXTRACT_PERM is specified. + */ + if ((a->mode != st_mode) + && (a->todo & TODO_MODE_FORCE)) + a->deferred |= (a->todo & TODO_MODE); + /* Ownership doesn't need deferred fixup. */ + en = 0; /* Forget the EEXIST. */ + } + } + + if (en) { + /* Everything failed; give up here. */ + archive_set_error(&a->archive, en, "Can't create '%ls'", + a->name); + return (ARCHIVE_FAILED); + } + + a->pst = NULL; /* Cached stat data no longer valid. */ + return (ret); +} + +/* + * Returns 0 if creation succeeds, or else returns errno value from + * the failed system call. Note: This function should only ever perform + * a single system call. + */ +static int +create_filesystem_object(struct archive_write_disk *a) +{ + /* Create the entry. */ + const wchar_t *linkname; + wchar_t *fullname; + mode_t final_mode, mode; + int r; + + /* We identify hard/symlinks according to the link names. */ + /* Since link(2) and symlink(2) don't handle modes, we're done here. */ + linkname = archive_entry_hardlink_w(a->entry); + if (linkname != NULL) { + wchar_t *linkfull, *namefull; + + linkfull = __la_win_permissive_name_w(linkname); + namefull = __la_win_permissive_name_w(a->name); + if (linkfull == NULL || namefull == NULL) { + errno = EINVAL; + r = -1; + } else { + r = la_CreateHardLinkW(namefull, linkfull); + if (r == 0) { + la_dosmaperr(GetLastError()); + r = errno; + } else + r = 0; + } + /* + * New cpio and pax formats allow hardlink entries + * to carry data, so we may have to open the file + * for hardlink entries. + * + * If the hardlink was successfully created and + * the archive doesn't have carry data for it, + * consider it to be non-authoritative for meta data. + * This is consistent with GNU tar and BSD pax. + * If the hardlink does carry data, let the last + * archive entry decide ownership. + */ + if (r == 0 && a->filesize <= 0) { + a->todo = 0; + a->deferred = 0; + } else if (r == 0 && a->filesize > 0) { + a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL, + TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (a->fh == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + r = errno; + } + } + free(linkfull); + free(namefull); + return (r); + } + linkname = archive_entry_symlink_w(a->entry); + if (linkname != NULL) { +#if HAVE_SYMLINK + return symlink(linkname, a->name) ? errno : 0; +#else + return (EPERM); +#endif + } + + /* + * The remaining system calls all set permissions, so let's + * try to take advantage of that to avoid an extra chmod() + * call. (Recall that umask is set to zero right now!) + */ + + /* Mode we want for the final restored object (w/o file type bits). */ + final_mode = a->mode & 07777; + /* + * The mode that will actually be restored in this step. Note + * that SUID, SGID, etc, require additional work to ensure + * security, so we never restore them at this point. + */ + mode = final_mode & 0777 & ~a->user_umask; + + switch (a->mode & AE_IFMT) { + default: + /* POSIX requires that we fall through here. */ + /* FALLTHROUGH */ + case AE_IFREG: + fullname = a->name; + /* O_WRONLY | O_CREAT | O_EXCL */ + a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (a->fh == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_NAME && + fullname == a->name) { + fullname = __la_win_permissive_name_w(a->name); + a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + } + if (a->fh == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_ACCESS_DENIED) { + DWORD attr; + /* Simulate an errno of POSIX system. */ + attr = GetFileAttributesW(fullname); + if (attr == (DWORD)-1) + la_dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } else + la_dosmaperr(GetLastError()); + r = 1; + } else + r = 0; + if (fullname != a->name) + free(fullname); + break; + case AE_IFCHR: + case AE_IFBLK: + /* TODO: Find a better way to warn about our inability + * to restore a block device node. */ + return (EINVAL); + case AE_IFDIR: + mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; + fullname = a->name; + r = CreateDirectoryW(fullname, NULL); + if (r == 0 && GetLastError() == ERROR_INVALID_NAME && + fullname == a->name) { + fullname = __la_win_permissive_name_w(a->name); + r = CreateDirectoryW(fullname, NULL); + } + if (r != 0) { + r = 0; + /* Defer setting dir times. */ + a->deferred |= (a->todo & TODO_TIMES); + a->todo &= ~TODO_TIMES; + /* Never use an immediate chmod(). */ + /* We can't avoid the chmod() entirely if EXTRACT_PERM + * because of SysV SGID inheritance. */ + if ((mode != final_mode) + || (a->flags & ARCHIVE_EXTRACT_PERM)) + a->deferred |= (a->todo & TODO_MODE); + a->todo &= ~TODO_MODE; + } else { + la_dosmaperr(GetLastError()); + r = -1; + } + if (fullname != a->name) + free(fullname); + break; + case AE_IFIFO: + /* TODO: Find a better way to warn about our inability + * to restore a fifo. */ + return (EINVAL); + } + + /* All the system calls above set errno on failure. */ + if (r) + return (errno); + + /* If we managed to set the final mode, we've avoided a chmod(). */ + if (mode == final_mode) + a->todo &= ~TODO_MODE; + return (0); +} + +/* + * Cleanup function for archive_extract. Mostly, this involves processing + * the fixup list, which is used to address a number of problems: + * * Dir permissions might prevent us from restoring a file in that + * dir, so we restore the dir with minimum 0700 permissions first, + * then correct the mode at the end. + * * Similarly, the act of restoring a file touches the directory + * and changes the timestamp on the dir, so we have to touch-up dir + * timestamps at the end as well. + * * Some file flags can interfere with the restore by, for example, + * preventing the creation of hardlinks to those files. + * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. + * + * Note that tar/cpio do not require that archives be in a particular + * order; there is no way to know when the last file has been restored + * within a directory, so there's no way to optimize the memory usage + * here by fixing up the directory any earlier than the + * end-of-archive. + * + * XXX TODO: Directory ACLs should be restored here, for the same + * reason we set directory perms here. XXX + */ +static int +_archive_write_disk_close(struct archive *_a) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + struct fixup_entry *next, *p; + int ret; + + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_disk_close"); + ret = _archive_write_disk_finish_entry(&a->archive); + + /* Sort dir list so directories are fixed up in depth-first order. */ + p = sort_dir_list(a->fixup_list); + + while (p != NULL) { + a->pst = NULL; /* Mark stat cache as out-of-date. */ + if (p->fixup & TODO_TIMES) { + set_times(a, INVALID_HANDLE_VALUE, p->mode, p->name, + p->atime, p->atime_nanos, + p->birthtime, p->birthtime_nanos, + p->mtime, p->mtime_nanos, + p->ctime, p->ctime_nanos); + } + if (p->fixup & TODO_MODE_BASE) + la_chmod(p->name, p->mode); + if (p->fixup & TODO_ACLS) + set_acls(a, INVALID_HANDLE_VALUE, p->name, &p->acl); + next = p->next; + archive_acl_clear(&p->acl); + free(p->name); + free(p); + p = next; + } + a->fixup_list = NULL; + return (ret); +} + +static int +_archive_write_disk_free(struct archive *_a) +{ + struct archive_write_disk *a; + int ret; + if (_a == NULL) + return (ARCHIVE_OK); + archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); + a = (struct archive_write_disk *)_a; + ret = _archive_write_disk_close(&a->archive); + archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); + archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); + if (a->entry) + archive_entry_free(a->entry); + archive_wstring_free(&a->_name_data); + archive_string_free(&a->archive.error_string); + archive_wstring_free(&a->path_safe); + a->archive.magic = 0; + __archive_clean(&a->archive); + free(a); + return (ret); +} + +/* + * Simple O(n log n) merge sort to order the fixup list. In + * particular, we want to restore dir timestamps depth-first. + */ +static struct fixup_entry * +sort_dir_list(struct fixup_entry *p) +{ + struct fixup_entry *a, *b, *t; + + if (p == NULL) + return (NULL); + /* A one-item list is already sorted. */ + if (p->next == NULL) + return (p); + + /* Step 1: split the list. */ + t = p; + a = p->next->next; + while (a != NULL) { + /* Step a twice, t once. */ + a = a->next; + if (a != NULL) + a = a->next; + t = t->next; + } + /* Now, t is at the mid-point, so break the list here. */ + b = t->next; + t->next = NULL; + a = p; + + /* Step 2: Recursively sort the two sub-lists. */ + a = sort_dir_list(a); + b = sort_dir_list(b); + + /* Step 3: Merge the returned lists. */ + /* Pick the first element for the merged list. */ + if (wcscmp(a->name, b->name) > 0) { + t = p = a; + a = a->next; + } else { + t = p = b; + b = b->next; + } + + /* Always put the later element on the list first. */ + while (a != NULL && b != NULL) { + if (wcscmp(a->name, b->name) > 0) { + t->next = a; + a = a->next; + } else { + t->next = b; + b = b->next; + } + t = t->next; + } + + /* Only one list is non-empty, so just splice it on. */ + if (a != NULL) + t->next = a; + if (b != NULL) + t->next = b; + + return (p); +} + +/* + * Returns a new, initialized fixup entry. + * + * TODO: Reduce the memory requirements for this list by using a tree + * structure rather than a simple list of names. + */ +static struct fixup_entry * +new_fixup(struct archive_write_disk *a, const wchar_t *pathname) +{ + struct fixup_entry *fe; + + fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); + if (fe == NULL) + return (NULL); + fe->next = a->fixup_list; + a->fixup_list = fe; + fe->fixup = 0; + fe->name = _wcsdup(pathname); + return (fe); +} + +/* + * Returns a fixup structure for the current entry. + */ +static struct fixup_entry * +current_fixup(struct archive_write_disk *a, const wchar_t *pathname) +{ + if (a->current_fixup == NULL) + a->current_fixup = new_fixup(a, pathname); + return (a->current_fixup); +} + +/* TODO: Make this work. */ +/* + * TODO: The deep-directory support bypasses this; disable deep directory + * support if we're doing symlink checks. + */ +/* + * TODO: Someday, integrate this with the deep dir support; they both + * scan the path and both can be optimized by comparing against other + * recent paths. + */ +/* TODO: Extend this to support symlinks on Windows Vista and later. */ +static int +check_symlinks(struct archive_write_disk *a) +{ + wchar_t *pn, *p; + wchar_t c; + int r; + BY_HANDLE_FILE_INFORMATION st; + mode_t st_mode; + + /* + * Guard against symlink tricks. Reject any archive entry whose + * destination would be altered by a symlink. + */ + /* Whatever we checked last time doesn't need to be re-checked. */ + pn = a->name; + p = a->path_safe.s; + while ((*pn != '\0') && (*p == *pn)) + ++p, ++pn; + c = pn[0]; + /* Keep going until we've checked the entire name. */ + while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) { + /* Skip the next path element. */ + while (*pn != '\0' && *pn != '\\') + ++pn; + c = pn[0]; + pn[0] = '\0'; + /* Check that we haven't hit a symlink. */ + r = file_information(a, a->name, &st, &st_mode, 1); + if (r != 0) { + /* We've hit a dir that doesn't exist; stop now. */ + if (errno == ENOENT) + break; + } else if (S_ISLNK(st_mode)) { + if (c == '\0') { + /* + * Last element is symlink; remove it + * so we can overwrite it with the + * item being extracted. + */ + if (disk_unlink(a->name)) { + archive_set_error(&a->archive, errno, + "Could not remove symlink %ls", + a->name); + pn[0] = c; + return (ARCHIVE_FAILED); + } + a->pst = NULL; + /* + * Even if we did remove it, a warning + * is in order. The warning is silly, + * though, if we're just replacing one + * symlink with another symlink. + */ + if (!S_ISLNK(a->mode)) { + archive_set_error(&a->archive, 0, + "Removing symlink %ls", + a->name); + } + /* Symlink gone. No more problem! */ + pn[0] = c; + return (0); + } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { + /* User asked us to remove problems. */ + if (disk_unlink(a->name) != 0) { + archive_set_error(&a->archive, 0, + "Cannot remove intervening " + "symlink %ls", a->name); + pn[0] = c; + return (ARCHIVE_FAILED); + } + a->pst = NULL; + } else { + archive_set_error(&a->archive, 0, + "Cannot extract through symlink %ls", + a->name); + pn[0] = c; + return (ARCHIVE_FAILED); + } + } + } + pn[0] = c; + /* We've checked and/or cleaned the whole path, so remember it. */ + archive_wstrcpy(&a->path_safe, a->name); + return (ARCHIVE_OK); +} + +static int +guidword(wchar_t *p, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if ((*p >= L'0' && *p <= L'9') || + (*p >= L'a' && *p <= L'f') || + (*p >= L'A' && *p <= L'F')) + p++; + else + return (-1); + } + return (0); +} + +/* + * Canonicalize the pathname. In particular, this strips duplicate + * '\' characters, '.' elements, and trailing '\'. It also raises an + * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is + * set) any '..' in the path. + */ +static int +cleanup_pathname(struct archive_write_disk *a) +{ + wchar_t *dest, *src, *p, *top; + wchar_t separator = L'\0'; + + p = a->name; + if (*p == L'\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid empty pathname"); + return (ARCHIVE_FAILED); + } + + /* Replace '/' by '\' */ + for (; *p != L'\0'; p++) { + if (*p == L'/') + *p = L'\\'; + } + p = a->name; + + /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or + * "\\?\Volume{GUID}\" + * (absolute path prefixes used by Windows API) */ + if (p[0] == L'\\' && p[1] == L'\\' && + (p[2] == L'.' || p[2] == L'?') && p[3] == L'\\') + { + /* A path begin with "\\?\UNC\" */ + if (p[2] == L'?' && + (p[4] == L'U' || p[4] == L'u') && + (p[5] == L'N' || p[5] == L'n') && + (p[6] == L'C' || p[6] == L'c') && + p[7] == L'\\') + p += 8; + /* A path begin with "\\?\Volume{GUID}\" */ + else if (p[2] == L'?' && + (p[4] == L'V' || p[4] == L'v') && + (p[5] == L'O' || p[5] == L'o') && + (p[6] == L'L' || p[6] == L'l') && + (p[7] == L'U' || p[7] == L'u') && + (p[8] == L'M' || p[8] == L'm') && + (p[9] == L'E' || p[9] == L'e') && + p[10] == L'{') { + if (guidword(p+11, 8) == 0 && p[19] == L'-' && + guidword(p+20, 4) == 0 && p[24] == L'-' && + guidword(p+25, 4) == 0 && p[29] == L'-' && + guidword(p+30, 4) == 0 && p[34] == L'-' && + guidword(p+35, 12) == 0 && p[47] == L'}' && + p[48] == L'\\') + p += 49; + else + p += 4; + /* A path begin with "\\.\PhysicalDriveX" */ + } else if (p[2] == L'.' && + (p[4] == L'P' || p[4] == L'p') && + (p[5] == L'H' || p[5] == L'h') && + (p[6] == L'Y' || p[6] == L'y') && + (p[7] == L'S' || p[7] == L's') && + (p[8] == L'I' || p[8] == L'i') && + (p[9] == L'C' || p[9] == L'c') && + (p[9] == L'A' || p[9] == L'a') && + (p[9] == L'L' || p[9] == L'l') && + (p[9] == L'D' || p[9] == L'd') && + (p[9] == L'R' || p[9] == L'r') && + (p[9] == L'I' || p[9] == L'i') && + (p[9] == L'V' || p[9] == L'v') && + (p[9] == L'E' || p[9] == L'e') && + (p[10] >= L'0' && p[10] <= L'9') && + p[11] == L'\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Path is a physical drive name"); + return (ARCHIVE_FAILED); + } else + p += 4; + } + + /* Skip leading drive letter from archives created + * on Windows. */ + if (((p[0] >= L'a' && p[0] <= L'z') || + (p[0] >= L'A' && p[0] <= L'Z')) && + p[1] == L':') { + if (p[2] == L'\0') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Path is a drive name"); + return (ARCHIVE_FAILED); + } + if (p[2] == L'\\') + p += 2; + } + + top = dest = src = p; + /* Rewrite the path name if its character is a unusable. */ + for (; *p != L'\0'; p++) { + if (*p == L':' || *p == L'*' || *p == L'?' || *p == L'"' || + *p == L'<' || *p == L'>' || *p == L'|') + *p = L'_'; + } + /* Skip leading '\'. */ + if (*src == L'\\') + separator = *src++; + + /* Scan the pathname one element at a time. */ + for (;;) { + /* src points to first char after '\' */ + if (src[0] == L'\0') { + break; + } else if (src[0] == L'\\') { + /* Found '\\'('//'), ignore second one. */ + src++; + continue; + } else if (src[0] == L'.') { + if (src[1] == L'\0') { + /* Ignore trailing '.' */ + break; + } else if (src[1] == L'\\') { + /* Skip '.\'. */ + src += 2; + continue; + } else if (src[1] == L'.') { + if (src[2] == L'\\' || src[2] == L'\0') { + /* Conditionally warn about '..' */ + if (a->flags & + ARCHIVE_EXTRACT_SECURE_NODOTDOT) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Path contains '..'"); + return (ARCHIVE_FAILED); + } + } + /* + * Note: Under no circumstances do we + * remove '..' elements. In + * particular, restoring + * '\foo\..\bar\' should create the + * 'foo' dir as a side-effect. + */ + } + } + + /* Copy current element, including leading '\'. */ + if (separator) + *dest++ = L'\\'; + while (*src != L'\0' && *src != L'\\') { + *dest++ = *src++; + } + + if (*src == L'\0') + break; + + /* Skip '\' separator. */ + separator = *src++; + } + /* + * We've just copied zero or more path elements, not including the + * final '\'. + */ + if (dest == top) { + /* + * Nothing got copied. The path must have been something + * like '.' or '\' or './' or '/././././/./'. + */ + if (separator) + *dest++ = L'\\'; + else + *dest++ = L'.'; + } + /* Terminate the result. */ + *dest = L'\0'; + return (ARCHIVE_OK); +} + +/* + * Create the parent directory of the specified path, assuming path + * is already in mutable storage. + */ +static int +create_parent_dir(struct archive_write_disk *a, wchar_t *path) +{ + wchar_t *slash; + int r; + + /* Remove tail element to obtain parent name. */ + slash = wcsrchr(path, L'\\'); + if (slash == NULL) + return (ARCHIVE_OK); + *slash = L'\0'; + r = create_dir(a, path); + *slash = L'\\'; + return (r); +} + +/* + * Create the specified dir, recursing to create parents as necessary. + * + * Returns ARCHIVE_OK if the path exists when we're done here. + * Otherwise, returns ARCHIVE_FAILED. + * Assumes path is in mutable storage; path is unchanged on exit. + */ +static int +create_dir(struct archive_write_disk *a, wchar_t *path) +{ + BY_HANDLE_FILE_INFORMATION st; + struct fixup_entry *le; + wchar_t *slash, *base, *full; + mode_t mode_final, mode, st_mode; + int r; + + /* Check for special names and just skip them. */ + slash = wcsrchr(path, L'\\'); + if (slash == NULL) + base = path; + else + base = slash + 1; + + if (base[0] == L'\0' || + (base[0] == L'.' && base[1] == L'\0') || + (base[0] == L'.' && base[1] == L'.' && base[2] == L'\0')) { + /* Don't bother trying to create null path, '.', or '..'. */ + if (slash != NULL) { + *slash = L'\0'; + r = create_dir(a, path); + *slash = L'\\'; + return (r); + } + return (ARCHIVE_OK); + } + + /* + * Yes, this should be stat() and not lstat(). Using lstat() + * here loses the ability to extract through symlinks. Also note + * that this should not use the a->st cache. + */ + if (file_information(a, path, &st, &st_mode, 0) == 0) { + if (S_ISDIR(st_mode)) + return (ARCHIVE_OK); + if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { + archive_set_error(&a->archive, EEXIST, + "Can't create directory '%ls'", path); + return (ARCHIVE_FAILED); + } + if (disk_unlink(path) != 0) { + archive_set_error(&a->archive, errno, + "Can't create directory '%ls': " + "Conflicting file cannot be removed", + path); + return (ARCHIVE_FAILED); + } + } else if (errno != ENOENT && errno != ENOTDIR) { + /* Stat failed? */ + archive_set_error(&a->archive, errno, + "Can't test directory '%ls'", path); + return (ARCHIVE_FAILED); + } else if (slash != NULL) { + *slash = '\0'; + r = create_dir(a, path); + *slash = '\\'; + if (r != ARCHIVE_OK) + return (r); + } + + /* + * Mode we want for the final restored directory. Per POSIX, + * implicitly-created dirs must be created obeying the umask. + * There's no mention whether this is different for privileged + * restores (which the rest of this code handles by pretending + * umask=0). I've chosen here to always obey the user's umask for + * implicit dirs, even if _EXTRACT_PERM was specified. + */ + mode_final = DEFAULT_DIR_MODE & ~a->user_umask; + /* Mode we want on disk during the restore process. */ + mode = mode_final; + mode |= MINIMUM_DIR_MODE; + mode &= MAXIMUM_DIR_MODE; + /* + * Apply __la_win_permissive_name_w to path in order to + * remove '../' path string. + */ + full = __la_win_permissive_name_w(path); + if (full == NULL) + errno = EINVAL; + else if (CreateDirectoryW(full, NULL) != 0) { + if (mode != mode_final) { + le = new_fixup(a, path); + le->fixup |=TODO_MODE_BASE; + le->mode = mode_final; + } + free(full); + return (ARCHIVE_OK); + } else { + la_dosmaperr(GetLastError()); + } + free(full); + + /* + * Without the following check, a/b/../b/c/d fails at the + * second visit to 'b', so 'd' can't be created. Note that we + * don't add it to the fixup list here, as it's already been + * added. + */ + if (file_information(a, path, &st, &st_mode, 0) == 0 && + S_ISDIR(st_mode)) + return (ARCHIVE_OK); + + archive_set_error(&a->archive, errno, "Failed to create dir '%ls'", + path); + return (ARCHIVE_FAILED); +} + +/* + * Note: Although we can skip setting the user id if the desired user + * id matches the current user, we cannot skip setting the group, as + * many systems set the gid based on the containing directory. So + * we have to perform a chown syscall if we want to set the SGID + * bit. (The alternative is to stat() and then possibly chown(); it's + * more efficient to skip the stat() and just always chown().) Note + * that a successful chown() here clears the TODO_SGID_CHECK bit, which + * allows set_mode to skip the stat() check for the GID. + */ +static int +set_ownership(struct archive_write_disk *a) +{ +/* unfortunately, on win32 there is no 'root' user with uid 0, + so we just have to try the chown and see if it works */ + + /* If we know we can't change it, don't bother trying. */ + if (a->user_uid != 0 && a->user_uid != a->uid) { + archive_set_error(&a->archive, errno, + "Can't set UID=%jd", (intmax_t)a->uid); + return (ARCHIVE_WARN); + } + + archive_set_error(&a->archive, errno, + "Can't set user=%jd/group=%jd for %ls", + (intmax_t)a->uid, (intmax_t)a->gid, a->name); + return (ARCHIVE_WARN); +} + +static int +set_times(struct archive_write_disk *a, + HANDLE h, int mode, const wchar_t *name, + time_t atime, long atime_nanos, + time_t birthtime, long birthtime_nanos, + time_t mtime, long mtime_nanos, + time_t ctime_sec, long ctime_nanos) +{ +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) +#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ + + (((nsec)/1000)*10)) + + HANDLE hw = 0; + ULARGE_INTEGER wintm; + FILETIME *pfbtime; + FILETIME fatime, fbtime, fmtime; + + (void)ctime_sec; /* UNUSED */ + (void)ctime_nanos; /* UNUSED */ + + if (h != INVALID_HANDLE_VALUE) { + hw = NULL; + } else { + wchar_t *ws; + + if (S_ISLNK(mode)) + return (ARCHIVE_OK); + ws = __la_win_permissive_name_w(name); + if (ws == NULL) + goto settimes_failed; + hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES, + 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + free(ws); + if (hw == INVALID_HANDLE_VALUE) + goto settimes_failed; + h = hw; + } + + wintm.QuadPart = WINTIME(atime, atime_nanos); + fatime.dwLowDateTime = wintm.LowPart; + fatime.dwHighDateTime = wintm.HighPart; + wintm.QuadPart = WINTIME(mtime, mtime_nanos); + fmtime.dwLowDateTime = wintm.LowPart; + fmtime.dwHighDateTime = wintm.HighPart; + /* + * SetFileTime() supports birthtime. + */ + if (birthtime > 0 || birthtime_nanos > 0) { + wintm.QuadPart = WINTIME(birthtime, birthtime_nanos); + fbtime.dwLowDateTime = wintm.LowPart; + fbtime.dwHighDateTime = wintm.HighPart; + pfbtime = &fbtime; + } else + pfbtime = NULL; + if (SetFileTime(h, pfbtime, &fatime, &fmtime) == 0) + goto settimes_failed; + CloseHandle(hw); + return (ARCHIVE_OK); + +settimes_failed: + CloseHandle(hw); + archive_set_error(&a->archive, EINVAL, "Can't restore time"); + return (ARCHIVE_WARN); +} + +static int +set_times_from_entry(struct archive_write_disk *a) +{ + time_t atime, birthtime, mtime, ctime_sec; + long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; + + /* Suitable defaults. */ + atime = birthtime = mtime = ctime_sec = a->start_time; + atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; + + /* If no time was provided, we're done. */ + if (!archive_entry_atime_is_set(a->entry) + && !archive_entry_birthtime_is_set(a->entry) + && !archive_entry_mtime_is_set(a->entry)) + return (ARCHIVE_OK); + + if (archive_entry_atime_is_set(a->entry)) { + atime = archive_entry_atime(a->entry); + atime_nsec = archive_entry_atime_nsec(a->entry); + } + if (archive_entry_birthtime_is_set(a->entry)) { + birthtime = archive_entry_birthtime(a->entry); + birthtime_nsec = archive_entry_birthtime_nsec(a->entry); + } + if (archive_entry_mtime_is_set(a->entry)) { + mtime = archive_entry_mtime(a->entry); + mtime_nsec = archive_entry_mtime_nsec(a->entry); + } + if (archive_entry_ctime_is_set(a->entry)) { + ctime_sec = archive_entry_ctime(a->entry); + ctime_nsec = archive_entry_ctime_nsec(a->entry); + } + + return set_times(a, a->fh, a->mode, a->name, + atime, atime_nsec, + birthtime, birthtime_nsec, + mtime, mtime_nsec, + ctime_sec, ctime_nsec); +} + +static int +set_mode(struct archive_write_disk *a, int mode) +{ + int r = ARCHIVE_OK; + mode &= 07777; /* Strip off file type bits. */ + + if (a->todo & TODO_SGID_CHECK) { + /* + * If we don't know the GID is right, we must stat() + * to verify it. We can't just check the GID of this + * process, since systems sometimes set GID from + * the enclosing dir or based on ACLs. + */ + if ((r = lazy_stat(a)) != ARCHIVE_OK) + return (r); + if (0 != a->gid) { + mode &= ~ S_ISGID; + } + /* While we're here, double-check the UID. */ + if (0 != a->uid + && (a->todo & TODO_SUID)) { + mode &= ~ S_ISUID; + } + a->todo &= ~TODO_SGID_CHECK; + a->todo &= ~TODO_SUID_CHECK; + } else if (a->todo & TODO_SUID_CHECK) { + /* + * If we don't know the UID is right, we can just check + * the user, since all systems set the file UID from + * the process UID. + */ + if (a->user_uid != a->uid) { + mode &= ~ S_ISUID; + } + a->todo &= ~TODO_SUID_CHECK; + } + + if (S_ISLNK(a->mode)) { +#ifdef HAVE_LCHMOD + /* + * If this is a symlink, use lchmod(). If the + * platform doesn't support lchmod(), just skip it. A + * platform that doesn't provide a way to set + * permissions on symlinks probably ignores + * permissions on symlinks, so a failure here has no + * impact. + */ + if (lchmod(a->name, mode) != 0) { + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } +#endif + } else if (!S_ISDIR(a->mode)) { + /* + * If it's not a symlink and not a dir, then use + * fchmod() or chmod(), depending on whether we have + * an fd. Dirs get their perms set during the + * post-extract fixup, which is handled elsewhere. + */ +#ifdef HAVE_FCHMOD + if (a->fd >= 0) { + if (fchmod(a->fd, mode) != 0) { + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } + } else +#endif + /* If this platform lacks fchmod(), then + * we'll just use chmod(). */ + if (la_chmod(a->name, mode) != 0) { + archive_set_error(&a->archive, errno, + "Can't set permissions to 0%o", (int)mode); + r = ARCHIVE_WARN; + } + } + return (r); +} + +static int +set_fflags(struct archive_write_disk *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} + +/* Default empty function body to satisfy mainline code. */ +static int +set_acls(struct archive_write_disk *a, HANDLE h, const wchar_t *name, + struct archive_acl *acl) +{ + (void)a; /* UNUSED */ + (void)h; /* UNUSED */ + (void)name; /* UNUSED */ + (void)acl; /* UNUSED */ + return (ARCHIVE_OK); +} + +/* + * Restore extended attributes - stub implementation for unsupported systems + */ +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; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Cannot restore extended attributes on this system"); + return (ARCHIVE_WARN); + } + /* Warning was already emitted; suppress further warnings. */ + return (ARCHIVE_OK); +} + +static void +fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + /* milli seconds base */ + *t = (time_t)(utc.QuadPart / 10000000); + /* nano seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100; + } else { + *t = 0; + *ns = 0; + } +} +/* + * Test if file on disk is older than entry. + */ +static int +older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry) +{ + time_t sec; + long nsec; + + fileTimeToUtc(&st->ftLastWriteTime, &sec, &nsec); + /* First, test the seconds and return if we have a definite answer. */ + /* Definitely older. */ + if (sec < archive_entry_mtime(entry)) + return (1); + /* Definitely younger. */ + if (sec > archive_entry_mtime(entry)) + return (0); + if (nsec < archive_entry_mtime_nsec(entry)) + return (1); + /* Same age or newer, so not older. */ + return (0); +} + +#endif /* _WIN32 && !__CYGWIN__ */ + diff --git a/src/3rdparty/libarchive/libarchive/archive_write_open_fd.c b/src/3rdparty/libarchive/libarchive/archive_write_open_fd.c new file mode 100644 index 00000000..d5c426cf --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_open_fd.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_fd.c 201093 2009-12-28 02:28:44Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" + +struct write_fd_data { + int fd; +}; + +static int file_close(struct archive *, void *); +static int file_open(struct archive *, void *); +static ssize_t file_write(struct archive *, void *, const void *buff, size_t); + +int +archive_write_open_fd(struct archive *a, int fd) +{ + struct write_fd_data *mine; + + mine = (struct write_fd_data *)malloc(sizeof(*mine)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + mine->fd = fd; +#if defined(__CYGWIN__) || defined(_WIN32) + setmode(mine->fd, O_BINARY); +#endif + return (archive_write_open(a, mine, + file_open, file_write, file_close)); +} + +static int +file_open(struct archive *a, void *client_data) +{ + struct write_fd_data *mine; + struct stat st; + + mine = (struct write_fd_data *)client_data; + + if (fstat(mine->fd, &st) != 0) { + archive_set_error(a, errno, "Couldn't stat fd %d", mine->fd); + return (ARCHIVE_FATAL); + } + + /* + * If this is a regular file, don't add it to itself. + */ + if (S_ISREG(st.st_mode)) + archive_write_set_skip_file(a, st.st_dev, st.st_ino); + + /* + * If client hasn't explicitly set the last block handling, + * then set it here. + */ + if (archive_write_get_bytes_in_last_block(a) < 0) { + /* If the output is a block or character device, fifo, + * or stdout, pad the last block, otherwise leave it + * unpadded. */ + if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || + S_ISFIFO(st.st_mode) || (mine->fd == 1)) + /* Last block will be fully padded. */ + archive_write_set_bytes_in_last_block(a, 0); + else + archive_write_set_bytes_in_last_block(a, 1); + } + + return (ARCHIVE_OK); +} + +static ssize_t +file_write(struct archive *a, void *client_data, const void *buff, size_t length) +{ + struct write_fd_data *mine; + ssize_t bytesWritten; + + mine = (struct write_fd_data *)client_data; + for (;;) { + bytesWritten = write(mine->fd, buff, length); + if (bytesWritten <= 0) { + if (errno == EINTR) + continue; + archive_set_error(a, errno, "Write error"); + return (-1); + } + return (bytesWritten); + } +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct write_fd_data *mine = (struct write_fd_data *)client_data; + + (void)a; /* UNUSED */ + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_open_file.c b/src/3rdparty/libarchive/libarchive/archive_write_open_file.c new file mode 100644 index 00000000..f6b14123 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_open_file.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_file.c,v 1.19 2007/01/09 08:05:56 kientzle Exp $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" + +struct write_FILE_data { + FILE *f; +}; + +static int file_close(struct archive *, void *); +static int file_open(struct archive *, void *); +static ssize_t file_write(struct archive *, void *, const void *buff, size_t); + +int +archive_write_open_FILE(struct archive *a, FILE *f) +{ + struct write_FILE_data *mine; + + mine = (struct write_FILE_data *)malloc(sizeof(*mine)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + mine->f = f; + return (archive_write_open(a, mine, + file_open, file_write, file_close)); +} + +static int +file_open(struct archive *a, void *client_data) +{ + (void)a; /* UNUSED */ + (void)client_data; /* UNUSED */ + + return (ARCHIVE_OK); +} + +static ssize_t +file_write(struct archive *a, void *client_data, const void *buff, size_t length) +{ + struct write_FILE_data *mine; + size_t bytesWritten; + + mine = client_data; + for (;;) { + bytesWritten = fwrite(buff, 1, length, mine->f); + if (bytesWritten <= 0) { + if (errno == EINTR) + continue; + archive_set_error(a, errno, "Write error"); + return (-1); + } + return (bytesWritten); + } +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct write_FILE_data *mine = client_data; + + (void)a; /* UNUSED */ + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_open_filename.c b/src/3rdparty/libarchive/libarchive/archive_write_open_filename.c new file mode 100644 index 00000000..66e0dfee --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_open_filename.c @@ -0,0 +1,253 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 2009-04-17 00:39:35Z kientzle $"); + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +struct write_file_data { + int fd; + struct archive_mstring filename; +}; + +static int file_close(struct archive *, void *); +static int file_open(struct archive *, void *); +static ssize_t file_write(struct archive *, void *, const void *buff, size_t); +static int open_filename(struct archive *, int, const void *); + +int +archive_write_open_file(struct archive *a, const char *filename) +{ + return (archive_write_open_filename(a, filename)); +} + +int +archive_write_open_filename(struct archive *a, const char *filename) +{ + + if (filename == NULL || filename[0] == '\0') + return (archive_write_open_fd(a, 1)); + + return (open_filename(a, 1, filename)); +} + +int +archive_write_open_filename_w(struct archive *a, const wchar_t *filename) +{ + + if (filename == NULL || filename[0] == L'\0') + return (archive_write_open_fd(a, 1)); + + return (open_filename(a, 0, filename)); +} + +static int +open_filename(struct archive *a, int mbs_fn, const void *filename) +{ + struct write_file_data *mine; + int r; + + mine = (struct write_file_data *)calloc(1, sizeof(*mine)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + if (mbs_fn) + r = archive_mstring_copy_mbs(&mine->filename, filename); + else + r = archive_mstring_copy_wcs(&mine->filename, filename); + if (r < 0) { + if (errno == ENOMEM) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + if (mbs_fn) + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Can't convert '%s' to WCS", + (const char *)filename); + else + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Can't convert '%S' to MBS", + (const wchar_t *)filename); + return (ARCHIVE_FAILED); + } + mine->fd = -1; + return (archive_write_open(a, mine, + file_open, file_write, file_close)); +} + +static int +file_open(struct archive *a, void *client_data) +{ + int flags; + struct write_file_data *mine; + struct stat st; +#if defined(_WIN32) && !defined(__CYGWIN__) + wchar_t *fullpath; +#endif + const wchar_t *wcs; + const char *mbs; + + mine = (struct write_file_data *)client_data; + flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC; + + /* + * Open the file. + */ + mbs = NULL; wcs = NULL; +#if defined(_WIN32) && !defined(__CYGWIN__) + if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) { + if (errno == ENOMEM) + archive_set_error(a, errno, "No memory"); + else { + archive_mstring_get_mbs(a, &mine->filename, &mbs); + archive_set_error(a, errno, + "Can't convert '%s' to WCS", mbs); + } + return (ARCHIVE_FATAL); + } + fullpath = __la_win_permissive_name_w(wcs); + if (fullpath != NULL) { + mine->fd = _wopen(fullpath, flags, 0666); + free(fullpath); + } else + mine->fd = _wopen(wcs, flags, 0666); +#else + if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) { + if (errno == ENOMEM) + archive_set_error(a, errno, "No memory"); + else { + archive_mstring_get_wcs(a, &mine->filename, &wcs); + archive_set_error(a, errno, + "Can't convert '%S' to MBS", wcs); + } + return (ARCHIVE_FATAL); + } + mine->fd = open(mbs, flags, 0666); + __archive_ensure_cloexec_flag(mine->fd); +#endif + if (mine->fd < 0) { + if (mbs != NULL) + archive_set_error(a, errno, "Failed to open '%s'", mbs); + else + archive_set_error(a, errno, "Failed to open '%S'", wcs); + return (ARCHIVE_FATAL); + } + + if (fstat(mine->fd, &st) != 0) { + if (mbs != NULL) + archive_set_error(a, errno, "Couldn't stat '%s'", mbs); + else + archive_set_error(a, errno, "Couldn't stat '%S'", wcs); + return (ARCHIVE_FATAL); + } + + /* + * Set up default last block handling. + */ + if (archive_write_get_bytes_in_last_block(a) < 0) { + if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || + S_ISFIFO(st.st_mode)) + /* Pad last block when writing to device or FIFO. */ + archive_write_set_bytes_in_last_block(a, 0); + else + /* Don't pad last block otherwise. */ + archive_write_set_bytes_in_last_block(a, 1); + } + + /* + * If the output file is a regular file, don't add it to + * itself. If it's a device file, it's okay to add the device + * entry to the output archive. + */ + if (S_ISREG(st.st_mode)) + archive_write_set_skip_file(a, st.st_dev, st.st_ino); + + return (ARCHIVE_OK); +} + +static ssize_t +file_write(struct archive *a, void *client_data, const void *buff, + size_t length) +{ + struct write_file_data *mine; + ssize_t bytesWritten; + + mine = (struct write_file_data *)client_data; + for (;;) { + bytesWritten = write(mine->fd, buff, length); + if (bytesWritten <= 0) { + if (errno == EINTR) + continue; + archive_set_error(a, errno, "Write error"); + return (-1); + } + return (bytesWritten); + } +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct write_file_data *mine = (struct write_file_data *)client_data; + + (void)a; /* UNUSED */ + + if (mine->fd >= 0) + close(mine->fd); + + archive_mstring_clean(&mine->filename); + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_open_memory.c b/src/3rdparty/libarchive/libarchive/archive_write_open_memory.c new file mode 100644 index 00000000..ea6ae0ac --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_open_memory.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_memory.c,v 1.3 2007/01/09 08:05:56 kientzle Exp $"); + +#include +#include +#include + +#include "archive.h" + +struct write_memory_data { + size_t used; + size_t size; + size_t * client_size; + unsigned char * buff; +}; + +static int memory_write_close(struct archive *, void *); +static int memory_write_open(struct archive *, void *); +static ssize_t memory_write(struct archive *, void *, const void *buff, size_t); + +/* + * Client provides a pointer to a block of memory to receive + * the data. The 'size' param both tells us the size of the + * client buffer and lets us tell the client the final size. + */ +int +archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) +{ + struct write_memory_data *mine; + + mine = (struct write_memory_data *)calloc(1, sizeof(*mine)); + if (mine == NULL) { + archive_set_error(a, ENOMEM, "No memory"); + return (ARCHIVE_FATAL); + } + mine->buff = buff; + mine->size = buffSize; + mine->client_size = used; + return (archive_write_open(a, mine, + memory_write_open, memory_write, memory_write_close)); +} + +static int +memory_write_open(struct archive *a, void *client_data) +{ + struct write_memory_data *mine; + mine = client_data; + mine->used = 0; + if (mine->client_size != NULL) + *mine->client_size = mine->used; + /* Disable padding if it hasn't been set explicitly. */ + if (-1 == archive_write_get_bytes_in_last_block(a)) + archive_write_set_bytes_in_last_block(a, 1); + return (ARCHIVE_OK); +} + +/* + * Copy the data into the client buffer. + * Note that we update mine->client_size on every write. + * In particular, this means the client can follow exactly + * how much has been written into their buffer at any time. + */ +static ssize_t +memory_write(struct archive *a, void *client_data, const void *buff, size_t length) +{ + struct write_memory_data *mine; + mine = client_data; + + if (mine->used + length > mine->size) { + archive_set_error(a, ENOMEM, "Buffer exhausted"); + return (ARCHIVE_FATAL); + } + memcpy(mine->buff + mine->used, buff, length); + mine->used += length; + if (mine->client_size != NULL) + *mine->client_size = mine->used; + return (length); +} + +static int +memory_write_close(struct archive *a, void *client_data) +{ + struct write_memory_data *mine; + (void)a; /* UNUSED */ + mine = client_data; + free(mine); + return (ARCHIVE_OK); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_private.h b/src/3rdparty/libarchive/libarchive/archive_write_private.h new file mode 100644 index 00000000..0dfd1b1b --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_private.h @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/archive_write_private.h 201155 2009-12-29 05:20:12Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#ifndef __LIBARCHIVE_TEST +#error This header is only to be used internally to libarchive. +#endif +#endif + +#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED +#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED + +#include "archive.h" +#include "archive_string.h" +#include "archive_private.h" + +struct archive_write; + +struct archive_write_filter { + int64_t bytes_written; + struct archive *archive; /* Associated archive. */ + struct archive_write_filter *next_filter; /* Who I write to. */ + int (*options)(struct archive_write_filter *, + const char *key, const char *value); + int (*open)(struct archive_write_filter *); + int (*write)(struct archive_write_filter *, const void *, size_t); + int (*close)(struct archive_write_filter *); + int (*free)(struct archive_write_filter *); + void *data; + const char *name; + int code; + int bytes_per_block; + int bytes_in_last_block; +}; + +#if ARCHIVE_VERSION < 4000000 +void __archive_write_filters_free(struct archive *); +#endif + +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_filter(struct archive_write_filter *, const void *, size_t); +int __archive_write_open_filter(struct archive_write_filter *); +int __archive_write_close_filter(struct archive_write_filter *); + +struct archive_write { + struct archive archive; + + /* Dev/ino of the archive being written. */ + int skip_file_set; + int64_t skip_file_dev; + int64_t skip_file_ino; + + /* Utility: Pointer to a block of nulls. */ + const unsigned char *nulls; + size_t null_length; + + /* Callbacks to open/read/write/close archive stream. */ + archive_open_callback *client_opener; + archive_write_callback *client_writer; + archive_close_callback *client_closer; + void *client_data; + + /* + * Blocking information. Note that bytes_in_last_block is + * misleadingly named; I should find a better name. These + * control the final output from all compressors, including + * compression_none. + */ + int bytes_per_block; + int bytes_in_last_block; + + /* + * First and last write filters in the pipeline. + */ + struct archive_write_filter *filter_first; + struct archive_write_filter *filter_last; + + /* + * Pointers to format-specific functions for writing. They're + * initialized by archive_write_set_format_XXX() calls. + */ + void *format_data; + const char *format_name; + int (*format_init)(struct archive_write *); + int (*format_options)(struct archive_write *, + const char *key, const char *value); + int (*format_finish_entry)(struct archive_write *); + int (*format_write_header)(struct archive_write *, + struct archive_entry *); + ssize_t (*format_write_data)(struct archive_write *, + const void *buff, size_t); + int (*format_close)(struct archive_write *); + int (*format_free)(struct archive_write *); + + + /* + * Encryption passphrase. + */ + char *passphrase; + archive_passphrase_callback *passphrase_callback; + void *passphrase_client_data; +}; + +/* + * Utility function to format a USTAR header into a buffer. If + * "strict" is set, this tries to create the absolutely most portable + * version of a ustar header. If "strict" is set to 0, then it will + * relax certain requirements. + * + * Generally, format-specific declarations don't belong in this + * header; this is a rare example of a function that is shared by + * two very similar formats (ustar and pax). + */ +int +__archive_write_format_header_ustar(struct archive_write *, char buff[512], + struct archive_entry *, int tartype, int strict, + struct archive_string_conv *); + +struct archive_write_program_data; +struct archive_write_program_data * __archive_write_program_allocate(const char *program_name); +int __archive_write_program_free(struct archive_write_program_data *); +int __archive_write_program_open(struct archive_write_filter *, + struct archive_write_program_data *, const char *); +int __archive_write_program_close(struct archive_write_filter *, + struct archive_write_program_data *); +int __archive_write_program_write(struct archive_write_filter *, + struct archive_write_program_data *, const void *, size_t); + +/* + * Get a encryption passphrase. + */ +const char * __archive_write_get_passphrase(struct archive_write *a); +#endif diff --git a/src/3rdparty/libarchive/libarchive/archive_write_set_format.c b/src/3rdparty/libarchive/libarchive/archive_write_set_format.c new file mode 100644 index 00000000..0f706231 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_set_format.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format.c 201168 2009-12-29 06:15:32Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" + +/* A table that maps format codes to functions. */ +static const +struct { int code; int (*setter)(struct archive *); } codes[] = +{ + { ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip }, + { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio }, + { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio }, + { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc }, + { ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 }, + { ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree }, + { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw }, + { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar }, + { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar }, + { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump }, + { ARCHIVE_FORMAT_TAR, archive_write_set_format_pax_restricted }, + { ARCHIVE_FORMAT_TAR_GNUTAR, archive_write_set_format_gnutar }, + { ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_write_set_format_pax }, + { ARCHIVE_FORMAT_TAR_PAX_RESTRICTED, + archive_write_set_format_pax_restricted }, + { ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar }, + { ARCHIVE_FORMAT_WARC, archive_write_set_format_warc }, + { ARCHIVE_FORMAT_XAR, archive_write_set_format_xar }, + { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip }, + { 0, NULL } +}; + +int +archive_write_set_format(struct archive *a, int code) +{ + int i; + + for (i = 0; codes[i].code != 0; i++) { + if (code == codes[i].code) + return ((codes[i].setter)(a)); + } + + archive_set_error(a, EINVAL, "No such format"); + return (ARCHIVE_FATAL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c b/src/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c new file mode 100644 index 00000000..86e8621e --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $"); + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" + +/* A table that maps names to functions. */ +static const +struct { const char *name; int (*setter)(struct archive *); } names[] = +{ + { "7zip", archive_write_set_format_7zip }, + { "ar", archive_write_set_format_ar_bsd }, + { "arbsd", archive_write_set_format_ar_bsd }, + { "argnu", archive_write_set_format_ar_svr4 }, + { "arsvr4", archive_write_set_format_ar_svr4 }, + { "bsdtar", archive_write_set_format_pax_restricted }, + { "cd9660", archive_write_set_format_iso9660 }, + { "cpio", archive_write_set_format_cpio }, + { "gnutar", archive_write_set_format_gnutar }, + { "iso", archive_write_set_format_iso9660 }, + { "iso9660", archive_write_set_format_iso9660 }, + { "mtree", archive_write_set_format_mtree }, + { "mtree-classic", archive_write_set_format_mtree_classic }, + { "newc", archive_write_set_format_cpio_newc }, + { "odc", archive_write_set_format_cpio }, + { "oldtar", archive_write_set_format_v7tar }, + { "pax", archive_write_set_format_pax }, + { "paxr", archive_write_set_format_pax_restricted }, + { "posix", archive_write_set_format_pax }, + { "raw", archive_write_set_format_raw }, + { "rpax", archive_write_set_format_pax_restricted }, + { "shar", archive_write_set_format_shar }, + { "shardump", archive_write_set_format_shar_dump }, + { "ustar", archive_write_set_format_ustar }, + { "v7tar", archive_write_set_format_v7tar }, + { "v7", archive_write_set_format_v7tar }, + { "warc", archive_write_set_format_warc }, + { "xar", archive_write_set_format_xar }, + { "zip", archive_write_set_format_zip }, + { NULL, NULL } +}; + +int +archive_write_set_format_by_name(struct archive *a, const char *name) +{ + int i; + + for (i = 0; names[i].name != NULL; i++) { + if (strcmp(name, names[i].name) == 0) + return ((names[i].setter)(a)); + } + + archive_set_error(a, EINVAL, "No such format '%s'", name); + a->state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c b/src/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c new file mode 100644 index 00000000..2d858c9f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c @@ -0,0 +1,763 @@ +/*- + * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Author: Jonas Gastal + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $"); + + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_write_private.h" + +struct gnutar { + uint64_t entry_bytes_remaining; + uint64_t entry_padding; + const char * linkname; + size_t linkname_length; + const char * pathname; + size_t pathname_length; + const char * uname; + size_t uname_length; + const char * gname; + size_t gname_length; + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv_default; + int init_default_conversion; +}; + +/* + * Define structure of GNU tar header. + */ +#define GNUTAR_name_offset 0 +#define GNUTAR_name_size 100 +#define GNUTAR_mode_offset 100 +#define GNUTAR_mode_size 7 +#define GNUTAR_mode_max_size 8 +#define GNUTAR_uid_offset 108 +#define GNUTAR_uid_size 7 +#define GNUTAR_uid_max_size 8 +#define GNUTAR_gid_offset 116 +#define GNUTAR_gid_size 7 +#define GNUTAR_gid_max_size 8 +#define GNUTAR_size_offset 124 +#define GNUTAR_size_size 11 +#define GNUTAR_size_max_size 12 +#define GNUTAR_mtime_offset 136 +#define GNUTAR_mtime_size 11 +#define GNUTAR_mtime_max_size 11 +#define GNUTAR_checksum_offset 148 +#define GNUTAR_checksum_size 8 +#define GNUTAR_typeflag_offset 156 +#define GNUTAR_typeflag_size 1 +#define GNUTAR_linkname_offset 157 +#define GNUTAR_linkname_size 100 +#define GNUTAR_magic_offset 257 +#define GNUTAR_magic_size 6 +#define GNUTAR_version_offset 263 +#define GNUTAR_version_size 2 +#define GNUTAR_uname_offset 265 +#define GNUTAR_uname_size 32 +#define GNUTAR_gname_offset 297 +#define GNUTAR_gname_size 32 +#define GNUTAR_rdevmajor_offset 329 +#define GNUTAR_rdevmajor_size 6 +#define GNUTAR_rdevmajor_max_size 8 +#define GNUTAR_rdevminor_offset 337 +#define GNUTAR_rdevminor_size 6 +#define GNUTAR_rdevminor_max_size 8 + +/* + * A filled-in copy of the header for initialization. + */ +static const char template_header[] = { + /* name: 100 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0, + /* Mode, null termination: 8 bytes */ + '0','0','0','0','0','0', '0','\0', + /* uid, null termination: 8 bytes */ + '0','0','0','0','0','0', '0','\0', + /* gid, null termination: 8 bytes */ + '0','0','0','0','0','0', '0','\0', + /* size, space termination: 12 bytes */ + '0','0','0','0','0','0','0','0','0','0','0', '\0', + /* mtime, space termination: 12 bytes */ + '0','0','0','0','0','0','0','0','0','0','0', '\0', + /* Initial checksum value: 8 spaces */ + ' ',' ',' ',' ',' ',' ',' ',' ', + /* Typeflag: 1 byte */ + '0', /* '0' = regular file */ + /* Linkname: 100 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0, + /* Magic: 8 bytes */ + 'u','s','t','a','r',' ', ' ','\0', + /* Uname: 32 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + /* Gname: 32 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + /* rdevmajor + null padding: 8 bytes */ + '\0','\0','\0','\0','\0','\0', '\0','\0', + /* rdevminor + null padding: 8 bytes */ + '\0','\0','\0','\0','\0','\0', '\0','\0', + /* Padding: 167 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0 +}; + +static int archive_write_gnutar_options(struct archive_write *, + const char *, const char *); +static int archive_format_gnutar_header(struct archive_write *, char h[512], + struct archive_entry *, int tartype); +static int archive_write_gnutar_header(struct archive_write *, + struct archive_entry *entry); +static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, + size_t s); +static int archive_write_gnutar_free(struct archive_write *); +static int archive_write_gnutar_close(struct archive_write *); +static int archive_write_gnutar_finish_entry(struct archive_write *); +static int format_256(int64_t, char *, int); +static int format_number(int64_t, char *, int size, int maxsize); +static int format_octal(int64_t, char *, int); + +/* + * Set output format to 'GNU tar' format. + */ +int +archive_write_set_format_gnutar(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct gnutar *gnutar; + + gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar)); + if (gnutar == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate gnutar data"); + return (ARCHIVE_FATAL); + } + a->format_data = gnutar; + a->format_name = "gnutar"; + a->format_options = archive_write_gnutar_options; + a->format_write_header = archive_write_gnutar_header; + a->format_write_data = archive_write_gnutar_data; + a->format_close = archive_write_gnutar_close; + a->format_free = archive_write_gnutar_free; + a->format_finish_entry = archive_write_gnutar_finish_entry; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; + a->archive.archive_format_name = "GNU tar"; + return (ARCHIVE_OK); +} + +static int +archive_write_gnutar_options(struct archive_write *a, const char *key, + const char *val) +{ + struct gnutar *gnutar = (struct gnutar *)a->format_data; + int ret = ARCHIVE_FAILED; + + if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: hdrcharset option needs a character-set name", + a->format_name); + else { + gnutar->opt_sconv = archive_string_conversion_to_charset( + &a->archive, val, 0); + if (gnutar->opt_sconv != NULL) + ret = ARCHIVE_OK; + else + ret = ARCHIVE_FATAL; + } + return (ret); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +static int +archive_write_gnutar_close(struct archive_write *a) +{ + return (__archive_write_nulls(a, 512*2)); +} + +static int +archive_write_gnutar_free(struct archive_write *a) +{ + struct gnutar *gnutar; + + gnutar = (struct gnutar *)a->format_data; + free(gnutar); + a->format_data = NULL; + return (ARCHIVE_OK); +} + +static int +archive_write_gnutar_finish_entry(struct archive_write *a) +{ + struct gnutar *gnutar; + int ret; + + gnutar = (struct gnutar *)a->format_data; + ret = __archive_write_nulls(a, (size_t) + (gnutar->entry_bytes_remaining + gnutar->entry_padding)); + gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; + return (ret); +} + +static ssize_t +archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) +{ + struct gnutar *gnutar; + 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); + gnutar->entry_bytes_remaining -= s; + if (ret != ARCHIVE_OK) + return (ret); + return (s); +} + +static int +archive_write_gnutar_header(struct archive_write *a, + struct archive_entry *entry) +{ + char buff[512]; + int r, ret, ret2 = ARCHIVE_OK; + int 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) { + gnutar->sconv_default = + archive_string_default_conversion_for_write( + &(a->archive)); + gnutar->init_default_conversion = 1; + } + sconv = gnutar->sconv_default; + } else + sconv = gnutar->opt_sconv; + + /* Only regular files (not hardlinks) have data. */ + if (archive_entry_hardlink(entry) != NULL || + archive_entry_symlink(entry) != NULL || + !(archive_entry_filetype(entry) == AE_IFREG)) + archive_entry_set_size(entry, 0); + + if (AE_IFDIR == archive_entry_filetype(entry)) { + const char *p; + size_t path_length; + /* + * Ensure a trailing '/'. Modify the entry so + * the client sees the change. + */ +#if defined(_WIN32) && !defined(__CYGWIN__) + const wchar_t *wp; + + wp = archive_entry_pathname_w(entry); + if (wp != NULL && wp[wcslen(wp) -1] != L'/') { + struct archive_wstring ws; + + archive_string_init(&ws); + path_length = wcslen(wp); + if (archive_wstring_ensure(&ws, + path_length + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + archive_wstring_free(&ws); + return(ARCHIVE_FATAL); + } + /* Should we keep '\' ? */ + if (wp[path_length -1] == L'\\') + path_length--; + archive_wstrncpy(&ws, wp, path_length); + archive_wstrappend_wchar(&ws, L'/'); + archive_entry_copy_pathname_w(entry, ws.s); + archive_wstring_free(&ws); + p = NULL; + } else +#endif + p = archive_entry_pathname(entry); + /* + * On Windows, this is a backup operation just in + * case getting WCS failed. On POSIX, this is a + * normal operation. + */ + if (p != NULL && p[strlen(p) - 1] != '/') { + struct archive_string as; + + archive_string_init(&as); + path_length = strlen(p); + if (archive_string_ensure(&as, + path_length + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + archive_string_free(&as); + return(ARCHIVE_FATAL); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + /* NOTE: This might break the pathname + * if the current code page is CP932 and + * the pathname includes a character '\' + * as a part of its multibyte pathname. */ + if (p[strlen(p) -1] == '\\') + path_length--; + else +#endif + archive_strncpy(&as, p, path_length); + archive_strappend_char(&as, '/'); + archive_entry_copy_pathname(entry, as.s); + archive_string_free(&as); + } + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure the path separators in pathname, hardlink and symlink + * are all slash '/', not the Windows path separator '\'. */ + entry_main = __la_win_entry_in_posix_pathseparator(entry); + if (entry_main == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + return(ARCHIVE_FATAL); + } + if (entry != entry_main) + entry = entry_main; + else + entry_main = NULL; +#else + entry_main = NULL; +#endif + r = archive_entry_pathname_l(entry, &(gnutar->pathname), + &(gnutar->pathname_length), sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathame"); + ret = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate pathname '%s' to %s", + archive_entry_pathname(entry), + archive_string_conversion_charset_name(sconv)); + ret2 = ARCHIVE_WARN; + } + r = archive_entry_uname_l(entry, &(gnutar->uname), + &(gnutar->uname_length), sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Uname"); + ret = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate uname '%s' to %s", + archive_entry_uname(entry), + archive_string_conversion_charset_name(sconv)); + ret2 = ARCHIVE_WARN; + } + r = archive_entry_gname_l(entry, &(gnutar->gname), + &(gnutar->gname_length), sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Gname"); + ret = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate gname '%s' to %s", + archive_entry_gname(entry), + archive_string_conversion_charset_name(sconv)); + ret2 = ARCHIVE_WARN; + } + + /* If linkname is longer than 100 chars we need to add a 'K' header. */ + r = archive_entry_hardlink_l(entry, &(gnutar->linkname), + &(gnutar->linkname_length), sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + ret = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + archive_entry_hardlink(entry), + archive_string_conversion_charset_name(sconv)); + ret2 = ARCHIVE_WARN; + } + if (gnutar->linkname_length == 0) { + r = archive_entry_symlink_l(entry, &(gnutar->linkname), + &(gnutar->linkname_length), sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + ret = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + archive_entry_hardlink(entry), + archive_string_conversion_charset_name(sconv)); + ret2 = ARCHIVE_WARN; + } + } + if (gnutar->linkname_length > GNUTAR_linkname_size) { + size_t length = gnutar->linkname_length + 1; + struct archive_entry *temp = archive_entry_new2(&a->archive); + + /* Uname/gname here don't really matter since no one reads them; + * these are the values that GNU tar happens to use on FreeBSD. */ + archive_entry_set_uname(temp, "root"); + archive_entry_set_gname(temp, "wheel"); + + archive_entry_set_pathname(temp, "././@LongLink"); + archive_entry_set_size(temp, length); + ret = archive_format_gnutar_header(a, buff, temp, 'K'); + archive_entry_free(temp); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + ret = __archive_write_output(a, buff, 512); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + /* Write name and trailing null byte. */ + ret = __archive_write_output(a, gnutar->linkname, length); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + /* Pad to 512 bytes */ + ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + } + + /* If pathname is longer than 100 chars we need to add an 'L' header. */ + if (gnutar->pathname_length > GNUTAR_name_size) { + const char *pathname = gnutar->pathname; + size_t length = gnutar->pathname_length + 1; + struct archive_entry *temp = archive_entry_new2(&a->archive); + + /* Uname/gname here don't really matter since no one reads them; + * these are the values that GNU tar happens to use on FreeBSD. */ + archive_entry_set_uname(temp, "root"); + archive_entry_set_gname(temp, "wheel"); + + archive_entry_set_pathname(temp, "././@LongLink"); + archive_entry_set_size(temp, length); + ret = archive_format_gnutar_header(a, buff, temp, 'L'); + archive_entry_free(temp); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + ret = __archive_write_output(a, buff, 512); + if(ret < ARCHIVE_WARN) + goto exit_write_header; + /* Write pathname + trailing null byte. */ + ret = __archive_write_output(a, pathname, length); + if(ret < ARCHIVE_WARN) + goto exit_write_header; + /* Pad to multiple of 512 bytes. */ + ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + } + + if (archive_entry_hardlink(entry) != NULL) { + tartype = '1'; + } else + switch (archive_entry_filetype(entry)) { + case AE_IFREG: tartype = '0' ; break; + case AE_IFLNK: tartype = '2' ; break; + case AE_IFCHR: tartype = '3' ; break; + case AE_IFBLK: tartype = '4' ; break; + case AE_IFDIR: tartype = '5' ; break; + case AE_IFIFO: tartype = '6' ; break; + case AE_IFSOCK: + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "tar format cannot archive socket"); + ret = ARCHIVE_FAILED; + goto exit_write_header; + default: + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "tar format cannot archive this (mode=0%lo)", + (unsigned long)archive_entry_mode(entry)); + ret = ARCHIVE_FAILED; + goto exit_write_header; + } + + ret = archive_format_gnutar_header(a, buff, entry, tartype); + if (ret < ARCHIVE_WARN) + goto exit_write_header; + if (ret2 < ret) + ret = ret2; + ret2 = __archive_write_output(a, buff, 512); + if (ret2 < ARCHIVE_WARN) { + ret = ret2; + goto exit_write_header; + } + if (ret2 < ret) + ret = ret2; + + gnutar->entry_bytes_remaining = archive_entry_size(entry); + gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining); +exit_write_header: + if (entry_main) + archive_entry_free(entry_main); + return (ret); +} + +static int +archive_format_gnutar_header(struct archive_write *a, char h[512], + struct archive_entry *entry, int tartype) +{ + unsigned int checksum; + int i, ret; + size_t copy_length; + const char *p; + struct gnutar *gnutar; + + gnutar = (struct gnutar *)a->format_data; + + ret = 0; + + /* + * The "template header" already includes the signature, + * various end-of-field markers, and other required elements. + */ + memcpy(h, &template_header, 512); + + /* + * Because the block is already null-filled, and strings + * are allowed to exactly fill their destination (without null), + * I use memcpy(dest, src, strlen()) here a lot to copy strings. + */ + + if (tartype == 'K' || tartype == 'L') { + p = archive_entry_pathname(entry); + copy_length = strlen(p); + } else { + p = gnutar->pathname; + copy_length = gnutar->pathname_length; + } + if (copy_length > GNUTAR_name_size) + copy_length = GNUTAR_name_size; + memcpy(h + GNUTAR_name_offset, p, copy_length); + + if ((copy_length = gnutar->linkname_length) > 0) { + if (copy_length > GNUTAR_linkname_size) + copy_length = GNUTAR_linkname_size; + memcpy(h + GNUTAR_linkname_offset, gnutar->linkname, + copy_length); + } + + /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */ + if (tartype == 'K' || tartype == 'L') { + p = archive_entry_uname(entry); + copy_length = strlen(p); + } else { + p = gnutar->uname; + copy_length = gnutar->uname_length; + } + if (copy_length > 0) { + if (copy_length > GNUTAR_uname_size) + copy_length = GNUTAR_uname_size; + memcpy(h + GNUTAR_uname_offset, p, copy_length); + } + + /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */ + if (tartype == 'K' || tartype == 'L') { + p = archive_entry_gname(entry); + copy_length = strlen(p); + } else { + p = gnutar->gname; + copy_length = gnutar->gname_length; + } + if (copy_length > 0) { + if (strlen(p) > GNUTAR_gname_size) + copy_length = GNUTAR_gname_size; + memcpy(h + GNUTAR_gname_offset, p, copy_length); + } + + /* By truncating the mode here, we ensure it always fits. */ + format_octal(archive_entry_mode(entry) & 07777, + h + GNUTAR_mode_offset, GNUTAR_mode_size); + + /* GNU tar supports base-256 here, so should never overflow. */ + if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset, + GNUTAR_uid_size, GNUTAR_uid_max_size)) { + archive_set_error(&a->archive, ERANGE, + "Numeric user ID %jd too large", + (intmax_t)archive_entry_uid(entry)); + ret = ARCHIVE_FAILED; + } + + /* GNU tar supports base-256 here, so should never overflow. */ + if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset, + GNUTAR_gid_size, GNUTAR_gid_max_size)) { + archive_set_error(&a->archive, ERANGE, + "Numeric group ID %jd too large", + (intmax_t)archive_entry_gid(entry)); + ret = ARCHIVE_FAILED; + } + + /* GNU tar supports base-256 here, so should never overflow. */ + if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset, + GNUTAR_size_size, GNUTAR_size_max_size)) { + archive_set_error(&a->archive, ERANGE, + "File size out of range"); + ret = ARCHIVE_FAILED; + } + + /* Shouldn't overflow before 2106, since mtime field is 33 bits. */ + format_octal(archive_entry_mtime(entry), + h + GNUTAR_mtime_offset, GNUTAR_mtime_size); + + if (archive_entry_filetype(entry) == AE_IFBLK + || archive_entry_filetype(entry) == AE_IFCHR) { + if (format_octal(archive_entry_rdevmajor(entry), + h + GNUTAR_rdevmajor_offset, + GNUTAR_rdevmajor_size)) { + archive_set_error(&a->archive, ERANGE, + "Major device number too large"); + ret = ARCHIVE_FAILED; + } + + if (format_octal(archive_entry_rdevminor(entry), + h + GNUTAR_rdevminor_offset, + GNUTAR_rdevminor_size)) { + archive_set_error(&a->archive, ERANGE, + "Minor device number too large"); + ret = ARCHIVE_FAILED; + } + } + + h[GNUTAR_typeflag_offset] = tartype; + + checksum = 0; + for (i = 0; i < 512; i++) + checksum += 255 & (unsigned int)h[i]; + h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ + /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ + format_octal(checksum, h + GNUTAR_checksum_offset, 6); + return (ret); +} + +/* + * Format a number into a field, falling back to base-256 if necessary. + */ +static int +format_number(int64_t v, char *p, int s, int maxsize) +{ + int64_t limit = ((int64_t)1 << (s*3)); + + if (v < limit) + return (format_octal(v, p, s)); + return (format_256(v, p, maxsize)); +} + +/* + * Format a number into the specified field using base-256. + */ +static int +format_256(int64_t v, char *p, int s) +{ + p += s; + while (s-- > 0) { + *--p = (char)(v & 0xff); + v >>= 8; + } + *p |= 0x80; /* Set the base-256 marker bit. */ + return (0); +} + +/* + * Format a number into the specified field using octal. + */ +static int +format_octal(int64_t v, char *p, int s) +{ + int len = s; + + /* Octal values can't be negative, so use 0. */ + if (v < 0) + v = 0; + + p += s; /* Start at the end and work backwards. */ + while (s-- > 0) { + *--p = (char)('0' + (v & 7)); + v >>= 3; + } + + if (v == 0) + return (0); + + /* If it overflowed, fill field with max value. */ + while (len-- > 0) + *p++ = '7'; + + return (-1); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c b/src/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c new file mode 100644 index 00000000..c54aeabd --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c @@ -0,0 +1,763 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z kientzle $"); + + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_write_private.h" + +struct ustar { + uint64_t entry_bytes_remaining; + uint64_t entry_padding; + + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv_default; + int init_default_conversion; +}; + +/* + * Define structure of POSIX 'ustar' tar header. + */ +#define USTAR_name_offset 0 +#define USTAR_name_size 100 +#define USTAR_mode_offset 100 +#define USTAR_mode_size 6 +#define USTAR_mode_max_size 8 +#define USTAR_uid_offset 108 +#define USTAR_uid_size 6 +#define USTAR_uid_max_size 8 +#define USTAR_gid_offset 116 +#define USTAR_gid_size 6 +#define USTAR_gid_max_size 8 +#define USTAR_size_offset 124 +#define USTAR_size_size 11 +#define USTAR_size_max_size 12 +#define USTAR_mtime_offset 136 +#define USTAR_mtime_size 11 +#define USTAR_mtime_max_size 11 +#define USTAR_checksum_offset 148 +#define USTAR_checksum_size 8 +#define USTAR_typeflag_offset 156 +#define USTAR_typeflag_size 1 +#define USTAR_linkname_offset 157 +#define USTAR_linkname_size 100 +#define USTAR_magic_offset 257 +#define USTAR_magic_size 6 +#define USTAR_version_offset 263 +#define USTAR_version_size 2 +#define USTAR_uname_offset 265 +#define USTAR_uname_size 32 +#define USTAR_gname_offset 297 +#define USTAR_gname_size 32 +#define USTAR_rdevmajor_offset 329 +#define USTAR_rdevmajor_size 6 +#define USTAR_rdevmajor_max_size 8 +#define USTAR_rdevminor_offset 337 +#define USTAR_rdevminor_size 6 +#define USTAR_rdevminor_max_size 8 +#define USTAR_prefix_offset 345 +#define USTAR_prefix_size 155 +#define USTAR_padding_offset 500 +#define USTAR_padding_size 12 + +/* + * A filled-in copy of the header for initialization. + */ +static const char template_header[] = { + /* name: 100 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0, + /* Mode, space-null termination: 8 bytes */ + '0','0','0','0','0','0', ' ','\0', + /* uid, space-null termination: 8 bytes */ + '0','0','0','0','0','0', ' ','\0', + /* gid, space-null termination: 8 bytes */ + '0','0','0','0','0','0', ' ','\0', + /* size, space termination: 12 bytes */ + '0','0','0','0','0','0','0','0','0','0','0', ' ', + /* mtime, space termination: 12 bytes */ + '0','0','0','0','0','0','0','0','0','0','0', ' ', + /* Initial checksum value: 8 spaces */ + ' ',' ',' ',' ',' ',' ',' ',' ', + /* Typeflag: 1 byte */ + '0', /* '0' = regular file */ + /* Linkname: 100 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0, + /* Magic: 6 bytes, Version: 2 bytes */ + 'u','s','t','a','r','\0', '0','0', + /* Uname: 32 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + /* Gname: 32 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + /* rdevmajor + space/null padding: 8 bytes */ + '0','0','0','0','0','0', ' ','\0', + /* rdevminor + space/null padding: 8 bytes */ + '0','0','0','0','0','0', ' ','\0', + /* Prefix: 155 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0, + /* Padding: 12 bytes */ + 0,0,0,0,0,0,0,0, 0,0,0,0 +}; + +static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff, + size_t s); +static int archive_write_ustar_free(struct archive_write *); +static int archive_write_ustar_close(struct archive_write *); +static int archive_write_ustar_finish_entry(struct archive_write *); +static int archive_write_ustar_header(struct archive_write *, + struct archive_entry *entry); +static int archive_write_ustar_options(struct archive_write *, + const char *, const char *); +static int format_256(int64_t, char *, int); +static int format_number(int64_t, char *, int size, int max, int strict); +static int format_octal(int64_t, char *, int); + +/* + * Set output format to 'ustar' format. + */ +int +archive_write_set_format_ustar(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct ustar *ustar; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + 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); + + /* Basic internal sanity test. */ + if (sizeof(template_header) != 512) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Internal: template_header wrong size: %zu should be 512", + sizeof(template_header)); + return (ARCHIVE_FATAL); + } + + ustar = (struct ustar *)calloc(1, sizeof(*ustar)); + if (ustar == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + return (ARCHIVE_FATAL); + } + a->format_data = ustar; + a->format_name = "ustar"; + a->format_options = archive_write_ustar_options; + a->format_write_header = archive_write_ustar_header; + a->format_write_data = archive_write_ustar_data; + a->format_close = archive_write_ustar_close; + a->format_free = archive_write_ustar_free; + a->format_finish_entry = archive_write_ustar_finish_entry; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; + a->archive.archive_format_name = "POSIX ustar"; + return (ARCHIVE_OK); +} + +static int +archive_write_ustar_options(struct archive_write *a, const char *key, + const char *val) +{ + struct ustar *ustar = (struct ustar *)a->format_data; + int ret = ARCHIVE_FAILED; + + if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: hdrcharset option needs a character-set name", + a->format_name); + else { + ustar->opt_sconv = archive_string_conversion_to_charset( + &a->archive, val, 0); + if (ustar->opt_sconv != NULL) + ret = ARCHIVE_OK; + else + ret = ARCHIVE_FATAL; + } + return (ret); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +static int +archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) +{ + 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) { + ustar->sconv_default = + archive_string_default_conversion_for_write(&(a->archive)); + ustar->init_default_conversion = 1; + } + sconv = ustar->sconv_default; + } else + sconv = ustar->opt_sconv; + + /* Sanity check. */ + if (archive_entry_pathname(entry) == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can't record entry in tar file without pathname"); + return (ARCHIVE_FAILED); + } + + /* Only regular files (not hardlinks) have data. */ + if (archive_entry_hardlink(entry) != NULL || + archive_entry_symlink(entry) != NULL || + !(archive_entry_filetype(entry) == AE_IFREG)) + archive_entry_set_size(entry, 0); + + if (AE_IFDIR == archive_entry_filetype(entry)) { + const char *p; + size_t path_length; + /* + * Ensure a trailing '/'. Modify the entry so + * the client sees the change. + */ +#if defined(_WIN32) && !defined(__CYGWIN__) + const wchar_t *wp; + + wp = archive_entry_pathname_w(entry); + if (wp != NULL && wp[wcslen(wp) -1] != L'/') { + struct archive_wstring ws; + + archive_string_init(&ws); + path_length = wcslen(wp); + if (archive_wstring_ensure(&ws, + path_length + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + archive_wstring_free(&ws); + return(ARCHIVE_FATAL); + } + /* Should we keep '\' ? */ + if (wp[path_length -1] == L'\\') + path_length--; + archive_wstrncpy(&ws, wp, path_length); + archive_wstrappend_wchar(&ws, L'/'); + archive_entry_copy_pathname_w(entry, ws.s); + archive_wstring_free(&ws); + p = NULL; + } else +#endif + p = archive_entry_pathname(entry); + /* + * On Windows, this is a backup operation just in + * case getting WCS failed. On POSIX, this is a + * normal operation. + */ + if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') { + struct archive_string as; + + archive_string_init(&as); + path_length = strlen(p); + if (archive_string_ensure(&as, + path_length + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + archive_string_free(&as); + return(ARCHIVE_FATAL); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + /* NOTE: This might break the pathname + * if the current code page is CP932 and + * the pathname includes a character '\' + * as a part of its multibyte pathname. */ + if (p[strlen(p) -1] == '\\') + path_length--; + else +#endif + archive_strncpy(&as, p, path_length); + archive_strappend_char(&as, '/'); + archive_entry_copy_pathname(entry, as.s); + archive_string_free(&as); + } + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure the path separators in pathname, hardlink and symlink + * are all slash '/', not the Windows path separator '\'. */ + entry_main = __la_win_entry_in_posix_pathseparator(entry); + if (entry_main == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + return(ARCHIVE_FATAL); + } + if (entry != entry_main) + entry = entry_main; + else + entry_main = NULL; +#else + entry_main = NULL; +#endif + ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv); + if (ret < ARCHIVE_WARN) { + if (entry_main) + archive_entry_free(entry_main); + return (ret); + } + ret2 = __archive_write_output(a, buff, 512); + if (ret2 < ARCHIVE_WARN) { + if (entry_main) + archive_entry_free(entry_main); + return (ret2); + } + if (ret2 < ret) + ret = ret2; + + ustar->entry_bytes_remaining = archive_entry_size(entry); + ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining); + if (entry_main) + archive_entry_free(entry_main); + return (ret); +} + +/* + * Format a basic 512-byte "ustar" header. + * + * Returns -1 if format failed (due to field overflow). + * Note that this always formats as much of the header as possible. + * If "strict" is set to zero, it will extend numeric fields as + * necessary (overwriting terminators or using base-256 extensions). + * + * This is exported so that other 'tar' formats can use it. + */ +int +__archive_write_format_header_ustar(struct archive_write *a, char h[512], + struct archive_entry *entry, int tartype, int strict, + struct archive_string_conv *sconv) +{ + unsigned int checksum; + int i, r, ret; + size_t copy_length; + const char *p, *pp; + int mytartype; + + ret = 0; + mytartype = -1; + /* + * The "template header" already includes the "ustar" + * signature, various end-of-field markers and other required + * elements. + */ + memcpy(h, &template_header, 512); + + /* + * Because the block is already null-filled, and strings + * are allowed to exactly fill their destination (without null), + * I use memcpy(dest, src, strlen()) here a lot to copy strings. + */ + r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathname"); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate pathname '%s' to %s", + pp, archive_string_conversion_charset_name(sconv)); + ret = ARCHIVE_WARN; + } + if (copy_length <= USTAR_name_size) + memcpy(h + USTAR_name_offset, pp, copy_length); + else { + /* Store in two pieces, splitting at a '/'. */ + p = strchr(pp + copy_length - USTAR_name_size - 1, '/'); + /* + * Look for the next '/' if we chose the first character + * as the separator. (ustar format doesn't permit + * an empty prefix.) + */ + if (p == pp) + p = strchr(p + 1, '/'); + /* Fail if the name won't fit. */ + if (!p) { + /* No separator. */ + archive_set_error(&a->archive, ENAMETOOLONG, + "Pathname too long"); + ret = ARCHIVE_FAILED; + } else if (p[1] == '\0') { + /* + * The only feasible separator is a final '/'; + * this would result in a non-empty prefix and + * an empty name, which POSIX doesn't + * explicitly forbid, but it just feels wrong. + */ + archive_set_error(&a->archive, ENAMETOOLONG, + "Pathname too long"); + ret = ARCHIVE_FAILED; + } else if (p > pp + USTAR_prefix_size) { + /* Prefix is too long. */ + archive_set_error(&a->archive, ENAMETOOLONG, + "Pathname too long"); + ret = ARCHIVE_FAILED; + } else { + /* Copy prefix and remainder to appropriate places */ + memcpy(h + USTAR_prefix_offset, pp, p - pp); + memcpy(h + USTAR_name_offset, p + 1, + pp + copy_length - p - 1); + } + } + + r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + p, archive_string_conversion_charset_name(sconv)); + ret = ARCHIVE_WARN; + } + if (copy_length > 0) + mytartype = '1'; + else { + r = archive_entry_symlink_l(entry, &p, ©_length, sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + p, archive_string_conversion_charset_name(sconv)); + ret = ARCHIVE_WARN; + } + } + if (copy_length > 0) { + if (copy_length > USTAR_linkname_size) { + archive_set_error(&a->archive, ENAMETOOLONG, + "Link contents too long"); + ret = ARCHIVE_FAILED; + copy_length = USTAR_linkname_size; + } + memcpy(h + USTAR_linkname_offset, p, copy_length); + } + + r = archive_entry_uname_l(entry, &p, ©_length, sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Uname"); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate uname '%s' to %s", + p, archive_string_conversion_charset_name(sconv)); + ret = ARCHIVE_WARN; + } + if (copy_length > 0) { + if (copy_length > USTAR_uname_size) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Username too long"); + ret = ARCHIVE_FAILED; + copy_length = USTAR_uname_size; + } + memcpy(h + USTAR_uname_offset, p, copy_length); + } + + r = archive_entry_gname_l(entry, &p, ©_length, sconv); + if (r != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Gname"); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate gname '%s' to %s", + p, archive_string_conversion_charset_name(sconv)); + ret = ARCHIVE_WARN; + } + if (copy_length > 0) { + if (strlen(p) > USTAR_gname_size) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Group name too long"); + ret = ARCHIVE_FAILED; + copy_length = USTAR_gname_size; + } + memcpy(h + USTAR_gname_offset, p, copy_length); + } + + if (format_number(archive_entry_mode(entry) & 07777, + h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "Numeric mode too large"); + ret = ARCHIVE_FAILED; + } + + if (format_number(archive_entry_uid(entry), + h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "Numeric user ID too large"); + ret = ARCHIVE_FAILED; + } + + if (format_number(archive_entry_gid(entry), + h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "Numeric group ID too large"); + ret = ARCHIVE_FAILED; + } + + if (format_number(archive_entry_size(entry), + h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "File size out of range"); + ret = ARCHIVE_FAILED; + } + + if (format_number(archive_entry_mtime(entry), + h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "File modification time too large"); + ret = ARCHIVE_FAILED; + } + + if (archive_entry_filetype(entry) == AE_IFBLK + || archive_entry_filetype(entry) == AE_IFCHR) { + if (format_number(archive_entry_rdevmajor(entry), + h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size, + USTAR_rdevmajor_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "Major device number too large"); + ret = ARCHIVE_FAILED; + } + + if (format_number(archive_entry_rdevminor(entry), + h + USTAR_rdevminor_offset, USTAR_rdevminor_size, + USTAR_rdevminor_max_size, strict)) { + archive_set_error(&a->archive, ERANGE, + "Minor device number too large"); + ret = ARCHIVE_FAILED; + } + } + + if (tartype >= 0) { + h[USTAR_typeflag_offset] = tartype; + } else if (mytartype >= 0) { + h[USTAR_typeflag_offset] = mytartype; + } else { + switch (archive_entry_filetype(entry)) { + case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break; + case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break; + case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break; + case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break; + case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break; + case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break; + case AE_IFSOCK: + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "tar format cannot archive socket"); + return (ARCHIVE_FAILED); + default: + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "tar format cannot archive this (mode=0%lo)", + (unsigned long)archive_entry_mode(entry)); + ret = ARCHIVE_FAILED; + } + } + + checksum = 0; + for (i = 0; i < 512; i++) + checksum += 255 & (unsigned int)h[i]; + h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ + /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ + format_octal(checksum, h + USTAR_checksum_offset, 6); + return (ret); +} + +/* + * Format a number into a field, with some intelligence. + */ +static int +format_number(int64_t v, char *p, int s, int maxsize, int strict) +{ + int64_t limit; + + limit = ((int64_t)1 << (s*3)); + + /* "Strict" only permits octal values with proper termination. */ + if (strict) + return (format_octal(v, p, s)); + + /* + * In non-strict mode, we allow the number to overwrite one or + * more bytes of the field termination. Even old tar + * implementations should be able to handle this with no + * problem. + */ + if (v >= 0) { + while (s <= maxsize) { + if (v < limit) + return (format_octal(v, p, s)); + s++; + limit <<= 3; + } + } + + /* Base-256 can handle any number, positive or negative. */ + return (format_256(v, p, maxsize)); +} + +/* + * Format a number into the specified field using base-256. + */ +static int +format_256(int64_t v, char *p, int s) +{ + p += s; + while (s-- > 0) { + *--p = (char)(v & 0xff); + v >>= 8; + } + *p |= 0x80; /* Set the base-256 marker bit. */ + return (0); +} + +/* + * Format a number into the specified field. + */ +static int +format_octal(int64_t v, char *p, int s) +{ + int len; + + len = s; + + /* Octal values can't be negative, so use 0. */ + if (v < 0) { + while (len-- > 0) + *p++ = '0'; + return (-1); + } + + p += s; /* Start at the end and work backwards. */ + while (s-- > 0) { + *--p = (char)('0' + (v & 7)); + v >>= 3; + } + + if (v == 0) + return (0); + + /* If it overflowed, fill field with max value. */ + while (len-- > 0) + *p++ = '7'; + + return (-1); +} + +static int +archive_write_ustar_close(struct archive_write *a) +{ + return (__archive_write_nulls(a, 512*2)); +} + +static int +archive_write_ustar_free(struct archive_write *a) +{ + struct ustar *ustar; + + ustar = (struct ustar *)a->format_data; + free(ustar); + a->format_data = NULL; + return (ARCHIVE_OK); +} + +static int +archive_write_ustar_finish_entry(struct archive_write *a) +{ + struct ustar *ustar; + 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 = 0; + return (ret); +} + +static ssize_t +archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) +{ + struct ustar *ustar; + 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); + ustar->entry_bytes_remaining -= s; + if (ret != ARCHIVE_OK) + return (ret); + return (s); +} diff --git a/src/3rdparty/libarchive/libarchive/archive_write_set_options.c b/src/3rdparty/libarchive/libarchive/archive_write_set_options.c new file mode 100644 index 00000000..962309ad --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/archive_write_set_options.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD$"); + +#include "archive_write_private.h" +#include "archive_options_private.h" + +static int archive_set_format_option(struct archive *a, + const char *m, const char *o, const char *v); +static int archive_set_filter_option(struct archive *a, + const char *m, const char *o, const char *v); +static int archive_set_option(struct archive *a, + const char *m, const char *o, const char *v); + +int +archive_write_set_format_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_WRITE_MAGIC, "archive_write_set_format_option", + archive_set_format_option); +} + +int +archive_write_set_filter_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_WRITE_MAGIC, "archive_write_set_filter_option", + archive_set_filter_option); +} + +int +archive_write_set_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_option(a, m, o, v, + ARCHIVE_WRITE_MAGIC, "archive_write_set_option", + archive_set_option); +} + +int +archive_write_set_options(struct archive *a, const char *options) +{ + return _archive_set_options(a, options, + ARCHIVE_WRITE_MAGIC, "archive_write_set_options", + archive_set_option); +} + +static int +archive_set_format_option(struct archive *_a, const char *m, const char *o, + const char *v) +{ + struct archive_write *a = (struct archive_write *)_a; + + if (a->format_name == NULL) + return (m == NULL)?ARCHIVE_FAILED:ARCHIVE_WARN - 1; + /* If the format name didn't match, return a special code for + * _archive_set_option[s]. */ + if (m != NULL && strcmp(m, a->format_name) != 0) + return (ARCHIVE_WARN - 1); + if (a->format_options == NULL) + return (ARCHIVE_WARN); + return a->format_options(a, o, v); +} + +static int +archive_set_filter_option(struct archive *_a, const char *m, const char *o, + const char *v) +{ + struct archive_write *a = (struct archive_write *)_a; + struct archive_write_filter *filter; + int r, rv = ARCHIVE_WARN; + + for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) { + if (filter->options == NULL) + continue; + if (m != NULL && strcmp(filter->name, m) != 0) + continue; + + r = filter->options(filter, o, v); + + if (r == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + + if (m != NULL) + return (r); + + if (r == ARCHIVE_OK) + rv = ARCHIVE_OK; + } + /* If the filter name didn't match, return a special code for + * _archive_set_option[s]. */ + if (rv == ARCHIVE_WARN && m != NULL) + rv = ARCHIVE_WARN - 1; + return (rv); +} + +static int +archive_set_option(struct archive *a, const char *m, const char *o, + const char *v) +{ + return _archive_set_either_option(a, m, o, v, + archive_set_format_option, + archive_set_filter_option); +} diff --git a/src/3rdparty/libarchive/libarchive/config_freebsd.h b/src/3rdparty/libarchive/libarchive/config_freebsd.h new file mode 100644 index 00000000..be25258f --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/config_freebsd.h @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* FreeBSD 5.0 and later has ACL and extattr support. */ +#if __FreeBSD__ > 4 +#define ARCHIVE_ACL_FREEBSD 1 +#define HAVE_ACL_GET_PERM_NP 1 +#define HAVE_ARC4RANDOM_BUF 1 +#define HAVE_EXTATTR_GET_FILE 1 +#define HAVE_EXTATTR_LIST_FILE 1 +#define HAVE_EXTATTR_SET_FD 1 +#define HAVE_EXTATTR_SET_FILE 1 +#define HAVE_STRUCT_XVFSCONF 1 +#define HAVE_SYS_ACL_H 1 +#define HAVE_SYS_EXTATTR_H 1 +#if __FreeBSD__ > 7 +/* FreeBSD 8.0 and later has NFSv4 ACL support */ +#define ARCHIVE_ACL_FREEBSD_NFS4 1 +#define HAVE_ACL_GET_LINK_NP 1 +#define HAVE_ACL_IS_TRIVIAL_NP 1 +#define HAVE_ACL_SET_LINK_NP 1 +#endif /* __FreeBSD__ > 7 */ +#endif /* __FreeBSD__ > 4 */ + +#ifdef WITH_OPENSSL +#define HAVE_LIBCRYPTO 1 +#define HAVE_OPENSSL_EVP_H 1 +#define HAVE_OPENSSL_MD5_H 1 +#define HAVE_OPENSSL_RIPEMD_H 1 +#define HAVE_OPENSSL_SHA_H 1 +#define HAVE_OPENSSL_SHA256_INIT 1 +#define HAVE_OPENSSL_SHA384_INIT 1 +#define HAVE_OPENSSL_SHA512_INIT 1 +#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1 +#define HAVE_SHA256 1 +#define HAVE_SHA384 1 +#define HAVE_SHA512 1 +#else +#define HAVE_LIBMD 1 +#define HAVE_MD5_H 1 +#define HAVE_MD5INIT 1 +#define HAVE_RIPEMD_H 1 +#define HAVE_SHA_H 1 +#define HAVE_SHA1 1 +#define HAVE_SHA1_INIT 1 +#define HAVE_SHA256 1 +#define HAVE_SHA256_H 1 +#define HAVE_SHA256_INIT 1 +#define HAVE_SHA512 1 +#define HAVE_SHA512_H 1 +#define HAVE_SHA512_INIT 1 +#endif + +#define HAVE_BSDXML_H 1 +#define HAVE_BZLIB_H 1 +#define HAVE_CHFLAGS 1 +#define HAVE_CHOWN 1 +#define HAVE_CHROOT 1 +#define HAVE_CTIME_R 1 +#define HAVE_CTYPE_H 1 +#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1 +#define HAVE_DECL_INT32_MAX 1 +#define HAVE_DECL_INT32_MIN 1 +#define HAVE_DECL_INT64_MAX 1 +#define HAVE_DECL_INT64_MIN 1 +#define HAVE_DECL_INTMAX_MAX 1 +#define HAVE_DECL_INTMAX_MIN 1 +#define HAVE_DECL_SIZE_MAX 1 +#define HAVE_DECL_SSIZE_MAX 1 +#define HAVE_DECL_STRERROR_R 1 +#define HAVE_DECL_UINT32_MAX 1 +#define HAVE_DECL_UINT64_MAX 1 +#define HAVE_DECL_UINTMAX_MAX 1 +#define HAVE_DIRENT_H 1 +#define HAVE_DLFCN_H 1 +#define HAVE_D_MD_ORDER 1 +#define HAVE_EFTYPE 1 +#define HAVE_EILSEQ 1 +#define HAVE_ERRNO_H 1 +#define HAVE_FCHDIR 1 +#define HAVE_FCHFLAGS 1 +#define HAVE_FCHMOD 1 +#define HAVE_FCHOWN 1 +#define HAVE_FCNTL 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FDOPENDIR 1 +#define HAVE_FORK 1 +#define HAVE_FSEEKO 1 +#define HAVE_FSTAT 1 +#define HAVE_FSTATAT 1 +#define HAVE_FSTATFS 1 +#define HAVE_FSTATVFS 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_FUTIMES 1 +#define HAVE_FUTIMESAT 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGRGID_R 1 +#define HAVE_GETGRNAM_R 1 +#define HAVE_GETPID 1 +#define HAVE_GETPWNAM_R 1 +#define HAVE_GETPWUID_R 1 +#define HAVE_GETVFSBYNAME 1 +#define HAVE_GMTIME_R 1 +#define HAVE_GRP_H 1 +#define HAVE_INTMAX_T 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LANGINFO_H 1 +#define HAVE_LCHFLAGS 1 +#define HAVE_LCHMOD 1 +#define HAVE_LCHOWN 1 +#define HAVE_LIBZ 1 +#define HAVE_LIMITS_H 1 +#define HAVE_LINK 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LOCALTIME_R 1 +#define HAVE_LONG_LONG_INT 1 +#define HAVE_LSTAT 1 +#define HAVE_LUTIMES 1 +#define HAVE_MBRTOWC 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MEMSET 1 +#define HAVE_MKDIR 1 +#define HAVE_MKFIFO 1 +#define HAVE_MKNOD 1 +#define HAVE_MKSTEMP 1 +#define HAVE_NL_LANGINFO 1 +#define HAVE_OPENAT 1 +#define HAVE_PATHS_H 1 +#define HAVE_PIPE 1 +#define HAVE_POLL 1 +#define HAVE_POLL_H 1 +#define HAVE_POSIX_SPAWNP 1 +#define HAVE_PTHREAD_H 1 +#define HAVE_PWD_H 1 +#define HAVE_READDIR_R 1 +#define HAVE_READLINK 1 +#define HAVE_READLINKAT 1 +#define HAVE_READPASSPHRASE 1 +#define HAVE_READPASSPHRASE_H 1 +#define HAVE_REGEX_H 1 +#define HAVE_SELECT 1 +#define HAVE_SETENV 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SIGACTION 1 +#define HAVE_SIGNAL_H 1 +#define HAVE_SPAWN_H 1 +#define HAVE_STATFS 1 +#define HAVE_STATVFS 1 +#define HAVE_STDARG_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRCHR 1 +#define HAVE_STRDUP 1 +#define HAVE_STRERROR 1 +#define HAVE_STRERROR_R 1 +#define HAVE_STRFTIME 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRRCHR 1 +#define HAVE_STRUCT_STATFS_F_NAMEMAX 1 +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 +#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +#define HAVE_STRUCT_STAT_ST_FLAGS 1 +#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 +#define HAVE_STRUCT_TM_TM_GMTOFF 1 +#define HAVE_SYMLINK 1 +#define HAVE_SYS_CDEFS_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_POLL_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_STATVFS_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_WAIT_H 1 +#define HAVE_TIMEGM 1 +#define HAVE_TIME_H 1 +#define HAVE_TZSET 1 +#define HAVE_UINTMAX_T 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UNSETENV 1 +#define HAVE_UNSIGNED_LONG_LONG 1 +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#define HAVE_UTIME 1 +#define HAVE_UTIMES 1 +#define HAVE_UTIME_H 1 +#define HAVE_VFORK 1 +#define HAVE_VPRINTF 1 +#define HAVE_WCHAR_H 1 +#define HAVE_WCHAR_T 1 +#define HAVE_WCRTOMB 1 +#define HAVE_WCSCMP 1 +#define HAVE_WCSCPY 1 +#define HAVE_WCSLEN 1 +#define HAVE_WCTOMB 1 +#define HAVE_WCTYPE_H 1 +#define HAVE_WMEMCMP 1 +#define HAVE_WMEMCPY 1 +#define HAVE_WMEMMOVE 1 +#define HAVE_ZLIB_H 1 +#define TIME_WITH_SYS_TIME 1 + +#if __FreeBSD_version >= 1100056 +#define HAVE_FUTIMENS 1 +#define HAVE_UTIMENSAT 1 +#endif + +/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */ +#if __FreeBSD__ < 5 +#define intmax_t int64_t +#define uintmax_t uint64_t +#endif + +/* FreeBSD defines for archive_hash.h */ +#ifdef WITH_OPENSSL +#define ARCHIVE_CRYPTO_MD5_OPENSSL 1 +#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA1_OPENSSL +#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1 +#else +#define ARCHIVE_CRYPTO_MD5_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA1_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA256_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA512_LIBMD 1 +#endif diff --git a/src/3rdparty/libarchive/libarchive/filter_fork.h b/src/3rdparty/libarchive/libarchive/filter_fork.h new file mode 100644 index 00000000..a28272be --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/filter_fork.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2007 Joerg Sonnenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef FILTER_FORK_H +#define FILTER_FORK_H + +pid_t +__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout); + +void +__archive_check_child(int in, int out); + +#endif diff --git a/src/3rdparty/libarchive/libarchive/filter_fork_posix.c b/src/3rdparty/libarchive/libarchive/filter_fork_posix.c new file mode 100644 index 00000000..02dbd4bb --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/filter_fork_posix.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 2007 Joerg Sonnenberger + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +/* This capability is only available on POSIX systems. */ +#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \ + (defined(HAVE_FORK) || defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP)) + +__FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $"); + +#if defined(HAVE_SYS_TYPES_H) +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) +# if defined(HAVE_POLL_H) +# include +# elif defined(HAVE_SYS_POLL_H) +# include +# endif +#elif defined(HAVE_SELECT) +# if defined(HAVE_SYS_SELECT_H) +# include +# elif defined(HAVE_UNISTD_H) +# include +# endif +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_SPAWN_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "archive.h" +#include "archive_cmdline_private.h" + +#include "filter_fork.h" + +pid_t +__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) +{ + pid_t child; + int stdin_pipe[2], stdout_pipe[2], tmp; +#if HAVE_POSIX_SPAWNP + posix_spawn_file_actions_t actions; + int r; +#endif + struct archive_cmdline *cmdline; + + cmdline = __archive_cmdline_allocate(); + if (cmdline == NULL) + goto state_allocated; + if (__archive_cmdline_parse(cmdline, cmd) != ARCHIVE_OK) + goto state_allocated; + + if (pipe(stdin_pipe) == -1) + goto state_allocated; + if (stdin_pipe[0] == 1 /* stdout */) { + if ((tmp = dup(stdin_pipe[0])) == -1) + goto stdin_opened; + close(stdin_pipe[0]); + stdin_pipe[0] = tmp; + } + if (pipe(stdout_pipe) == -1) + goto stdin_opened; + if (stdout_pipe[1] == 0 /* stdin */) { + if ((tmp = dup(stdout_pipe[1])) == -1) + goto stdout_opened; + close(stdout_pipe[1]); + stdout_pipe[1] = tmp; + } + +#if HAVE_POSIX_SPAWNP + + r = posix_spawn_file_actions_init(&actions); + if (r != 0) { + errno = r; + goto stdout_opened; + } + r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]); + if (r != 0) + goto actions_inited; + r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]); + if (r != 0) + goto actions_inited; + /* Setup for stdin. */ + r = posix_spawn_file_actions_adddup2(&actions, stdin_pipe[0], 0); + if (r != 0) + goto actions_inited; + if (stdin_pipe[0] != 0 /* stdin */) { + r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[0]); + if (r != 0) + goto actions_inited; + } + /* Setup for stdout. */ + r = posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], 1); + if (r != 0) + goto actions_inited; + if (stdout_pipe[1] != 1 /* stdout */) { + r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]); + if (r != 0) + goto actions_inited; + } + r = posix_spawnp(&child, cmdline->path, &actions, NULL, + cmdline->argv, NULL); + if (r != 0) + goto actions_inited; + posix_spawn_file_actions_destroy(&actions); + +#else /* HAVE_POSIX_SPAWNP */ + +#if HAVE_VFORK + child = vfork(); +#else + child = fork(); +#endif + if (child == -1) + goto stdout_opened; + if (child == 0) { + close(stdin_pipe[1]); + close(stdout_pipe[0]); + if (dup2(stdin_pipe[0], 0 /* stdin */) == -1) + _exit(254); + if (stdin_pipe[0] != 0 /* stdin */) + close(stdin_pipe[0]); + if (dup2(stdout_pipe[1], 1 /* stdout */) == -1) + _exit(254); + if (stdout_pipe[1] != 1 /* stdout */) + close(stdout_pipe[1]); + execvp(cmdline->path, cmdline->argv); + _exit(254); + } +#endif /* HAVE_POSIX_SPAWNP */ + + close(stdin_pipe[0]); + close(stdout_pipe[1]); + + *child_stdin = stdin_pipe[1]; + fcntl(*child_stdin, F_SETFL, O_NONBLOCK); + *child_stdout = stdout_pipe[0]; + fcntl(*child_stdout, F_SETFL, O_NONBLOCK); + __archive_cmdline_free(cmdline); + + return child; + +#if HAVE_POSIX_SPAWNP +actions_inited: + errno = r; + posix_spawn_file_actions_destroy(&actions); +#endif +stdout_opened: + close(stdout_pipe[0]); + close(stdout_pipe[1]); +stdin_opened: + close(stdin_pipe[0]); + close(stdin_pipe[1]); +state_allocated: + __archive_cmdline_free(cmdline); + return -1; +} + +void +__archive_check_child(int in, int out) +{ +#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)) + struct pollfd fds[2]; + int idx; + + idx = 0; + if (in != -1) { + fds[idx].fd = in; + fds[idx].events = POLLOUT; + ++idx; + } + if (out != -1) { + fds[idx].fd = out; + fds[idx].events = POLLIN; + ++idx; + } + + poll(fds, idx, -1); /* -1 == INFTIM, wait forever */ +#elif defined(HAVE_SELECT) + fd_set fds_in, fds_out, fds_error; + + FD_ZERO(&fds_in); + FD_ZERO(&fds_out); + FD_ZERO(&fds_error); + if (out != -1) { + FD_SET(out, &fds_in); + FD_SET(out, &fds_error); + } + if (in != -1) { + FD_SET(in, &fds_out); + FD_SET(in, &fds_error); + } + select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL); +#else + sleep(1); +#endif +} + +#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */ diff --git a/src/3rdparty/libarchive/libarchive/filter_fork_windows.c b/src/3rdparty/libarchive/libarchive/filter_fork_windows.c new file mode 100644 index 00000000..ad271fe6 --- /dev/null +++ b/src/3rdparty/libarchive/libarchive/filter_fork_windows.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2009-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include "archive_cmdline_private.h" +#include "archive_string.h" + +#include "filter_fork.h" + +pid_t +__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) +{ + HANDLE childStdout[2], childStdin[2],childStderr; + SECURITY_ATTRIBUTES secAtts; + STARTUPINFOA staInfo; + PROCESS_INFORMATION childInfo; + struct archive_string cmdline; + struct archive_string fullpath; + struct archive_cmdline *acmd; + char *arg0, *ext; + int i, l; + DWORD fl, fl_old; + + childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE; + childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE; + childStderr = INVALID_HANDLE_VALUE; + archive_string_init(&cmdline); + archive_string_init(&fullpath); + + acmd = __archive_cmdline_allocate(); + if (acmd == NULL) + goto fail; + if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK) + goto fail; + + /* + * Search the full path of 'path'. + * NOTE: This does not need if we give CreateProcessA 'path' as + * a part of the cmdline and give CreateProcessA NULL as first + * parameter, but I do not like that way. + */ + ext = strrchr(acmd->path, '.'); + if (ext == NULL || strlen(ext) > 4) + /* 'path' does not have a proper extension, so we have to + * give SearchPath() ".exe" as the extension. */ + ext = ".exe"; + else + ext = NULL;/* 'path' has an extension. */ + + fl = MAX_PATH; + do { + if (archive_string_ensure(&fullpath, fl) == NULL) + goto fail; + fl_old = fl; + fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s, + &arg0); + } while (fl != 0 && fl > fl_old); + if (fl == 0) + goto fail; + + /* + * Make a command line. + */ + for (l = 0, i = 0; acmd->argv[i] != NULL; i++) { + if (i == 0) + continue; + l += (int)strlen(acmd->argv[i]) + 1; + } + if (archive_string_ensure(&cmdline, l + 1) == NULL) + goto fail; + for (i = 0; acmd->argv[i] != NULL; i++) { + if (i == 0) { + const char *p, *sp; + + if ((p = strchr(acmd->argv[i], '/')) != NULL || + (p = strchr(acmd->argv[i], '\\')) != NULL) + p++; + else + p = acmd->argv[i]; + if ((sp = strchr(p, ' ')) != NULL) + archive_strappend_char(&cmdline, '"'); + archive_strcat(&cmdline, p); + if (sp != NULL) + archive_strappend_char(&cmdline, '"'); + } else { + archive_strappend_char(&cmdline, ' '); + archive_strcat(&cmdline, acmd->argv[i]); + } + } + if (i <= 1) { + const char *sp; + + if ((sp = strchr(arg0, ' ')) != NULL) + archive_strappend_char(&cmdline, '"'); + archive_strcat(&cmdline, arg0); + if (sp != NULL) + archive_strappend_char(&cmdline, '"'); + } + + secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); + secAtts.bInheritHandle = TRUE; + secAtts.lpSecurityDescriptor = NULL; + if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0) + goto fail; + if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0)) + goto fail; + if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) + goto fail; + if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0)) + goto fail; + if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), + GetCurrentProcess(), &childStderr, 0, TRUE, + DUPLICATE_SAME_ACCESS) == 0) + goto fail; + + memset(&staInfo, 0, sizeof(staInfo)); + staInfo.cb = sizeof(staInfo); + staInfo.hStdError = childStderr; + staInfo.hStdOutput = childStdout[1]; + staInfo.hStdInput = childStdin[0]; + staInfo.wShowWindow = SW_HIDE; + staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0, + NULL, NULL, &staInfo, &childInfo) == 0) + goto fail; + WaitForInputIdle(childInfo.hProcess, INFINITE); + CloseHandle(childInfo.hProcess); + CloseHandle(childInfo.hThread); + + *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY); + *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY); + + CloseHandle(childStdout[1]); + CloseHandle(childStdin[0]); + + archive_string_free(&cmdline); + archive_string_free(&fullpath); + __archive_cmdline_free(acmd); + return (childInfo.dwProcessId); + +fail: + if (childStdout[0] != INVALID_HANDLE_VALUE) + CloseHandle(childStdout[0]); + if (childStdout[1] != INVALID_HANDLE_VALUE) + CloseHandle(childStdout[1]); + if (childStdin[0] != INVALID_HANDLE_VALUE) + CloseHandle(childStdin[0]); + if (childStdin[1] != INVALID_HANDLE_VALUE) + CloseHandle(childStdin[1]); + if (childStderr != INVALID_HANDLE_VALUE) + CloseHandle(childStderr); + archive_string_free(&cmdline); + archive_string_free(&fullpath); + __archive_cmdline_free(acmd); + return (-1); +} + +void +__archive_check_child(int in, int out) +{ + (void)in; /* UNUSED */ + (void)out; /* UNUSED */ + Sleep(100); +} + +#endif /* _WIN32 && !__CYGWIN__ */ diff --git a/src/3rdparty/libarchive/qt_attribution.json b/src/3rdparty/libarchive/qt_attribution.json new file mode 100644 index 00000000..3abf2fcb --- /dev/null +++ b/src/3rdparty/libarchive/qt_attribution.json @@ -0,0 +1,15 @@ +{ + "Id": "libarchive", + "Name": "libarchive", + "QDocModule": "applicationmanager", + "QtUsage": "Optionally used in Qt ApplicationManager. Configure with -config force-system-libarchive to avoid.", + + "Description": "Multi-format archive and compression library.", + "Homepage": "http://www.libarchive.org/", + "Version": "3.3.2", + + "License": "BSD 2-clause \"Simplified\" License", + "LicenseId": "BSD-2-Clause", + "LicenseFile": "COPYING", + "Copyright": "(c) 2003-2017 Tim Kientzle et al. - see COPYING and the individual file headers" +} diff --git a/src/3rdparty/libbacktrace/CMakeLists.txt b/src/3rdparty/libbacktrace/CMakeLists.txt new file mode 100644 index 00000000..1102b117 --- /dev/null +++ b/src/3rdparty/libbacktrace/CMakeLists.txt @@ -0,0 +1,53 @@ +# Generated from libbacktrace.pro. + +##################################################################### +## BundledBacktrace Generic Library: +##################################################################### + +qt_internal_add_3rdparty_library(BundledBacktrace + QMAKE_LIB_NAME backtrace + STATIC + INSTALL + SOURCES + libbacktrace/atomic.c + libbacktrace/backtrace.c + libbacktrace/dwarf.c + libbacktrace/fileline.c + libbacktrace/mmap.c + libbacktrace/mmapio.c + libbacktrace/posix.c + libbacktrace/print.c + libbacktrace/simple.c + libbacktrace/sort.c + libbacktrace/state.c + DEFINES + _GNU_SOURCE + INCLUDE_DIRECTORIES + auxincl + libbacktrace + PUBLIC_INCLUDE_DIRECTORIES + $ +) +qt_disable_warnings(BundledBacktrace) +qt_set_symbol_visibility_hidden(BundledBacktrace) + +##################################################################### + +#### Keys ignored in scope 2:.:.:libbacktrace.pro:win32-msvc_x_: +# QMAKE_CFLAGS = "/D_CRT_SECURE_NO_WARNINGS" + +#### Keys ignored in scope 3:.:.:libbacktrace.pro:GCC: +# QMAKE_CFLAGS = "-Wno-unused" "-funwind-tables" "-Wno-switch" "-Wno-enum-compare" + +#### Keys ignored in scope 4:.:.:libbacktrace.pro:CLANG: +# QMAKE_CFLAGS = "-Wall" "-W" "-Wno-unused" + +qt_internal_extend_target(BundledBacktrace CONDITION LINUX + SOURCES + libbacktrace/elf.c +) + +qt_internal_extend_target(BundledBacktrace CONDITION MACOS + SOURCES + libbacktrace/macho.c +) diff --git a/src/3rdparty/libbacktrace/LICENSE b/src/3rdparty/libbacktrace/LICENSE new file mode 100644 index 00000000..74b5ddb5 --- /dev/null +++ b/src/3rdparty/libbacktrace/LICENSE @@ -0,0 +1,30 @@ +Copyright (C) 2012-2016 Free Software Foundation, Inc. +Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. diff --git a/src/3rdparty/libbacktrace/README.md b/src/3rdparty/libbacktrace/README.md new file mode 100644 index 00000000..14a2da2d --- /dev/null +++ b/src/3rdparty/libbacktrace/README.md @@ -0,0 +1,25 @@ +This is a standalone version of libbacktrace. + +libbacktrace prints stack traces. + +libbacktrace was originally writen by Ian Lance Taylor as part of GCC. + +Building libbacktrace requires CMake. + +How to build with ninja: + + mkdir build + cd build/ + cmake -GNinja -DENABLE_LIBBACKTRACE_TEST=true path/to/libbacktrace/source + ninja + +How to build with make: + + mkdir build + cd build/ + cmake -G'Unix Makefiles' -DENABLE_LIBBACKTRACE_TEST=true path/to/libbacktrace/source + make + +How to run the tests: + + ctest diff --git a/src/3rdparty/libbacktrace/auxincl/dwarf2.h b/src/3rdparty/libbacktrace/auxincl/dwarf2.h new file mode 100644 index 00000000..205df8d2 --- /dev/null +++ b/src/3rdparty/libbacktrace/auxincl/dwarf2.h @@ -0,0 +1,109 @@ +/* dwarf2.h -- minimal GCC dwarf2.h replacement for libbacktrace + Contributed by Alexander Monakov, ISP RAS + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_AUX_DWARF2_H +#define BACKTRACE_AUX_DWARF2_H + +/* Provide stub enum tags. */ +enum dwarf_attribute {_dummy_dwarf_attribute}; +enum dwarf_form {_dummy_dwarf_form}; +enum dwarf_tag {_dummy_dwarf_tag}; + +#define DW_AT_abstract_origin 0x31 +#define DW_AT_call_file 0x58 +#define DW_AT_call_line 0x59 +#define DW_AT_comp_dir 0x1b +#define DW_AT_high_pc 0x12 +#define DW_AT_linkage_name 0x6e +#define DW_AT_low_pc 0x11 +#define DW_AT_MIPS_linkage_name 0x2007 +#define DW_AT_name 0x03 +#define DW_AT_namelist_item 0x44 +#define DW_AT_ranges 0x55 +#define DW_AT_ranges_base 0x74 +#define DW_AT_specification 0x47 +#define DW_AT_stmt_list 0x10 +#define DW_FORM_addr 0x01 +#define DW_FORM_addrx 0x1b +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data1 0x0b +#define DW_FORM_data16 0x1e +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_exprloc 0x18 +#define DW_FORM_flag 0x0c +#define DW_FORM_flag_present 0x19 +#define DW_FORM_GNU_addr_index 0x1f01 +#define DW_FORM_GNU_ref_alt 0x1f20 +#define DW_FORM_GNU_str_index 0x1f02 +#define DW_FORM_GNU_strp_alt 0x1f21 +#define DW_FORM_indirect 0x16 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref_sig8 0x20 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_sdata 0x0d +#define DW_FORM_sec_offset 0x17 +#define DW_FORM_string 0x08 +#define DW_FORM_strp 0x0e +#define DW_FORM_strp_sup 0x1d +#define DW_FORM_udata 0x0f +#define DW_LNE_define_file 0x03 +#define DW_LNE_define_file_MD5 0x05 +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_set_discriminator 0x04 +#define DW_LNS_advance_line 0x03 +#define DW_LNS_advance_pc 0x02 +#define DW_LNS_const_add_pc 0x08 +#define DW_LNS_copy 0x01 +#define DW_LNS_extended_op 0x00 +#define DW_LNS_fixed_advance_pc 0x09 +#define DW_LNS_negate_stmt 0x06 +#define DW_LNS_set_basic_block 0x07 +#define DW_LNS_set_column 0x05 +#define DW_LNS_set_epilogue_begin 0x0b +#define DW_LNS_set_file 0x04 +#define DW_LNS_set_isa 0x0c +#define DW_LNS_set_prologue_end 0x0a +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_entry_point 0x03 +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_subprogram 0x2e + +#endif diff --git a/src/3rdparty/libbacktrace/auxincl/filenames.h b/src/3rdparty/libbacktrace/auxincl/filenames.h new file mode 100644 index 00000000..90f95cd8 --- /dev/null +++ b/src/3rdparty/libbacktrace/auxincl/filenames.h @@ -0,0 +1,41 @@ +/* filenames.h -- minimal GCC filenames.h replacement for libbacktrace + Contributed by Alexander Monakov, ISP RAS + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_AUX_FILENAMES_H +#define BACKTRACE_AUX_FILENAMES_H + +/* Assume POSIX paths. */ + +#define IS_DIR_SEPARATOR(c) ((c) == '/') +#define IS_ABSOLUTE_PATH(f) ((f)[0] == '/') + +#endif + diff --git a/src/3rdparty/libbacktrace/libbacktrace.pro b/src/3rdparty/libbacktrace/libbacktrace.pro new file mode 100644 index 00000000..ff3da892 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace.pro @@ -0,0 +1,47 @@ +requires(linux|macos) + +TEMPLATE = lib +TARGET = qtbacktrace + +load(am-config) + +CONFIG += \ + static \ + hide_symbols \ + exceptions_off rtti_off warn_off \ + installed + +MODULE_INCLUDEPATH += $$PWD + +load(qt_helper_lib) + +win32-msvc* { + QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS +} +*-g++* { + QMAKE_CFLAGS += -Wno-unused -funwind-tables -Wno-switch -Wno-enum-compare +} +*-clang* { + CONFIG += warn_off + QMAKE_CFLAGS += -Wall -W -Wno-unused +} + +DEFINES *= _GNU_SOURCE + +INCLUDEPATH += $$PWD/auxincl $$PWD/libbacktrace + +linux: SOURCES += libbacktrace/elf.c +macos: SOURCES += libbacktrace/macho.c + +SOURCES += \ + libbacktrace/backtrace.c \ + libbacktrace/simple.c \ + libbacktrace/dwarf.c \ + libbacktrace/mmapio.c \ + libbacktrace/mmap.c \ + libbacktrace/atomic.c \ + libbacktrace/fileline.c \ + libbacktrace/posix.c \ + libbacktrace/print.c \ + libbacktrace/sort.c \ + libbacktrace/state.c \ diff --git a/src/3rdparty/libbacktrace/libbacktrace/ChangeLog b/src/3rdparty/libbacktrace/libbacktrace/ChangeLog new file mode 100644 index 00000000..acc07047 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/ChangeLog @@ -0,0 +1,590 @@ +2016-05-18 Uros Bizjak + + PR target/71161 + * elf.c (phdr_callback) [__i386__]: Add + __attribute__((__force_align_arg_pointer__)). + +2016-03-02 Maxim Ostapenko + + * elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to + avoid possible crash. + (elf_add): Don't set *fileline_fn to elf_nodebug value in case of + missing debug info anymore. + +2016-02-06 John David Anglin + + * mmap.c (MAP_FAILED): Define if not defined. + +2016-01-04 Jakub Jelinek + + Update copyright years. + +2015-12-18 Andris Pavenis + + * configure.ac: Specify that DJGPP do not have mmap + even when sys/mman.h exists. + * configure: Regenerate + +2015-12-09 John David Anglin + + PR libgfortran/68115 + * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. + * configure: Regenerate. + * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call + to void. + +2015-09-17 Ian Lance Taylor + + * posix.c (backtrace_open): Cast second argument of open() to int. + +2015-09-11 Ian Lance Taylor + + * Makefile.am (backtrace.lo): Depend on internal.h. + (sort.lo, stest.lo): Add explicit dependencies. + * Makefile.in: Rebuild. + +2015-09-09 Hans-Peter Nilsson + + * backtrace.c: #include . + +2015-09-08 Ian Lance Taylor + + PR other/67457 + * backtrace.c: #include "internal.h". + (struct backtrace_data): Add can_alloc field. + (unwind): If can_alloc is false, don't try to get file/line + information. + (backtrace_full): Set can_alloc field in bdata. + * alloc.c (backtrace_alloc): Don't call error_callback if it is + NULL. + * mmap.c (backtrace_alloc): Likewise. + * internal.h: Update comments for backtrace_alloc and + backtrace_free. + +2015-09-08 Ian Lance Taylor + + PR other/67457 + * mmap.c (backtrace_alloc): Correct test for mmap failure. + +2015-08-31 Ulrich Weigand + + * configure.ac: For spu-*-* targets, set have_fcntl to no. + * configure: Regenerate. + +2015-08-27 Ulrich Weigand + + * configure.ac: Remove [disable-shared] argument to LT_INIT. + Remove setting PIC_FLAG when building as target library. + * configure: Regenerate. + +2015-08-26 Hans-Peter Nilsson + + * configure.ac: Only compile with -fPIC if the target + supports it. + * configure: Regenerate. + +2015-08-24 Ulrich Weigand + + * configure.ac: Set have_mmap to no on spu-*-* targets. + * configure: Regenerate. + +2015-08-13 Ian Lance Taylor + + * dwarf.c (read_function_entry): Add vec_inlined parameter. + Change all callers. + +2015-06-11 Martin Sebor + + PR sanitizer/65479 + * dwarf.c (struct line): Add new field idx. + (line_compare): Use it. + (add_line): Set it. + (read_line_info): Reset it. + +2015-05-29 Tristan Gingold + + * pecoff.c: New file. + * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. + * Makefile.in: Regenerate. + * filetype.awk: Detect pecoff. + * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. + Add pecoff. + * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is + true. + * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. + * configure: Regenerate. + * pecoff.c: New file. + +2015-05-13 Michael Haubenwallner + + * Makefile.in: Regenerated with automake-1.11.6. + * aclocal.m4: Likewise. + * configure: Likewise. + +2015-01-24 Matthias Klose + + * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. + * configure: Regenerate. + +2015-01-05 Jakub Jelinek + + Update copyright years. + +2014-11-21 H.J. Lu + + PR bootstrap/63784 + * configure: Regenerated. + +2014-11-11 David Malcolm + + * ChangeLog.jit: New. + +2014-11-11 Francois-Xavier Coudert + + PR target/63610 + * configure: Regenerate. + +2014-10-23 Ian Lance Taylor + + * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: + Fix to return void *. + +2014-05-08 Ian Lance Taylor + + * mmap.c (backtrace_free): If freeing a large aligned block of + memory, call munmap rather than holding onto it. + (backtrace_vector_grow): When growing a vector, double the number + of pages requested. When releasing the old version of a grown + vector, pass the correct size to backtrace_free. + +2014-03-07 Ian Lance Taylor + + * sort.c (backtrace_qsort): Use middle element as pivot. + +2014-03-06 Ian Lance Taylor + + * sort.c: New file. + * stest.c: New file. + * internal.h (backtrace_qsort): Declare. + * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. + (read_line_info, read_function_entry): Likewise. + (read_function_info, build_dwarf_data): Likewise. + * elf.c (elf_initialize_syminfo): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. + (stest_SOURCES, stest_LDADD): Define. + (check_PROGRAMS): Add stest. + +2014-02-07 Misty De Meo + + PR target/58710 + * configure.ac: Use AC_LINK_IFELSE in check for + _Unwind_GetIPInfo. + * configure: Regenerate. + +2014-01-02 Richard Sandiford + + Update copyright years + +2013-12-06 Jakub Jelinek + + * elf.c (ET_DYN): Undefine and define again. + (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, + return early -1 without closing the descriptor. + (struct phdr_data): Add exe_descriptor. + (phdr_callback): If pd->exe_descriptor is not -1, for very first + call if dlpi_name is NULL just call elf_add with the exe_descriptor, + otherwise backtrace_close the exe_descriptor if not -1. Adjust + call to elf_add. + (backtrace_initialize): Adjust call to elf_add. If it returns + -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. + +2013-12-05 Ian Lance Taylor + + * alloc.c (backtrace_vector_finish): Add error_callback and data + parameters. Call backtrace_vector_release. Return address base. + * mmap.c (backtrace_vector_finish): Add error_callback and data + parameters. Return address base. + * dwarf.c (read_function_info): Get new address base from + backtrace_vector_finish. + * internal.h (backtrace_vector_finish): Update declaration. + +2013-11-27 Ian Lance Taylor + + * dwarf.c (find_address_ranges): New static function, broken out + of build_address_map. + (build_address_map): Call it. + * btest.c (check): Check for missing filename or function, rather + than crashing. + (f3): Check that enough frames were returned. + +2013-11-19 Jakub Jelinek + + * backtrace.h (backtrace_syminfo_callback): Add symsize argument. + * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as + last argument. + * btest.c (struct symdata): Add size field. + (callback_three): Add symsize argument. Copy it to the data->size + field. + (f23): Set symdata.size to 0. + (test5): Likewise. If sizeof (int) > 1, lookup address of + ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size + values. + + * atomic.c: Include sys/types.h. + +2013-11-18 Ian Lance Taylor + + * configure.ac: Check for support of __atomic extensions. + * internal.h: Declare or #define atomic functions for use in + backtrace code. + * atomic.c: New file. + * dwarf.c (dwarf_lookup_pc): Use atomic functions. + (dwarf_fileline, backtrace_dwarf_add): Likewise. + * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. + (backtrace_initialize): Likewise. + * fileline.c (fileline_initialize): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. + * configure, config.h.in, Makefile.in: Rebuild. + +2013-11-18 Jakub Jelinek + + * elf.c (SHN_UNDEF): Define. + (elf_initialize_syminfo): Add base_address argument. Ignore symbols + with st_shndx == SHN_UNDEF. Add base_address to address fields. + (elf_add): Adjust caller. + + * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. + +2013-11-16 Ian Lance Taylor + + * backtrace.h (backtrace_create_state): Correct comment about + threading. + +2013-11-15 Ian Lance Taylor + + * backtrace.h (backtrace_syminfo): Update comment and parameter + name to take any address, not just a PC value. + * elf.c (STT_OBJECT): Define. + (elf_nosyms): Rename parameter pc to addr. + (elf_symbol_search): Rename local variable pc to addr. + (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. + (elf_syminfo): Rename parameter pc to addr. + * btest.c (global): New global variable. + (test5): New test. + (main): Call test5. + +2013-10-17 Ian Lance Taylor + + * elf.c (elf_add): Don't get the wrong offsets if a debug section + is missing. + +2013-10-15 David Malcolm + + * configure.ac: Add --enable-host-shared, setting up + pre-existing PIC_FLAG variable within Makefile.am et al. + * configure: Regenerate. + +2013-09-20 Alan Modra + + * configure: Regenerate. + +2013-07-23 Alexander Monakov + + * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. + +2013-07-23 Alexander Monakov + + * elf.c (backtrace_initialize): Pass elf_fileline_fn to + dl_iterate_phdr callbacks. + +2013-03-25 Ian Lance Taylor + + * alloc.c: #include . + * mmap.c: Likewise. + +2013-01-31 Ian Lance Taylor + + * dwarf.c (read_function_info): Permit fvec parameter to be NULL. + (dwarf_lookup_pc): Don't use ddata->fvec if threaded. + +2013-01-25 Jakub Jelinek + + PR other/56076 + * dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir + attribute was not seen. + +2013-01-16 Ian Lance Taylor + + * dwarf.c (struct unit): Add filename and abs_filename fields. + (build_address_map): Set new fields when reading unit. + (dwarf_lookup_pc): If we don't find an entry in the line table, + just return the main file name. + +2013-01-14 Richard Sandiford + + Update copyright years. + +2013-01-01 Ian Lance Taylor + + PR bootstrap/54834 + * Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I + $(MULTIBUILDTOP)/../../gcc/include. + * Makefile.in: Rebuild. + +2013-01-01 Ian Lance Taylor + + PR other/55536 + * mmap.c (backtrace_alloc): Don't call sync functions if not + threaded. + (backtrace_free): Likewise. + +2012-12-12 John David Anglin + + * mmapio.c: Define MAP_FAILED if not defined. + +2012-12-11 Jakub Jelinek + + PR bootstrap/54926 + * Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@. + * configure.ac: If --with-target-subdir, add -frandom-seed=$@ + to EXTRA_FLAGS unconditionally, otherwise check whether the compiler + accepts it. + * Makefile.in: Regenerated. + * configure: Regenerated. + +2012-12-07 Jakub Jelinek + + PR bootstrap/54926 + * Makefile.am (AM_CFLAGS): Add -frandom-seed=$@. + * Makefile.in: Regenerated. + +2012-11-20 Ian Lance Taylor + + * dwarf.c (read_attribute): Always clear val. + +2012-11-13 Ian Lance Taylor + + PR other/55312 + * configure.ac: Only add -Werror if building a target library. + * configure: Rebuild. + +2012-11-12 Ian Lance Taylor + Rainer Orth + Gerald Pfeifer + + * configure.ac: Check for getexecname. + * fileline.c: #include . Define getexecname if not + available. + (fileline_initialize): Try to find the executable in a few + different ways. + * print.c (error_callback): Only print the filename if it came + from the backtrace state. + * configure, config.h.in: Rebuild. + +2012-10-29 Ian Lance Taylor + + * mmap.c (backtrace_vector_release): Correct last patch: add + aligned, not size. + +2012-10-29 Ian Lance Taylor + + * mmap.c (backtrace_vector_release): Make sure freed block is + aligned on 8-byte boundary. + +2012-10-26 Ian Lance Taylor + + PR other/55087 + * posix.c (backtrace_open): Add does_not_exist parameter. + * elf.c (phdr_callback): Do not warn if shared library could not + be opened. + * fileline.c (fileline_initialize): Update calls to + backtrace_open. + * internal.h (backtrace_open): Update declaration. + +2012-10-26 Jack Howarth + + PR target/55061 + * configure.ac: Check for _Unwind_GetIPInfo function declaration. + * configure: Regenerate. + +2012-10-24 Ian Lance Taylor + + PR target/55061 + * configure.ac: Check whether -funwind-tables option works. + * configure: Rebuild. + +2012-10-11 Ian Lance Taylor + + * configure.ac: Do not use dl_iterate_phdr on Solaris 10. + * configure: Rebuild. + +2012-10-10 Ian Lance Taylor + + * elf.c: Rename all Elf typedefs to start with b_elf, and be all + lower case. + +2012-10-10 Hans-Peter Nilsson + + * elf.c (elf_add_syminfo_data): Add casts to avoid warning. + +2012-10-09 Ian Lance Taylor + + * dwarf.c (dwarf_fileline): Add cast to avoid warning. + (backtrace_dwarf_add): Likewise. + +2012-10-09 Ian Lance Taylor + + Add support for tracing through shared libraries. + * configure.ac: Check for link.h and dl_iterate_phdr. + * elf.c: #include if system has dl_iterate_phdr. #undef + ELF macros before #defining them. + (dl_phdr_info, dl_iterate_phdr): Define if system does not have + dl_iterate_phdr. + (struct elf_syminfo_data): Add next field. + (elf_initialize_syminfo): Initialize next field. + (elf_add_syminfo_data): New static function. + (elf_add): New static function, broken out of + backtrace_initialize. Call backtrace_dwarf_add instead of + backtrace_dwarf_initialize. + (struct phdr_data): Define. + (phdr_callback): New static function. + (backtrace_initialize): Call elf_add. + * dwarf.c (struct dwarf_data): Add next and base_address fields. + (add_unit_addr): Add base_address parameter. Change all callers. + (add_unit_ranges, build_address_map): Likewise. + (add_line): Add ddata parameter. Change all callers. + (read_line_program, add_function_range): Likewise. + (dwarf_lookup_pc): New static function, broken out of + dwarf_fileline. + (dwarf_fileline): Call dwarf_lookup_pc. + (build_dwarf_data): New static function. + (backtrace_dwarf_add): New function. + (backtrace_dwarf_initialize): Remove. + * internal.h (backtrace_dwarf_initialize): Don't declare. + (backtrace_dwarf_add): Declare. + * configure, config.h.in: Rebuild. + +2012-10-04 Gerald Pfeifer + + * btest.c (f23): Avoid uninitialized variable warning. + +2012-10-04 Ian Lance Taylor + + * dwarf.c: If the system header files do not declare strnlen, + provide our own version. + +2012-10-03 Ian Lance Taylor + + * dwarf.c (read_uleb128): Fix overflow test. + (read_sleb128): Likewise. + (build_address_map): Don't change unit_buf.start. + +2012-10-02 Uros Bizjak + + PR other/54761 + * configure.ac (EXTRA_FLAGS): New. + * Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS). + * configure, Makefile.in: Regenerate. + +2012-09-29 Ian Lance Taylor + + PR other/54749 + * fileline.c (fileline_initialize): Pass errnum as -1 when + reporting that we could not read executable information after a + previous failure. + +2012-09-27 Ian Lance Taylor + + PR bootstrap/54732 + * configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE. + * Makefile.am: Add dependencies for all objects. + * configure, aclocal.m4, Makefile.in: Rebuild. + +2012-09-27 Ian Lance Taylor + + PR other/54726 + * elf.c (backtrace_initialize): Set *fileln_fn, not + state->fileln_fn. + +2012-09-19 Ian Lance Taylor + + * configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled + as a target library. + * configure: Rebuild. + +2012-09-19 Rainer Orth + Ian Lance Taylor + + * configure.ac (GCC_HEADER_STDINT): Invoke. + * backtrace.h: If we can't find , use "gstdint.h". + * btest.c: Don't include . + * dwarf.c: Likewise. + * configure, aclocal.m4, Makefile.in, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + PR bootstrap/54623 + * Makefile.am (AM_CPPFLAGS): Define. + (AM_CFLAGS): Remove -I options. + * Makefile.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * posix.c (O_BINARY): Define if not defined. + (backtrace_open): Pass O_BINARY to open. Only call fcntl if + HAVE_FCNTL is defined. + * configure.ac: Test for the fcntl function. + * configure, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * btest.c (test1, test2, test3, test4): Add the unused attribute. + +2012-09-18 Ian Lance Taylor + + * dwarf.c: Correct test of HAVE_DECL_STRNLEN. + +2012-09-18 Ian Lance Taylor + + * configure.ac: Add AC_USE_SYSTEM_EXTENSIONS. + * mmapio.c: Don't define _GNU_SOURCE. + * configure, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * configure.ac: Check whether strnlen is declared. + * dwarf.c: Declare strnlen if not declared. + * configure, config.h.in: Rebuild. + +2012-09-18 Rainer Orth + + * fileline.c: Include . + * mmap.c: Likewise. + +2012-09-17 Ian Lance Taylor + + PR bootstrap/54611 + * nounwind.c (backtrace_full): Rename from backtrace. Add state + parameter. + +2012-09-17 Gerald Pfeifer + + PR bootstrap/54611 + * nounwind.c (backtrace_simple): Add state parameter. + +2012-09-17 Ian Lance Taylor + + PR bootstrap/54609 + * unknown.c (unknown_fileline): Add state parameter, remove + fileline_data parameter, name error_callback parameter. + (backtrace_initialize): Add state parameter. + +2012-09-17 Ian Lance Taylor + + * Initial implementation. + +Copyright (C) 2012-2016 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/src/3rdparty/libbacktrace/libbacktrace/README b/src/3rdparty/libbacktrace/libbacktrace/README new file mode 100644 index 00000000..e8b22574 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/README @@ -0,0 +1,23 @@ +The libbacktrace library +Initially written by Ian Lance Taylor + +The libbacktrace library may be linked into a program or library and +used to produce symbolic backtraces. Sample uses would be to print a +detailed backtrace when an error occurs or to gather detailed +profiling information. + +The libbacktrace library is provided under a BSD license. See the +source files for the exact license text. + +The public functions are declared and documented in the header file +backtrace.h, which should be #include'd by a user of the library. + +Building libbacktrace will generate a file backtrace-supported.h, +which a user of the library may use to determine whether backtraces +will work. See the source file backtrace-supported.h.in for the +macros that it defines. + +As of September 2012, libbacktrace only supports ELF executables with +DWARF debugging information. The library is written to make it +straightforward to add support for other object file and debugging +formats. diff --git a/src/3rdparty/libbacktrace/libbacktrace/atomic.c b/src/3rdparty/libbacktrace/libbacktrace/atomic.c new file mode 100644 index 00000000..502ad358 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/atomic.c @@ -0,0 +1,113 @@ +/* atomic.c -- Support for atomic functions if not present. + Copyright (C) 2013-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* This file holds implementations of the atomic functions that are + used if the host compiler has the sync functions but not the atomic + functions, as is true of versions of GCC before 4.7. */ + +#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) + +/* Do an atomic load of a pointer. */ + +void * +backtrace_atomic_load_pointer (void *arg) +{ + void **pp; + void *p; + + pp = (void **) arg; + p = *pp; + while (!__sync_bool_compare_and_swap (pp, p, p)) + p = *pp; + return p; +} + +/* Do an atomic load of an int. */ + +int +backtrace_atomic_load_int (int *p) +{ + int i; + + i = *p; + while (!__sync_bool_compare_and_swap (p, i, i)) + i = *p; + return i; +} + +/* Do an atomic store of a pointer. */ + +void +backtrace_atomic_store_pointer (void *arg, void *p) +{ + void **pp; + void *old; + + pp = (void **) arg; + old = *pp; + while (!__sync_bool_compare_and_swap (pp, old, p)) + old = *pp; +} + +/* Do an atomic store of a size_t value. */ + +void +backtrace_atomic_store_size_t (size_t *p, size_t v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +/* Do an atomic store of a int value. */ + +void +backtrace_atomic_store_int (int *p, int v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +#endif diff --git a/src/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h b/src/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h new file mode 100644 index 00000000..d89221c7 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/backtrace-supported.h @@ -0,0 +1,3 @@ +#define BACKTRACE_SUPPORTED 1 +#define BACKTRACE_USES_MALLOC 0 +#define BACKTRACE_SUPPORTS_THREADS 1 diff --git a/src/3rdparty/libbacktrace/libbacktrace/backtrace.c b/src/3rdparty/libbacktrace/libbacktrace/backtrace.c new file mode 100644 index 00000000..c579e803 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/backtrace.c @@ -0,0 +1,129 @@ +/* backtrace.c -- Entry point for stack backtrace library. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include + +#include "unwind.h" +#include "backtrace.h" +#include "internal.h" + +/* The main backtrace_full routine. */ + +/* Data passed through _Unwind_Backtrace. */ + +struct backtrace_data +{ + /* Number of frames to skip. */ + int skip; + /* Library state. */ + struct backtrace_state *state; + /* Callback routine. */ + backtrace_full_callback callback; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data to pass to callback routines. */ + void *data; + /* Value to return from backtrace_full. */ + int ret; + /* Whether there is any memory available. */ + int can_alloc; +}; + +/* Unwind library callback routine. This is passed to + _Unwind_Backtrace. */ + +static _Unwind_Reason_Code +unwind (struct _Unwind_Context *context, void *vdata) +{ + struct backtrace_data *bdata = (struct backtrace_data *) vdata; + uintptr_t pc; + int ip_before_insn = 0; + +#ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + pc = _Unwind_GetIP (context); +#endif + + if (bdata->skip > 0) + { + --bdata->skip; + return _URC_NO_REASON; + } + + if (!ip_before_insn) + --pc; + + if (!bdata->can_alloc) + bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); + else + bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, + bdata->error_callback, bdata->data); + if (bdata->ret != 0) + return _URC_END_OF_STACK; + + return _URC_NO_REASON; +} + +/* Get a stack backtrace. */ + +int __attribute__((noinline)) +backtrace_full (struct backtrace_state *state, int skip, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct backtrace_data bdata; + void *p; + + bdata.skip = skip + 1; + bdata.state = state; + bdata.callback = callback; + bdata.error_callback = error_callback; + bdata.data = data; + bdata.ret = 0; + + /* If we can't allocate any memory at all, don't try to produce + file/line information. */ + p = backtrace_alloc (state, 4096, NULL, NULL); + if (p == NULL) + bdata.can_alloc = 0; + else + { + backtrace_free (state, p, 4096, NULL, NULL); + bdata.can_alloc = 1; + } + + _Unwind_Backtrace (unwind, &bdata); + return bdata.ret; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/backtrace.h b/src/3rdparty/libbacktrace/libbacktrace/backtrace.h new file mode 100644 index 00000000..0631f265 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/backtrace.h @@ -0,0 +1,188 @@ +/* backtrace.h -- Public header file for stack backtrace library. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_H +#define BACKTRACE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The backtrace state. This struct is intentionally not defined in + the public interface. */ + +struct backtrace_state; + +/* The type of the error callback argument to backtrace functions. + This function, if not NULL, will be called for certain error cases. + The DATA argument is passed to the function that calls this one. + The MSG argument is an error message. The ERRNUM argument, if + greater than 0, holds an errno value. The MSG buffer may become + invalid after this function returns. + + As a special case, the ERRNUM argument will be passed as -1 if no + debug info can be found for the executable, but the function + requires debug info (e.g., backtrace_full, backtrace_pcinfo). The + MSG in this case will be something along the lines of "no debug + info". Similarly, ERRNUM will be passed as -1 if there is no + symbol table, but the function requires a symbol table (e.g., + backtrace_syminfo). This may be used as a signal that some other + approach should be tried. */ + +typedef void (*backtrace_error_callback) (void *data, const char *msg, + int errnum); + +/* Create state information for the backtrace routines. This must be + called before any of the other routines, and its return value must + be passed to all of the other routines. FILENAME is the path name + of the executable file; if it is NULL the library will try + system-specific path names. If not NULL, FILENAME must point to a + permanent buffer. If THREADED is non-zero the state may be + accessed by multiple threads simultaneously, and the library will + use appropriate atomic operations. If THREADED is zero the state + may only be accessed by one thread at a time. This returns a state + pointer on success, NULL on error. If an error occurs, this will + call the ERROR_CALLBACK routine. + + Calling this function allocates resources that cannot be freed. + There is no backtrace_free_state function. The state is used to + cache information that is expensive to recompute. Programs are + expected to call this function at most once and to save the return + value for all later calls to backtrace functions. */ + +extern struct backtrace_state *backtrace_create_state ( + const char *filename, int threaded, + backtrace_error_callback error_callback, void *data); + +/* The type of the callback argument to the backtrace_full function. + DATA is the argument passed to backtrace_full. PC is the program + counter. FILENAME is the name of the file containing PC, or NULL + if not available. LINENO is the line number in FILENAME containing + PC, or 0 if not available. FUNCTION is the name of the function + containing PC, or NULL if not available. This should return 0 to + continuing tracing. The FILENAME and FUNCTION buffers may become + invalid after this function returns. */ + +typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, + const char *filename, int lineno, + const char *function); + +/* Get a full stack backtrace. SKIP is the number of frames to skip; + passing 0 will start the trace with the function calling + backtrace_full. DATA is passed to the callback routine. If any + call to CALLBACK returns a non-zero value, the stack backtrace + stops, and backtrace returns that value; this may be used to limit + the number of stack frames desired. If all calls to CALLBACK + return 0, backtrace returns 0. The backtrace_full function will + make at least one call to either CALLBACK or ERROR_CALLBACK. This + function requires debug info for the executable. */ + +extern int backtrace_full (struct backtrace_state *state, int skip, + backtrace_full_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* The type of the callback argument to the backtrace_simple function. + DATA is the argument passed to simple_backtrace. PC is the program + counter. This should return 0 to continue tracing. */ + +typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc); + +/* Get a simple backtrace. SKIP is the number of frames to skip, as + in backtrace. DATA is passed to the callback routine. If any call + to CALLBACK returns a non-zero value, the stack backtrace stops, + and backtrace_simple returns that value. Otherwise + backtrace_simple returns 0. The backtrace_simple function will + make at least one call to either CALLBACK or ERROR_CALLBACK. This + function does not require any debug info for the executable. */ + +extern int backtrace_simple (struct backtrace_state *state, int skip, + backtrace_simple_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* Print the current backtrace in a user readable format to a FILE. + SKIP is the number of frames to skip, as in backtrace_full. Any + error messages are printed to stderr. This function requires debug + info for the executable. */ + +extern void backtrace_print (struct backtrace_state *state, int skip, FILE *); + +/* Given PC, a program counter in the current program, call the + callback function with filename, line number, and function name + information. This will normally call the callback function exactly + once. However, if the PC happens to describe an inlined call, and + the debugging information contains the necessary information, then + this may call the callback function multiple times. This will make + at least one call to either CALLBACK or ERROR_CALLBACK. This + returns the first non-zero value returned by CALLBACK, or 0. */ + +extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* The type of the callback argument to backtrace_syminfo. DATA and + PC are the arguments passed to backtrace_syminfo. SYMNAME is the + name of the symbol for the corresponding code. SYMVAL is the + value and SYMSIZE is the size of the symbol. SYMNAME will be NULL + if no error occurred but the symbol could not be found. */ + +typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, + const char *symname, + uintptr_t symval, + uintptr_t symsize); + +/* Given ADDR, an address or program counter in the current program, + call the callback information with the symbol name and value + describing the function or variable in which ADDR may be found. + This will call either CALLBACK or ERROR_CALLBACK exactly once. + This returns 1 on success, 0 on failure. This function requires + the symbol table but does not require the debug info. Note that if + the symbol table is present but ADDR could not be found in the + table, CALLBACK will be called with a NULL SYMNAME argument. + Returns 1 on success, 0 on error. */ + +extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, + void *data); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif + +#endif diff --git a/src/3rdparty/libbacktrace/libbacktrace/config.h b/src/3rdparty/libbacktrace/libbacktrace/config.h new file mode 100644 index 00000000..c7a9e18c --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/config.h @@ -0,0 +1,9 @@ +#define BACKTRACE_ELF_SIZE __WORDSIZE +#define HAVE_DECL_STRNLEN 1 +#define HAVE_DL_ITERATE_PHDR 1 +#define HAVE_FCNTL 1 +// #define HAVE_GETEXECNAME 1 +#define HAVE_GETIPINFO 1 +#define HAVE_SYNC_FUNCTIONS 1 +#define HAVE_LIBDWARF_DWARF_H 1 + diff --git a/src/3rdparty/libbacktrace/libbacktrace/dwarf.c b/src/3rdparty/libbacktrace/libbacktrace/dwarf.c new file mode 100644 index 00000000..af79dfe5 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/dwarf.c @@ -0,0 +1,4280 @@ +/* dwarf.c -- Get file/line information from DWARF for backtraces. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include + +#include "filenames.h" + +#include "backtrace.h" +#include "internal.h" + +/* DWARF constants. */ + +enum dwarf_tag { + DW_TAG_entry_point = 0x3, + DW_TAG_compile_unit = 0x11, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_subprogram = 0x2e, +}; + +enum dwarf_form { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20, + DW_FORM_strx = 0x1a, + DW_FORM_addrx = 0x1b, + DW_FORM_ref_sup4 = 0x1c, + DW_FORM_strp_sup = 0x1d, + DW_FORM_data16 = 0x1e, + DW_FORM_line_strp = 0x1f, + DW_FORM_implicit_const = 0x21, + DW_FORM_loclistx = 0x22, + DW_FORM_rnglistx = 0x23, + DW_FORM_ref_sup8 = 0x24, + DW_FORM_strx1 = 0x25, + DW_FORM_strx2 = 0x26, + DW_FORM_strx3 = 0x27, + DW_FORM_strx4 = 0x28, + DW_FORM_addrx1 = 0x29, + DW_FORM_addrx2 = 0x2a, + DW_FORM_addrx3 = 0x2b, + DW_FORM_addrx4 = 0x2c, + DW_FORM_GNU_addr_index = 0x1f01, + DW_FORM_GNU_str_index = 0x1f02, + DW_FORM_GNU_ref_alt = 0x1f20, + DW_FORM_GNU_strp_alt = 0x1f21 +}; + +enum dwarf_attribute { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_bit_stride = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_byte_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_binary_scale = 0x5b, + DW_AT_decimal_scale = 0x5c, + DW_AT_small = 0x5d, + DW_AT_decimal_sign = 0x5e, + DW_AT_digit_count = 0x5f, + DW_AT_picture_string = 0x60, + DW_AT_mutable = 0x61, + DW_AT_threads_scaled = 0x62, + DW_AT_explicit = 0x63, + DW_AT_object_pointer = 0x64, + DW_AT_endianity = 0x65, + DW_AT_elemental = 0x66, + DW_AT_pure = 0x67, + DW_AT_recursive = 0x68, + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, + DW_AT_enum_class = 0x6d, + DW_AT_linkage_name = 0x6e, + DW_AT_string_length_bit_size = 0x6f, + DW_AT_string_length_byte_size = 0x70, + DW_AT_rank = 0x71, + DW_AT_str_offsets_base = 0x72, + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, + DW_AT_dwo_name = 0x76, + DW_AT_reference = 0x77, + DW_AT_rvalue_reference = 0x78, + DW_AT_macros = 0x79, + DW_AT_call_all_calls = 0x7a, + DW_AT_call_all_source_calls = 0x7b, + DW_AT_call_all_tail_calls = 0x7c, + DW_AT_call_return_pc = 0x7d, + DW_AT_call_value = 0x7e, + DW_AT_call_origin = 0x7f, + DW_AT_call_parameter = 0x80, + DW_AT_call_pc = 0x81, + DW_AT_call_tail_call = 0x82, + DW_AT_call_target = 0x83, + DW_AT_call_target_clobbered = 0x84, + DW_AT_call_data_location = 0x85, + DW_AT_call_data_value = 0x86, + DW_AT_noreturn = 0x87, + DW_AT_alignment = 0x88, + DW_AT_export_symbols = 0x89, + DW_AT_deleted = 0x8a, + DW_AT_defaulted = 0x8b, + DW_AT_loclists_base = 0x8c, + DW_AT_lo_user = 0x2000, + DW_AT_hi_user = 0x3fff, + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_HP_block_index = 0x2000, + DW_AT_HP_unmodifiable = 0x2001, + DW_AT_HP_prologue = 0x2005, + DW_AT_HP_epilogue = 0x2008, + DW_AT_HP_actuals_stmt_list = 0x2010, + DW_AT_HP_proc_per_section = 0x2011, + DW_AT_HP_raw_data_ptr = 0x2012, + DW_AT_HP_pass_by_reference = 0x2013, + DW_AT_HP_opt_level = 0x2014, + DW_AT_HP_prof_version_id = 0x2015, + DW_AT_HP_opt_flags = 0x2016, + DW_AT_HP_cold_region_low_pc = 0x2017, + DW_AT_HP_cold_region_high_pc = 0x2018, + DW_AT_HP_all_variables_modifiable = 0x2019, + DW_AT_HP_linkage_name = 0x201a, + DW_AT_HP_prof_flags = 0x201b, + DW_AT_HP_unit_name = 0x201f, + DW_AT_HP_unit_size = 0x2020, + DW_AT_HP_widened_byte_size = 0x2021, + DW_AT_HP_definition_points = 0x2022, + DW_AT_HP_default_location = 0x2023, + DW_AT_HP_is_result_param = 0x2029, + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + DW_AT_GNU_guarded_by = 0x2108, + DW_AT_GNU_pt_guarded_by = 0x2109, + DW_AT_GNU_guarded = 0x210a, + DW_AT_GNU_pt_guarded = 0x210b, + DW_AT_GNU_locks_excluded = 0x210c, + DW_AT_GNU_exclusive_locks_required = 0x210d, + DW_AT_GNU_shared_locks_required = 0x210e, + DW_AT_GNU_odr_signature = 0x210f, + DW_AT_GNU_template_name = 0x2110, + DW_AT_GNU_call_site_value = 0x2111, + DW_AT_GNU_call_site_data_value = 0x2112, + DW_AT_GNU_call_site_target = 0x2113, + DW_AT_GNU_call_site_target_clobbered = 0x2114, + DW_AT_GNU_tail_call = 0x2115, + DW_AT_GNU_all_tail_call_sites = 0x2116, + DW_AT_GNU_all_call_sites = 0x2117, + DW_AT_GNU_all_source_call_sites = 0x2118, + DW_AT_GNU_macros = 0x2119, + DW_AT_GNU_deleted = 0x211a, + DW_AT_GNU_dwo_name = 0x2130, + DW_AT_GNU_dwo_id = 0x2131, + DW_AT_GNU_ranges_base = 0x2132, + DW_AT_GNU_addr_base = 0x2133, + DW_AT_GNU_pubnames = 0x2134, + DW_AT_GNU_pubtypes = 0x2135, + DW_AT_GNU_discriminator = 0x2136, + DW_AT_GNU_locviews = 0x2137, + DW_AT_GNU_entry_view = 0x2138, + DW_AT_VMS_rtnbeg_pd_address = 0x2201, + DW_AT_use_GNAT_descriptive_type = 0x2301, + DW_AT_GNAT_descriptive_type = 0x2302, + DW_AT_GNU_numerator = 0x2303, + DW_AT_GNU_denominator = 0x2304, + DW_AT_GNU_bias = 0x2305, + DW_AT_upc_threads_scaled = 0x3210, + DW_AT_PGI_lbase = 0x3a00, + DW_AT_PGI_soffset = 0x3a01, + DW_AT_PGI_lstride = 0x3a02, + DW_AT_APPLE_optimized = 0x3fe1, + DW_AT_APPLE_flags = 0x3fe2, + DW_AT_APPLE_isa = 0x3fe3, + DW_AT_APPLE_block = 0x3fe4, + DW_AT_APPLE_major_runtime_vers = 0x3fe5, + DW_AT_APPLE_runtime_class = 0x3fe6, + DW_AT_APPLE_omit_frame_ptr = 0x3fe7, + DW_AT_APPLE_property_name = 0x3fe8, + DW_AT_APPLE_property_getter = 0x3fe9, + DW_AT_APPLE_property_setter = 0x3fea, + DW_AT_APPLE_property_attribute = 0x3feb, + DW_AT_APPLE_objc_complete_type = 0x3fec, + DW_AT_APPLE_property = 0x3fed +}; + +enum dwarf_line_number_op { + DW_LNS_extended_op = 0x0, + DW_LNS_copy = 0x1, + DW_LNS_advance_pc = 0x2, + DW_LNS_advance_line = 0x3, + DW_LNS_set_file = 0x4, + DW_LNS_set_column = 0x5, + DW_LNS_negate_stmt = 0x6, + DW_LNS_set_basic_block = 0x7, + DW_LNS_const_add_pc = 0x8, + DW_LNS_fixed_advance_pc = 0x9, + DW_LNS_set_prologue_end = 0xa, + DW_LNS_set_epilogue_begin = 0xb, + DW_LNS_set_isa = 0xc, +}; + +enum dwarf_extended_line_number_op { + DW_LNE_end_sequence = 0x1, + DW_LNE_set_address = 0x2, + DW_LNE_define_file = 0x3, + DW_LNE_set_discriminator = 0x4, +}; + +enum dwarf_line_number_content_type { + DW_LNCT_path = 0x1, + DW_LNCT_directory_index = 0x2, + DW_LNCT_timestamp = 0x3, + DW_LNCT_size = 0x4, + DW_LNCT_MD5 = 0x5, + DW_LNCT_lo_user = 0x2000, + DW_LNCT_hi_user = 0x3fff +}; + +enum dwarf_range_list_entry { + DW_RLE_end_of_list = 0x00, + DW_RLE_base_addressx = 0x01, + DW_RLE_startx_endx = 0x02, + DW_RLE_startx_length = 0x03, + DW_RLE_offset_pair = 0x04, + DW_RLE_base_address = 0x05, + DW_RLE_start_end = 0x06, + DW_RLE_start_length = 0x07 +}; + +enum dwarf_unit_type { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff +}; + +#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN + +/* If strnlen is not declared, provide our own version. */ + +static size_t +xstrnlen (const char *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen; ++i) + if (s[i] == '\0') + break; + return i; +} + +#define strnlen xstrnlen + +#endif + +/* A buffer to read DWARF info. */ + +struct dwarf_buf +{ + /* Buffer name for error messages. */ + const char *name; + /* Start of the buffer. */ + const unsigned char *start; + /* Next byte to read. */ + const unsigned char *buf; + /* The number of bytes remaining. */ + size_t left; + /* Whether the data is big-endian. */ + int is_bigendian; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data for error_callback. */ + void *data; + /* Non-zero if we've reported an underflow error. */ + int reported_underflow; +}; + +/* A single attribute in a DWARF abbreviation. */ + +struct attr +{ + /* The attribute name. */ + enum dwarf_attribute name; + /* The attribute form. */ + enum dwarf_form form; + /* The attribute value, for DW_FORM_implicit_const. */ + int64_t val; +}; + +/* A single DWARF abbreviation. */ + +struct abbrev +{ + /* The abbrev code--the number used to refer to the abbrev. */ + uint64_t code; + /* The entry tag. */ + enum dwarf_tag tag; + /* Non-zero if this abbrev has child entries. */ + int has_children; + /* The number of attributes. */ + size_t num_attrs; + /* The attributes. */ + struct attr *attrs; +}; + +/* The DWARF abbreviations for a compilation unit. This structure + only exists while reading the compilation unit. Most DWARF readers + seem to a hash table to map abbrev ID's to abbrev entries. + However, we primarily care about GCC, and GCC simply issues ID's in + numerical order starting at 1. So we simply keep a sorted vector, + and try to just look up the code. */ + +struct abbrevs +{ + /* The number of abbrevs in the vector. */ + size_t num_abbrevs; + /* The abbrevs, sorted by the code field. */ + struct abbrev *abbrevs; +}; + +/* The different kinds of attribute values. */ + +enum attr_val_encoding +{ + /* No attribute value. */ + ATTR_VAL_NONE, + /* An address. */ + ATTR_VAL_ADDRESS, + /* An index into the .debug_addr section, whose value is relative to + * the DW_AT_addr_base attribute of the compilation unit. */ + ATTR_VAL_ADDRESS_INDEX, + /* A unsigned integer. */ + ATTR_VAL_UINT, + /* A sigd integer. */ + ATTR_VAL_SINT, + /* A string. */ + ATTR_VAL_STRING, + /* An index into the .debug_str_offsets section. */ + ATTR_VAL_STRING_INDEX, + /* An offset to other data in the containing unit. */ + ATTR_VAL_REF_UNIT, + /* An offset to other data within the .debug_info section. */ + ATTR_VAL_REF_INFO, + /* An offset to other data within the alt .debug_info section. */ + ATTR_VAL_REF_ALT_INFO, + /* An offset to data in some other section. */ + ATTR_VAL_REF_SECTION, + /* A type signature. */ + ATTR_VAL_REF_TYPE, + /* An index into the .debug_rnglists section. */ + ATTR_VAL_RNGLISTS_INDEX, + /* A block of data (not represented). */ + ATTR_VAL_BLOCK, + /* An expression (not represented). */ + ATTR_VAL_EXPR, +}; + +/* An attribute value. */ + +struct attr_val +{ + /* How the value is stored in the field u. */ + enum attr_val_encoding encoding; + union + { + /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */ + uint64_t uint; + /* ATTR_VAL_SINT. */ + int64_t sint; + /* ATTR_VAL_STRING. */ + const char *string; + /* ATTR_VAL_BLOCK not stored. */ + } u; +}; + +/* The line number program header. */ + +struct line_header +{ + /* The version of the line number information. */ + int version; + /* Address size. */ + int addrsize; + /* The minimum instruction length. */ + unsigned int min_insn_len; + /* The maximum number of ops per instruction. */ + unsigned int max_ops_per_insn; + /* The line base for special opcodes. */ + int line_base; + /* The line range for special opcodes. */ + unsigned int line_range; + /* The opcode base--the first special opcode. */ + unsigned int opcode_base; + /* Opcode lengths, indexed by opcode - 1. */ + const unsigned char *opcode_lengths; + /* The number of directory entries. */ + size_t dirs_count; + /* The directory entries. */ + const char **dirs; + /* The number of filenames. */ + size_t filenames_count; + /* The filenames. */ + const char **filenames; +}; + +/* A format description from a line header. */ + +struct line_header_format +{ + int lnct; /* LNCT code. */ + enum dwarf_form form; /* Form of entry data. */ +}; + +/* Map a single PC value to a file/line. We will keep a vector of + these sorted by PC value. Each file/line will be correct from the + PC up to the PC of the next entry if there is one. We allocate one + extra entry at the end so that we can use bsearch. */ + +struct line +{ + /* PC. */ + uintptr_t pc; + /* File name. Many entries in the array are expected to point to + the same file name. */ + const char *filename; + /* Line number. */ + int lineno; + /* Index of the object in the original array read from the DWARF + section, before it has been sorted. The index makes it possible + to use Quicksort and maintain stability. */ + int idx; +}; + +/* A growable vector of line number information. This is used while + reading the line numbers. */ + +struct line_vector +{ + /* Memory. This is an array of struct line. */ + struct backtrace_vector vec; + /* Number of valid mappings. */ + size_t count; +}; + +/* A function described in the debug info. */ + +struct function +{ + /* The name of the function. */ + const char *name; + /* If this is an inlined function, the filename of the call + site. */ + const char *caller_filename; + /* If this is an inlined function, the line number of the call + site. */ + int caller_lineno; + /* Map PC ranges to inlined functions. */ + struct function_addrs *function_addrs; + size_t function_addrs_count; +}; + +/* An address range for a function. This maps a PC value to a + specific function. */ + +struct function_addrs +{ + /* Range is LOW <= PC < HIGH. */ + uint64_t low; + uint64_t high; + /* Function for this address range. */ + struct function *function; +}; + +/* A growable vector of function address ranges. */ + +struct function_vector +{ + /* Memory. This is an array of struct function_addrs. */ + struct backtrace_vector vec; + /* Number of address ranges present. */ + size_t count; +}; + +/* A DWARF compilation unit. This only holds the information we need + to map a PC to a file and line. */ + +struct unit +{ + /* The first entry for this compilation unit. */ + const unsigned char *unit_data; + /* The length of the data for this compilation unit. */ + size_t unit_data_len; + /* The offset of UNIT_DATA from the start of the information for + this compilation unit. */ + size_t unit_data_offset; + /* Offset of the start of the compilation unit from the start of the + .debug_info section. */ + size_t low_offset; + /* Offset of the end of the compilation unit from the start of the + .debug_info section. */ + size_t high_offset; + /* DWARF version. */ + int version; + /* Whether unit is DWARF64. */ + int is_dwarf64; + /* Address size. */ + int addrsize; + /* Offset into line number information. */ + off_t lineoff; + /* Offset of compilation unit in .debug_str_offsets. */ + uint64_t str_offsets_base; + /* Offset of compilation unit in .debug_addr. */ + uint64_t addr_base; + /* Offset of compilation unit in .debug_rnglists. */ + uint64_t rnglists_base; + /* Primary source file. */ + const char *filename; + /* Compilation command working directory. */ + const char *comp_dir; + /* Absolute file name, only set if needed. */ + const char *abs_filename; + /* The abbreviations for this unit. */ + struct abbrevs abbrevs; + + /* The fields above this point are read in during initialization and + may be accessed freely. The fields below this point are read in + as needed, and therefore require care, as different threads may + try to initialize them simultaneously. */ + + /* PC to line number mapping. This is NULL if the values have not + been read. This is (struct line *) -1 if there was an error + reading the values. */ + struct line *lines; + /* Number of entries in lines. */ + size_t lines_count; + /* PC ranges to function. */ + struct function_addrs *function_addrs; + size_t function_addrs_count; +}; + +/* An address range for a compilation unit. This maps a PC value to a + specific compilation unit. Note that we invert the representation + in DWARF: instead of listing the units and attaching a list of + ranges, we list the ranges and have each one point to the unit. + This lets us do a binary search to find the unit. */ + +struct unit_addrs +{ + /* Range is LOW <= PC < HIGH. */ + uint64_t low; + uint64_t high; + /* Compilation unit for this address range. */ + struct unit *u; +}; + +/* A growable vector of compilation unit address ranges. */ + +struct unit_addrs_vector +{ + /* Memory. This is an array of struct unit_addrs. */ + struct backtrace_vector vec; + /* Number of address ranges present. */ + size_t count; +}; + +/* A growable vector of compilation unit pointer. */ + +struct unit_vector +{ + struct backtrace_vector vec; + size_t count; +}; + +/* The information we need to map a PC to a file and line. */ + +struct dwarf_data +{ + /* The data for the next file we know about. */ + struct dwarf_data *next; + /* The data for .gnu_debugaltlink. */ + struct dwarf_data *altlink; + /* The base address for this file. */ + uintptr_t base_address; + /* A sorted list of address ranges. */ + struct unit_addrs *addrs; + /* Number of address ranges in list. */ + size_t addrs_count; + /* A sorted list of units. */ + struct unit **units; + /* Number of units in the list. */ + size_t units_count; + /* The unparsed DWARF debug data. */ + struct dwarf_sections dwarf_sections; + /* Whether the data is big-endian or not. */ + int is_bigendian; + /* A vector used for function addresses. We keep this here so that + we can grow the vector as we read more functions. */ + struct function_vector fvec; +}; + +/* Report an error for a DWARF buffer. */ + +static void +dwarf_buf_error (struct dwarf_buf *buf, const char *msg) +{ + char b[200]; + + snprintf (b, sizeof b, "%s in %s at %d", + msg, buf->name, (int) (buf->buf - buf->start)); + buf->error_callback (buf->data, b, 0); +} + +/* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on + error. */ + +static int +require (struct dwarf_buf *buf, size_t count) +{ + if (buf->left >= count) + return 1; + + if (!buf->reported_underflow) + { + dwarf_buf_error (buf, "DWARF underflow"); + buf->reported_underflow = 1; + } + + return 0; +} + +/* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on + error. */ + +static int +advance (struct dwarf_buf *buf, size_t count) +{ + if (!require (buf, count)) + return 0; + buf->buf += count; + buf->left -= count; + return 1; +} + +/* Read one zero-terminated string from BUF and advance past the string. */ + +static const char * +read_string (struct dwarf_buf *buf) +{ + const char *p = (const char *)buf->buf; + size_t len = strnlen (p, buf->left); + + /* - If len == left, we ran out of buffer before finding the zero terminator. + Generate an error by advancing len + 1. + - If len < left, advance by len + 1 to skip past the zero terminator. */ + size_t count = len + 1; + + if (!advance (buf, count)) + return NULL; + + return p; +} + +/* Read one byte from BUF and advance 1 byte. */ + +static unsigned char +read_byte (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 1)) + return 0; + return p[0]; +} + +/* Read a signed char from BUF and advance 1 byte. */ + +static signed char +read_sbyte (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 1)) + return 0; + return (*p ^ 0x80) - 0x80; +} + +/* Read a uint16 from BUF and advance 2 bytes. */ + +static uint16_t +read_uint16 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 2)) + return 0; + if (buf->is_bigendian) + return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; + else + return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; +} + +/* Read a 24 bit value from BUF and advance 3 bytes. */ + +static uint32_t +read_uint24 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 3)) + return 0; + if (buf->is_bigendian) + return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8) + | (uint32_t) p[2]); + else + return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8) + | (uint32_t) p[0]); +} + +/* Read a uint32 from BUF and advance 4 bytes. */ + +static uint32_t +read_uint32 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 4)) + return 0; + if (buf->is_bigendian) + return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) + | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); + else + return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) + | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); +} + +/* Read a uint64 from BUF and advance 8 bytes. */ + +static uint64_t +read_uint64 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 8)) + return 0; + if (buf->is_bigendian) + return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48) + | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32) + | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16) + | ((uint64_t) p[6] << 8) | (uint64_t) p[7]); + else + return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) + | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) + | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) + | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); +} + +/* Read an offset from BUF and advance the appropriate number of + bytes. */ + +static uint64_t +read_offset (struct dwarf_buf *buf, int is_dwarf64) +{ + if (is_dwarf64) + return read_uint64 (buf); + else + return read_uint32 (buf); +} + +/* Read an address from BUF and advance the appropriate number of + bytes. */ + +static uint64_t +read_address (struct dwarf_buf *buf, int addrsize) +{ + switch (addrsize) + { + case 1: + return read_byte (buf); + case 2: + return read_uint16 (buf); + case 4: + return read_uint32 (buf); + case 8: + return read_uint64 (buf); + default: + dwarf_buf_error (buf, "unrecognized address size"); + return 0; + } +} + +/* Return whether a value is the highest possible address, given the + address size. */ + +static int +is_highest_address (uint64_t address, int addrsize) +{ + switch (addrsize) + { + case 1: + return address == (unsigned char) -1; + case 2: + return address == (uint16_t) -1; + case 4: + return address == (uint32_t) -1; + case 8: + return address == (uint64_t) -1; + default: + return 0; + } +} + +/* Read an unsigned LEB128 number. */ + +static uint64_t +read_uleb128 (struct dwarf_buf *buf) +{ + uint64_t ret; + unsigned int shift; + int overflow; + unsigned char b; + + ret = 0; + shift = 0; + overflow = 0; + do + { + const unsigned char *p; + + p = buf->buf; + if (!advance (buf, 1)) + return 0; + b = *p; + if (shift < 64) + ret |= ((uint64_t) (b & 0x7f)) << shift; + else if (!overflow) + { + dwarf_buf_error (buf, "LEB128 overflows uint64_t"); + overflow = 1; + } + shift += 7; + } + while ((b & 0x80) != 0); + + return ret; +} + +/* Read a signed LEB128 number. */ + +static int64_t +read_sleb128 (struct dwarf_buf *buf) +{ + uint64_t val; + unsigned int shift; + int overflow; + unsigned char b; + + val = 0; + shift = 0; + overflow = 0; + do + { + const unsigned char *p; + + p = buf->buf; + if (!advance (buf, 1)) + return 0; + b = *p; + if (shift < 64) + val |= ((uint64_t) (b & 0x7f)) << shift; + else if (!overflow) + { + dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); + overflow = 1; + } + shift += 7; + } + while ((b & 0x80) != 0); + + if ((b & 0x40) != 0 && shift < 64) + val |= ((uint64_t) -1) << shift; + + return (int64_t) val; +} + +/* Return the length of an LEB128 number. */ + +static size_t +leb128_len (const unsigned char *p) +{ + size_t ret; + + ret = 1; + while ((*p & 0x80) != 0) + { + ++p; + ++ret; + } + return ret; +} + +/* Read initial_length from BUF and advance the appropriate number of bytes. */ + +static uint64_t +read_initial_length (struct dwarf_buf *buf, int *is_dwarf64) +{ + uint64_t len; + + len = read_uint32 (buf); + if (len == 0xffffffff) + { + len = read_uint64 (buf); + *is_dwarf64 = 1; + } + else + *is_dwarf64 = 0; + + return len; +} + +/* Free an abbreviations structure. */ + +static void +free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, + backtrace_error_callback error_callback, void *data) +{ + size_t i; + + for (i = 0; i < abbrevs->num_abbrevs; ++i) + backtrace_free (state, abbrevs->abbrevs[i].attrs, + abbrevs->abbrevs[i].num_attrs * sizeof (struct attr), + error_callback, data); + backtrace_free (state, abbrevs->abbrevs, + abbrevs->num_abbrevs * sizeof (struct abbrev), + error_callback, data); + abbrevs->num_abbrevs = 0; + abbrevs->abbrevs = NULL; +} + +/* Read an attribute value. Returns 1 on success, 0 on failure. If + the value can be represented as a uint64_t, sets *VAL and sets + *IS_VALID to 1. We don't try to store the value of other attribute + forms, because we don't care about them. */ + +static int +read_attribute (enum dwarf_form form, uint64_t implicit_val, + struct dwarf_buf *buf, int is_dwarf64, int version, + int addrsize, const struct dwarf_sections *dwarf_sections, + struct dwarf_data *altlink, struct attr_val *val) +{ + /* Avoid warnings about val.u.FIELD may be used uninitialized if + this function is inlined. The warnings aren't valid but can + occur because the different fields are set and used + conditionally. */ + memset (val, 0, sizeof *val); + + switch (form) + { + case DW_FORM_addr: + val->encoding = ATTR_VAL_ADDRESS; + val->u.uint = read_address (buf, addrsize); + return 1; + case DW_FORM_block2: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uint16 (buf)); + case DW_FORM_block4: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uint32 (buf)); + case DW_FORM_data2: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint16 (buf); + return 1; + case DW_FORM_data4: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint32 (buf); + return 1; + case DW_FORM_data8: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_data16: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, 16); + case DW_FORM_string: + val->encoding = ATTR_VAL_STRING; + val->u.string = read_string (buf); + return val->u.string == NULL ? 0 : 1; + case DW_FORM_block: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uleb128 (buf)); + case DW_FORM_block1: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_byte (buf)); + case DW_FORM_data1: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_flag: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_sdata: + val->encoding = ATTR_VAL_SINT; + val->u.sint = read_sleb128 (buf); + return 1; + case DW_FORM_strp: + { + uint64_t offset; + + offset = read_offset (buf, is_dwarf64); + if (offset >= dwarf_sections->size[DEBUG_STR]) + { + dwarf_buf_error (buf, "DW_FORM_strp out of range"); + return 0; + } + val->encoding = ATTR_VAL_STRING; + val->u.string = + (const char *) dwarf_sections->data[DEBUG_STR] + offset; + return 1; + } + case DW_FORM_line_strp: + { + uint64_t offset; + + offset = read_offset (buf, is_dwarf64); + if (offset >= dwarf_sections->size[DEBUG_LINE_STR]) + { + dwarf_buf_error (buf, "DW_FORM_line_strp out of range"); + return 0; + } + val->encoding = ATTR_VAL_STRING; + val->u.string = + (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset; + return 1; + } + case DW_FORM_udata: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_ref_addr: + val->encoding = ATTR_VAL_REF_INFO; + if (version == 2) + val->u.uint = read_address (buf, addrsize); + else + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + case DW_FORM_ref1: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_ref2: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint16 (buf); + return 1; + case DW_FORM_ref4: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint32 (buf); + return 1; + case DW_FORM_ref8: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_ref_udata: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_indirect: + { + uint64_t form; + + form = read_uleb128 (buf); + if (form == DW_FORM_implicit_const) + { + dwarf_buf_error (buf, + "DW_FORM_indirect to DW_FORM_implicit_const"); + return 0; + } + return read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64, + version, addrsize, dwarf_sections, altlink, + val); + } + case DW_FORM_sec_offset: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + case DW_FORM_exprloc: + val->encoding = ATTR_VAL_EXPR; + return advance (buf, read_uleb128 (buf)); + case DW_FORM_flag_present: + val->encoding = ATTR_VAL_UINT; + val->u.uint = 1; + return 1; + case DW_FORM_ref_sig8: + val->encoding = ATTR_VAL_REF_TYPE; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2: + case DW_FORM_strx3: case DW_FORM_strx4: + { + uint64_t offset; + + switch (form) + { + case DW_FORM_strx: + offset = read_uleb128 (buf); + break; + case DW_FORM_strx1: + offset = read_byte (buf); + break; + case DW_FORM_strx2: + offset = read_uint16 (buf); + break; + case DW_FORM_strx3: + offset = read_uint24 (buf); + break; + case DW_FORM_strx4: + offset = read_uint32 (buf); + break; + default: + /* This case can't happen. */ + return 0; + } + val->encoding = ATTR_VAL_STRING_INDEX; + val->u.uint = offset; + return 1; + } + case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2: + case DW_FORM_addrx3: case DW_FORM_addrx4: + { + uint64_t offset; + + switch (form) + { + case DW_FORM_addrx: + offset = read_uleb128 (buf); + break; + case DW_FORM_addrx1: + offset = read_byte (buf); + break; + case DW_FORM_addrx2: + offset = read_uint16 (buf); + break; + case DW_FORM_addrx3: + offset = read_uint24 (buf); + break; + case DW_FORM_addrx4: + offset = read_uint32 (buf); + break; + default: + /* This case can't happen. */ + return 0; + } + val->encoding = ATTR_VAL_ADDRESS_INDEX; + val->u.uint = offset; + return 1; + } + case DW_FORM_ref_sup4: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uint32 (buf); + return 1; + case DW_FORM_ref_sup8: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_implicit_const: + val->encoding = ATTR_VAL_UINT; + val->u.uint = implicit_val; + return 1; + case DW_FORM_loclistx: + /* We don't distinguish this from DW_FORM_sec_offset. It + * shouldn't matter since we don't care about loclists. */ + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_rnglistx: + val->encoding = ATTR_VAL_RNGLISTS_INDEX; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_GNU_addr_index: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_GNU_str_index: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_GNU_ref_alt: + val->u.uint = read_offset (buf, is_dwarf64); + if (altlink == NULL) + { + val->encoding = ATTR_VAL_NONE; + return 1; + } + val->encoding = ATTR_VAL_REF_ALT_INFO; + return 1; + case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt: + { + uint64_t offset; + + offset = read_offset (buf, is_dwarf64); + if (altlink == NULL) + { + val->encoding = ATTR_VAL_NONE; + return 1; + } + if (offset >= altlink->dwarf_sections.size[DEBUG_STR]) + { + dwarf_buf_error (buf, "DW_FORM_strp_sup out of range"); + return 0; + } + val->encoding = ATTR_VAL_STRING; + val->u.string = + (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset; + return 1; + } + default: + dwarf_buf_error (buf, "unrecognized DWARF form"); + return 0; + } +} + +/* If we can determine the value of a string attribute, set *STRING to + point to the string. Return 1 on success, 0 on error. If we don't + know the value, we consider that a success, and we don't change + *STRING. An error is only reported for some sort of out of range + offset. */ + +static int +resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64, + int is_bigendian, uint64_t str_offsets_base, + const struct attr_val *val, + backtrace_error_callback error_callback, void *data, + const char **string) +{ + switch (val->encoding) + { + case ATTR_VAL_STRING: + *string = val->u.string; + return 1; + + case ATTR_VAL_STRING_INDEX: + { + uint64_t offset; + struct dwarf_buf offset_buf; + + offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base; + if (offset + (is_dwarf64 ? 8 : 4) + >= dwarf_sections->size[DEBUG_STR_OFFSETS]) + { + error_callback (data, "DW_FORM_strx value out of range", 0); + return 0; + } + + offset_buf.name = ".debug_str_offsets"; + offset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS]; + offset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset; + offset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset; + offset_buf.is_bigendian = is_bigendian; + offset_buf.error_callback = error_callback; + offset_buf.data = data; + offset_buf.reported_underflow = 0; + + offset = read_offset (&offset_buf, is_dwarf64); + if (offset >= dwarf_sections->size[DEBUG_STR]) + { + dwarf_buf_error (&offset_buf, "DW_FORM_strx offset out of range"); + return 0; + } + *string = (const char *) dwarf_sections->data[DEBUG_STR] + offset; + return 1; + } + + default: + return 1; + } +} + +/* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX. + Return 1 on success, 0 on error. */ + +static int +resolve_addr_index (const struct dwarf_sections *dwarf_sections, + uint64_t addr_base, int addrsize, int is_bigendian, + uint64_t addr_index, + backtrace_error_callback error_callback, void *data, + uint64_t *address) +{ + uint64_t offset; + struct dwarf_buf addr_buf; + + offset = addr_index * addrsize + addr_base; + if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR]) + { + error_callback (data, "DW_FORM_addrx value out of range", 0); + return 0; + } + + addr_buf.name = ".debug_addr"; + addr_buf.start = dwarf_sections->data[DEBUG_ADDR]; + addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset; + addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset; + addr_buf.is_bigendian = is_bigendian; + addr_buf.error_callback = error_callback; + addr_buf.data = data; + addr_buf.reported_underflow = 0; + + *address = read_address (&addr_buf, addrsize); + return 1; +} + +/* Compare a unit offset against a unit for bsearch. */ + +static int +units_search (const void *vkey, const void *ventry) +{ + const size_t *key = (const size_t *) vkey; + const struct unit *entry = *((const struct unit *const *) ventry); + size_t offset; + + offset = *key; + if (offset < entry->low_offset) + return -1; + else if (offset >= entry->high_offset) + return 1; + else + return 0; +} + +/* Find a unit in PU containing OFFSET. */ + +static struct unit * +find_unit (struct unit **pu, size_t units_count, size_t offset) +{ + struct unit **u; + u = bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search); + return u == NULL ? NULL : *u; +} + +/* Compare function_addrs for qsort. When ranges are nested, make the + smallest one sort last. */ + +static int +function_addrs_compare (const void *v1, const void *v2) +{ + const struct function_addrs *a1 = (const struct function_addrs *) v1; + const struct function_addrs *a2 = (const struct function_addrs *) v2; + + if (a1->low < a2->low) + return -1; + if (a1->low > a2->low) + return 1; + if (a1->high < a2->high) + return 1; + if (a1->high > a2->high) + return -1; + return strcmp (a1->function->name, a2->function->name); +} + +/* Compare a PC against a function_addrs for bsearch. Note that if + there are multiple ranges containing PC, which one will be returned + is unpredictable. We compensate for that in dwarf_fileline. */ + +static int +function_addrs_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct function_addrs *entry = (const struct function_addrs *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->low) + return -1; + else if (pc >= entry->high) + return 1; + else + return 0; +} + +/* Add a new compilation unit address range to a vector. This is + called via add_ranges. Returns 1 on success, 0 on failure. */ + +static int +add_unit_addr (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, void *data, + void *pvec) +{ + struct unit *u = (struct unit *) rdata; + struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec; + struct unit_addrs *p; + + /* Try to merge with the last entry. */ + if (vec->count > 0) + { + p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); + if ((lowpc == p->high || lowpc == p->high + 1) + && u == p->u) + { + if (highpc > p->high) + p->high = highpc; + return 1; + } + } + + p = ((struct unit_addrs *) + backtrace_vector_grow (state, sizeof (struct unit_addrs), + error_callback, data, &vec->vec)); + if (p == NULL) + return 0; + + p->low = lowpc; + p->high = highpc; + p->u = u; + + ++vec->count; + + return 1; +} + +/* Compare unit_addrs for qsort. When ranges are nested, make the + smallest one sort last. */ + +static int +unit_addrs_compare (const void *v1, const void *v2) +{ + const struct unit_addrs *a1 = (const struct unit_addrs *) v1; + const struct unit_addrs *a2 = (const struct unit_addrs *) v2; + + if (a1->low < a2->low) + return -1; + if (a1->low > a2->low) + return 1; + if (a1->high < a2->high) + return 1; + if (a1->high > a2->high) + return -1; + if (a1->u->lineoff < a2->u->lineoff) + return -1; + if (a1->u->lineoff > a2->u->lineoff) + return 1; + return 0; +} + +/* Compare a PC against a unit_addrs for bsearch. Note that if there + are multiple ranges containing PC, which one will be returned is + unpredictable. We compensate for that in dwarf_fileline. */ + +static int +unit_addrs_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct unit_addrs *entry = (const struct unit_addrs *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->low) + return -1; + else if (pc >= entry->high) + return 1; + else + return 0; +} + +/* Sort the line vector by PC. We want a stable sort here to maintain + the order of lines for the same PC values. Since the sequence is + being sorted in place, their addresses cannot be relied on to + maintain stability. That is the purpose of the index member. */ + +static int +line_compare (const void *v1, const void *v2) +{ + const struct line *ln1 = (const struct line *) v1; + const struct line *ln2 = (const struct line *) v2; + + if (ln1->pc < ln2->pc) + return -1; + else if (ln1->pc > ln2->pc) + return 1; + else if (ln1->idx < ln2->idx) + return -1; + else if (ln1->idx > ln2->idx) + return 1; + else + return 0; +} + +/* Find a PC in a line vector. We always allocate an extra entry at + the end of the lines vector, so that this routine can safely look + at the next entry. Note that when there are multiple mappings for + the same PC value, this will return the last one. */ + +static int +line_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct line *entry = (const struct line *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->pc) + return -1; + else if (pc >= (entry + 1)->pc) + return 1; + else + return 0; +} + +/* Sort the abbrevs by the abbrev code. This function is passed to + both qsort and bsearch. */ + +static int +abbrev_compare (const void *v1, const void *v2) +{ + const struct abbrev *a1 = (const struct abbrev *) v1; + const struct abbrev *a2 = (const struct abbrev *) v2; + + if (a1->code < a2->code) + return -1; + else if (a1->code > a2->code) + return 1; + else + { + /* This really shouldn't happen. It means there are two + different abbrevs with the same code, and that means we don't + know which one lookup_abbrev should return. */ + return 0; + } +} + +/* Read the abbreviation table for a compilation unit. Returns 1 on + success, 0 on failure. */ + +static int +read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, + const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct abbrevs *abbrevs) +{ + struct dwarf_buf abbrev_buf; + struct dwarf_buf count_buf; + size_t num_abbrevs; + + abbrevs->num_abbrevs = 0; + abbrevs->abbrevs = NULL; + + if (abbrev_offset >= dwarf_abbrev_size) + { + error_callback (data, "abbrev offset out of range", 0); + return 0; + } + + abbrev_buf.name = ".debug_abbrev"; + abbrev_buf.start = dwarf_abbrev; + abbrev_buf.buf = dwarf_abbrev + abbrev_offset; + abbrev_buf.left = dwarf_abbrev_size - abbrev_offset; + abbrev_buf.is_bigendian = is_bigendian; + abbrev_buf.error_callback = error_callback; + abbrev_buf.data = data; + abbrev_buf.reported_underflow = 0; + + /* Count the number of abbrevs in this list. */ + + count_buf = abbrev_buf; + num_abbrevs = 0; + while (read_uleb128 (&count_buf) != 0) + { + if (count_buf.reported_underflow) + return 0; + ++num_abbrevs; + // Skip tag. + read_uleb128 (&count_buf); + // Skip has_children. + read_byte (&count_buf); + // Skip attributes. + while (read_uleb128 (&count_buf) != 0) + { + uint64_t form; + + form = read_uleb128 (&count_buf); + if ((enum dwarf_form) form == DW_FORM_implicit_const) + read_sleb128 (&count_buf); + } + // Skip form of last attribute. + read_uleb128 (&count_buf); + } + + if (count_buf.reported_underflow) + return 0; + + if (num_abbrevs == 0) + return 1; + + abbrevs->abbrevs = ((struct abbrev *) + backtrace_alloc (state, + num_abbrevs * sizeof (struct abbrev), + error_callback, data)); + if (abbrevs->abbrevs == NULL) + return 0; + abbrevs->num_abbrevs = num_abbrevs; + memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev)); + + num_abbrevs = 0; + while (1) + { + uint64_t code; + struct abbrev a; + size_t num_attrs; + struct attr *attrs; + + if (abbrev_buf.reported_underflow) + goto fail; + + code = read_uleb128 (&abbrev_buf); + if (code == 0) + break; + + a.code = code; + a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf); + a.has_children = read_byte (&abbrev_buf); + + count_buf = abbrev_buf; + num_attrs = 0; + while (read_uleb128 (&count_buf) != 0) + { + uint64_t form; + + ++num_attrs; + form = read_uleb128 (&count_buf); + if ((enum dwarf_form) form == DW_FORM_implicit_const) + read_sleb128 (&count_buf); + } + + if (num_attrs == 0) + { + attrs = NULL; + read_uleb128 (&abbrev_buf); + read_uleb128 (&abbrev_buf); + } + else + { + attrs = ((struct attr *) + backtrace_alloc (state, num_attrs * sizeof *attrs, + error_callback, data)); + if (attrs == NULL) + goto fail; + num_attrs = 0; + while (1) + { + uint64_t name; + uint64_t form; + + name = read_uleb128 (&abbrev_buf); + form = read_uleb128 (&abbrev_buf); + if (name == 0) + break; + attrs[num_attrs].name = (enum dwarf_attribute) name; + attrs[num_attrs].form = (enum dwarf_form) form; + if ((enum dwarf_form) form == DW_FORM_implicit_const) + attrs[num_attrs].val = read_sleb128 (&abbrev_buf); + else + attrs[num_attrs].val = 0; + ++num_attrs; + } + } + + a.num_attrs = num_attrs; + a.attrs = attrs; + + abbrevs->abbrevs[num_abbrevs] = a; + ++num_abbrevs; + } + + backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); + + return 1; + + fail: + free_abbrevs (state, abbrevs, error_callback, data); + return 0; +} + +/* Return the abbrev information for an abbrev code. */ + +static const struct abbrev * +lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, + backtrace_error_callback error_callback, void *data) +{ + struct abbrev key; + void *p; + + /* With GCC, where abbrevs are simply numbered in order, we should + be able to just look up the entry. */ + if (code - 1 < abbrevs->num_abbrevs + && abbrevs->abbrevs[code - 1].code == code) + return &abbrevs->abbrevs[code - 1]; + + /* Otherwise we have to search. */ + memset (&key, 0, sizeof key); + key.code = code; + p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); + if (p == NULL) + { + error_callback (data, "invalid abbreviation code", 0); + return NULL; + } + return (const struct abbrev *) p; +} + +/* This struct is used to gather address range information while + reading attributes. We use this while building a mapping from + address ranges to compilation units and then again while mapping + from address ranges to function entries. Normally either + lowpc/highpc is set or ranges is set. */ + +struct pcrange { + uint64_t lowpc; /* The low PC value. */ + int have_lowpc; /* Whether a low PC value was found. */ + int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */ + uint64_t highpc; /* The high PC value. */ + int have_highpc; /* Whether a high PC value was found. */ + int highpc_is_relative; /* Whether highpc is relative to lowpc. */ + int highpc_is_addr_index; /* Whether highpc is in .debug_addr. */ + uint64_t ranges; /* Offset in ranges section. */ + int have_ranges; /* Whether ranges is valid. */ + int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */ +}; + +/* Update PCRANGE from an attribute value. */ + +static void +update_pcrange (const struct attr* attr, const struct attr_val* val, + struct pcrange *pcrange) +{ + switch (attr->name) + { + case DW_AT_low_pc: + if (val->encoding == ATTR_VAL_ADDRESS) + { + pcrange->lowpc = val->u.uint; + pcrange->have_lowpc = 1; + } + else if (val->encoding == ATTR_VAL_ADDRESS_INDEX) + { + pcrange->lowpc = val->u.uint; + pcrange->have_lowpc = 1; + pcrange->lowpc_is_addr_index = 1; + } + break; + + case DW_AT_high_pc: + if (val->encoding == ATTR_VAL_ADDRESS) + { + pcrange->highpc = val->u.uint; + pcrange->have_highpc = 1; + } + else if (val->encoding == ATTR_VAL_UINT) + { + pcrange->highpc = val->u.uint; + pcrange->have_highpc = 1; + pcrange->highpc_is_relative = 1; + } + else if (val->encoding == ATTR_VAL_ADDRESS_INDEX) + { + pcrange->highpc = val->u.uint; + pcrange->have_highpc = 1; + pcrange->highpc_is_addr_index = 1; + } + break; + + case DW_AT_ranges: + if (val->encoding == ATTR_VAL_UINT + || val->encoding == ATTR_VAL_REF_SECTION) + { + pcrange->ranges = val->u.uint; + pcrange->have_ranges = 1; + } + else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX) + { + pcrange->ranges = val->u.uint; + pcrange->have_ranges = 1; + pcrange->ranges_is_index = 1; + } + break; + + default: + break; + } +} + +/* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on + error. */ + +static int +add_low_high_range (struct backtrace_state *state, + const struct dwarf_sections *dwarf_sections, + uintptr_t base_address, int is_bigendian, + struct unit *u, const struct pcrange *pcrange, + int (*add_range) (struct backtrace_state *state, + void *rdata, uint64_t lowpc, + uint64_t highpc, + backtrace_error_callback error_callback, + void *data, void *vec), + void *rdata, + backtrace_error_callback error_callback, void *data, + void *vec) +{ + uint64_t lowpc; + uint64_t highpc; + + lowpc = pcrange->lowpc; + if (pcrange->lowpc_is_addr_index) + { + if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize, + is_bigendian, lowpc, error_callback, data, + &lowpc)) + return 0; + } + + highpc = pcrange->highpc; + if (pcrange->highpc_is_addr_index) + { + if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize, + is_bigendian, highpc, error_callback, data, + &highpc)) + return 0; + } + if (pcrange->highpc_is_relative) + highpc += lowpc; + + /* Add in the base address of the module when recording PC values, + so that we can look up the PC directly. */ + lowpc += base_address; + highpc += base_address; + + return add_range (state, rdata, lowpc, highpc, error_callback, data, vec); +} + +/* Call ADD_RANGE for each range read from .debug_ranges, as used in + DWARF versions 2 through 4. */ + +static int +add_ranges_from_ranges ( + struct backtrace_state *state, + const struct dwarf_sections *dwarf_sections, + uintptr_t base_address, int is_bigendian, + struct unit *u, uint64_t base, + const struct pcrange *pcrange, + int (*add_range) (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, void *data, + void *vec), + void *rdata, + backtrace_error_callback error_callback, void *data, + void *vec) +{ + struct dwarf_buf ranges_buf; + + if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES]) + { + error_callback (data, "ranges offset out of range", 0); + return 0; + } + + ranges_buf.name = ".debug_ranges"; + ranges_buf.start = dwarf_sections->data[DEBUG_RANGES]; + ranges_buf.buf = dwarf_sections->data[DEBUG_RANGES] + pcrange->ranges; + ranges_buf.left = dwarf_sections->size[DEBUG_RANGES] - pcrange->ranges; + ranges_buf.is_bigendian = is_bigendian; + ranges_buf.error_callback = error_callback; + ranges_buf.data = data; + ranges_buf.reported_underflow = 0; + + while (1) + { + uint64_t low; + uint64_t high; + + if (ranges_buf.reported_underflow) + return 0; + + low = read_address (&ranges_buf, u->addrsize); + high = read_address (&ranges_buf, u->addrsize); + + if (low == 0 && high == 0) + break; + + if (is_highest_address (low, u->addrsize)) + base = high; + else + { + if (!add_range (state, rdata, + low + base + base_address, + high + base + base_address, + error_callback, data, vec)) + return 0; + } + } + + if (ranges_buf.reported_underflow) + return 0; + + return 1; +} + +/* Call ADD_RANGE for each range read from .debug_rnglists, as used in + DWARF version 5. */ + +static int +add_ranges_from_rnglists ( + struct backtrace_state *state, + const struct dwarf_sections *dwarf_sections, + uintptr_t base_address, int is_bigendian, + struct unit *u, uint64_t base, + const struct pcrange *pcrange, + int (*add_range) (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, void *data, + void *vec), + void *rdata, + backtrace_error_callback error_callback, void *data, + void *vec) +{ + uint64_t offset; + struct dwarf_buf rnglists_buf; + + if (!pcrange->ranges_is_index) + offset = pcrange->ranges; + else + offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4); + if (offset >= dwarf_sections->size[DEBUG_RNGLISTS]) + { + error_callback (data, "rnglists offset out of range", 0); + return 0; + } + + rnglists_buf.name = ".debug_rnglists"; + rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS]; + rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset; + rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset; + rnglists_buf.is_bigendian = is_bigendian; + rnglists_buf.error_callback = error_callback; + rnglists_buf.data = data; + rnglists_buf.reported_underflow = 0; + + if (pcrange->ranges_is_index) + { + offset = read_offset (&rnglists_buf, u->is_dwarf64); + offset += u->rnglists_base; + if (offset >= dwarf_sections->size[DEBUG_RNGLISTS]) + { + error_callback (data, "rnglists index offset out of range", 0); + return 0; + } + rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset; + rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset; + } + + while (1) + { + unsigned char rle; + + rle = read_byte (&rnglists_buf); + if (rle == DW_RLE_end_of_list) + break; + switch (rle) + { + case DW_RLE_base_addressx: + { + uint64_t index; + + index = read_uleb128 (&rnglists_buf); + if (!resolve_addr_index (dwarf_sections, u->addr_base, + u->addrsize, is_bigendian, index, + error_callback, data, &base)) + return 0; + } + break; + + case DW_RLE_startx_endx: + { + uint64_t index; + uint64_t low; + uint64_t high; + + index = read_uleb128 (&rnglists_buf); + if (!resolve_addr_index (dwarf_sections, u->addr_base, + u->addrsize, is_bigendian, index, + error_callback, data, &low)) + return 0; + index = read_uleb128 (&rnglists_buf); + if (!resolve_addr_index (dwarf_sections, u->addr_base, + u->addrsize, is_bigendian, index, + error_callback, data, &high)) + return 0; + if (!add_range (state, rdata, low + base_address, + high + base_address, error_callback, data, + vec)) + return 0; + } + break; + + case DW_RLE_startx_length: + { + uint64_t index; + uint64_t low; + uint64_t length; + + index = read_uleb128 (&rnglists_buf); + if (!resolve_addr_index (dwarf_sections, u->addr_base, + u->addrsize, is_bigendian, index, + error_callback, data, &low)) + return 0; + length = read_uleb128 (&rnglists_buf); + low += base_address; + if (!add_range (state, rdata, low, low + length, + error_callback, data, vec)) + return 0; + } + break; + + case DW_RLE_offset_pair: + { + uint64_t low; + uint64_t high; + + low = read_uleb128 (&rnglists_buf); + high = read_uleb128 (&rnglists_buf); + if (!add_range (state, rdata, low + base + base_address, + high + base + base_address, + error_callback, data, vec)) + return 0; + } + break; + + case DW_RLE_base_address: + base = read_address (&rnglists_buf, u->addrsize); + break; + + case DW_RLE_start_end: + { + uint64_t low; + uint64_t high; + + low = read_address (&rnglists_buf, u->addrsize); + high = read_address (&rnglists_buf, u->addrsize); + if (!add_range (state, rdata, low + base_address, + high + base_address, error_callback, data, + vec)) + return 0; + } + break; + + case DW_RLE_start_length: + { + uint64_t low; + uint64_t length; + + low = read_address (&rnglists_buf, u->addrsize); + length = read_uleb128 (&rnglists_buf); + low += base_address; + if (!add_range (state, rdata, low, low + length, + error_callback, data, vec)) + return 0; + } + break; + + default: + dwarf_buf_error (&rnglists_buf, "unrecognized DW_RLE value"); + return 0; + } + } + + if (rnglists_buf.reported_underflow) + return 0; + + return 1; +} + +/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is + passed to ADD_RANGE, and is either a struct unit * or a struct + function *. VEC is the vector we are adding ranges to, and is + either a struct unit_addrs_vector * or a struct function_vector *. + Returns 1 on success, 0 on error. */ + +static int +add_ranges (struct backtrace_state *state, + const struct dwarf_sections *dwarf_sections, + uintptr_t base_address, int is_bigendian, + struct unit *u, uint64_t base, const struct pcrange *pcrange, + int (*add_range) (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, + void *data, void *vec), + void *rdata, + backtrace_error_callback error_callback, void *data, + void *vec) +{ + if (pcrange->have_lowpc && pcrange->have_highpc) + return add_low_high_range (state, dwarf_sections, base_address, + is_bigendian, u, pcrange, add_range, rdata, + error_callback, data, vec); + + if (!pcrange->have_ranges) + { + /* Did not find any address ranges to add. */ + return 1; + } + + if (u->version < 5) + return add_ranges_from_ranges (state, dwarf_sections, base_address, + is_bigendian, u, base, pcrange, add_range, + rdata, error_callback, data, vec); + else + return add_ranges_from_rnglists (state, dwarf_sections, base_address, + is_bigendian, u, base, pcrange, add_range, + rdata, error_callback, data, vec); +} + +/* Find the address range covered by a compilation unit, reading from + UNIT_BUF and adding values to U. Returns 1 if all data could be + read, 0 if there is some error. */ + +static int +find_address_ranges (struct backtrace_state *state, uintptr_t base_address, + struct dwarf_buf *unit_buf, + const struct dwarf_sections *dwarf_sections, + int is_bigendian, struct dwarf_data *altlink, + backtrace_error_callback error_callback, void *data, + struct unit *u, struct unit_addrs_vector *addrs, + enum dwarf_tag *unit_tag) +{ + while (unit_buf->left > 0) + { + uint64_t code; + const struct abbrev *abbrev; + struct pcrange pcrange; + struct attr_val name_val; + int have_name_val; + struct attr_val comp_dir_val; + int have_comp_dir_val; + size_t i; + + code = read_uleb128 (unit_buf); + if (code == 0) + return 1; + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return 0; + + if (unit_tag != NULL) + *unit_tag = abbrev->tag; + + memset (&pcrange, 0, sizeof pcrange); + memset (&name_val, 0, sizeof name_val); + have_name_val = 0; + memset (&comp_dir_val, 0, sizeof comp_dir_val); + have_comp_dir_val = 0; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, + unit_buf, u->is_dwarf64, u->version, + u->addrsize, dwarf_sections, altlink, &val)) + return 0; + + switch (abbrev->attrs[i].name) + { + case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges: + update_pcrange (&abbrev->attrs[i], &val, &pcrange); + break; + + case DW_AT_stmt_list: + if (abbrev->tag == DW_TAG_compile_unit + && (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_SECTION)) + u->lineoff = val.u.uint; + break; + + case DW_AT_name: + if (abbrev->tag == DW_TAG_compile_unit) + { + name_val = val; + have_name_val = 1; + } + break; + + case DW_AT_comp_dir: + if (abbrev->tag == DW_TAG_compile_unit) + { + comp_dir_val = val; + have_comp_dir_val = 1; + } + break; + + case DW_AT_str_offsets_base: + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_REF_SECTION) + u->str_offsets_base = val.u.uint; + break; + + case DW_AT_addr_base: + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_REF_SECTION) + u->addr_base = val.u.uint; + break; + + case DW_AT_rnglists_base: + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_REF_SECTION) + u->rnglists_base = val.u.uint; + break; + + default: + break; + } + } + + // Resolve strings after we're sure that we have seen + // DW_AT_str_offsets_base. + if (have_name_val) + { + if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian, + u->str_offsets_base, &name_val, + error_callback, data, &u->filename)) + return 0; + } + if (have_comp_dir_val) + { + if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian, + u->str_offsets_base, &comp_dir_val, + error_callback, data, &u->comp_dir)) + return 0; + } + + if (abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_subprogram) + { + if (!add_ranges (state, dwarf_sections, base_address, + is_bigendian, u, pcrange.lowpc, &pcrange, + add_unit_addr, (void *) u, error_callback, data, + (void *) addrs)) + return 0; + + /* If we found the PC range in the DW_TAG_compile_unit, we + can stop now. */ + if (abbrev->tag == DW_TAG_compile_unit + && (pcrange.have_ranges + || (pcrange.have_lowpc && pcrange.have_highpc))) + return 1; + } + + if (abbrev->has_children) + { + if (!find_address_ranges (state, base_address, unit_buf, + dwarf_sections, is_bigendian, altlink, + error_callback, data, u, addrs, NULL)) + return 0; + } + } + + return 1; +} + +/* Build a mapping from address ranges to the compilation units where + the line number information for that range can be found. Returns 1 + on success, 0 on failure. */ + +static int +build_address_map (struct backtrace_state *state, uintptr_t base_address, + const struct dwarf_sections *dwarf_sections, + int is_bigendian, struct dwarf_data *altlink, + backtrace_error_callback error_callback, void *data, + struct unit_addrs_vector *addrs, + struct unit_vector *unit_vec) +{ + struct dwarf_buf info; + struct backtrace_vector units; + size_t units_count; + size_t i; + struct unit **pu; + size_t unit_offset = 0; + + memset (&addrs->vec, 0, sizeof addrs->vec); + memset (&unit_vec->vec, 0, sizeof unit_vec->vec); + addrs->count = 0; + unit_vec->count = 0; + + /* Read through the .debug_info section. FIXME: Should we use the + .debug_aranges section? gdb and addr2line don't use it, but I'm + not sure why. */ + + info.name = ".debug_info"; + info.start = dwarf_sections->data[DEBUG_INFO]; + info.buf = info.start; + info.left = dwarf_sections->size[DEBUG_INFO]; + info.is_bigendian = is_bigendian; + info.error_callback = error_callback; + info.data = data; + info.reported_underflow = 0; + + memset (&units, 0, sizeof units); + units_count = 0; + + while (info.left > 0) + { + const unsigned char *unit_data_start; + uint64_t len; + int is_dwarf64; + struct dwarf_buf unit_buf; + int version; + int unit_type; + uint64_t abbrev_offset; + int addrsize; + struct unit *u; + enum dwarf_tag unit_tag; + + if (info.reported_underflow) + goto fail; + + unit_data_start = info.buf; + + len = read_initial_length (&info, &is_dwarf64); + unit_buf = info; + unit_buf.left = len; + + if (!advance (&info, len)) + goto fail; + + version = read_uint16 (&unit_buf); + if (version < 2 || version > 5) + { + dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); + goto fail; + } + + if (version < 5) + unit_type = 0; + else + { + unit_type = read_byte (&unit_buf); + if (unit_type == DW_UT_type || unit_type == DW_UT_split_type) + { + /* This unit doesn't have anything we need. */ + continue; + } + } + + pu = ((struct unit **) + backtrace_vector_grow (state, sizeof (struct unit *), + error_callback, data, &units)); + if (pu == NULL) + goto fail; + + u = ((struct unit *) + backtrace_alloc (state, sizeof *u, error_callback, data)); + if (u == NULL) + goto fail; + + *pu = u; + ++units_count; + + if (version < 5) + addrsize = 0; /* Set below. */ + else + addrsize = read_byte (&unit_buf); + + memset (&u->abbrevs, 0, sizeof u->abbrevs); + abbrev_offset = read_offset (&unit_buf, is_dwarf64); + if (!read_abbrevs (state, abbrev_offset, + dwarf_sections->data[DEBUG_ABBREV], + dwarf_sections->size[DEBUG_ABBREV], + is_bigendian, error_callback, data, &u->abbrevs)) + goto fail; + + if (version < 5) + addrsize = read_byte (&unit_buf); + + switch (unit_type) + { + case 0: + break; + case DW_UT_compile: case DW_UT_partial: + break; + case DW_UT_skeleton: case DW_UT_split_compile: + read_uint64 (&unit_buf); /* dwo_id */ + break; + default: + break; + } + + u->low_offset = unit_offset; + unit_offset += len + (is_dwarf64 ? 12 : 4); + u->high_offset = unit_offset; + u->unit_data = unit_buf.buf; + u->unit_data_len = unit_buf.left; + u->unit_data_offset = unit_buf.buf - unit_data_start; + u->version = version; + u->is_dwarf64 = is_dwarf64; + u->addrsize = addrsize; + u->filename = NULL; + u->comp_dir = NULL; + u->abs_filename = NULL; + u->lineoff = 0; + + /* The actual line number mappings will be read as needed. */ + u->lines = NULL; + u->lines_count = 0; + u->function_addrs = NULL; + u->function_addrs_count = 0; + + if (!find_address_ranges (state, base_address, &unit_buf, dwarf_sections, + is_bigendian, altlink, error_callback, data, + u, addrs, &unit_tag)) + goto fail; + + if (unit_buf.reported_underflow) + goto fail; + } + if (info.reported_underflow) + goto fail; + + unit_vec->vec = units; + unit_vec->count = units_count; + return 1; + + fail: + if (units_count > 0) + { + pu = (struct unit **) units.base; + for (i = 0; i < units_count; i++) + { + free_abbrevs (state, &pu[i]->abbrevs, error_callback, data); + backtrace_free (state, pu[i], sizeof **pu, error_callback, data); + } + backtrace_vector_free (state, &units, error_callback, data); + } + if (addrs->count > 0) + { + backtrace_vector_free (state, &addrs->vec, error_callback, data); + addrs->count = 0; + } + return 0; +} + +/* Add a new mapping to the vector of line mappings that we are + building. Returns 1 on success, 0 on failure. */ + +static int +add_line (struct backtrace_state *state, struct dwarf_data *ddata, + uintptr_t pc, const char *filename, int lineno, + backtrace_error_callback error_callback, void *data, + struct line_vector *vec) +{ + struct line *ln; + + /* If we are adding the same mapping, ignore it. This can happen + when using discriminators. */ + if (vec->count > 0) + { + ln = (struct line *) vec->vec.base + (vec->count - 1); + if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno) + return 1; + } + + ln = ((struct line *) + backtrace_vector_grow (state, sizeof (struct line), error_callback, + data, &vec->vec)); + if (ln == NULL) + return 0; + + /* Add in the base address here, so that we can look up the PC + directly. */ + ln->pc = pc + ddata->base_address; + + ln->filename = filename; + ln->lineno = lineno; + ln->idx = vec->count; + + ++vec->count; + + return 1; +} + +/* Free the line header information. */ + +static void +free_line_header (struct backtrace_state *state, struct line_header *hdr, + backtrace_error_callback error_callback, void *data) +{ + if (hdr->dirs_count != 0) + backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), + error_callback, data); + backtrace_free (state, hdr->filenames, + hdr->filenames_count * sizeof (char *), + error_callback, data); +} + +/* Read the directories and file names for a line header for version + 2, setting fields in HDR. Return 1 on success, 0 on failure. */ + +static int +read_v2_paths (struct backtrace_state *state, struct unit *u, + struct dwarf_buf *hdr_buf, struct line_header *hdr) +{ + const unsigned char *p; + const unsigned char *pend; + size_t i; + + /* Count the number of directory entries. */ + hdr->dirs_count = 0; + p = hdr_buf->buf; + pend = p + hdr_buf->left; + while (p < pend && *p != '\0') + { + p += strnlen((const char *) p, pend - p) + 1; + ++hdr->dirs_count; + } + + hdr->dirs = NULL; + if (hdr->dirs_count != 0) + { + hdr->dirs = ((const char **) + backtrace_alloc (state, + hdr->dirs_count * sizeof (const char *), + hdr_buf->error_callback, + hdr_buf->data)); + if (hdr->dirs == NULL) + return 0; + } + + i = 0; + while (*hdr_buf->buf != '\0') + { + if (hdr_buf->reported_underflow) + return 0; + + hdr->dirs[i] = read_string (hdr_buf); + if (hdr->dirs[i] == NULL) + return 0; + ++i; + } + if (!advance (hdr_buf, 1)) + return 0; + + /* Count the number of file entries. */ + hdr->filenames_count = 0; + p = hdr_buf->buf; + pend = p + hdr_buf->left; + while (p < pend && *p != '\0') + { + p += strnlen ((const char *) p, pend - p) + 1; + p += leb128_len (p); + p += leb128_len (p); + p += leb128_len (p); + ++hdr->filenames_count; + } + + hdr->filenames = ((const char **) + backtrace_alloc (state, + hdr->filenames_count * sizeof (char *), + hdr_buf->error_callback, + hdr_buf->data)); + if (hdr->filenames == NULL) + return 0; + i = 0; + while (*hdr_buf->buf != '\0') + { + const char *filename; + uint64_t dir_index; + + if (hdr_buf->reported_underflow) + return 0; + + filename = read_string (hdr_buf); + if (filename == NULL) + return 0; + dir_index = read_uleb128 (hdr_buf); + if (IS_ABSOLUTE_PATH (filename) + || (dir_index == 0 && u->comp_dir == NULL)) + hdr->filenames[i] = filename; + else + { + const char *dir; + size_t dir_len; + size_t filename_len; + char *s; + + if (dir_index == 0) + dir = u->comp_dir; + else if (dir_index - 1 < hdr->dirs_count) + dir = hdr->dirs[dir_index - 1]; + else + { + dwarf_buf_error (hdr_buf, + ("invalid directory index in " + "line number program header")); + return 0; + } + dir_len = strlen (dir); + filename_len = strlen (filename); + s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2, + hdr_buf->error_callback, + hdr_buf->data)); + if (s == NULL) + return 0; + memcpy (s, dir, dir_len); + /* FIXME: If we are on a DOS-based file system, and the + directory or the file name use backslashes, then we + should use a backslash here. */ + s[dir_len] = '/'; + memcpy (s + dir_len + 1, filename, filename_len + 1); + hdr->filenames[i] = s; + } + + /* Ignore the modification time and size. */ + read_uleb128 (hdr_buf); + read_uleb128 (hdr_buf); + + ++i; + } + + return 1; +} + +/* Read a single version 5 LNCT entry for a directory or file name in a + line header. Sets *STRING to the resulting name, ignoring other + data. Return 1 on success, 0 on failure. */ + +static int +read_lnct (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, struct dwarf_buf *hdr_buf, + const struct line_header *hdr, size_t formats_count, + const struct line_header_format *formats, const char **string) +{ + size_t i; + const char *dir; + const char *path; + + dir = NULL; + path = NULL; + for (i = 0; i < formats_count; i++) + { + struct attr_val val; + + if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64, + u->version, hdr->addrsize, &ddata->dwarf_sections, + ddata->altlink, &val)) + return 0; + switch (formats[i].lnct) + { + case DW_LNCT_path: + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, u->str_offsets_base, + &val, hdr_buf->error_callback, hdr_buf->data, + &path)) + return 0; + break; + case DW_LNCT_directory_index: + if (val.encoding == ATTR_VAL_UINT) + { + if (val.u.uint >= hdr->dirs_count) + { + dwarf_buf_error (hdr_buf, + ("invalid directory index in " + "line number program header")); + return 0; + } + dir = hdr->dirs[val.u.uint]; + } + break; + default: + /* We don't care about timestamps or sizes or hashes. */ + break; + } + } + + if (path == NULL) + { + dwarf_buf_error (hdr_buf, + "missing file name in line number program header"); + return 0; + } + + if (dir == NULL) + *string = path; + else + { + size_t dir_len; + size_t path_len; + char *s; + + dir_len = strlen (dir); + path_len = strlen (path); + s = (char *) backtrace_alloc (state, dir_len + path_len + 2, + hdr_buf->error_callback, hdr_buf->data); + if (s == NULL) + return 0; + memcpy (s, dir, dir_len); + /* FIXME: If we are on a DOS-based file system, and the + directory or the path name use backslashes, then we should + use a backslash here. */ + s[dir_len] = '/'; + memcpy (s + dir_len + 1, path, path_len + 1); + *string = s; + } + + return 1; +} + +/* Read a set of DWARF 5 line header format entries, setting *PCOUNT + and *PPATHS. Return 1 on success, 0 on failure. */ + +static int +read_line_header_format_entries (struct backtrace_state *state, + struct dwarf_data *ddata, + struct unit *u, + struct dwarf_buf *hdr_buf, + struct line_header *hdr, + size_t *pcount, + const char ***ppaths) +{ + size_t formats_count; + struct line_header_format *formats; + size_t paths_count; + const char **paths; + size_t i; + int ret; + + formats_count = read_byte (hdr_buf); + if (formats_count == 0) + formats = NULL; + else + { + formats = ((struct line_header_format *) + backtrace_alloc (state, + (formats_count + * sizeof (struct line_header_format)), + hdr_buf->error_callback, + hdr_buf->data)); + if (formats == NULL) + return 0; + + for (i = 0; i < formats_count; i++) + { + formats[i].lnct = (int) read_uleb128(hdr_buf); + formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf); + } + } + + paths_count = read_uleb128 (hdr_buf); + if (paths_count == 0) + { + *pcount = 0; + *ppaths = NULL; + ret = 1; + goto exit; + } + + paths = ((const char **) + backtrace_alloc (state, paths_count * sizeof (const char *), + hdr_buf->error_callback, hdr_buf->data)); + if (paths == NULL) + { + ret = 0; + goto exit; + } + for (i = 0; i < paths_count; i++) + { + if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count, + formats, &paths[i])) + { + backtrace_free (state, paths, + paths_count * sizeof (const char *), + hdr_buf->error_callback, hdr_buf->data); + ret = 0; + goto exit; + } + } + + *pcount = paths_count; + *ppaths = paths; + + ret = 1; + + exit: + if (formats != NULL) + backtrace_free (state, formats, + formats_count * sizeof (struct line_header_format), + hdr_buf->error_callback, hdr_buf->data); + + return ret; +} + +/* Read the line header. Return 1 on success, 0 on failure. */ + +static int +read_line_header (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf, + struct line_header *hdr) +{ + uint64_t hdrlen; + struct dwarf_buf hdr_buf; + + hdr->version = read_uint16 (line_buf); + if (hdr->version < 2 || hdr->version > 5) + { + dwarf_buf_error (line_buf, "unsupported line number version"); + return 0; + } + + if (hdr->version < 5) + hdr->addrsize = u->addrsize; + else + { + hdr->addrsize = read_byte (line_buf); + /* We could support a non-zero segment_selector_size but I doubt + we'll ever see it. */ + if (read_byte (line_buf) != 0) + { + dwarf_buf_error (line_buf, + "non-zero segment_selector_size not supported"); + return 0; + } + } + + hdrlen = read_offset (line_buf, is_dwarf64); + + hdr_buf = *line_buf; + hdr_buf.left = hdrlen; + + if (!advance (line_buf, hdrlen)) + return 0; + + hdr->min_insn_len = read_byte (&hdr_buf); + if (hdr->version < 4) + hdr->max_ops_per_insn = 1; + else + hdr->max_ops_per_insn = read_byte (&hdr_buf); + + /* We don't care about default_is_stmt. */ + read_byte (&hdr_buf); + + hdr->line_base = read_sbyte (&hdr_buf); + hdr->line_range = read_byte (&hdr_buf); + + hdr->opcode_base = read_byte (&hdr_buf); + hdr->opcode_lengths = hdr_buf.buf; + if (!advance (&hdr_buf, hdr->opcode_base - 1)) + return 0; + + if (hdr->version < 5) + { + if (!read_v2_paths (state, u, &hdr_buf, hdr)) + return 0; + } + else + { + if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr, + &hdr->dirs_count, + &hdr->dirs)) + return 0; + if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr, + &hdr->filenames_count, + &hdr->filenames)) + return 0; + } + + if (hdr_buf.reported_underflow) + return 0; + + return 1; +} + +/* Read the line program, adding line mappings to VEC. Return 1 on + success, 0 on failure. */ + +static int +read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, const struct line_header *hdr, + struct dwarf_buf *line_buf, struct line_vector *vec) +{ + uint64_t address; + unsigned int op_index; + const char *reset_filename; + const char *filename; + int lineno; + + address = 0; + op_index = 0; + if (hdr->filenames_count > 0) + reset_filename = hdr->filenames[0]; + else + reset_filename = ""; + filename = reset_filename; + lineno = 1; + while (line_buf->left > 0) + { + unsigned int op; + + op = read_byte (line_buf); + if (op >= hdr->opcode_base) + { + unsigned int advance; + + /* Special opcode. */ + op -= hdr->opcode_base; + advance = op / hdr->line_range; + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + lineno += hdr->line_base + (int) (op % hdr->line_range); + add_line (state, ddata, address, filename, lineno, + line_buf->error_callback, line_buf->data, vec); + } + else if (op == DW_LNS_extended_op) + { + uint64_t len; + + len = read_uleb128 (line_buf); + op = read_byte (line_buf); + switch (op) + { + case DW_LNE_end_sequence: + /* FIXME: Should we mark the high PC here? It seems + that we already have that information from the + compilation unit. */ + address = 0; + op_index = 0; + filename = reset_filename; + lineno = 1; + break; + case DW_LNE_set_address: + address = read_address (line_buf, hdr->addrsize); + break; + case DW_LNE_define_file: + { + const char *f; + unsigned int dir_index; + + f = read_string (line_buf); + if (f == NULL) + return 0; + dir_index = read_uleb128 (line_buf); + /* Ignore that time and length. */ + read_uleb128 (line_buf); + read_uleb128 (line_buf); + if (IS_ABSOLUTE_PATH (f)) + filename = f; + else + { + const char *dir; + size_t dir_len; + size_t f_len; + char *p; + + if (dir_index == 0 && hdr->version < 5) + dir = u->comp_dir; + else if (dir_index - 1 < hdr->dirs_count) + dir = hdr->dirs[dir_index - 1]; + else + { + dwarf_buf_error (line_buf, + ("invalid directory index " + "in line number program")); + return 0; + } + dir_len = strlen (dir); + f_len = strlen (f); + p = ((char *) + backtrace_alloc (state, dir_len + f_len + 2, + line_buf->error_callback, + line_buf->data)); + if (p == NULL) + return 0; + memcpy (p, dir, dir_len); + /* FIXME: If we are on a DOS-based file system, + and the directory or the file name use + backslashes, then we should use a backslash + here. */ + p[dir_len] = '/'; + memcpy (p + dir_len + 1, f, f_len + 1); + filename = p; + } + } + break; + case DW_LNE_set_discriminator: + /* We don't care about discriminators. */ + read_uleb128 (line_buf); + break; + default: + if (!advance (line_buf, len - 1)) + return 0; + break; + } + } + else + { + switch (op) + { + case DW_LNS_copy: + add_line (state, ddata, address, filename, lineno, + line_buf->error_callback, line_buf->data, vec); + break; + case DW_LNS_advance_pc: + { + uint64_t advance; + + advance = read_uleb128 (line_buf); + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + } + break; + case DW_LNS_advance_line: + lineno += (int) read_sleb128 (line_buf); + break; + case DW_LNS_set_file: + { + uint64_t fileno; + + fileno = read_uleb128 (line_buf); + if (fileno == 0) + filename = ""; + else + { + if (fileno - 1 >= hdr->filenames_count) + { + dwarf_buf_error (line_buf, + ("invalid file number in " + "line number program")); + return 0; + } + filename = hdr->filenames[fileno - 1]; + } + } + break; + case DW_LNS_set_column: + read_uleb128 (line_buf); + break; + case DW_LNS_negate_stmt: + break; + case DW_LNS_set_basic_block: + break; + case DW_LNS_const_add_pc: + { + unsigned int advance; + + op = 255 - hdr->opcode_base; + advance = op / hdr->line_range; + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + } + break; + case DW_LNS_fixed_advance_pc: + address += read_uint16 (line_buf); + op_index = 0; + break; + case DW_LNS_set_prologue_end: + break; + case DW_LNS_set_epilogue_begin: + break; + case DW_LNS_set_isa: + read_uleb128 (line_buf); + break; + default: + { + unsigned int i; + + for (i = hdr->opcode_lengths[op - 1]; i > 0; --i) + read_uleb128 (line_buf); + } + break; + } + } + } + + return 1; +} + +/* Read the line number information for a compilation unit. Returns 1 + on success, 0 on failure. */ + +static int +read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, + backtrace_error_callback error_callback, void *data, + struct unit *u, struct line_header *hdr, struct line **lines, + size_t *lines_count) +{ + struct line_vector vec; + struct dwarf_buf line_buf; + uint64_t len; + int is_dwarf64; + struct line *ln; + + memset (&vec.vec, 0, sizeof vec.vec); + vec.count = 0; + + memset (hdr, 0, sizeof *hdr); + + if (u->lineoff != (off_t) (size_t) u->lineoff + || (size_t) u->lineoff >= ddata->dwarf_sections.size[DEBUG_LINE]) + { + error_callback (data, "unit line offset out of range", 0); + goto fail; + } + + line_buf.name = ".debug_line"; + line_buf.start = ddata->dwarf_sections.data[DEBUG_LINE]; + line_buf.buf = ddata->dwarf_sections.data[DEBUG_LINE] + u->lineoff; + line_buf.left = ddata->dwarf_sections.size[DEBUG_LINE] - u->lineoff; + line_buf.is_bigendian = ddata->is_bigendian; + line_buf.error_callback = error_callback; + line_buf.data = data; + line_buf.reported_underflow = 0; + + len = read_initial_length (&line_buf, &is_dwarf64); + line_buf.left = len; + + if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr)) + goto fail; + + if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) + goto fail; + + if (line_buf.reported_underflow) + goto fail; + + if (vec.count == 0) + { + /* This is not a failure in the sense of a generating an error, + but it is a failure in that sense that we have no useful + information. */ + goto fail; + } + + /* Allocate one extra entry at the end. */ + ln = ((struct line *) + backtrace_vector_grow (state, sizeof (struct line), error_callback, + data, &vec.vec)); + if (ln == NULL) + goto fail; + ln->pc = (uintptr_t) -1; + ln->filename = NULL; + ln->lineno = 0; + ln->idx = 0; + + if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) + goto fail; + + ln = (struct line *) vec.vec.base; + backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); + + *lines = ln; + *lines_count = vec.count; + + return 1; + + fail: + backtrace_vector_free (state, &vec.vec, error_callback, data); + free_line_header (state, hdr, error_callback, data); + *lines = (struct line *) (uintptr_t) -1; + *lines_count = 0; + return 0; +} + +static const char *read_referenced_name (struct dwarf_data *, struct unit *, + uint64_t, backtrace_error_callback, + void *); + +/* Read the name of a function from a DIE referenced by ATTR with VAL. */ + +static const char * +read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u, + struct attr *attr, struct attr_val *val, + backtrace_error_callback error_callback, + void *data) +{ + switch (attr->name) + { + case DW_AT_abstract_origin: + case DW_AT_specification: + break; + default: + return NULL; + } + + if (attr->form == DW_FORM_ref_sig8) + return NULL; + + if (val->encoding == ATTR_VAL_REF_INFO) + { + struct unit *unit + = find_unit (ddata->units, ddata->units_count, + val->u.uint); + if (unit == NULL) + return NULL; + + uint64_t offset = val->u.uint - unit->low_offset; + return read_referenced_name (ddata, unit, offset, error_callback, data); + } + + if (val->encoding == ATTR_VAL_UINT + || val->encoding == ATTR_VAL_REF_UNIT) + return read_referenced_name (ddata, u, val->u.uint, error_callback, data); + + if (val->encoding == ATTR_VAL_REF_ALT_INFO) + { + struct unit *alt_unit + = find_unit (ddata->altlink->units, ddata->altlink->units_count, + val->u.uint); + if (alt_unit == NULL) + return NULL; + + uint64_t offset = val->u.uint - alt_unit->low_offset; + return read_referenced_name (ddata->altlink, alt_unit, offset, + error_callback, data); + } + + return NULL; +} + +/* Read the name of a function from a DIE referenced by a + DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within + the same compilation unit. */ + +static const char * +read_referenced_name (struct dwarf_data *ddata, struct unit *u, + uint64_t offset, backtrace_error_callback error_callback, + void *data) +{ + struct dwarf_buf unit_buf; + uint64_t code; + const struct abbrev *abbrev; + const char *ret; + size_t i; + + /* OFFSET is from the start of the data for this compilation unit. + U->unit_data is the data, but it starts U->unit_data_offset bytes + from the beginning. */ + + if (offset < u->unit_data_offset + || offset - u->unit_data_offset >= u->unit_data_len) + { + error_callback (data, + "abstract origin or specification out of range", + 0); + return NULL; + } + + offset -= u->unit_data_offset; + + unit_buf.name = ".debug_info"; + unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO]; + unit_buf.buf = u->unit_data + offset; + unit_buf.left = u->unit_data_len - offset; + unit_buf.is_bigendian = ddata->is_bigendian; + unit_buf.error_callback = error_callback; + unit_buf.data = data; + unit_buf.reported_underflow = 0; + + code = read_uleb128 (&unit_buf); + if (code == 0) + { + dwarf_buf_error (&unit_buf, "invalid abstract origin or specification"); + return NULL; + } + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return NULL; + + ret = NULL; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, + &unit_buf, u->is_dwarf64, u->version, u->addrsize, + &ddata->dwarf_sections, ddata->altlink, &val)) + return NULL; + + switch (abbrev->attrs[i].name) + { + case DW_AT_name: + /* Third name preference: don't override. A name we found in some + other way, will normally be more useful -- e.g., this name is + normally not mangled. */ + if (ret != NULL) + break; + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, u->str_offsets_base, + &val, error_callback, data, &ret)) + return NULL; + break; + + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + /* First name preference: override all. */ + { + const char *s; + + s = NULL; + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, u->str_offsets_base, + &val, error_callback, data, &s)) + return NULL; + if (s != NULL) + return s; + } + break; + + case DW_AT_specification: + /* Second name preference: override DW_AT_name, don't override + DW_AT_linkage_name. */ + { + const char *name; + + name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i], + &val, error_callback, data); + if (name != NULL) + ret = name; + } + break; + + default: + break; + } + } + + return ret; +} + +/* Add a range to a unit that maps to a function. This is called via + add_ranges. Returns 1 on success, 0 on error. */ + +static int +add_function_range (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, void *data, + void *pvec) +{ + struct function *function = (struct function *) rdata; + struct function_vector *vec = (struct function_vector *) pvec; + struct function_addrs *p; + + if (vec->count > 0) + { + p = (struct function_addrs *) vec->vec.base + (vec->count - 1); + if ((lowpc == p->high || lowpc == p->high + 1) + && function == p->function) + { + if (highpc > p->high) + p->high = highpc; + return 1; + } + } + + p = ((struct function_addrs *) + backtrace_vector_grow (state, sizeof (struct function_addrs), + error_callback, data, &vec->vec)); + if (p == NULL) + return 0; + + p->low = lowpc; + p->high = highpc; + p->function = function; + + ++vec->count; + + return 1; +} + +/* Read one entry plus all its children. Add function addresses to + VEC. Returns 1 on success, 0 on error. */ + +static int +read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, + const struct line_header *lhdr, + backtrace_error_callback error_callback, void *data, + struct function_vector *vec_function, + struct function_vector *vec_inlined) +{ + while (unit_buf->left > 0) + { + uint64_t code; + const struct abbrev *abbrev; + int is_function; + struct function *function; + struct function_vector *vec; + size_t i; + struct pcrange pcrange; + int have_linkage_name; + + code = read_uleb128 (unit_buf); + if (code == 0) + return 1; + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return 0; + + is_function = (abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_entry_point + || abbrev->tag == DW_TAG_inlined_subroutine); + + if (abbrev->tag == DW_TAG_inlined_subroutine) + vec = vec_inlined; + else + vec = vec_function; + + function = NULL; + if (is_function) + { + function = ((struct function *) + backtrace_alloc (state, sizeof *function, + error_callback, data)); + if (function == NULL) + return 0; + memset (function, 0, sizeof *function); + } + + memset (&pcrange, 0, sizeof pcrange); + have_linkage_name = 0; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val, + unit_buf, u->is_dwarf64, u->version, + u->addrsize, &ddata->dwarf_sections, + ddata->altlink, &val)) + return 0; + + /* The compile unit sets the base address for any address + ranges in the function entries. */ + if (abbrev->tag == DW_TAG_compile_unit + && abbrev->attrs[i].name == DW_AT_low_pc) + { + if (val.encoding == ATTR_VAL_ADDRESS) + base = val.u.uint; + else if (val.encoding == ATTR_VAL_ADDRESS_INDEX) + { + if (!resolve_addr_index (&ddata->dwarf_sections, + u->addr_base, u->addrsize, + ddata->is_bigendian, val.u.uint, + error_callback, data, &base)) + return 0; + } + } + + if (is_function) + { + switch (abbrev->attrs[i].name) + { + case DW_AT_call_file: + if (val.encoding == ATTR_VAL_UINT) + { + if (val.u.uint == 0) + function->caller_filename = ""; + else + { + if (val.u.uint - 1 >= lhdr->filenames_count) + { + dwarf_buf_error (unit_buf, + ("invalid file number in " + "DW_AT_call_file attribute")); + return 0; + } + function->caller_filename = + lhdr->filenames[val.u.uint - 1]; + } + } + break; + + case DW_AT_call_line: + if (val.encoding == ATTR_VAL_UINT) + function->caller_lineno = val.u.uint; + break; + + case DW_AT_abstract_origin: + case DW_AT_specification: + /* Second name preference: override DW_AT_name, don't override + DW_AT_linkage_name. */ + if (have_linkage_name) + break; + { + const char *name; + + name + = read_referenced_name_from_attr (ddata, u, + &abbrev->attrs[i], &val, + error_callback, data); + if (name != NULL) + function->name = name; + } + break; + + case DW_AT_name: + /* Third name preference: don't override. */ + if (function->name != NULL) + break; + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, + u->str_offsets_base, &val, + error_callback, data, &function->name)) + return 0; + break; + + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + /* First name preference: override all. */ + { + const char *s; + + s = NULL; + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, + u->str_offsets_base, &val, + error_callback, data, &s)) + return 0; + if (s != NULL) + { + function->name = s; + have_linkage_name = 1; + } + } + break; + + case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges: + update_pcrange (&abbrev->attrs[i], &val, &pcrange); + break; + + default: + break; + } + } + } + + /* If we couldn't find a name for the function, we have no use + for it. */ + if (is_function && function->name == NULL) + { + backtrace_free (state, function, sizeof *function, + error_callback, data); + is_function = 0; + } + + if (is_function) + { + if (pcrange.have_ranges + || (pcrange.have_lowpc && pcrange.have_highpc)) + { + if (!add_ranges (state, &ddata->dwarf_sections, + ddata->base_address, ddata->is_bigendian, + u, base, &pcrange, add_function_range, + (void *) function, error_callback, data, + (void *) vec)) + return 0; + } + else + { + backtrace_free (state, function, sizeof *function, + error_callback, data); + is_function = 0; + } + } + + if (abbrev->has_children) + { + if (!is_function) + { + if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, + error_callback, data, vec_function, + vec_inlined)) + return 0; + } + else + { + struct function_vector fvec; + + /* Gather any information for inlined functions in + FVEC. */ + + memset (&fvec, 0, sizeof fvec); + + if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, + error_callback, data, vec_function, + &fvec)) + return 0; + + if (fvec.count > 0) + { + struct function_addrs *faddrs; + + if (!backtrace_vector_release (state, &fvec.vec, + error_callback, data)) + return 0; + + faddrs = (struct function_addrs *) fvec.vec.base; + backtrace_qsort (faddrs, fvec.count, + sizeof (struct function_addrs), + function_addrs_compare); + + function->function_addrs = faddrs; + function->function_addrs_count = fvec.count; + } + } + } + } + + return 1; +} + +/* Read function name information for a compilation unit. We look + through the whole unit looking for function tags. */ + +static void +read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, + const struct line_header *lhdr, + backtrace_error_callback error_callback, void *data, + struct unit *u, struct function_vector *fvec, + struct function_addrs **ret_addrs, + size_t *ret_addrs_count) +{ + struct function_vector lvec; + struct function_vector *pfvec; + struct dwarf_buf unit_buf; + struct function_addrs *addrs; + size_t addrs_count; + + /* Use FVEC if it is not NULL. Otherwise use our own vector. */ + if (fvec != NULL) + pfvec = fvec; + else + { + memset (&lvec, 0, sizeof lvec); + pfvec = &lvec; + } + + unit_buf.name = ".debug_info"; + unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO]; + unit_buf.buf = u->unit_data; + unit_buf.left = u->unit_data_len; + unit_buf.is_bigendian = ddata->is_bigendian; + unit_buf.error_callback = error_callback; + unit_buf.data = data; + unit_buf.reported_underflow = 0; + + while (unit_buf.left > 0) + { + if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, + error_callback, data, pfvec, pfvec)) + return; + } + + if (pfvec->count == 0) + return; + + addrs_count = pfvec->count; + + if (fvec == NULL) + { + if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) + return; + addrs = (struct function_addrs *) pfvec->vec.base; + } + else + { + /* Finish this list of addresses, but leave the remaining space in + the vector available for the next function unit. */ + addrs = ((struct function_addrs *) + backtrace_vector_finish (state, &fvec->vec, + error_callback, data)); + if (addrs == NULL) + return; + fvec->count = 0; + } + + backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), + function_addrs_compare); + + *ret_addrs = addrs; + *ret_addrs_count = addrs_count; +} + +/* See if PC is inlined in FUNCTION. If it is, print out the inlined + information, and update FILENAME and LINENO for the caller. + Returns whatever CALLBACK returns, or 0 to keep going. */ + +static int +report_inlined_functions (uintptr_t pc, struct function *function, + backtrace_full_callback callback, void *data, + const char **filename, int *lineno) +{ + struct function_addrs *function_addrs; + struct function *inlined; + int ret; + + if (function->function_addrs_count == 0) + return 0; + + function_addrs = ((struct function_addrs *) + bsearch (&pc, function->function_addrs, + function->function_addrs_count, + sizeof (struct function_addrs), + function_addrs_search)); + if (function_addrs == NULL) + return 0; + + while (((size_t) (function_addrs - function->function_addrs) + 1 + < function->function_addrs_count) + && pc >= (function_addrs + 1)->low + && pc < (function_addrs + 1)->high) + ++function_addrs; + + /* We found an inlined call. */ + + inlined = function_addrs->function; + + /* Report any calls inlined into this one. */ + ret = report_inlined_functions (pc, inlined, callback, data, + filename, lineno); + if (ret != 0) + return ret; + + /* Report this inlined call. */ + ret = callback (data, pc, *filename, *lineno, inlined->name); + if (ret != 0) + return ret; + + /* Our caller will report the caller of the inlined function; tell + it the appropriate filename and line number. */ + *filename = inlined->caller_filename; + *lineno = inlined->caller_lineno; + + return 0; +} + +/* Look for a PC in the DWARF mapping for one module. On success, + call CALLBACK and return whatever it returns. On error, call + ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, + 0 if not. */ + +static int +dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, + uintptr_t pc, backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data, + int *found) +{ + struct unit_addrs *entry; + struct unit *u; + int new_data; + struct line *lines; + struct line *ln; + struct function_addrs *function_addrs; + struct function *function; + const char *filename; + int lineno; + int ret; + + *found = 1; + + /* Find an address range that includes PC. */ + entry = (ddata->addrs_count == 0 + ? NULL + : bsearch (&pc, ddata->addrs, ddata->addrs_count, + sizeof (struct unit_addrs), unit_addrs_search)); + + if (entry == NULL) + { + *found = 0; + return 0; + } + + /* If there are multiple ranges that contain PC, use the last one, + in order to produce predictable results. If we assume that all + ranges are properly nested, then the last range will be the + smallest one. */ + while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count + && pc >= (entry + 1)->low + && pc < (entry + 1)->high) + ++entry; + + /* We need the lines, lines_count, function_addrs, + function_addrs_count fields of u. If they are not set, we need + to set them. When running in threaded mode, we need to allow for + the possibility that some other thread is setting them + simultaneously. */ + + u = entry->u; + lines = u->lines; + + /* Skip units with no useful line number information by walking + backward. Useless line number information is marked by setting + lines == -1. */ + while (entry > ddata->addrs + && pc >= (entry - 1)->low + && pc < (entry - 1)->high) + { + if (state->threaded) + lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); + + if (lines != (struct line *) (uintptr_t) -1) + break; + + --entry; + + u = entry->u; + lines = u->lines; + } + + if (state->threaded) + lines = backtrace_atomic_load_pointer (&u->lines); + + new_data = 0; + if (lines == NULL) + { + size_t function_addrs_count; + struct line_header lhdr; + size_t count; + + /* We have never read the line information for this unit. Read + it now. */ + + function_addrs = NULL; + function_addrs_count = 0; + if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr, + &lines, &count)) + { + struct function_vector *pfvec; + + /* If not threaded, reuse DDATA->FVEC for better memory + consumption. */ + if (state->threaded) + pfvec = NULL; + else + pfvec = &ddata->fvec; + read_function_info (state, ddata, &lhdr, error_callback, data, + entry->u, pfvec, &function_addrs, + &function_addrs_count); + free_line_header (state, &lhdr, error_callback, data); + new_data = 1; + } + + /* Atomically store the information we just read into the unit. + If another thread is simultaneously writing, it presumably + read the same information, and we don't care which one we + wind up with; we just leak the other one. We do have to + write the lines field last, so that the acquire-loads above + ensure that the other fields are set. */ + + if (!state->threaded) + { + u->lines_count = count; + u->function_addrs = function_addrs; + u->function_addrs_count = function_addrs_count; + u->lines = lines; + } + else + { + backtrace_atomic_store_size_t (&u->lines_count, count); + backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); + backtrace_atomic_store_size_t (&u->function_addrs_count, + function_addrs_count); + backtrace_atomic_store_pointer (&u->lines, lines); + } + } + + /* Now all fields of U have been initialized. */ + + if (lines == (struct line *) (uintptr_t) -1) + { + /* If reading the line number information failed in some way, + try again to see if there is a better compilation unit for + this PC. */ + if (new_data) + return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, found); + return callback (data, pc, NULL, 0, NULL); + } + + /* Search for PC within this unit. */ + + ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count, + sizeof (struct line), line_search); + if (ln == NULL) + { + /* The PC is between the low_pc and high_pc attributes of the + compilation unit, but no entry in the line table covers it. + This implies that the start of the compilation unit has no + line number information. */ + + if (entry->u->abs_filename == NULL) + { + const char *filename; + + filename = entry->u->filename; + if (filename != NULL + && !IS_ABSOLUTE_PATH (filename) + && entry->u->comp_dir != NULL) + { + size_t filename_len; + const char *dir; + size_t dir_len; + char *s; + + filename_len = strlen (filename); + dir = entry->u->comp_dir; + dir_len = strlen (dir); + s = (char *) backtrace_alloc (state, dir_len + filename_len + 2, + error_callback, data); + if (s == NULL) + { + *found = 0; + return 0; + } + memcpy (s, dir, dir_len); + /* FIXME: Should use backslash if DOS file system. */ + s[dir_len] = '/'; + memcpy (s + dir_len + 1, filename, filename_len + 1); + filename = s; + } + entry->u->abs_filename = filename; + } + + return callback (data, pc, entry->u->abs_filename, 0, NULL); + } + + /* Search for function name within this unit. */ + + if (entry->u->function_addrs_count == 0) + return callback (data, pc, ln->filename, ln->lineno, NULL); + + function_addrs = ((struct function_addrs *) + bsearch (&pc, entry->u->function_addrs, + entry->u->function_addrs_count, + sizeof (struct function_addrs), + function_addrs_search)); + if (function_addrs == NULL) + return callback (data, pc, ln->filename, ln->lineno, NULL); + + /* If there are multiple function ranges that contain PC, use the + last one, in order to produce predictable results. */ + + while (((size_t) (function_addrs - entry->u->function_addrs + 1) + < entry->u->function_addrs_count) + && pc >= (function_addrs + 1)->low + && pc < (function_addrs + 1)->high) + ++function_addrs; + + function = function_addrs->function; + + filename = ln->filename; + lineno = ln->lineno; + + ret = report_inlined_functions (pc, function, callback, data, + &filename, &lineno); + if (ret != 0) + return ret; + + return callback (data, pc, filename, lineno, function->name); +} + + +/* Return the file/line information for a PC using the DWARF mapping + we built earlier. */ + +static int +dwarf_fileline (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct dwarf_data *ddata; + int found; + int ret; + + if (!state->threaded) + { + for (ddata = (struct dwarf_data *) state->fileline_data; + ddata != NULL; + ddata = ddata->next) + { + ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + } + } + else + { + struct dwarf_data **pp; + + pp = (struct dwarf_data **) (void *) &state->fileline_data; + while (1) + { + ddata = backtrace_atomic_load_pointer (pp); + if (ddata == NULL) + break; + + ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + + pp = &ddata->next; + } + } + + /* FIXME: See if any libraries have been dlopen'ed. */ + + return callback (data, pc, NULL, 0, NULL); +} + +/* Initialize our data structures from the DWARF debug info for a + file. Return NULL on failure. */ + +static struct dwarf_data * +build_dwarf_data (struct backtrace_state *state, + uintptr_t base_address, + const struct dwarf_sections *dwarf_sections, + int is_bigendian, + struct dwarf_data *altlink, + backtrace_error_callback error_callback, + void *data) +{ + struct unit_addrs_vector addrs_vec; + struct unit_addrs *addrs; + size_t addrs_count; + struct unit_vector units_vec; + struct unit **units; + size_t units_count; + struct dwarf_data *fdata; + + if (!build_address_map (state, base_address, dwarf_sections, is_bigendian, + altlink, error_callback, data, &addrs_vec, + &units_vec)) + return NULL; + + if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) + return NULL; + if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data)) + return NULL; + addrs = (struct unit_addrs *) addrs_vec.vec.base; + units = (struct unit **) units_vec.vec.base; + addrs_count = addrs_vec.count; + units_count = units_vec.count; + backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), + unit_addrs_compare); + /* No qsort for units required, already sorted. */ + + fdata = ((struct dwarf_data *) + backtrace_alloc (state, sizeof (struct dwarf_data), + error_callback, data)); + if (fdata == NULL) + return NULL; + + fdata->next = NULL; + fdata->altlink = altlink; + fdata->base_address = base_address; + fdata->addrs = addrs; + fdata->addrs_count = addrs_count; + fdata->units = units; + fdata->units_count = units_count; + fdata->dwarf_sections = *dwarf_sections; + fdata->is_bigendian = is_bigendian; + memset (&fdata->fvec, 0, sizeof fdata->fvec); + + return fdata; +} + +/* Build our data structures from the DWARF sections for a module. + Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0 + on failure. */ + +int +backtrace_dwarf_add (struct backtrace_state *state, + uintptr_t base_address, + const struct dwarf_sections *dwarf_sections, + int is_bigendian, + struct dwarf_data *fileline_altlink, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, + struct dwarf_data **fileline_entry) +{ + struct dwarf_data *fdata; + + fdata = build_dwarf_data (state, base_address, dwarf_sections, is_bigendian, + fileline_altlink, error_callback, data); + if (fdata == NULL) + return 0; + + if (fileline_entry != NULL) + *fileline_entry = fdata; + + if (!state->threaded) + { + struct dwarf_data **pp; + + for (pp = (struct dwarf_data **) (void *) &state->fileline_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = fdata; + } + else + { + while (1) + { + struct dwarf_data **pp; + + pp = (struct dwarf_data **) (void *) &state->fileline_data; + + while (1) + { + struct dwarf_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, fdata)) + break; + } + } + + *fileline_fn = dwarf_fileline; + + return 1; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/elf.c b/src/3rdparty/libbacktrace/libbacktrace/elf.c new file mode 100644 index 00000000..d1d257b1 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/elf.c @@ -0,0 +1,3435 @@ +/* elf.c -- Get debug data from an ELF file for backtraces. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DL_ITERATE_PHDR +#include +#endif + +#include "backtrace.h" +#include "internal.h" + +#ifndef S_ISLNK + #ifndef S_IFLNK + #define S_IFLNK 0120000 + #endif + #ifndef S_IFMT + #define S_IFMT 0170000 + #endif + #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif + +#ifndef __GNUC__ +#define __builtin_prefetch(p, r, l) +#define unlikely(x) (x) +#else +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN + +/* If strnlen is not declared, provide our own version. */ + +static size_t +xstrnlen (const char *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen; ++i) + if (s[i] == '\0') + break; + return i; +} + +#define strnlen xstrnlen + +#endif + +#ifndef HAVE_LSTAT + +/* Dummy version of lstat for systems that don't have it. */ + +static int +xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED) +{ + return -1; +} + +#define lstat xlstat + +#endif + +#ifndef HAVE_READLINK + +/* Dummy version of readlink for systems that don't have it. */ + +static ssize_t +xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED, + size_t bufsz ATTRIBUTE_UNUSED) +{ + return -1; +} + +#define readlink xreadlink + +#endif + +#ifndef HAVE_DL_ITERATE_PHDR + +/* Dummy version of dl_iterate_phdr for systems that don't have it. */ + +#define dl_phdr_info x_dl_phdr_info +#define dl_iterate_phdr x_dl_iterate_phdr + +struct dl_phdr_info +{ + uintptr_t dlpi_addr; + const char *dlpi_name; +}; + +static int +dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, + size_t, void *) ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + return 0; +} + +#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */ + +/* The configure script must tell us whether we are 32-bit or 64-bit + ELF. We could make this code test and support either possibility, + but there is no point. This code only works for the currently + running executable, which means that we know the ELF mode at + configure time. */ + +#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 +#error "Unknown BACKTRACE_ELF_SIZE" +#endif + +/* might #include which might define our constants + with slightly different values. Undefine them to be safe. */ + +#undef EI_NIDENT +#undef EI_MAG0 +#undef EI_MAG1 +#undef EI_MAG2 +#undef EI_MAG3 +#undef EI_CLASS +#undef EI_DATA +#undef EI_VERSION +#undef ELF_MAG0 +#undef ELF_MAG1 +#undef ELF_MAG2 +#undef ELF_MAG3 +#undef ELFCLASS32 +#undef ELFCLASS64 +#undef ELFDATA2LSB +#undef ELFDATA2MSB +#undef EV_CURRENT +#undef ET_DYN +#undef EM_PPC64 +#undef EF_PPC64_ABI +#undef SHN_LORESERVE +#undef SHN_XINDEX +#undef SHN_UNDEF +#undef SHT_PROGBITS +#undef SHT_SYMTAB +#undef SHT_STRTAB +#undef SHT_DYNSYM +#undef SHF_COMPRESSED +#undef STT_OBJECT +#undef STT_FUNC +#undef NT_GNU_BUILD_ID +#undef ELFCOMPRESS_ZLIB + +/* Basic types. */ + +typedef uint16_t b_elf_half; /* Elf_Half. */ +typedef uint32_t b_elf_word; /* Elf_Word. */ +typedef int32_t b_elf_sword; /* Elf_Sword. */ + +#if BACKTRACE_ELF_SIZE == 32 + +typedef uint32_t b_elf_addr; /* Elf_Addr. */ +typedef uint32_t b_elf_off; /* Elf_Off. */ + +typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ + +#else + +typedef uint64_t b_elf_addr; /* Elf_Addr. */ +typedef uint64_t b_elf_off; /* Elf_Off. */ +typedef uint64_t b_elf_xword; /* Elf_Xword. */ +typedef int64_t b_elf_sxword; /* Elf_Sxword. */ + +typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ + +#endif + +/* Data structures and associated constants. */ + +#define EI_NIDENT 16 + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + b_elf_half e_type; /* Identifies object file type */ + b_elf_half e_machine; /* Specifies required architecture */ + b_elf_word e_version; /* Identifies object file version */ + b_elf_addr e_entry; /* Entry point virtual address */ + b_elf_off e_phoff; /* Program header table file offset */ + b_elf_off e_shoff; /* Section header table file offset */ + b_elf_word e_flags; /* Processor-specific flags */ + b_elf_half e_ehsize; /* ELF header size in bytes */ + b_elf_half e_phentsize; /* Program header table entry size */ + b_elf_half e_phnum; /* Program header table entry count */ + b_elf_half e_shentsize; /* Section header table entry size */ + b_elf_half e_shnum; /* Section header table entry count */ + b_elf_half e_shstrndx; /* Section header string table index */ +} b_elf_ehdr; /* Elf_Ehdr. */ + +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 + +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_CURRENT 1 + +#define ET_DYN 3 + +#define EM_PPC64 21 +#define EF_PPC64_ABI 3 + +typedef struct { + b_elf_word sh_name; /* Section name, index in string tbl */ + b_elf_word sh_type; /* Type of section */ + b_elf_wxword sh_flags; /* Miscellaneous section attributes */ + b_elf_addr sh_addr; /* Section virtual addr at execution */ + b_elf_off sh_offset; /* Section file offset */ + b_elf_wxword sh_size; /* Size of section in bytes */ + b_elf_word sh_link; /* Index of another section */ + b_elf_word sh_info; /* Additional section information */ + b_elf_wxword sh_addralign; /* Section alignment */ + b_elf_wxword sh_entsize; /* Entry size if section holds table */ +} b_elf_shdr; /* Elf_Shdr. */ + +#define SHN_UNDEF 0x0000 /* Undefined section */ +#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ +#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ + +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_DYNSYM 11 + +#define SHF_COMPRESSED 0x800 + +#if BACKTRACE_ELF_SIZE == 32 + +typedef struct +{ + b_elf_word st_name; /* Symbol name, index in string tbl */ + b_elf_addr st_value; /* Symbol value */ + b_elf_word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol binding and type */ + unsigned char st_other; /* Visibility and other data */ + b_elf_half st_shndx; /* Symbol section index */ +} b_elf_sym; /* Elf_Sym. */ + +#else /* BACKTRACE_ELF_SIZE != 32 */ + +typedef struct +{ + b_elf_word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Symbol binding and type */ + unsigned char st_other; /* Visibility and other data */ + b_elf_half st_shndx; /* Symbol section index */ + b_elf_addr st_value; /* Symbol value */ + b_elf_xword st_size; /* Symbol size */ +} b_elf_sym; /* Elf_Sym. */ + +#endif /* BACKTRACE_ELF_SIZE != 32 */ + +#define STT_OBJECT 1 +#define STT_FUNC 2 + +typedef struct +{ + uint32_t namesz; + uint32_t descsz; + uint32_t type; + char name[1]; +} b_elf_note; + +#define NT_GNU_BUILD_ID 3 + +#if BACKTRACE_ELF_SIZE == 32 + +typedef struct +{ + b_elf_word ch_type; /* Compresstion algorithm */ + b_elf_word ch_size; /* Uncompressed size */ + b_elf_word ch_addralign; /* Alignment for uncompressed data */ +} b_elf_chdr; /* Elf_Chdr */ + +#else /* BACKTRACE_ELF_SIZE != 32 */ + +typedef struct +{ + b_elf_word ch_type; /* Compression algorithm */ + b_elf_word ch_reserved; /* Reserved */ + b_elf_xword ch_size; /* Uncompressed size */ + b_elf_xword ch_addralign; /* Alignment for uncompressed data */ +} b_elf_chdr; /* Elf_Chdr */ + +#endif /* BACKTRACE_ELF_SIZE != 32 */ + +#define ELFCOMPRESS_ZLIB 1 + +/* Names of sections, indexed by enum dwarf_section in internal.h. */ + +static const char * const dwarf_section_names[DEBUG_MAX] = +{ + ".debug_info", + ".debug_line", + ".debug_abbrev", + ".debug_ranges", + ".debug_str", + ".debug_addr", + ".debug_str_offsets", + ".debug_line_str", + ".debug_rnglists" +}; + +/* Information we gather for the sections we care about. */ + +struct debug_section_info +{ + /* Section file offset. */ + off_t offset; + /* Section size. */ + size_t size; + /* Section contents, after read from file. */ + const unsigned char *data; + /* Whether the SHF_COMPRESSED flag is set for the section. */ + int compressed; +}; + +/* Information we keep for an ELF symbol. */ + +struct elf_symbol +{ + /* The name of the symbol. */ + const char *name; + /* The address of the symbol. */ + uintptr_t address; + /* The size of the symbol. */ + size_t size; +}; + +/* Information to pass to elf_syminfo. */ + +struct elf_syminfo_data +{ + /* Symbols for the next module. */ + struct elf_syminfo_data *next; + /* The ELF symbols, sorted by address. */ + struct elf_symbol *symbols; + /* The number of symbols. */ + size_t count; +}; + +/* Information about PowerPC64 ELFv1 .opd section. */ + +struct elf_ppc64_opd_data +{ + /* Address of the .opd section. */ + b_elf_addr addr; + /* Section data. */ + const char *data; + /* Size of the .opd section. */ + size_t size; + /* Corresponding section view. */ + struct backtrace_view view; +}; + +/* Compute the CRC-32 of BUF/LEN. This uses the CRC used for + .gnu_debuglink files. */ + +static uint32_t +elf_crc32 (uint32_t crc, const unsigned char *buf, size_t len) +{ + static const uint32_t crc32_table[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 + }; + const unsigned char *end; + + crc = ~crc; + for (end = buf + len; buf < end; ++ buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} + +/* Return the CRC-32 of the entire file open at DESCRIPTOR. */ + +static uint32_t +elf_crc32_file (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data) +{ + struct stat st; + struct backtrace_view file_view; + uint32_t ret; + + if (fstat (descriptor, &st) < 0) + { + error_callback (data, "fstat", errno); + return 0; + } + + if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback, + data, &file_view)) + return 0; + + ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size); + + backtrace_release_view (state, &file_view, error_callback, data); + + return ret; +} + +/* A dummy callback function used when we can't find any debug info. */ + +static int +elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no debug info in ELF executable", -1); + return 0; +} + +/* A dummy callback function used when we can't find a symbol + table. */ + +static void +elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, + backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no symbol table in ELF executable", -1); +} + +/* Compare struct elf_symbol for qsort. */ + +static int +elf_symbol_compare (const void *v1, const void *v2) +{ + const struct elf_symbol *e1 = (const struct elf_symbol *) v1; + const struct elf_symbol *e2 = (const struct elf_symbol *) v2; + + if (e1->address < e2->address) + return -1; + else if (e1->address > e2->address) + return 1; + else + return 0; +} + +/* Compare an ADDR against an elf_symbol for bsearch. We allocate one + extra entry in the array so that this can look safely at the next + entry. */ + +static int +elf_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct elf_symbol *entry = (const struct elf_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->address) + return -1; + else if (addr >= entry->address + entry->size) + return 1; + else + return 0; +} + +/* Initialize the symbol table info for elf_syminfo. */ + +static int +elf_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, + const unsigned char *symtab_data, size_t symtab_size, + const unsigned char *strtab, size_t strtab_size, + backtrace_error_callback error_callback, + void *data, struct elf_syminfo_data *sdata, + struct elf_ppc64_opd_data *opd) +{ + size_t sym_count; + const b_elf_sym *sym; + size_t elf_symbol_count; + size_t elf_symbol_size; + struct elf_symbol *elf_symbols; + size_t i; + unsigned int j; + + sym_count = symtab_size / sizeof (b_elf_sym); + + /* We only care about function symbols. Count them. */ + sym = (const b_elf_sym *) symtab_data; + elf_symbol_count = 0; + for (i = 0; i < sym_count; ++i, ++sym) + { + int info; + + info = sym->st_info & 0xf; + if ((info == STT_FUNC || info == STT_OBJECT) + && sym->st_shndx != SHN_UNDEF) + ++elf_symbol_count; + } + + elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); + elf_symbols = ((struct elf_symbol *) + backtrace_alloc (state, elf_symbol_size, error_callback, + data)); + if (elf_symbols == NULL) + return 0; + + sym = (const b_elf_sym *) symtab_data; + j = 0; + for (i = 0; i < sym_count; ++i, ++sym) + { + int info; + + info = sym->st_info & 0xf; + if (info != STT_FUNC && info != STT_OBJECT) + continue; + if (sym->st_shndx == SHN_UNDEF) + continue; + if (sym->st_name >= strtab_size) + { + error_callback (data, "symbol string index out of range", 0); + backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, + data); + return 0; + } + elf_symbols[j].name = (const char *) strtab + sym->st_name; + /* Special case PowerPC64 ELFv1 symbols in .opd section, if the symbol + is a function descriptor, read the actual code address from the + descriptor. */ + if (opd + && sym->st_value >= opd->addr + && sym->st_value < opd->addr + opd->size) + elf_symbols[j].address + = *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr)); + else + elf_symbols[j].address = sym->st_value; + elf_symbols[j].address += base_address; + elf_symbols[j].size = sym->st_size; + ++j; + } + + backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), + elf_symbol_compare); + + sdata->next = NULL; + sdata->symbols = elf_symbols; + sdata->count = elf_symbol_count; + + return 1; +} + +/* Add EDATA to the list in STATE. */ + +static void +elf_add_syminfo_data (struct backtrace_state *state, + struct elf_syminfo_data *edata) +{ + if (!state->threaded) + { + struct elf_syminfo_data **pp; + + for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = edata; + } + else + { + while (1) + { + struct elf_syminfo_data **pp; + + pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct elf_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, edata)) + break; + } + } +} + +/* Return the symbol name and value for an ADDR. */ + +static void +elf_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct elf_syminfo_data *edata; + struct elf_symbol *sym = NULL; + + if (!state->threaded) + { + for (edata = (struct elf_syminfo_data *) state->syminfo_data; + edata != NULL; + edata = edata->next) + { + sym = ((struct elf_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct elf_symbol), elf_symbol_search)); + if (sym != NULL) + break; + } + } + else + { + struct elf_syminfo_data **pp; + + pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + edata = backtrace_atomic_load_pointer (pp); + if (edata == NULL) + break; + + sym = ((struct elf_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct elf_symbol), elf_symbol_search)); + if (sym != NULL) + break; + + pp = &edata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->address, sym->size); +} + +/* Return whether FILENAME is a symlink. */ + +static int +elf_is_symlink (const char *filename) +{ + struct stat st; + + if (lstat (filename, &st) < 0) + return 0; + return S_ISLNK (st.st_mode); +} + +/* Return the results of reading the symlink FILENAME in a buffer + allocated by backtrace_alloc. Return the length of the buffer in + *LEN. */ + +static char * +elf_readlink (struct backtrace_state *state, const char *filename, + backtrace_error_callback error_callback, void *data, + size_t *plen) +{ + size_t len; + char *buf; + + len = 128; + while (1) + { + ssize_t rl; + + buf = backtrace_alloc (state, len, error_callback, data); + if (buf == NULL) + return NULL; + rl = readlink (filename, buf, len); + if (rl < 0) + { + backtrace_free (state, buf, len, error_callback, data); + return NULL; + } + if ((size_t) rl < len - 1) + { + buf[rl] = '\0'; + *plen = len; + return buf; + } + backtrace_free (state, buf, len, error_callback, data); + len *= 2; + } +} + +#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/" + +/* Open a separate debug info file, using the build ID to find it. + Returns an open file descriptor, or -1. + + The GDB manual says that the only place gdb looks for a debug file + when the build ID is known is in /usr/lib/debug/.build-id. */ + +static int +elf_open_debugfile_by_buildid (struct backtrace_state *state, + const char *buildid_data, size_t buildid_size, + backtrace_error_callback error_callback, + void *data) +{ + const char * const prefix = SYSTEM_BUILD_ID_DIR; + const size_t prefix_len = strlen (prefix); + const char * const suffix = ".debug"; + const size_t suffix_len = strlen (suffix); + size_t len; + char *bd_filename; + char *t; + size_t i; + int ret; + int does_not_exist; + + len = prefix_len + buildid_size * 2 + suffix_len + 2; + bd_filename = backtrace_alloc (state, len, error_callback, data); + if (bd_filename == NULL) + return -1; + + t = bd_filename; + memcpy (t, prefix, prefix_len); + t += prefix_len; + for (i = 0; i < buildid_size; i++) + { + unsigned char b; + unsigned char nib; + + b = (unsigned char) buildid_data[i]; + nib = (b & 0xf0) >> 4; + *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; + nib = b & 0x0f; + *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; + if (i == 0) + *t++ = '/'; + } + memcpy (t, suffix, suffix_len); + t[suffix_len] = '\0'; + + ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist); + + backtrace_free (state, bd_filename, len, error_callback, data); + + /* gdb checks that the debuginfo file has the same build ID note. + That seems kind of pointless to me--why would it have the right + name but not the right build ID?--so skipping the check. */ + + return ret; +} + +/* Try to open a file whose name is PREFIX (length PREFIX_LEN) + concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with + DEBUGLINK_NAME. Returns an open file descriptor, or -1. */ + +static int +elf_try_debugfile (struct backtrace_state *state, const char *prefix, + size_t prefix_len, const char *prefix2, size_t prefix2_len, + const char *debuglink_name, + backtrace_error_callback error_callback, void *data) +{ + size_t debuglink_len; + size_t try_len; + char *try; + int does_not_exist; + int ret; + + debuglink_len = strlen (debuglink_name); + try_len = prefix_len + prefix2_len + debuglink_len + 1; + try = backtrace_alloc (state, try_len, error_callback, data); + if (try == NULL) + return -1; + + memcpy (try, prefix, prefix_len); + memcpy (try + prefix_len, prefix2, prefix2_len); + memcpy (try + prefix_len + prefix2_len, debuglink_name, debuglink_len); + try[prefix_len + prefix2_len + debuglink_len] = '\0'; + + ret = backtrace_open (try, error_callback, data, &does_not_exist); + + backtrace_free (state, try, try_len, error_callback, data); + + return ret; +} + +/* Find a separate debug info file, using the debuglink section data + to find it. Returns an open file descriptor, or -1. */ + +static int +elf_find_debugfile_by_debuglink (struct backtrace_state *state, + const char *filename, + const char *debuglink_name, + backtrace_error_callback error_callback, + void *data) +{ + int ret; + char *alc; + size_t alc_len; + const char *slash; + int ddescriptor; + const char *prefix; + size_t prefix_len; + + /* Resolve symlinks in FILENAME. Since FILENAME is fairly likely to + be /proc/self/exe, symlinks are common. We don't try to resolve + the whole path name, just the base name. */ + ret = -1; + alc = NULL; + alc_len = 0; + while (elf_is_symlink (filename)) + { + char *new_buf; + size_t new_len; + + new_buf = elf_readlink (state, filename, error_callback, data, &new_len); + if (new_buf == NULL) + break; + + if (new_buf[0] == '/') + filename = new_buf; + else + { + slash = strrchr (filename, '/'); + if (slash == NULL) + filename = new_buf; + else + { + size_t clen; + char *c; + + slash++; + clen = slash - filename + strlen (new_buf) + 1; + c = backtrace_alloc (state, clen, error_callback, data); + if (c == NULL) + goto done; + + memcpy (c, filename, slash - filename); + memcpy (c + (slash - filename), new_buf, strlen (new_buf)); + c[slash - filename + strlen (new_buf)] = '\0'; + backtrace_free (state, new_buf, new_len, error_callback, data); + filename = c; + new_buf = c; + new_len = clen; + } + } + + if (alc != NULL) + backtrace_free (state, alc, alc_len, error_callback, data); + alc = new_buf; + alc_len = new_len; + } + + /* Look for DEBUGLINK_NAME in the same directory as FILENAME. */ + + slash = strrchr (filename, '/'); + if (slash == NULL) + { + prefix = ""; + prefix_len = 0; + } + else + { + slash++; + prefix = filename; + prefix_len = slash - filename; + } + + ddescriptor = elf_try_debugfile (state, prefix, prefix_len, "", 0, + debuglink_name, error_callback, data); + if (ddescriptor >= 0) + { + ret = ddescriptor; + goto done; + } + + /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME. */ + + ddescriptor = elf_try_debugfile (state, prefix, prefix_len, ".debug/", + strlen (".debug/"), debuglink_name, + error_callback, data); + if (ddescriptor >= 0) + { + ret = ddescriptor; + goto done; + } + + /* Look for DEBUGLINK_NAME in /usr/lib/debug. */ + + ddescriptor = elf_try_debugfile (state, "/usr/lib/debug/", + strlen ("/usr/lib/debug/"), prefix, + prefix_len, debuglink_name, + error_callback, data); + if (ddescriptor >= 0) + ret = ddescriptor; + + done: + if (alc != NULL && alc_len > 0) + backtrace_free (state, alc, alc_len, error_callback, data); + return ret; +} + +/* Open a separate debug info file, using the debuglink section data + to find it. Returns an open file descriptor, or -1. */ + +static int +elf_open_debugfile_by_debuglink (struct backtrace_state *state, + const char *filename, + const char *debuglink_name, + uint32_t debuglink_crc, + backtrace_error_callback error_callback, + void *data) +{ + int ddescriptor; + + ddescriptor = elf_find_debugfile_by_debuglink (state, filename, + debuglink_name, + error_callback, data); + if (ddescriptor < 0) + return -1; + + if (debuglink_crc != 0) + { + uint32_t got_crc; + + got_crc = elf_crc32_file (state, ddescriptor, error_callback, data); + if (got_crc != debuglink_crc) + { + backtrace_close (ddescriptor, error_callback, data); + return -1; + } + } + + return ddescriptor; +} + +/* A function useful for setting a breakpoint for an inflation failure + when this code is compiled with -g. */ + +static void +elf_zlib_failed(void) +{ +} + +/* *PVAL is the current value being read from the stream, and *PBITS + is the number of valid bits. Ensure that *PVAL holds at least 15 + bits by reading additional bits from *PPIN, up to PINEND, as + needed. Updates *PPIN, *PVAL and *PBITS. Returns 1 on success, 0 + on error. */ + +static int +elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend, + uint64_t *pval, unsigned int *pbits) +{ + unsigned int bits; + const unsigned char *pin; + uint64_t val; + uint32_t next; + + bits = *pbits; + if (bits >= 15) + return 1; + pin = *ppin; + val = *pval; + + if (unlikely (pinend - pin < 4)) + { + elf_zlib_failed (); + return 0; + } + +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \ + && defined(__ORDER_BIG_ENDIAN__) \ + && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ \ + || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + /* We've ensured that PIN is aligned. */ + next = *(const uint32_t *)pin; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + next = __builtin_bswap32 (next); +#endif +#else + next = pin[0] | (pin[1] << 8) | (pin[2] << 16) | (pin[3] << 24); +#endif + + val |= (uint64_t)next << bits; + bits += 32; + pin += 4; + + /* We will need the next four bytes soon. */ + __builtin_prefetch (pin, 0, 0); + + *ppin = pin; + *pval = val; + *pbits = bits; + return 1; +} + +/* Huffman code tables, like the rest of the zlib format, are defined + by RFC 1951. We store a Huffman code table as a series of tables + stored sequentially in memory. Each entry in a table is 16 bits. + The first, main, table has 256 entries. It is followed by a set of + secondary tables of length 2 to 128 entries. The maximum length of + a code sequence in the deflate format is 15 bits, so that is all we + need. Each secondary table has an index, which is the offset of + the table in the overall memory storage. + + The deflate format says that all codes of a given bit length are + lexicographically consecutive. Perhaps we could have 130 values + that require a 15-bit code, perhaps requiring three secondary + tables of size 128. I don't know if this is actually possible, but + it suggests that the maximum size required for secondary tables is + 3 * 128 + 3 * 64 ... == 768. The zlib enough program reports 660 + as the maximum. We permit 768, since in addition to the 256 for + the primary table, with two bytes per entry, and with the two + tables we need, that gives us a page. + + A single table entry needs to store a value or (for the main table + only) the index and size of a secondary table. Values range from 0 + to 285, inclusive. Secondary table indexes, per above, range from + 0 to 510. For a value we need to store the number of bits we need + to determine that value (one value may appear multiple times in the + table), which is 1 to 8. For a secondary table we need to store + the number of bits used to index into the table, which is 1 to 7. + And of course we need 1 bit to decide whether we have a value or a + secondary table index. So each entry needs 9 bits for value/table + index, 3 bits for size, 1 bit what it is. For simplicity we use 16 + bits per entry. */ + +/* Number of entries we allocate to for one code table. We get a page + for the two code tables we need. */ + +#define HUFFMAN_TABLE_SIZE (1024) + +/* Bit masks and shifts for the values in the table. */ + +#define HUFFMAN_VALUE_MASK 0x01ff +#define HUFFMAN_BITS_SHIFT 9 +#define HUFFMAN_BITS_MASK 0x7 +#define HUFFMAN_SECONDARY_SHIFT 12 + +/* For working memory while inflating we need two code tables, we need + an array of code lengths (max value 15, so we use unsigned char), + and an array of unsigned shorts used while building a table. The + latter two arrays must be large enough to hold the maximum number + of code lengths, which RFC 1951 defines as 286 + 30. */ + +#define ZDEBUG_TABLE_SIZE \ + (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ + + (286 + 30) * sizeof (uint16_t) \ + + (286 + 30) * sizeof (unsigned char)) + +#define ZDEBUG_TABLE_CODELEN_OFFSET \ + (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ + + (286 + 30) * sizeof (uint16_t)) + +#define ZDEBUG_TABLE_WORK_OFFSET \ + (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t)) + +#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE + +/* Used by the main function that generates the fixed table to learn + the table size. */ +static size_t final_next_secondary; + +#endif + +/* Build a Huffman code table from an array of lengths in CODES of + length CODES_LEN. The table is stored into *TABLE. ZDEBUG_TABLE + is the same as for elf_zlib_inflate, used to find some work space. + Returns 1 on success, 0 on error. */ + +static int +elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, + uint16_t *zdebug_table, uint16_t *table) +{ + uint16_t count[16]; + uint16_t start[16]; + uint16_t prev[16]; + uint16_t firstcode[7]; + uint16_t *next; + size_t i; + size_t j; + unsigned int code; + size_t next_secondary; + + /* Count the number of code of each length. Set NEXT[val] to be the + next value after VAL with the same bit length. */ + + next = (uint16_t *) (((unsigned char *) zdebug_table) + + ZDEBUG_TABLE_WORK_OFFSET); + + memset (&count[0], 0, 16 * sizeof (uint16_t)); + for (i = 0; i < codes_len; ++i) + { + if (unlikely (codes[i] >= 16)) + { + elf_zlib_failed (); + return 0; + } + + if (count[codes[i]] == 0) + { + start[codes[i]] = i; + prev[codes[i]] = i; + } + else + { + next[prev[codes[i]]] = i; + prev[codes[i]] = i; + } + + ++count[codes[i]]; + } + + /* For each length, fill in the table for the codes of that + length. */ + + memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t)); + + /* Handle the values that do not require a secondary table. */ + + code = 0; + for (j = 1; j <= 8; ++j) + { + unsigned int jcnt; + unsigned int val; + + jcnt = count[j]; + if (jcnt == 0) + continue; + + if (unlikely (jcnt > (1U << j))) + { + elf_zlib_failed (); + return 0; + } + + /* There are JCNT values that have this length, the values + starting from START[j] continuing through NEXT[VAL]. Those + values are assigned consecutive values starting at CODE. */ + + val = start[j]; + for (i = 0; i < jcnt; ++i) + { + uint16_t tval; + size_t ind; + unsigned int incr; + + /* In the compressed bit stream, the value VAL is encoded as + J bits with the value C. */ + + if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0)) + { + elf_zlib_failed (); + return 0; + } + + tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT); + + /* The table lookup uses 8 bits. If J is less than 8, we + don't know what the other bits will be. We need to fill + in all possibilities in the table. Since the Huffman + code is unambiguous, those entries can't be used for any + other code. */ + + for (ind = code; ind < 0x100; ind += 1 << j) + { + if (unlikely (table[ind] != 0)) + { + elf_zlib_failed (); + return 0; + } + table[ind] = tval; + } + + /* Advance to the next value with this length. */ + if (i + 1 < jcnt) + val = next[val]; + + /* The Huffman codes are stored in the bitstream with the + most significant bit first, as is required to make them + unambiguous. The effect is that when we read them from + the bitstream we see the bit sequence in reverse order: + the most significant bit of the Huffman code is the least + significant bit of the value we read from the bitstream. + That means that to make our table lookups work, we need + to reverse the bits of CODE. Since reversing bits is + tedious and in general requires using a table, we instead + increment CODE in reverse order. That is, if the number + of bits we are currently using, here named J, is 3, we + count as 000, 100, 010, 110, 001, 101, 011, 111, which is + to say the numbers from 0 to 7 but with the bits + reversed. Going to more bits, aka incrementing J, + effectively just adds more zero bits as the beginning, + and as such does not change the numeric value of CODE. + + To increment CODE of length J in reverse order, find the + most significant zero bit and set it to one while + clearing all higher bits. In other words, add 1 modulo + 2^J, only reversed. */ + + incr = 1U << (j - 1); + while ((code & incr) != 0) + incr >>= 1; + if (incr == 0) + code = 0; + else + { + code &= incr - 1; + code += incr; + } + } + } + + /* Handle the values that require a secondary table. */ + + /* Set FIRSTCODE, the number at which the codes start, for each + length. */ + + for (j = 9; j < 16; j++) + { + unsigned int jcnt; + unsigned int k; + + jcnt = count[j]; + if (jcnt == 0) + continue; + + /* There are JCNT values that have this length, the values + starting from START[j]. Those values are assigned + consecutive values starting at CODE. */ + + firstcode[j - 9] = code; + + /* Reverse add JCNT to CODE modulo 2^J. */ + for (k = 0; k < j; ++k) + { + if ((jcnt & (1U << k)) != 0) + { + unsigned int m; + unsigned int bit; + + bit = 1U << (j - k - 1); + for (m = 0; m < j - k; ++m, bit >>= 1) + { + if ((code & bit) == 0) + { + code += bit; + break; + } + code &= ~bit; + } + jcnt &= ~(1U << k); + } + } + if (unlikely (jcnt != 0)) + { + elf_zlib_failed (); + return 0; + } + } + + /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive + values starting at START[J] with consecutive codes starting at + FIRSTCODE[J - 9]. In the primary table we need to point to the + secondary table, and the secondary table will be indexed by J - 9 + bits. We count down from 15 so that we install the larger + secondary tables first, as the smaller ones may be embedded in + the larger ones. */ + + next_secondary = 0; /* Index of next secondary table (after primary). */ + for (j = 15; j >= 9; j--) + { + unsigned int jcnt; + unsigned int val; + size_t primary; /* Current primary index. */ + size_t secondary; /* Offset to current secondary table. */ + size_t secondary_bits; /* Bit size of current secondary table. */ + + jcnt = count[j]; + if (jcnt == 0) + continue; + + val = start[j]; + code = firstcode[j - 9]; + primary = 0x100; + secondary = 0; + secondary_bits = 0; + for (i = 0; i < jcnt; ++i) + { + uint16_t tval; + size_t ind; + unsigned int incr; + + if ((code & 0xff) != primary) + { + uint16_t tprimary; + + /* Fill in a new primary table entry. */ + + primary = code & 0xff; + + tprimary = table[primary]; + if (tprimary == 0) + { + /* Start a new secondary table. */ + + if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK) + != next_secondary)) + { + elf_zlib_failed (); + return 0; + } + + secondary = next_secondary; + secondary_bits = j - 8; + next_secondary += 1 << secondary_bits; + table[primary] = (secondary + + ((j - 8) << HUFFMAN_BITS_SHIFT) + + (1U << HUFFMAN_SECONDARY_SHIFT)); + } + else + { + /* There is an existing entry. It had better be a + secondary table with enough bits. */ + if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT)) + == 0)) + { + elf_zlib_failed (); + return 0; + } + secondary = tprimary & HUFFMAN_VALUE_MASK; + secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT) + & HUFFMAN_BITS_MASK); + if (unlikely (secondary_bits < j - 8)) + { + elf_zlib_failed (); + return 0; + } + } + } + + /* Fill in secondary table entries. */ + + tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT); + + for (ind = code >> 8; + ind < (1U << secondary_bits); + ind += 1U << (j - 8)) + { + if (unlikely (table[secondary + 0x100 + ind] != 0)) + { + elf_zlib_failed (); + return 0; + } + table[secondary + 0x100 + ind] = tval; + } + + if (i + 1 < jcnt) + val = next[val]; + + incr = 1U << (j - 1); + while ((code & incr) != 0) + incr >>= 1; + if (incr == 0) + code = 0; + else + { + code &= incr - 1; + code += incr; + } + } + } + +#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE + final_next_secondary = next_secondary; +#endif + + return 1; +} + +#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE + +/* Used to generate the fixed Huffman table for block type 1. */ + +#include + +static uint16_t table[ZDEBUG_TABLE_SIZE]; +static unsigned char codes[288]; + +int +main () +{ + size_t i; + + for (i = 0; i <= 143; ++i) + codes[i] = 8; + for (i = 144; i <= 255; ++i) + codes[i] = 9; + for (i = 256; i <= 279; ++i) + codes[i] = 7; + for (i = 280; i <= 287; ++i) + codes[i] = 8; + if (!elf_zlib_inflate_table (&codes[0], 288, &table[0], &table[0])) + { + fprintf (stderr, "elf_zlib_inflate_table failed\n"); + exit (EXIT_FAILURE); + } + + printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n", + final_next_secondary + 0x100); + printf ("{\n"); + for (i = 0; i < final_next_secondary + 0x100; i += 8) + { + size_t j; + + printf (" "); + for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) + printf (" %#x,", table[j]); + printf ("\n"); + } + printf ("};\n"); + printf ("\n"); + + for (i = 0; i < 32; ++i) + codes[i] = 5; + if (!elf_zlib_inflate_table (&codes[0], 32, &table[0], &table[0])) + { + fprintf (stderr, "elf_zlib_inflate_table failed\n"); + exit (EXIT_FAILURE); + } + + printf ("static const uint16_t elf_zlib_default_dist_table[%#zx] =\n", + final_next_secondary + 0x100); + printf ("{\n"); + for (i = 0; i < final_next_secondary + 0x100; i += 8) + { + size_t j; + + printf (" "); + for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) + printf (" %#x,", table[j]); + printf ("\n"); + } + printf ("};\n"); + + return 0; +} + +#endif + +/* The fixed tables generated by the #ifdef'ed out main function + above. */ + +static const uint16_t elf_zlib_default_table[0x170] = +{ + 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230, + 0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250, + 0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240, + 0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260, + 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238, + 0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258, + 0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248, + 0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268, + 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234, + 0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254, + 0xd05, 0xe5a, 0xe1a, 0x1204, 0xd15, 0xe7a, 0xe3a, 0x1244, + 0xd0d, 0xe6a, 0xe2a, 0x1224, 0xe0a, 0xe8a, 0xe4a, 0x1264, + 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123c, + 0xd0b, 0xe66, 0xe26, 0x121c, 0xe06, 0xe86, 0xe46, 0x125c, + 0xd07, 0xe5e, 0xe1e, 0x120c, 0xd17, 0xe7e, 0xe3e, 0x124c, + 0xd0f, 0xe6e, 0xe2e, 0x122c, 0xe0e, 0xe8e, 0xe4e, 0x126c, + 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1232, + 0xd08, 0xe61, 0xe21, 0x1212, 0xe01, 0xe81, 0xe41, 0x1252, + 0xd04, 0xe59, 0xe19, 0x1202, 0xd14, 0xe79, 0xe39, 0x1242, + 0xd0c, 0xe69, 0xe29, 0x1222, 0xe09, 0xe89, 0xe49, 0x1262, + 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123a, + 0xd0a, 0xe65, 0xe25, 0x121a, 0xe05, 0xe85, 0xe45, 0x125a, + 0xd06, 0xe5d, 0xe1d, 0x120a, 0xd16, 0xe7d, 0xe3d, 0x124a, + 0xd0e, 0xe6d, 0xe2d, 0x122a, 0xe0d, 0xe8d, 0xe4d, 0x126a, + 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1236, + 0xd09, 0xe63, 0xe23, 0x1216, 0xe03, 0xe83, 0xe43, 0x1256, + 0xd05, 0xe5b, 0xe1b, 0x1206, 0xd15, 0xe7b, 0xe3b, 0x1246, + 0xd0d, 0xe6b, 0xe2b, 0x1226, 0xe0b, 0xe8b, 0xe4b, 0x1266, + 0xd03, 0xe57, 0xe17, 0xf1f, 0xd13, 0xe77, 0xe37, 0x123e, + 0xd0b, 0xe67, 0xe27, 0x121e, 0xe07, 0xe87, 0xe47, 0x125e, + 0xd07, 0xe5f, 0xe1f, 0x120e, 0xd17, 0xe7f, 0xe3f, 0x124e, + 0xd0f, 0xe6f, 0xe2f, 0x122e, 0xe0f, 0xe8f, 0xe4f, 0x126e, + 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, + 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, + 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, + 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, + 0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, + 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf, + 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, + 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf, + 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, + 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, + 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, + 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, + 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, + 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff, +}; + +static const uint16_t elf_zlib_default_dist_table[0x100] = +{ + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, + 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c, + 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e, + 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d, + 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f, +}; + +/* Inflate a zlib stream from PIN/SIN to POUT/SOUT. Return 1 on + success, 0 on some error parsing the stream. */ + +static int +elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, + unsigned char *pout, size_t sout) +{ + unsigned char *porigout; + const unsigned char *pinend; + unsigned char *poutend; + + /* We can apparently see multiple zlib streams concatenated + together, so keep going as long as there is something to read. + The last 4 bytes are the checksum. */ + porigout = pout; + pinend = pin + sin; + poutend = pout + sout; + while ((pinend - pin) > 4) + { + uint64_t val; + unsigned int bits; + int last; + + /* Read the two byte zlib header. */ + + if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */ + { + /* Unknown compression method. */ + elf_zlib_failed (); + return 0; + } + if (unlikely ((pin[0] >> 4) > 7)) + { + /* Window size too large. Other than this check, we don't + care about the window size. */ + elf_zlib_failed (); + return 0; + } + if (unlikely ((pin[1] & 0x20) != 0)) + { + /* Stream expects a predefined dictionary, but we have no + dictionary. */ + elf_zlib_failed (); + return 0; + } + val = (pin[0] << 8) | pin[1]; + if (unlikely (val % 31 != 0)) + { + /* Header check failure. */ + elf_zlib_failed (); + return 0; + } + pin += 2; + + /* Align PIN to a 32-bit boundary. */ + + val = 0; + bits = 0; + while ((((uintptr_t) pin) & 3) != 0) + { + val |= (uint64_t)*pin << bits; + bits += 8; + ++pin; + } + + /* Read blocks until one is marked last. */ + + last = 0; + + while (!last) + { + unsigned int type; + const uint16_t *tlit; + const uint16_t *tdist; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + last = val & 1; + type = (val >> 1) & 3; + val >>= 3; + bits -= 3; + + if (unlikely (type == 3)) + { + /* Invalid block type. */ + elf_zlib_failed (); + return 0; + } + + if (type == 0) + { + uint16_t len; + uint16_t lenc; + + /* An uncompressed block. */ + + /* If we've read ahead more than a byte, back up. */ + while (bits > 8) + { + --pin; + bits -= 8; + } + + val = 0; + bits = 0; + if (unlikely ((pinend - pin) < 4)) + { + /* Missing length. */ + elf_zlib_failed (); + return 0; + } + len = pin[0] | (pin[1] << 8); + lenc = pin[2] | (pin[3] << 8); + pin += 4; + lenc = ~lenc; + if (unlikely (len != lenc)) + { + /* Corrupt data. */ + elf_zlib_failed (); + return 0; + } + if (unlikely (len > (unsigned int) (pinend - pin) + || len > (unsigned int) (poutend - pout))) + { + /* Not enough space in buffers. */ + elf_zlib_failed (); + return 0; + } + memcpy (pout, pin, len); + pout += len; + pin += len; + + /* Align PIN. */ + while ((((uintptr_t) pin) & 3) != 0) + { + val |= (uint64_t)*pin << bits; + bits += 8; + ++pin; + } + + /* Go around to read the next block. */ + continue; + } + + if (type == 1) + { + tlit = elf_zlib_default_table; + tdist = elf_zlib_default_dist_table; + } + else + { + unsigned int nlit; + unsigned int ndist; + unsigned int nclen; + unsigned char codebits[19]; + unsigned char *plenbase; + unsigned char *plen; + unsigned char *plenend; + + /* Read a Huffman encoding table. The various magic + numbers here are from RFC 1951. */ + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + nlit = (val & 0x1f) + 257; + val >>= 5; + ndist = (val & 0x1f) + 1; + val >>= 5; + nclen = (val & 0xf) + 4; + val >>= 4; + bits -= 14; + if (unlikely (nlit > 286 || ndist > 30)) + { + /* Values out of range. */ + elf_zlib_failed (); + return 0; + } + + /* Read and build the table used to compress the + literal, length, and distance codes. */ + + memset(&codebits[0], 0, 19); + + /* There are always at least 4 elements in the + table. */ + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + codebits[16] = val & 7; + codebits[17] = (val >> 3) & 7; + codebits[18] = (val >> 6) & 7; + codebits[0] = (val >> 9) & 7; + val >>= 12; + bits -= 12; + + if (nclen == 4) + goto codebitsdone; + + codebits[8] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 5) + goto codebitsdone; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + codebits[7] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 6) + goto codebitsdone; + + codebits[9] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 7) + goto codebitsdone; + + codebits[6] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 8) + goto codebitsdone; + + codebits[10] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 9) + goto codebitsdone; + + codebits[5] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 10) + goto codebitsdone; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + codebits[11] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 11) + goto codebitsdone; + + codebits[4] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 12) + goto codebitsdone; + + codebits[12] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 13) + goto codebitsdone; + + codebits[3] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 14) + goto codebitsdone; + + codebits[13] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 15) + goto codebitsdone; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + codebits[2] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 16) + goto codebitsdone; + + codebits[14] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 17) + goto codebitsdone; + + codebits[1] = val & 7; + val >>= 3; + bits -= 3; + + if (nclen == 18) + goto codebitsdone; + + codebits[15] = val & 7; + val >>= 3; + bits -= 3; + + codebitsdone: + + if (!elf_zlib_inflate_table (codebits, 19, zdebug_table, + zdebug_table)) + return 0; + + /* Read the compressed bit lengths of the literal, + length, and distance codes. We have allocated space + at the end of zdebug_table to hold them. */ + + plenbase = (((unsigned char *) zdebug_table) + + ZDEBUG_TABLE_CODELEN_OFFSET); + plen = plenbase; + plenend = plen + nlit + ndist; + while (plen < plenend) + { + uint16_t t; + unsigned int b; + uint16_t v; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + t = zdebug_table[val & 0xff]; + + /* The compression here uses bit lengths up to 7, so + a secondary table is never necessary. */ + if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0)) + { + elf_zlib_failed (); + return 0; + } + + b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; + val >>= b + 1; + bits -= b + 1; + + v = t & HUFFMAN_VALUE_MASK; + if (v < 16) + *plen++ = v; + else if (v == 16) + { + unsigned int c; + unsigned int prev; + + /* Copy previous entry 3 to 6 times. */ + + if (unlikely (plen == plenbase)) + { + elf_zlib_failed (); + return 0; + } + + /* We used up to 7 bits since the last + elf_zlib_fetch, so we have at least 8 bits + available here. */ + + c = 3 + (val & 0x3); + val >>= 2; + bits -= 2; + if (unlikely ((unsigned int) (plenend - plen) < c)) + { + elf_zlib_failed (); + return 0; + } + + prev = plen[-1]; + switch (c) + { + case 6: + *plen++ = prev; + /* fallthrough */ + case 5: + *plen++ = prev; + /* fallthrough */ + case 4: + *plen++ = prev; + } + *plen++ = prev; + *plen++ = prev; + *plen++ = prev; + } + else if (v == 17) + { + unsigned int c; + + /* Store zero 3 to 10 times. */ + + /* We used up to 7 bits since the last + elf_zlib_fetch, so we have at least 8 bits + available here. */ + + c = 3 + (val & 0x7); + val >>= 3; + bits -= 3; + if (unlikely ((unsigned int) (plenend - plen) < c)) + { + elf_zlib_failed (); + return 0; + } + + switch (c) + { + case 10: + *plen++ = 0; + /* fallthrough */ + case 9: + *plen++ = 0; + /* fallthrough */ + case 8: + *plen++ = 0; + /* fallthrough */ + case 7: + *plen++ = 0; + /* fallthrough */ + case 6: + *plen++ = 0; + /* fallthrough */ + case 5: + *plen++ = 0; + /* fallthrough */ + case 4: + *plen++ = 0; + } + *plen++ = 0; + *plen++ = 0; + *plen++ = 0; + } + else if (v == 18) + { + unsigned int c; + + /* Store zero 11 to 138 times. */ + + /* We used up to 7 bits since the last + elf_zlib_fetch, so we have at least 8 bits + available here. */ + + c = 11 + (val & 0x7f); + val >>= 7; + bits -= 7; + if (unlikely ((unsigned int) (plenend - plen) < c)) + { + elf_zlib_failed (); + return 0; + } + + memset (plen, 0, c); + plen += c; + } + else + { + elf_zlib_failed (); + return 0; + } + } + + /* Make sure that the stop code can appear. */ + + plen = plenbase; + if (unlikely (plen[256] == 0)) + { + elf_zlib_failed (); + return 0; + } + + /* Build the decompression tables. */ + + if (!elf_zlib_inflate_table (plen, nlit, zdebug_table, + zdebug_table)) + return 0; + if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table, + zdebug_table + HUFFMAN_TABLE_SIZE)) + return 0; + tlit = zdebug_table; + tdist = zdebug_table + HUFFMAN_TABLE_SIZE; + } + + /* Inflate values until the end of the block. This is the + main loop of the inflation code. */ + + while (1) + { + uint16_t t; + unsigned int b; + uint16_t v; + unsigned int lit; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + t = tlit[val & 0xff]; + b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; + v = t & HUFFMAN_VALUE_MASK; + + if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) + { + lit = v; + val >>= b + 1; + bits -= b + 1; + } + else + { + t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; + b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; + lit = t & HUFFMAN_VALUE_MASK; + val >>= b + 8; + bits -= b + 8; + } + + if (lit < 256) + { + if (unlikely (pout == poutend)) + { + elf_zlib_failed (); + return 0; + } + + *pout++ = lit; + + /* We will need to write the next byte soon. We ask + for high temporal locality because we will write + to the whole cache line soon. */ + __builtin_prefetch (pout, 1, 3); + } + else if (lit == 256) + { + /* The end of the block. */ + break; + } + else + { + unsigned int dist; + unsigned int len; + + /* Convert lit into a length. */ + + if (lit < 265) + len = lit - 257 + 3; + else if (lit == 285) + len = 258; + else if (unlikely (lit > 285)) + { + elf_zlib_failed (); + return 0; + } + else + { + unsigned int extra; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + /* This is an expression for the table of length + codes in RFC 1951 3.2.5. */ + lit -= 265; + extra = (lit >> 2) + 1; + len = (lit & 3) << extra; + len += 11; + len += ((1U << (extra - 1)) - 1) << 3; + len += val & ((1U << extra) - 1); + val >>= extra; + bits -= extra; + } + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + t = tdist[val & 0xff]; + b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; + v = t & HUFFMAN_VALUE_MASK; + + if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) + { + dist = v; + val >>= b + 1; + bits -= b + 1; + } + else + { + t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; + b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; + dist = t & HUFFMAN_VALUE_MASK; + val >>= b + 8; + bits -= b + 8; + } + + /* Convert dist to a distance. */ + + if (dist == 0) + { + /* A distance of 1. A common case, meaning + repeat the last character LEN times. */ + + if (unlikely (pout == porigout)) + { + elf_zlib_failed (); + return 0; + } + + if (unlikely ((unsigned int) (poutend - pout) < len)) + { + elf_zlib_failed (); + return 0; + } + + memset (pout, pout[-1], len); + pout += len; + } + else if (unlikely (dist > 29)) + { + elf_zlib_failed (); + return 0; + } + else + { + if (dist < 4) + dist = dist + 1; + else + { + unsigned int extra; + + if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) + return 0; + + /* This is an expression for the table of + distance codes in RFC 1951 3.2.5. */ + dist -= 4; + extra = (dist >> 1) + 1; + dist = (dist & 1) << extra; + dist += 5; + dist += ((1U << (extra - 1)) - 1) << 2; + dist += val & ((1U << extra) - 1); + val >>= extra; + bits -= extra; + } + + /* Go back dist bytes, and copy len bytes from + there. */ + + if (unlikely ((unsigned int) (pout - porigout) < dist)) + { + elf_zlib_failed (); + return 0; + } + + if (unlikely ((unsigned int) (poutend - pout) < len)) + { + elf_zlib_failed (); + return 0; + } + + if (dist >= len) + { + memcpy (pout, pout - dist, len); + pout += len; + } + else + { + while (len > 0) + { + unsigned int copy; + + copy = len < dist ? len : dist; + memcpy (pout, pout - dist, copy); + len -= copy; + pout += copy; + } + } + } + } + } + } + } + + /* We should have filled the output buffer. */ + if (unlikely (pout != poutend)) + { + elf_zlib_failed (); + return 0; + } + + return 1; +} + +/* Verify the zlib checksum. The checksum is in the 4 bytes at + CHECKBYTES, and the uncompressed data is at UNCOMPRESSED / + UNCOMPRESSED_SIZE. Returns 1 on success, 0 on failure. */ + +static int +elf_zlib_verify_checksum (const unsigned char *checkbytes, + const unsigned char *uncompressed, + size_t uncompressed_size) +{ + unsigned int i; + unsigned int cksum; + const unsigned char *p; + uint32_t s1; + uint32_t s2; + size_t hsz; + + cksum = 0; + for (i = 0; i < 4; i++) + cksum = (cksum << 8) | checkbytes[i]; + + s1 = 1; + s2 = 0; + + /* Minimize modulo operations. */ + + p = uncompressed; + hsz = uncompressed_size; + while (hsz >= 5552) + { + for (i = 0; i < 5552; i += 16) + { + /* Manually unroll loop 16 times. */ + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + } + hsz -= 5552; + s1 %= 65521; + s2 %= 65521; + } + + while (hsz >= 16) + { + /* Manually unroll loop 16 times. */ + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + s1 = s1 + *p++; + s2 = s2 + s1; + + hsz -= 16; + } + + for (i = 0; i < hsz; ++i) + { + s1 = s1 + *p++; + s2 = s2 + s1; + } + + s1 %= 65521; + s2 %= 65521; + + if (unlikely ((s2 << 16) + s1 != cksum)) + { + elf_zlib_failed (); + return 0; + } + + return 1; +} + +/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the + checksum. Return 1 on success, 0 on error. */ + +static int +elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin, + uint16_t *zdebug_table, unsigned char *pout, + size_t sout) +{ + if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout)) + return 0; + if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout)) + return 0; + return 1; +} + +/* Uncompress the old compressed debug format, the one emitted by + --compress-debug-sections=zlib-gnu. The compressed data is in + COMPRESSED / COMPRESSED_SIZE, and the function writes to + *UNCOMPRESSED / *UNCOMPRESSED_SIZE. ZDEBUG_TABLE is work space to + hold Huffman tables. Returns 0 on error, 1 on successful + decompression or if something goes wrong. In general we try to + carry on, by returning 1, even if we can't decompress. */ + +static int +elf_uncompress_zdebug (struct backtrace_state *state, + const unsigned char *compressed, size_t compressed_size, + uint16_t *zdebug_table, + backtrace_error_callback error_callback, void *data, + unsigned char **uncompressed, size_t *uncompressed_size) +{ + size_t sz; + size_t i; + unsigned char *po; + + *uncompressed = NULL; + *uncompressed_size = 0; + + /* The format starts with the four bytes ZLIB, followed by the 8 + byte length of the uncompressed data in big-endian order, + followed by a zlib stream. */ + + if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0) + return 1; + + sz = 0; + for (i = 0; i < 8; i++) + sz = (sz << 8) | compressed[i + 4]; + + if (*uncompressed != NULL && *uncompressed_size >= sz) + po = *uncompressed; + else + { + po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data); + if (po == NULL) + return 0; + } + + if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12, + zdebug_table, po, sz)) + return 1; + + *uncompressed = po; + *uncompressed_size = sz; + + return 1; +} + +/* Uncompress the new compressed debug format, the official standard + ELF approach emitted by --compress-debug-sections=zlib-gabi. The + compressed data is in COMPRESSED / COMPRESSED_SIZE, and the + function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE. + ZDEBUG_TABLE is work space as for elf_uncompress_zdebug. Returns 0 + on error, 1 on successful decompression or if something goes wrong. + In general we try to carry on, by returning 1, even if we can't + decompress. */ + +static int +elf_uncompress_chdr (struct backtrace_state *state, + const unsigned char *compressed, size_t compressed_size, + uint16_t *zdebug_table, + backtrace_error_callback error_callback, void *data, + unsigned char **uncompressed, size_t *uncompressed_size) +{ + const b_elf_chdr *chdr; + unsigned char *po; + + *uncompressed = NULL; + *uncompressed_size = 0; + + /* The format starts with an ELF compression header. */ + if (compressed_size < sizeof (b_elf_chdr)) + return 1; + + chdr = (const b_elf_chdr *) compressed; + + if (chdr->ch_type != ELFCOMPRESS_ZLIB) + { + /* Unsupported compression algorithm. */ + return 1; + } + + if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size) + po = *uncompressed; + else + { + po = (unsigned char *) backtrace_alloc (state, chdr->ch_size, + error_callback, data); + if (po == NULL) + return 0; + } + + if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr), + compressed_size - sizeof (b_elf_chdr), + zdebug_table, po, chdr->ch_size)) + return 1; + + *uncompressed = po; + *uncompressed_size = chdr->ch_size; + + return 1; +} + +/* This function is a hook for testing the zlib support. It is only + used by tests. */ + +int +backtrace_uncompress_zdebug (struct backtrace_state *state, + const unsigned char *compressed, + size_t compressed_size, + backtrace_error_callback error_callback, + void *data, unsigned char **uncompressed, + size_t *uncompressed_size) +{ + uint16_t *zdebug_table; + int ret; + + zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE, + error_callback, data)); + if (zdebug_table == NULL) + return 0; + ret = elf_uncompress_zdebug (state, compressed, compressed_size, + zdebug_table, error_callback, data, + uncompressed, uncompressed_size); + backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, + error_callback, data); + return ret; +} + +/* Add the backtrace data for one ELF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed) or -1 if exe + is non-zero and the ELF file is ET_DYN, which tells the caller that + elf_add will need to be called on the descriptor again after + base_address is determined. */ + +static int +elf_add (struct backtrace_state *state, const char *filename, int descriptor, + uintptr_t base_address, backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, + struct dwarf_data **fileline_entry, int exe, int debuginfo, + const char *with_buildid_data, uint32_t with_buildid_size) +{ + struct backtrace_view ehdr_view; + b_elf_ehdr ehdr; + off_t shoff; + unsigned int shnum; + unsigned int shstrndx; + struct backtrace_view shdrs_view; + int shdrs_view_valid; + const b_elf_shdr *shdrs; + const b_elf_shdr *shstrhdr; + size_t shstr_size; + off_t shstr_off; + struct backtrace_view names_view; + int names_view_valid; + const char *names; + unsigned int symtab_shndx; + unsigned int dynsym_shndx; + unsigned int i; + struct debug_section_info sections[DEBUG_MAX]; + struct debug_section_info zsections[DEBUG_MAX]; + struct backtrace_view symtab_view; + int symtab_view_valid; + struct backtrace_view strtab_view; + int strtab_view_valid; + struct backtrace_view buildid_view; + int buildid_view_valid; + const char *buildid_data; + uint32_t buildid_size; + struct backtrace_view debuglink_view; + int debuglink_view_valid; + const char *debuglink_name; + uint32_t debuglink_crc; + struct backtrace_view debugaltlink_view; + int debugaltlink_view_valid; + const char *debugaltlink_name; + const char *debugaltlink_buildid_data; + uint32_t debugaltlink_buildid_size; + off_t min_offset; + off_t max_offset; + struct backtrace_view debug_view; + int debug_view_valid; + unsigned int using_debug_view; + uint16_t *zdebug_table; + struct elf_ppc64_opd_data opd_data, *opd; + struct dwarf_sections dwarf_sections; + + if (!debuginfo) + { + *found_sym = 0; + *found_dwarf = 0; + } + + shdrs_view_valid = 0; + names_view_valid = 0; + symtab_view_valid = 0; + strtab_view_valid = 0; + buildid_view_valid = 0; + buildid_data = NULL; + buildid_size = 0; + debuglink_view_valid = 0; + debuglink_name = NULL; + debuglink_crc = 0; + debugaltlink_view_valid = 0; + debugaltlink_name = NULL; + debugaltlink_buildid_data = NULL; + debugaltlink_buildid_size = 0; + debug_view_valid = 0; + opd = NULL; + + if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, + data, &ehdr_view)) + goto fail; + + memcpy (&ehdr, ehdr_view.data, sizeof ehdr); + + backtrace_release_view (state, &ehdr_view, error_callback, data); + + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 + || ehdr.e_ident[EI_MAG1] != ELFMAG1 + || ehdr.e_ident[EI_MAG2] != ELFMAG2 + || ehdr.e_ident[EI_MAG3] != ELFMAG3) + { + error_callback (data, "executable file is not ELF", 0); + goto fail; + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) + { + error_callback (data, "executable file is unrecognized ELF version", 0); + goto fail; + } + +#if BACKTRACE_ELF_SIZE == 32 +#define BACKTRACE_ELFCLASS ELFCLASS32 +#else +#define BACKTRACE_ELFCLASS ELFCLASS64 +#endif + + if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) + { + error_callback (data, "executable file is unexpected ELF class", 0); + goto fail; + } + + if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB + && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) + { + error_callback (data, "executable file has unknown endianness", 0); + goto fail; + } + + /* If the executable is ET_DYN, it is either a PIE, or we are running + directly a shared library with .interp. We need to wait for + dl_iterate_phdr in that case to determine the actual base_address. */ + if (exe && ehdr.e_type == ET_DYN) + return -1; + + shoff = ehdr.e_shoff; + shnum = ehdr.e_shnum; + shstrndx = ehdr.e_shstrndx; + + if ((shnum == 0 || shstrndx == SHN_XINDEX) + && shoff != 0) + { + struct backtrace_view shdr_view; + const b_elf_shdr *shdr; + + if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, + error_callback, data, &shdr_view)) + goto fail; + + shdr = (const b_elf_shdr *) shdr_view.data; + + if (shnum == 0) + shnum = shdr->sh_size; + + if (shstrndx == SHN_XINDEX) + { + shstrndx = shdr->sh_link; + + /* Versions of the GNU binutils between 2.12 and 2.18 did + not handle objects with more than SHN_LORESERVE sections + correctly. All large section indexes were offset by + 0x100. There is more information at + http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . + Fortunately these object files are easy to detect, as the + GNU binutils always put the section header string table + near the end of the list of sections. Thus if the + section header string table index is larger than the + number of sections, then we know we have to subtract + 0x100 to get the real section index. */ + if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) + shstrndx -= 0x100; + } + + backtrace_release_view (state, &shdr_view, error_callback, data); + } + + /* To translate PC to file/line when using DWARF, we need to find + the .debug_info and .debug_line sections. */ + + /* Read the section headers, skipping the first one. */ + + if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), + (shnum - 1) * sizeof (b_elf_shdr), + error_callback, data, &shdrs_view)) + goto fail; + shdrs_view_valid = 1; + shdrs = (const b_elf_shdr *) shdrs_view.data; + + /* Read the section names. */ + + shstrhdr = &shdrs[shstrndx - 1]; + shstr_size = shstrhdr->sh_size; + shstr_off = shstrhdr->sh_offset; + + if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size, + error_callback, data, &names_view)) + goto fail; + names_view_valid = 1; + names = (const char *) names_view.data; + + symtab_shndx = 0; + dynsym_shndx = 0; + + memset (sections, 0, sizeof sections); + memset (zsections, 0, sizeof zsections); + + /* Look for the symbol table. */ + for (i = 1; i < shnum; ++i) + { + const b_elf_shdr *shdr; + unsigned int sh_name; + const char *name; + int j; + + shdr = &shdrs[i - 1]; + + if (shdr->sh_type == SHT_SYMTAB) + symtab_shndx = i; + else if (shdr->sh_type == SHT_DYNSYM) + dynsym_shndx = i; + + sh_name = shdr->sh_name; + if (sh_name >= shstr_size) + { + error_callback (data, "ELF section name out of range", 0); + goto fail; + } + + name = names + sh_name; + + for (j = 0; j < (int) DEBUG_MAX; ++j) + { + if (strcmp (name, dwarf_section_names[j]) == 0) + { + sections[j].offset = shdr->sh_offset; + sections[j].size = shdr->sh_size; + sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0; + break; + } + } + + if (name[0] == '.' && name[1] == 'z') + { + for (j = 0; j < (int) DEBUG_MAX; ++j) + { + if (strcmp (name + 2, dwarf_section_names[j] + 1) == 0) + { + zsections[j].offset = shdr->sh_offset; + zsections[j].size = shdr->sh_size; + break; + } + } + } + + /* Read the build ID if present. This could check for any + SHT_NOTE section with the right note name and type, but gdb + looks for a specific section name. */ + if ((!debuginfo || with_buildid_data != NULL) + && !buildid_view_valid + && strcmp (name, ".note.gnu.build-id") == 0) + { + const b_elf_note *note; + + if (!backtrace_get_view (state, descriptor, shdr->sh_offset, + shdr->sh_size, error_callback, data, + &buildid_view)) + goto fail; + + buildid_view_valid = 1; + note = (const b_elf_note *) buildid_view.data; + if (note->type == NT_GNU_BUILD_ID + && note->namesz == 4 + && strncmp (note->name, "GNU", 4) == 0 + && shdr->sh_size <= 12 + ((note->namesz + 3) & ~ 3) + note->descsz) + { + buildid_data = ¬e->name[0] + ((note->namesz + 3) & ~ 3); + buildid_size = note->descsz; + } + + if (with_buildid_size != 0) + { + if (buildid_size != with_buildid_size) + goto fail; + + if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0) + goto fail; + } + } + + /* Read the debuglink file if present. */ + if (!debuginfo + && !debuglink_view_valid + && strcmp (name, ".gnu_debuglink") == 0) + { + const char *debuglink_data; + size_t crc_offset; + + if (!backtrace_get_view (state, descriptor, shdr->sh_offset, + shdr->sh_size, error_callback, data, + &debuglink_view)) + goto fail; + + debuglink_view_valid = 1; + debuglink_data = (const char *) debuglink_view.data; + crc_offset = strnlen (debuglink_data, shdr->sh_size); + crc_offset = (crc_offset + 3) & ~3; + if (crc_offset + 4 <= shdr->sh_size) + { + debuglink_name = debuglink_data; + debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset); + } + } + + if (!debugaltlink_view_valid + && strcmp (name, ".gnu_debugaltlink") == 0) + { + const char *debugaltlink_data; + size_t debugaltlink_name_len; + + if (!backtrace_get_view (state, descriptor, shdr->sh_offset, + shdr->sh_size, error_callback, data, + &debugaltlink_view)) + goto fail; + + debugaltlink_view_valid = 1; + debugaltlink_data = (const char *) debugaltlink_view.data; + debugaltlink_name = debugaltlink_data; + debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size); + if (debugaltlink_name_len < shdr->sh_size) + { + /* Include terminating zero. */ + debugaltlink_name_len += 1; + + debugaltlink_buildid_data + = debugaltlink_data + debugaltlink_name_len; + debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len; + } + } + + /* Read the .opd section on PowerPC64 ELFv1. */ + if (ehdr.e_machine == EM_PPC64 + && (ehdr.e_flags & EF_PPC64_ABI) < 2 + && shdr->sh_type == SHT_PROGBITS + && strcmp (name, ".opd") == 0) + { + if (!backtrace_get_view (state, descriptor, shdr->sh_offset, + shdr->sh_size, error_callback, data, + &opd_data.view)) + goto fail; + + opd = &opd_data; + opd->addr = shdr->sh_addr; + opd->data = (const char *) opd_data.view.data; + opd->size = shdr->sh_size; + } + } + + if (symtab_shndx == 0) + symtab_shndx = dynsym_shndx; + if (symtab_shndx != 0 && !debuginfo) + { + const b_elf_shdr *symtab_shdr; + unsigned int strtab_shndx; + const b_elf_shdr *strtab_shdr; + struct elf_syminfo_data *sdata; + + symtab_shdr = &shdrs[symtab_shndx - 1]; + strtab_shndx = symtab_shdr->sh_link; + if (strtab_shndx >= shnum) + { + error_callback (data, + "ELF symbol table strtab link out of range", 0); + goto fail; + } + strtab_shdr = &shdrs[strtab_shndx - 1]; + + if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, + symtab_shdr->sh_size, error_callback, data, + &symtab_view)) + goto fail; + symtab_view_valid = 1; + + if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, + strtab_shdr->sh_size, error_callback, data, + &strtab_view)) + goto fail; + strtab_view_valid = 1; + + sdata = ((struct elf_syminfo_data *) + backtrace_alloc (state, sizeof *sdata, error_callback, data)); + if (sdata == NULL) + goto fail; + + if (!elf_initialize_syminfo (state, base_address, + symtab_view.data, symtab_shdr->sh_size, + strtab_view.data, strtab_shdr->sh_size, + error_callback, data, sdata, opd)) + { + backtrace_free (state, sdata, sizeof *sdata, error_callback, data); + goto fail; + } + + /* We no longer need the symbol table, but we hold on to the + string table permanently. */ + backtrace_release_view (state, &symtab_view, error_callback, data); + symtab_view_valid = 0; + + *found_sym = 1; + + elf_add_syminfo_data (state, sdata); + } + + backtrace_release_view (state, &shdrs_view, error_callback, data); + shdrs_view_valid = 0; + backtrace_release_view (state, &names_view, error_callback, data); + names_view_valid = 0; + + /* If the debug info is in a separate file, read that one instead. */ + + if (buildid_data != NULL) + { + int d; + + d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size, + error_callback, data); + if (d >= 0) + { + int ret; + + backtrace_release_view (state, &buildid_view, error_callback, data); + if (debuglink_view_valid) + backtrace_release_view (state, &debuglink_view, error_callback, + data); + if (debugaltlink_view_valid) + backtrace_release_view (state, &debugaltlink_view, error_callback, + data); + ret = elf_add (state, "", d, base_address, error_callback, data, + fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, + 0); + if (ret < 0) + backtrace_close (d, error_callback, data); + else + backtrace_close (descriptor, error_callback, data); + return ret; + } + } + + if (buildid_view_valid) + { + backtrace_release_view (state, &buildid_view, error_callback, data); + buildid_view_valid = 0; + } + + if (opd) + { + backtrace_release_view (state, &opd->view, error_callback, data); + opd = NULL; + } + + if (debuglink_name != NULL) + { + int d; + + d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name, + debuglink_crc, error_callback, + data); + if (d >= 0) + { + int ret; + + backtrace_release_view (state, &debuglink_view, error_callback, + data); + if (debugaltlink_view_valid) + backtrace_release_view (state, &debugaltlink_view, error_callback, + data); + ret = elf_add (state, "", d, base_address, error_callback, data, + fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, + 0); + if (ret < 0) + backtrace_close (d, error_callback, data); + else + backtrace_close(descriptor, error_callback, data); + return ret; + } + } + + if (debuglink_view_valid) + { + backtrace_release_view (state, &debuglink_view, error_callback, data); + debuglink_view_valid = 0; + } + + struct dwarf_data *fileline_altlink = NULL; + if (debugaltlink_name != NULL) + { + int d; + + d = elf_open_debugfile_by_debuglink (state, filename, debugaltlink_name, + 0, error_callback, data); + if (d >= 0) + { + int ret; + + ret = elf_add (state, filename, d, base_address, error_callback, data, + fileline_fn, found_sym, found_dwarf, &fileline_altlink, + 0, 1, debugaltlink_buildid_data, + debugaltlink_buildid_size); + backtrace_release_view (state, &debugaltlink_view, error_callback, + data); + debugaltlink_view_valid = 0; + if (ret < 0) + { + backtrace_close (d, error_callback, data); + return ret; + } + } + } + + if (debugaltlink_view_valid) + { + backtrace_release_view (state, &debugaltlink_view, error_callback, data); + debugaltlink_view_valid = 0; + } + + /* Read all the debug sections in a single view, since they are + probably adjacent in the file. If any of sections are + uncompressed, we never release this view. */ + + min_offset = 0; + max_offset = 0; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + off_t end; + + if (sections[i].size != 0) + { + if (min_offset == 0 || sections[i].offset < min_offset) + min_offset = sections[i].offset; + end = sections[i].offset + sections[i].size; + if (end > max_offset) + max_offset = end; + } + if (zsections[i].size != 0) + { + if (min_offset == 0 || zsections[i].offset < min_offset) + min_offset = zsections[i].offset; + end = zsections[i].offset + zsections[i].size; + if (end > max_offset) + max_offset = end; + } + } + if (min_offset == 0 || max_offset == 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + return 1; + } + + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, &debug_view)) + goto fail; + debug_view_valid = 1; + + /* We've read all we need from the executable. */ + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + + using_debug_view = 0; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (sections[i].size == 0) + sections[i].data = NULL; + else + { + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + ++using_debug_view; + } + + if (zsections[i].size == 0) + zsections[i].data = NULL; + else + zsections[i].data = ((const unsigned char *) debug_view.data + + (zsections[i].offset - min_offset)); + } + + /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */ + + zdebug_table = NULL; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (sections[i].size == 0 && zsections[i].size > 0) + { + unsigned char *uncompressed_data; + size_t uncompressed_size; + + if (zdebug_table == NULL) + { + zdebug_table = ((uint16_t *) + backtrace_alloc (state, ZDEBUG_TABLE_SIZE, + error_callback, data)); + if (zdebug_table == NULL) + goto fail; + } + + uncompressed_data = NULL; + uncompressed_size = 0; + if (!elf_uncompress_zdebug (state, zsections[i].data, + zsections[i].size, zdebug_table, + error_callback, data, + &uncompressed_data, &uncompressed_size)) + goto fail; + sections[i].data = uncompressed_data; + sections[i].size = uncompressed_size; + sections[i].compressed = 0; + } + } + + /* Uncompress the official ELF format + (--compress-debug-sections=zlib-gabi). */ + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + unsigned char *uncompressed_data; + size_t uncompressed_size; + + if (sections[i].size == 0 || !sections[i].compressed) + continue; + + if (zdebug_table == NULL) + { + zdebug_table = ((uint16_t *) + backtrace_alloc (state, ZDEBUG_TABLE_SIZE, + error_callback, data)); + if (zdebug_table == NULL) + goto fail; + } + + uncompressed_data = NULL; + uncompressed_size = 0; + if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size, + zdebug_table, error_callback, data, + &uncompressed_data, &uncompressed_size)) + goto fail; + sections[i].data = uncompressed_data; + sections[i].size = uncompressed_size; + sections[i].compressed = 0; + + --using_debug_view; + } + + if (zdebug_table != NULL) + backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, + error_callback, data); + + if (debug_view_valid && using_debug_view == 0) + { + backtrace_release_view (state, &debug_view, error_callback, data); + debug_view_valid = 0; + } + + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + dwarf_sections.data[i] = sections[i].data; + dwarf_sections.size[i] = sections[i].size; + } + + if (!backtrace_dwarf_add (state, base_address, &dwarf_sections, + ehdr.e_ident[EI_DATA] == ELFDATA2MSB, + fileline_altlink, + error_callback, data, fileline_fn, + fileline_entry)) + goto fail; + + *found_dwarf = 1; + + return 1; + + fail: + if (shdrs_view_valid) + backtrace_release_view (state, &shdrs_view, error_callback, data); + if (names_view_valid) + backtrace_release_view (state, &names_view, error_callback, data); + if (symtab_view_valid) + backtrace_release_view (state, &symtab_view, error_callback, data); + if (strtab_view_valid) + backtrace_release_view (state, &strtab_view, error_callback, data); + if (debuglink_view_valid) + backtrace_release_view (state, &debuglink_view, error_callback, data); + if (debugaltlink_view_valid) + backtrace_release_view (state, &debugaltlink_view, error_callback, data); + if (buildid_view_valid) + backtrace_release_view (state, &buildid_view, error_callback, data); + if (debug_view_valid) + backtrace_release_view (state, &debug_view, error_callback, data); + if (opd) + backtrace_release_view (state, &opd->view, error_callback, data); + if (descriptor != -1) + backtrace_close (descriptor, error_callback, data); + return 0; +} + +/* Data passed to phdr_callback. */ + +struct phdr_data +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; + fileline *fileline_fn; + int *found_sym; + int *found_dwarf; + const char *exe_filename; + int exe_descriptor; +}; + +/* Callback passed to dl_iterate_phdr. Load debug info from shared + libraries. */ + +static int +#ifdef __i386__ +__attribute__ ((__force_align_arg_pointer__)) +#endif +phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, + void *pdata) +{ + struct phdr_data *pd = (struct phdr_data *) pdata; + const char *filename; + int descriptor; + int does_not_exist; + fileline elf_fileline_fn; + int found_dwarf; + + /* There is not much we can do if we don't have the module name, + unless executable is ET_DYN, where we expect the very first + phdr_callback to be for the PIE. */ + if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') + { + if (pd->exe_descriptor == -1) + return 0; + filename = pd->exe_filename; + descriptor = pd->exe_descriptor; + pd->exe_descriptor = -1; + } + else + { + if (pd->exe_descriptor != -1) + { + backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); + pd->exe_descriptor = -1; + } + + filename = info->dlpi_name; + descriptor = backtrace_open (info->dlpi_name, pd->error_callback, + pd->data, &does_not_exist); + if (descriptor < 0) + return 0; + } + + if (elf_add (pd->state, filename, descriptor, info->dlpi_addr, + pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym, + &found_dwarf, NULL, 0, 0, NULL, 0)) + { + if (found_dwarf) + { + *pd->found_dwarf = 1; + *pd->fileline_fn = elf_fileline_fn; + } + } + + return 0; +} + +/* Initialize the backtrace data we need from an ELF executable. At + the ELF level, all we need to do is find the debug info + sections. */ + +int +backtrace_initialize (struct backtrace_state *state, const char *filename, + int descriptor, backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + int found_sym; + int found_dwarf; + fileline elf_fileline_fn = elf_nodebug; + struct phdr_data pd; + + ret = elf_add (state, filename, descriptor, 0, error_callback, data, + &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL, + 0); + if (!ret) + return 0; + + pd.state = state; + pd.error_callback = error_callback; + pd.data = data; + pd.fileline_fn = &elf_fileline_fn; + pd.found_sym = &found_sym; + pd.found_dwarf = &found_dwarf; + pd.exe_filename = filename; + pd.exe_descriptor = ret < 0 ? descriptor : -1; + + dl_iterate_phdr (phdr_callback, (void *) &pd); + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = elf_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = elf_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); + else + (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, + elf_nosyms); + } + + if (!state->threaded) + *fileline_fn = state->fileline_fn; + else + *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + + if (*fileline_fn == NULL || *fileline_fn == elf_nodebug) + *fileline_fn = elf_fileline_fn; + + return 1; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/fileline.c b/src/3rdparty/libbacktrace/libbacktrace/fileline.c new file mode 100644 index 00000000..369c9dee --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/fileline.c @@ -0,0 +1,201 @@ +/* fileline.c -- Get file and line number information in a backtrace. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef HAVE_GETEXECNAME +#define getexecname() NULL +#endif + +/* Initialize the fileline information from the executable. Returns 1 + on success, 0 on failure. */ + +static int +fileline_initialize (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + int failed; + fileline fileline_fn; + int pass; + int called_error_callback; + int descriptor; + const char *filename; + char buf[64]; + + if (!state->threaded) + failed = state->fileline_initialization_failed; + else + failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); + + if (failed) + { + error_callback (data, "failed to read executable information", -1); + return 0; + } + + if (!state->threaded) + fileline_fn = state->fileline_fn; + else + fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (fileline_fn != NULL) + return 1; + + /* We have not initialized the information. Do it now. */ + + descriptor = -1; + called_error_callback = 0; + for (pass = 0; pass < 5; ++pass) + { + int does_not_exist; + + switch (pass) + { + case 0: + filename = state->filename; + break; + case 1: + filename = getexecname (); + break; + case 2: + filename = "/proc/self/exe"; + break; + case 3: + filename = "/proc/curproc/file"; + break; + case 4: + snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", + (long) getpid ()); + filename = buf; + break; + default: + abort (); + } + + if (filename == NULL) + continue; + + descriptor = backtrace_open (filename, error_callback, data, + &does_not_exist); + if (descriptor < 0 && !does_not_exist) + { + called_error_callback = 1; + break; + } + if (descriptor >= 0) + break; + } + + if (descriptor < 0) + { + if (!called_error_callback) + { + if (state->filename != NULL) + error_callback (data, state->filename, ENOENT); + else + error_callback (data, + "libbacktrace could not find executable to open", + 0); + } + failed = 1; + } + + if (!failed) + { + if (!backtrace_initialize (state, filename, descriptor, error_callback, + data, &fileline_fn)) + failed = 1; + } + + if (failed) + { + if (!state->threaded) + state->fileline_initialization_failed = 1; + else + backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); + return 0; + } + + if (!state->threaded) + state->fileline_fn = fileline_fn; + else + { + backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); + + /* Note that if two threads initialize at once, one of the data + sets may be leaked. */ + } + + return 1; +} + +/* Given a PC, find the file name, line number, and function name. */ + +int +backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + if (!fileline_initialize (state, error_callback, data)) + return 0; + + if (state->fileline_initialization_failed) + return 0; + + return state->fileline_fn (state, pc, callback, error_callback, data); +} + +/* Given a PC, find the symbol for it, and its value. */ + +int +backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, void *data) +{ + if (!fileline_initialize (state, error_callback, data)) + return 0; + + if (state->fileline_initialization_failed) + return 0; + + state->syminfo_fn (state, pc, callback, error_callback, data); + return 1; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/internal.h b/src/3rdparty/libbacktrace/libbacktrace/internal.h new file mode 100644 index 00000000..a9c66882 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/internal.h @@ -0,0 +1,338 @@ +/* internal.h -- Internal header file for stack backtrace library. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 BACKTRACE_INTERNAL_H +#define BACKTRACE_INTERNAL_H + +/* We assume that and "backtrace.h" have already been + included. */ + +#ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif +#endif + +#ifndef HAVE_SYNC_FUNCTIONS + +/* Define out the sync functions. These should never be called if + they are not available. */ + +#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1) +#define __sync_lock_test_and_set(A, B) (abort(), 0) +#define __sync_lock_release(A) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ + +#ifdef HAVE_ATOMIC_FUNCTIONS + +/* We have the atomic builtin functions. */ + +#define backtrace_atomic_load_pointer(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_load_int(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_store_pointer(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_size_t(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_int(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) + +#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ +#ifdef HAVE_SYNC_FUNCTIONS + +/* We have the sync functions but not the atomic functions. Define + the atomic ones in terms of the sync ones. */ + +extern void *backtrace_atomic_load_pointer (void *); +extern int backtrace_atomic_load_int (int *); +extern void backtrace_atomic_store_pointer (void *, void *); +extern void backtrace_atomic_store_size_t (size_t *, size_t); +extern void backtrace_atomic_store_int (int *, int); + +#else /* !defined (HAVE_SYNC_FUNCTIONS) */ + +/* We have neither the sync nor the atomic functions. These will + never be called. */ + +#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) +#define backtrace_atomic_load_int(p) (abort(), 0) +#define backtrace_atomic_store_pointer(p, v) abort() +#define backtrace_atomic_store_size_t(p, v) abort() +#define backtrace_atomic_store_int(p, v) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ + +/* The type of the function that collects file/line information. This + is like backtrace_pcinfo. */ + +typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data); + +/* The type of the function that collects symbol information. This is + like backtrace_syminfo. */ + +typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, void *data); + +/* What the backtrace state pointer points to. */ + +struct backtrace_state +{ + /* The name of the executable. */ + const char *filename; + /* Non-zero if threaded. */ + int threaded; + /* The master lock for fileline_fn, fileline_data, syminfo_fn, + syminfo_data, fileline_initialization_failed and everything the + data pointers point to. */ + void *lock; + /* The function that returns file/line information. */ + fileline fileline_fn; + /* The data to pass to FILELINE_FN. */ + void *fileline_data; + /* The function that returns symbol information. */ + syminfo syminfo_fn; + /* The data to pass to SYMINFO_FN. */ + void *syminfo_data; + /* Whether initializing the file/line information failed. */ + int fileline_initialization_failed; + /* The lock for the freelist. */ + int lock_alloc; + /* The freelist when using mmap. */ + struct backtrace_freelist_struct *freelist; +}; + +/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST + is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1 + if the file does not exist. If the file does not exist and + DOES_NOT_EXIST is not NULL, the function will return -1 and will + not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is + NULL, the function will call ERROR_CALLBACK before returning. */ +extern int backtrace_open (const char *filename, + backtrace_error_callback error_callback, + void *data, + int *does_not_exist); + +/* A view of the contents of a file. This supports mmap when + available. A view will remain in memory even after backtrace_close + is called on the file descriptor from which the view was + obtained. */ + +struct backtrace_view +{ + /* The data that the caller requested. */ + const void *data; + /* The base of the view. */ + void *base; + /* The total length of the view. */ + size_t len; +}; + +/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the + result in *VIEW. Returns 1 on success, 0 on error. */ +extern int backtrace_get_view (struct backtrace_state *state, int descriptor, + off_t offset, uint64_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_view *view); + +/* Release a view created by backtrace_get_view. */ +extern void backtrace_release_view (struct backtrace_state *state, + struct backtrace_view *view, + backtrace_error_callback error_callback, + void *data); + +/* Close a file opened by backtrace_open. Returns 1 on success, 0 on + error. */ + +extern int backtrace_close (int descriptor, + backtrace_error_callback error_callback, + void *data); + +/* Sort without using memory. */ + +extern void backtrace_qsort (void *base, size_t count, size_t size, + int (*compar) (const void *, const void *)); + +/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, + this does not report an error, it just returns NULL. */ + +extern void *backtrace_alloc (struct backtrace_state *state, size_t size, + backtrace_error_callback error_callback, + void *data) ATTRIBUTE_MALLOC; + +/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is + NULL, this does not report an error. */ + +extern void backtrace_free (struct backtrace_state *state, void *mem, + size_t size, + backtrace_error_callback error_callback, + void *data); + +/* A growable vector of some struct. This is used for more efficient + allocation when we don't know the final size of some group of data + that we want to represent as an array. */ + +struct backtrace_vector +{ + /* The base of the vector. */ + void *base; + /* The number of bytes in the vector. */ + size_t size; + /* The number of bytes available at the current allocation. */ + size_t alc; +}; + +/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated + bytes. Note that this may move the entire vector to a new memory + location. Returns NULL on failure. */ + +extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, + backtrace_error_callback error_callback, + void *data, + struct backtrace_vector *vec); + +/* Finish the current allocation on VEC. Prepare to start a new + allocation. The finished allocation will never be freed. Returns + a pointer to the base of the finished entries, or NULL on + failure. */ + +extern void* backtrace_vector_finish (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data); + +/* Release any extra space allocated for VEC. This may change + VEC->base. Returns 1 on success, 0 on failure. */ + +extern int backtrace_vector_release (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data); + +/* Free the space managed by VEC. This will reset VEC. */ + +static inline void +backtrace_vector_free (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, void *data) +{ + vec->alc += vec->size; + vec->size = 0; + backtrace_vector_release (state, vec, error_callback, data); +} + +/* Read initial debug data from a descriptor, and set the + fileline_data, syminfo_fn, and syminfo_data fields of STATE. + Return the fileln_fn field in *FILELN_FN--this is done this way so + that the synchronization code is only implemented once. This is + called after the descriptor has first been opened. It will close + the descriptor if it is no longer needed. Returns 1 on success, 0 + on error. There will be multiple implementations of this function, + for different file formats. Each system will compile the + appropriate one. */ + +extern int backtrace_initialize (struct backtrace_state *state, + const char *filename, + int descriptor, + backtrace_error_callback error_callback, + void *data, + fileline *fileline_fn); + +/* An enum for the DWARF sections we care about. */ + +enum dwarf_section +{ + DEBUG_INFO, + DEBUG_LINE, + DEBUG_ABBREV, + DEBUG_RANGES, + DEBUG_STR, + DEBUG_ADDR, + DEBUG_STR_OFFSETS, + DEBUG_LINE_STR, + DEBUG_RNGLISTS, + + DEBUG_MAX +}; + +/* Data for the DWARF sections we care about. */ + +struct dwarf_sections +{ + const unsigned char *data[DEBUG_MAX]; + size_t size[DEBUG_MAX]; +}; + +/* DWARF data read from a file, used for .gnu_debugaltlink. */ + +struct dwarf_data; + +/* Add file/line information for a DWARF module. */ + +extern int backtrace_dwarf_add (struct backtrace_state *state, + uintptr_t base_address, + const struct dwarf_sections *dwarf_sections, + int is_bigendian, + struct dwarf_data *fileline_altlink, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, + struct dwarf_data **fileline_entry); + +/* A test-only hook for elf_uncompress_zdebug. */ + +extern int backtrace_uncompress_zdebug (struct backtrace_state *, + const unsigned char *compressed, + size_t compressed_size, + backtrace_error_callback, void *data, + unsigned char **uncompressed, + size_t *uncompressed_size); + +#endif diff --git a/src/3rdparty/libbacktrace/libbacktrace/macho.c b/src/3rdparty/libbacktrace/libbacktrace/macho.c new file mode 100644 index 00000000..b16b7710 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/macho.c @@ -0,0 +1,1471 @@ +/* macho.c -- Get debug data from an Mach-O file for backtraces. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by John Colanduoni. + + Pending upstream pull request: + https://github.com/ianlancetaylor/libbacktrace/pull/2 + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +/* We can't use autotools to detect the pointer width of our program because + we may be building a fat Mach-O file containing both 32-bit and 64-bit + variants. However Mach-O runs a limited set of platforms so detection + via preprocessor is not difficult. */ + +#if defined(__MACH__) +#if defined(__LP64__) +#define BACKTRACE_BITS 64 +#else +#define BACKTRACE_BITS 32 +#endif +#else +#error Attempting to build Mach-O support on incorrect platform +#endif + +#if defined(__x86_64__) +#define NATIVE_CPU_TYPE CPU_TYPE_X86_64 +#elif defined(__i386__) +#define NATIVE_CPU_TYPE CPU_TYPE_X86 +#elif defined(__aarch64__) +#define NATIVE_CPU_TYPE CPU_TYPE_ARM64 +#elif defined(__arm__) +#define NATIVE_CPU_TYPE CPU_TYPE_ARM +#else +#error Could not detect native Mach-O cpu_type_t +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +struct macho_commands_view +{ + struct backtrace_view view; + uint32_t commands_count; + uint32_t commands_total_size; + int bytes_swapped; + size_t base_offset; +}; + +static const char *const debug_section_names[DEBUG_MAX] = + { + "__debug_info", + "__debug_line", + "__debug_abbrev", + "__debug_ranges", + "__debug_str", + "", + "__debug_str_offs", + "", + "__debug_rnglists" + }; + +struct found_dwarf_section +{ + uint32_t file_offset; + uintptr_t file_size; + const unsigned char *data; +}; + +/* Mach-O symbols don't have a length. As a result we have to infer it + by sorting the symbol addresses for each image and recording the + memory range attributed to each image. */ +struct macho_symbol +{ + uintptr_t addr; + size_t size; + const char *name; +}; + +struct macho_syminfo_data +{ + struct macho_syminfo_data *next; + struct macho_symbol *symbols; + size_t symbol_count; + uintptr_t min_addr; + uintptr_t max_addr; +}; + +uint16_t +macho_file_to_host_u16 (int file_bytes_swapped, uint16_t input) +{ + if (file_bytes_swapped) + return (input >> 8) | (input << 8); + else + return input; +} + +uint32_t +macho_file_to_host_u32 (int file_bytes_swapped, uint32_t input) +{ + if (file_bytes_swapped) + { + return ((input >> 24) & 0x000000FF) + | ((input >> 8) & 0x0000FF00) + | ((input << 8) & 0x00FF0000) + | ((input << 24) & 0xFF000000); + } + else + { + return input; + } +} + +uint64_t +macho_file_to_host_u64 (int file_bytes_swapped, uint64_t input) +{ + if (file_bytes_swapped) + { + return macho_file_to_host_u32 (file_bytes_swapped, + (uint32_t) (input >> 32)) + | (((uint64_t) macho_file_to_host_u32 (file_bytes_swapped, + (uint32_t) input)) << 32); + } + else + { + return input; + } +} + +#if BACKTRACE_BITS == 64 +#define macho_file_to_host_usize macho_file_to_host_u64 +typedef struct mach_header_64 mach_header_native_t; +#define LC_SEGMENT_NATIVE LC_SEGMENT_64 +typedef struct segment_command_64 segment_command_native_t; +typedef struct nlist_64 nlist_native_t; +typedef struct section_64 section_native_t; +#else /* BACKTRACE_BITS == 32 */ +#define macho_file_to_host_usize macho_file_to_host_u32 +typedef struct mach_header mach_header_native_t; +#define LC_SEGMENT_NATIVE LC_SEGMENT +typedef struct segment_command segment_command_native_t; +typedef struct nlist nlist_native_t; +typedef struct section section_native_t; +#endif + +// Gets a view into a Mach-O image, taking any slice offset into account +int +macho_get_view (struct backtrace_state *state, int descriptor, + off_t offset, size_t size, + backtrace_error_callback error_callback, + void *data, struct macho_commands_view *commands_view, + struct backtrace_view *view) +{ + return backtrace_get_view (state, descriptor, + commands_view->base_offset + offset, size, + error_callback, data, view); +} + +int +macho_get_commands (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, + void *data, struct macho_commands_view *commands_view, + int *incompatible) +{ + int ret = 0; + int is_fat = 0; + struct backtrace_view file_header_view; + int file_header_view_valid = 0; + struct backtrace_view fat_archs_view; + int fat_archs_view_valid = 0; + const mach_header_native_t *file_header; + uint64_t commands_offset; + + *incompatible = 0; + + if (!backtrace_get_view (state, descriptor, 0, sizeof (mach_header_native_t), + error_callback, data, &file_header_view)) + goto end; + file_header_view_valid = 1; + + switch (*(uint32_t *) file_header_view.data) + { + case MH_MAGIC: + if (BACKTRACE_BITS == 32) + commands_view->bytes_swapped = 0; + else + { + *incompatible = 1; + goto end; + } + break; + case MH_CIGAM: + if (BACKTRACE_BITS == 32) + commands_view->bytes_swapped = 1; + else + { + *incompatible = 1; + goto end; + } + break; + case MH_MAGIC_64: + if (BACKTRACE_BITS == 64) + commands_view->bytes_swapped = 0; + else + { + *incompatible = 1; + goto end; + } + break; + case MH_CIGAM_64: + if (BACKTRACE_BITS == 64) + commands_view->bytes_swapped = 1; + else + { + *incompatible = 1; + goto end; + } + break; + case FAT_MAGIC: + is_fat = 1; + commands_view->bytes_swapped = 0; + break; + case FAT_CIGAM: + is_fat = 1; + commands_view->bytes_swapped = 1; + break; + default: + goto end; + } + + if (is_fat) + { + uint32_t native_slice_offset; + size_t archs_total_size; + uint32_t arch_count; + const struct fat_header *fat_header; + const struct fat_arch *archs; + uint32_t i; + + fat_header = file_header_view.data; + arch_count = + macho_file_to_host_u32 (commands_view->bytes_swapped, + fat_header->nfat_arch); + + archs_total_size = arch_count * sizeof (struct fat_arch); + + if (!backtrace_get_view (state, descriptor, sizeof (struct fat_header), + archs_total_size, error_callback, + data, &fat_archs_view)) + goto end; + fat_archs_view_valid = 1; + + native_slice_offset = 0; + archs = fat_archs_view.data; + for (i = 0; i < arch_count; i++) + { + const struct fat_arch *raw_arch = archs + i; + int cpu_type = + (int) macho_file_to_host_u32 (commands_view->bytes_swapped, + (uint32_t) raw_arch->cputype); + + if (cpu_type == NATIVE_CPU_TYPE) + { + native_slice_offset = + macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_arch->offset); + + break; + } + } + + if (native_slice_offset == 0) + { + *incompatible = 1; + goto end; + } + + backtrace_release_view (state, &file_header_view, error_callback, data); + file_header_view_valid = 0; + if (!backtrace_get_view (state, descriptor, native_slice_offset, + sizeof (mach_header_native_t), error_callback, + data, &file_header_view)) + goto end; + file_header_view_valid = 1; + + // The endianess of the slice may be different than the fat image + switch (*(uint32_t *) file_header_view.data) + { + case MH_MAGIC: + if (BACKTRACE_BITS == 32) + commands_view->bytes_swapped = 0; + else + goto end; + break; + case MH_CIGAM: + if (BACKTRACE_BITS == 32) + commands_view->bytes_swapped = 1; + else + goto end; + break; + case MH_MAGIC_64: + if (BACKTRACE_BITS == 64) + commands_view->bytes_swapped = 0; + else + goto end; + break; + case MH_CIGAM_64: + if (BACKTRACE_BITS == 64) + commands_view->bytes_swapped = 1; + else + goto end; + break; + default: + goto end; + } + + commands_view->base_offset = native_slice_offset; + } + else + commands_view->base_offset = 0; + + file_header = file_header_view.data; + commands_view->commands_count = + macho_file_to_host_u32 (commands_view->bytes_swapped, + file_header->ncmds); + commands_view->commands_total_size = + macho_file_to_host_u32 (commands_view->bytes_swapped, + file_header->sizeofcmds); + commands_offset = + commands_view->base_offset + sizeof (mach_header_native_t); + + if (!backtrace_get_view (state, descriptor, commands_offset, + commands_view->commands_total_size, error_callback, + data, &commands_view->view)) + goto end; + + ret = 1; + +end: + if (file_header_view_valid) + backtrace_release_view (state, &file_header_view, error_callback, data); + if (fat_archs_view_valid) + backtrace_release_view (state, &fat_archs_view, error_callback, data); + return ret; +} + +int +macho_get_uuid (struct backtrace_state *state ATTRIBUTE_UNUSED, + int descriptor ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, + void *data, struct macho_commands_view *commands_view, + uuid_t *uuid) +{ + size_t offset = 0; + uint32_t i = 0; + + for (i = 0; i < commands_view->commands_count; i++) + { + const struct load_command *raw_command; + struct load_command command; + + if (offset + sizeof (struct load_command) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + raw_command = + commands_view->view.data + offset; + command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmd); + command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmdsize); + + if (command.cmd == LC_UUID) + { + const struct uuid_command *uuid_command; + + if (offset + sizeof (struct uuid_command) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + uuid_command = + (struct uuid_command *) raw_command; + memcpy (uuid, uuid_command->uuid, sizeof (uuid_t)); + return 1; + } + + offset += command.cmdsize; + } + + error_callback (data, "executable file is missing an identifying UUID", 0); + return 0; +} + +/* Returns the base address of a Mach-O image, as encoded in the file header. + * WARNING: This does not take ASLR into account, which is ubiquitous on recent + * Darwin platforms. + */ +int +macho_get_addr_range (struct backtrace_state *state ATTRIBUTE_UNUSED, + int descriptor ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, + void *data, struct macho_commands_view *commands_view, + uintptr_t *base_address, uintptr_t *max_address) +{ + size_t offset = 0; + int found_text = 0; + uint32_t i = 0; + + *max_address = 0; + + for (i = 0; i < commands_view->commands_count; i++) + { + const struct load_command *raw_command; + struct load_command command; + + if (offset + sizeof (struct load_command) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + raw_command = commands_view->view.data + offset; + command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmd); + command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmdsize); + + if (command.cmd == LC_SEGMENT_NATIVE) + { + const segment_command_native_t *raw_segment; + uintptr_t segment_vmaddr; + uintptr_t segment_vmsize; + uintptr_t segment_maxaddr; + uintptr_t text_fileoff; + + if (offset + sizeof (segment_command_native_t) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + raw_segment = (segment_command_native_t *) raw_command; + + segment_vmaddr = macho_file_to_host_usize ( + commands_view->bytes_swapped, raw_segment->vmaddr); + segment_vmsize = macho_file_to_host_usize ( + commands_view->bytes_swapped, raw_segment->vmsize); + segment_maxaddr = segment_vmaddr + segment_vmsize; + + if (strncmp (raw_segment->segname, "__TEXT", + sizeof (raw_segment->segname)) == 0) + { + text_fileoff = macho_file_to_host_usize ( + commands_view->bytes_swapped, raw_segment->fileoff); + *base_address = segment_vmaddr - text_fileoff; + + found_text = 1; + } + + if (segment_maxaddr > *max_address) + *max_address = segment_maxaddr; + } + + offset += command.cmdsize; + } + + if (found_text) + return 1; + else + { + error_callback (data, "executable is missing __TEXT segment", 0); + return 0; + } +} + +static int +macho_symbol_compare_addr (const void *left_raw, const void *right_raw) +{ + const struct macho_symbol *left = left_raw; + const struct macho_symbol *right = right_raw; + + if (left->addr > right->addr) + return 1; + else if (left->addr < right->addr) + return -1; + else + return 0; +} + +int +macho_symbol_type_relevant (uint8_t type) +{ + uint8_t type_field = (uint8_t) (type & N_TYPE); + + return (type_field == N_ABS || type_field == N_SECT); +} + +int +macho_add_symtab (struct backtrace_state *state, + backtrace_error_callback error_callback, + void *data, int descriptor, + struct macho_commands_view *commands_view, + uintptr_t base_address, uintptr_t max_image_address, + intptr_t vmslide, int *found_sym) +{ + struct macho_syminfo_data *syminfo_data; + + int ret = 0; + size_t offset = 0; + struct backtrace_view symtab_view; + int symtab_view_valid = 0; + struct backtrace_view strtab_view; + int strtab_view_valid = 0; + size_t syminfo_index = 0; + size_t function_count = 0; + uint32_t i = 0; + uint32_t j = 0; + uint32_t symtab_index = 0; + + *found_sym = 0; + + for (i = 0; i < commands_view->commands_count; i++) + { + const struct load_command *raw_command; + struct load_command command; + + if (offset + sizeof (struct load_command) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + raw_command = commands_view->view.data + offset; + command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmd); + command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, + raw_command->cmdsize); + + if (command.cmd == LC_SYMTAB) + { + const struct symtab_command *symtab_command; + uint32_t symbol_table_offset; + uint32_t symbol_count; + uint32_t string_table_offset; + uint32_t string_table_size; + + if (offset + sizeof (struct symtab_command) + > commands_view->commands_total_size) + { + error_callback (data, + "executable file contains out of range command offset", + 0); + return 0; + } + + symtab_command = (struct symtab_command *) raw_command; + + symbol_table_offset = macho_file_to_host_u32 ( + commands_view->bytes_swapped, symtab_command->symoff); + symbol_count = macho_file_to_host_u32 ( + commands_view->bytes_swapped, symtab_command->nsyms); + string_table_offset = macho_file_to_host_u32 ( + commands_view->bytes_swapped, symtab_command->stroff); + string_table_size = macho_file_to_host_u32 ( + commands_view->bytes_swapped, symtab_command->strsize); + + + if (!macho_get_view (state, descriptor, symbol_table_offset, + symbol_count * sizeof (nlist_native_t), + error_callback, data, commands_view, + &symtab_view)) + goto end; + symtab_view_valid = 1; + + if (!macho_get_view (state, descriptor, string_table_offset, + string_table_size, error_callback, data, + commands_view, &strtab_view)) + goto end; + strtab_view_valid = 1; + + // Count functions first + for (j = 0; j < symbol_count; j++) + { + const nlist_native_t *raw_sym = + ((const nlist_native_t *) symtab_view.data) + j; + + if (macho_symbol_type_relevant (raw_sym->n_type)) + { + function_count += 1; + } + } + + // Allocate space for the: + // (a) macho_syminfo_data for this image + // (b) macho_symbol entries + syminfo_data = + backtrace_alloc (state, + sizeof (struct macho_syminfo_data), + error_callback, data); + if (syminfo_data == NULL) + goto end; + + syminfo_data->symbols = backtrace_alloc ( + state, function_count * sizeof (struct macho_symbol), + error_callback, data); + if (syminfo_data->symbols == NULL) + goto end; + + syminfo_data->symbol_count = function_count; + syminfo_data->next = NULL; + syminfo_data->min_addr = base_address; + syminfo_data->max_addr = max_image_address; + + for (symtab_index = 0; + symtab_index < symbol_count; symtab_index++) + { + const nlist_native_t *raw_sym = + ((const nlist_native_t *) symtab_view.data) + + symtab_index; + + if (macho_symbol_type_relevant (raw_sym->n_type)) + { + size_t strtab_index; + const char *name; + size_t max_len_plus_one; + + syminfo_data->symbols[syminfo_index].addr = + macho_file_to_host_usize (commands_view->bytes_swapped, + raw_sym->n_value) + vmslide; + + strtab_index = macho_file_to_host_u32 ( + commands_view->bytes_swapped, + raw_sym->n_un.n_strx); + + // Check the range of the supposed "string" we've been + // given + if (strtab_index >= string_table_size) + { + error_callback ( + data, + "dSYM file contains out of range string table index", + 0); + goto end; + } + + name = strtab_view.data + strtab_index; + max_len_plus_one = string_table_size - strtab_index; + + if (strnlen (name, max_len_plus_one) >= max_len_plus_one) + { + error_callback ( + data, + "dSYM file contains unterminated string", + 0); + goto end; + } + + // Remove underscore prefixes + if (name[0] == '_') + { + name = name + 1; + } + + syminfo_data->symbols[syminfo_index].name = name; + + syminfo_index += 1; + } + } + + backtrace_qsort (syminfo_data->symbols, + syminfo_data->symbol_count, + sizeof (struct macho_symbol), + macho_symbol_compare_addr); + + // Calculate symbol sizes + for (syminfo_index = 0; + syminfo_index < syminfo_data->symbol_count; syminfo_index++) + { + if (syminfo_index + 1 < syminfo_data->symbol_count) + { + syminfo_data->symbols[syminfo_index].size = + syminfo_data->symbols[syminfo_index + 1].addr - + syminfo_data->symbols[syminfo_index].addr; + } + else + { + syminfo_data->symbols[syminfo_index].size = + max_image_address - + syminfo_data->symbols[syminfo_index].addr; + } + } + + if (!state->threaded) + { + struct macho_syminfo_data **pp; + + for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next); + *pp = syminfo_data; + } + else + { + while (1) + { + struct macho_syminfo_data **pp; + + pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct macho_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, syminfo_data)) + break; + } + } + + strtab_view_valid = 0; // We need to keep string table around + *found_sym = 1; + ret = 1; + goto end; + } + + offset += command.cmdsize; + } + + // No symbol table here + ret = 1; + goto end; + +end: + if (symtab_view_valid) + backtrace_release_view (state, &symtab_view, error_callback, data); + if (strtab_view_valid) + backtrace_release_view (state, &strtab_view, error_callback, data); + return ret; +} + +int +macho_try_dwarf (struct backtrace_state *state, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, uuid_t *executable_uuid, + uintptr_t base_address, uintptr_t max_image_address, + intptr_t vmslide, char *dwarf_filename, int *matched, + int *found_sym, int *found_dwarf) +{ + uuid_t dwarf_uuid; + + int ret = 0; + int dwarf_descriptor; + int dwarf_descriptor_valid = 0; + struct macho_commands_view commands_view; + int commands_view_valid = 0; + struct backtrace_view dwarf_view; + int dwarf_view_valid = 0; + size_t offset = 0; + struct found_dwarf_section sections[DEBUG_MAX]; + struct dwarf_sections dwarf_sections; + uintptr_t min_dwarf_offset = 0; + uintptr_t max_dwarf_offset = 0; + uint32_t i = 0; + uint32_t j = 0; + int k = 0; + + *matched = 0; + *found_sym = 0; + *found_dwarf = 0; + + if ((dwarf_descriptor = backtrace_open (dwarf_filename, error_callback, + data, NULL)) == 0) + goto end; + dwarf_descriptor_valid = 1; + + int incompatible; + if (!macho_get_commands (state, dwarf_descriptor, error_callback, data, + &commands_view, &incompatible)) + { + // Failing to read the header here is fine, because this dSYM may be + // for a different architecture + if (incompatible) + { + ret = 1; + } + goto end; + } + commands_view_valid = 1; + + // Get dSYM UUID and compare + if (!macho_get_uuid (state, dwarf_descriptor, error_callback, data, + &commands_view, &dwarf_uuid)) + { + error_callback (data, "dSYM file is missing an identifying uuid", 0); + goto end; + } + if (memcmp (executable_uuid, &dwarf_uuid, sizeof (uuid_t)) != 0) + { + // DWARF doesn't belong to desired executable + ret = 1; + goto end; + } + + *matched = 1; + + // Read symbol table + if (!macho_add_symtab (state, error_callback, data, dwarf_descriptor, + &commands_view, base_address, max_image_address, + vmslide, found_sym)) + goto end; + + // Get DWARF sections + + memset (sections, 0, sizeof (sections)); + offset = 0; + for (i = 0; i < commands_view.commands_count; i++) + { + const struct load_command *raw_command; + struct load_command command; + + if (offset + sizeof (struct load_command) + > commands_view.commands_total_size) + { + error_callback (data, + "dSYM file contains out of range command offset", 0); + goto end; + } + + raw_command = commands_view.view.data + offset; + command.cmd = macho_file_to_host_u32 (commands_view.bytes_swapped, + raw_command->cmd); + command.cmdsize = macho_file_to_host_u32 (commands_view.bytes_swapped, + raw_command->cmdsize); + + if (command.cmd == LC_SEGMENT_NATIVE) + { + uint32_t section_count; + size_t section_offset; + const segment_command_native_t *raw_segment; + + if (offset + sizeof (segment_command_native_t) + > commands_view.commands_total_size) + { + error_callback (data, + "dSYM file contains out of range command offset", + 0); + goto end; + } + + raw_segment = (const segment_command_native_t *) raw_command; + + if (strncmp (raw_segment->segname, "__DWARF", + sizeof (raw_segment->segname)) == 0) + { + section_count = macho_file_to_host_u32 ( + commands_view.bytes_swapped, + raw_segment->nsects); + + section_offset = offset + sizeof (segment_command_native_t); + + // Search sections for relevant DWARF section names + for (j = 0; j < section_count; j++) + { + const section_native_t *raw_section; + + if (section_offset + sizeof (section_native_t) > + commands_view.commands_total_size) + { + error_callback (data, + "dSYM file contains out of range command offset", + 0); + goto end; + } + + raw_section = commands_view.view.data + section_offset; + + for (k = 0; k < DEBUG_MAX; k++) + { + uintptr_t dwarf_section_end; + + if (debug_section_names[k][0] != '\0' && + strncmp (raw_section->sectname, + debug_section_names[k], + sizeof (raw_section->sectname)) == 0) + { + *found_dwarf = 1; + + sections[k].file_offset = + macho_file_to_host_u32 ( + commands_view.bytes_swapped, + raw_section->offset); + sections[k].file_size = + macho_file_to_host_usize ( + commands_view.bytes_swapped, + raw_section->size); + + if (min_dwarf_offset == 0 || + sections[k].file_offset < + min_dwarf_offset) + min_dwarf_offset = sections[k].file_offset; + + dwarf_section_end = + sections[k].file_offset + + sections[k].file_size; + if (dwarf_section_end > max_dwarf_offset) + max_dwarf_offset = dwarf_section_end; + + break; + } + } + + section_offset += sizeof (section_native_t); + } + + break; + } + } + + offset += command.cmdsize; + } + + if (!*found_dwarf) + { + // No DWARF in this file + ret = 1; + goto end; + } + + if (!macho_get_view (state, dwarf_descriptor, (off_t) min_dwarf_offset, + max_dwarf_offset - min_dwarf_offset, error_callback, + data, &commands_view, &dwarf_view)) + goto end; + dwarf_view_valid = 1; + + for (i = 0; i < DEBUG_MAX; i++) + { + if (sections[i].file_offset == 0) + dwarf_sections.data[i] = NULL; + else + dwarf_sections.data[i] = + dwarf_view.data + sections[i].file_offset - min_dwarf_offset; + + dwarf_sections.size[i] = sections[i].file_size; + } + + if (!backtrace_dwarf_add (state, vmslide, + &dwarf_sections, + ((__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN)^ commands_view.bytes_swapped), + NULL, /* altlink */ + error_callback, data, fileline_fn, + NULL /* returned fileline_entry */)) + goto end; + + // Don't release the DWARF view because it is still in use + dwarf_descriptor_valid = 0; + dwarf_view_valid = 0; + ret = 1; + +end: + if (dwarf_descriptor_valid) + backtrace_close (dwarf_descriptor, error_callback, data); + if (commands_view_valid) + backtrace_release_view (state, &commands_view.view, error_callback, data); + if (dwarf_view_valid) + backtrace_release_view (state, &dwarf_view, error_callback, data); + return ret; +} + +int +macho_try_dsym (struct backtrace_state *state, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, uuid_t *executable_uuid, + uintptr_t base_address, uintptr_t max_image_address, + intptr_t vmslide, char *dsym_filename, int *matched, + int *found_sym, int *found_dwarf) +{ + int ret = 0; + char dwarf_image_dir_path[PATH_MAX]; + DIR *dwarf_image_dir; + int dwarf_image_dir_valid = 0; + struct dirent *directory_entry; + char dwarf_filename[PATH_MAX]; + int dwarf_matched; + int dwarf_had_sym; + int dwarf_had_dwarf; + + *matched = 0; + *found_sym = 0; + *found_dwarf = 0; + + strncpy (dwarf_image_dir_path, dsym_filename, PATH_MAX); + strncat (dwarf_image_dir_path, "/Contents/Resources/DWARF", PATH_MAX); + + if (!(dwarf_image_dir = opendir (dwarf_image_dir_path))) + { + error_callback (data, "could not open DWARF directory in dSYM", + 0); + goto end; + } + dwarf_image_dir_valid = 1; + + while ((directory_entry = readdir (dwarf_image_dir))) + { + if (directory_entry->d_type != DT_REG) + continue; + + strncpy (dwarf_filename, dwarf_image_dir_path, PATH_MAX); + strncat (dwarf_filename, "/", PATH_MAX); + strncat (dwarf_filename, directory_entry->d_name, PATH_MAX); + + if (!macho_try_dwarf (state, error_callback, data, fileline_fn, + executable_uuid, base_address, max_image_address, + vmslide, dwarf_filename, + &dwarf_matched, &dwarf_had_sym, &dwarf_had_dwarf)) + goto end; + + if (dwarf_matched) + { + *matched = 1; + *found_sym = dwarf_had_sym; + *found_dwarf = dwarf_had_dwarf; + ret = 1; + goto end; + } + } + + // No matching DWARF in this dSYM + ret = 1; + goto end; + +end: + if (dwarf_image_dir_valid) + closedir (dwarf_image_dir); + return ret; +} + +int +macho_add (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data, int descriptor, + const char *filename, fileline *fileline_fn, intptr_t vmslide, + int *found_sym, int *found_dwarf) +{ + uuid_t image_uuid; + uintptr_t image_file_base_address; + uintptr_t image_file_max_address; + uintptr_t image_actual_base_address = 0; + uintptr_t image_actual_max_address = 0; + + int ret = 0; + struct macho_commands_view commands_view; + int commands_view_valid = 0; + char executable_dirname[PATH_MAX]; + size_t filename_len; + DIR *executable_dir = NULL; + int executable_dir_valid = 0; + struct dirent *directory_entry; + char dsym_full_path[PATH_MAX]; + static const char *extension; + size_t extension_len; + ssize_t i; + + static const char *framework = ".framework"; + size_t framework_len = strlen (framework); + char full_framework_dbsym[PATH_MAX]; + char* framework_path = 0; + + int matched; + int dsym_had_sym; + int dsym_had_dwarf; + + *found_sym = 0; + *found_dwarf = 0; + + // Find Mach-O commands list + int incompatible; + if (!macho_get_commands (state, descriptor, error_callback, data, + &commands_view, &incompatible)) + goto end; + commands_view_valid = 1; + + // First we need to get the uuid of our file so we can hunt down the correct + // dSYM + if (!macho_get_uuid (state, descriptor, error_callback, data, &commands_view, + &image_uuid)) + goto end; + + // Now we need to find the in memory base address. Step one is to find out + // what the executable thinks the base address is + if (!macho_get_addr_range (state, descriptor, error_callback, data, + &commands_view, + &image_file_base_address, + &image_file_max_address)) + goto end; + + // As we use _dyld_get_image_header the vmslide is the actual base address already + image_actual_base_address = vmslide; + image_actual_max_address = + image_file_max_address + vmslide - image_file_base_address; + + //Calculate the vmslide from the real start address + vmslide = vmslide - image_file_base_address; + + if (image_actual_base_address == 0) + { + error_callback (data, "executable file is not loaded", 0); + goto end; + } + + // Look for dSYM in our executable's directory + strncpy (executable_dirname, filename, PATH_MAX); + filename_len = strlen (executable_dirname); + for (i = filename_len - 1; i >= 0; i--) + { + if (executable_dirname[i] == '/') + { + executable_dirname[i] = '\0'; + break; + } + else if (i == 0) + { + executable_dirname[0] = '.'; + executable_dirname[1] = '\0'; + break; + } + } + + if (!(executable_dir = opendir (executable_dirname))) + { + error_callback (data, "could not open directory containing executable", + 0); + goto end; + } + executable_dir_valid = 1; + + extension = ".dSYM"; + extension_len = strlen (extension); + + //Search for a dSYM in the executable path, this includes dylibs + while ((directory_entry = readdir (executable_dir))) + { + if (directory_entry->d_namlen < extension_len) + continue; + if (strncasecmp (directory_entry->d_name + directory_entry->d_namlen + - extension_len, extension, extension_len) == 0) + { + // Found a dSYM + strncpy (dsym_full_path, executable_dirname, PATH_MAX); + strncat (dsym_full_path, "/", PATH_MAX); + strncat (dsym_full_path, directory_entry->d_name, PATH_MAX); + + if (!macho_try_dsym (state, error_callback, data, + fileline_fn, &image_uuid, + image_actual_base_address, + image_actual_max_address, vmslide, + dsym_full_path, + &matched, &dsym_had_sym, &dsym_had_dwarf)) + goto end; + + if (matched) + { + *found_sym = dsym_had_sym; + *found_dwarf = dsym_had_dwarf; + ret = 1; + goto end; + } + } + } + + // If we couldn't find a dSYM in the executable path, check whether the library is from a + // framework and search for a dSYM in the special .framework.dSYM folder + framework_path = strstr(executable_dirname, framework); + if (framework_path) { + size_t new_len = framework_path - executable_dirname + framework_len; + strncpy (full_framework_dbsym, executable_dirname, new_len); + full_framework_dbsym[new_len] = '\0'; + strncat (full_framework_dbsym, extension, extension_len); + + DIR *framework_dir = NULL; + if ((framework_dir = opendir (full_framework_dbsym))) + { + closedir (framework_dir); + + if (!macho_try_dsym (state, error_callback, data, + fileline_fn, &image_uuid, + image_actual_base_address, + image_actual_max_address, vmslide, + full_framework_dbsym, + &matched, &dsym_had_sym, &dsym_had_dwarf)) + goto end; + + if (matched) + { + *found_sym = dsym_had_sym; + *found_dwarf = dsym_had_dwarf; + ret = 1; + goto end; + } + } + } + + strncpy (executable_dirname, filename, PATH_MAX); + + // If we still don't have a DSYM file, load the DWARF data from the lib itself. Although there + // is no DWARF data in libs on macos embedded, this makes sure the symtab is loaded and we can + // try to resolve the symbols + if (!macho_try_dwarf (state, error_callback, data, fileline_fn, + &image_uuid, image_actual_base_address, image_actual_max_address, + vmslide, executable_dirname, + &matched, &dsym_had_sym, &dsym_had_dwarf)) + goto end; + + if (matched) + { + *found_sym = dsym_had_sym; + *found_dwarf = dsym_had_dwarf; + ret = 1; + goto end; + } + + // No matching dSYM + ret = 1; + goto end; + +end: + if (commands_view_valid) + backtrace_release_view (state, &commands_view.view, error_callback, + data); + if (executable_dir_valid) + closedir (executable_dir); + return ret; +} + +static int +macho_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct macho_symbol *entry = (const struct macho_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->addr) + return -1; + else if (addr >= entry->addr + entry->size) + return 1; + else + return 0; +} + +static void +macho_syminfo (struct backtrace_state *state, + uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct macho_syminfo_data *edata; + struct macho_symbol *sym = NULL; + + if (!state->threaded) + { + for (edata = (struct macho_syminfo_data *) state->syminfo_data; + edata != NULL; + edata = edata->next) + { + if (addr >= edata->min_addr && addr <= edata->max_addr) + { + sym = ((struct macho_symbol *) + bsearch (&addr, edata->symbols, edata->symbol_count, + sizeof (struct macho_symbol), macho_symbol_search)); + if (sym != NULL) + break; + } + } + } + else + { + struct macho_syminfo_data **pp; + + pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + edata = backtrace_atomic_load_pointer (pp); + if (edata == NULL) + break; + + if (addr >= edata->min_addr && addr <= edata->max_addr) + { + sym = ((struct macho_symbol *) + bsearch (&addr, edata->symbols, edata->symbol_count, + sizeof (struct macho_symbol), macho_symbol_search)); + if (sym != NULL) + break; + } + + pp = &edata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->addr, sym->size); +} + + +static int +macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no debug info in Mach-O executable", -1); + return 0; +} + +static void +macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, + backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no symbol table in Mach-O executable", -1); +} + +int +backtrace_initialize (struct backtrace_state *state, + const char *filename, + int descriptor, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + fileline macho_fileline_fn = macho_nodebug; + int found_sym = 0; + int found_dwarf = 0; + uint32_t i = 0; + uint32_t loaded_image_count; + + // Add all loaded images + loaded_image_count = _dyld_image_count (); + for (i = 0; i < loaded_image_count; i++) + { + + int current_found_sym; + int current_found_dwarf; + int current_descriptor; + intptr_t current_vmslide; + intptr_t image_header; + const char *current_name; + + current_vmslide = _dyld_get_image_vmaddr_slide (i); + image_header = _dyld_get_image_header(i); + current_name = _dyld_get_image_name (i); + + if (current_name == NULL || (i != 0 && current_vmslide == 0)) + continue; + + if (!(current_descriptor = + backtrace_open (current_name, error_callback, data, NULL))) + { + continue; + } + + if (macho_add (state, error_callback, data, current_descriptor, + current_name, &macho_fileline_fn, image_header, + ¤t_found_sym, ¤t_found_dwarf)) + { + found_sym = found_sym || current_found_sym; + found_dwarf = found_dwarf || current_found_dwarf; + } + + backtrace_close (current_descriptor, error_callback, data); + } + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = macho_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = macho_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo); + else + (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, + macho_nosyms); + } + + if (!state->threaded) + { + if (state->fileline_fn == NULL || state->fileline_fn == macho_nodebug) + *fileline_fn = macho_fileline_fn; + } + else + { + fileline current_fn; + + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (current_fn == NULL || current_fn == macho_nodebug) + *fileline_fn = macho_fileline_fn; + } + + return 1; +} + diff --git a/src/3rdparty/libbacktrace/libbacktrace/mmap.c b/src/3rdparty/libbacktrace/libbacktrace/mmap.c new file mode 100644 index 00000000..1b636649 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/mmap.c @@ -0,0 +1,327 @@ +/* mmap.c -- Memory allocation with mmap. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Memory allocation on systems that provide anonymous mmap. This + permits the backtrace functions to be invoked from a signal + handler, assuming that mmap is async-signal safe. */ + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +/* A list of free memory blocks. */ + +struct backtrace_freelist_struct +{ + /* Next on list. */ + struct backtrace_freelist_struct *next; + /* Size of this block, including this structure. */ + size_t size; +}; + +/* Free memory allocated by backtrace_alloc. */ + +static void +backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) +{ + /* Just leak small blocks. We don't have to be perfect. Don't put + more than 16 entries on the free list, to avoid wasting time + searching when allocating a block. If we have more than 16 + entries, leak the smallest entry. */ + + if (size >= sizeof (struct backtrace_freelist_struct)) + { + size_t c; + struct backtrace_freelist_struct **ppsmall; + struct backtrace_freelist_struct **pp; + struct backtrace_freelist_struct *p; + + c = 0; + ppsmall = NULL; + for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) + { + if (ppsmall == NULL || (*pp)->size < (*ppsmall)->size) + ppsmall = pp; + ++c; + } + if (c >= 16) + { + if (size <= (*ppsmall)->size) + return; + *ppsmall = (*ppsmall)->next; + } + + p = (struct backtrace_freelist_struct *) addr; + p->next = state->freelist; + p->size = size; + state->freelist = p; + } +} + +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ + +void * +backtrace_alloc (struct backtrace_state *state, + size_t size, backtrace_error_callback error_callback, + void *data) +{ + void *ret; + int locked; + struct backtrace_freelist_struct **pp; + size_t pagesize; + size_t asksize; + void *page; + + ret = NULL; + + /* If we can acquire the lock, then see if there is space on the + free list. If we can't acquire the lock, drop straight into + using mmap. __sync_lock_test_and_set returns the old state of + the lock, so we have acquired it if it returns 0. */ + + if (!state->threaded) + locked = 1; + else + locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; + + if (locked) + { + for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) + { + if ((*pp)->size >= size) + { + struct backtrace_freelist_struct *p; + + p = *pp; + *pp = p->next; + + /* Round for alignment; we assume that no type we care about + is more than 8 bytes. */ + size = (size + 7) & ~ (size_t) 7; + if (size < p->size) + backtrace_free_locked (state, (char *) p + size, + p->size - size); + + ret = (void *) p; + + break; + } + } + + if (state->threaded) + __sync_lock_release (&state->lock_alloc); + } + + if (ret == NULL) + { + /* Allocate a new page. */ + + pagesize = getpagesize (); + asksize = (size + pagesize - 1) & ~ (pagesize - 1); + page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (page == MAP_FAILED) + { + if (error_callback) + error_callback (data, "mmap", errno); + } + else + { + size = (size + 7) & ~ (size_t) 7; + if (size < asksize) + backtrace_free (state, (char *) page + size, asksize - size, + error_callback, data); + + ret = page; + } + } + + return ret; +} + +/* Free memory allocated by backtrace_alloc. */ + +void +backtrace_free (struct backtrace_state *state, void *addr, size_t size, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + int locked; + + /* If we are freeing a large aligned block, just release it back to + the system. This case arises when growing a vector for a large + binary with lots of debug info. Calling munmap here may cause us + to call mmap again if there is also a large shared library; we + just live with that. */ + if (size >= 16 * 4096) + { + size_t pagesize; + + pagesize = getpagesize (); + if (((uintptr_t) addr & (pagesize - 1)) == 0 + && (size & (pagesize - 1)) == 0) + { + /* If munmap fails for some reason, just add the block to + the freelist. */ + if (munmap (addr, size) == 0) + return; + } + } + + /* If we can acquire the lock, add the new space to the free list. + If we can't acquire the lock, just leak the memory. + __sync_lock_test_and_set returns the old state of the lock, so we + have acquired it if it returns 0. */ + + if (!state->threaded) + locked = 1; + else + locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; + + if (locked) + { + backtrace_free_locked (state, addr, size); + + if (state->threaded) + __sync_lock_release (&state->lock_alloc); + } +} + +/* Grow VEC by SIZE bytes. */ + +void * +backtrace_vector_grow (struct backtrace_state *state,size_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_vector *vec) +{ + void *ret; + + if (size > vec->alc) + { + size_t pagesize; + size_t alc; + void *base; + + pagesize = getpagesize (); + alc = vec->size + size; + if (vec->size == 0) + alc = 16 * size; + else if (alc < pagesize) + { + alc *= 2; + if (alc > pagesize) + alc = pagesize; + } + else + { + alc *= 2; + alc = (alc + pagesize - 1) & ~ (pagesize - 1); + } + base = backtrace_alloc (state, alc, error_callback, data); + if (base == NULL) + return NULL; + if (vec->base != NULL) + { + memcpy (base, vec->base, vec->size); + backtrace_free (state, vec->base, vec->size + vec->alc, + error_callback, data); + } + vec->base = base; + vec->alc = alc - vec->size; + } + + ret = (char *) vec->base + vec->size; + vec->size += size; + vec->alc -= size; + return ret; +} + +/* Finish the current allocation on VEC. */ + +void * +backtrace_vector_finish ( + struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_vector *vec, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + void *ret; + + ret = vec->base; + vec->base = (char *) vec->base + vec->size; + vec->size = 0; + return ret; +} + +/* Release any extra space allocated for VEC. */ + +int +backtrace_vector_release (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data) +{ + size_t size; + size_t alc; + size_t aligned; + + /* Make sure that the block that we free is aligned on an 8-byte + boundary. */ + size = vec->size; + alc = vec->alc; + aligned = (size + 7) & ~ (size_t) 7; + alc -= aligned - size; + + backtrace_free (state, (char *) vec->base + aligned, alc, + error_callback, data); + vec->alc = 0; + if (vec->size == 0) + vec->base = NULL; + return 1; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/mmapio.c b/src/3rdparty/libbacktrace/libbacktrace/mmapio.c new file mode 100644 index 00000000..b188a43a --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/mmapio.c @@ -0,0 +1,106 @@ +/* mmapio.c -- File views using mmap. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +/* This file implements file views and memory allocation when mmap is + available. */ + +/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ + +int +backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED, + int descriptor, off_t offset, uint64_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_view *view) +{ + size_t pagesize; + unsigned int inpage; + off_t pageoff; + void *map; + + if ((uint64_t) (size_t) size != size) + { + error_callback (data, "file size too large", 0); + return 0; + } + + pagesize = getpagesize (); + inpage = offset % pagesize; + pageoff = offset - inpage; + + size += inpage; + size = (size + (pagesize - 1)) & ~ (pagesize - 1); + + map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff); + if (map == MAP_FAILED) + { + error_callback (data, "mmap", errno); + return 0; + } + + view->data = (char *) map + inpage; + view->base = map; + view->len = size; + + return 1; +} + +/* Release a view read by backtrace_get_view. */ + +void +backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_view *view, + backtrace_error_callback error_callback, + void *data) +{ + union { + const void *cv; + void *v; + } const_cast; + + const_cast.cv = view->base; + if (munmap (const_cast.v, view->len) < 0) + error_callback (data, "munmap", errno); +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/posix.c b/src/3rdparty/libbacktrace/libbacktrace/posix.c new file mode 100644 index 00000000..baffb85b --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/posix.c @@ -0,0 +1,100 @@ +/* posix.c -- POSIX file I/O routines for the backtrace library. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* Open a file for reading. */ + +int +backtrace_open (const char *filename, backtrace_error_callback error_callback, + void *data, int *does_not_exist) +{ + int descriptor; + + if (does_not_exist != NULL) + *does_not_exist = 0; + + descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); + if (descriptor < 0) + { + if (does_not_exist != NULL && errno == ENOENT) + *does_not_exist = 1; + else + error_callback (data, filename, errno); + return -1; + } + +#ifdef HAVE_FCNTL + /* Set FD_CLOEXEC just in case the kernel does not support + O_CLOEXEC. It doesn't matter if this fails for some reason. + FIXME: At some point it should be safe to only do this if + O_CLOEXEC == 0. */ + fcntl (descriptor, F_SETFD, FD_CLOEXEC); +#endif + + return descriptor; +} + +/* Close DESCRIPTOR. */ + +int +backtrace_close (int descriptor, backtrace_error_callback error_callback, + void *data) +{ + if (close (descriptor) < 0) + { + error_callback (data, "close", errno); + return 0; + } + return 1; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/print.c b/src/3rdparty/libbacktrace/libbacktrace/print.c new file mode 100644 index 00000000..0767face --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/print.c @@ -0,0 +1,92 @@ +/* print.c -- Print the current backtrace. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Passed to callbacks. */ + +struct print_data +{ + struct backtrace_state *state; + FILE *f; +}; + +/* Print one level of a backtrace. */ + +static int +print_callback (void *data, uintptr_t pc, const char *filename, int lineno, + const char *function) +{ + struct print_data *pdata = (struct print_data *) data; + + fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", + (unsigned long) pc, + function == NULL ? "???" : function, + filename == NULL ? "???" : filename, + lineno); + return 0; +} + +/* Print errors to stderr. */ + +static void +error_callback (void *data, const char *msg, int errnum) +{ + struct print_data *pdata = (struct print_data *) data; + + if (pdata->state->filename != NULL) + fprintf (stderr, "%s: ", pdata->state->filename); + fprintf (stderr, "libbacktrace: %s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fputc ('\n', stderr); +} + +/* Print a backtrace. */ + +void __attribute__((noinline)) +backtrace_print (struct backtrace_state *state, int skip, FILE *f) +{ + struct print_data data; + + data.state = state; + data.f = f; + backtrace_full (state, skip + 1, print_callback, error_callback, + (void *) &data); +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/simple.c b/src/3rdparty/libbacktrace/libbacktrace/simple.c new file mode 100644 index 00000000..11893639 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/simple.c @@ -0,0 +1,108 @@ +/* simple.c -- The backtrace_simple function. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include "unwind.h" +#include "backtrace.h" + +/* The simple_backtrace routine. */ + +/* Data passed through _Unwind_Backtrace. */ + +struct backtrace_simple_data +{ + /* Number of frames to skip. */ + int skip; + /* Library state. */ + struct backtrace_state *state; + /* Callback routine. */ + backtrace_simple_callback callback; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data to pass to callback routine. */ + void *data; + /* Value to return from backtrace. */ + int ret; +}; + +/* Unwind library callback routine. This is passd to + _Unwind_Backtrace. */ + +static _Unwind_Reason_Code +simple_unwind (struct _Unwind_Context *context, void *vdata) +{ + struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata; + uintptr_t pc; + int ip_before_insn = 0; + +#ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + pc = _Unwind_GetIP (context); +#endif + + if (bdata->skip > 0) + { + --bdata->skip; + return _URC_NO_REASON; + } + + if (!ip_before_insn) + --pc; + + bdata->ret = bdata->callback (bdata->data, pc); + + if (bdata->ret != 0) + return _URC_END_OF_STACK; + + return _URC_NO_REASON; +} + +/* Get a simple stack backtrace. */ + +int __attribute__((noinline)) +backtrace_simple (struct backtrace_state *state, int skip, + backtrace_simple_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct backtrace_simple_data bdata; + + bdata.skip = skip + 1; + bdata.state = state; + bdata.callback = callback; + bdata.error_callback = error_callback; + bdata.data = data; + bdata.ret = 0; + _Unwind_Backtrace (simple_unwind, &bdata); + return bdata.ret; +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/sort.c b/src/3rdparty/libbacktrace/libbacktrace/sort.c new file mode 100644 index 00000000..6fe5ba24 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/sort.c @@ -0,0 +1,108 @@ +/* sort.c -- Sort without allocating memory + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* The GNU glibc version of qsort allocates memory, which we must not + do if we are invoked by a signal handler. So provide our own + sort. */ + +static void +swap (char *a, char *b, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++, a++, b++) + { + char t; + + t = *a; + *a = *b; + *b = t; + } +} + +void +backtrace_qsort (void *basearg, size_t count, size_t size, + int (*compar) (const void *, const void *)) +{ + char *base = (char *) basearg; + size_t i; + size_t mid; + + tail_recurse: + if (count < 2) + return; + + /* The symbol table and DWARF tables, which is all we use this + routine for, tend to be roughly sorted. Pick the middle element + in the array as our pivot point, so that we are more likely to + cut the array in half for each recursion step. */ + swap (base, base + (count / 2) * size, size); + + mid = 0; + for (i = 1; i < count; i++) + { + if ((*compar) (base, base + i * size) > 0) + { + ++mid; + if (i != mid) + swap (base + mid * size, base + i * size, size); + } + } + + if (mid > 0) + swap (base, base + mid * size, size); + + /* Recurse with the smaller array, loop with the larger one. That + ensures that our maximum stack depth is log count. */ + if (2 * mid < count) + { + backtrace_qsort (base, mid, size, compar); + base += (mid + 1) * size; + count -= mid + 1; + goto tail_recurse; + } + else + { + backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), + size, compar); + count = mid; + goto tail_recurse; + } +} diff --git a/src/3rdparty/libbacktrace/libbacktrace/state.c b/src/3rdparty/libbacktrace/libbacktrace/state.c new file mode 100644 index 00000000..6196c267 --- /dev/null +++ b/src/3rdparty/libbacktrace/libbacktrace/state.c @@ -0,0 +1,72 @@ +/* state.c -- Create the backtrace state. + Copyright (C) 2012-2019 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "config.h" + +#include +#include + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* Create the backtrace state. This will then be passed to all the + other routines. */ + +struct backtrace_state * +backtrace_create_state (const char *filename, int threaded, + backtrace_error_callback error_callback, + void *data) +{ + struct backtrace_state init_state; + struct backtrace_state *state; + +#ifndef HAVE_SYNC_FUNCTIONS + if (threaded) + { + error_callback (data, "backtrace library does not support threads", 0); + return NULL; + } +#endif + + memset (&init_state, 0, sizeof init_state); + init_state.filename = filename; + init_state.threaded = threaded; + + state = ((struct backtrace_state *) + backtrace_alloc (&init_state, sizeof *state, error_callback, data)); + if (state == NULL) + return NULL; + *state = init_state; + + return state; +} diff --git a/src/3rdparty/libbacktrace/qt_attribution.json b/src/3rdparty/libbacktrace/qt_attribution.json new file mode 100644 index 00000000..e8c7bf6f --- /dev/null +++ b/src/3rdparty/libbacktrace/qt_attribution.json @@ -0,0 +1,15 @@ +{ + "Id": "libbacktrace", + "Name": "libbacktrace", + "QDocModule": "applicationmanager", + "QtUsage": "Automatically used in Qt ApplicationManager, if available. Configure with -config disable-libbacktrace to avoid.", + + "Description": "Standalone fork of libbacktrace - libbacktrace prints stack traces.", + "Homepage": "https://github.com/ErwanLegrand/libbacktrace", + "Version": "2016-05-18", + + "License": "BSD 3-clause \"New\" or \"Revised\" License", + "LicenseId": "BSD-3-Clause", + "LicenseFile": "LICENSE", + "Copyright": "Copyright (C) 2012-2016 Free Software Foundation, Inc." +} diff --git a/src/3rdparty/libyaml/CMakeLists.txt b/src/3rdparty/libyaml/CMakeLists.txt new file mode 100644 index 00000000..1c189116 --- /dev/null +++ b/src/3rdparty/libyaml/CMakeLists.txt @@ -0,0 +1,43 @@ +# Generated from libyaml.pro. + +##################################################################### +## BundledLibYaml Generic Library: +##################################################################### + +qt_internal_add_3rdparty_library(BundledLibYaml + QMAKE_LIB_NAME yaml + STATIC + INSTALL + SOURCES + src/api.c + src/dumper.c + src/emitter.c + src/loader.c + src/parser.c + src/reader.c + src/scanner.c + src/writer.c + DEFINES + HAVE_CONFIG_H + YAML_DECLARE_STATIC + YAML_DECLARE_EXPORT + PUBLIC_DEFINES + YAML_DECLARE_STATIC + INCLUDE_DIRECTORIES + include + win32 + PUBLIC_INCLUDE_DIRECTORIES + $ +) + +qt_disable_warnings(BundledLibYaml) +qt_set_symbol_visibility_hidden(BundledLibYaml) + +#### Keys ignored in scope 2:.:.:libyaml.pro:win32-msvc_x_: +# QMAKE_CFLAGS = "/D_CRT_SECURE_NO_WARNINGS" + +#### Keys ignored in scope 3:.:.:libyaml.pro:GCC: +# QMAKE_CFLAGS = "-Wno-unused" + +#### Keys ignored in scope 4:.:.:libyaml.pro:CLANG: +# QMAKE_CFLAGS = "-Wall" "-W" "-Wno-unused" diff --git a/src/3rdparty/libyaml/LICENSE b/src/3rdparty/libyaml/LICENSE new file mode 100644 index 00000000..21cdd1d6 --- /dev/null +++ b/src/3rdparty/libyaml/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2017-2018 Ingy döt Net +Copyright (c) 2006-2016 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/3rdparty/libyaml/README b/src/3rdparty/libyaml/README new file mode 100644 index 00000000..373727e0 --- /dev/null +++ b/src/3rdparty/libyaml/README @@ -0,0 +1,27 @@ +LibYAML - A C library for parsing and emitting YAML. + +To build and install the library, run: +$ ./configure +$ make +# make install + +If you checked the source code from the Mercurial repository, run +$ ./bootstrap +$ ./configure +$ make +# make install + +For more information, check the LibYAML homepage: +'http://pyyaml.org/wiki/LibYAML'. + +Post your questions and opinions to the YAML-Core mailing list: +'http://lists.sourceforge.net/lists/listinfo/yaml-core'. + +Submit bug reports and feature requests to the LibYAML bug tracker: +'https://bitbucket.org/xi/libyaml/issues/new'. + +LibYAML is written by Kirill Simonov . It is released +under the MIT license. See the file LICENSE for more details. + +This project is developed for Python Software Foundation as a part of +Google Summer of Code under the mentorship of Clark Evans. diff --git a/src/3rdparty/libyaml/include/yaml.h b/src/3rdparty/libyaml/include/yaml.h new file mode 100644 index 00000000..89050e4f --- /dev/null +++ b/src/3rdparty/libyaml/include/yaml.h @@ -0,0 +1,1985 @@ +/** + * @file yaml.h + * @brief Public interface for libyaml. + * + * Include the header file with the code: + * @code + * #include + * @endcode + */ + +#ifndef YAML_H +#define YAML_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @defgroup export Export Definitions + * @{ + */ + +/** The public API declaration. */ + +#if defined(__MINGW32__) +# define YAML_DECLARE(type) type +#elif defined(_WIN32) +# if defined(YAML_DECLARE_STATIC) +# define YAML_DECLARE(type) type +# elif defined(YAML_DECLARE_EXPORT) +# define YAML_DECLARE(type) __declspec(dllexport) type +# else +# define YAML_DECLARE(type) __declspec(dllimport) type +# endif +#else +# define YAML_DECLARE(type) type +#endif + +/** @} */ + +/** + * @defgroup version Version Information + * @{ + */ + +/** + * Get the library version as a string. + * + * @returns The function returns the pointer to a static string of the form + * @c "X.Y.Z", where @c X is the major version number, @c Y is a minor version + * number, and @c Z is the patch version number. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void); + +/** + * Get the library version numbers. + * + * @param[out] major Major version number. + * @param[out] minor Minor version number. + * @param[out] patch Patch version number. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch); + +/** @} */ + +/** + * @defgroup basic Basic Types + * @{ + */ + +/** The character type (UTF-8 octet). */ +typedef unsigned char yaml_char_t; + +/** The version directive data. */ +typedef struct yaml_version_directive_s { + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; +} yaml_version_directive_t; + +/** The tag directive data. */ +typedef struct yaml_tag_directive_s { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; +} yaml_tag_directive_t; + +/** The stream encoding. */ +typedef enum yaml_encoding_e { + /** Let the parser choose the encoding. */ + YAML_ANY_ENCODING, + /** The default UTF-8 encoding. */ + YAML_UTF8_ENCODING, + /** The UTF-16-LE encoding with BOM. */ + YAML_UTF16LE_ENCODING, + /** The UTF-16-BE encoding with BOM. */ + YAML_UTF16BE_ENCODING +} yaml_encoding_t; + +/** Line break types. */ + +typedef enum yaml_break_e { + /** Let the parser choose the break type. */ + YAML_ANY_BREAK, + /** Use CR for line breaks (Mac style). */ + YAML_CR_BREAK, + /** Use LN for line breaks (Unix style). */ + YAML_LN_BREAK, + /** Use CR LN for line breaks (DOS style). */ + YAML_CRLN_BREAK +} yaml_break_t; + +/** Many bad things could happen with the parser and emitter. */ +typedef enum yaml_error_type_e { + /** No error is produced. */ + YAML_NO_ERROR, + + /** Cannot allocate or reallocate a block of memory. */ + YAML_MEMORY_ERROR, + + /** Cannot read or decode the input stream. */ + YAML_READER_ERROR, + /** Cannot scan the input stream. */ + YAML_SCANNER_ERROR, + /** Cannot parse the input stream. */ + YAML_PARSER_ERROR, + /** Cannot compose a YAML document. */ + YAML_COMPOSER_ERROR, + + /** Cannot write to the output stream. */ + YAML_WRITER_ERROR, + /** Cannot emit a YAML stream. */ + YAML_EMITTER_ERROR +} yaml_error_type_t; + +/** The pointer position. */ +typedef struct yaml_mark_s { + /** The position index. */ + size_t index; + + /** The position line. */ + size_t line; + + /** The position column. */ + size_t column; +} yaml_mark_t; + +/** @} */ + +/** + * @defgroup styles Node Styles + * @{ + */ + +/** Scalar styles. */ +typedef enum yaml_scalar_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_SCALAR_STYLE, + + /** The plain scalar style. */ + YAML_PLAIN_SCALAR_STYLE, + + /** The single-quoted scalar style. */ + YAML_SINGLE_QUOTED_SCALAR_STYLE, + /** The double-quoted scalar style. */ + YAML_DOUBLE_QUOTED_SCALAR_STYLE, + + /** The literal scalar style. */ + YAML_LITERAL_SCALAR_STYLE, + /** The folded scalar style. */ + YAML_FOLDED_SCALAR_STYLE +} yaml_scalar_style_t; + +/** Sequence styles. */ +typedef enum yaml_sequence_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_SEQUENCE_STYLE, + + /** The block sequence style. */ + YAML_BLOCK_SEQUENCE_STYLE, + /** The flow sequence style. */ + YAML_FLOW_SEQUENCE_STYLE +} yaml_sequence_style_t; + +/** Mapping styles. */ +typedef enum yaml_mapping_style_e { + /** Let the emitter choose the style. */ + YAML_ANY_MAPPING_STYLE, + + /** The block mapping style. */ + YAML_BLOCK_MAPPING_STYLE, + /** The flow mapping style. */ + YAML_FLOW_MAPPING_STYLE +/* YAML_FLOW_SET_MAPPING_STYLE */ +} yaml_mapping_style_t; + +/** @} */ + +/** + * @defgroup tokens Tokens + * @{ + */ + +/** Token types. */ +typedef enum yaml_token_type_e { + /** An empty token. */ + YAML_NO_TOKEN, + + /** A STREAM-START token. */ + YAML_STREAM_START_TOKEN, + /** A STREAM-END token. */ + YAML_STREAM_END_TOKEN, + + /** A VERSION-DIRECTIVE token. */ + YAML_VERSION_DIRECTIVE_TOKEN, + /** A TAG-DIRECTIVE token. */ + YAML_TAG_DIRECTIVE_TOKEN, + /** A DOCUMENT-START token. */ + YAML_DOCUMENT_START_TOKEN, + /** A DOCUMENT-END token. */ + YAML_DOCUMENT_END_TOKEN, + + /** A BLOCK-SEQUENCE-START token. */ + YAML_BLOCK_SEQUENCE_START_TOKEN, + /** A BLOCK-MAPPING-START token. */ + YAML_BLOCK_MAPPING_START_TOKEN, + /** A BLOCK-END token. */ + YAML_BLOCK_END_TOKEN, + + /** A FLOW-SEQUENCE-START token. */ + YAML_FLOW_SEQUENCE_START_TOKEN, + /** A FLOW-SEQUENCE-END token. */ + YAML_FLOW_SEQUENCE_END_TOKEN, + /** A FLOW-MAPPING-START token. */ + YAML_FLOW_MAPPING_START_TOKEN, + /** A FLOW-MAPPING-END token. */ + YAML_FLOW_MAPPING_END_TOKEN, + + /** A BLOCK-ENTRY token. */ + YAML_BLOCK_ENTRY_TOKEN, + /** A FLOW-ENTRY token. */ + YAML_FLOW_ENTRY_TOKEN, + /** A KEY token. */ + YAML_KEY_TOKEN, + /** A VALUE token. */ + YAML_VALUE_TOKEN, + + /** An ALIAS token. */ + YAML_ALIAS_TOKEN, + /** An ANCHOR token. */ + YAML_ANCHOR_TOKEN, + /** A TAG token. */ + YAML_TAG_TOKEN, + /** A SCALAR token. */ + YAML_SCALAR_TOKEN +} yaml_token_type_t; + +/** The token structure. */ +typedef struct yaml_token_s { + + /** The token type. */ + yaml_token_type_t type; + + /** The token data. */ + union { + + /** The stream start (for @c YAML_STREAM_START_TOKEN). */ + struct { + /** The stream encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The alias (for @c YAML_ALIAS_TOKEN). */ + struct { + /** The alias value. */ + yaml_char_t *value; + } alias; + + /** The anchor (for @c YAML_ANCHOR_TOKEN). */ + struct { + /** The anchor value. */ + yaml_char_t *value; + } anchor; + + /** The tag (for @c YAML_TAG_TOKEN). */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag suffix. */ + yaml_char_t *suffix; + } tag; + + /** The scalar value (for @c YAML_SCALAR_TOKEN). */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The version directive (for @c YAML_VERSION_DIRECTIVE_TOKEN). */ + struct { + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; + } version_directive; + + /** The tag directive (for @c YAML_TAG_DIRECTIVE_TOKEN). */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; + } tag_directive; + + } data; + + /** The beginning of the token. */ + yaml_mark_t start_mark; + /** The end of the token. */ + yaml_mark_t end_mark; + +} yaml_token_t; + +/** + * Free any memory allocated for a token object. + * + * @param[in,out] token A token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token); + +/** @} */ + +/** + * @defgroup events Events + * @{ + */ + +/** Event types. */ +typedef enum yaml_event_type_e { + /** An empty event. */ + YAML_NO_EVENT, + + /** A STREAM-START event. */ + YAML_STREAM_START_EVENT, + /** A STREAM-END event. */ + YAML_STREAM_END_EVENT, + + /** A DOCUMENT-START event. */ + YAML_DOCUMENT_START_EVENT, + /** A DOCUMENT-END event. */ + YAML_DOCUMENT_END_EVENT, + + /** An ALIAS event. */ + YAML_ALIAS_EVENT, + /** A SCALAR event. */ + YAML_SCALAR_EVENT, + + /** A SEQUENCE-START event. */ + YAML_SEQUENCE_START_EVENT, + /** A SEQUENCE-END event. */ + YAML_SEQUENCE_END_EVENT, + + /** A MAPPING-START event. */ + YAML_MAPPING_START_EVENT, + /** A MAPPING-END event. */ + YAML_MAPPING_END_EVENT +} yaml_event_type_t; + +/** The event structure. */ +typedef struct yaml_event_s { + + /** The event type. */ + yaml_event_type_t type; + + /** The event data. */ + union { + + /** The stream parameters (for @c YAML_STREAM_START_EVENT). */ + struct { + /** The document encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The document parameters (for @c YAML_DOCUMENT_START_EVENT). */ + struct { + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document indicator implicit? */ + int implicit; + } document_start; + + /** The document end parameters (for @c YAML_DOCUMENT_END_EVENT). */ + struct { + /** Is the document end indicator implicit? */ + int implicit; + } document_end; + + /** The alias parameters (for @c YAML_ALIAS_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + } alias; + + /** The scalar parameters (for @c YAML_SCALAR_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** Is the tag optional for the plain style? */ + int plain_implicit; + /** Is the tag optional for any non-plain style? */ + int quoted_implicit; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_START_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence_start; + + /** The mapping parameters (for @c YAML_MAPPING_START_EVENT). */ + struct { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping_start; + + } data; + + /** The beginning of the event. */ + yaml_mark_t start_mark; + /** The end of the event. */ + yaml_mark_t end_mark; + +} yaml_event_t; + +/** + * Create the STREAM-START event. + * + * @param[out] event An empty event object. + * @param[in] encoding The stream encoding. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding); + +/** + * Create the STREAM-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event); + +/** + * Create the DOCUMENT-START event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] implicit If the document start indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit); + +/** + * Create the DOCUMENT-END event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] implicit If the document end indicator is implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit); + +/** + * Create an ALIAS event. + * + * @param[out] event An empty event object. + * @param[in] anchor The anchor value. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, const yaml_char_t *anchor); + +/** + * Create a SCALAR event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or one of the @a plain_implicit and + * @a quoted_implicit flags must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The scalar anchor or @c NULL. + * @param[in] tag The scalar tag or @c NULL. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] plain_implicit If the tag may be omitted for the plain + * style. + * @param[in] quoted_implicit If the tag may be omitted for any + * non-plain style. + * @param[in] style The scalar style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, + const yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The sequence anchor or @c NULL. + * @param[in] tag The sequence tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The sequence style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, int implicit, + yaml_sequence_style_t style); + +/** + * Create a SEQUENCE-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event); + +/** + * Create a MAPPING-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The mapping anchor or @c NULL. + * @param[in] tag The mapping tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The mapping style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, int implicit, + yaml_mapping_style_t style); + +/** + * Create a MAPPING-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event); + +/** + * Free any memory allocated for an event object. + * + * @param[in,out] event An event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event); + +/** @} */ + +/** + * @defgroup nodes Nodes + * @{ + */ + +/** The tag @c !!null with the only possible value: @c null. */ +#define YAML_NULL_TAG "tag:yaml.org,2002:null" +/** The tag @c !!bool with the values: @c true and @c false. */ +#define YAML_BOOL_TAG "tag:yaml.org,2002:bool" +/** The tag @c !!str for string values. */ +#define YAML_STR_TAG "tag:yaml.org,2002:str" +/** The tag @c !!int for integer values. */ +#define YAML_INT_TAG "tag:yaml.org,2002:int" +/** The tag @c !!float for float values. */ +#define YAML_FLOAT_TAG "tag:yaml.org,2002:float" +/** The tag @c !!timestamp for date and time values. */ +#define YAML_TIMESTAMP_TAG "tag:yaml.org,2002:timestamp" + +/** The tag @c !!seq is used to denote sequences. */ +#define YAML_SEQ_TAG "tag:yaml.org,2002:seq" +/** The tag @c !!map is used to denote mapping. */ +#define YAML_MAP_TAG "tag:yaml.org,2002:map" + +/** The default scalar tag is @c !!str. */ +#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG +/** The default sequence tag is @c !!seq. */ +#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG +/** The default mapping tag is @c !!map. */ +#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG + +/** Node types. */ +typedef enum yaml_node_type_e { + /** An empty node. */ + YAML_NO_NODE, + + /** A scalar node. */ + YAML_SCALAR_NODE, + /** A sequence node. */ + YAML_SEQUENCE_NODE, + /** A mapping node. */ + YAML_MAPPING_NODE +} yaml_node_type_t; + +/** The forward definition of a document node structure. */ +typedef struct yaml_node_s yaml_node_t; + +/** An element of a sequence node. */ +typedef int yaml_node_item_t; + +/** An element of a mapping node. */ +typedef struct yaml_node_pair_s { + /** The key of the element. */ + int key; + /** The value of the element. */ + int value; +} yaml_node_pair_t; + +/** The node structure. */ +struct yaml_node_s { + + /** The node type. */ + yaml_node_type_t type; + + /** The node tag. */ + yaml_char_t *tag; + + /** The node data. */ + union { + + /** The scalar parameters (for @c YAML_SCALAR_NODE). */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */ + struct { + /** The stack of sequence items. */ + struct { + /** The beginning of the stack. */ + yaml_node_item_t *start; + /** The end of the stack. */ + yaml_node_item_t *end; + /** The top of the stack. */ + yaml_node_item_t *top; + } items; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence; + + /** The mapping parameters (for @c YAML_MAPPING_NODE). */ + struct { + /** The stack of mapping pairs (key, value). */ + struct { + /** The beginning of the stack. */ + yaml_node_pair_t *start; + /** The end of the stack. */ + yaml_node_pair_t *end; + /** The top of the stack. */ + yaml_node_pair_t *top; + } pairs; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping; + + } data; + + /** The beginning of the node. */ + yaml_mark_t start_mark; + /** The end of the node. */ + yaml_mark_t end_mark; + +}; + +/** The document structure. */ +typedef struct yaml_document_s { + + /** The document nodes. */ + struct { + /** The beginning of the stack. */ + yaml_node_t *start; + /** The end of the stack. */ + yaml_node_t *end; + /** The top of the stack. */ + yaml_node_t *top; + } nodes; + + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document start indicator implicit? */ + int start_implicit; + /** Is the document end indicator implicit? */ + int end_implicit; + + /** The beginning of the document. */ + yaml_mark_t start_mark; + /** The end of the document. */ + yaml_mark_t end_mark; + +} yaml_document_t; + +/** + * Create a YAML document. + * + * @param[out] document An empty document object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] start_implicit If the document start indicator is + * implicit. + * @param[in] end_implicit If the document end indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit); + +/** + * Delete a YAML document and all its nodes. + * + * @param[in,out] document A document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document); + +/** + * Get a node of a YAML document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * @param[in] document A document object. + * @param[in] index The node id. + * + * @returns the node objct or @c NULL if @c node_id is out of range. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index); + +/** + * Get the root of a YAML document node. + * + * The root object is the first object added to the document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * An empty document produced by the parser signifies the end of a YAML + * stream. + * + * @param[in] document A document object. + * + * @returns the node object or @c NULL if the document is empty. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document); + +/** + * Create a SCALAR node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The scalar tag. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] style The scalar style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + const yaml_char_t *tag, const yaml_char_t *value, int length, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + const yaml_char_t *tag, yaml_sequence_style_t style); + +/** + * Create a MAPPING node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + const yaml_char_t *tag, yaml_mapping_style_t style); + +/** + * Add an item to a SEQUENCE node. + * + * @param[in,out] document A document object. + * @param[in] sequence The sequence node id. + * @param[in] item The item node id. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item); + +/** + * Add a pair of a key and a value to a MAPPING node. + * + * @param[in,out] document A document object. + * @param[in] mapping The mapping node id. + * @param[in] key The key node id. + * @param[in] value The value node id. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value); + +/** @} */ + +/** + * @defgroup parser Parser Definitions + * @{ + */ + +/** + * The prototype of a read handler. + * + * The read handler is called when the parser needs to read more bytes from the + * source. The handler should write not more than @a size bytes to the @a + * buffer. The number of written bytes should be set to the @a length variable. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_parser_set_input(). + * @param[out] buffer The buffer to write the data from the source. + * @param[in] size The size of the buffer. + * @param[out] size_read The actual number of bytes read from the source. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. On EOF, the handler should set the + * @a size_read to @c 0 and return @c 1. + */ + +typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size, + size_t *size_read); + +/** + * This structure holds information about a potential simple key. + */ + +typedef struct yaml_simple_key_s { + /** Is a simple key possible? */ + int possible; + + /** Is a simple key required? */ + int required; + + /** The number of the token. */ + size_t token_number; + + /** The position mark. */ + yaml_mark_t mark; +} yaml_simple_key_t; + +/** + * The states of the parser. + */ +typedef enum yaml_parser_state_e { + /** Expect STREAM-START. */ + YAML_PARSE_STREAM_START_STATE, + /** Expect the beginning of an implicit document. */ + YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START. */ + YAML_PARSE_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_PARSE_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_PARSE_DOCUMENT_END_STATE, + + /** Expect a block node. */ + YAML_PARSE_BLOCK_NODE_STATE, + /** Expect a block node or indentless sequence. */ + YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, + /** Expect a flow node. */ + YAML_PARSE_FLOW_NODE_STATE, + /** Expect the first entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, + /** Expect an entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, + + /** Expect an entry of an indentless sequence. */ + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, + /** Expect the first key of a block mapping. */ + YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect a block mapping key. */ + YAML_PARSE_BLOCK_MAPPING_KEY_STATE, + /** Expect a block mapping value. */ + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, + /** Expect the first entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, + + /** Expect an entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, + /** Expect a key of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, + /** Expect a value of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, + /** Expect the and of an ordered mapping entry. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, + /** Expect the first key of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + + YAML_PARSE_FLOW_MAPPING_KEY_STATE, + /** Expect a value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_VALUE_STATE, + /** Expect an empty value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, + /** Expect nothing. */ + YAML_PARSE_END_STATE +} yaml_parser_state_t; + +/** + * This structure holds aliases data. + */ + +typedef struct yaml_alias_data_s { + /** The anchor. */ + yaml_char_t *anchor; + /** The node id. */ + int index; + /** The anchor mark. */ + yaml_mark_t mark; +} yaml_alias_data_t; + +/** + * The parser structure. + * + * All members are internal. Manage the structure using the @c yaml_parser_ + * family of functions. + */ + +typedef struct yaml_parser_s { + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + /** The byte about which the problem occured. */ + size_t problem_offset; + /** The problematic value (@c -1 is none). */ + int problem_value; + /** The problem position. */ + yaml_mark_t problem_mark; + /** The error context. */ + const char *context; + /** The context position. */ + yaml_mark_t context_mark; + + /** + * @} + */ + + /** + * @name Reader stuff + * @{ + */ + + /** Read handler. */ + yaml_read_handler_t *read_handler; + + /** A pointer for passing to the read handler. */ + void *read_handler_data; + + /** Standard (string or file) input data. */ + union { + /** String input data. */ + struct { + /** The string start pointer. */ + const unsigned char *start; + /** The string end pointer. */ + const unsigned char *end; + /** The string current position. */ + const unsigned char *current; + } string; + + /** File input data. */ + FILE *file; + } input; + + /** EOF flag */ + int eof; + + /** The working buffer. */ + struct { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /* The number of unread characters in the buffer. */ + size_t unread; + + /** The raw buffer. */ + struct { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The input encoding. */ + yaml_encoding_t encoding; + + /** The offset of the current position (in bytes). */ + size_t offset; + + /** The mark of the current position. */ + yaml_mark_t mark; + + /** + * @} + */ + + /** + * @name Scanner stuff + * @{ + */ + + /** Have we started to scan the input stream? */ + int stream_start_produced; + + /** Have we reached the end of the input stream? */ + int stream_end_produced; + + /** The number of unclosed '[' and '{' indicators. */ + int flow_level; + + /** The tokens queue. */ + struct { + /** The beginning of the tokens queue. */ + yaml_token_t *start; + /** The end of the tokens queue. */ + yaml_token_t *end; + /** The head of the tokens queue. */ + yaml_token_t *head; + /** The tail of the tokens queue. */ + yaml_token_t *tail; + } tokens; + + /** The number of tokens fetched from the queue. */ + size_t tokens_parsed; + + /** Does the tokens queue contain a token ready for dequeueing. */ + int token_available; + + /** The indentation levels stack. */ + struct { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The current indentation level. */ + int indent; + + /** May a simple key occur at the current position? */ + int simple_key_allowed; + + /** The stack of simple keys. */ + struct { + /** The beginning of the stack. */ + yaml_simple_key_t *start; + /** The end of the stack. */ + yaml_simple_key_t *end; + /** The top of the stack. */ + yaml_simple_key_t *top; + } simple_keys; + + /** + * @} + */ + + /** + * @name Parser stuff + * @{ + */ + + /** The parser states stack. */ + struct { + /** The beginning of the stack. */ + yaml_parser_state_t *start; + /** The end of the stack. */ + yaml_parser_state_t *end; + /** The top of the stack. */ + yaml_parser_state_t *top; + } states; + + /** The current parser state. */ + yaml_parser_state_t state; + + /** The stack of marks. */ + struct { + /** The beginning of the stack. */ + yaml_mark_t *start; + /** The end of the stack. */ + yaml_mark_t *end; + /** The top of the stack. */ + yaml_mark_t *top; + } marks; + + /** The list of TAG directives. */ + struct { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** The alias data. */ + struct { + /** The beginning of the list. */ + yaml_alias_data_t *start; + /** The end of the list. */ + yaml_alias_data_t *end; + /** The top of the list. */ + yaml_alias_data_t *top; + } aliases; + + /** The currently parsed document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_parser_t; + +/** + * Initialize a parser. + * + * This function creates a new parser object. An application is responsible + * for destroying the object using the yaml_parser_delete() function. + * + * @param[out] parser An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser); + +/** + * Destroy a parser. + * + * @param[in,out] parser A parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser); + +/** + * Set a string input. + * + * Note that the @a input pointer must be valid while the @a parser object + * exists. The application is responsible for destroing @a input after + * destroying the @a parser. + * + * @param[in,out] parser A parser object. + * @param[in] input A source data. + * @param[in] size The length of the source data in bytes. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size); + +/** + * Set a file input. + * + * @a file should be a file object open for reading. The application is + * responsible for closing the @a file. + * + * @param[in,out] parser A parser object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file); + +/** + * Set a generic input handler. + * + * @param[in,out] parser A parser object. + * @param[in] handler A read handler. + * @param[in] data Any application data for passing to the read + * handler. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data); + +/** + * Set the source encoding. + * + * @param[in,out] parser A parser object. + * @param[in] encoding The source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding); + +/** + * Scan the input stream and produce the next token. + * + * Call the function subsequently to produce a sequence of tokens corresponding + * to the input stream. The initial token has the type + * @c YAML_STREAM_START_TOKEN while the ending token has the type + * @c YAML_STREAM_END_TOKEN. + * + * An application is responsible for freeing any buffers associated with the + * produced token object using the @c yaml_token_delete function. + * + * An application must not alternate the calls of yaml_parser_scan() with the + * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] token An empty token object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/** + * Parse the input stream and produce the next parsing event. + * + * Call the function subsequently to produce a sequence of events corresponding + * to the input stream. The initial event has the type + * @c YAML_STREAM_START_EVENT while the ending event has the type + * @c YAML_STREAM_END_EVENT. + * + * An application is responsible for freeing any buffers associated with the + * produced event object using the yaml_event_delete() function. + * + * An application must not alternate the calls of yaml_parser_parse() with the + * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the + * parser. + * + * @param[in,out] parser A parser object. + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/** + * Parse the input stream and produce the next YAML document. + * + * Call this function subsequently to produce a sequence of documents + * constituting the input stream. + * + * If the produced document has no root node, it means that the document + * end has been reached. + * + * An application is responsible for freeing any data associated with the + * produced document object using the yaml_document_delete() function. + * + * An application must not alternate the calls of yaml_parser_load() with the + * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] document An empty document object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/** @} */ + +/** + * @defgroup emitter Emitter Definitions + * @{ + */ + +/** + * The prototype of a write handler. + * + * The write handler is called when the emitter needs to flush the accumulated + * characters to the output. The handler should write @a size bytes of the + * @a buffer to the output. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_emitter_set_output(). + * @param[in] buffer The buffer with bytes to be written. + * @param[in] size The size of the buffer. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. + */ + +typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size); + +/** The emitter states. */ +typedef enum yaml_emitter_state_e { + /** Expect STREAM-START. */ + YAML_EMIT_STREAM_START_STATE, + /** Expect the first DOCUMENT-START or STREAM-END. */ + YAML_EMIT_FIRST_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START or STREAM-END. */ + YAML_EMIT_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_EMIT_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_EMIT_DOCUMENT_END_STATE, + + /** Expect the first item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, + /** Expect the first key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_KEY_STATE, + /** Expect a value for a simple key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, + + /** Expect a value of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_VALUE_STATE, + /** Expect the first item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, + /** Expect the first key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect the key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_KEY_STATE, + + /** Expect a value for a simple key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, + /** Expect a value of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, + /** Expect nothing. */ + YAML_EMIT_END_STATE +} yaml_emitter_state_t; + + +/* This is needed for C++ */ + +typedef struct yaml_anchors_s { + /** The number of references. */ + int references; + /** The anchor id. */ + int anchor; + /** If the node has been emitted? */ + int serialized; +} yaml_anchors_t; + +/** + * The emitter structure. + * + * All members are internal. Manage the structure using the @c yaml_emitter_ + * family of functions. + */ + +typedef struct yaml_emitter_s { + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + + /** + * @} + */ + + /** + * @name Writer stuff + * @{ + */ + + /** Write handler. */ + yaml_write_handler_t *write_handler; + + /** A pointer for passing to the write handler. */ + void *write_handler_data; + + /** Standard (string or file) output data. */ + union { + /** String output data. */ + struct { + /** The buffer pointer. */ + unsigned char *buffer; + /** The buffer size. */ + size_t size; + /** The number of written bytes. */ + size_t *size_written; + } string; + + /** File output data. */ + FILE *file; + } output; + + /** The working buffer. */ + struct { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /** The raw buffer. */ + struct { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The stream encoding. */ + yaml_encoding_t encoding; + + /** + * @} + */ + + /** + * @name Emitter stuff + * @{ + */ + + /** If the output is in the canonical style? */ + int canonical; + /** The number of indentation spaces. */ + int best_indent; + /** The preferred width of the output lines. */ + int best_width; + /** Allow unescaped non-ASCII characters? */ + int unicode; + /** The preferred line break. */ + yaml_break_t line_break; + + /** The stack of states. */ + struct { + /** The beginning of the stack. */ + yaml_emitter_state_t *start; + /** The end of the stack. */ + yaml_emitter_state_t *end; + /** The top of the stack. */ + yaml_emitter_state_t *top; + } states; + + /** The current emitter state. */ + yaml_emitter_state_t state; + + /** The event queue. */ + struct { + /** The beginning of the event queue. */ + yaml_event_t *start; + /** The end of the event queue. */ + yaml_event_t *end; + /** The head of the event queue. */ + yaml_event_t *head; + /** The tail of the event queue. */ + yaml_event_t *tail; + } events; + + /** The stack of indentation levels. */ + struct { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The list of tag directives. */ + struct { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** The current indentation level. */ + int indent; + + /** The current flow level. */ + int flow_level; + + /** Is it the document root context? */ + int root_context; + /** Is it a sequence context? */ + int sequence_context; + /** Is it a mapping context? */ + int mapping_context; + /** Is it a simple mapping key context? */ + int simple_key_context; + + /** The current line. */ + int line; + /** The current column. */ + int column; + /** If the last character was a whitespace? */ + int whitespace; + /** If the last character was an indentation character (' ', '-', '?', ':')? */ + int indention; + /** If an explicit document end is required? */ + int open_ended; + + /** Anchor analysis. */ + struct { + /** The anchor value. */ + yaml_char_t *anchor; + /** The anchor length. */ + size_t anchor_length; + /** Is it an alias? */ + int alias; + } anchor_data; + + /** Tag analysis. */ + struct { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag handle length. */ + size_t handle_length; + /** The tag suffix. */ + yaml_char_t *suffix; + /** The tag suffix length. */ + size_t suffix_length; + } tag_data; + + /** Scalar analysis. */ + struct { + /** The scalar value. */ + yaml_char_t *value; + /** The scalar length. */ + size_t length; + /** Does the scalar contain line breaks? */ + int multiline; + /** Can the scalar be expessed in the flow plain style? */ + int flow_plain_allowed; + /** Can the scalar be expressed in the block plain style? */ + int block_plain_allowed; + /** Can the scalar be expressed in the single quoted style? */ + int single_quoted_allowed; + /** Can the scalar be expressed in the literal or folded styles? */ + int block_allowed; + /** The output style. */ + yaml_scalar_style_t style; + } scalar_data; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** If the stream was already opened? */ + int opened; + /** If the stream was already closed? */ + int closed; + + /** The information associated with the document nodes. */ + yaml_anchors_t *anchors; + + /** The last assigned anchor id. */ + int last_anchor_id; + + /** The currently emitted document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_emitter_t; + +/** + * Initialize an emitter. + * + * This function creates a new emitter object. An application is responsible + * for destroying the object using the yaml_emitter_delete() function. + * + * @param[out] emitter An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter); + +/** + * Destroy an emitter. + * + * @param[in,out] emitter An emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter); + +/** + * Set a string output. + * + * The emitter will write the output characters to the @a output buffer of the + * size @a size. The emitter will set @a size_written to the number of written + * bytes. If the buffer is smaller than required, the emitter produces the + * YAML_WRITE_ERROR error. + * + * @param[in,out] emitter An emitter object. + * @param[in] output An output buffer. + * @param[in] size The buffer size. + * @param[in] size_written The pointer to save the number of written + * bytes. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written); + +/** + * Set a file output. + * + * @a file should be a file object open for writing. The application is + * responsible for closing the @a file. + * + * @param[in,out] emitter An emitter object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file); + +/** + * Set a generic output handler. + * + * @param[in,out] emitter An emitter object. + * @param[in] handler A write handler. + * @param[in] data Any application data for passing to the write + * handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data); + +/** + * Set the output encoding. + * + * @param[in,out] emitter An emitter object. + * @param[in] encoding The output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding); + +/** + * Set if the output should be in the "canonical" format as in the YAML + * specification. + * + * @param[in,out] emitter An emitter object. + * @param[in] canonical If the output is canonical. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical); + +/** + * Set the indentation increment. + * + * @param[in,out] emitter An emitter object. + * @param[in] indent The indentation increment (1 < . < 10). + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent); + +/** + * Set the preferred line width. @c -1 means unlimited. + * + * @param[in,out] emitter An emitter object. + * @param[in] width The preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width); + +/** + * Set if unescaped non-ASCII characters are allowed. + * + * @param[in,out] emitter An emitter object. + * @param[in] unicode If unescaped Unicode characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode); + +/** + * Set the preferred line break. + * + * @param[in,out] emitter An emitter object. + * @param[in] line_break The preferred line break. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break); + +/** + * Emit an event. + * + * The event object may be generated using the yaml_parser_parse() function. + * The emitter takes the responsibility for the event object and destroys its + * content after it is emitted. The event object is destroyed even if the + * function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] event An event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/** + * Start a YAML stream. + * + * This function should be used before yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +/** + * Finish a YAML stream. + * + * This function should be used after yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +/** + * Emit a YAML document. + * + * The documen object may be generated using the yaml_parser_load() function + * or the yaml_document_initialize() function. The emitter takes the + * responsibility for the document object and destroys its content after + * it is emitted. The document object is destroyed even if the function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] document A document object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/** + * Flush the accumulated characters to the output. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef YAML_H */ + diff --git a/src/3rdparty/libyaml/libyaml.pro b/src/3rdparty/libyaml/libyaml.pro new file mode 100644 index 00000000..c1cabd71 --- /dev/null +++ b/src/3rdparty/libyaml/libyaml.pro @@ -0,0 +1,40 @@ +TEMPLATE = lib +TARGET = qtyaml + +load(am-config) + +CONFIG += \ + static \ + hide_symbols \ + exceptions_off rtti_off warn_off \ + installed + +MODULE_DEFINES *= YAML_DECLARE_STATIC +MODULE_INCLUDEPATH += $$PWD/include + +load(qt_helper_lib) + +win32-msvc* { + QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS +} +*-g++* { + QMAKE_CFLAGS += -Wno-unused +} +*-clang* { + CONFIG += warn_off + QMAKE_CFLAGS += -Wall -W -Wno-unused +} + +DEFINES *= YAML_DECLARE_STATIC HAVE_CONFIG_H + +INCLUDEPATH += $$PWD/win32 $$PWD/include + +SOURCES += \ + src/api.c \ + src/dumper.c \ + src/emitter.c \ + src/loader.c \ + src/parser.c \ + src/reader.c \ + src/scanner.c \ + src/writer.c \ diff --git a/src/3rdparty/libyaml/qt_attribution.json b/src/3rdparty/libyaml/qt_attribution.json new file mode 100644 index 00000000..f6cf786e --- /dev/null +++ b/src/3rdparty/libyaml/qt_attribution.json @@ -0,0 +1,16 @@ +{ + "Id": "libyaml", + "Name": "libyaml", + "QDocModule": "applicationmanager", + "QtUsage": "Optionally used in Qt ApplicationManager. Configure with -config force-system-libyaml to avoid.", + + "Description": "LibYAML is a YAML 1.1 parser and emitter written in C.", + "Homepage": "http://pyyaml.org/wiki/LibYAML/", + "Version": "0.2.1", + + "License": "MIT License", + "LicenseId": "MIT", + "LicenseFile": "LICENSE", + "Copyright": "Copyright (c) 2017-2018 Ingy döt Net +Copyright (c) 2006-2016 Kirill Simonov" +} diff --git a/src/3rdparty/libyaml/src/api.c b/src/3rdparty/libyaml/src/api.c new file mode 100644 index 00000000..0c86bf8f --- /dev/null +++ b/src/3rdparty/libyaml/src/api.c @@ -0,0 +1,1401 @@ +// vv AM added vv +// without these, we have no declaration for strdup and since this is C, +// we default to the return value being a 32bit int, effectively destroying +// the actual 64bit pointer. +#define _GNU_SOURCE +#include +#include +// ^^ AM added ^^ + +#include "yaml_private.h" + +/* + * Get the library version. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void) +{ + return YAML_VERSION_STRING; +} + +/* + * Get the library version numbers. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch) +{ + *major = YAML_VERSION_MAJOR; + *minor = YAML_VERSION_MINOR; + *patch = YAML_VERSION_PATCH; +} + +/* + * Allocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size) +{ + return malloc(size ? size : 1); +} + +/* + * Reallocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size) +{ + return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1); +} + +/* + * Free a dynamic memory block. + */ + +YAML_DECLARE(void) +yaml_free(void *ptr) +{ + if (ptr) free(ptr); +} + +/* + * Duplicate a string. + */ + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *str) +{ + if (!str) + return NULL; + + return (yaml_char_t *)strdup((char *)str); +} + +/* + * Extend a string. + */ + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end) +{ + yaml_char_t *new_start = (yaml_char_t *)yaml_realloc((void*)*start, (*end - *start)*2); + + if (!new_start) return 0; + + memset(new_start + (*end - *start), 0, *end - *start); + + *pointer = new_start + (*pointer - *start); + *end = new_start + (*end - *start)*2; + *start = new_start; + + return 1; +} + +/* + * Append a string B to a string A. + */ + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, SHIM(yaml_char_t **b_end)) +{ + UNUSED_PARAM(b_end) + if (*b_start == *b_pointer) + return 1; + + while (*a_end - *a_pointer <= *b_pointer - *b_start) { + if (!yaml_string_extend(a_start, a_pointer, a_end)) + return 0; + } + + memcpy(*a_pointer, *b_start, *b_pointer - *b_start); + *a_pointer += *b_pointer - *b_start; + + return 1; +} + +/* + * Extend a stack. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end) +{ + void *new_start; + + if ((char *)*end - (char *)*start >= INT_MAX / 2) + return 0; + + new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *top = (char *)new_start + ((char *)*top - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + + return 1; +} + +/* + * Extend or move a queue. + */ + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end) +{ + /* Check if we need to resize the queue. */ + + if (*start == *head && *tail == *end) { + void *new_start = yaml_realloc(*start, + ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *head = (char *)new_start + ((char *)*head - (char *)*start); + *tail = (char *)new_start + ((char *)*tail - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + } + + /* Check if we need to move the queue at the beginning of the buffer. */ + + if (*tail == *end) { + if (*head != *tail) { + memmove(*start, *head, (char *)*tail - (char *)*head); + } + *tail = (char *)*tail - (char *)*head + (char *)*start; + *head = *start; + } + + return 1; +} + + +/* + * Create a new parser object. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + memset(parser, 0, sizeof(yaml_parser_t)); + if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE)) + goto error; + if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE, yaml_token_t*)) + goto error; + if (!STACK_INIT(parser, parser->indents, int*)) + goto error; + if (!STACK_INIT(parser, parser->simple_keys, yaml_simple_key_t*)) + goto error; + if (!STACK_INIT(parser, parser->states, yaml_parser_state_t*)) + goto error; + if (!STACK_INIT(parser, parser->marks, yaml_mark_t*)) + goto error; + if (!STACK_INIT(parser, parser->tag_directives, yaml_tag_directive_t*)) + goto error; + + return 1; + +error: + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + STACK_DEL(parser, parser->tag_directives); + + return 0; +} + +/* + * Destroy a parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + while (!QUEUE_EMPTY(parser, parser->tokens)) { + yaml_token_delete(&DEQUEUE(parser, parser->tokens)); + } + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, parser->tag_directives); + + memset(parser, 0, sizeof(yaml_parser_t)); +} + +/* + * String read handler. + */ + +static int +yaml_string_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = (yaml_parser_t *)data; + + if (parser->input.string.current == parser->input.string.end) { + *size_read = 0; + return 1; + } + + if (size > (size_t)(parser->input.string.end + - parser->input.string.current)) { + size = parser->input.string.end - parser->input.string.current; + } + + memcpy(buffer, parser->input.string.current, size); + parser->input.string.current += size; + *size_read = size; + return 1; +} + +/* + * File read handler. + */ + +static int +yaml_file_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = (yaml_parser_t *)data; + + *size_read = fread(buffer, 1, size, parser->input.file); + return !ferror(parser->input.file); +} + +/* + * Set a string input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(input); /* Non-NULL input string expected. */ + + parser->read_handler = yaml_string_read_handler; + parser->read_handler_data = parser; + + parser->input.string.start = input; + parser->input.string.current = input; + parser->input.string.end = input+size; +} + +/* + * Set a file input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(file); /* Non-NULL file object expected. */ + + parser->read_handler = yaml_file_read_handler; + parser->read_handler_data = parser; + + parser->input.file = file; +} + +/* + * Set a generic input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(handler); /* Non-NULL read handler expected. */ + + parser->read_handler = handler; + parser->read_handler_data = data; +} + +/* + * Set the source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->encoding); /* Encoding is already set or detected. */ + + parser->encoding = encoding; +} + +/* + * Create a new emitter object. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + memset(emitter, 0, sizeof(yaml_emitter_t)); + if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->states, yaml_emitter_state_t*)) + goto error; + if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE, yaml_event_t*)) + goto error; + if (!STACK_INIT(emitter, emitter->indents, int*)) + goto error; + if (!STACK_INIT(emitter, emitter->tag_directives, yaml_tag_directive_t*)) + goto error; + + return 1; + +error: + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + STACK_DEL(emitter, emitter->tag_directives); + + return 0; +} + +/* + * Destroy an emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + while (!QUEUE_EMPTY(emitter, emitter->events)) { + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + while (!STACK_EMPTY(empty, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(emitter, emitter->tag_directives); + yaml_free(emitter->anchors); + + memset(emitter, 0, sizeof(yaml_emitter_t)); +} + +/* + * String write handler. + */ + +static int +yaml_string_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = (yaml_emitter_t *)data; + + if (emitter->output.string.size - *emitter->output.string.size_written + < size) { + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, + buffer, + emitter->output.string.size + - *emitter->output.string.size_written); + *emitter->output.string.size_written = emitter->output.string.size; + return 0; + } + + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, buffer, size); + *emitter->output.string.size_written += size; + return 1; +} + +/* + * File write handler. + */ + +static int +yaml_file_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = (yaml_emitter_t *)data; + + return (fwrite(buffer, 1, size, emitter->output.file) == size); +} +/* + * Set a string output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(output); /* Non-NULL output string expected. */ + + emitter->write_handler = yaml_string_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.string.buffer = output; + emitter->output.string.size = size; + emitter->output.string.size_written = size_written; + *size_written = 0; +} + +/* + * Set a file output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(file); /* Non-NULL file object expected. */ + + emitter->write_handler = yaml_file_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.file = file; +} + +/* + * Set a generic output handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(handler); /* Non-NULL handler object expected. */ + + emitter->write_handler = handler; + emitter->write_handler_data = data; +} + +/* + * Set the output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->encoding); /* You can set encoding only once. */ + + emitter->encoding = encoding; +} + +/* + * Set the canonical output style. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->canonical = (canonical != 0); +} + +/* + * Set the indentation increment. + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; +} + +/* + * Set the preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_width = (width >= 0) ? width : -1; +} + +/* + * Set if unescaped non-ASCII characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->unicode = (unicode != 0); +} + +/* + * Set the preferred line break character. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->line_break = line_break; +} + +/* + * Destroy a token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token) +{ + assert(token); /* Non-NULL token object expected. */ + + switch (token->type) + { + case YAML_TAG_DIRECTIVE_TOKEN: + yaml_free(token->data.tag_directive.handle); + yaml_free(token->data.tag_directive.prefix); + break; + + case YAML_ALIAS_TOKEN: + yaml_free(token->data.alias.value); + break; + + case YAML_ANCHOR_TOKEN: + yaml_free(token->data.anchor.value); + break; + + case YAML_TAG_TOKEN: + yaml_free(token->data.tag.handle); + yaml_free(token->data.tag.suffix); + break; + + case YAML_SCALAR_TOKEN: + yaml_free(token->data.scalar.value); + break; + + default: + break; + } + + memset(token, 0, sizeof(yaml_token_t)); +} + +/* + * Check if a string is a valid UTF-8 sequence. + * + * Check 'reader.c' for more details on UTF-8 encoding. + */ + +static int +yaml_check_utf8(const yaml_char_t *start, size_t length) +{ + const yaml_char_t *end = start+length; + const yaml_char_t *pointer = start; + + while (pointer < end) { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + octet = pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + if (!width) return 0; + if (pointer+width > end) return 0; + for (k = 1; k < width; k ++) { + octet = pointer[k]; + if ((octet & 0xC0) != 0x80) return 0; + value = (value << 6) + (octet & 0x3F); + } + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return 0; + + pointer += width; + } + + return 1; +} + +/* + * Create STREAM-START. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_START_EVENT_INIT(*event, encoding, mark, mark); + + return 1; +} + +/* + * Create STREAM-END. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create DOCUMENT-START. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + + assert(event); /* Non-NULL event object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (version_directive) { + version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_START_EVENT_INIT(*event, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + implicit, mark, mark); + + return 1; + +error: + yaml_free(version_directive_copy); + while (!STACK_EMPTY(context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Create DOCUMENT-END. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL emitter object is expected. */ + + DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); + + return 1; +} + +/* + * Create ALIAS. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, const yaml_char_t *anchor) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(anchor); /* Non-NULL anchor is expected. */ + + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; + + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) + return 0; + + ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); + + return 1; +} + +/* + * Create SCALAR. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, + const yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(value); /* Non-NULL anchor is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = YAML_MALLOC(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, + plain_implicit, quoted_implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Create SEQUENCE-START. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, int implicit, + yaml_sequence_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create SEQUENCE-END. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + SEQUENCE_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create MAPPING-START. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + const yaml_char_t *anchor, const yaml_char_t *tag, int implicit, + yaml_mapping_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create MAPPING-END. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + MAPPING_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Destroy an event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event) +{ + yaml_tag_directive_t *tag_directive; + + assert(event); /* Non-NULL event object expected. */ + + switch (event->type) + { + case YAML_DOCUMENT_START_EVENT: + yaml_free(event->data.document_start.version_directive); + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(event->data.document_start.tag_directives.start); + break; + + case YAML_ALIAS_EVENT: + yaml_free(event->data.alias.anchor); + break; + + case YAML_SCALAR_EVENT: + yaml_free(event->data.scalar.anchor); + yaml_free(event->data.scalar.tag); + yaml_free(event->data.scalar.value); + break; + + case YAML_SEQUENCE_START_EVENT: + yaml_free(event->data.sequence_start.anchor); + yaml_free(event->data.sequence_start.tag); + break; + + case YAML_MAPPING_START_EVENT: + yaml_free(event->data.mapping_start.anchor); + yaml_free(event->data.mapping_start.tag); + break; + + default: + break; + } + + memset(event, 0, sizeof(yaml_event_t)); +} + +/* + * Create a document object. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit) +{ + struct { + yaml_error_type_t error; + } context; + struct { + yaml_node_t *start; + yaml_node_t *end; + yaml_node_t *top; + } nodes = { NULL, NULL, NULL }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(document); /* Non-NULL document object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (!STACK_INIT(&context, nodes, yaml_node_t*)) goto error; + + if (version_directive) { + version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + start_implicit, end_implicit, mark, mark); + + return 1; + +error: + STACK_DEL(&context, nodes); + yaml_free(version_directive_copy); + while (!STACK_EMPTY(&context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Destroy a document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document) +{ + yaml_tag_directive_t *tag_directive; + + assert(document); /* Non-NULL document object is expected. */ + + while (!STACK_EMPTY(&context, document->nodes)) { + yaml_node_t node = POP(&context, document->nodes); + yaml_free(node.tag); + switch (node.type) { + case YAML_SCALAR_NODE: + yaml_free(node.data.scalar.value); + break; + case YAML_SEQUENCE_NODE: + STACK_DEL(&context, node.data.sequence.items); + break; + case YAML_MAPPING_NODE: + STACK_DEL(&context, node.data.mapping.pairs); + break; + default: + assert(0); /* Should not happen. */ + } + } + STACK_DEL(&context, document->nodes); + + yaml_free(document->version_directive); + for (tag_directive = document->tag_directives.start; + tag_directive != document->tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(document->tag_directives.start); + + memset(document, 0, sizeof(yaml_document_t)); +} + +/** + * Get a document node. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (index > 0 && document->nodes.start + index <= document->nodes.top) { + return document->nodes.start + index - 1; + } + return NULL; +} + +/** + * Get the root object. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (document->nodes.top != document->nodes.start) { + return document->nodes.start; + } + return NULL; +} + +/* + * Add a scalar node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + const yaml_char_t *tag, const yaml_char_t *value, int length, + yaml_scalar_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + assert(value); /* Non-NULL value is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = YAML_MALLOC(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Add a sequence node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + const yaml_char_t *tag, yaml_sequence_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, items, yaml_node_item_t*)) goto error; + + SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, items); + yaml_free(tag_copy); + + return 0; +} + +/* + * Add a mapping node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + const yaml_char_t *tag, yaml_mapping_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, pairs, yaml_node_pair_t*)) goto error; + + MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, pairs); + yaml_free(tag_copy); + + return 0; +} + +/* + * Append an item to a sequence node. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item) +{ + struct { + yaml_error_type_t error; + } context; + + assert(document); /* Non-NULL document is required. */ + assert(sequence > 0 + && document->nodes.start + sequence <= document->nodes.top); + /* Valid sequence id is required. */ + assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); + /* A sequence node is required. */ + assert(item > 0 && document->nodes.start + item <= document->nodes.top); + /* Valid item id is required. */ + + if (!PUSH(&context, + document->nodes.start[sequence-1].data.sequence.items, item)) + return 0; + + return 1; +} + +/* + * Append a pair of a key and a value to a mapping node. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value) +{ + struct { + yaml_error_type_t error; + } context; + + yaml_node_pair_t pair; + + assert(document); /* Non-NULL document is required. */ + assert(mapping > 0 + && document->nodes.start + mapping <= document->nodes.top); + /* Valid mapping id is required. */ + assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); + /* A mapping node is required. */ + assert(key > 0 && document->nodes.start + key <= document->nodes.top); + /* Valid key id is required. */ + assert(value > 0 && document->nodes.start + value <= document->nodes.top); + /* Valid value id is required. */ + + pair.key = key; + pair.value = value; + + if (!PUSH(&context, + document->nodes.start[mapping-1].data.mapping.pairs, pair)) + return 0; + + return 1; +} + + diff --git a/src/3rdparty/libyaml/src/dumper.c b/src/3rdparty/libyaml/src/dumper.c new file mode 100644 index 00000000..1fe940b6 --- /dev/null +++ b/src/3rdparty/libyaml/src/dumper.c @@ -0,0 +1,394 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/* + * Clean up functions. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter); + +/* + * Anchor functions. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index); + +static yaml_char_t * +yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id); + + +/* + * Serialize functions. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index); + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +/* + * Issue a STREAM-START event. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(!emitter->opened); /* Emitter should not be opened yet. */ + + STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->opened = 1; + + return 1; +} + +/* + * Issue a STREAM-END event. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(emitter->opened); /* Emitter should be opened. */ + + if (emitter->closed) return 1; + + STREAM_END_EVENT_INIT(event, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->closed = 1; + + return 1; +} + +/* + * Dump a YAML document. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(document); /* Non-NULL emitter object is expected. */ + + emitter->document = document; + + if (!emitter->opened) { + if (!yaml_emitter_open(emitter)) goto error; + } + + if (STACK_EMPTY(emitter, document->nodes)) { + if (!yaml_emitter_close(emitter)) goto error; + yaml_emitter_delete_document_and_anchors(emitter); + return 1; + } + + assert(emitter->opened); /* Emitter should be opened. */ + + emitter->anchors = (yaml_anchors_t*)yaml_malloc(sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + if (!emitter->anchors) goto error; + memset(emitter->anchors, 0, sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + + DOCUMENT_START_EVENT_INIT(event, document->version_directive, + document->tag_directives.start, document->tag_directives.end, + document->start_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_anchor_node(emitter, 1); + if (!yaml_emitter_dump_node(emitter, 1)) goto error; + + DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_delete_document_and_anchors(emitter); + + return 1; + +error: + + yaml_emitter_delete_document_and_anchors(emitter); + + return 0; +} + +/* + * Clean up the emitter object after a document is dumped. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter) +{ + int index; + + if (!emitter->anchors) { + yaml_document_delete(emitter->document); + emitter->document = NULL; + return; + } + + for (index = 0; emitter->document->nodes.start + index + < emitter->document->nodes.top; index ++) { + yaml_node_t node = emitter->document->nodes.start[index]; + if (!emitter->anchors[index].serialized) { + yaml_free(node.tag); + if (node.type == YAML_SCALAR_NODE) { + yaml_free(node.data.scalar.value); + } + } + if (node.type == YAML_SEQUENCE_NODE) { + STACK_DEL(emitter, node.data.sequence.items); + } + if (node.type == YAML_MAPPING_NODE) { + STACK_DEL(emitter, node.data.mapping.pairs); + } + } + + STACK_DEL(emitter, emitter->document->nodes); + yaml_free(emitter->anchors); + + emitter->anchors = NULL; + emitter->last_anchor_id = 0; + emitter->document = NULL; +} + +/* + * Check the references of a node and assign the anchor id if needed. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + yaml_node_item_t *item; + yaml_node_pair_t *pair; + + emitter->anchors[index-1].references ++; + + if (emitter->anchors[index-1].references == 1) { + switch (node->type) { + case YAML_SEQUENCE_NODE: + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + yaml_emitter_anchor_node(emitter, *item); + } + break; + case YAML_MAPPING_NODE: + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + yaml_emitter_anchor_node(emitter, pair->key); + yaml_emitter_anchor_node(emitter, pair->value); + } + break; + default: + break; + } + } + + else if (emitter->anchors[index-1].references == 2) { + emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id); + } +} + +/* + * Generate a textual representation for an anchor. + */ + +#define ANCHOR_TEMPLATE "id%03d" +#define ANCHOR_TEMPLATE_LENGTH 16 + +static yaml_char_t * +yaml_emitter_generate_anchor(SHIM(yaml_emitter_t *emitter), int anchor_id) +{ + yaml_char_t *anchor = YAML_MALLOC(ANCHOR_TEMPLATE_LENGTH); + + if (!anchor) return NULL; + + sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id); + + return anchor; +} + +/* + * Serialize a node. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + int anchor_id = emitter->anchors[index-1].anchor; + yaml_char_t *anchor = NULL; + + if (anchor_id) { + anchor = yaml_emitter_generate_anchor(emitter, anchor_id); + if (!anchor) return 0; + } + + if (emitter->anchors[index-1].serialized) { + return yaml_emitter_dump_alias(emitter, anchor); + } + + emitter->anchors[index-1].serialized = 1; + + switch (node->type) { + case YAML_SCALAR_NODE: + return yaml_emitter_dump_scalar(emitter, node, anchor); + case YAML_SEQUENCE_NODE: + return yaml_emitter_dump_sequence(emitter, node, anchor); + case YAML_MAPPING_NODE: + return yaml_emitter_dump_mapping(emitter, node, anchor); + default: + assert(0); /* Could not happen. */ + break; + } + + return 0; /* Could not happen. */ +} + +/* + * Serialize an alias. + */ + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + ALIAS_EVENT_INIT(event, anchor, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a scalar. + */ + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int plain_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + int quoted_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + + SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value, + node->data.scalar.length, plain_implicit, quoted_implicit, + node->data.scalar.style, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a sequence. + */ + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0); + + yaml_node_item_t *item; + + SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.sequence.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + if (!yaml_emitter_dump_node(emitter, *item)) return 0; + } + + SEQUENCE_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + +/* + * Serialize a mapping. + */ + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0); + + yaml_node_pair_t *pair; + + MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.mapping.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + if (!yaml_emitter_dump_node(emitter, pair->key)) return 0; + if (!yaml_emitter_dump_node(emitter, pair->value)) return 0; + } + + MAPPING_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + diff --git a/src/3rdparty/libyaml/src/emitter.c b/src/3rdparty/libyaml/src/emitter.c new file mode 100644 index 00000000..609b28a4 --- /dev/null +++ b/src/3rdparty/libyaml/src/emitter.c @@ -0,0 +1,2358 @@ + +#include "yaml_private.h" + +/* + * Flush the buffer if needed. + */ + +#define FLUSH(emitter) \ + ((emitter->buffer.pointer+5 < emitter->buffer.end) \ + || yaml_emitter_flush(emitter)) + +/* + * Put a character to the output buffer. + */ + +#define PUT(emitter,value) \ + (FLUSH(emitter) \ + && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \ + emitter->column++, \ + 1)) + +/* + * Put a line break to the output buffer. + */ + +#define PUT_BREAK(emitter) \ + (FLUSH(emitter) \ + && ((emitter->line_break == YAML_CR_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \ + emitter->line_break == YAML_LN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \ + emitter->line_break == YAML_CRLN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \ + *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \ + emitter->column = 0, \ + emitter->line ++, \ + 1)) + +/* + * Copy a character from a string into buffer. + */ + +#define WRITE(emitter,string) \ + (FLUSH(emitter) \ + && (COPY(emitter->buffer,string), \ + emitter->column ++, \ + 1)) + +/* + * Copy a line break character from a string into buffer. + */ + +#define WRITE_BREAK(emitter,string) \ + (FLUSH(emitter) \ + && (CHECK(string,'\n') ? \ + (PUT_BREAK(emitter), \ + string.pointer ++, \ + 1) : \ + (COPY(emitter->buffer,string), \ + emitter->column = 0, \ + emitter->line ++, \ + 1))) + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Utility functions. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem); + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter); + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates); + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless); + +/* + * State functions. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key); + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Checkers. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter); + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Processors. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter); + +/* + * Analyzers. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive); + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive); + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias); + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag); + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event); + +/* + * Writers. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + const char *indicator, int need_whitespace, + int is_whitespace, int is_indention); + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int need_whitespace); + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string); + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +/* + * Set an emitter error and return 0. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_EMITTER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Emit an event. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!ENQUEUE(emitter, emitter->events, *event)) { + yaml_event_delete(event); + return 0; + } + + while (!yaml_emitter_need_more_events(emitter)) { + if (!yaml_emitter_analyze_event(emitter, emitter->events.head)) + return 0; + if (!yaml_emitter_state_machine(emitter, emitter->events.head)) + return 0; + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + + return 1; +} + +/* + * Check if we need to accumulate more events before emitting. + * + * We accumulate extra + * - 1 event for DOCUMENT-START + * - 2 events for SEQUENCE-START + * - 3 events for MAPPING-START + */ + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter) +{ + int level = 0; + int accumulate = 0; + yaml_event_t *event; + + if (QUEUE_EMPTY(emitter, emitter->events)) + return 1; + + switch (emitter->events.head->type) { + case YAML_DOCUMENT_START_EVENT: + accumulate = 1; + break; + case YAML_SEQUENCE_START_EVENT: + accumulate = 2; + break; + case YAML_MAPPING_START_EVENT: + accumulate = 3; + break; + default: + return 0; + } + + if (emitter->events.tail - emitter->events.head > accumulate) + return 0; + + for (event = emitter->events.head; event != emitter->events.tail; event ++) { + switch (event->type) { + case YAML_STREAM_START_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_SEQUENCE_START_EVENT: + case YAML_MAPPING_START_EVENT: + level += 1; + break; + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_END_EVENT: + case YAML_SEQUENCE_END_EVENT: + case YAML_MAPPING_END_EVENT: + level -= 1; + break; + default: + break; + } + if (!level) + return 0; + } + + return 1; +} + +/* + * Append a directive to the directives stack. + */ + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_emitter_set_emitter_error(emitter, + "duplicate %TAG directive"); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + emitter->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(emitter, emitter->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + +/* + * Increase the indentation level. + */ + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless) +{ + if (!PUSH(emitter, emitter->indents, emitter->indent)) + return 0; + + if (emitter->indent < 0) { + emitter->indent = flow ? emitter->best_indent : 0; + } + else if (!indentless) { + emitter->indent += emitter->best_indent; + } + + return 1; +} + +/* + * State dispatcher. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event) +{ + switch (emitter->state) + { + case YAML_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event); + + case YAML_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 1); + + case YAML_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 0); + + case YAML_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event); + + case YAML_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event); + + case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 1); + + case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 0); + + case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 1); + + case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 0); + + case YAML_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, + "expected nothing after STREAM-END"); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Expect STREAM-START. + */ + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + emitter->open_ended = 0; + if (event->type == YAML_STREAM_START_EVENT) + { + if (!emitter->encoding) { + emitter->encoding = event->data.stream_start.encoding; + } + + if (!emitter->encoding) { + emitter->encoding = YAML_UTF8_ENCODING; + } + + if (emitter->best_indent < 2 || emitter->best_indent > 9) { + emitter->best_indent = 2; + } + + if (emitter->best_width >= 0 + && emitter->best_width <= emitter->best_indent*2) { + emitter->best_width = 80; + } + + if (emitter->best_width < 0) { + emitter->best_width = INT_MAX; + } + + if (!emitter->line_break) { + emitter->line_break = YAML_LN_BREAK; + } + + emitter->indent = -1; + + emitter->line = 0; + emitter->column = 0; + emitter->whitespace = 1; + emitter->indention = 1; + + if (emitter->encoding != YAML_UTF8_ENCODING) { + if (!yaml_emitter_write_bom(emitter)) + return 0; + } + + emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected STREAM-START"); +} + +/* + * Expect DOCUMENT-START or STREAM-END. + */ + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (event->type == YAML_DOCUMENT_START_EVENT) + { + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *tag_directive; + int implicit; + + if (event->data.document_start.version_directive) { + if (!yaml_emitter_analyze_version_directive(emitter, + *event->data.document_start.version_directive)) + return 0; + } + + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_analyze_tag_directive(emitter, *tag_directive)) + return 0; + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0)) + return 0; + } + + for (tag_directive = default_tag_directives; + tag_directive->handle; tag_directive ++) { + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1)) + return 0; + } + + implicit = event->data.document_start.implicit; + if (!first || emitter->canonical) { + implicit = 0; + } + + if ((event->data.document_start.version_directive || + (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end)) && + emitter->open_ended) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + emitter->open_ended = 0; + + if (event->data.document_start.version_directive) { + implicit = 0; + if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0)) + return 0; + if (event->data.document_start.version_directive->minor == 1) { + if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0)) + return 0; + } + else { + if (!yaml_emitter_write_indicator(emitter, "1.2", 1, 0, 0)) + return 0; + } + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end) { + implicit = 0; + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle, + strlen((char *)tag_directive->handle))) + return 0; + if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix, + strlen((char *)tag_directive->prefix), 1)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + if (yaml_emitter_check_empty_document(emitter)) { + implicit = 0; + } + + if (!implicit) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0)) + return 0; + if (emitter->canonical) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE; + + emitter->open_ended = 0; + return 1; + } + + else if (event->type == YAML_STREAM_END_EVENT) + { + + /** + * This can happen if a block scalar with trailing empty lines + * is at the end of the stream + */ + if (emitter->open_ended == 2) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + emitter->open_ended = 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_END_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-START or STREAM-END"); +} + +/* + * Expect the root node. + */ + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0); +} + +/* + * Expect DOCUMENT-END. + */ + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (event->type == YAML_DOCUMENT_END_EVENT) + { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!event->data.document_end.implicit) { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + emitter->open_ended = 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + else if (!emitter->open_ended) + emitter->open_ended = 1; + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_DOCUMENT_START_STATE; + + while (!STACK_EMPTY(emitter, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, + emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-END"); +} + +/* + * + * Expect a flow item node. + */ + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a flow key node. + */ + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (!emitter->canonical && yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a flow value node. + */ + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a block item node. + */ + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, + (emitter->mapping_context && !emitter->indention))) + return 0; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a block key node. + */ + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, 0)) + return 0; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + + if (yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a block value node. + */ + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1)) + return 0; + } + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_KEY_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a node. + */ + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key) +{ + emitter->root_context = root; + emitter->sequence_context = sequence; + emitter->mapping_context = mapping; + emitter->simple_key_context = simple_key; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event); + + case YAML_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event); + + case YAML_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event); + + case YAML_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event); + + default: + return yaml_emitter_set_emitter_error(emitter, + "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS"); + } + + return 0; +} + +/* + * Expect ALIAS. + */ + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, SHIM(yaml_event_t *event)) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (emitter->simple_key_context) + if (!PUT(emitter, ' ')) return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SCALAR. + */ + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_select_scalar_style(emitter, event)) + return 0; + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + if (!yaml_emitter_process_scalar(emitter)) + return 0; + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SEQUENCE-START. + */ + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE + || yaml_emitter_check_empty_sequence(emitter)) { + emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; + } + + return 1; +} + +/* + * Expect MAPPING-START. + */ + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE + || yaml_emitter_check_empty_mapping(emitter)) { + emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; + } + + return 1; +} + +/* + * Check if the document content is an empty scalar. + */ + +static int +yaml_emitter_check_empty_document(SHIM(yaml_emitter_t *emitter)) +{ + return 0; +} + +/* + * Check if the next events represent an empty sequence. + */ + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT + && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT); +} + +/* + * Check if the next events represent an empty mapping. + */ + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT + && emitter->events.head[1].type == YAML_MAPPING_END_EVENT); +} + +/* + * Check if the next node can be expressed as a simple key. + */ + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter) +{ + yaml_event_t *event = emitter->events.head; + size_t length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + length += emitter->anchor_data.anchor_length; + break; + + case YAML_SCALAR_EVENT: + if (emitter->scalar_data.multiline) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length + + emitter->scalar_data.length; + break; + + case YAML_SEQUENCE_START_EVENT: + if (!yaml_emitter_check_empty_sequence(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + case YAML_MAPPING_START_EVENT: + if (!yaml_emitter_check_empty_mapping(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + default: + return 0; + } + + if (length > 128) + return 0; + + return 1; +} + +/* + * Determine an acceptable scalar style. + */ + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) +{ + yaml_scalar_style_t style = event->data.scalar.style; + int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix); + + if (no_tag && !event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit) { + return yaml_emitter_set_emitter_error(emitter, + "neither tag nor implicit flags are specified"); + } + + if (style == YAML_ANY_SCALAR_STYLE) + style = YAML_PLAIN_SCALAR_STYLE; + + if (emitter->canonical) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (emitter->simple_key_context && emitter->scalar_data.multiline) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (style == YAML_PLAIN_SCALAR_STYLE) + { + if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed) + || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (!emitter->scalar_data.length + && (emitter->flow_level || emitter->simple_key_context)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (no_tag && !event->data.scalar.plain_implicit) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE) + { + if (!emitter->scalar_data.single_quoted_allowed) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE) + { + if (!emitter->scalar_data.block_allowed + || emitter->flow_level || emitter->simple_key_context) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (no_tag && !event->data.scalar.quoted_implicit + && style != YAML_PLAIN_SCALAR_STYLE) + { + emitter->tag_data.handle = (yaml_char_t *)"!"; + emitter->tag_data.handle_length = 1; + } + + emitter->scalar_data.style = style; + + return 1; +} + +/* + * Write an anchor. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter) +{ + if (!emitter->anchor_data.anchor) + return 1; + + if (!yaml_emitter_write_indicator(emitter, + (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0)) + return 0; + + return yaml_emitter_write_anchor(emitter, + emitter->anchor_data.anchor, emitter->anchor_data.anchor_length); +} + +/* + * Write a tag. + */ + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter) +{ + if (!emitter->tag_data.handle && !emitter->tag_data.suffix) + return 1; + + if (emitter->tag_data.handle) + { + if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle, + emitter->tag_data.handle_length)) + return 0; + if (emitter->tag_data.suffix) { + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + } + } + else + { + if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0)) + return 0; + } + + return 1; +} + +/* + * Write a scalar. + */ + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter) +{ + switch (emitter->scalar_data.style) + { + case YAML_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + case YAML_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + default: + assert(1); /* Impossible. */ + } + + return 0; +} + +/* + * Check if a %YAML directive is valid. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive) +{ + if (version_directive.major != 1 || ( + version_directive.minor != 1 + && version_directive.minor != 2 + )) { + return yaml_emitter_set_emitter_error(emitter, + "incompatible %YAML directive"); + } + + return 1; +} + +/* + * Check if a %TAG directive is valid. + */ + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive) +{ + yaml_string_t handle; + yaml_string_t prefix; + size_t handle_length; + size_t prefix_length; + + handle_length = strlen((char *)tag_directive.handle); + prefix_length = strlen((char *)tag_directive.prefix); + STRING_ASSIGN(handle, tag_directive.handle, handle_length); + STRING_ASSIGN(prefix, tag_directive.prefix, prefix_length); + + if (handle.start == handle.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must not be empty"); + } + + if (handle.start[0] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must start with '!'"); + } + + if (handle.end[-1] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must end with '!'"); + } + + handle.pointer ++; + + while (handle.pointer < handle.end-1) { + if (!IS_ALPHA(handle)) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must contain alphanumerical characters only"); + } + MOVE(handle); + } + + if (prefix.start == prefix.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag prefix must not be empty"); + } + + return 1; +} + +/* + * Check if an anchor is valid. + */ + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias) +{ + size_t anchor_length; + yaml_string_t string; + + anchor_length = strlen((char *)anchor); + STRING_ASSIGN(string, anchor, anchor_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must not be empty" : + "anchor value must not be empty"); + } + + while (string.pointer != string.end) { + if (!IS_ALPHA(string)) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must contain alphanumerical characters only" : + "anchor value must contain alphanumerical characters only"); + } + MOVE(string); + } + + emitter->anchor_data.anchor = string.start; + emitter->anchor_data.anchor_length = string.end - string.start; + emitter->anchor_data.alias = alias; + + return 1; +} + +/* + * Check if a tag is valid. + */ + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag) +{ + size_t tag_length; + yaml_string_t string; + yaml_tag_directive_t *tag_directive; + + tag_length = strlen((char *)tag); + STRING_ASSIGN(string, tag, tag_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag value must not be empty"); + } + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + size_t prefix_length = strlen((char *)tag_directive->prefix); + if (prefix_length < (size_t)(string.end - string.start) + && strncmp((char *)tag_directive->prefix, (char *)string.start, + prefix_length) == 0) + { + emitter->tag_data.handle = tag_directive->handle; + emitter->tag_data.handle_length = + strlen((char *)tag_directive->handle); + emitter->tag_data.suffix = string.start + prefix_length; + emitter->tag_data.suffix_length = + (string.end - string.start) - prefix_length; + return 1; + } + } + + emitter->tag_data.suffix = string.start; + emitter->tag_data.suffix_length = string.end - string.start; + + return 1; +} + +/* + * Check if a scalar is valid. + */ + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + + int block_indicators = 0; + int flow_indicators = 0; + int line_breaks = 0; + int special_characters = 0; + + int leading_space = 0; + int leading_break = 0; + int trailing_space = 0; + int trailing_break = 0; + int break_space = 0; + int space_break = 0; + + int preceded_by_whitespace = 0; + int followed_by_whitespace = 0; + int previous_space = 0; + int previous_break = 0; + + STRING_ASSIGN(string, value, length); + + emitter->scalar_data.value = value; + emitter->scalar_data.length = length; + + if (string.start == string.end) + { + emitter->scalar_data.multiline = 0; + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 0; + + return 1; + } + + if ((CHECK_AT(string, '-', 0) + && CHECK_AT(string, '-', 1) + && CHECK_AT(string, '-', 2)) + || (CHECK_AT(string, '.', 0) + && CHECK_AT(string, '.', 1) + && CHECK_AT(string, '.', 2))) { + block_indicators = 1; + flow_indicators = 1; + } + + preceded_by_whitespace = 1; + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + + while (string.pointer != string.end) + { + if (string.start == string.pointer) + { + if (CHECK(string, '#') || CHECK(string, ',') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}') + || CHECK(string, '&') || CHECK(string, '*') + || CHECK(string, '!') || CHECK(string, '|') + || CHECK(string, '>') || CHECK(string, '\'') + || CHECK(string, '"') || CHECK(string, '%') + || CHECK(string, '@') || CHECK(string, '`')) { + flow_indicators = 1; + block_indicators = 1; + } + + if (CHECK(string, '?') || CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '-') && followed_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + else + { + if (CHECK(string, ',') || CHECK(string, '?') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}')) { + flow_indicators = 1; + } + + if (CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '#') && preceded_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + + if (!IS_PRINTABLE(string) + || (!IS_ASCII(string) && !emitter->unicode)) { + special_characters = 1; + } + + if (IS_BREAK(string)) { + line_breaks = 1; + } + + if (IS_SPACE(string)) + { + if (string.start == string.pointer) { + leading_space = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_space = 1; + } + if (previous_break) { + break_space = 1; + } + previous_space = 1; + previous_break = 0; + } + else if (IS_BREAK(string)) + { + if (string.start == string.pointer) { + leading_break = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_break = 1; + } + if (previous_space) { + space_break = 1; + } + previous_space = 0; + previous_break = 1; + } + else + { + previous_space = 0; + previous_break = 0; + } + + preceded_by_whitespace = IS_BLANKZ(string); + MOVE(string); + if (string.pointer != string.end) { + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + } + } + + emitter->scalar_data.multiline = line_breaks; + + emitter->scalar_data.flow_plain_allowed = 1; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 1; + + if (leading_space || leading_break || trailing_space || trailing_break) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (trailing_space) { + emitter->scalar_data.block_allowed = 0; + } + + if (break_space) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + } + + if (space_break || special_characters) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + emitter->scalar_data.block_allowed = 0; + } + + if (line_breaks) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (flow_indicators) { + emitter->scalar_data.flow_plain_allowed = 0; + } + + if (block_indicators) { + emitter->scalar_data.block_plain_allowed = 0; + } + + return 1; +} + +/* + * Check if the event data is valid. + */ + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + emitter->anchor_data.anchor = NULL; + emitter->anchor_data.anchor_length = 0; + emitter->tag_data.handle = NULL; + emitter->tag_data.handle_length = 0; + emitter->tag_data.suffix = NULL; + emitter->tag_data.suffix_length = 0; + emitter->scalar_data.value = NULL; + emitter->scalar_data.length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + if (!yaml_emitter_analyze_anchor(emitter, + event->data.alias.anchor, 1)) + return 0; + return 1; + + case YAML_SCALAR_EVENT: + if (event->data.scalar.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.scalar.anchor, 0)) + return 0; + } + if (event->data.scalar.tag && (emitter->canonical || + (!event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit))) { + if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag)) + return 0; + } + if (!yaml_emitter_analyze_scalar(emitter, + event->data.scalar.value, event->data.scalar.length)) + return 0; + return 1; + + case YAML_SEQUENCE_START_EVENT: + if (event->data.sequence_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.sequence_start.anchor, 0)) + return 0; + } + if (event->data.sequence_start.tag && (emitter->canonical || + !event->data.sequence_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.sequence_start.tag)) + return 0; + } + return 1; + + case YAML_MAPPING_START_EVENT: + if (event->data.mapping_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.mapping_start.anchor, 0)) + return 0; + } + if (event->data.mapping_start.tag && (emitter->canonical || + !event->data.mapping_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.mapping_start.tag)) + return 0; + } + return 1; + + default: + return 1; + } +} + +/* + * Write the BOM character. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter) +{ + if (!FLUSH(emitter)) return 0; + + *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF'; + + return 1; +} + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter) +{ + int indent = (emitter->indent >= 0) ? emitter->indent : 0; + + if (!emitter->indention || emitter->column > indent + || (emitter->column == indent && !emitter->whitespace)) { + if (!PUT_BREAK(emitter)) return 0; + } + + while (emitter->column < indent) { + if (!PUT(emitter, ' ')) return 0; + } + + emitter->whitespace = 1; + emitter->indention = 1; + + return 1; +} + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + const char *indicator, int need_whitespace, + int is_whitespace, int is_indention) +{ + size_t indicator_length; + yaml_string_t string; + + indicator_length = strlen(indicator); + STRING_ASSIGN(string, (yaml_char_t *)indicator, indicator_length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = is_whitespace; + emitter->indention = (emitter->indention && is_indention); + + return 1; +} + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (!emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, + int need_whitespace) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (IS_ALPHA(string) + || CHECK(string, ';') || CHECK(string, '/') + || CHECK(string, '?') || CHECK(string, ':') + || CHECK(string, '@') || CHECK(string, '&') + || CHECK(string, '=') || CHECK(string, '+') + || CHECK(string, '$') || CHECK(string, ',') + || CHECK(string, '_') || CHECK(string, '.') + || CHECK(string, '~') || CHECK(string, '*') + || CHECK(string, '\'') || CHECK(string, '(') + || CHECK(string, ')') || CHECK(string, '[') + || CHECK(string, ']')) { + if (!WRITE(emitter, string)) return 0; + } + else { + int width = WIDTH(string); + unsigned int value; + while (width --) { + value = *(string.pointer++); + if (!PUT(emitter, '%')) return 0; + if (!PUT(emitter, (value >> 4) + + ((value >> 4) < 10 ? '0' : 'A' - 10))) + return 0; + if (!PUT(emitter, (value & 0x0F) + + ((value & 0x0F) < 10 ? '0' : 'A' - 10))) + return 0; + } + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + /** + * Avoid trailing spaces for empty values in block mode. + * In flow mode, we still want the space to prevent ambiguous things + * like {a:}. + * Currently, the emitter forbids any plain empty scalar in flow mode + * (e.g. it outputs {a: ''} instead), so emitter->flow_level will + * never be true here. + * But if the emitter is ever changed to allow emitting empty values, + * the check for flow_level is already here. + */ + if (!emitter->whitespace && (length || emitter->flow_level)) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "'", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1 + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (CHECK(string, '\'')) { + if (!PUT(emitter, '\'')) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + if (breaks) + if (!yaml_emitter_write_indent(emitter)) return 0; + + if (!yaml_emitter_write_indicator(emitter, "'", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "\"", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (!IS_PRINTABLE(string) || (!emitter->unicode && !IS_ASCII(string)) + || IS_BOM(string) || IS_BREAK(string) + || CHECK(string, '"') || CHECK(string, '\\')) + { + unsigned char octet; + unsigned int width; + unsigned int value; + int k; + + octet = string.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + for (k = 1; k < (int)width; k ++) { + octet = string.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + string.pointer += width; + + if (!PUT(emitter, '\\')) return 0; + + switch (value) + { + case 0x00: + if (!PUT(emitter, '0')) return 0; + break; + + case 0x07: + if (!PUT(emitter, 'a')) return 0; + break; + + case 0x08: + if (!PUT(emitter, 'b')) return 0; + break; + + case 0x09: + if (!PUT(emitter, 't')) return 0; + break; + + case 0x0A: + if (!PUT(emitter, 'n')) return 0; + break; + + case 0x0B: + if (!PUT(emitter, 'v')) return 0; + break; + + case 0x0C: + if (!PUT(emitter, 'f')) return 0; + break; + + case 0x0D: + if (!PUT(emitter, 'r')) return 0; + break; + + case 0x1B: + if (!PUT(emitter, 'e')) return 0; + break; + + case 0x22: + if (!PUT(emitter, '\"')) return 0; + break; + + case 0x5C: + if (!PUT(emitter, '\\')) return 0; + break; + + case 0x85: + if (!PUT(emitter, 'N')) return 0; + break; + + case 0xA0: + if (!PUT(emitter, '_')) return 0; + break; + + case 0x2028: + if (!PUT(emitter, 'L')) return 0; + break; + + case 0x2029: + if (!PUT(emitter, 'P')) return 0; + break; + + default: + if (value <= 0xFF) { + if (!PUT(emitter, 'x')) return 0; + width = 2; + } + else if (value <= 0xFFFF) { + if (!PUT(emitter, 'u')) return 0; + width = 4; + } + else { + if (!PUT(emitter, 'U')) return 0; + width = 8; + } + for (k = (width-1)*4; k >= 0; k -= 4) { + int digit = (value >> k) & 0x0F; + if (!PUT(emitter, digit + (digit < 10 ? '0' : 'A'-10))) + return 0; + } + } + spaces = 0; + } + else if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1) { + if (!yaml_emitter_write_indent(emitter)) return 0; + if (IS_SPACE_AT(string, 1)) { + if (!PUT(emitter, '\\')) return 0; + } + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else + { + if (!WRITE(emitter, string)) return 0; + spaces = 0; + } + } + + if (!yaml_emitter_write_indicator(emitter, "\"", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string) +{ + char indent_hint[2]; + const char *chomp_hint = NULL; + + if (IS_SPACE(string) || IS_BREAK(string)) + { + indent_hint[0] = '0' + (char)emitter->best_indent; + indent_hint[1] = '\0'; + if (!yaml_emitter_write_indicator(emitter, indent_hint, 0, 0, 0)) + return 0; + } + + emitter->open_ended = 0; + + string.pointer = string.end; + if (string.start == string.pointer) + { + chomp_hint = "-"; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (!IS_BREAK(string)) + { + chomp_hint = "-"; + } + else if (string.start == string.pointer) + { + chomp_hint = "+"; + emitter->open_ended = 2; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (IS_BREAK(string)) + { + chomp_hint = "+"; + emitter->open_ended = 2; + } + } + } + + if (chomp_hint) + { + if (!yaml_emitter_write_indicator(emitter, chomp_hint, 0, 0, 0)) + return 0; + } + + return 1; +} + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "|", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + int leading_spaces = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, ">", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!breaks && !leading_spaces && CHECK(string, '\n')) { + int k = 0; + while (IS_BREAK_AT(string, k)) { + k += WIDTH_AT(string, k); + } + if (!IS_BLANKZ_AT(string, k)) { + if (!PUT_BREAK(emitter)) return 0; + } + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + leading_spaces = IS_BLANK(string); + } + if (!breaks && IS_SPACE(string) && !IS_SPACE_AT(string, 1) + && emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} diff --git a/src/3rdparty/libyaml/src/loader.c b/src/3rdparty/libyaml/src/loader.c new file mode 100644 index 00000000..dea8ac42 --- /dev/null +++ b/src/3rdparty/libyaml/src/loader.c @@ -0,0 +1,544 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/* + * Error handling. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + + +/* + * Alias handling. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor); + +/* + * Clean up functions. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser); + +/* + * Document loading context. + */ +struct loader_ctx { + int *start; + int *end; + int *top; +}; + +/* + * Composer functions. + */ +static int +yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx); + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +static int +yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +static int +yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx); + +/* + * Load the next document of the stream. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document) +{ + yaml_event_t event; + + assert(parser); /* Non-NULL parser object is expected. */ + assert(document); /* Non-NULL document object is expected. */ + + memset(document, 0, sizeof(yaml_document_t)); + if (!STACK_INIT(parser, document->nodes, yaml_node_t*)) + goto error; + + if (!parser->stream_start_produced) { + if (!yaml_parser_parse(parser, &event)) goto error; + assert(event.type == YAML_STREAM_START_EVENT); + /* STREAM-START is expected. */ + } + + if (parser->stream_end_produced) { + return 1; + } + + if (!yaml_parser_parse(parser, &event)) goto error; + if (event.type == YAML_STREAM_END_EVENT) { + return 1; + } + + if (!STACK_INIT(parser, parser->aliases, yaml_alias_data_t*)) + goto error; + + parser->document = document; + + if (!yaml_parser_load_document(parser, &event)) goto error; + + yaml_parser_delete_aliases(parser); + parser->document = NULL; + + return 1; + +error: + + yaml_parser_delete_aliases(parser); + yaml_document_delete(document); + parser->document = NULL; + + return 0; +} + +/* + * Set composer error. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Set composer error with context. + */ + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Delete the stack of aliases. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser) +{ + while (!STACK_EMPTY(parser, parser->aliases)) { + yaml_free(POP(parser, parser->aliases).anchor); + } + STACK_DEL(parser, parser->aliases); +} + +/* + * Compose a document object. + */ + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event) +{ + struct loader_ctx ctx = { NULL, NULL, NULL }; + + assert(event->type == YAML_DOCUMENT_START_EVENT); + /* DOCUMENT-START is expected. */ + + parser->document->version_directive + = event->data.document_start.version_directive; + parser->document->tag_directives.start + = event->data.document_start.tag_directives.start; + parser->document->tag_directives.end + = event->data.document_start.tag_directives.end; + parser->document->start_implicit + = event->data.document_start.implicit; + parser->document->start_mark = event->start_mark; + + if (!STACK_INIT(parser, ctx, int*)) return 0; + if (!yaml_parser_load_nodes(parser, &ctx)) { + STACK_DEL(parser, ctx); + return 0; + } + STACK_DEL(parser, ctx); + + return 1; +} + +/* + * Compose a node tree. + */ + +static int +yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx) +{ + yaml_event_t event; + + do { + if (!yaml_parser_parse(parser, &event)) return 0; + + switch (event.type) { + case YAML_ALIAS_EVENT: + if (!yaml_parser_load_alias(parser, &event, ctx)) return 0; + break; + case YAML_SCALAR_EVENT: + if (!yaml_parser_load_scalar(parser, &event, ctx)) return 0; + break; + case YAML_SEQUENCE_START_EVENT: + if (!yaml_parser_load_sequence(parser, &event, ctx)) return 0; + break; + case YAML_SEQUENCE_END_EVENT: + if (!yaml_parser_load_sequence_end(parser, &event, ctx)) + return 0; + break; + case YAML_MAPPING_START_EVENT: + if (!yaml_parser_load_mapping(parser, &event, ctx)) return 0; + break; + case YAML_MAPPING_END_EVENT: + if (!yaml_parser_load_mapping_end(parser, &event, ctx)) + return 0; + break; + default: + assert(0); /* Could not happen. */ + return 0; + case YAML_DOCUMENT_END_EVENT: + break; + } + } while (event.type != YAML_DOCUMENT_END_EVENT); + + parser->document->end_implicit = event.data.document_end.implicit; + parser->document->end_mark = event.end_mark; + + return 1; +} + +/* + * Add an anchor. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor) +{ + yaml_alias_data_t data; + yaml_alias_data_t *alias_data; + + if (!anchor) return 1; + + data.anchor = anchor; + data.index = index; + data.mark = parser->document->nodes.start[index-1].start_mark; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return yaml_parser_set_composer_error_context(parser, + "found duplicate anchor; first occurrence", + alias_data->mark, "second occurrence", data.mark); + } + } + + if (!PUSH(parser, parser->aliases, data)) { + yaml_free(anchor); + return 0; + } + + return 1; +} + +/* + * Compose node into its parent in the stree. + */ + +static int +yaml_parser_load_node_add(yaml_parser_t *parser, struct loader_ctx *ctx, + int index) +{ + struct yaml_node_s *parent; + int parent_index; + + if (STACK_EMPTY(parser, *ctx)) { + /* This is the root node, there's no tree to add it to. */ + return 1; + } + + parent_index = *((*ctx).top - 1); + parent = &parser->document->nodes.start[parent_index-1]; + + switch (parent->type) { + case YAML_SEQUENCE_NODE: + if (!STACK_LIMIT(parser, parent->data.sequence.items, INT_MAX-1)) + return 0; + if (!PUSH(parser, parent->data.sequence.items, index)) + return 0; + break; + case YAML_MAPPING_NODE: { + yaml_node_pair_t pair; + if (!STACK_EMPTY(parser, parent->data.mapping.pairs)) { + yaml_node_pair_t *p = parent->data.mapping.pairs.top - 1; + if (p->key != 0 && p->value == 0) { + p->value = index; + break; + } + } + + pair.key = index; + pair.value = 0; + if (!STACK_LIMIT(parser, parent->data.mapping.pairs, INT_MAX-1)) + return 0; + if (!PUSH(parser, parent->data.mapping.pairs, pair)) + return 0; + + break; + } + default: + assert(0); /* Could not happen. */ + return 0; + } + return 1; +} + +/* + * Compose a node corresponding to an alias. + */ + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + yaml_char_t *anchor = event->data.alias.anchor; + yaml_alias_data_t *alias_data; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return yaml_parser_load_node_add(parser, ctx, alias_data->index); + } + } + + yaml_free(anchor); + return yaml_parser_set_composer_error(parser, "found undefined alias", + event->start_mark); +} + +/* + * Compose a scalar node. + */ + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + yaml_node_t node; + int index; + yaml_char_t *tag = event->data.scalar.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG); + if (!tag) goto error; + } + + SCALAR_NODE_INIT(node, tag, event->data.scalar.value, + event->data.scalar.length, event->data.scalar.style, + event->start_mark, event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + event->data.scalar.anchor)) return 0; + + return yaml_parser_load_node_add(parser, ctx, index); + +error: + yaml_free(tag); + yaml_free(event->data.scalar.anchor); + yaml_free(event->data.scalar.value); + return 0; +} + +/* + * Compose a sequence node. + */ + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + yaml_node_t node; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + int index; + yaml_char_t *tag = event->data.sequence_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, items, yaml_node_item_t*)) goto error; + + SEQUENCE_NODE_INIT(node, tag, items.start, items.end, + event->data.sequence_start.style, + event->start_mark, event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + event->data.sequence_start.anchor)) return 0; + + if (!yaml_parser_load_node_add(parser, ctx, index)) return 0; + + if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0; + if (!PUSH(parser, *ctx, index)) return 0; + + return 1; + +error: + yaml_free(tag); + yaml_free(event->data.sequence_start.anchor); + return 0; +} + +static int +yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + int index; + + assert(((*ctx).top - (*ctx).start) > 0); + + index = *((*ctx).top - 1); + assert(parser->document->nodes.start[index-1].type == YAML_SEQUENCE_NODE); + parser->document->nodes.start[index-1].end_mark = event->end_mark; + + (void)POP(parser, *ctx); + + return 1; +} + +/* + * Compose a mapping node. + */ + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + yaml_node_t node; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + int index; + yaml_char_t *tag = event->data.mapping_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, pairs, yaml_node_pair_t*)) goto error; + + MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end, + event->data.mapping_start.style, + event->start_mark, event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + event->data.mapping_start.anchor)) return 0; + + if (!yaml_parser_load_node_add(parser, ctx, index)) return 0; + + if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0; + if (!PUSH(parser, *ctx, index)) return 0; + + return 1; + +error: + yaml_free(tag); + yaml_free(event->data.mapping_start.anchor); + return 0; +} + +static int +yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event, + struct loader_ctx *ctx) +{ + int index; + + assert(((*ctx).top - (*ctx).start) > 0); + + index = *((*ctx).top - 1); + assert(parser->document->nodes.start[index-1].type == YAML_MAPPING_NODE); + parser->document->nodes.start[index-1].end_mark = event->end_mark; + + (void)POP(parser, *ctx); + + return 1; +} \ No newline at end of file diff --git a/src/3rdparty/libyaml/src/parser.c b/src/3rdparty/libyaml/src/parser.c new file mode 100644 index 00000000..ec2f8d3e --- /dev/null +++ b/src/3rdparty/libyaml/src/parser.c @@ -0,0 +1,1375 @@ + +/* + * The parser implements the following grammar: + * + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * block_node_or_indentless_sequence ::= + * ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + */ + +#include "yaml_private.h" + +/* + * Peek the next token in the token queue. + */ + +#define PEEK_TOKEN(parser) \ + ((parser->token_available || yaml_parser_fetch_more_tokens(parser)) ? \ + parser->tokens.head : NULL) + +/* + * Remove the next token from the queue (must be called after PEEK_TOKEN). + */ + +#define SKIP_TOKEN(parser) \ + (parser->token_available = 0, \ + parser->tokens_parsed ++, \ + parser->stream_end_produced = \ + (parser->tokens.head->type == YAML_STREAM_END_TOKEN), \ + parser->tokens.head ++) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/* + * Error handling. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + +/* + * State functions. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit); + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence); + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty); + +/* + * Utility functions. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, + yaml_event_t *event, yaml_mark_t mark); + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref); + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark); + +/* + * Get the next event. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(event); /* Non-NULL event object is expected. */ + + /* Erase the event object. */ + + memset(event, 0, sizeof(yaml_event_t)); + + /* No events after the end of the stream or error. */ + + if (parser->stream_end_produced || parser->error || + parser->state == YAML_PARSE_END_STATE) { + return 1; + } + + /* Generate the next event. */ + + return yaml_parser_state_machine(parser, event); +} + +/* + * Set parser error. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + + +/* + * State dispatcher. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event) +{ + switch (parser->state) + { + case YAML_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event); + + case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 1); + + case YAML_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 0); + + case YAML_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event); + + case YAML_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event); + + case YAML_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, 1, 0); + + case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, 1, 1); + + case YAML_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, 0, 0); + + case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 1); + + case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 0); + + case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event); + + case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 1); + + case YAML_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 0); + + case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 1); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 0); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event); + + case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 1); + + case YAML_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 1); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Parse the production: + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * ************ + */ + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_STREAM_START_TOKEN) { + return yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + } + + parser->state = YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE; + STREAM_START_EVENT_INIT(*event, token->data.stream_start.encoding, + token->start_mark, token->start_mark); + SKIP_TOKEN(parser); + + return 1; +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * * + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************************* + */ + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit) +{ + yaml_token_t *token; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + } tag_directives = { NULL, NULL }; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + /* Parse extra document end indicators. */ + + if (!implicit) + { + while (token->type == YAML_DOCUMENT_END_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + } + + /* Parse an implicit document. */ + + if (implicit && token->type != YAML_VERSION_DIRECTIVE_TOKEN && + token->type != YAML_TAG_DIRECTIVE_TOKEN && + token->type != YAML_DOCUMENT_START_TOKEN && + token->type != YAML_STREAM_END_TOKEN) + { + if (!yaml_parser_process_directives(parser, NULL, NULL, NULL)) + return 0; + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + return 0; + parser->state = YAML_PARSE_BLOCK_NODE_STATE; + DOCUMENT_START_EVENT_INIT(*event, NULL, NULL, NULL, 1, + token->start_mark, token->start_mark); + return 1; + } + + /* Parse an explicit document. */ + + else if (token->type != YAML_STREAM_END_TOKEN) + { + yaml_mark_t start_mark, end_mark; + start_mark = token->start_mark; + if (!yaml_parser_process_directives(parser, &version_directive, + &tag_directives.start, &tag_directives.end)) + return 0; + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type != YAML_DOCUMENT_START_TOKEN) { + yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + goto error; + } + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + goto error; + parser->state = YAML_PARSE_DOCUMENT_CONTENT_STATE; + end_mark = token->end_mark; + DOCUMENT_START_EVENT_INIT(*event, version_directive, + tag_directives.start, tag_directives.end, 0, + start_mark, end_mark); + SKIP_TOKEN(parser); + version_directive = NULL; + tag_directives.start = tag_directives.end = NULL; + return 1; + } + + /* Parse the stream end. */ + + else + { + parser->state = YAML_PARSE_END_STATE; + STREAM_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + +error: + yaml_free(version_directive); + while (tag_directives.start != tag_directives.end) { + yaml_free(tag_directives.end[-1].handle); + yaml_free(tag_directives.end[-1].prefix); + tag_directives.end --; + } + yaml_free(tag_directives.start); + return 0; +} + +/* + * Parse the productions: + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * *********** + */ + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN || + token->type == YAML_DOCUMENT_START_TOKEN || + token->type == YAML_DOCUMENT_END_TOKEN || + token->type == YAML_STREAM_END_TOKEN) { + parser->state = POP(parser, parser->states); + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + else { + return yaml_parser_parse_node(parser, event, 1, 0); + } +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * ************* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************* + */ + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + yaml_mark_t start_mark, end_mark; + int implicit = 1; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_DOCUMENT_END_TOKEN) { + end_mark = token->end_mark; + SKIP_TOKEN(parser); + implicit = 0; + } + + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + parser->state = YAML_PARSE_DOCUMENT_START_STATE; + DOCUMENT_END_EVENT_INIT(*event, implicit, start_mark, end_mark); + + return 1; +} + +/* + * Parse the productions: + * block_node_or_indentless_sequence ::= + * ALIAS + * ***** + * | properties (block_content | indentless_block_sequence)? + * ********** * + * | block_content | indentless_block_sequence + * * + * block_node ::= ALIAS + * ***** + * | properties block_content? + * ********** * + * | block_content + * * + * flow_node ::= ALIAS + * ***** + * | properties flow_content? + * ********** * + * | flow_content + * * + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * ************************* + * block_content ::= block_collection | flow_collection | SCALAR + * ****** + * flow_content ::= flow_collection | SCALAR + * ****** + */ + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence) +{ + yaml_token_t *token; + yaml_char_t *anchor = NULL; + yaml_char_t *tag_handle = NULL; + yaml_char_t *tag_suffix = NULL; + yaml_char_t *tag = NULL; + yaml_mark_t start_mark, end_mark, tag_mark; + int implicit; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_ALIAS_TOKEN) + { + parser->state = POP(parser, parser->states); + ALIAS_EVENT_INIT(*event, token->data.alias.value, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + start_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + else if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + start_mark = tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + + if (tag_handle) { + if (!*tag_handle) { + tag = tag_suffix; + yaml_free(tag_handle); + tag_handle = tag_suffix = NULL; + } + else { + yaml_tag_directive_t *tag_directive; + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; + tag_directive ++) { + if (strcmp((char *)tag_directive->handle, (char *)tag_handle) == 0) { + size_t prefix_len = strlen((char *)tag_directive->prefix); + size_t suffix_len = strlen((char *)tag_suffix); + tag = YAML_MALLOC(prefix_len+suffix_len+1); + if (!tag) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + memcpy(tag, tag_directive->prefix, prefix_len); + memcpy(tag+prefix_len, tag_suffix, suffix_len); + tag[prefix_len+suffix_len] = '\0'; + yaml_free(tag_handle); + yaml_free(tag_suffix); + tag_handle = tag_suffix = NULL; + break; + } + } + if (!tag) { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark); + goto error; + } + } + } + + implicit = (!tag || !*tag); + if (indentless_sequence && token->type == YAML_BLOCK_ENTRY_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else { + if (token->type == YAML_SCALAR_TOKEN) { + int plain_implicit = 0; + int quoted_implicit = 0; + end_mark = token->end_mark; + if ((token->data.scalar.style == YAML_PLAIN_SCALAR_STYLE && !tag) + || (tag && strcmp((char *)tag, "!") == 0)) { + plain_implicit = 1; + } + else if (!tag) { + quoted_implicit = 1; + } + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, + token->data.scalar.value, token->data.scalar.length, + plain_implicit, quoted_implicit, + token->data.scalar.style, start_mark, end_mark); + SKIP_TOKEN(parser); + return 1; + } + else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (anchor || tag) { + yaml_char_t *value = YAML_MALLOC(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + value[0] = '\0'; + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, value, 0, + implicit, 0, YAML_PLAIN_SCALAR_STYLE, + start_mark, end_mark); + return 1; + } + else { + yaml_parser_set_parser_error_context(parser, + (block ? "while parsing a block node" + : "while parsing a flow node"), start_mark, + "did not find expected node content", token->start_mark); + goto error; + } + } + } + +error: + yaml_free(anchor); + yaml_free(tag_handle); + yaml_free(tag_suffix); + yaml_free(tag); + + return 0; +} + +/* + * Parse the productions: + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * ******************** *********** * ********* + */ + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + parser->state = POP(parser, parser->states); + (void)POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", POP(parser, parser->marks), + "did not find expected '-' indicator", token->start_mark); + } +} + +/* + * Parse the productions: + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * *********** * + */ + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = POP(parser, parser->states); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * ******************* + * ((KEY block_node_or_indentless_sequence?)? + * *** * + * (VALUE block_node_or_indentless_sequence?)?)* + * + * BLOCK-END + * ********* + */ + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_KEY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + parser->state = POP(parser, parser->states); + (void)POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", POP(parser, parser->marks), + "did not find expected key", token->start_mark); + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * + * ((KEY block_node_or_indentless_sequence?)? + * + * (VALUE block_node_or_indentless_sequence?)?)* + * ***** * + * BLOCK-END + * + */ + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); + } +} + +/* + * Parse the productions: + * flow_sequence ::= FLOW-SEQUENCE-START + * ******************* + * (flow_sequence_entry FLOW-ENTRY)* + * * ********** + * flow_sequence_entry? + * * + * FLOW-SEQUENCE-END + * ***************** + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", POP(parser, parser->marks), + "did not find expected ',' or ']'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, NULL, NULL, + 1, YAML_FLOW_MAPPING_STYLE, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + (void)POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * *** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_VALUE_TOKEN && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * ***** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE; + + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; +} + +/* + * Parse the productions: + * flow_mapping ::= FLOW-MAPPING-START + * ****************** + * (flow_mapping_entry FLOW-ENTRY)* + * * ********** + * flow_mapping_entry? + * ****************** + * FLOW-MAPPING-END + * **************** + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * *** * + */ + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_MAPPING_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", POP(parser, parser->marks), + "did not find expected ',' or '}'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_VALUE_TOKEN + && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + parser->state = YAML_PARSE_FLOW_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + } + else if (token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + (void)POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * ***** * + */ + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (empty) { + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Generate an empty scalar event. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, yaml_event_t *event, + yaml_mark_t mark) +{ + yaml_char_t *value; + + value = YAML_MALLOC(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + value[0] = '\0'; + + SCALAR_EVENT_INIT(*event, NULL, NULL, value, 0, + 1, 0, YAML_PLAIN_SCALAR_STYLE, mark, mark); + + return 1; +} + +/* + * Parse directives. + */ + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref) +{ + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *default_tag_directive; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives = { NULL, NULL, NULL }; + yaml_token_t *token; + + if (!STACK_INIT(parser, tag_directives, yaml_tag_directive_t*)) + goto error; + + token = PEEK_TOKEN(parser); + if (!token) goto error; + + while (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN) + { + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN) { + if (version_directive) { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token->start_mark); + goto error; + } + if (token->data.version_directive.major != 1 + || ( + token->data.version_directive.minor != 1 + && token->data.version_directive.minor != 2 + )) { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token->start_mark); + goto error; + } + version_directive = YAML_MALLOC_STATIC(yaml_version_directive_t); + if (!version_directive) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + version_directive->major = token->data.version_directive.major; + version_directive->minor = token->data.version_directive.minor; + } + + else if (token->type == YAML_TAG_DIRECTIVE_TOKEN) { + yaml_tag_directive_t value; + value.handle = token->data.tag_directive.handle; + value.prefix = token->data.tag_directive.prefix; + + if (!yaml_parser_append_tag_directive(parser, value, 0, + token->start_mark)) + goto error; + if (!PUSH(parser, tag_directives, value)) + goto error; + } + + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + + for (default_tag_directive = default_tag_directives; + default_tag_directive->handle; default_tag_directive++) { + if (!yaml_parser_append_tag_directive(parser, *default_tag_directive, 1, + token->start_mark)) + goto error; + } + + if (version_directive_ref) { + *version_directive_ref = version_directive; + } + if (tag_directives_start_ref) { + if (STACK_EMPTY(parser, tag_directives)) { + *tag_directives_start_ref = *tag_directives_end_ref = NULL; + STACK_DEL(parser, tag_directives); + } + else { + *tag_directives_start_ref = tag_directives.start; + *tag_directives_end_ref = tag_directives.top; + } + } + else { + STACK_DEL(parser, tag_directives); + } + + if (!version_directive_ref) + yaml_free(version_directive); + return 1; + +error: + yaml_free(version_directive); + while (!STACK_EMPTY(parser, tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, tag_directives); + return 0; +} + +/* + * Append a tag directive to the directives stack. + */ + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_parser_set_parser_error(parser, + "found duplicate %TAG directive", mark); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(parser, parser->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + diff --git a/src/3rdparty/libyaml/src/reader.c b/src/3rdparty/libyaml/src/reader.c new file mode 100644 index 00000000..f3ac54c2 --- /dev/null +++ b/src/3rdparty/libyaml/src/reader.c @@ -0,0 +1,469 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value); + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser); + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser); + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Set the reader error and return 0. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value) +{ + parser->error = YAML_READER_ERROR; + parser->problem = problem; + parser->problem_offset = offset; + parser->problem_value = value; + + return 0; +} + +/* + * Byte order marks. + */ + +#define BOM_UTF8 "\xef\xbb\xbf" +#define BOM_UTF16LE "\xff\xfe" +#define BOM_UTF16BE "\xfe\xff" + +/* + * Determine the input stream encoding by checking the BOM symbol. If no BOM is + * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. + */ + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser) +{ + /* Ensure that we had enough bytes in the raw buffer. */ + + while (!parser->eof + && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { + if (!yaml_parser_update_raw_buffer(parser)) { + return 0; + } + } + + /* Determine the encoding. */ + + if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { + parser->encoding = YAML_UTF16LE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { + parser->encoding = YAML_UTF16BE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { + parser->encoding = YAML_UTF8_ENCODING; + parser->raw_buffer.pointer += 3; + parser->offset += 3; + } + else { + parser->encoding = YAML_UTF8_ENCODING; + } + + return 1; +} + +/* + * Update the raw buffer. + */ + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser) +{ + size_t size_read = 0; + + /* Return if the raw buffer is full. */ + + if (parser->raw_buffer.start == parser->raw_buffer.pointer + && parser->raw_buffer.last == parser->raw_buffer.end) + return 1; + + /* Return on EOF. */ + + if (parser->eof) return 1; + + /* Move the remaining bytes in the raw buffer to the beginning. */ + + if (parser->raw_buffer.start < parser->raw_buffer.pointer + && parser->raw_buffer.pointer < parser->raw_buffer.last) { + memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, + parser->raw_buffer.last - parser->raw_buffer.pointer); + } + parser->raw_buffer.last -= + parser->raw_buffer.pointer - parser->raw_buffer.start; + parser->raw_buffer.pointer = parser->raw_buffer.start; + + /* Call the read handler to fill the buffer. */ + + if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, + parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { + return yaml_parser_set_reader_error(parser, "input error", + parser->offset, -1); + } + parser->raw_buffer.last += size_read; + if (!size_read) { + parser->eof = 1; + } + + return 1; +} + +/* + * Ensure that the buffer contains at least `length` characters. + * Return 1 on success, 0 on failure. + * + * The length is supposed to be significantly less that the buffer size. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) +{ + int first = 1; + + assert(parser->read_handler); /* Read handler must be set. */ + + /* If the EOF flag is set and the raw buffer is empty, do nothing. */ + + if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) + return 1; + + /* Return if the buffer contains enough characters. */ + + if (parser->unread >= length) + return 1; + + /* Determine the input encoding if it is not known yet. */ + + if (!parser->encoding) { + if (!yaml_parser_determine_encoding(parser)) + return 0; + } + + /* Move the unread characters to the beginning of the buffer. */ + + if (parser->buffer.start < parser->buffer.pointer + && parser->buffer.pointer < parser->buffer.last) { + size_t size = parser->buffer.last - parser->buffer.pointer; + memmove(parser->buffer.start, parser->buffer.pointer, size); + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start + size; + } + else if (parser->buffer.pointer == parser->buffer.last) { + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start; + } + + /* Fill the buffer until it has enough characters. */ + + while (parser->unread < length) + { + /* Fill the raw buffer if necessary. */ + + if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { + if (!yaml_parser_update_raw_buffer(parser)) return 0; + } + first = 0; + + /* Decode the raw buffer. */ + + while (parser->raw_buffer.pointer != parser->raw_buffer.last) + { + unsigned int value = 0, value2 = 0; + int incomplete = 0; + unsigned char octet; + unsigned int width = 0; + int low, high; + size_t k; + size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; + + /* Decode the next character. */ + + switch (parser->encoding) + { + case YAML_UTF8_ENCODING: + + /* + * Decode a UTF-8 character. Check RFC 3629 + * (http://www.ietf.org/rfc/rfc3629.txt) for more details. + * + * The following table (taken from the RFC) is used for + * decoding. + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+------------------------------------ + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * Additionally, the characters in the range 0xD800-0xDFFF + * are prohibited as they are reserved for use with UTF-16 + * surrogate pairs. + */ + + /* Determine the length of the UTF-8 sequence. */ + + octet = parser->raw_buffer.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + /* Check if the leading octet is valid. */ + + if (!width) + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser->offset, octet); + + /* Check if the raw buffer contains an incomplete character. */ + + if (width > raw_unread) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Decode the leading octet. */ + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + /* Check and decode the trailing octets. */ + + for (k = 1; k < width; k ++) + { + octet = parser->raw_buffer.pointer[k]; + + /* Check if the octet is valid. */ + + if ((octet & 0xC0) != 0x80) + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser->offset+k, octet); + + /* Decode the octet. */ + + value = (value << 6) + (octet & 0x3F); + } + + /* Check the length of the sequence against the value. */ + + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser->offset, -1); + + /* Check the range of the value. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser->offset, value); + + break; + + case YAML_UTF16LE_ENCODING: + case YAML_UTF16BE_ENCODING: + + low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + /* + * The UTF-16 encoding is not as simple as one might + * naively think. Check RFC 2781 + * (http://www.ietf.org/rfc/rfc2781.txt). + * + * Normally, two subsequent bytes describe a Unicode + * character. However a special technique (called a + * surrogate pair) is used for specifying character + * values larger than 0xFFFF. + * + * A surrogate pair consists of two pseudo-characters: + * high surrogate area (0xD800-0xDBFF) + * low surrogate area (0xDC00-0xDFFF) + * + * The following formulas are used for decoding + * and encoding characters using surrogate pairs: + * + * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + * W1 = 110110yyyyyyyyyy + * W2 = 110111xxxxxxxxxx + * + * where U is the character value, W1 is the high surrogate + * area, W2 is the low surrogate area. + */ + + /* Check for incomplete UTF-16 character. */ + + if (raw_unread < 2) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the character. */ + + value = parser->raw_buffer.pointer[low] + + (parser->raw_buffer.pointer[high] << 8); + + /* Check for unexpected low surrogate area. */ + + if ((value & 0xFC00) == 0xDC00) + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser->offset, value); + + /* Check for a high surrogate area. */ + + if ((value & 0xFC00) == 0xD800) { + + width = 4; + + /* Check for incomplete surrogate pair. */ + + if (raw_unread < 4) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the next character. */ + + value2 = parser->raw_buffer.pointer[low+2] + + (parser->raw_buffer.pointer[high+2] << 8); + + /* Check for a low surrogate area. */ + + if ((value2 & 0xFC00) != 0xDC00) + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser->offset+2, value2); + + /* Generate the value of the surrogate pair. */ + + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); + } + + else { + width = 2; + } + + break; + + default: + assert(1); /* Impossible. */ + } + + /* Check if the raw buffer contains enough bytes to form a character. */ + + if (incomplete) break; + + /* + * Check if the character is in the allowed range: + * #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + * | [#x10000-#x10FFFF] (32 bit) + */ + + if (! (value == 0x09 || value == 0x0A || value == 0x0D + || (value >= 0x20 && value <= 0x7E) + || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) + || (value >= 0xE000 && value <= 0xFFFD) + || (value >= 0x10000 && value <= 0x10FFFF))) + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser->offset, value); + + /* Move the raw pointers. */ + + parser->raw_buffer.pointer += width; + parser->offset += width; + + /* Finally put the character into the buffer. */ + + /* 0000 0000-0000 007F -> 0xxxxxxx */ + if (value <= 0x7F) { + *(parser->buffer.last++) = value; + } + /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ + else if (value <= 0x7FF) { + *(parser->buffer.last++) = 0xC0 + (value >> 6); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ + else if (value <= 0xFFFF) { + *(parser->buffer.last++) = 0xE0 + (value >> 12); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + else { + *(parser->buffer.last++) = 0xF0 + (value >> 18); + *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + + parser->unread ++; + } + + /* On EOF, put NUL into the buffer and return. */ + + if (parser->eof) { + *(parser->buffer.last++) = '\0'; + parser->unread ++; + return 1; + } + + } + + if (parser->offset >= MAX_FILE_SIZE) { + return yaml_parser_set_reader_error(parser, "input is too long", + parser->offset, -1); + } + + return 1; +} diff --git a/src/3rdparty/libyaml/src/scanner.c b/src/3rdparty/libyaml/src/scanner.c new file mode 100644 index 00000000..c6b49876 --- /dev/null +++ b/src/3rdparty/libyaml/src/scanner.c @@ -0,0 +1,3598 @@ + +/* + * Introduction + * ************ + * + * The following notes assume that you are familiar with the YAML specification + * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in + * some cases we are less restrictive that it requires. + * + * The process of transforming a YAML stream into a sequence of events is + * divided on two steps: Scanning and Parsing. + * + * The Scanner transforms the input stream into a sequence of tokens, while the + * parser transform the sequence of tokens produced by the Scanner into a + * sequence of parsing events. + * + * The Scanner is rather clever and complicated. The Parser, on the contrary, + * is a straightforward implementation of a recursive-descendant parser (or, + * LL(1) parser, as it is usually called). + * + * Actually there are two issues of Scanning that might be called "clever", the + * rest is quite straightforward. The issues are "block collection start" and + * "simple keys". Both issues are explained below in details. + * + * Here the Scanning step is explained and implemented. We start with the list + * of all the tokens produced by the Scanner together with short descriptions. + * + * Now, tokens: + * + * STREAM-START(encoding) # The stream start. + * STREAM-END # The stream end. + * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. + * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. + * DOCUMENT-START # '---' + * DOCUMENT-END # '...' + * BLOCK-SEQUENCE-START # Indentation increase denoting a block + * BLOCK-MAPPING-START # sequence or a block mapping. + * BLOCK-END # Indentation decrease. + * FLOW-SEQUENCE-START # '[' + * FLOW-SEQUENCE-END # ']' + * FLOW-MAPPING-START # '{' + * FLOW-MAPPING-END # '}' + * BLOCK-ENTRY # '-' + * FLOW-ENTRY # ',' + * KEY # '?' or nothing (simple keys). + * VALUE # ':' + * ALIAS(anchor) # '*anchor' + * ANCHOR(anchor) # '&anchor' + * TAG(handle,suffix) # '!handle!suffix' + * SCALAR(value,style) # A scalar. + * + * The following two tokens are "virtual" tokens denoting the beginning and the + * end of the stream: + * + * STREAM-START(encoding) + * STREAM-END + * + * We pass the information about the input stream encoding with the + * STREAM-START token. + * + * The next two tokens are responsible for tags: + * + * VERSION-DIRECTIVE(major,minor) + * TAG-DIRECTIVE(handle,prefix) + * + * Example: + * + * %YAML 1.1 + * %TAG ! !foo + * %TAG !yaml! tag:yaml.org,2002: + * --- + * + * The corresponding sequence of tokens: + * + * STREAM-START(utf-8) + * VERSION-DIRECTIVE(1,1) + * TAG-DIRECTIVE("!","!foo") + * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") + * DOCUMENT-START + * STREAM-END + * + * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole + * line. + * + * The document start and end indicators are represented by: + * + * DOCUMENT-START + * DOCUMENT-END + * + * Note that if a YAML stream contains an implicit document (without '---' + * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be + * produced. + * + * In the following examples, we present whole documents together with the + * produced tokens. + * + * 1. An implicit document: + * + * 'a scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * STREAM-END + * + * 2. An explicit document: + * + * --- + * 'a scalar' + * ... + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * SCALAR("a scalar",single-quoted) + * DOCUMENT-END + * STREAM-END + * + * 3. Several documents in a stream: + * + * 'a scalar' + * --- + * 'another scalar' + * --- + * 'yet another scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * DOCUMENT-START + * SCALAR("another scalar",single-quoted) + * DOCUMENT-START + * SCALAR("yet another scalar",single-quoted) + * STREAM-END + * + * We have already introduced the SCALAR token above. The following tokens are + * used to describe aliases, anchors, tag, and scalars: + * + * ALIAS(anchor) + * ANCHOR(anchor) + * TAG(handle,suffix) + * SCALAR(value,style) + * + * The following series of examples illustrate the usage of these tokens: + * + * 1. A recursive sequence: + * + * &A [ *A ] + * + * Tokens: + * + * STREAM-START(utf-8) + * ANCHOR("A") + * FLOW-SEQUENCE-START + * ALIAS("A") + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A tagged scalar: + * + * !!float "3.14" # A good approximation. + * + * Tokens: + * + * STREAM-START(utf-8) + * TAG("!!","float") + * SCALAR("3.14",double-quoted) + * STREAM-END + * + * 3. Various scalar styles: + * + * --- # Implicit empty plain scalars do not produce tokens. + * --- a plain scalar + * --- 'a single-quoted scalar' + * --- "a double-quoted scalar" + * --- |- + * a literal scalar + * --- >- + * a folded + * scalar + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * DOCUMENT-START + * SCALAR("a plain scalar",plain) + * DOCUMENT-START + * SCALAR("a single-quoted scalar",single-quoted) + * DOCUMENT-START + * SCALAR("a double-quoted scalar",double-quoted) + * DOCUMENT-START + * SCALAR("a literal scalar",literal) + * DOCUMENT-START + * SCALAR("a folded scalar",folded) + * STREAM-END + * + * Now it's time to review collection-related tokens. We will start with + * flow collections: + * + * FLOW-SEQUENCE-START + * FLOW-SEQUENCE-END + * FLOW-MAPPING-START + * FLOW-MAPPING-END + * FLOW-ENTRY + * KEY + * VALUE + * + * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and + * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' + * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the + * indicators '?' and ':', which are used for denoting mapping keys and values, + * are represented by the KEY and VALUE tokens. + * + * The following examples show flow collections: + * + * 1. A flow sequence: + * + * [item 1, item 2, item 3] + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-SEQUENCE-START + * SCALAR("item 1",plain) + * FLOW-ENTRY + * SCALAR("item 2",plain) + * FLOW-ENTRY + * SCALAR("item 3",plain) + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A flow mapping: + * + * { + * a simple key: a value, # Note that the KEY token is produced. + * ? a complex key: another value, + * } + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * FLOW-ENTRY + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * FLOW-ENTRY + * FLOW-MAPPING-END + * STREAM-END + * + * A simple key is a key which is not denoted by the '?' indicator. Note that + * the Scanner still produce the KEY token whenever it encounters a simple key. + * + * For scanning block collections, the following tokens are used (note that we + * repeat KEY and VALUE here): + * + * BLOCK-SEQUENCE-START + * BLOCK-MAPPING-START + * BLOCK-END + * BLOCK-ENTRY + * KEY + * VALUE + * + * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation + * increase that precedes a block collection (cf. the INDENT token in Python). + * The token BLOCK-END denote indentation decrease that ends a block collection + * (cf. the DEDENT token in Python). However YAML has some syntax pecularities + * that makes detections of these tokens more complex. + * + * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators + * '-', '?', and ':' correspondingly. + * + * The following examples show how the tokens BLOCK-SEQUENCE-START, + * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: + * + * 1. Block sequences: + * + * - item 1 + * - item 2 + * - + * - item 3.1 + * - item 3.2 + * - + * key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 3.1",plain) + * BLOCK-ENTRY + * SCALAR("item 3.2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Block mappings: + * + * a simple key: a value # The KEY token is produced here. + * ? a complex key + * : another value + * a mapping: + * key 1: value 1 + * key 2: value 2 + * a sequence: + * - item 1 + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * KEY + * SCALAR("a mapping",plain) + * VALUE + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML does not always require to start a new block collection from a new + * line. If the current line contains only '-', '?', and ':' indicators, a new + * block collection may start at the current line. The following examples + * illustrate this case: + * + * 1. Collections in a sequence: + * + * - - item 1 + * - item 2 + * - key 1: value 1 + * key 2: value 2 + * - ? complex key + * : complex value + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("complex key") + * VALUE + * SCALAR("complex value") + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Collections in a mapping: + * + * ? a sequence + * : - item 1 + * - item 2 + * ? a mapping + * : key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * KEY + * SCALAR("a mapping",plain) + * VALUE + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML also permits non-indented sequences if they are included into a block + * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: + * + * key: + * - item 1 # BLOCK-SEQUENCE-START is NOT produced here. + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("key",plain) + * VALUE + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + */ + +#include "yaml_private.h" + +/* + * Ensure that the buffer contains the required number of characters. + * Return 1 on success, 0 on failure (reader error or memory error). + */ + +#define CACHE(parser,length) \ + (parser->unread >= (length) \ + ? 1 \ + : yaml_parser_update_buffer(parser, (length))) + +/* + * Advance the buffer pointer. + */ + +#define SKIP(parser) \ + (parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) + +#define SKIP_LINE(parser) \ + (IS_CRLF(parser->buffer) ? \ + (parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2, \ + parser->buffer.pointer += 2) : \ + IS_BREAK(parser->buffer) ? \ + (parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) : 0) + +/* + * Copy a character to a string buffer and advance pointers. + */ + +#define READ(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (COPY(string,parser->buffer), \ + parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + 1) : 0) + +/* + * Copy a line break character to a string buffer and advance pointers. + */ + +#define READ_LINE(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (((CHECK_AT(parser->buffer,'\r',0) \ + && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2) : \ + (CHECK_AT(parser->buffer,'\r',0) \ + || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer ++, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xC2',0) \ + && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xE2',0) && \ + CHECK_AT(parser->buffer,'\x80',1) && \ + (CHECK_AT(parser->buffer,'\xA8',2) || \ + CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \ + (*((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : 0), \ + 1) : 0) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Error handling. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem); + +/* + * High-level token API. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser); + +/* + * Potential simple keys. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser); + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser); + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser); + +/* + * Indentation treatment. + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark); + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column); + +/* + * Token fetchers. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser); + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser); + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser); + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_key(yaml_parser_t *parser); + +static int +yaml_parser_fetch_value(yaml_parser_t *parser); + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type); + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal); + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single); + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser); + +/* + * Token scanners. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser); + +static int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name); + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor); + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number); + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix); + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type); + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle); + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri); + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string); + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal); + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark); + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single); + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Get the next token. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(token); /* Non-NULL token object is expected. */ + + /* Erase the token object. */ + + memset(token, 0, sizeof(yaml_token_t)); + + /* No tokens after STREAM-END or error. */ + + if (parser->stream_end_produced || parser->error) { + return 1; + } + + /* Ensure that the tokens queue contains enough tokens. */ + + if (!parser->token_available) { + if (!yaml_parser_fetch_more_tokens(parser)) + return 0; + } + + /* Fetch the next token from the queue. */ + + *token = DEQUEUE(parser, parser->tokens); + parser->token_available = 0; + parser->tokens_parsed ++; + + if (token->type == YAML_STREAM_END_TOKEN) { + parser->stream_end_produced = 1; + } + + return 1; +} + +/* + * Set the scanner error and return 0. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem) +{ + parser->error = YAML_SCANNER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = parser->mark; + + return 0; +} + +/* + * Ensure that the tokens queue contains at least one token which can be + * returned to the Parser. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser) +{ + int need_more_tokens; + + /* While we need more tokens to fetch, do it. */ + + while (1) + { + /* + * Check if we really need to fetch more tokens. + */ + + need_more_tokens = 0; + + if (parser->tokens.head == parser->tokens.tail) + { + /* Queue is empty. */ + + need_more_tokens = 1; + } + else + { + yaml_simple_key_t *simple_key; + + /* Check if any potential simple key may occupy the head position. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key++) { + if (simple_key->possible + && simple_key->token_number == parser->tokens_parsed) { + need_more_tokens = 1; + break; + } + } + } + + /* We are finished. */ + + if (!need_more_tokens) + break; + + /* Fetch the next token. */ + + if (!yaml_parser_fetch_next_token(parser)) + return 0; + } + + parser->token_available = 1; + + return 1; +} + +/* + * The dispatcher for token fetchers. + */ + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser) +{ + /* Ensure that the buffer is initialized. */ + + if (!CACHE(parser, 1)) + return 0; + + /* Check if we just started scanning. Fetch STREAM-START then. */ + + if (!parser->stream_start_produced) + return yaml_parser_fetch_stream_start(parser); + + /* Eat whitespaces and comments until we reach the next token. */ + + if (!yaml_parser_scan_to_next_token(parser)) + return 0; + + /* Remove obsolete potential simple keys. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + /* Check the indentation level against the current column. */ + + if (!yaml_parser_unroll_indent(parser, parser->mark.column)) + return 0; + + /* + * Ensure that the buffer contains at least 4 characters. 4 is the length + * of the longest indicators ('--- ' and '... '). + */ + + if (!CACHE(parser, 4)) + return 0; + + /* Is it the end of the stream? */ + + if (IS_Z(parser->buffer)) + return yaml_parser_fetch_stream_end(parser); + + /* Is it a directive? */ + + if (parser->mark.column == 0 && CHECK(parser->buffer, '%')) + return yaml_parser_fetch_directive(parser); + + /* Is it the document start indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '-', 0) + && CHECK_AT(parser->buffer, '-', 1) + && CHECK_AT(parser->buffer, '-', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_START_TOKEN); + + /* Is it the document end indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '.', 0) + && CHECK_AT(parser->buffer, '.', 1) + && CHECK_AT(parser->buffer, '.', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_END_TOKEN); + + /* Is it the flow sequence start indicator? */ + + if (CHECK(parser->buffer, '[')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_SEQUENCE_START_TOKEN); + + /* Is it the flow mapping start indicator? */ + + if (CHECK(parser->buffer, '{')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_MAPPING_START_TOKEN); + + /* Is it the flow sequence end indicator? */ + + if (CHECK(parser->buffer, ']')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_SEQUENCE_END_TOKEN); + + /* Is it the flow mapping end indicator? */ + + if (CHECK(parser->buffer, '}')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_MAPPING_END_TOKEN); + + /* Is it the flow entry indicator? */ + + if (CHECK(parser->buffer, ',')) + return yaml_parser_fetch_flow_entry(parser); + + /* Is it the block entry indicator? */ + + if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1)) + return yaml_parser_fetch_block_entry(parser); + + /* Is it the key indicator? */ + + if (CHECK(parser->buffer, '?') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_key(parser); + + /* Is it the value indicator? */ + + if (CHECK(parser->buffer, ':') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_value(parser); + + /* Is it an alias? */ + + if (CHECK(parser->buffer, '*')) + return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN); + + /* Is it an anchor? */ + + if (CHECK(parser->buffer, '&')) + return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN); + + /* Is it a tag? */ + + if (CHECK(parser->buffer, '!')) + return yaml_parser_fetch_tag(parser); + + /* Is it a literal scalar? */ + + if (CHECK(parser->buffer, '|') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 1); + + /* Is it a folded scalar? */ + + if (CHECK(parser->buffer, '>') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 0); + + /* Is it a single-quoted scalar? */ + + if (CHECK(parser->buffer, '\'')) + return yaml_parser_fetch_flow_scalar(parser, 1); + + /* Is it a double-quoted scalar? */ + + if (CHECK(parser->buffer, '"')) + return yaml_parser_fetch_flow_scalar(parser, 0); + + /* + * Is it a plain scalar? + * + * A plain scalar may start with any non-blank characters except + * + * '-', '?', ':', ',', '[', ']', '{', '}', + * '#', '&', '*', '!', '|', '>', '\'', '\"', + * '%', '@', '`'. + * + * In the block context (and, for the '-' indicator, in the flow context + * too), it may also start with the characters + * + * '-', '?', ':' + * + * if it is followed by a non-space character. + * + * The last rule is more restrictive than the specification requires. + */ + + if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-') + || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':') + || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|') + || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%') + || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) || + (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) || + (!parser->flow_level && + (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')) + && !IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_plain_scalar(parser); + + /* + * If we don't determine the token type so far, it is an error. + */ + + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser->mark, + "found character that cannot start any token"); +} + +/* + * Check the list of potential simple keys and remove the positions that + * cannot contain simple keys anymore. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key; + + /* Check for a potential simple key for each flow level. */ + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key ++) + { + /* + * The specification requires that a simple key + * + * - is limited to a single line, + * - is shorter than 1024 characters. + */ + + if (simple_key->possible + && (simple_key->mark.line < parser->mark.line + || simple_key->mark.index+1024 < parser->mark.index)) { + + /* Check if the potential simple key to be removed is required. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + + simple_key->possible = 0; + } + } + + return 1; +} + +/* + * Check if a simple key may start at the current position and add it if + * needed. + */ + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser) +{ + /* + * A simple key is required at the current position if the scanner is in + * the block context and the current column coincides with the indentation + * level. + */ + + int required = (!parser->flow_level + && parser->indent == (ptrdiff_t)parser->mark.column); + + /* + * If the current position may start a simple key, save it. + */ + + if (parser->simple_key_allowed) + { + yaml_simple_key_t simple_key; + simple_key.possible = 1; + simple_key.required = required; + simple_key.token_number = + parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head); + simple_key.mark = parser->mark; + + if (!yaml_parser_remove_simple_key(parser)) return 0; + + *(parser->simple_keys.top-1) = simple_key; + } + + return 1; +} + +/* + * Remove a potential simple key at the current flow level. + */ + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + if (simple_key->possible) + { + /* If the key is required, it is an error. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + } + + /* Remove the key from the stack. */ + + simple_key->possible = 0; + + return 1; +} + +/* + * Increase the flow level and resize the simple key list if needed. + */ + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser) +{ + yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } }; + + /* Reset the simple key on the next level. */ + + if (!PUSH(parser, parser->simple_keys, empty_simple_key)) + return 0; + + /* Increase the flow level. */ + + if (parser->flow_level == INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->flow_level++; + + return 1; +} + +/* + * Decrease the flow level. + */ + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser) +{ + if (parser->flow_level) { + parser->flow_level --; + (void)POP(parser, parser->simple_keys); + } + + return 1; +} + +/* + * Push the current indentation level to the stack and set the new level + * the current column is greater than the indentation level. In this case, + * append or insert the specified token into the token queue. + * + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + if (parser->indent < column) + { + /* + * Push the current indentation level to the stack and set the new + * indentation level. + */ + + if (!PUSH(parser, parser->indents, parser->indent)) + return 0; + + if (column > INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->indent = column; + + /* Create a token and insert it into the queue. */ + + TOKEN_INIT(token, type, mark, mark); + + if (number == -1) { + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + } + else { + if (!QUEUE_INSERT(parser, + parser->tokens, number - parser->tokens_parsed, token)) + return 0; + } + } + + return 1; +} + +/* + * Pop indentation levels from the indents stack until the current level + * becomes less or equal to the column. For each indentation level, append + * the BLOCK-END token. + */ + + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + /* Loop through the indentation levels in the stack. */ + + while (parser->indent > column) + { + /* Create a token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + /* Pop the indentation level. */ + + parser->indent = POP(parser, parser->indents); + } + + return 1; +} + +/* + * Initialize the scanner and produce the STREAM-START token. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser) +{ + yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } }; + yaml_token_t token; + + /* Set the initial indentation. */ + + parser->indent = -1; + + /* Initialize the simple key stack. */ + + if (!PUSH(parser, parser->simple_keys, simple_key)) + return 0; + + /* A simple key is allowed at the beginning of the stream. */ + + parser->simple_key_allowed = 1; + + /* We have started. */ + + parser->stream_start_produced = 1; + + /* Create the STREAM-START token and append it to the queue. */ + + STREAM_START_TOKEN_INIT(token, parser->encoding, + parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the STREAM-END token and shut down the scanner. + */ + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Force new line. */ + + if (parser->mark.column != 0) { + parser->mark.column = 0; + parser->mark.line ++; + } + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the STREAM-END token and append it to the queue. */ + + STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. + */ + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */ + + if (!yaml_parser_scan_directive(parser, &token)) + return 0; + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the DOCUMENT-START or DOCUMENT-END token. + */ + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + + SKIP(parser); + SKIP(parser); + SKIP(parser); + + end_mark = parser->mark; + + /* Create the DOCUMENT-START or DOCUMENT-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + */ + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* The indicators '[' and '{' may start a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* Increase the flow level. */ + + if (!yaml_parser_increase_flow_level(parser)) + return 0; + + /* A simple key may follow the indicators '[' and '{'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. + */ + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple key on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Decrease the flow level. */ + + if (!yaml_parser_decrease_flow_level(parser)) + return 0; + + /* No simple keys after the indicators ']' and '}'. */ + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-ENTRY token. + */ + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after ','. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the BLOCK-ENTRY token. + */ + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Check if the scanner is in the block context. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new entry. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "block sequence entries are not allowed in this context"); + } + + /* Add the BLOCK-SEQUENCE-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark)) + return 0; + } + else + { + /* + * It is an error for the '-' indicator to occur in the flow context, + * but we let the Parser detect and report about it because the Parser + * is able to point to the context. + */ + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '-'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the BLOCK-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the KEY token. + */ + +static int +yaml_parser_fetch_key(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* In the block context, additional checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new key (not necessary simple). */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping keys are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '?' in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the KEY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the VALUE token. + */ + +static int +yaml_parser_fetch_value(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + /* Have we found a simple key? */ + + if (simple_key->possible) + { + + /* Create the KEY token and insert it into the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark); + + if (!QUEUE_INSERT(parser, parser->tokens, + simple_key->token_number - parser->tokens_parsed, token)) + return 0; + + /* In the block context, we may need to add the BLOCK-MAPPING-START token. */ + + if (!yaml_parser_roll_indent(parser, simple_key->mark.column, + simple_key->token_number, + YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark)) + return 0; + + /* Remove the simple key. */ + + simple_key->possible = 0; + + /* A simple key cannot follow another simple key. */ + + parser->simple_key_allowed = 0; + } + else + { + /* The ':' indicator follows a complex key. */ + + /* In the block context, extra checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a complex value. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping values are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Simple keys after ':' are allowed in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + } + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the VALUE token and append it to the queue. */ + + TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the ALIAS or ANCHOR token. + */ + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type) +{ + yaml_token_t token; + + /* An anchor or an alias could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow an anchor or an alias. */ + + parser->simple_key_allowed = 0; + + /* Create the ALIAS or ANCHOR token and append it to the queue. */ + + if (!yaml_parser_scan_anchor(parser, &token, type)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + return 1; +} + +/* + * Produce the TAG token. + */ + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A tag could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a tag. */ + + parser->simple_key_allowed = 0; + + /* Create the TAG token and append it to the queue. */ + + if (!yaml_parser_scan_tag(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. + */ + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal) +{ + yaml_token_t token; + + /* Remove any potential simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* A simple key may follow a block scalar. */ + + parser->simple_key_allowed = 1; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_block_scalar(parser, &token, literal)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. + */ + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_flow_scalar(parser, &token, single)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,plain) token. + */ + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_plain_scalar(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Eat whitespaces and comments until the next token is found. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser) +{ + /* Until the next token is not found. */ + + while (1) + { + /* Allow the BOM mark to start a line. */ + + if (!CACHE(parser, 1)) return 0; + + if (parser->mark.column == 0 && IS_BOM(parser->buffer)) + SKIP(parser); + + /* + * Eat whitespaces. + * + * Tabs are allowed: + * + * - in the flow context; + * - in the block context, but not at the beginning of the line or + * after '-', '?', or ':' (complex value). + */ + + if (!CACHE(parser, 1)) return 0; + + while (CHECK(parser->buffer,' ') || + ((parser->flow_level || !parser->simple_key_allowed) && + CHECK(parser->buffer, '\t'))) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Eat a comment until a line break. */ + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + } + + /* If it is a line break, eat it. */ + + if (IS_BREAK(parser->buffer)) + { + if (!CACHE(parser, 2)) return 0; + SKIP_LINE(parser); + + /* In the block context, a new line may start a simple key. */ + + if (!parser->flow_level) { + parser->simple_key_allowed = 1; + } + } + else + { + /* We have found a token. */ + + break; + } + } + + return 1; +} + +/* + * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark, end_mark; + yaml_char_t *name = NULL; + int major, minor; + yaml_char_t *handle = NULL, *prefix = NULL; + + /* Eat '%'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the directive name. */ + + if (!yaml_parser_scan_directive_name(parser, start_mark, &name)) + goto error; + + /* Is it a YAML directive? */ + + if (strcmp((char *)name, "YAML") == 0) + { + /* Scan the VERSION directive value. */ + + if (!yaml_parser_scan_version_directive_value(parser, start_mark, + &major, &minor)) + goto error; + + end_mark = parser->mark; + + /* Create a VERSION-DIRECTIVE token. */ + + VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor, + start_mark, end_mark); + } + + /* Is it a TAG directive? */ + + else if (strcmp((char *)name, "TAG") == 0) + { + /* Scan the TAG directive value. */ + + if (!yaml_parser_scan_tag_directive_value(parser, start_mark, + &handle, &prefix)) + goto error; + + end_mark = parser->mark; + + /* Create a TAG-DIRECTIVE token. */ + + TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix, + start_mark, end_mark); + } + + /* Unknown directive. */ + + else + { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unknown directive name"); + goto error; + } + + /* Eat the rest of the line including any comments. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + yaml_free(name); + + return 1; + +error: + yaml_free(prefix); + yaml_free(handle); + yaml_free(name); + return 0; +} + +/* + * Scan the directive name. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^ + */ + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Consume the directive name. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the name is empty. */ + + if (string.start == string.pointer) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name"); + goto error; + } + + /* Check for an blank character after the name. */ + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character"); + goto error; + } + + *name = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan the value of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^ + */ + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor) +{ + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Consume the major version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, major)) + return 0; + + /* Eat '.'. */ + + if (!CHECK(parser->buffer, '.')) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character"); + } + + SKIP(parser); + + /* Consume the minor version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor)) + return 0; + + return 1; +} + +#define MAX_NUMBER_LENGTH 9 + +/* + * Scan the version number of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^ + * %YAML 1.1 # a comment \n + * ^ + */ + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number) +{ + int value = 0; + size_t length = 0; + + /* Repeat while the next character is digit. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_DIGIT(parser->buffer)) + { + /* Check if the number is too long. */ + + if (++length > MAX_NUMBER_LENGTH) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number"); + } + + value = value*10 + AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) return 0; + } + + /* Check if the number was present. */ + + if (!length) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number"); + } + + *number = value; + + return 1; +} + +/* + * Scan the value of a TAG-DIRECTIVE token. + * + * Scope: + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix) +{ + yaml_char_t *handle_value = NULL; + yaml_char_t *prefix_value = NULL; + + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value)) + goto error; + + /* Expect a whitespace. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANK(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace"); + goto error; + } + + /* Eat whitespaces. */ + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a prefix. */ + + if (!yaml_parser_scan_tag_uri(parser, 1, 1, NULL, start_mark, &prefix_value)) + goto error; + + /* Expect a whitespace or line break. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + + *handle = handle_value; + *prefix = prefix_value; + + return 1; + +error: + yaml_free(handle_value); + yaml_free(prefix_value); + return 0; +} + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type) +{ + int length = 0; + yaml_mark_t start_mark, end_mark; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator character. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the value. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + length ++; + } + + end_mark = parser->mark; + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}') + || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '`'))) { + yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ? + "while scanning an anchor" : "while scanning an alias", start_mark, + "did not find expected alphabetic or numeric character"); + goto error; + } + + /* Create a token. */ + + if (type == YAML_ANCHOR_TOKEN) { + ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + else { + ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a TAG token. + */ + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_char_t *handle = NULL; + yaml_char_t *suffix = NULL; + yaml_mark_t start_mark, end_mark; + + start_mark = parser->mark; + + /* Check if the tag is in the canonical form. */ + + if (!CACHE(parser, 2)) goto error; + + if (CHECK_AT(parser->buffer, '<', 1)) + { + /* Set the handle to '' */ + + handle = YAML_MALLOC(1); + if (!handle) goto error; + handle[0] = '\0'; + + /* Eat '!<' */ + + SKIP(parser); + SKIP(parser); + + /* Consume the tag value. */ + + if (!yaml_parser_scan_tag_uri(parser, 1, 0, NULL, start_mark, &suffix)) + goto error; + + /* Check for '>' and eat it. */ + + if (!CHECK(parser->buffer, '>')) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'"); + goto error; + } + + SKIP(parser); + } + else + { + /* The tag has either the '!suffix' or the '!handle!suffix' form. */ + + /* First, try to scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle)) + goto error; + + /* Check if it is, indeed, handle. */ + + if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!') + { + /* Scan the suffix now. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, 0, NULL, start_mark, &suffix)) + goto error; + } + else + { + /* It wasn't a handle after all. Scan the rest of the tag. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, 0, handle, start_mark, &suffix)) + goto error; + + /* Set the handle to '!'. */ + + yaml_free(handle); + handle = YAML_MALLOC(2); + if (!handle) goto error; + handle[0] = '!'; + handle[1] = '\0'; + + /* + * A special case: the '!' tag. Set the handle to '' and the + * suffix to '!'. + */ + + if (suffix[0] == '\0') { + yaml_char_t *tmp = handle; + handle = suffix; + suffix = tmp; + } + } + } + + /* Check the character which ends the tag. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + if (!parser->flow_level || !CHECK(parser->buffer, ',') ) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + } + + end_mark = parser->mark; + + /* Create a token. */ + + TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark); + + return 1; + +error: + yaml_free(handle); + yaml_free(suffix); + return 0; +} + +/* + * Scan a tag handle. + */ + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Check the initial '!' character. */ + + if (!CACHE(parser, 1)) goto error; + + if (!CHECK(parser->buffer, '!')) { + yaml_parser_set_scanner_error(parser, directive ? + "while scanning a tag directive" : "while scanning a tag", + start_mark, "did not find expected '!'"); + goto error; + } + + /* Copy the '!' character. */ + + if (!READ(parser, string)) goto error; + + /* Copy all subsequent alphabetical and numerical characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the trailing character is '!' and copy it. */ + + if (CHECK(parser->buffer, '!')) + { + if (!READ(parser, string)) goto error; + } + else + { + /* + * It's either the '!' tag or not really a tag handle. If it's a %TAG + * directive, it's an error. If it's a tag token, it must be a part of + * URI. + */ + + if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) { + yaml_parser_set_scanner_error(parser, "while parsing a tag directive", + start_mark, "did not find expected '!'"); + goto error; + } + } + + *handle = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a tag. + */ + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri) +{ + size_t length = head ? strlen((char *)head) : 0; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Resize the string to include the head. */ + + while ((size_t)(string.end - string.start) <= length) { + if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + } + + /* + * Copy the head if needed. + * + * Note that we don't copy the leading '!' character. + */ + + if (length > 1) { + memcpy(string.start, head+1, length-1); + string.pointer += length-1; + } + + /* Scan the tag. */ + + if (!CACHE(parser, 1)) goto error; + + /* + * The set of characters that may appear in URI is as follows: + * + * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + * '=', '+', '$', '.', '!', '~', '*', '\'', '(', ')', '%'. + * + * If we are inside a verbatim tag <...> (parameter uri_char is true) + * then also the following flow indicators are allowed: + * ',', '[', ']' + */ + + while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';') + || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=') + || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$') + || CHECK(parser->buffer, '.') || CHECK(parser->buffer, '%') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~') + || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')') + || (uri_char && ( + CHECK(parser->buffer, ',') + || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']') + ) + )) + { + /* Check if it is a URI-escape sequence. */ + + if (CHECK(parser->buffer, '%')) { + if (!STRING_EXTEND(parser, string)) + goto error; + + if (!yaml_parser_scan_uri_escapes(parser, + directive, start_mark, &string)) goto error; + } + else { + if (!READ(parser, string)) goto error; + } + + length ++; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the tag is non-empty. */ + + if (!length) { + if (!STRING_EXTEND(parser, string)) + goto error; + + yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find expected tag URI"); + goto error; + } + + *uri = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Decode an URI-escape sequence corresponding to a single UTF-8 character. + */ + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string) +{ + int width = 0; + + /* Decode the required number of characters. */ + + do { + + unsigned char octet = 0; + + /* Check for a URI-escaped octet. */ + + if (!CACHE(parser, 3)) return 0; + + if (!(CHECK(parser->buffer, '%') + && IS_HEX_AT(parser->buffer, 1) + && IS_HEX_AT(parser->buffer, 2))) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find URI escaped octet"); + } + + /* Get the octet. */ + + octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2); + + /* If it is the leading octet, determine the length of the UTF-8 sequence. */ + + if (!width) + { + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + if (!width) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect leading UTF-8 octet"); + } + } + else + { + /* Check if the trailing octet is correct. */ + + if ((octet & 0xC0) != 0x80) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect trailing UTF-8 octet"); + } + } + + /* Copy the octet and move the pointers. */ + + *(string->pointer++) = octet; + SKIP(parser); + SKIP(parser); + SKIP(parser); + + } while (--width); + + return 1; +} + +/* + * Scan a block scalar. + */ + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + int chomping = 0; + int increment = 0; + int indent = 0; + int leading_blank = 0; + int trailing_blank = 0; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator '|' or '>'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the additional block scalar indicators. */ + + if (!CACHE(parser, 1)) goto error; + + /* Check for a chomping indicator. */ + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) + { + /* Set the chomping method and eat the indicator. */ + + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + + /* Check for an indentation indicator. */ + + if (!CACHE(parser, 1)) goto error; + + if (IS_DIGIT(parser->buffer)) + { + /* Check that the indentation is greater than 0. */ + + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0"); + goto error; + } + + /* Get the indentation level and eat the indicator. */ + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + } + } + + /* Do the same as above, but in the opposite order. */ + + else if (IS_DIGIT(parser->buffer)) + { + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0"); + goto error; + } + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) goto error; + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) { + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + } + } + + /* Eat whitespaces and comments to the end of the line. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + end_mark = parser->mark; + + /* Set the indentation level if it was specified. */ + + if (increment) { + indent = parser->indent >= 0 ? parser->indent+increment : increment; + } + + /* Scan the leading line breaks and determine the indentation level if needed. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, + start_mark, &end_mark)) goto error; + + /* Scan the block scalar content. */ + + if (!CACHE(parser, 1)) goto error; + + while ((int)parser->mark.column == indent && !(IS_Z(parser->buffer))) + { + /* + * We are at the beginning of a non-empty line. + */ + + /* Is it a trailing whitespace? */ + + trailing_blank = IS_BLANK(parser->buffer); + + /* Check if we need to fold the leading line break. */ + + if (!literal && (*leading_break.start == '\n') + && !leading_blank && !trailing_blank) + { + /* Do we need to join the lines by space? */ + + if (*trailing_breaks.start == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer ++) = ' '; + } + + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + CLEAR(parser, leading_break); + } + + /* Append the remaining line breaks. */ + + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + + /* Is it a leading whitespace? */ + + leading_blank = IS_BLANK(parser->buffer); + + /* Consume the current line. */ + + while (!IS_BREAKZ(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) goto error; + + if (!READ_LINE(parser, leading_break)) goto error; + + /* Eat the following indentation spaces and line breaks. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, + &indent, &trailing_breaks, start_mark, &end_mark)) goto error; + } + + /* Chomp the tail. */ + + if (chomping != -1) { + if (!JOIN(parser, string, leading_break)) goto error; + } + if (chomping == 1) { + if (!JOIN(parser, string, trailing_breaks)) goto error; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 0; +} + +/* + * Scan indentation spaces and line breaks for a block scalar. Determine the + * indentation level if needed. + */ + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark) +{ + int max_indent = 0; + + *end_mark = parser->mark; + + /* Eat the indentation spaces and line breaks. */ + + while (1) + { + /* Eat the indentation spaces. */ + + if (!CACHE(parser, 1)) return 0; + + while ((!*indent || (int)parser->mark.column < *indent) + && IS_SPACE(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + if ((int)parser->mark.column > max_indent) + max_indent = (int)parser->mark.column; + + /* Check for a tab character messing the indentation. */ + + if ((!*indent || (int)parser->mark.column < *indent) + && IS_TAB(parser->buffer)) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an indentation space is expected"); + } + + /* Have we found a non-empty line? */ + + if (!IS_BREAK(parser->buffer)) break; + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) return 0; + if (!READ_LINE(parser, *breaks)) return 0; + *end_mark = parser->mark; + } + + /* Determine the indentation level if needed. */ + + if (!*indent) { + *indent = max_indent; + if (*indent < parser->indent + 1) + *indent = parser->indent + 1; + if (*indent < 1) + *indent = 1; + } + + return 1; +} + +/* + * Scan a quoted scalar. + */ + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + /* Eat the left quote. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the content of the quoted scalar. */ + + while (1) + { + /* Check that there are no document indicators at the beginning of the line. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) + { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator"); + goto error; + } + + /* Check for EOF. */ + + if (IS_Z(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream"); + goto error; + } + + /* Consume non-blank characters. */ + + if (!CACHE(parser, 2)) goto error; + + leading_blanks = 0; + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for an escaped single quote. */ + + if (single && CHECK_AT(parser->buffer, '\'', 0) + && CHECK_AT(parser->buffer, '\'', 1)) + { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = '\''; + SKIP(parser); + SKIP(parser); + } + + /* Check for the right quote. */ + + else if (CHECK(parser->buffer, single ? '\'' : '"')) + { + break; + } + + /* Check for an escaped line break. */ + + else if (!single && CHECK(parser->buffer, '\\') + && IS_BREAK_AT(parser->buffer, 1)) + { + if (!CACHE(parser, 3)) goto error; + SKIP(parser); + SKIP_LINE(parser); + leading_blanks = 1; + break; + } + + /* Check for an escape sequence. */ + + else if (!single && CHECK(parser->buffer, '\\')) + { + size_t code_length = 0; + + if (!STRING_EXTEND(parser, string)) goto error; + + /* Check the escape character. */ + + switch (parser->buffer.pointer[1]) + { + case '0': + *(string.pointer++) = '\0'; + break; + + case 'a': + *(string.pointer++) = '\x07'; + break; + + case 'b': + *(string.pointer++) = '\x08'; + break; + + case 't': + case '\t': + *(string.pointer++) = '\x09'; + break; + + case 'n': + *(string.pointer++) = '\x0A'; + break; + + case 'v': + *(string.pointer++) = '\x0B'; + break; + + case 'f': + *(string.pointer++) = '\x0C'; + break; + + case 'r': + *(string.pointer++) = '\x0D'; + break; + + case 'e': + *(string.pointer++) = '\x1B'; + break; + + case ' ': + *(string.pointer++) = '\x20'; + break; + + case '"': + *(string.pointer++) = '"'; + break; + + case '/': + *(string.pointer++) = '/'; + break; + + case '\\': + *(string.pointer++) = '\\'; + break; + + case 'N': /* NEL (#x85) */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\x85'; + break; + + case '_': /* #xA0 */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\xA0'; + break; + + case 'L': /* LS (#x2028) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA8'; + break; + + case 'P': /* PS (#x2029) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA9'; + break; + + case 'x': + code_length = 2; + break; + + case 'u': + code_length = 4; + break; + + case 'U': + code_length = 8; + break; + + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character"); + goto error; + } + + SKIP(parser); + SKIP(parser); + + /* Consume an arbitrary escape code. */ + + if (code_length) + { + unsigned int value = 0; + size_t k; + + /* Scan the character value. */ + + if (!CACHE(parser, code_length)) goto error; + + for (k = 0; k < code_length; k ++) { + if (!IS_HEX_AT(parser->buffer, k)) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number"); + goto error; + } + value = (value << 4) + AS_HEX_AT(parser->buffer, k); + } + + /* Check the value and write the character. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code"); + goto error; + } + + if (value <= 0x7F) { + *(string.pointer++) = value; + } + else if (value <= 0x7FF) { + *(string.pointer++) = 0xC0 + (value >> 6); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else if (value <= 0xFFFF) { + *(string.pointer++) = 0xE0 + (value >> 12); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else { + *(string.pointer++) = 0xF0 + (value >> 18); + *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + + /* Advance the pointer. */ + + for (k = 0; k < code_length; k ++) { + SKIP(parser); + } + } + } + + else + { + /* It is a non-escaped non-blank character. */ + + if (!READ(parser, string)) goto error; + } + + if (!CACHE(parser, 2)) goto error; + } + + /* Check if we are at the end of the scalar. */ + + /* Fix for crash unitialized value crash + * Credit for the bug and input is to OSS Fuzz + * Credit for the fix to Alex Gaynor + */ + if (!CACHE(parser, 1)) goto error; + if (CHECK(parser->buffer, single ? '\'' : '"')) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Join the whitespaces or fold line breaks. */ + + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Eat the right quote. */ + + SKIP(parser); + + end_mark = parser->mark; + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} + +/* + * Scan a plain scalar. + */ + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks = 0; + int indent = parser->indent+1; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + start_mark = end_mark = parser->mark; + + /* Consume the content of the plain scalar. */ + + while (1) + { + /* Check for a document indicator. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) break; + + /* Check for a comment. */ + + if (CHECK(parser->buffer, '#')) + break; + + /* Consume non-blank characters. */ + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for "x:" + one of ',?[]{}' in the flow context. TODO: Fix the test "spec-08-13". + * This is not completely according to the spec + * See http://yaml.org/spec/1.1/#id907281 9.1.3. Plain + */ + + if (parser->flow_level + && CHECK(parser->buffer, ':') + && ( + CHECK_AT(parser->buffer, ',', 1) + || CHECK_AT(parser->buffer, '?', 1) + || CHECK_AT(parser->buffer, '[', 1) + || CHECK_AT(parser->buffer, ']', 1) + || CHECK_AT(parser->buffer, '{', 1) + || CHECK_AT(parser->buffer, '}', 1) + ) + ) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found unexpected ':'"); + goto error; + } + + /* Check for indicators that may end a plain scalar. */ + + if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1)) + || (parser->flow_level && + (CHECK(parser->buffer, ',') + || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}')))) + break; + + /* Check if we need to join whitespaces and breaks. */ + + if (leading_blanks || whitespaces.start != whitespaces.pointer) + { + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + + leading_blanks = 0; + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Copy the character. */ + + if (!READ(parser, string)) goto error; + + end_mark = parser->mark; + + if (!CACHE(parser, 2)) goto error; + } + + /* Is it the end? */ + + if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Check for tab characters that abuse indentation. */ + + if (leading_blanks && (int)parser->mark.column < indent + && IS_TAB(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violates indentation"); + goto error; + } + + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Check indentation level. */ + + if (!parser->flow_level && (int)parser->mark.column < indent) + break; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark); + + /* Note that we change the 'simple_key_allowed' flag. */ + + if (leading_blanks) { + parser->simple_key_allowed = 1; + } + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} diff --git a/src/3rdparty/libyaml/src/writer.c b/src/3rdparty/libyaml/src/writer.c new file mode 100644 index 00000000..5d57f392 --- /dev/null +++ b/src/3rdparty/libyaml/src/writer.c @@ -0,0 +1,141 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/* + * Set the writer error and return 0. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_WRITER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Flush the output buffer. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter) +{ + int low, high; + + assert(emitter); /* Non-NULL emitter object is expected. */ + assert(emitter->write_handler); /* Write handler must be set. */ + assert(emitter->encoding); /* Output encoding must be set. */ + + emitter->buffer.last = emitter->buffer.pointer; + emitter->buffer.pointer = emitter->buffer.start; + + /* Check if the buffer is empty. */ + + if (emitter->buffer.start == emitter->buffer.last) { + return 1; + } + + /* If the output encoding is UTF-8, we don't need to recode the buffer. */ + + if (emitter->encoding == YAML_UTF8_ENCODING) + { + if (emitter->write_handler(emitter->write_handler_data, + emitter->buffer.start, + emitter->buffer.last - emitter->buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } + } + + /* Recode the buffer into the raw buffer. */ + + low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + while (emitter->buffer.pointer != emitter->buffer.last) + { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + /* + * See the "reader.c" code for more details on UTF-8 encoding. Note + * that we assume that the buffer contains a valid UTF-8 sequence. + */ + + /* Read the next UTF-8 character. */ + + octet = emitter->buffer.pointer[0]; + + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + for (k = 1; k < width; k ++) { + octet = emitter->buffer.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + + emitter->buffer.pointer += width; + + /* Write the character. */ + + if (value < 0x10000) + { + emitter->raw_buffer.last[high] = value >> 8; + emitter->raw_buffer.last[low] = value & 0xFF; + + emitter->raw_buffer.last += 2; + } + else + { + /* Write the character using a surrogate pair (check "reader.c"). */ + + value -= 0x10000; + emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); + emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; + emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); + emitter->raw_buffer.last[low+2] = value & 0xFF; + + emitter->raw_buffer.last += 4; + } + } + + /* Write the raw buffer. */ + + if (emitter->write_handler(emitter->write_handler_data, + emitter->raw_buffer.start, + emitter->raw_buffer.last - emitter->raw_buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + emitter->raw_buffer.last = emitter->raw_buffer.start; + emitter->raw_buffer.pointer = emitter->raw_buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } +} + diff --git a/src/3rdparty/libyaml/src/yaml_private.h b/src/3rdparty/libyaml/src/yaml_private.h new file mode 100644 index 00000000..b3351c41 --- /dev/null +++ b/src/3rdparty/libyaml/src/yaml_private.h @@ -0,0 +1,684 @@ +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +/* + * Memory management. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size); + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size); + +YAML_DECLARE(void) +yaml_free(void *ptr); + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *); + +/* + * Reader: Ensure that the buffer contains at least `length` characters. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Scanner: Ensure that the token stack contains at least one token ready. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +/* + * The size of the input raw buffer. + */ + +#define INPUT_RAW_BUFFER_SIZE 16384 + +/* + * The size of the input buffer. + * + * It should be possible to decode the whole raw buffer. + */ + +#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3) + +/* + * The size of the output buffer. + */ + +#define OUTPUT_BUFFER_SIZE 16384 + +/* + * The size of the output raw buffer. + * + * It should be possible to encode the whole output buffer. + */ + +#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2) + +/* + * The maximum size of a YAML input file. + * This used to be PTRDIFF_MAX, but that's not entirely portable + * because stdint.h isn't available on all platforms. + * It is not entirely clear why this isn't the maximum value + * that can fit into the parser->offset field. + */ + +#define MAX_FILE_SIZE (~(size_t)0 / 2) + + +/* + * The size of other stacks and queues. + */ + +#define INITIAL_STACK_SIZE 16 +#define INITIAL_QUEUE_SIZE 16 +#define INITIAL_STRING_SIZE 16 + +/* + * Buffer management. + */ + +#define BUFFER_INIT(context,buffer,size) \ + (((buffer).start = (yaml_char_t *)yaml_malloc(size)) ? \ + ((buffer).last = (buffer).pointer = (buffer).start, \ + (buffer).end = (buffer).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define BUFFER_DEL(context,buffer) \ + (yaml_free((buffer).start), \ + (buffer).start = (buffer).pointer = (buffer).end = 0) + +/* + * String management. + */ + +typedef struct { + yaml_char_t *start; + yaml_char_t *end; + yaml_char_t *pointer; +} yaml_string_t; + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end); + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end); + +#define NULL_STRING { NULL, NULL, NULL } + +#define STRING(string,length) { (string), (string)+(length), (string) } + +#define STRING_ASSIGN(value,string,length) \ + ((value).start = (string), \ + (value).end = (string)+(length), \ + (value).pointer = (string)) + +#define STRING_INIT(context,string,size) \ + (((string).start = YAML_MALLOC(size)) ? \ + ((string).pointer = (string).start, \ + (string).end = (string).start+(size), \ + memset((string).start, 0, (size)), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STRING_DEL(context,string) \ + (yaml_free((string).start), \ + (string).start = (string).pointer = (string).end = 0) + +#define STRING_EXTEND(context,string) \ + ((((string).pointer+5 < (string).end) \ + || yaml_string_extend(&(string).start, \ + &(string).pointer, &(string).end)) ? \ + 1 : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define CLEAR(context,string) \ + ((string).pointer = (string).start, \ + memset((string).start, 0, (string).end-(string).start)) + +#define JOIN(context,string_a,string_b) \ + ((yaml_string_join(&(string_a).start, &(string_a).pointer, \ + &(string_a).end, &(string_b).start, \ + &(string_b).pointer, &(string_b).end)) ? \ + ((string_b).pointer = (string_b).start, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * String check operations. + */ + +/* + * Check the octet at the specified position. + */ + +#define CHECK_AT(string,octet,offset) \ + ((string).pointer[offset] == (yaml_char_t)(octet)) + +/* + * Check the current octet in the buffer. + */ + +#define CHECK(string,octet) (CHECK_AT((string),(octet),0)) + +/* + * Check if the character at the specified position is an alphabetical + * character, a digit, '_', or '-'. + */ + +#define IS_ALPHA_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'Z') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'z') || \ + (string).pointer[offset] == '_' || \ + (string).pointer[offset] == '-') + +#define IS_ALPHA(string) IS_ALPHA_AT((string),0) + +/* + * Check if the character at the specified position is a digit. + */ + +#define IS_DIGIT_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9')) + +#define IS_DIGIT(string) IS_DIGIT_AT((string),0) + +/* + * Get the value of a digit. + */ + +#define AS_DIGIT_AT(string,offset) \ + ((string).pointer[offset] - (yaml_char_t) '0') + +#define AS_DIGIT(string) AS_DIGIT_AT((string),0) + +/* + * Check if the character at the specified position is a hex-digit. + */ + +#define IS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f')) + +#define IS_HEX(string) IS_HEX_AT((string),0) + +/* + * Get the value of a hex-digit. + */ + +#define AS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') ? \ + ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f') ? \ + ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \ + ((string).pointer[offset] - (yaml_char_t) '0')) + +#define AS_HEX(string) AS_HEX_AT((string),0) + +/* + * Check if the character is ASCII. + */ + +#define IS_ASCII_AT(string,offset) \ + ((string).pointer[offset] <= (yaml_char_t) '\x7F') + +#define IS_ASCII(string) IS_ASCII_AT((string),0) + +/* + * Check if the character can be printed unescaped. + */ + +#define IS_PRINTABLE_AT(string,offset) \ + (((string).pointer[offset] == 0x0A) /* . == #x0A */ \ + || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \ + && (string).pointer[offset] <= 0x7E) \ + || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \ + && (string).pointer[offset+1] >= 0xA0) \ + || ((string).pointer[offset] > 0xC2 \ + && (string).pointer[offset] < 0xED) \ + || ((string).pointer[offset] == 0xED \ + && (string).pointer[offset+1] < 0xA0) \ + || ((string).pointer[offset] == 0xEE) \ + || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \ + && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \ + && (string).pointer[offset+2] == 0xBF) \ + && !((string).pointer[offset+1] == 0xBF \ + && ((string).pointer[offset+2] == 0xBE \ + || (string).pointer[offset+2] == 0xBF)))) + +#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0) + +/* + * Check if the character at the specified position is NUL. + */ + +#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset)) + +#define IS_Z(string) IS_Z_AT((string),0) + +/* + * Check if the character at the specified position is BOM. + */ + +#define IS_BOM_AT(string,offset) \ + (CHECK_AT((string),'\xEF',(offset)) \ + && CHECK_AT((string),'\xBB',(offset)+1) \ + && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */ + +#define IS_BOM(string) IS_BOM_AT(string,0) + +/* + * Check if the character at the specified position is space. + */ + +#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset)) + +#define IS_SPACE(string) IS_SPACE_AT((string),0) + +/* + * Check if the character at the specified position is tab. + */ + +#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset)) + +#define IS_TAB(string) IS_TAB_AT((string),0) + +/* + * Check if the character at the specified position is blank (space or tab). + */ + +#define IS_BLANK_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset))) + +#define IS_BLANK(string) IS_BLANK_AT((string),0) + +/* + * Check if the character at the specified position is a line break. + */ + +#define IS_BREAK_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \ + || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \ + || (CHECK_AT((string),'\xC2',(offset)) \ + && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */ + +#define IS_BREAK(string) IS_BREAK_AT((string),0) + +#define IS_CRLF_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1)) + +#define IS_CRLF(string) IS_CRLF_AT((string),0) + +/* + * Check if the character is a line break or NUL. + */ + +#define IS_BREAKZ_AT(string,offset) \ + (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset))) + +#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0) + +/* + * Check if the character is a line break, space, or NUL. + */ + +#define IS_SPACEZ_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0) + +/* + * Check if the character is a line break, space, tab, or NUL. + */ + +#define IS_BLANKZ_AT(string,offset) \ + (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0) + +/* + * Determine the width of the character. + */ + +#define WIDTH_AT(string,offset) \ + (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \ + ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \ + ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \ + ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0) + +#define WIDTH(string) WIDTH_AT((string),0) + +/* + * Move the string pointer to the next character. + */ + +#define MOVE(string) ((string).pointer += WIDTH((string))) + +/* + * Copy a character and move the pointers of both strings. + */ + +#define COPY(string_a,string_b) \ + ((*(string_b).pointer & 0x80) == 0x00 ? \ + (*((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xE0) == 0xC0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF0) == 0xE0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF8) == 0xF0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : 0) + +/* + * Stack and queue management. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end); + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end); + +#define STACK_INIT(context,stack,type) \ + (((stack).start = (type)yaml_malloc(INITIAL_STACK_SIZE*sizeof(*(stack).start))) ? \ + ((stack).top = (stack).start, \ + (stack).end = (stack).start+INITIAL_STACK_SIZE, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STACK_DEL(context,stack) \ + (yaml_free((stack).start), \ + (stack).start = (stack).top = (stack).end = 0) + +#define STACK_EMPTY(context,stack) \ + ((stack).start == (stack).top) + +#define STACK_LIMIT(context,stack,size) \ + ((stack).top - (stack).start < (size) ? \ + 1 : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define PUSH(context,stack,value) \ + (((stack).top != (stack).end \ + || yaml_stack_extend((void **)&(stack).start, \ + (void **)&(stack).top, (void **)&(stack).end)) ? \ + (*((stack).top++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define POP(context,stack) \ + (*(--(stack).top)) + +#define QUEUE_INIT(context,queue,size,type) \ + (((queue).start = (type)yaml_malloc((size)*sizeof(*(queue).start))) ? \ + ((queue).head = (queue).tail = (queue).start, \ + (queue).end = (queue).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define QUEUE_DEL(context,queue) \ + (yaml_free((queue).start), \ + (queue).start = (queue).head = (queue).tail = (queue).end = 0) + +#define QUEUE_EMPTY(context,queue) \ + ((queue).head == (queue).tail) + +#define ENQUEUE(context,queue,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (*((queue).tail++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define DEQUEUE(context,queue) \ + (*((queue).head++)) + +#define QUEUE_INSERT(context,queue,index,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (memmove((queue).head+(index)+1,(queue).head+(index), \ + ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \ + *((queue).head+(index)) = value, \ + (queue).tail++, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * Token initializers. + */ + +#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \ + (memset(&(token), 0, sizeof(yaml_token_t)), \ + (token).type = (token_type), \ + (token).start_mark = (token_start_mark), \ + (token).end_mark = (token_end_mark)) + +#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \ + (token).data.stream_start.encoding = (token_encoding)) + +#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark))) + +#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \ + (token).data.alias.value = (token_value)) + +#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \ + (token).data.anchor.value = (token_value)) + +#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag.handle = (token_handle), \ + (token).data.tag.suffix = (token_suffix)) + +#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \ + (token).data.scalar.value = (token_value), \ + (token).data.scalar.length = (token_length), \ + (token).data.scalar.style = (token_style)) + +#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.version_directive.major = (token_major), \ + (token).data.version_directive.minor = (token_minor)) + +#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag_directive.handle = (token_handle), \ + (token).data.tag_directive.prefix = (token_prefix)) + +/* + * Event initializers. + */ + +#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \ + (memset(&(event), 0, sizeof(yaml_event_t)), \ + (event).type = (event_type), \ + (event).start_mark = (event_start_mark), \ + (event).end_mark = (event_end_mark)) + +#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \ + (event).data.stream_start.encoding = (event_encoding)) + +#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark))) + +#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \ + event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \ + (event).data.document_start.version_directive = (event_version_directive), \ + (event).data.document_start.tag_directives.start = (event_tag_directives_start), \ + (event).data.document_start.tag_directives.end = (event_tag_directives_end), \ + (event).data.document_start.implicit = (event_implicit)) + +#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \ + (event).data.document_end.implicit = (event_implicit)) + +#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \ + (event).data.alias.anchor = (event_anchor)) + +#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \ + event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \ + (event).data.scalar.anchor = (event_anchor), \ + (event).data.scalar.tag = (event_tag), \ + (event).data.scalar.value = (event_value), \ + (event).data.scalar.length = (event_length), \ + (event).data.scalar.plain_implicit = (event_plain_implicit), \ + (event).data.scalar.quoted_implicit = (event_quoted_implicit), \ + (event).data.scalar.style = (event_style)) + +#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \ + (event).data.sequence_start.anchor = (event_anchor), \ + (event).data.sequence_start.tag = (event_tag), \ + (event).data.sequence_start.implicit = (event_implicit), \ + (event).data.sequence_start.style = (event_style)) + +#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark))) + +#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \ + (event).data.mapping_start.anchor = (event_anchor), \ + (event).data.mapping_start.tag = (event_tag), \ + (event).data.mapping_start.implicit = (event_implicit), \ + (event).data.mapping_start.style = (event_style)) + +#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark))) + +/* + * Document initializer. + */ + +#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ + document_version_directive,document_tag_directives_start, \ + document_tag_directives_end,document_start_implicit, \ + document_end_implicit,document_start_mark,document_end_mark) \ + (memset(&(document), 0, sizeof(yaml_document_t)), \ + (document).nodes.start = (document_nodes_start), \ + (document).nodes.end = (document_nodes_end), \ + (document).nodes.top = (document_nodes_start), \ + (document).version_directive = (document_version_directive), \ + (document).tag_directives.start = (document_tag_directives_start), \ + (document).tag_directives.end = (document_tag_directives_end), \ + (document).start_implicit = (document_start_implicit), \ + (document).end_implicit = (document_end_implicit), \ + (document).start_mark = (document_start_mark), \ + (document).end_mark = (document_end_mark)) + +/* + * Node initializers. + */ + +#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ + (memset(&(node), 0, sizeof(yaml_node_t)), \ + (node).type = (node_type), \ + (node).tag = (node_tag), \ + (node).start_mark = (node_start_mark), \ + (node).end_mark = (node_end_mark)) + +#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.scalar.value = (node_value), \ + (node).data.scalar.length = (node_length), \ + (node).data.scalar.style = (node_style)) + +#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.sequence.items.start = (node_items_start), \ + (node).data.sequence.items.end = (node_items_end), \ + (node).data.sequence.items.top = (node_items_start), \ + (node).data.sequence.style = (node_style)) + +#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.mapping.pairs.start = (node_pairs_start), \ + (node).data.mapping.pairs.end = (node_pairs_end), \ + (node).data.mapping.pairs.top = (node_pairs_start), \ + (node).data.mapping.style = (node_style)) + +/* Strict C compiler warning helpers */ + +#if defined(__clang__) || defined(__GNUC__) +# define HASATTRIBUTE_UNUSED +#endif +#ifdef HASATTRIBUTE_UNUSED +# define __attribute__unused__ __attribute__((__unused__)) +#else +# define __attribute__unused__ +#endif + +/* Shim arguments are arguments that must be included in your function, + * but serve no purpose inside. Silence compiler warnings. */ +#define SHIM(a) /*@unused@*/ a __attribute__unused__ + +/* UNUSED_PARAM() marks a shim argument in the body to silence compiler warnings */ +#ifdef __clang__ +# define UNUSED_PARAM(a) (void)(a); +#else +# define UNUSED_PARAM(a) /*@-noeffect*/if (0) (void)(a)/*@=noeffect*/; +#endif + +#define YAML_MALLOC_STATIC(type) (type*)yaml_malloc(sizeof(type)) +#define YAML_MALLOC(size) (yaml_char_t *)yaml_malloc(size) diff --git a/src/3rdparty/libyaml/win32/config.h b/src/3rdparty/libyaml/win32/config.h new file mode 100644 index 00000000..405d3e75 --- /dev/null +++ b/src/3rdparty/libyaml/win32/config.h @@ -0,0 +1,4 @@ +#define YAML_VERSION_MAJOR 0 +#define YAML_VERSION_MINOR 2 +#define YAML_VERSION_PATCH 1 +#define YAML_VERSION_STRING "0.2.1" diff --git a/src/3rdparty/stackwalker/CMakeLists.txt b/src/3rdparty/stackwalker/CMakeLists.txt new file mode 100644 index 00000000..3d29945c --- /dev/null +++ b/src/3rdparty/stackwalker/CMakeLists.txt @@ -0,0 +1,24 @@ +# Generated from stackwalker.pro. + +##################################################################### +## BundledStackwalker Generic Library: +##################################################################### + +qt_internal_add_3rdparty_library(BundledStackwalker + QMAKE_LIB_NAME stackwalker + STATIC + INSTALL + SOURCES + stackwalker.cpp stackwalker.h + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDE_DIRECTORIES + $ +) +qt_disable_warnings(BundledStackwalker) +qt_set_symbol_visibility_hidden(BundledStackwalker) + +#### Keys ignored in scope 1:.:.:stackwalker.pro:: +# QMAKE_CFLAGS = "/D_CRT_SECURE_NO_WARNINGS" +# TEMPLATE = "lib" +# _REQUIREMENTS = "windows && msvc" diff --git a/src/3rdparty/stackwalker/LICENSE b/src/3rdparty/stackwalker/LICENSE new file mode 100644 index 00000000..43fd8dba --- /dev/null +++ b/src/3rdparty/stackwalker/LICENSE @@ -0,0 +1,25 @@ +BSD-2-Clause + +Copyright (c) 2005 - 2019, Jochen Kalmbach +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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. diff --git a/src/3rdparty/stackwalker/qt_attribution.json b/src/3rdparty/stackwalker/qt_attribution.json new file mode 100644 index 00000000..8a4adba4 --- /dev/null +++ b/src/3rdparty/stackwalker/qt_attribution.json @@ -0,0 +1,15 @@ +{ + "Id": "stackwalker", + "Name": "StackWalker", + "QDocModule": "applicationmanager", + "QtUsage": "Automatically used in Qt ApplicationManager, if available. Configure with -config disable-stackwalker to avoid.", + + "Description": "Walking the callstack in windows applications.", + "Homepage": "https://github.com/JochenKalmbach/StackWalker", + "Version": "2020-02-06", + + "License": "BSD 2-clause \"Simplified\" License", + "LicenseId": "BSD-2-Clause", + "LicenseFile": "LICENSE", + "Copyright": "Copyright (C) 2005-2019 Jochen Kalmbach" +} diff --git a/src/3rdparty/stackwalker/stackwalker.cpp b/src/3rdparty/stackwalker/stackwalker.cpp new file mode 100644 index 00000000..7008ac67 --- /dev/null +++ b/src/3rdparty/stackwalker/stackwalker.cpp @@ -0,0 +1,1469 @@ +/********************************************************************** + * + * StackWalker.cpp + * https://github.com/JochenKalmbach/StackWalker + * + * Old location: http://stackwalker.codeplex.com/ + * + * + * History: + * 2005-07-27 v1 - First public release on http://www.codeproject.com/ + * http://www.codeproject.com/threads/StackWalker.asp + * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack + * (to simplify the usage) + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL + * (should also be enough) + * - Changed to compile correctly with the PSDK of VC7.0 + * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: + * it uses LPSTR instead of LPCSTR as first parameter) + * - Added declarations to support VC5/6 without using 'dbghelp.h' + * - Added a 'pUserData' member to the ShowCallstack function and the + * PReadProcessMemoryRoutine declaration (to pass some user-defined data, + * which can be used in the readMemoryFunction-callback) + * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default + * - Added example for doing an exception-callstack-walking in main.cpp + * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) + * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! + * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx + * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx + * Fixed Bug: Compiling with "/Wall" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx + * Fixed Bug: Now checking SymUseSymSrv + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx + * Fixed Bug: Support for recursive function calls + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx + * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx + * Fixed Bug: SymDia is number 7, not 9! + * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! + * Thanks to Teajay which reported the bug... + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx + * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory + * Thanks to Luiz Salamon which reported this "bug"... + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx + * 2009-04-10 v9 License slightly corrected ( replaced) + * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ + * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available + * 2010-04-15 v12 Added support for VS2010 RTM + * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx + * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed: + * http://stackwalker.codeplex.com/workitem/10511 + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2013, Jochen Kalmbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 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. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include "StackWalker.h" + +#include +#include +#include +#include +#pragma comment(lib, "version.lib") // for "VerQueryValue" +#pragma warning(disable : 4826) + + +// If VC7 and later, then use the shipped 'dbghelp.h'-file +#pragma pack(push, 8) +#if _MSC_VER >= 1300 +#include +#else +// inline the important dbghelp.h-declarations... +typedef enum +{ + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, + SymDia, + SymVirtual, + NumSymTypes +} SYM_TYPE; +typedef struct _IMAGEHLP_LINE64 +{ + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; +typedef struct _IMAGEHLP_MODULE64 +{ + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; +typedef struct _IMAGEHLP_SYMBOL64 +{ + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; +typedef enum +{ + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat +} ADDRESS_MODE; +typedef struct _tagADDRESS64 +{ + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64, *LPADDRESS64; +typedef struct _KDHELP64 +{ + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 Reserved[8]; +} KDHELP64, *PKDHELP64; +typedef struct _tagSTACKFRAME64 +{ + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64, *LPSTACKFRAME64; +typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead); +typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess, DWORD64 AddrBase); +typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); +typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, + HANDLE hThread, + LPADDRESS64 lpaddr); + +// clang-format off +#define SYMOPT_CASE_INSENSITIVE 0x00000001 +#define SYMOPT_UNDNAME 0x00000002 +#define SYMOPT_DEFERRED_LOADS 0x00000004 +#define SYMOPT_NO_CPP 0x00000008 +#define SYMOPT_LOAD_LINES 0x00000010 +#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 +#define SYMOPT_LOAD_ANYTHING 0x00000040 +#define SYMOPT_IGNORE_CVREC 0x00000080 +#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 +#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 +#define SYMOPT_EXACT_SYMBOLS 0x00000400 +#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 +#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 +#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 +#define SYMOPT_PUBLICS_ONLY 0x00004000 +#define SYMOPT_NO_PUBLICS 0x00008000 +#define SYMOPT_AUTO_PUBLICS 0x00010000 +#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 +#define SYMOPT_SECURE 0x00040000 +#define SYMOPT_DEBUG 0x80000000 +#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration +#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; +// clang-format on + +#endif // _MSC_VER < 1300 +#pragma pack(pop) + +// Some missing defines (for VC5/6): +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +// secure-CRT_functions are only available starting with VC8 +#if _MSC_VER < 1400 +#define strcpy_s(dst, len, src) strcpy(dst, src) +#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src) +#define strcat_s(dst, len, src) strcat(dst, src) +#define _snprintf_s _snprintf +#define _tcscat_s _tcscat +#endif + +static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) +{ + if (nMaxDestSize <= 0) + return; + strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE); + // INFO: _TRUNCATE will ensure that it is null-terminated; + // but with older compilers (<1400) it uses "strncpy" and this does not!) + szDest[nMaxDestSize - 1] = 0; +} // MyStrCpy + +// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') +#define USED_CONTEXT_FLAGS CONTEXT_FULL + +class StackWalkerInternal +{ +public: + StackWalkerInternal(StackWalker* parent, HANDLE hProcess) + { + m_parent = parent; + m_hDbhHelp = NULL; + pSC = NULL; + m_hProcess = hProcess; + m_szSymPath = NULL; + pSFTA = NULL; + pSGLFA = NULL; + pSGMB = NULL; + pSGMI = NULL; + pSGO = NULL; + pSGSFA = NULL; + pSI = NULL; + pSLM = NULL; + pSSO = NULL; + pSW = NULL; + pUDSN = NULL; + pSGSP = NULL; + } + ~StackWalkerInternal() + { + if (pSC != NULL) + pSC(m_hProcess); // SymCleanup + if (m_hDbhHelp != NULL) + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + m_parent = NULL; + if (m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + } + BOOL Init(LPCSTR szSymPath) + { + if (m_parent == NULL) + return FALSE; + // Dynamically load the Entry-Points for dbghelp.dll: + // First try to load the newest one from + TCHAR szTemp[4096]; + // But before we do this, we first check if the ".local" file exists + if (GetModuleFileName(NULL, szTemp, 4096) > 0) + { + _tcscat_s(szTemp, _T(".local")); + if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) + { + // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" + // Ok, first try the new path according to the architecture: +#ifdef _M_IX86 + if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_X64 + if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_IA64 + if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + // If still not found, try the old directories... + if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#if defined _M_X64 || defined _M_IA64 + // Still not found? Then try to load the (old) 64-Bit version: + if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + } + } + if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one + m_hDbhHelp = LoadLibrary(_T("dbghelp.dll")); + if (m_hDbhHelp == NULL) + return FALSE; + pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize"); + pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup"); + + pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64"); + pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions"); + pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions"); + + pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64"); + pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64"); + pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64"); + pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64"); + pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64"); + pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName"); + pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64"); + pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath"); + + if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL || + pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL || + pSLM == NULL) + { + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + pSC = NULL; + return FALSE; + } + + // SymInitialize + if (szSymPath != NULL) + m_szSymPath = _strdup(szSymPath); + if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) + this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); + + DWORD symOptions = this->pSGO(); // SymGetOptions + symOptions |= SYMOPT_LOAD_LINES; + symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; + //symOptions |= SYMOPT_NO_PROMPTS; + // SymSetOptions + symOptions = this->pSSO(symOptions); + + char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; + if (this->pSGSP != NULL) + { + if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) + this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); + } + char szUserName[1024] = {0}; + DWORD dwSize = 1024; + GetUserNameA(szUserName, &dwSize); + this->m_parent->OnSymInit(buf, symOptions, szUserName); + + return TRUE; + } + + StackWalker* m_parent; + + HMODULE m_hDbhHelp; + HANDLE m_hProcess; + LPSTR m_szSymPath; + +#pragma pack(push, 8) + typedef struct IMAGEHLP_MODULE64_V3 + { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name + // new elements: 07-Jun-2002 + CHAR LoadedPdbName[256]; // pdb file name + DWORD CVSig; // Signature of the CV record in the debug directories + CHAR CVData[MAX_PATH * 3]; // Contents of the CV record + DWORD PdbSig; // Signature of PDB + GUID PdbSig70; // Signature of PDB (VC 7 and up) + DWORD PdbAge; // DBI age of pdb + BOOL PdbUnmatched; // loaded an unmatched pdb + BOOL DbgUnmatched; // loaded an unmatched dbg + BOOL LineNumbers; // we have line number information + BOOL GlobalSymbols; // we have internal symbol information + BOOL TypeInfo; // we have type information + // new elements: 17-Dec-2003 + BOOL SourceIndexed; // pdb supports source server + BOOL Publics; // contains public symbols + }; + + typedef struct IMAGEHLP_MODULE64_V2 + { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name + }; +#pragma pack(pop) + + // SymCleanup() + typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess); + tSC pSC; + + // SymFunctionTableAccess64() + typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase); + tSFTA pSFTA; + + // SymGetLineFromAddr64() + typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess, + IN DWORD64 dwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_LINE64 Line); + tSGLFA pSGLFA; + + // SymGetModuleBase64() + typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr); + tSGMB pSGMB; + + // SymGetModuleInfo64() + typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess, + IN DWORD64 dwAddr, + OUT IMAGEHLP_MODULE64_V3* ModuleInfo); + tSGMI pSGMI; + + // SymGetOptions() + typedef DWORD(__stdcall* tSGO)(VOID); + tSGO pSGO; + + // SymGetSymFromAddr64() + typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess, + IN DWORD64 dwAddr, + OUT PDWORD64 pdwDisplacement, + OUT PIMAGEHLP_SYMBOL64 Symbol); + tSGSFA pSGSFA; + + // SymInitialize() + typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess); + tSI pSI; + + // SymLoadModule64() + typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD64 BaseOfDll, + IN DWORD SizeOfDll); + tSLM pSLM; + + // SymSetOptions() + typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions); + tSSO pSSO; + + // StackWalk64() + typedef BOOL(__stdcall* tSW)(DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + tSW pSW; + + // UnDecorateSymbolName() + typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName, + PSTR UnDecoratedName, + DWORD UndecoratedLength, + DWORD Flags); + tUDSN pUDSN; + + typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); + tSGSP pSGSP; + +private: +// **************************************** ToolHelp32 ************************ +#define MAX_MODULE_NAME32 255 +#define TH32CS_SNAPMODULE 0x00000008 +#pragma pack(push, 8) + typedef struct tagMODULEENTRY32 + { + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE* modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + char szModule[MAX_MODULE_NAME32 + 1]; + char szExePath[MAX_PATH]; + } MODULEENTRY32; + typedef MODULEENTRY32* PMODULEENTRY32; + typedef MODULEENTRY32* LPMODULEENTRY32; +#pragma pack(pop) + + BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) + { + // CreateToolhelp32Snapshot() + typedef HANDLE(__stdcall * tCT32S)(DWORD dwFlags, DWORD th32ProcessID); + // Module32First() + typedef BOOL(__stdcall * tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + // Module32Next() + typedef BOOL(__stdcall * tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + + // try both dlls... + const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")}; + HINSTANCE hToolhelp = NULL; + tCT32S pCT32S = NULL; + tM32F pM32F = NULL; + tM32N pM32N = NULL; + + HANDLE hSnap; + MODULEENTRY32 me; + me.dwSize = sizeof(me); + BOOL keepGoing; + size_t i; + + for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++) + { + hToolhelp = LoadLibrary(dllname[i]); + if (hToolhelp == NULL) + continue; + pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); + pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First"); + pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next"); + if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL)) + break; // found the functions! + FreeLibrary(hToolhelp); + hToolhelp = NULL; + } + + if (hToolhelp == NULL) + return FALSE; + + hSnap = pCT32S(TH32CS_SNAPMODULE, pid); + if (hSnap == (HANDLE)-1) + { + FreeLibrary(hToolhelp); + return FALSE; + } + + keepGoing = !!pM32F(hSnap, &me); + int cnt = 0; + while (keepGoing) + { + this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr, + me.modBaseSize); + cnt++; + keepGoing = !!pM32N(hSnap, &me); + } + CloseHandle(hSnap); + FreeLibrary(hToolhelp); + if (cnt <= 0) + return FALSE; + return TRUE; + } // GetModuleListTH32 + + // **************************************** PSAPI ************************ + typedef struct _MODULEINFO + { + LPVOID lpBaseOfDll; + DWORD SizeOfImage; + LPVOID EntryPoint; + } MODULEINFO, *LPMODULEINFO; + + BOOL GetModuleListPSAPI(HANDLE hProcess) + { + // EnumProcessModules() + typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, + LPDWORD lpcbNeeded); + // GetModuleFileNameEx() + typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, + DWORD nSize); + // GetModuleBaseName() + typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, + DWORD nSize); + // GetModuleInformation() + typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize); + + HINSTANCE hPsapi; + tEPM pEPM; + tGMFNE pGMFNE; + tGMBN pGMBN; + tGMI pGMI; + + DWORD i; + //ModuleEntry e; + DWORD cbNeeded; + MODULEINFO mi; + HMODULE* hMods = 0; + char* tt = NULL; + char* tt2 = NULL; + const SIZE_T TTBUFLEN = 8096; + int cnt = 0; + + hPsapi = LoadLibrary(_T("psapi.dll")); + if (hPsapi == NULL) + return FALSE; + + pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules"); + pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA"); + pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA"); + pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation"); + if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL)) + { + // we couldn't find all functions + FreeLibrary(hPsapi); + return FALSE; + } + + hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE))); + tt = (char*)malloc(sizeof(char) * TTBUFLEN); + tt2 = (char*)malloc(sizeof(char) * TTBUFLEN); + if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL)) + goto cleanup; + + if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded)) + { + //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); + goto cleanup; + } + + if (cbNeeded > TTBUFLEN) + { + //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); + goto cleanup; + } + + for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++) + { + // base address, size + pGMI(hProcess, hMods[i], &mi, sizeof(mi)); + // image file name + tt[0] = 0; + pGMFNE(hProcess, hMods[i], tt, TTBUFLEN); + // module name + tt2[0] = 0; + pGMBN(hProcess, hMods[i], tt2, TTBUFLEN); + + DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage); + if (dwRes != ERROR_SUCCESS) + this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); + cnt++; + } + + cleanup: + if (hPsapi != NULL) + FreeLibrary(hPsapi); + if (tt2 != NULL) + free(tt2); + if (tt != NULL) + free(tt); + if (hMods != NULL) + free(hMods); + + return cnt != 0; + } // GetModuleListPSAPI + + DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) + { + CHAR* szImg = _strdup(img); + CHAR* szMod = _strdup(mod); + DWORD result = ERROR_SUCCESS; + if ((szImg == NULL) || (szMod == NULL)) + result = ERROR_NOT_ENOUGH_MEMORY; + else + { + if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) + result = GetLastError(); + } + ULONGLONG fileVersion = 0; + if ((m_parent != NULL) && (szImg != NULL)) + { + // try to retrieve the file-version: + if ((this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) + { + VS_FIXEDFILEINFO* fInfo = NULL; + DWORD dwHandle; + DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); + if (dwSize > 0) + { + LPVOID vData = malloc(dwSize); + if (vData != NULL) + { + if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) + { + UINT len; + TCHAR szSubBlock[] = _T("\\"); + if (VerQueryValue(vData, szSubBlock, (LPVOID*)&fInfo, &len) == 0) + fInfo = NULL; + else + { + fileVersion = + ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); + } + } + free(vData); + } + } + } + + // Retrieve some additional-infos about the module + IMAGEHLP_MODULE64_V3 Module; + const char* szSymType = "-unknown-"; + if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) + { + switch (Module.SymType) + { + case SymNone: + szSymType = "-nosymbols-"; + break; + case SymCoff: // 1 + szSymType = "COFF"; + break; + case SymCv: // 2 + szSymType = "CV"; + break; + case SymPdb: // 3 + szSymType = "PDB"; + break; + case SymExport: // 4 + szSymType = "-exported-"; + break; + case SymDeferred: // 5 + szSymType = "-deferred-"; + break; + case SymSym: // 6 + szSymType = "SYM"; + break; + case 7: // SymDia: + szSymType = "DIA"; + break; + case 8: //SymVirtual: + szSymType = "Virtual"; + break; + } + } + LPCSTR pdbName = Module.LoadedImageName; + if (Module.LoadedPdbName[0] != 0) + pdbName = Module.LoadedPdbName; + this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, + fileVersion); + } + if (szImg != NULL) + free(szImg); + if (szMod != NULL) + free(szMod); + return result; + } + +public: + BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) + { + // first try toolhelp32 + if (GetModuleListTH32(hProcess, dwProcessId)) + return true; + // then try psapi + return GetModuleListPSAPI(hProcess); + } + + BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo) + { + memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); + if (this->pSGMI == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + // First try to use the larger ModuleInfo-Structure + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + void* pData = malloc( + 4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... + if (pData == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); + static bool s_useV3Version = true; + if (s_useV3Version) + { + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + free(pData); + return TRUE; + } + s_useV3Version = false; // to prevent unnecessary calls with the larger struct... + } + + // could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)... + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + free(pData); + return TRUE; + } + free(pData); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } +}; + +// ############################################################# +StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) +{ + this->m_options = OptionsAll; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} +StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) +{ + this->m_options = options; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + if (szSymPath != NULL) + { + this->m_szSymPath = _strdup(szSymPath); + this->m_options |= SymBuildPath; + } + else + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} + +StackWalker::~StackWalker() +{ + if (m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + if (this->m_sw != NULL) + delete this->m_sw; + this->m_sw = NULL; +} + +BOOL StackWalker::LoadModules() +{ + if (this->m_sw == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + if (m_modulesLoaded != FALSE) + return TRUE; + + // Build the sym-path: + char* szSymPath = NULL; + if ((this->m_options & SymBuildPath) != 0) + { + const size_t nSymPathLen = 4096; + szSymPath = (char*)malloc(nSymPathLen); + if (szSymPath == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + szSymPath[0] = 0; + // Now first add the (optional) provided sympath: + if (this->m_szSymPath != NULL) + { + strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + strcat_s(szSymPath, nSymPathLen, ".;"); + + const size_t nTempLen = 1024; + char szTemp[nTempLen]; + // Now add the current directory: + if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) + { + szTemp[nTempLen - 1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + // Now add the path for the main-module: + if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) + { + szTemp[nTempLen - 1] = 0; + for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p) + { + // locate the rightmost path separator + if ((*p == '\\') || (*p == '/') || (*p == ':')) + { + *p = 0; + break; + } + } // for (search for path separator...) + if (strlen(szTemp) > 0) + { + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + } + if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen - 1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen - 1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) + { + szTemp[nTempLen - 1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + // also add the "system32"-directory: + strcat_s(szTemp, nTempLen, "\\system32"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + if ((this->m_options & SymUseSymSrv) != 0) + { + if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) + { + szTemp[nTempLen - 1] = 0; + strcat_s(szSymPath, nSymPathLen, "SRV*"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, "\\websymbols"); + strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); + } + else + strcat_s(szSymPath, nSymPathLen, + "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); + } + } // if SymBuildPath + + // First Init the whole stuff... + BOOL bRet = this->m_sw->Init(szSymPath); + if (szSymPath != NULL) + free(szSymPath); + szSymPath = NULL; + if (bRet == FALSE) + { + this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); + if (bRet != FALSE) + m_modulesLoaded = TRUE; + return bRet; +} + +// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction +// This has to be done due to a problem with the "hProcess"-parameter in x64... +// Because this class is in no case multi-threading-enabled (because of the limitations +// of dbghelp.dll) it is "safe" to use a static-variable +static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; +static LPVOID s_readMemoryFunction_UserData = NULL; + +BOOL StackWalker::ShowCallstack(HANDLE hThread, + const CONTEXT* context, + PReadProcessMemoryRoutine readMemoryFunction, + LPVOID pUserData) +{ + CONTEXT c; + CallstackEntry csEntry; + IMAGEHLP_SYMBOL64* pSym = NULL; + StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; + IMAGEHLP_LINE64 Line; + int frameNum; + bool bLastEntryCalled = true; + int curRecursionCount = 0; + + if (m_modulesLoaded == FALSE) + this->LoadModules(); // ignore the result... + + if (this->m_sw->m_hDbhHelp == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + s_readMemoryFunction = readMemoryFunction; + s_readMemoryFunction_UserData = pUserData; + + if (context == NULL) + { + // If no context is provided, capture the context + // See: https://stackwalker.codeplex.com/discussions/446958 +#if _WIN32_WINNT <= 0x0501 + // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available! + if (hThread == GetCurrentThread()) +#else + if (GetThreadId(hThread) == GetCurrentThreadId()) +#endif + { + GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); + } + else + { + SuspendThread(hThread); + memset(&c, 0, sizeof(CONTEXT)); + c.ContextFlags = USED_CONTEXT_FLAGS; + + // TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture... + // This does only work if we are x64 and the target process is x64 or x86; + // It cannot work, if this process is x64 and the target process is x64... this is not supported... + // See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html + if (GetThreadContext(hThread, &c) == FALSE) + { + ResumeThread(hThread); + return FALSE; + } + } + } + else + c = *context; + + // init STACKFRAME for first call + STACKFRAME64 s; // in/out stackframe + memset(&s, 0, sizeof(s)); + DWORD imageType; +#ifdef _M_IX86 + // normally, call ImageNtHeader() and use machine info from PE header + imageType = IMAGE_FILE_MACHINE_I386; + s.AddrPC.Offset = c.Eip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Ebp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Esp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_X64 + imageType = IMAGE_FILE_MACHINE_AMD64; + s.AddrPC.Offset = c.Rip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Rsp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Rsp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_IA64 + imageType = IMAGE_FILE_MACHINE_IA64; + s.AddrPC.Offset = c.StIIP; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.IntSp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrBStore.Offset = c.RsBSP; + s.AddrBStore.Mode = AddrModeFlat; + s.AddrStack.Offset = c.IntSp; + s.AddrStack.Mode = AddrModeFlat; +#else +#error "Platform not supported!" +#endif + + pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + if (!pSym) + goto cleanup; // not enough memory... + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; + + memset(&Line, 0, sizeof(Line)); + Line.SizeOfStruct = sizeof(Line); + + memset(&Module, 0, sizeof(Module)); + Module.SizeOfStruct = sizeof(Module); + + for (frameNum = 0;; ++frameNum) + { + // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) + // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can + // assume that either you are done, or that the stack is so hosed that the next + // deeper frame could not be found. + // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386! + if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, + this->m_sw->pSFTA, this->m_sw->pSGMB, NULL)) + { + // INFO: "StackWalk64" does not set "GetLastError"... + this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); + break; + } + + csEntry.offset = s.AddrPC.Offset; + csEntry.name[0] = 0; + csEntry.undName[0] = 0; + csEntry.undFullName[0] = 0; + csEntry.offsetFromSmybol = 0; + csEntry.offsetFromLine = 0; + csEntry.lineFileName[0] = 0; + csEntry.lineNumber = 0; + csEntry.loadedImageName[0] = 0; + csEntry.moduleName[0] = 0; + if (s.AddrPC.Offset == s.AddrReturn.Offset) + { + if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount)) + { + this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); + break; + } + curRecursionCount++; + } + else + curRecursionCount = 0; + if (s.AddrPC.Offset != 0) + { + // we seem to have a valid PC + // show procedure info (SymGetSymFromAddr64()) + if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), + pSym) != FALSE) + { + MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); + // UnDecorateSymbolName() + this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY); + this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE); + } + else + { + this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); + } + + // show line number info, NT5.0-method (SymGetLineFromAddr64()) + if (this->m_sw->pSGLFA != NULL) + { // yes, we have SymGetLineFromAddr64() + if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), + &Line) != FALSE) + { + csEntry.lineNumber = Line.LineNumber; + MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); + } + else + { + this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); + } + } // yes, we have SymGetLineFromAddr64() + + // show module info (SymGetModuleInfo64()) + if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module) != FALSE) + { // got module info OK + switch (Module.SymType) + { + case SymNone: + csEntry.symTypeString = "-nosymbols-"; + break; + case SymCoff: + csEntry.symTypeString = "COFF"; + break; + case SymCv: + csEntry.symTypeString = "CV"; + break; + case SymPdb: + csEntry.symTypeString = "PDB"; + break; + case SymExport: + csEntry.symTypeString = "-exported-"; + break; + case SymDeferred: + csEntry.symTypeString = "-deferred-"; + break; + case SymSym: + csEntry.symTypeString = "SYM"; + break; +#if API_VERSION_NUMBER >= 9 + case SymDia: + csEntry.symTypeString = "DIA"; + break; +#endif + case 8: //SymVirtual: + csEntry.symTypeString = "Virtual"; + break; + default: + //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType ); + csEntry.symTypeString = NULL; + break; + } + + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); + csEntry.baseOfImage = Module.BaseOfImage; + MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); + } // got module info OK + else + { + this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); + } + } // we seem to have a valid PC + + CallstackEntryType et = nextEntry; + if (frameNum == 0) + et = firstEntry; + bLastEntryCalled = false; + this->OnCallstackEntry(et, csEntry); + + if (s.AddrReturn.Offset == 0) + { + bLastEntryCalled = true; + this->OnCallstackEntry(lastEntry, csEntry); + SetLastError(ERROR_SUCCESS); + break; + } + } // for ( frameNum ) + +cleanup: + if (pSym) + free(pSym); + + if (bLastEntryCalled == false) + this->OnCallstackEntry(lastEntry, csEntry); + + if (context == NULL) + ResumeThread(hThread); + + return TRUE; +} + +BOOL StackWalker::ShowObject(LPVOID pObject) +{ + // Load modules if not done yet + if (m_modulesLoaded == FALSE) + this->LoadModules(); // ignore the result... + + // Verify that the DebugHelp.dll was actually found + if (this->m_sw->m_hDbhHelp == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + // SymGetSymFromAddr64() is required + if (this->m_sw->pSGSFA == NULL) + return FALSE; + + // Show object info (SymGetSymFromAddr64()) + DWORD64 dwAddress = DWORD64(pObject); + DWORD64 dwDisplacement = 0; + IMAGEHLP_SYMBOL64* pSym = + (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; + if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE) + { + this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress); + return FALSE; + } + // Object name output + this->OnOutput(pSym->Name); + + free(pSym); + return TRUE; +}; + +BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead) +{ + if (s_readMemoryFunction == NULL) + { + SIZE_T st; + BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st); + *lpNumberOfBytesRead = (DWORD)st; + //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); + return bRet; + } + else + { + return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, + s_readMemoryFunction_UserData); + } +} + +void StackWalker::OnLoadModule(LPCSTR img, + LPCSTR mod, + DWORD64 baseAddr, + DWORD size, + DWORD result, + LPCSTR symType, + LPCSTR pdbName, + ULONGLONG fileVersion) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + size_t maxLen = STACKWALK_MAX_NAMELEN; +#if _MSC_VER >= 1400 + maxLen = _TRUNCATE; +#endif + if (fileVersion == 0) + _snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", + img, mod, (LPVOID)baseAddr, size, result, symType, pdbName); + else + { + DWORD v4 = (DWORD)(fileVersion & 0xFFFF); + DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF); + DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF); + DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF); + _snprintf_s( + buffer, maxLen, + "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", + img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); + } + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated + OnOutput(buffer); +} + +void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + size_t maxLen = STACKWALK_MAX_NAMELEN; +#if _MSC_VER >= 1400 + maxLen = _TRUNCATE; +#endif + if ((eType != lastEntry) && (entry.offset != 0)) + { + if (entry.name[0] == 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); + if (entry.undName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); + if (entry.undFullName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); + if (entry.lineFileName[0] == 0) + { + MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); + if (entry.moduleName[0] == 0) + MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); + _snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName, + entry.lineFileName, entry.name); + } + else + _snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, + entry.name); + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; + OnOutput(buffer); + } +} + +void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + size_t maxLen = STACKWALK_MAX_NAMELEN; +#if _MSC_VER >= 1400 + maxLen = _TRUNCATE; +#endif + _snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, + (LPVOID)addr); + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; + OnOutput(buffer); +} + +void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + size_t maxLen = STACKWALK_MAX_NAMELEN; +#if _MSC_VER >= 1400 + maxLen = _TRUNCATE; +#endif + _snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", + szSearchPath, symOptions, szUserName); + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; + OnOutput(buffer); + // Also display the OS-version +#if _MSC_VER <= 1200 + OSVERSIONINFOA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); + ver.dwOSVersionInfoSize = sizeof(ver); + if (GetVersionExA(&ver) != FALSE) + { + _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, + ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; + OnOutput(buffer); + } +#else + OSVERSIONINFOEXA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); + ver.dwOSVersionInfoSize = sizeof(ver); +#if _MSC_VER >= 1900 +#pragma warning(push) +#pragma warning(disable : 4996) +#endif + if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE) + { + _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, + ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, + ver.wProductType); + buffer[STACKWALK_MAX_NAMELEN - 1] = 0; + OnOutput(buffer); + } +#if _MSC_VER >= 1900 +#pragma warning(pop) +#endif +#endif +} + +void StackWalker::OnOutput(LPCSTR buffer) +{ + OutputDebugStringA(buffer); +} diff --git a/src/3rdparty/stackwalker/stackwalker.h b/src/3rdparty/stackwalker/stackwalker.h new file mode 100644 index 00000000..0a004d96 --- /dev/null +++ b/src/3rdparty/stackwalker/stackwalker.h @@ -0,0 +1,255 @@ +#ifndef __STACKWALKER_H__ +#define __STACKWALKER_H__ + +#if defined(_MSC_VER) + +/********************************************************************** + * + * StackWalker.h + * + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2009, Jochen Kalmbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 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. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * **********************************************************************/ +// #pragma once is supported starting with _MSC_VER 1000, +// so we need not to check the version (because we only support _MSC_VER >= 1100)! +#pragma once + +#include + +#if _MSC_VER >= 1900 +#pragma warning(disable : 4091) +#endif + +// special defines for VC5/6 (if no actual PSDK is installed): +#if _MSC_VER < 1300 +typedef unsigned __int64 DWORD64, *PDWORD64; +#if defined(_WIN64) +typedef unsigned __int64 SIZE_T, *PSIZE_T; +#else +typedef unsigned long SIZE_T, *PSIZE_T; +#endif +#endif // _MSC_VER < 1300 + +class StackWalkerInternal; // forward +class StackWalker +{ +public: + typedef enum StackWalkOptions + { + // No addition info will be retrieved + // (only the address is available) + RetrieveNone = 0, + + // Try to get the symbol-name + RetrieveSymbol = 1, + + // Try to get the line for this symbol + RetrieveLine = 2, + + // Try to retrieve the module-infos + RetrieveModuleInfo = 4, + + // Also retrieve the version for the DLL/EXE + RetrieveFileVersion = 8, + + // Contains all the above + RetrieveVerbose = 0xF, + + // Generate a "good" symbol-search-path + SymBuildPath = 0x10, + + // Also use the public Microsoft-Symbol-Server + SymUseSymSrv = 0x20, + + // Contains all the above "Sym"-options + SymAll = 0x30, + + // Contains all options (default) + OptionsAll = 0x3F + } StackWalkOptions; + + StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags + LPCSTR szSymPath = NULL, + DWORD dwProcessId = GetCurrentProcessId(), + HANDLE hProcess = GetCurrentProcess()); + StackWalker(DWORD dwProcessId, HANDLE hProcess); + virtual ~StackWalker(); + + typedef BOOL(__stdcall* PReadProcessMemoryRoutine)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead, + LPVOID pUserData // optional data, which was passed in "ShowCallstack" + ); + + BOOL LoadModules(); + + BOOL ShowCallstack( + HANDLE hThread = GetCurrentThread(), + const CONTEXT* context = NULL, + PReadProcessMemoryRoutine readMemoryFunction = NULL, + LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback + ); + + BOOL ShowObject(LPVOID pObject); + +#if _MSC_VER >= 1300 + // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" + // in older compilers in order to use it... starting with VC7 we can declare it as "protected" +protected: +#endif + enum + { + STACKWALK_MAX_NAMELEN = 1024 + }; // max name length for found symbols + +protected: + // Entry for each Callstack-Entry + typedef struct CallstackEntry + { + DWORD64 offset; // if 0, we have no valid entry + CHAR name[STACKWALK_MAX_NAMELEN]; + CHAR undName[STACKWALK_MAX_NAMELEN]; + CHAR undFullName[STACKWALK_MAX_NAMELEN]; + DWORD64 offsetFromSmybol; + DWORD offsetFromLine; + DWORD lineNumber; + CHAR lineFileName[STACKWALK_MAX_NAMELEN]; + DWORD symType; + LPCSTR symTypeString; + CHAR moduleName[STACKWALK_MAX_NAMELEN]; + DWORD64 baseOfImage; + CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; + } CallstackEntry; + + typedef enum CallstackEntryType + { + firstEntry, + nextEntry, + lastEntry + } CallstackEntryType; + + virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); + virtual void OnLoadModule(LPCSTR img, + LPCSTR mod, + DWORD64 baseAddr, + DWORD size, + DWORD result, + LPCSTR symType, + LPCSTR pdbName, + ULONGLONG fileVersion); + virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry); + virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); + virtual void OnOutput(LPCSTR szText); + + StackWalkerInternal* m_sw; + HANDLE m_hProcess; + DWORD m_dwProcessId; + BOOL m_modulesLoaded; + LPSTR m_szSymPath; + + int m_options; + int m_MaxRecursionCount; + + static BOOL __stdcall myReadProcMem(HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead); + + friend StackWalkerInternal; +}; // class StackWalker + +// The "ugly" assembler-implementation is needed for systems before XP +// If you have a new PSDK and you only compile for XP and later, then you can use +// the "RtlCaptureContext" +// Currently there is no define which determines the PSDK-Version... +// So we just use the compiler-version (and assumes that the PSDK is +// the one which was installed by the VS-IDE) + +// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... +// But I currently use it in x64/IA64 environments... +//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) + +#if defined(_M_IX86) +#ifdef CURRENT_THREAD_VIA_EXCEPTION +// TODO: The following is not a "good" implementation, +// because the callstack is only valid in the "__except" block... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do \ + { \ + memset(&c, 0, sizeof(CONTEXT)); \ + EXCEPTION_POINTERS* pExp = NULL; \ + __try \ + { \ + throw 0; \ + } \ + __except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \ + : EXCEPTION_EXECUTE_HANDLER)) \ + { \ + } \ + if (pExp != NULL) \ + memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + } while (0); +#else +// clang-format off +// The following should be enough for walking the callstack... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do \ + { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + __asm call x \ + __asm x: pop eax \ + __asm mov c.Eip, eax \ + __asm mov c.Ebp, ebp \ + __asm mov c.Esp, esp \ + } while (0) +// clang-format on +#endif + +#else + +// The following is defined for x86 (XP and higher), x64 and IA64: +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do \ + { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + RtlCaptureContext(&c); \ + } while (0); +#endif + +#endif //defined(_MSC_VER) + +#endif // __STACKWALKER_H__ diff --git a/src/3rdparty/stackwalker/stackwalker.pro b/src/3rdparty/stackwalker/stackwalker.pro new file mode 100644 index 00000000..19e68949 --- /dev/null +++ b/src/3rdparty/stackwalker/stackwalker.pro @@ -0,0 +1,26 @@ +requires(windows:msvc) + +TEMPLATE = lib +TARGET = stackwalker + +load(am-config) + +CONFIG += \ + static \ + hide_symbols \ + warn_off \ + installed + +MODULE_INCLUDEPATH += $$PWD + +load(qt_helper_lib) + +QMAKE_CFLAGS += /D_CRT_SECURE_NO_WARNINGS + +INCLUDEPATH += $$PWD + +HEADERS += \ + stackwalker.h + +SOURCES += \ + stackwalker.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..da54e2f1 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,57 @@ + +qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/common-lib/configure.cmake") +qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/package-lib/configure.cmake") +qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/window-lib/configure.cmake") + +add_subdirectory(3rdparty) +add_subdirectory(common-lib) +add_subdirectory(application-lib) +add_subdirectory(package-lib) + +if(QT_FEATURE_installer) + add_subdirectory(crypto-lib) +endif() + +# if(NOT QT_FEATURE_tools_only) + add_subdirectory(plugin-interfaces) + add_subdirectory(notification-lib) + add_subdirectory(monitor-lib) + add_subdirectory(shared-main-lib) + add_subdirectory(intent-server-lib) + add_subdirectory(intent-client-lib) + add_subdirectory(manager-lib) + add_subdirectory(window-lib) + + if(TARGET Qt::DBus AND QT_FEATURE_external_dbus_interfaces) + add_subdirectory(dbus-lib) + endif() + + add_subdirectory(main-lib) + add_subdirectory(tools/appman) + add_subdirectory(tools/testrunner) + + if(TARGET Qt::DBus) + add_subdirectory(launcher-lib) + endif() + + # This tool links against everything to extract the Qml type information + if (QT_FEATURE_installer AND TARGET Qt::DBus) + add_subdirectory(tools/dumpqmltypes) + endif() + + if (TARGET Qt::DBus AND QT_FEATURE_multi_process) + add_subdirectory(tools/launcher-qml) + endif() +# endif() + +if(NOT CMAKE_CROSSCOMPILING OR QT_FEATURE_tools_only) + if (QT_FEATURE_installer) + add_subdirectory(tools/packager) + endif() + + add_subdirectory(tools/uploader) +endif() + +if(TARGET Qt::DBus) + add_subdirectory(tools/controller) +endif() diff --git a/src/application-lib/CMakeLists.txt b/src/application-lib/CMakeLists.txt new file mode 100644 index 00000000..d1a648e1 --- /dev/null +++ b/src/application-lib/CMakeLists.txt @@ -0,0 +1,29 @@ +# Generated from application-lib.pro. + +##################################################################### +## AppManApplication Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManApplicationPrivate + CONFIG_MODULE_NAME appman_application + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + applicationinfo.cpp applicationinfo.h + applicationinterface.cpp applicationinterface.h + installationreport.cpp installationreport.h + intentinfo.cpp intentinfo.h + packagedatabase.cpp packagedatabase.h + packageinfo.cpp packageinfo.h + packagescanner.h + yamlpackagescanner.cpp yamlpackagescanner.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Network +) diff --git a/src/common-lib/CMakeLists.txt b/src/common-lib/CMakeLists.txt new file mode 100644 index 00000000..75d795d5 --- /dev/null +++ b/src/common-lib/CMakeLists.txt @@ -0,0 +1,77 @@ +# Generated from common-lib.pro. + +##################################################################### +## AppManCommon Module: +##################################################################### + +qt_find_package(WrapLibYaml PROVIDED_TARGETS WrapLibYaml::WrapLibYaml) + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManCommonPrivate + CONFIG_MODULE_NAME appman_common + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + configcache.cpp configcache.h configcache_p.h + crashhandler.cpp crashhandler.h + dbus-utilities.cpp + error.h + exception.cpp exception.h + global.h + logging.cpp logging.h + processtitle.cpp processtitle.h + qml-utilities.cpp qml-utilities.h + qtyaml.cpp qtyaml.h + startuptimer.cpp startuptimer.h + unixsignalhandler.cpp unixsignalhandler.h + utilities.cpp utilities.h + PUBLIC_LIBRARIES + Qt::Concurrent + Qt::Core + Qt::CorePrivate + Qt::Network + Qt::Qml + Qt::QmlPrivate +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION TARGET Qt::GeniviExtras + DEFINES + AM_GENIVIEXTRAS_LAZY_INIT + PUBLIC_LIBRARIES + Qt::GeniviExtras +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION TARGET Qt::DBus + SOURCES + dbus-utilities.h + PUBLIC_LIBRARIES + Qt::DBus +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION LINUX + PUBLIC_LIBRARIES + dl +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION QT_FEATURE_libbacktrace + LIBRARIES + Qt::BundledBacktrace +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION QT_FEATURE_stackwalker + LIBRARIES + Qt::BundledStackwalker +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION QT_FEATURE_system_libyaml + LIBRARIES + WrapLibYaml::WrapLibYaml +) + +qt_internal_extend_target(AppManCommonPrivate CONDITION NOT QT_FEATURE_system_libyaml + LIBRARIES + Qt::BundledLibYaml +) diff --git a/src/common-lib/common-lib.pro b/src/common-lib/common-lib.pro index 4b1ffda6..d9efdd85 100644 --- a/src/common-lib/common-lib.pro +++ b/src/common-lib/common-lib.pro @@ -11,14 +11,12 @@ qtHaveModule(qml):QT *= qml qml-private linux:LIBS += -ldl -versionAtLeast(QT.geniviextras.VERSION, 1.1.0) { - DEFINES += AM_GENIVIEXTRAS_LAZY_INIT -} +qtHaveModule(geniviextras):DEFINES *= AM_GENIVIEXTRAS_LAZY_INIT CONFIG *= static internal_module CONFIG -= create_cmake -include($$SOURCE_DIR/3rdparty/libyaml.pri) +include($$PWD/../../3rdparty/libyaml.pri) contains(DEFINES, "AM_USE_LIBBACKTRACE"):include($$SOURCE_DIR/3rdparty/libbacktrace.pri) contains(DEFINES, "AM_USE_STACKWALKER"):include($$SOURCE_DIR/3rdparty/stackwalker.pri) diff --git a/src/common-lib/configure.cmake b/src/common-lib/configure.cmake new file mode 100644 index 00000000..e20cf5f0 --- /dev/null +++ b/src/common-lib/configure.cmake @@ -0,0 +1,74 @@ +#### Inputs + +set(INPUT_libyaml "undefined" CACHE STRING "") +set_property(CACHE INPUT_libyaml PROPERTY STRINGS undefined qt system) + + +#### Libraries + +qt_find_package(WrapLibYaml PROVIDED_TARGETS WrapLibYaml::WrapLibYaml MODULE_NAME appman_common QMAKE_LIB yaml) + + +#### Tests + + +#### Features + +qt_feature("system-libyaml" PRIVATE + LABEL "Using system libyaml" + CONDITION WrapLibYaml_FOUND + ENABLE INPUT_libyaml STREQUAL 'system' + DISABLE INPUT_libyaml STREQUAL 'qt' +) + +qt_feature("multi-process" PUBLIC + LABEL "Multi-process mode" + CONDITION TARGET Qt::DBus AND TARGET Qt::WaylandCompositor AND LINUX + ENABLE INPUT_force_mode STREQUAL 'multi' + DISABLE INPUT_force_mode STREQUAL 'single' +) +qt_feature_definition("multi-process" "AM_MULTI_PROCESS") + +qt_feature("installer" PRIVATE + LABEL "Enable the installer component" + CONDITION QT_FEATURE_ssl + DISABLE INPUT_installer STREQUAL 'no' +) +qt_feature_definition("installer" "AM_DISABLE_INSTALLER" NEGATE) + +qt_feature("external-dbus-interfaces" PRIVATE + LABEL "Enable external DBus interfaces" + CONDITION NOT INPUT_external_dbus_interfaces STREQUAL 'no' AND TARGET Qt::DBus +) +qt_feature_definition("external-dbus-interfaces" "AM_DISABLE_EXTERNAL_DBUS_INTERFACES" NEGATE) + +qt_feature("tools-only" PRIVATE + LABEL "Tools only build" + CONDITION INPUT_tools_only STREQUAL 'yes' +) + +qt_feature("libbacktrace" PRIVATE + LABEL "Enable support for libbacktrace" + CONDITION LINUX AND ( ( INPUT_libbacktrace STREQUAL 'yes' ) OR ( ( CMAKE_BUILD_TYPE STREQUAL "Debug" ) AND ( NOT INPUT_libbacktrace STREQUAL 'no' ) ) ) + EMIT_IF LINUX +) +qt_feature_definition("libbacktrace" "AM_USE_LIBBACKTRACE") + +qt_feature("stackwalker" PRIVATE + LABEL "Enable support for StackWalker" + CONDITION WIN32 AND ( ( INPUT_stackwalker STREQUAL 'yes' ) OR ( ( CMAKE_BUILD_TYPE STREQUAL "Debug") AND (NOT INPUT_stackwalker STREQUAL 'no' ) ) ) + EMIT_IF WIN32 +) +qt_feature_definition("stackwalker" "AM_USE_STACKWALKER") + +qt_configure_add_summary_section(NAME "Qt Application Manager") +qt_configure_add_summary_entry(ARGS "system-libyaml") +qt_configure_add_summary_entry(ARGS "multi-process") +qt_configure_add_summary_entry(ARGS "installer") +qt_configure_add_summary_entry(ARGS "external-dbus-interfaces") +qt_configure_add_summary_entry(ARGS "tools-only") +qt_configure_add_summary_entry(ARGS "libbacktrace") +qt_configure_add_summary_entry(ARGS "stackwalker") +qt_configure_end_summary_section() # end of "Qt ApplicationManger" section + +qt_extra_definition("AM_VERSION" "\"${PROJECT_VERSION}\"" PUBLIC) diff --git a/src/common-lib/crashhandler.cpp b/src/common-lib/crashhandler.cpp index 128616c8..bde599fb 100644 --- a/src/common-lib/crashhandler.cpp +++ b/src/common-lib/crashhandler.cpp @@ -30,6 +30,7 @@ ****************************************************************************/ #include +#include #if defined(QT_QML_LIB) # include @@ -57,6 +58,9 @@ # define STDERR_FILENO _fileno(stderr) # endif # define write(a, b, c) _write(a, b, static_cast(c)) +# if defined(Q_CC_MINGW) +# include +# endif #endif QT_BEGIN_NAMESPACE_AM @@ -117,7 +121,6 @@ static struct InitBacktrace # pragma warning(pop) # elif defined(Q_OS_WINDOWS) && defined(Q_CC_MINGW) -# include // this will make it run before all other static constructor functions static void initBacktrace() __attribute__((constructor(101))); @@ -656,7 +659,9 @@ static void logCrashInfo(LogToDestination logTo, const char *why, int stackFrame // SDK used to compile this code typedef HRESULT(WINAPI* GetThreadDescriptionType)(HANDLE hThread, PWSTR *description); if (auto GetThreadDescriptionFunc = reinterpret_cast( - GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetThreadDescription"))) { + reinterpret_cast( + GetProcAddress(::GetModuleHandle(L"kernel32.dll"), + "GetThreadDescription")))) { WCHAR *desc = nullptr; if (SUCCEEDED(GetThreadDescriptionFunc(GetCurrentThread(), &desc))) wcscpy_s(threadName, sizeof(threadName) / sizeof(*threadName), desc); diff --git a/src/common-lib/global.h b/src/common-lib/global.h index 62ff6989..8b5afe29 100644 --- a/src/common-lib/global.h +++ b/src/common-lib/global.h @@ -30,7 +30,8 @@ ****************************************************************************/ #pragma once -#include +#include +#include #define QT_BEGIN_NAMESPACE_AM namespace QtAM { #define QT_END_NAMESPACE_AM } diff --git a/src/common-lib/qt_cmdline.cmake b/src/common-lib/qt_cmdline.cmake new file mode 100644 index 00000000..f3641516 --- /dev/null +++ b/src/common-lib/qt_cmdline.cmake @@ -0,0 +1,8 @@ +qt_commandline_option(force-single-process TYPE enum NAME force_mode VALUE single) +qt_commandline_option(force-multi-process TYPE enum NAME force_mode VALUE multi) +qt_commandline_option(installer TYPE boolean) +qt_commandline_option(external-dbus-interfaces TYPE boolean) +qt_commandline_option(tools-only TYPE boolean) +qt_commandline_option(libbacktrace TYPE boolean) +qt_commandline_option(stackwalker TYPE boolean) +qt_commandline_option(libyaml TYPE enum VALUES qt system) diff --git a/src/crypto-lib/CMakeLists.txt b/src/crypto-lib/CMakeLists.txt new file mode 100644 index 00000000..ac4c8a4e --- /dev/null +++ b/src/crypto-lib/CMakeLists.txt @@ -0,0 +1,50 @@ +# Generated from crypto-lib.pro. + +##################################################################### +## AppManCrypto Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManCryptoPrivate + CONFIG_MODULE_NAME appman_crypto + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + cryptography.cpp cryptography.h + signature.cpp signature.h signature_p.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core +) + + +qt_internal_extend_target(AppManCryptoPrivate CONDITION WIN32 + SOURCES + signature_win.cpp + PUBLIC_LIBRARIES + advapi32 + crypt32 +) + +qt_internal_extend_target(AppManCryptoPrivate CONDITION MACOS + SOURCES + signature_macos.cpp + PUBLIC_LIBRARIES + ${FWCoreFoundation} + ${FWSecurity} + Qt::CorePrivate +) + +qt_internal_extend_target(AppManCryptoPrivate CONDITION (UNIX AND NOT MACOS) + SOURCES + libcryptofunction.cpp libcryptofunction.h + signature_openssl.cpp + DEFINES + AM_USE_LIBCRYPTO + PUBLIC_LIBRARIES + Qt::Network +) diff --git a/src/dbus-lib/CMakeLists.txt b/src/dbus-lib/CMakeLists.txt new file mode 100644 index 00000000..8c371423 --- /dev/null +++ b/src/dbus-lib/CMakeLists.txt @@ -0,0 +1,66 @@ +# Generated from dbus-lib.pro. + +##################################################################### +## AppManDBus Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManDBusPrivate + CONFIG_MODULE_NAME appman_dbus + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + abstractdbuscontextadaptor.cpp abstractdbuscontextadaptor.h + applicationmanagerdbuscontextadaptor.cpp applicationmanagerdbuscontextadaptor.h + dbusdaemon.cpp dbusdaemon.h + dbuspolicy.cpp dbuspolicy.h + notificationmanagerdbuscontextadaptor.cpp notificationmanagerdbuscontextadaptor.h + windowmanagerdbuscontextadaptor.cpp windowmanagerdbuscontextadaptor.h + LIBRARIES + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate + Qt::AppManWindowPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::DBus +) + +#### Keys ignored in scope 1:.:.:dbus-lib.pro:: +# ADAPTORS_XML = "io.qt.applicationmanager.xml" "io.qt.windowmanager.xml" "org.freedesktop.notifications.xml" +# MODULE = "appman_dbus" +# OTHER_FILES = "io.qt.packagemanager.xml" "io.qt.applicationmanager.applicationinterface.xml" "io.qt.applicationmanager.runtimeinterface.xml" "io.qt.applicationmanager.intentinterface.xml" "io.qt.applicationmanager.xml" "io.qt.windowmanager.xml" "org.freedesktop.notifications.xml" +# QMAKE_EXTRA_TARGETS = "recreate-dbus-xml" "recreate-applicationmanager-dbus-xml" "recreate-packagemanager-dbus-xml" "recreate-windowmanager-dbus-xml" +# TEMPLATE = "lib" +# recreate-applicationmanager-dbus-xml.CONFIG = "phony" +# recreate-applicationmanager-dbus-xml.commands = "$$QDBUSCPP2XML" "-a" "$$PWD/../manager-lib/applicationmanager.h" "-o" "$$PWD/io.qt.applicationmanager.xml" +# recreate-dbus-xml.depends = "recreate-applicationmanager-dbus-xml" "recreate-applicationinstaller-dbus-xml" "recreate-windowmanager-dbus-xml" +# recreate-packagemanager-dbus-xml.CONFIG = "phony" +# recreate-packagemanager-dbus-xml.commands = "$$QDBUSCPP2XML" "-a" "$$PWD/../manager-lib/packagemanager.h" "-o" "$$PWD/io.qt.packagemanager.xml" +# recreate-windowmanager-dbus-xml.CONFIG = "phony" +# recreate-windowmanager-dbus-xml.commands = "$$QDBUSCPP2XML" "-a" "$$PWD/../manager/windowmanager.h" "-o" "$$PWD/io.qt.windowmanager.xml" + + +qtam_internal_add_dbus_adaptor(AppManDBusPrivate + DBUS_ADAPTOR_SOURCES + io.qt.applicationmanager.xml + io.qt.windowmanager.xml + org.freedesktop.notifications.xml + DBUS_ADAPTOR_FLAGS + -i dbus-utilities.h +) + +if (QT_FEATURE_installer) + qtam_internal_add_dbus_adaptor(AppManDBusPrivate + DBUS_ADAPTOR_SOURCES + io.qt.packagemanager.xml + DBUS_ADAPTOR_FLAGS + -i dbus-utilities.h + ) + qt_internal_extend_target(AppManDBusPrivate + SOURCES + packagemanagerdbuscontextadaptor.cpp packagemanagerdbuscontextadaptor.h + ) +endif() diff --git a/src/intent-client-lib/CMakeLists.txt b/src/intent-client-lib/CMakeLists.txt new file mode 100644 index 00000000..fc932c17 --- /dev/null +++ b/src/intent-client-lib/CMakeLists.txt @@ -0,0 +1,26 @@ +# Generated from intent-client-lib.pro. + +##################################################################### +## AppManIntentClient Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManIntentClientPrivate + CONFIG_MODULE_NAME appman_intent_client + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + intentclient.cpp intentclient.h + intentclientrequest.cpp intentclientrequest.h + intentclientsysteminterface.cpp intentclientsysteminterface.h + intenthandler.cpp intenthandler.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Network + Qt::Qml +) diff --git a/src/intent-server-lib/CMakeLists.txt b/src/intent-server-lib/CMakeLists.txt new file mode 100644 index 00000000..30a6b020 --- /dev/null +++ b/src/intent-server-lib/CMakeLists.txt @@ -0,0 +1,27 @@ +# Generated from intent-server-lib.pro. + +##################################################################### +## AppManIntentServer Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManIntentServerPrivate + CONFIG_MODULE_NAME appman_intent_server + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + intent.cpp intent.h + intentmodel.cpp intentmodel.h + intentserver.cpp intentserver.h + intentserverrequest.cpp intentserverrequest.h + intentserversysteminterface.cpp intentserversysteminterface.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Network + Qt::Qml +) diff --git a/src/launcher-lib/CMakeLists.txt b/src/launcher-lib/CMakeLists.txt new file mode 100644 index 00000000..12e77a68 --- /dev/null +++ b/src/launcher-lib/CMakeLists.txt @@ -0,0 +1,60 @@ +# Generated from launcher-lib.pro. + +##################################################################### +## AppManLauncher Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManLauncherPrivate + CONFIG_MODULE_NAME appman_launcher + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + applicationmanagerwindow.cpp applicationmanagerwindow_p.h + dbusapplicationinterface.cpp dbusapplicationinterface.h + dbusapplicationinterfaceextension.cpp dbusapplicationinterfaceextension.h + dbusnotification.cpp dbusnotification.h + intentclientdbusimplementation.cpp intentclientdbusimplementation.h + ipcwrapperobject.cpp ipcwrapperobject.h ipcwrapperobject_p.h + launchermain.cpp launchermain.h + DBUS_INTERFACE_SOURCES + ../dbus-lib/io.qt.applicationmanager.intentinterface.xml + LIBRARIES + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManIntentClientPrivate + Qt::AppManNotificationPrivate + Qt::AppManSharedMainPrivate + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::DBus + Qt::Gui + Qt::GuiPrivate + Qt::Qml + Qt::Quick + Qt::QuickPrivate +) + +qt_internal_extend_target(AppManLauncherPrivate CONDITION QT_FEATURE_widgets_support AND TARGET Qt::Widgets + PUBLIC_LIBRARIES + Qt::Widgets +) + +if(TARGET Qt::WaylandClient) + + qt6_generate_wayland_protocol_client_sources(AppManLauncherPrivate + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../wayland-extensions/qtam-extension.xml + ) +endif() + +qt_internal_extend_target(AppManLauncherPrivate CONDITION TARGET Qt::WaylandClient + SOURCES + waylandqtamclientextension.cpp waylandqtamclientextension_p.h + PUBLIC_LIBRARIES + Qt::WaylandClient + Qt::WaylandClientPrivate +) diff --git a/src/main-lib/CMakeLists.txt b/src/main-lib/CMakeLists.txt new file mode 100644 index 00000000..7aafc9e3 --- /dev/null +++ b/src/main-lib/CMakeLists.txt @@ -0,0 +1,55 @@ +# Generated from main-lib.pro. + +##################################################################### +## AppManMain Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManMainPrivate + CONFIG_MODULE_NAME appman_main + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + applicationinstaller.cpp applicationinstaller.h + configuration.cpp configuration.h configuration_p.h + defaultconfiguration.cpp defaultconfiguration.h + main.cpp main.h + windowframetimer.cpp windowframetimer.h + DEFINES + AM_BUILD_DIR=\\\"\\\" + PUBLIC_LIBRARIES + Qt::Core + Qt::CorePrivate + Qt::Gui + Qt::Network + Qt::Qml + Qt::Quick + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManIntentServerPrivate + Qt::AppManManagerPrivate + Qt::AppManMonitorPrivate + Qt::AppManNotificationPrivate + Qt::AppManPackagePrivate + Qt::AppManSharedMainPrivate + Qt::AppManWindowPrivate +) + +qt_internal_extend_target(AppManMainPrivate CONDITION QT_FEATURE_widgets_support AND TARGET Qt::Widgets + PUBLIC_LIBRARIES + Qt::Widgets +) + +qt_internal_extend_target(AppManMainPrivate CONDITION TARGET Qt::DBus AND QT_FEATURE_external_dbus_interfaces + PUBLIC_LIBRARIES + Qt::DBus + Qt::AppManDBusPrivate +) + +qt_internal_extend_target(AppManMainPrivate CONDITION WIN32 + PUBLIC_LIBRARIES + user32 +) diff --git a/src/main-lib/main.h b/src/main-lib/main.h index e7ddb5f2..d6d7e31a 100644 --- a/src/main-lib/main.h +++ b/src/main-lib/main.h @@ -33,9 +33,10 @@ #include #include +#include #include -#if defined(AM_ENABLE_WIDGETS) +#if defined(AM_WIDGETS_SUPPORT) # include # include typedef QApplication MainBase; diff --git a/src/manager-lib/CMakeLists.txt b/src/manager-lib/CMakeLists.txt new file mode 100644 index 00000000..45852406 --- /dev/null +++ b/src/manager-lib/CMakeLists.txt @@ -0,0 +1,90 @@ +# Generated from manager-lib.pro. + +##################################################################### +## AppManManager Module: +##################################################################### + +include(QtAppManHelpers) + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManManagerPrivate + CONFIG_MODULE_NAME appman_manager + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + ../plugin-interfaces/containerinterface.h + abstractcontainer.cpp abstractcontainer.h + abstractruntime.cpp abstractruntime.h + amnamespace.h + application.cpp application.h + applicationipcinterface.cpp applicationipcinterface.h applicationipcinterface_p.h + applicationipcmanager.cpp applicationipcmanager.h + applicationmanager.cpp applicationmanager.h applicationmanager_p.h + applicationmodel.cpp applicationmodel.h + asynchronoustask.cpp asynchronoustask.h + containerfactory.cpp containerfactory.h + debugwrapper.cpp debugwrapper.h + inprocesssurfaceitem.cpp inprocesssurfaceitem.h + intentaminterface.cpp intentaminterface.h + notificationmanager.cpp notificationmanager.h + package.cpp package.h + packagemanager.cpp packagemanager.h packagemanager_p.h + plugincontainer.cpp plugincontainer.h + processstatus.cpp processstatus.h + qmlinprocessapplicationmanagerwindow.cpp qmlinprocessapplicationmanagerwindow.h + qmlinprocessapplicationinterface.cpp qmlinprocessapplicationinterface.h + qmlinprocessruntime.cpp qmlinprocessruntime.h + quicklauncher.cpp quicklauncher.h + runtimefactory.cpp runtimefactory.h + LIBRARIES + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManIntentClientPrivate + Qt::AppManIntentServerPrivate + Qt::AppManMonitorPrivate + Qt::AppManNotificationPrivate + Qt::AppManPluginInterfacesPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::GuiPrivate + Qt::Network + Qt::Qml + Qt::QmlPrivate + Qt::Quick + Qt::QuickPrivate +) + +qt_internal_extend_target(AppManManagerPrivate CONDITION QT_FEATURE_multi_process + SOURCES + nativeruntime.cpp nativeruntime.h nativeruntime_p.h + processcontainer.cpp processcontainer.h + PUBLIC_LIBRARIES + Qt::DBus + dl +) + +if (QT_FEATURE_multi_process) + qtam_internal_add_dbus_adaptor(AppManManagerPrivate + DBUS_ADAPTOR_SOURCES + ../dbus-lib/io.qt.applicationmanager.intentinterface.xml + ) +endif() + +qt_internal_extend_target(AppManManagerPrivate CONDITION (TARGET Qt::WaylandCompositor OR QT_FEATURE_installer) + SOURCES + sudo.cpp sudo.h +) + +qt_internal_extend_target(AppManManagerPrivate CONDITION QT_FEATURE_installer + SOURCES + deinstallationtask.cpp deinstallationtask.h + installationtask.cpp installationtask.h + scopeutilities.cpp scopeutilities.h + LIBRARIES + Qt::AppManCryptoPrivate + Qt::AppManPackagePrivate +) diff --git a/src/manager-lib/applicationipcinterface.cpp b/src/manager-lib/applicationipcinterface.cpp index 88cb1797..e8f3f98c 100644 --- a/src/manager-lib/applicationipcinterface.cpp +++ b/src/manager-lib/applicationipcinterface.cpp @@ -51,6 +51,10 @@ #include "applicationipcinterface.h" #include "applicationipcinterface_p.h" +#if defined(interface) +# undef interface +#endif + /*! \qmltype ApplicationIPCInterface \ingroup system-ui-instantiable diff --git a/src/manager-lib/scopeutilities.h b/src/manager-lib/scopeutilities.h index a9019eb2..994e30cc 100644 --- a/src/manager-lib/scopeutilities.h +++ b/src/manager-lib/scopeutilities.h @@ -89,6 +89,7 @@ private: bool m_taken = false; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(ScopedRenamer::Modes) + QT_END_NAMESPACE_AM -Q_DECLARE_OPERATORS_FOR_FLAGS(QT_PREPEND_NAMESPACE_AM(ScopedRenamer::Modes)) diff --git a/src/monitor-lib/CMakeLists.txt b/src/monitor-lib/CMakeLists.txt new file mode 100644 index 00000000..77746240 --- /dev/null +++ b/src/monitor-lib/CMakeLists.txt @@ -0,0 +1,28 @@ +# Generated from monitor-lib.pro. + +##################################################################### +## AppManMonitor Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManMonitorPrivate + CONFIG_MODULE_NAME appman_monitor + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + processreader.cpp processreader.h + systemreader.cpp systemreader.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui +) + +qt_internal_extend_target(AppManMonitorPrivate CONDITION LINUX + SOURCES + sysfsreader.cpp sysfsreader.h +) diff --git a/src/monitor-lib/systemreader.cpp b/src/monitor-lib/systemreader.cpp index c02d9b0d..e89c1ad0 100644 --- a/src/monitor-lib/systemreader.cpp +++ b/src/monitor-lib/systemreader.cpp @@ -154,6 +154,7 @@ GpuVendor::Vendor GpuVendor::get() void GpuVendor::fetch() { QByteArray vendor; +#if !defined(QT_NO_OPENGL) auto readVendor = [&vendor](QOpenGLContext *c) { const GLubyte *p = c->functions()->glGetString(GL_VENDOR); if (p) @@ -173,6 +174,7 @@ void GpuVendor::fetch() context.doneCurrent(); } } +#endif if (vendor.contains("intel")) s_vendor = Intel; else if (vendor.contains("nvidia")) diff --git a/src/notification-lib/CMakeLists.txt b/src/notification-lib/CMakeLists.txt new file mode 100644 index 00000000..b60ffac0 --- /dev/null +++ b/src/notification-lib/CMakeLists.txt @@ -0,0 +1,22 @@ +# Generated from notification-lib.pro. + +##################################################################### +## AppManNotification Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManNotificationPrivate + CONFIG_MODULE_NAME appman_notification + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + notification.cpp notification.h + LIBRARIES + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Qml +) diff --git a/src/package-lib/CMakeLists.txt b/src/package-lib/CMakeLists.txt new file mode 100644 index 00000000..6f6fbab3 --- /dev/null +++ b/src/package-lib/CMakeLists.txt @@ -0,0 +1,37 @@ +# Generated from package-lib.pro. + +##################################################################### +## AppManPackage Module: +##################################################################### + +qt_find_package(WrapLibArchive PROVIDED_TARGETS WrapLibArchive::WrapLibArchive) + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManPackagePrivate + CONFIG_MODULE_NAME appman_package + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + packagecreator.cpp packagecreator.h packagecreator_p.h + packageextractor.cpp packageextractor.h packageextractor_p.h + packageutilities.cpp packageutilities.h packageutilities_p.h + LIBRARIES + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Network +) + +qt_internal_extend_target(AppManPackagePrivate CONDITION QT_FEATURE_system_libarchive + LIBRARIES + WrapLibArchive::WrapLibArchive +) + +qt_internal_extend_target(AppManPackagePrivate CONDITION NOT QT_FEATURE_system_libarchive + LIBRARIES + Qt::BundledLibArchive +) diff --git a/src/package-lib/configure.cmake b/src/package-lib/configure.cmake new file mode 100644 index 00000000..e4b58d81 --- /dev/null +++ b/src/package-lib/configure.cmake @@ -0,0 +1,23 @@ +#### Inputs + +set(INPUT_libarchive "undefined" CACHE STRING "") +set_property(CACHE INPUT_libarchive PROPERTY STRINGS undefined qt system) + +#### Libraries + +qt_find_package(WrapLibArchive PROVIDED_TARGETS WrapLibArchive::WrapLibArchive MODULE_NAME appman_package QMAKE_LIB archive) + +#### Tests + +#### Features + +qt_feature("system-libarchive" PRIVATE + LABEL "Using system libarchive" + CONDITION WrapLibArchive_FOUND + ENABLE INPUT_libarchive STREQUAL 'system' + DISABLE INPUT_libarchive STREQUAL 'qt' +) + +qt_configure_add_summary_section(NAME "Qt Application Manager [Packaging module]") +qt_configure_add_summary_entry(ARGS "system-libarchive") +qt_configure_end_summary_section() # end of "Qt ApplicationManger" section diff --git a/src/package-lib/qt_cmdline.cmake b/src/package-lib/qt_cmdline.cmake new file mode 100644 index 00000000..01007197 --- /dev/null +++ b/src/package-lib/qt_cmdline.cmake @@ -0,0 +1 @@ +qt_commandline_option(libarchive TYPE enum VALUES qt system) diff --git a/src/plugin-interfaces/CMakeLists.txt b/src/plugin-interfaces/CMakeLists.txt new file mode 100644 index 00000000..21584521 --- /dev/null +++ b/src/plugin-interfaces/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated from plugin-interfaces.pro. + +##################################################################### +## AppManPluginInterfaces Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManPluginInterfacesPrivate + CONFIG_MODULE_NAME appman_plugininterfaces + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + containerinterface.cpp containerinterface.h + startupinterface.cpp startupinterface.h + PUBLIC_LIBRARIES + Qt::Core +) diff --git a/src/shared-main-lib/CMakeLists.txt b/src/shared-main-lib/CMakeLists.txt new file mode 100644 index 00000000..16ad324a --- /dev/null +++ b/src/shared-main-lib/CMakeLists.txt @@ -0,0 +1,33 @@ +# Generated from shared-main-lib.pro. + +##################################################################### +## AppManSharedMain Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManSharedMainPrivate + CONFIG_MODULE_NAME appman_shared_main + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + cpustatus.cpp cpustatus.h + frametimer.cpp frametimer.h + gpustatus.cpp gpustatus.h + iostatus.cpp iostatus.h + memorystatus.cpp memorystatus.h + monitormodel.cpp monitormodel.h + qmllogger.cpp qmllogger.h + sharedmain.cpp sharedmain.h + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::GuiPrivate + Qt::Network + Qt::Qml + Qt::Quick + Qt::AppManCommonPrivate + Qt::AppManMonitorPrivate +) diff --git a/src/shared-main-lib/sharedmain.cpp b/src/shared-main-lib/sharedmain.cpp index 051d25db..c24fe4b1 100644 --- a/src/shared-main-lib/sharedmain.cpp +++ b/src/shared-main-lib/sharedmain.cpp @@ -93,6 +93,7 @@ void SharedMain::initialize() s_initialized = true; +#if !defined(QT_NO_OPENGL) // this is needed for both WebEngine and Wayland Multi-screen rendering QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); @@ -101,6 +102,7 @@ void SharedMain::initialize() // to parse the requested format from the config files - the creation is completed later // in setupOpenGL(). qt_gl_set_global_share_context(new QOpenGLContext()); +#endif #if defined(Q_OS_UNIX) && defined(AM_MULTI_PROCESS) // set a reasonable default for OSes/distros that do not set this by default @@ -158,6 +160,7 @@ void SharedMain::setupLogging(bool verbose, const QStringList &loggingRules, void SharedMain::setupOpenGL(const QVariantMap &openGLConfiguration) { +#if !defined(QT_NO_OPENGL) QString profileName = openGLConfiguration.value(qSL("desktopProfile")).toString(); int majorVersion = openGLConfiguration.value(qSL("esMajorVersion"), -1).toInt(); int minorVersion = openGLConfiguration.value(qSL("esMinorVersion"), -1).toInt(); @@ -230,10 +233,14 @@ void SharedMain::setupOpenGL(const QVariantMap &openGLConfiguration) // check if we got what we requested on the OpenGL side checkOpenGLFormat("global shared context", globalContext->format()); +#else + Q_UNUSED(openGLConfiguration) +#endif } void SharedMain::checkOpenGLFormat(const char *what, const QSurfaceFormat &format) const { +#if !defined(QT_NO_OPENGL) if ((m_requestedOpenGLProfile != QSurfaceFormat::NoProfile) && (format.profile() != m_requestedOpenGLProfile)) { qCWarning(LogGraphics) << "Failed to get the requested OpenGL profile" @@ -252,6 +259,10 @@ void SharedMain::checkOpenGLFormat(const char *what, const QSurfaceFormat &forma << format.minorVersion() << " instead"; } } +#else + Q_UNUSED(what) + Q_UNUSED(format) +#endif } QT_END_NAMESPACE_AM diff --git a/src/tools/appman/CMakeLists.txt b/src/tools/appman/CMakeLists.txt new file mode 100644 index 00000000..515dd098 --- /dev/null +++ b/src/tools/appman/CMakeLists.txt @@ -0,0 +1,32 @@ +# Generated from appman.pro. + +##################################################################### +## appman Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman) +qt_internal_add_tool(${target_name} + USER_FACING + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + appman.cpp + PUBLIC_LIBRARIES + Qt::AppManMainPrivate +) + +#### Keys ignored in scope 1:.:.:appman.pro:: +# GIT_VERSION = "$$cat($$SOURCE_DIR/.tag, lines)" +# TEMPLATE = "app" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 4:.:.:appman.pro:UNIX AND EXISTS _ss_SOURCE_DIR/.git: +# GIT_VERSION = "$$system(cd "$$SOURCE_DIR" && git describe --tags --always --dirty 2>/dev/null)" + +#### Keys ignored in scope 5:.:.:appman.pro:else: +# GIT_VERSION = "unknown" + +#### Keys ignored in scope 6:.:.:appman.pro:ANDROID: +# INSTALLS = diff --git a/src/tools/controller/CMakeLists.txt b/src/tools/controller/CMakeLists.txt new file mode 100644 index 00000000..a31b5ce4 --- /dev/null +++ b/src/tools/controller/CMakeLists.txt @@ -0,0 +1,29 @@ +# Generated from controller.pro. + +##################################################################### +## appman-controller Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman-controller) +qt_internal_add_tool(${target_name} + USER_FACING + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + controller.cpp + interrupthandler.cpp interrupthandler.h + PUBLIC_LIBRARIES + Qt::DBus + Qt::Network + Qt::AppManCommonPrivate +) +qt_internal_extend_target(${target_name} + DBUS_INTERFACE_SOURCES + ../../dbus-lib/io.qt.packagemanager.xml +) +qt_internal_extend_target(${target_name} + DBUS_INTERFACE_SOURCES + ../../dbus-lib/io.qt.applicationmanager.xml + DBUS_INTERFACE_FLAGS + -i dbus-utilities.h +) diff --git a/src/tools/dumpqmltypes/CMakeLists.txt b/src/tools/dumpqmltypes/CMakeLists.txt new file mode 100644 index 00000000..1f48b9f7 --- /dev/null +++ b/src/tools/dumpqmltypes/CMakeLists.txt @@ -0,0 +1,41 @@ +# Generated from dumpqmltypes.pro. + +##################################################################### +## appman-dumpqmltypes Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman-dumpqmltypes) +qt_internal_add_tool(${target_name} + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + dumpqmltypes.cpp + PUBLIC_LIBRARIES + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManIntentClientPrivate + Qt::AppManIntentServerPrivate + Qt::AppManLauncherPrivate + Qt::AppManMainPrivate + Qt::AppManManagerPrivate + Qt::AppManMonitorPrivate + Qt::AppManNotificationPrivate + Qt::AppManSharedMainPrivate + Qt::AppManWindowPrivate +) + +#### Keys ignored in scope 1:.:.:dumpqmltypes.pro:: +# TEMPLATE = "app" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:dumpqmltypes.pro:NOT CMAKE_CROSSCOMPILING: +# QT_TOOL_ENV = + +#### Keys ignored in scope 3:.:.:dumpqmltypes.pro:build_pass OR NOT debug_and_release: +# INSTALLS = "qmltypes_file" +# QMAKE_POST_LINK = "$$QMLPLUGINDUMP" "$$SOURCE_DIR/qmltypes" +# qmltypes_file.CONFIG = "no_check_exist" "directory" +# qmltypes_file.files = "$$SOURCE_DIR/qmltypes/QtApplicationManager" +# qmltypes_file.path = "$$[QT_INSTALL_QML]" diff --git a/src/tools/launcher-qml/CMakeLists.txt b/src/tools/launcher-qml/CMakeLists.txt new file mode 100644 index 00000000..60da4b95 --- /dev/null +++ b/src/tools/launcher-qml/CMakeLists.txt @@ -0,0 +1,31 @@ +# Generated from launcher-qml.pro. + +##################################################################### +## appman-launcher-qml Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman-launcher-qml) +qt_internal_add_tool(${target_name} + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + launcher-qml.cpp launcher-qml_p.h + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::DBus + Qt::Gui + Qt::GuiPrivate + Qt::Qml + Qt::Quick + Qt::QuickPrivate + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManLauncherPrivate + Qt::AppManMonitorPrivate + Qt::AppManNotificationPrivate + Qt::AppManPluginInterfacesPrivate + Qt::AppManSharedMainPrivate +) + +#### Keys ignored in scope 1:.:.:launcher-qml.pro:: +# TEMPLATE = "app" diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp index f63cfa5c..7a7e1046 100644 --- a/src/tools/launcher-qml/launcher-qml.cpp +++ b/src/tools/launcher-qml/launcher-qml.cpp @@ -50,6 +50,7 @@ #include #include +#include #include #include @@ -85,7 +86,7 @@ #include "memorystatus.h" #include "monitormodel.h" -#if defined(AM_ENABLE_WIDGETS) +#if defined(AM_WIDGETS_SUPPORT) # include using Application = QApplication; #else diff --git a/src/tools/packager/CMakeLists.txt b/src/tools/packager/CMakeLists.txt new file mode 100644 index 00000000..02c6d3b7 --- /dev/null +++ b/src/tools/packager/CMakeLists.txt @@ -0,0 +1,21 @@ +# Generated from packager.pro. + +##################################################################### +## appman-packager Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman-packager) +qt_internal_add_tool(${target_name} + USER_FACING + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + packager.cpp + packagingjob.cpp packagingjob.h + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManCryptoPrivate + Qt::AppManPackagePrivate +) diff --git a/src/tools/testrunner/CMakeLists.txt b/src/tools/testrunner/CMakeLists.txt new file mode 100644 index 00000000..c66c5d9f --- /dev/null +++ b/src/tools/testrunner/CMakeLists.txt @@ -0,0 +1,34 @@ +# Generated from testrunner.pro. + +##################################################################### +## appman-qmltestrunner Tool: +##################################################################### + +qt_get_tool_target_name(target_name appman-qmltestrunner) +qt_internal_add_tool(${target_name} + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + ../appman/appman.cpp + amtest.cpp amtest.h + testrunner.cpp testrunner.h testrunner_p.h + DEFINES + AM_TESTRUNNER + PUBLIC_LIBRARIES + Qt::QuickTest + Qt::QuickTestPrivate + Qt::TestPrivate + Qt::AppManMainPrivate +) + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:testrunner.pro:ANDROID: +# INSTALLS = + +#### Keys ignored in scope 6:.:../appman:../appman/appman.pro:UNIX AND EXISTS _ss_SOURCE_DIR/.git: +# GIT_VERSION = "$$system(cd "$$SOURCE_DIR" && git describe --tags --always --dirty 2>/dev/null)" + +#### Keys ignored in scope 7:.:../appman:../appman/appman.pro:else: +# GIT_VERSION = "unknown" diff --git a/src/tools/uploader/CMakeLists.txt b/src/tools/uploader/CMakeLists.txt new file mode 100644 index 00000000..bb6555ac --- /dev/null +++ b/src/tools/uploader/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated from uploader.pro. + +##################################################################### +## package-uploader Tool: +##################################################################### + +qt_get_tool_target_name(target_name package-uploader) +qt_internal_add_tool(${target_name} + USER_FACING + EXCEPTIONS + TOOLS_TARGET AppManMainPrivate + SOURCES + uploader.cpp + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate +) + +#### Keys ignored in scope 1:.:.:uploader.pro:: +# TEMPLATE = "app" diff --git a/src/window-lib/CMakeLists.txt b/src/window-lib/CMakeLists.txt new file mode 100644 index 00000000..3b0b647d --- /dev/null +++ b/src/window-lib/CMakeLists.txt @@ -0,0 +1,59 @@ +# Generated from window-lib.pro. + +##################################################################### +## AppManWindow Module: +##################################################################### + +# temporary hack to get around the "#pragma once not allowed in cpp" error +set(QT_FEATURE_headersclean FALSE) + +qt_internal_add_module(AppManWindowPrivate + CONFIG_MODULE_NAME appman_window + STATIC + EXCEPTIONS + INTERNAL_MODULE + SOURCES + inprocesswindow.cpp inprocesswindow.h + touchemulation.cpp touchemulation.h + window.cpp window.h + windowitem.cpp windowitem.h + windowmanager.cpp windowmanager.h windowmanager_p.h + LIBRARIES + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate + Qt::AppManMonitorPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::CorePrivate + Qt::Gui + Qt::Network + Qt::Qml + Qt::Quick +) + +if(QT_FEATURE_multi_process) + + qt6_generate_wayland_protocol_server_sources(AppManWindowPrivate + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../wayland-extensions/qtam-extension.xml + ) + + qt_internal_extend_target(AppManWindowPrivate + SOURCES + waylandcompositor.cpp waylandcompositor.h + waylandqtamserverextension.cpp waylandqtamserverextension_p.h + waylandwindow.cpp waylandwindow.h + PUBLIC_LIBRARIES + Qt::WaylandCompositor + ) +endif() + +qt_internal_extend_target(AppManWindowPrivate CONDITION QT_FEATURE_touch_emulation + SOURCES + touchemulation_x11.cpp touchemulation_x11_p.h + LIBRARIES + Qt::GuiPrivate + Qt::Test + X11::Xi +) diff --git a/src/window-lib/configure.cmake b/src/window-lib/configure.cmake new file mode 100644 index 00000000..76822c57 --- /dev/null +++ b/src/window-lib/configure.cmake @@ -0,0 +1,29 @@ +#### Inputs + +#### Libraries + +find_package(X11) + +#### Tests + +#### Features + +qt_feature("touch-emulation" PRIVATE + LABEL "Touch emulation support on X11" + CONDITION X11_Xi_FOUND AND LINUX + EMIT_IF LINUX +) +qt_feature_definition("touch-emulation" "AM_ENABLE_TOUCH_EMULATION") + +qt_feature("widgets-support" PRIVATE PUBLIC + LABEL "Enable support for Qt widgets" + CONDITION INPUT_widgets_support STREQUAL 'yes' AND TARGET Qt::Widgets +) +qt_feature_definition("widgets-support" "AM_WIDGETS_SUPPORT") + +qt_configure_add_summary_section(NAME "Qt Application Manager [Window module]") +qt_configure_add_summary_entry(ARGS "touch-emulation") +qt_configure_add_summary_entry(ARGS "widgets-support") +qt_configure_end_summary_section() # end of "Qt ApplicationManger" section + +qt_extra_definition("AM_VERSION" "\"${PROJECT_VERSION}\"" PUBLIC) diff --git a/src/window-lib/qt_cmdline.cmake b/src/window-lib/qt_cmdline.cmake new file mode 100644 index 00000000..99183336 --- /dev/null +++ b/src/window-lib/qt_cmdline.cmake @@ -0,0 +1 @@ +qt_commandline_option(widgets-support TYPE boolean) diff --git a/src/window-lib/touchemulation_x11_p.h b/src/window-lib/touchemulation_x11_p.h index 1f2f1390..3d6385dd 100644 --- a/src/window-lib/touchemulation_x11_p.h +++ b/src/window-lib/touchemulation_x11_p.h @@ -32,6 +32,7 @@ #pragma once #include +#include #include "touchemulation.h" #if defined(AM_ENABLE_TOUCH_EMULATION) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..c36223a4 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,10 @@ +# Generated from tests.pro. + +if(QT_BUILD_STANDALONE_TESTS) + # Add qt_find_package calls for extra dependencies that need to be found when building + # the standalone tests here. + find_package(X11) + find_package(ZLIB) + find_package(Iconv) +endif() +qt_build_tests() diff --git a/tests/application/application.pro b/tests/application/application.pro deleted file mode 100644 index 2bdaf9c5..00000000 --- a/tests/application/application.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = tst_application - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_application-private \ - appman_manager-private \ - -SOURCES += tst_application.cpp - -OTHER_FILES += info.yaml -RESOURCES += tst_application.qrc diff --git a/tests/application/icon.png b/tests/application/icon.png deleted file mode 100644 index 909c66db..00000000 Binary files a/tests/application/icon.png and /dev/null differ diff --git a/tests/application/info.yaml b/tests/application/info.yaml deleted file mode 100644 index 08329bb8..00000000 --- a/tests/application/info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatType: am-package -formatVersion: 1 ---- -id: pkg.test -name: { en: "Test Package" } -icon: icon.png -applications: -- id: app.test - runtime: qml - code: info.yaml # just to make the test simpler diff --git a/tests/application/tst_application.cpp b/tests/application/tst_application.cpp deleted file mode 100644 index 05b155c5..00000000 --- a/tests/application/tst_application.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "global.h" -#include "application.h" -#include "applicationinfo.h" -#include "packageinfo.h" -#include "package.h" -#include "abstractruntime.h" - -QT_USE_NAMESPACE_AM - -class TestRuntime : public AbstractRuntime -{ - Q_OBJECT - -public: - explicit TestRuntime(AbstractContainer *container, Application *app, AbstractRuntimeManager *manager) - : AbstractRuntime(container, app, manager) - { } - - void setSlowAnimations(bool) override {} - - qint64 applicationProcessId() const override - { - return m_state == Am::Running ? 1 : 0; - } - -public slots: - bool start() override - { - m_state = Am::Running; - return true; - } - - void stop(bool forceKill) override - { - Q_UNUSED(forceKill); - m_state = Am::NotRunning; - } -}; - -class TestRuntimeManager : public AbstractRuntimeManager -{ - Q_OBJECT - -public: - TestRuntimeManager(const QString &id, QObject *parent) - : AbstractRuntimeManager(id, parent) - { } - - static QString defaultIdentifier() { return qSL("foo"); } - - bool inProcess() const override - { - return !AbstractRuntimeManager::inProcess(); - } - - TestRuntime *create(AbstractContainer *container, Application *app) override - { - return new TestRuntime(container, app, this); - } -}; - -class tst_Application : public QObject -{ - Q_OBJECT - -public: - tst_Application(){} - -private slots: - void runtimeDestroyed(); -}; - -// Checks that when the runtime of an application is destroyed -// the application no longer holds a reference to it -void tst_Application::runtimeDestroyed() -{ - auto pi = PackageInfo::fromManifest(qL1S(":/info.yaml")); - auto pkg = new Package(pi); - auto ai = new ApplicationInfo(pi); - auto app = new Application(ai, pkg); - - auto runtimeManager = new TestRuntimeManager(qSL("foo"), qApp); - auto runtime = runtimeManager->create(nullptr, app); - - app->setCurrentRuntime(runtime); - - QCOMPARE(app->currentRuntime(), runtime); - - delete runtime; - - QCOMPARE(app->currentRuntime(), nullptr); - - delete app; - delete runtimeManager; - delete ai; - delete pkg; - delete pi; -} - -QTEST_APPLESS_MAIN(tst_Application) - -#include "tst_application.moc" diff --git a/tests/application/tst_application.qrc b/tests/application/tst_application.qrc deleted file mode 100644 index a24bcd9a..00000000 --- a/tests/application/tst_application.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - info.yaml - - diff --git a/tests/applicationinfo/applicationinfo.pro b/tests/applicationinfo/applicationinfo.pro deleted file mode 100644 index 9fcc7ffe..00000000 --- a/tests/applicationinfo/applicationinfo.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = tst_applicationinfo - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_application-private \ - appman_manager-private \ - -SOURCES += tst_applicationinfo.cpp diff --git a/tests/applicationinfo/tst_applicationinfo.cpp b/tests/applicationinfo/tst_applicationinfo.cpp deleted file mode 100644 index 56ba2294..00000000 --- a/tests/applicationinfo/tst_applicationinfo.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "global.h" -#include "application.h" -#include "applicationinfo.h" -#include "packageinfo.h" -#include "yamlpackagescanner.h" -#include "exception.h" - -QT_USE_NAMESPACE_AM - -class tst_ApplicationInfo : public QObject -{ - Q_OBJECT - -public: - tst_ApplicationInfo(); - -private slots: - void initTestCase(); - void cleanupTestCase(); - void application_data(); - void application(); - void validApplicationId_data(); - void validApplicationId(); - void validIcon_data(); - void validIcon(); - -private: - QVector m_pkgs; -}; - -tst_ApplicationInfo::tst_ApplicationInfo() -{ } - - -void tst_ApplicationInfo::initTestCase() -{ - YamlPackageScanner scanner; - QDir baseDir(qL1S(AM_TESTDATA_DIR "manifests")); - const QStringList pkgDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); - for (const QString &pkgDirName : pkgDirNames) { - QDir dir = baseDir.absoluteFilePath(pkgDirName); - try { - PackageInfo *pi = scanner.scan(dir.absoluteFilePath(qSL("info.yaml"))); - QVERIFY(pi); - QCOMPARE(pkgDirName, pi->id()); - m_pkgs << pi; - } catch (const std::exception &e) { - QFAIL(e.what()); - } - } - - QCOMPARE(m_pkgs.size(), 2); -} - -void tst_ApplicationInfo::cleanupTestCase() -{ - qDeleteAll(m_pkgs); -} - -void tst_ApplicationInfo::application_data() -{ - QTest::addColumn("id"); - - QTest::newRow("normal") << "com.pelagicore.test"; - QTest::newRow("json") << "com.pelagicore.json-legacy"; -} - -void tst_ApplicationInfo::application() -{ - QFETCH(QString, id); - - QString name = QString::fromLatin1(AM_TESTDATA_DIR "manifests/%1/info.yaml").arg(id); - - YamlPackageScanner scanner; - PackageInfo *pkg; - try { - pkg = scanner.scan(name); - QVERIFY(pkg); - } catch (const std::exception &e) { - QFAIL(e.what()); - } - - QCOMPARE(pkg->id(), id); - QCOMPARE(QFileInfo(pkg->icon()).fileName(), qSL("icon.png")); - QCOMPARE(pkg->names().size(), 2); - QCOMPARE(pkg->names().value(qSL("en")), qSL("english")); - QCOMPARE(pkg->names().value(qSL("de")), qSL("deutsch")); - QCOMPARE(pkg->name(qSL("en")), qSL("english")); - QCOMPARE(pkg->isBuiltIn(), false); - QCOMPARE(pkg->categories().size(), 2); - QVERIFY(pkg->categories().startsWith(qSL("bar"))); - QVERIFY(pkg->categories().endsWith(qSL("foo"))); - - ApplicationInfo *app = pkg->applications().size() == 1 ? pkg->applications().first() : nullptr; - QVERIFY(app); - QCOMPARE(QFileInfo(app->codeFilePath()).fileName(), qSL("Test.qml")); - QCOMPARE(app->runtimeName(), qSL("qml")); - QCOMPARE(app->runtimeParameters().size(), 1); - QCOMPARE(app->runtimeParameters().value(qSL("loadDummyData")).toBool(), true); - QCOMPARE(app->capabilities().size(), 2); - QVERIFY(app->capabilities().startsWith(qSL("cameraAccess"))); - QVERIFY(app->capabilities().endsWith(qSL("locationAccess"))); - - // legacy - QCOMPARE(app->supportedMimeTypes().size(), 2); - QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain"))); - QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto"))); - - delete pkg; -} - -void tst_ApplicationInfo::validApplicationId_data() -{ - QTest::addColumn("appId"); - QTest::addColumn("valid"); - - // passes - QTest::newRow("normal") << "Test" << true; - QTest::newRow("shortest") << "t" << true; - QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+@" << true; - QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << true; - - // failures - QTest::newRow("empty") << "" << false; - QTest::newRow("space-only") << " " << false; - QTest::newRow("space-only2") << " " << false; - QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false; - QTest::newRow("invalid-char<") << "t<" << false; - QTest::newRow("invalid-char>") << "t>" << false; - QTest::newRow("invalid-char:") << "t:" << false; - QTest::newRow("invalid-char-quote") << "t\"" << false; - QTest::newRow("invalid-char/") << "t/" << false; - QTest::newRow("invalid-char\\") << "t\\" << false; - QTest::newRow("invalid-char|") << "t|" << false; - QTest::newRow("invalid-char?") << "t?" << false; - QTest::newRow("invalid-char*") << "t*" << false; - QTest::newRow("control-char") << "t\t" << false; -} - -void tst_ApplicationInfo::validApplicationId() -{ - QFETCH(QString, appId); - QFETCH(bool, valid); - - QString errorString; - bool result = PackageInfo::isValidApplicationId(appId, &errorString); - - QVERIFY2(valid == result, qPrintable(errorString)); -} - -void tst_ApplicationInfo::validIcon_data() -{ - QTest::addColumn("icon"); - QTest::addColumn("isValid"); - - // valid - QTest::newRow("'icon.png' is valid") << "icon.png" << true; - QTest::newRow("'foo.bar' is valid") << "foo.bar" << true; - QTest::newRow("'foo' is valid") << "foo" << true; - - // invalid - QTest::newRow("empty is invalid") << "" << false; - QTest::newRow("'foo/icon.png' is invalid") << "foo/icon.png" << false; - QTest::newRow("'../icon.png' is invalid") << "../icon.png" << false; - QTest::newRow("'icon.png/' is invalid") << "icon.png/" << false; - QTest::newRow("'/foo' is invalid") << "/foo" << false; -} - -void tst_ApplicationInfo::validIcon() -{ - QFETCH(QString, icon); - QFETCH(bool, isValid); - - QString errorString; - bool result = PackageInfo::isValidIcon(icon, &errorString); - - QCOMPARE(result, isValid); -} - -QTEST_APPLESS_MAIN(tst_ApplicationInfo) - -#include "tst_applicationinfo.moc" - diff --git a/tests/applicationinstaller/applicationinstaller.pro b/tests/applicationinstaller/applicationinstaller.pro deleted file mode 100644 index b84ffac4..00000000 --- a/tests/applicationinstaller/applicationinstaller.pro +++ /dev/null @@ -1,13 +0,0 @@ -TARGET = tst_applicationinstaller - -COVERAGE_RUNTIME = sudo - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_application-private \ - appman_package-private \ - appman_manager-private \ - -SOURCES += tst_applicationinstaller.cpp diff --git a/tests/applicationinstaller/tst_applicationinstaller.cpp b/tests/applicationinstaller/tst_applicationinstaller.cpp deleted file mode 100644 index 15be7898..00000000 --- a/tests/applicationinstaller/tst_applicationinstaller.cpp +++ /dev/null @@ -1,793 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include - -#include "packagemanager.h" -#include "packagedatabase.h" -#include "package.h" -#include "applicationinfo.h" -#include "sudo.h" -#include "utilities.h" -#include "error.h" -#include "private/packageutilities_p.h" -#include "runtimefactory.h" -#include "qmlinprocessruntime.h" -#include "packageutilities.h" - -#include "../error-checking.h" - -QT_USE_NAMESPACE_AM - -static bool startedSudoServer = false; -static QString sudoServerError; - -static int spyTimeout = 5000; // shorthand for specifying QSignalSpy timeouts - -// RAII to reset the global attribute -class AllowInstallations -{ -public: - enum Type { - AllowUnsinged, - RequireDevSigned, - RequireStoreSigned - }; - - AllowInstallations(Type t) - : m_oldUnsigned(PackageManager::instance()->allowInstallationOfUnsignedPackages()) - , m_oldDevMode(PackageManager::instance()->developmentMode()) - { - switch (t) { - case AllowUnsinged: - PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); - PackageManager::instance()->setDevelopmentMode(false); - break; - case RequireDevSigned: - PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); - PackageManager::instance()->setDevelopmentMode(true); - break; - case RequireStoreSigned: - PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); - PackageManager::instance()->setDevelopmentMode(false); - break; - } - } - ~AllowInstallations() - { - PackageManager::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned); - PackageManager::instance()->setDevelopmentMode(m_oldDevMode); - } -private: - bool m_oldUnsigned; - bool m_oldDevMode; -}; - -class tst_PackageManager : public QObject -{ - Q_OBJECT - -public: - tst_PackageManager(QObject *parent = nullptr); - ~tst_PackageManager(); - -private slots: - void initTestCase(); - void cleanupTestCase(); - - void init(); - void cleanup(); - - //TODO: test AI::cleanupBrokenInstallations() before calling cleanup() the first time! - - void packageInstallation_data(); - void packageInstallation(); - - void simulateErrorConditions_data(); - void simulateErrorConditions(); - - void cancelPackageInstallation_data(); - void cancelPackageInstallation(); - - void parallelPackageInstallation(); - - void validateDnsName_data(); - void validateDnsName(); - - void compareVersions_data(); - void compareVersions(); - -public: - enum PathLocation { - Internal0, - Documents0, - - PathLocationCount - }; - -private: - QString pathTo(const QString &sub = QString()) - { - return pathTo(PathLocationCount, sub); - } - - QString pathTo(PathLocation pathLocation, const QString &sub = QString()) - { - QString base; - switch (pathLocation) { - case Internal0: base = qSL("internal"); break; - case Documents0: base = qSL("documents"); break; - default: break; - } - - QDir workDir(m_workDir.path()); - - if (base.isEmpty() && sub.isEmpty()) - base = workDir.absolutePath(); - else if (sub.isEmpty()) - base = workDir.absoluteFilePath(base); - else if (base.isEmpty()) - base = workDir.absoluteFilePath(sub); - else - base = workDir.absoluteFilePath(base + '/' + sub); - - if (QDir(base).exists()) - return base + '/'; - else - return base; - } - - void clearSignalSpies() - { - m_startedSpy->clear(); - m_requestingInstallationAcknowledgeSpy->clear(); - m_blockingUntilInstallationAcknowledgeSpy->clear(); - m_progressSpy->clear(); - m_finishedSpy->clear(); - m_failedSpy->clear(); - } - - static bool isDataTag(const char *tag) - { - return !qstrcmp(tag, QTest::currentDataTag()); - } - -private: - SudoClient *m_sudo = nullptr; - bool m_fakeSudo = false; - - QTemporaryDir m_workDir; - QString m_hardwareId; - PackageManager *m_pm = nullptr; - QSignalSpy *m_startedSpy = nullptr; - QSignalSpy *m_requestingInstallationAcknowledgeSpy = nullptr; - QSignalSpy *m_blockingUntilInstallationAcknowledgeSpy = nullptr; - QSignalSpy *m_progressSpy = nullptr; - QSignalSpy *m_finishedSpy = nullptr; - QSignalSpy *m_failedSpy = nullptr; -}; - - -tst_PackageManager::tst_PackageManager(QObject *parent) - : QObject(parent) -{ } - -tst_PackageManager::~tst_PackageManager() -{ - if (m_workDir.isValid()) { - if (m_sudo) - m_sudo->removeRecursive(m_workDir.path()); - else - recursiveOperation(m_workDir.path(), safeRemove); - } - - delete m_failedSpy; - delete m_finishedSpy; - delete m_progressSpy; - delete m_blockingUntilInstallationAcknowledgeSpy; - delete m_requestingInstallationAcknowledgeSpy; - delete m_startedSpy; - - delete m_pm; -} - -void tst_PackageManager::initTestCase() -{ - if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) - QSKIP("No test packages available in the data/ directory"); - - bool verbose = qEnvironmentVariableIsSet("AM_VERBOSE_TEST"); - if (!verbose) - QLoggingCategory::setFilterRules(qSL("am.installer.debug=false")); - qInfo() << "Verbose mode is" << (verbose ? "on" : "off") << "(change by (un)setting $AM_VERBOSE_TEST)"; - - spyTimeout *= timeoutFactor(); - - QVERIFY(PackageUtilities::checkCorrectLocale()); - QVERIFY2(startedSudoServer, qPrintable(sudoServerError)); - m_sudo = SudoClient::instance(); - QVERIFY(m_sudo); - m_fakeSudo = m_sudo->isFallbackImplementation(); - - // create a temporary dir (plus sub-dirs) for everything created by this test run - QVERIFY(m_workDir.isValid()); - - // make sure we have a valid hardware-id - m_hardwareId = qSL("foobar"); - - for (int i = 0; i < PathLocationCount; ++i) - QVERIFY(QDir().mkdir(pathTo(PathLocation(i)))); - - // finally, instantiate the PackageManager and a bunch of signal-spies for its signals - try { - PackageDatabase *pdb = new PackageDatabase(QStringList(), pathTo(Internal0)); - m_pm = PackageManager::createInstance(pdb, pathTo(Documents0)); - m_pm->setHardwareId(m_hardwareId); - m_pm->enableInstaller(); - - // simulate the ApplicationManager stopping blocked applications - connect(&m_pm->internalSignals, &PackageManagerInternalSignals::registerApplication, - this, [this](ApplicationInfo *ai, Package *package) { - connect(package, &Package::blockedChanged, this, [ai, package](bool blocked) { - if (package->info()->applications().contains(ai) && blocked) - package->applicationStoppedDueToBlock(ai->id()); - }); - }); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - - const QVariantMap iloc = m_pm->installationLocation(); - QCOMPARE(iloc.size(), 3); - QCOMPARE(iloc.value(qSL("path")).toString(), pathTo(Internal0)); - QVERIFY(iloc.value(qSL("deviceSize")).toLongLong() > 0); - QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() > 0); - QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() < iloc.value(qSL("deviceSize")).toLongLong()); - - const QVariantMap dloc = m_pm->documentLocation(); - QCOMPARE(dloc.size(), 3); - QCOMPARE(dloc.value(qSL("path")).toString(), pathTo(Documents0)); - QVERIFY(dloc.value(qSL("deviceSize")).toLongLong() > 0); - QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() > 0); - QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() < dloc.value(qSL("deviceSize")).toLongLong()); - - m_startedSpy = new QSignalSpy(m_pm, &PackageManager::taskStarted); - m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskRequestingInstallationAcknowledge); - m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskBlockingUntilInstallationAcknowledge); - m_progressSpy = new QSignalSpy(m_pm, &PackageManager::taskProgressChanged); - m_finishedSpy = new QSignalSpy(m_pm, &PackageManager::taskFinished); - m_failedSpy = new QSignalSpy(m_pm, &PackageManager::taskFailed); - - // crypto stuff - we need to load the root CA and developer CA certificates - - QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt")); - QFile storecaFile(qL1S(AM_TESTDATA_DIR "certificates/store.crt")); - QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt")); - QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); - QVERIFY2(storecaFile.open(QIODevice::ReadOnly), qPrintable(storecaFile.errorString())); - QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(caFile.errorString())); - - QList chainOfTrust; - chainOfTrust << devcaFile.readAll() << caFile.readAll(); - QVERIFY(!chainOfTrust.at(0).isEmpty()); - QVERIFY(!chainOfTrust.at(1).isEmpty()); - m_pm->setCACertificates(chainOfTrust); - - // we do not require valid store signatures for this test run - - m_pm->setDevelopmentMode(true); - - // make sure we have a valid runtime available. The important part is - // that we have a runtime called "native" - the functionality does not matter. - RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("native"))); -} - -void tst_PackageManager::cleanupTestCase() -{ - // the real cleanup happens in ~tst_PackageManager, since we also need - // to call this cleanup from the crash handler -} - -void tst_PackageManager::init() -{ - // start with a fresh App1 dir on each test run - - if (!QDir(pathTo(Internal0)).exists()) - QVERIFY(QDir().mkdir(pathTo(Internal0))); -} - -void tst_PackageManager::cleanup() -{ - // this helps with reducing the amount of cleanup work required - // at the end of each test - - try { - m_pm->cleanupBrokenInstallations(); - } catch (const Exception &e) { - QFAIL(e.what()); - } - - clearSignalSpies(); - recursiveOperation(pathTo(Internal0), safeRemove); -} - -void tst_PackageManager::packageInstallation_data() -{ - QTest::addColumn("packageName"); - QTest::addColumn("updatePackageName"); - QTest::addColumn("devSigned"); - QTest::addColumn("storeSigned"); - QTest::addColumn("expectedSuccess"); - QTest::addColumn("updateExpectedSuccess"); - QTest::addColumn("extraMetaData"); - QTest::addColumn("errorString"); // start with ~ to create a RegExp - - QVariantMap nomd { }; // no meta-data - QVariantMap extramd = QVariantMap { - { "extra", QVariantMap { - { "array", QVariantList { 1, 2 } }, - { "foo", "bar" }, - { "foo2","bar2" }, - { "key", "value" } } }, - { "extraSigned", QVariantMap { - { "sfoo", "sbar" }, - { "sfoo2", "sbar2" }, - { "signed-key", "signed-value" }, - { "signed-object", QVariantMap { { "k1", "v1" }, { "k2", "v2" } } } - } } - }; - - QTest::newRow("normal") \ - << "test.appkg" << "test-update.appkg" - << false << false << true << true << nomd<< ""; - QTest::newRow("no-dev-signed") \ - << "test.appkg" << "" - << true << false << false << false << nomd << "cannot install unsigned packages"; - QTest::newRow("dev-signed") \ - << "test-dev-signed.appkg" << "test-update-dev-signed.appkg" - << true << false << true << true << nomd << ""; - QTest::newRow("no-store-signed") \ - << "test.appkg" << "" - << false << true << false << false << nomd << "cannot install unsigned packages"; - QTest::newRow("no-store-but-dev-signed") \ - << "test-dev-signed.appkg" << "" - << false << true << false << false << nomd << "cannot install development packages on consumer devices"; - QTest::newRow("store-signed") \ - << "test-store-signed.appkg" << "" - << false << true << true << false << nomd << ""; - QTest::newRow("extra-metadata") \ - << "test-extra.appkg" << "" - << false << false << true << false << extramd << ""; - QTest::newRow("extra-metadata-dev-signed") \ - << "test-extra-dev-signed.appkg" << "" - << true << false << true << false << extramd << ""; - QTest::newRow("invalid-file-order") \ - << "test-invalid-file-order.appkg" << "" - << false << false << false << false << nomd << "The package icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'"; - QTest::newRow("invalid-header-format") \ - << "test-invalid-header-formatversion.appkg" << "" - << false << false << false << false << nomd << "metadata has an invalid format specification: wrong header: expected type 'am-package-header', version '2' or type 'am-package-header', version '1', but instead got type 'am-package-header', version '0'"; - QTest::newRow("invalid-header-diskspaceused") \ - << "test-invalid-header-diskspaceused.appkg" << "" - << false << false << false << false << nomd << "metadata has an invalid diskSpaceUsed field (0)"; - QTest::newRow("invalid-header-id") \ - << "test-invalid-header-id.appkg" << "" - << false << false << false << false << nomd << "metadata has an invalid packageId field (:invalid)"; - QTest::newRow("non-matching-header-id") \ - << "test-non-matching-header-id.appkg" << "" - << false << false << false << false << nomd << "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match"; - QTest::newRow("tampered-extra-signed-header") \ - << "test-tampered-extra-signed-header.appkg" << "" - << false << false << false << false << nomd << "~package digest mismatch.*"; - QTest::newRow("invalid-info.yaml") \ - << "test-invalid-info.appkg" << "" - << false << false << false << false << nomd << "~.*did not find expected key.*"; - QTest::newRow("invalid-info.yaml-id") \ - << "test-invalid-info-id.appkg" << "" - << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid package-id: must consist of printable ASCII characters only, except any of .*"; - QTest::newRow("invalid-footer-signature") \ - << "test-invalid-footer-signature.appkg" << "" - << true << false << false << false << nomd << "could not verify the package's developer signature"; -} - -// this test function is a bit of a kitchen sink, but the basic boiler plate -// code of testing the results of an installation is the biggest part and it -// is always the same. -void tst_PackageManager::packageInstallation() -{ - QFETCH(QString, packageName); - QFETCH(QString, updatePackageName); - QFETCH(bool, devSigned); - QFETCH(bool, storeSigned); - QFETCH(bool, expectedSuccess); - QFETCH(bool, updateExpectedSuccess); - QFETCH(QVariantMap, extraMetaData); - QFETCH(QString, errorString); - - QString installationDir = m_pm->installationLocation().value(qSL("path")).toString(); - QString documentDir = m_pm->documentLocation().value(qSL("path")).toString(); - - AllowInstallations allow(storeSigned ? AllowInstallations::RequireStoreSigned - : (devSigned ? AllowInstallations::RequireDevSigned - : AllowInstallations::AllowUnsinged)); - - int lastPass = (updatePackageName.isEmpty() ? 1 : 2); - // pass 1 is the installation / pass 2 is the update (if needed) - for (int pass = 1; pass <= lastPass; ++pass) { - // this makes the results a bit ugly to look at, but it helps with debugging a lot - if (pass > 1) - qInfo("Pass %d", pass); - - // install (or update) the package - - QUrl url = QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/" + (pass == 1 ? packageName : updatePackageName)); - QString taskId = m_pm->startPackageInstallation(url); - QVERIFY(!taskId.isEmpty()); - m_pm->acknowledgePackageInstallation(taskId); - - // check received signals... - - if (pass == 1 ? !expectedSuccess : !updateExpectedSuccess) { - // ...in case of expected failure - - QVERIFY(m_failedSpy->wait(spyTimeout)); - QCOMPARE(m_failedSpy->first()[0].toString(), taskId); - - AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString); - } else { - // ...in case of expected success - - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - QVERIFY(!m_progressSpy->isEmpty()); - QCOMPARE(m_progressSpy->last()[0].toString(), taskId); - QCOMPARE(m_progressSpy->last()[1].toDouble(), double(1)); - - // check files - - //TODO: remove system((QString::fromUtf8("find ") + m_workDir.path()).toLocal8Bit().constData()); - - QVERIFY(QFile::exists(installationDir + qSL("/com.pelagicore.test/.installation-report.yaml"))); - QVERIFY(QDir(documentDir + qSL("/com.pelagicore.test")).exists()); - - QString fileCheckPath = installationDir + "/com.pelagicore.test"; - - // now check the installed files - - QStringList files = QDir(fileCheckPath).entryList(QDir::AllEntries | QDir::NoDotAndDotDot); - files.sort(); - QVERIFY2(files == QStringList({ qSL("icon.png"), qSL("info.yaml"), qSL("test"), QString::fromUtf8("t\xc3\xa4st") }), - qPrintable(files.join(qSL(", ")))); - - QFile f(fileCheckPath + "/test"); - QVERIFY(f.open(QFile::ReadOnly)); - QCOMPARE(f.readAll(), QByteArray(pass == 1 ? "test\n" : "test update\n")); - f.close(); - - // check metadata - QCOMPARE(m_requestingInstallationAcknowledgeSpy->count(), 1); - QVariantMap extra = m_requestingInstallationAcknowledgeSpy->first()[2].toMap(); - QVariantMap extraSigned = m_requestingInstallationAcknowledgeSpy->first()[3].toMap(); - if (extraMetaData.value(qSL("extra")).toMap() != extra) { - qDebug() << "Actual: " << extra; - qDebug() << "Expected: " << extraMetaData.value(qSL("extra")).toMap(); - QVERIFY(extraMetaData == extra); - } - if (extraMetaData.value(qSL("extraSigned")).toMap() != extraSigned) { - qDebug() << "Actual: " << extraSigned; - qDebug() << "Expected: " << extraMetaData.value(qSL("extraSigned")).toMap(); - QVERIFY(extraMetaData == extraSigned); - } - - // check if the meta-data was saved to the installation report correctly - QVERIFY2(m_pm->installedPackageExtraMetaData(qSL("com.pelagicore.test")) == extra, - "Extra meta-data was not correctly saved to installation report"); - QVERIFY2(m_pm->installedPackageExtraSignedMetaData(qSL("com.pelagicore.test")) == extraSigned, - "Extra signed meta-data was not correctly saved to installation report"); - } - if (pass == lastPass && expectedSuccess) { - // remove package again - - clearSignalSpies(); - taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); - QVERIFY(!taskId.isEmpty()); - - // check signals - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - } - clearSignalSpies(); - } - // check that all files are gone - - for (PathLocation pl: { Internal0, Documents0 }) { - QStringList entries = QDir(pathTo(pl)).entryList({ qSL("com.pelagicore.test*") }); - QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + qSL(": ") + entries.join(qSL(", ")))); - } -} - - -Q_DECLARE_METATYPE(std::function) -typedef QMultiMap> FunctionMap; -Q_DECLARE_METATYPE(FunctionMap) - -void tst_PackageManager::simulateErrorConditions_data() -{ - QTest::addColumn("testUpdate"); - QTest::addColumn("errorString"); - QTest::addColumn("functions"); - -#ifdef Q_OS_LINUX - QTest::newRow("applications-dir-read-only") \ - << false << "~could not create installation directory .*" \ - << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0000) == 0; } }, - { "after-failed", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0777) == 0; } } }; - - QTest::newRow("documents-dir-read-only") \ - << false << "~could not create the document directory .*" \ - << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0000) == 0; } }, - { "after-failed", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0777) == 0; } } }; -#endif -} - -void tst_PackageManager::simulateErrorConditions() -{ -#ifndef Q_OS_LINUX - QSKIP("Only tested on Linux"); -#endif - - QFETCH(bool, testUpdate); - QFETCH(QString, errorString); - QFETCH(FunctionMap, functions); - - QString taskId; - - if (testUpdate) { - // the check will run when updating a package, so we need to install it first - - taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); - QVERIFY(!taskId.isEmpty()); - m_pm->acknowledgePackageInstallation(taskId); - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - clearSignalSpies(); - } - - foreach (const auto &f, functions.values(qSL("before-start"))) - QVERIFY(f()); - - taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); - - foreach (const auto &f, functions.values(qSL("after-start"))) - QVERIFY(f()); - - m_pm->acknowledgePackageInstallation(taskId); - - QVERIFY(m_failedSpy->wait(spyTimeout)); - QCOMPARE(m_failedSpy->first()[0].toString(), taskId); - AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString); - clearSignalSpies(); - - foreach (const auto &f, functions.values(qSL("after-failed"))) - QVERIFY(f()); - - if (testUpdate) { - taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); - - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - } -} - - -void tst_PackageManager::cancelPackageInstallation_data() -{ - QTest::addColumn("expectedResult"); - - // please note that the data tag names are used in the actual test function below! - - QTest::newRow("before-started-signal") << true; - QTest::newRow("after-started-signal") << true; - QTest::newRow("after-blocking-until-installation-acknowledge-signal") << true; - QTest::newRow("after-finished-signal") << false; -} - -void tst_PackageManager::cancelPackageInstallation() -{ - QFETCH(bool, expectedResult); - - QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); - QVERIFY(!taskId.isEmpty()); - - if (isDataTag("before-started-signal")) { - QCOMPARE(m_pm->cancelTask(taskId), expectedResult); - } else if (isDataTag("after-started-signal")) { - QVERIFY(m_startedSpy->wait(spyTimeout)); - QCOMPARE(m_startedSpy->first()[0].toString(), taskId); - QCOMPARE(m_pm->cancelTask(taskId), expectedResult); - } else if (isDataTag("after-blocking-until-installation-acknowledge-signal")) { - QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); - QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), taskId); - QCOMPARE(m_pm->cancelTask(taskId), expectedResult); - } else if (isDataTag("after-finished-signal")) { - m_pm->acknowledgePackageInstallation(taskId); - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - QCOMPARE(m_pm->cancelTask(taskId), expectedResult); - } - - if (expectedResult) { - if (!m_startedSpy->isEmpty()) { - QVERIFY(m_failedSpy->wait(spyTimeout)); - QCOMPARE(m_failedSpy->first()[0].toString(), taskId); - QCOMPARE(m_failedSpy->first()[1].toInt(), int(Error::Canceled)); - } - } else { - clearSignalSpies(); - - taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); - QVERIFY(!taskId.isEmpty()); - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - } - clearSignalSpies(); -} - -void tst_PackageManager::parallelPackageInstallation() -{ - QString task1Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); - QVERIFY(!task1Id.isEmpty()); - QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); - QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), task1Id); - - QString task2Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg"))); - QVERIFY(!task2Id.isEmpty()); - m_pm->acknowledgePackageInstallation(task2Id); - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), task2Id); - - clearSignalSpies(); - m_pm->acknowledgePackageInstallation(task1Id); - QVERIFY(m_finishedSpy->wait(spyTimeout)); - QCOMPARE(m_finishedSpy->first()[0].toString(), task1Id); - - clearSignalSpies(); -} - -void tst_PackageManager::validateDnsName_data() -{ - QTest::addColumn("dnsName"); - QTest::addColumn("minParts"); - QTest::addColumn("valid"); - - // passes - QTest::newRow("normal") << "com.pelagicore.test" << 3 << true; - QTest::newRow("shortest") << "c.p.t" << 3 << true; - QTest::newRow("valid-chars") << "1-2.c-d.3.z" << 3 << true; - QTest::newRow("longest-part") << "com.012345678901234567890123456789012345678901234567890123456789012.test" << 3 << true; - QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << 3 << true; - QTest::newRow("max-part-cnt") << "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.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.a.0.12" << 3 << true; - QTest::newRow("one-part-only") << "c" << 1 << true; - - // failures - QTest::newRow("too-few-parts") << "com.pelagicore" << 3 << false; - QTest::newRow("empty-part") << "com..test" << 3 << false; - QTest::newRow("empty") << "" << 3 << false; - QTest::newRow("dot-only") << "." << 3 << false; - QTest::newRow("invalid-char1") << "com.pelagi_core.test" << 3 << false; - QTest::newRow("invalid-char2") << "com.pelagi#core.test" << 3 << false; - QTest::newRow("invalid-char3") << "com.pelagi$core.test" << 3 << false; - QTest::newRow("invalid-char3") << "com.pelagi@core.test" << 3 << false; - QTest::newRow("unicode-char") << QString::fromUtf8("c\xc3\xb6m.pelagicore.test") << 3 << false; - QTest::newRow("upper-case") << "com.Pelagicore.test" << 3 << false; - QTest::newRow("dash-at-start") << "com.-pelagicore.test" << 3 << false; - QTest::newRow("dash-at-end") << "com.pelagicore-.test" << 3 << false; - QTest::newRow("part-too-long") << "com.x012345678901234567890123456789012345678901234567890123456789012.test" << 3 << false; -} - -void tst_PackageManager::validateDnsName() -{ - QFETCH(QString, dnsName); - QFETCH(int, minParts); - QFETCH(bool, valid); - - QString errorString; - bool result = m_pm->validateDnsName(dnsName, minParts); - - QVERIFY2(valid == result, qPrintable(errorString)); -} - -void tst_PackageManager::compareVersions_data() -{ - QTest::addColumn("version1"); - QTest::addColumn("version2"); - QTest::addColumn("result"); - - - QTest::newRow("1") << "" << "" << 0; - QTest::newRow("2") << "0" << "0" << 0; - QTest::newRow("3") << "foo" << "foo" << 0; - QTest::newRow("4") << "1foo" << "1foo" << 0; - QTest::newRow("5") << "foo1" << "foo1" << 0; - QTest::newRow("6") << "13.403.51-alpha2+git" << "13.403.51-alpha2+git" << 0; - QTest::newRow("7") << "1" << "2" << -1; - QTest::newRow("8") << "2" << "1" << 1; - QTest::newRow("9") << "1.0" << "2.0" << -1; - QTest::newRow("10") << "1.99" << "2.0" << -1; - QTest::newRow("11") << "1.9" << "11" << -1; - QTest::newRow("12") << "9" << "10" << -1; - QTest::newRow("12") << "9a" << "10" << -1; - QTest::newRow("13") << "9-a" << "10" << -1; - QTest::newRow("14") << "13.403.51-alpha2+gi" << "13.403.51-alpha2+git" << -1; - QTest::newRow("15") << "13.403.51-alpha1+git" << "13.403.51-alpha2+git" << -1; - QTest::newRow("16") << "13.403.51-alpha2+git" << "13.403.51-beta1+git" << -1; - QTest::newRow("17") << "13.403.51-alpha2+git" << "13.403.52" << -1; - QTest::newRow("18") << "13.403.51-alpha2+git" << "13.403.52-alpha2+git" << -1; - QTest::newRow("19") << "13.403.51-alpha2+git" << "13.404" << -1; - QTest::newRow("20") << "13.402" << "13.403.51-alpha2+git" << -1; - QTest::newRow("21") << "12.403.51-alpha2+git" << "13.403.51-alpha2+git" << -1; -} - -void tst_PackageManager::compareVersions() -{ - QFETCH(QString, version1); - QFETCH(QString, version2); - QFETCH(int, result); - - int cmp = m_pm->compareVersions(version1, version2); - QCOMPARE(cmp, result); - - if (result) { - cmp = m_pm->compareVersions(version2, version1); - QCOMPARE(cmp, -result); - } -} - -static tst_PackageManager *tstPackageManager = nullptr; - -int main(int argc, char **argv) -{ - PackageUtilities::ensureCorrectLocale(); - - try { - Sudo::forkServer(Sudo::DropPrivilegesPermanently); - startedSudoServer = true; - } catch (...) { } - - QCoreApplication a(argc, argv); - tstPackageManager = new tst_PackageManager(&a); - - return QTest::qExec(tstPackageManager, argc, argv); -} - -#include "tst_applicationinstaller.moc" diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt new file mode 100644 index 00000000..1f6dcca8 --- /dev/null +++ b/tests/auto/CMakeLists.txt @@ -0,0 +1,23 @@ + +add_subdirectory(application) +add_subdirectory(applicationinfo) +add_subdirectory(applicationinstaller) +add_subdirectory(configuration) +add_subdirectory(cryptography) +add_subdirectory(debugwrapper) +add_subdirectory(installationreport) +add_subdirectory(main) +add_subdirectory(packagecreator) +add_subdirectory(packageextractor) +add_subdirectory(packager-tool) +#add_subdirectory(qml) +add_subdirectory(runtime) +add_subdirectory(signature) +add_subdirectory(utilities) +add_subdirectory(yaml) + +if(LINUX) + add_subdirectory(systemreader) + add_subdirectory(processreader) + add_subdirectory(sudo) +endif() diff --git a/tests/auto/application/CMakeLists.txt b/tests/auto/application/CMakeLists.txt new file mode 100644 index 00000000..942bc0c3 --- /dev/null +++ b/tests/auto/application/CMakeLists.txt @@ -0,0 +1,30 @@ + +qt_internal_add_test(tst_application + SOURCES + ../error-checking.h + tst_application.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate +) + +# Resources: +set(tst_application_resource_files + "info.yaml" +) + +qt_internal_add_resource(tst_application "tst_application" + PREFIX + "/" + FILES + ${tst_application_resource_files} +) + +qt_internal_extend_target(tst_application CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/application/application.pro b/tests/auto/application/application.pro new file mode 100644 index 00000000..2bdaf9c5 --- /dev/null +++ b/tests/auto/application/application.pro @@ -0,0 +1,13 @@ +TARGET = tst_application + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_application-private \ + appman_manager-private \ + +SOURCES += tst_application.cpp + +OTHER_FILES += info.yaml +RESOURCES += tst_application.qrc diff --git a/tests/auto/application/icon.png b/tests/auto/application/icon.png new file mode 100644 index 00000000..909c66db Binary files /dev/null and b/tests/auto/application/icon.png differ diff --git a/tests/auto/application/info.yaml b/tests/auto/application/info.yaml new file mode 100644 index 00000000..08329bb8 --- /dev/null +++ b/tests/auto/application/info.yaml @@ -0,0 +1,10 @@ +formatType: am-package +formatVersion: 1 +--- +id: pkg.test +name: { en: "Test Package" } +icon: icon.png +applications: +- id: app.test + runtime: qml + code: info.yaml # just to make the test simpler diff --git a/tests/auto/application/tst_application.cpp b/tests/auto/application/tst_application.cpp new file mode 100644 index 00000000..05b155c5 --- /dev/null +++ b/tests/auto/application/tst_application.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "global.h" +#include "application.h" +#include "applicationinfo.h" +#include "packageinfo.h" +#include "package.h" +#include "abstractruntime.h" + +QT_USE_NAMESPACE_AM + +class TestRuntime : public AbstractRuntime +{ + Q_OBJECT + +public: + explicit TestRuntime(AbstractContainer *container, Application *app, AbstractRuntimeManager *manager) + : AbstractRuntime(container, app, manager) + { } + + void setSlowAnimations(bool) override {} + + qint64 applicationProcessId() const override + { + return m_state == Am::Running ? 1 : 0; + } + +public slots: + bool start() override + { + m_state = Am::Running; + return true; + } + + void stop(bool forceKill) override + { + Q_UNUSED(forceKill); + m_state = Am::NotRunning; + } +}; + +class TestRuntimeManager : public AbstractRuntimeManager +{ + Q_OBJECT + +public: + TestRuntimeManager(const QString &id, QObject *parent) + : AbstractRuntimeManager(id, parent) + { } + + static QString defaultIdentifier() { return qSL("foo"); } + + bool inProcess() const override + { + return !AbstractRuntimeManager::inProcess(); + } + + TestRuntime *create(AbstractContainer *container, Application *app) override + { + return new TestRuntime(container, app, this); + } +}; + +class tst_Application : public QObject +{ + Q_OBJECT + +public: + tst_Application(){} + +private slots: + void runtimeDestroyed(); +}; + +// Checks that when the runtime of an application is destroyed +// the application no longer holds a reference to it +void tst_Application::runtimeDestroyed() +{ + auto pi = PackageInfo::fromManifest(qL1S(":/info.yaml")); + auto pkg = new Package(pi); + auto ai = new ApplicationInfo(pi); + auto app = new Application(ai, pkg); + + auto runtimeManager = new TestRuntimeManager(qSL("foo"), qApp); + auto runtime = runtimeManager->create(nullptr, app); + + app->setCurrentRuntime(runtime); + + QCOMPARE(app->currentRuntime(), runtime); + + delete runtime; + + QCOMPARE(app->currentRuntime(), nullptr); + + delete app; + delete runtimeManager; + delete ai; + delete pkg; + delete pi; +} + +QTEST_APPLESS_MAIN(tst_Application) + +#include "tst_application.moc" diff --git a/tests/auto/application/tst_application.qrc b/tests/auto/application/tst_application.qrc new file mode 100644 index 00000000..a24bcd9a --- /dev/null +++ b/tests/auto/application/tst_application.qrc @@ -0,0 +1,5 @@ + + + info.yaml + + diff --git a/tests/auto/applicationinfo/CMakeLists.txt b/tests/auto/applicationinfo/CMakeLists.txt new file mode 100644 index 00000000..5cc7ca36 --- /dev/null +++ b/tests/auto/applicationinfo/CMakeLists.txt @@ -0,0 +1,21 @@ + +qt_internal_add_test(tst_applicationinfo + SOURCES + ../error-checking.h + tst_applicationinfo.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_applicationinfo CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/applicationinfo/applicationinfo.pro b/tests/auto/applicationinfo/applicationinfo.pro new file mode 100644 index 00000000..9fcc7ffe --- /dev/null +++ b/tests/auto/applicationinfo/applicationinfo.pro @@ -0,0 +1,10 @@ +TARGET = tst_applicationinfo + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_application-private \ + appman_manager-private \ + +SOURCES += tst_applicationinfo.cpp diff --git a/tests/auto/applicationinfo/tst_applicationinfo.cpp b/tests/auto/applicationinfo/tst_applicationinfo.cpp new file mode 100644 index 00000000..9dc93292 --- /dev/null +++ b/tests/auto/applicationinfo/tst_applicationinfo.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "global.h" +#include "application.h" +#include "applicationinfo.h" +#include "packageinfo.h" +#include "yamlpackagescanner.h" +#include "exception.h" + +QT_USE_NAMESPACE_AM + +class tst_ApplicationInfo : public QObject +{ + Q_OBJECT + +public: + tst_ApplicationInfo(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + void application_data(); + void application(); + void validApplicationId_data(); + void validApplicationId(); + void validIcon_data(); + void validIcon(); + +private: + QVector m_pkgs; +}; + +tst_ApplicationInfo::tst_ApplicationInfo() +{ } + + +void tst_ApplicationInfo::initTestCase() +{ + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); + + YamlPackageScanner scanner; + QDir baseDir(qL1S(AM_TESTDATA_DIR "manifests")); + const QStringList pkgDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); + for (const QString &pkgDirName : pkgDirNames) { + QDir dir = baseDir.absoluteFilePath(pkgDirName); + try { + PackageInfo *pi = scanner.scan(dir.absoluteFilePath(qSL("info.yaml"))); + QVERIFY(pi); + QCOMPARE(pkgDirName, pi->id()); + m_pkgs << pi; + } catch (const std::exception &e) { + QFAIL(e.what()); + } + } + + QCOMPARE(m_pkgs.size(), 2); +} + +void tst_ApplicationInfo::cleanupTestCase() +{ + qDeleteAll(m_pkgs); +} + +void tst_ApplicationInfo::application_data() +{ + QTest::addColumn("id"); + + QTest::newRow("normal") << "com.pelagicore.test"; + QTest::newRow("json") << "com.pelagicore.json-legacy"; +} + +void tst_ApplicationInfo::application() +{ + QFETCH(QString, id); + + QString name = QString::fromLatin1(AM_TESTDATA_DIR "manifests/%1/info.yaml").arg(id); + + YamlPackageScanner scanner; + PackageInfo *pkg; + try { + pkg = scanner.scan(name); + QVERIFY(pkg); + } catch (const std::exception &e) { + QFAIL(e.what()); + } + + QCOMPARE(pkg->id(), id); + QCOMPARE(QFileInfo(pkg->icon()).fileName(), qSL("icon.png")); + QCOMPARE(pkg->names().size(), 2); + QCOMPARE(pkg->names().value(qSL("en")), qSL("english")); + QCOMPARE(pkg->names().value(qSL("de")), qSL("deutsch")); + QCOMPARE(pkg->name(qSL("en")), qSL("english")); + QCOMPARE(pkg->isBuiltIn(), false); + QCOMPARE(pkg->categories().size(), 2); + QVERIFY(pkg->categories().startsWith(qSL("bar"))); + QVERIFY(pkg->categories().endsWith(qSL("foo"))); + + ApplicationInfo *app = pkg->applications().size() == 1 ? pkg->applications().first() : nullptr; + QVERIFY(app); + QCOMPARE(QFileInfo(app->codeFilePath()).fileName(), qSL("Test.qml")); + QCOMPARE(app->runtimeName(), qSL("qml")); + QCOMPARE(app->runtimeParameters().size(), 1); + QCOMPARE(app->runtimeParameters().value(qSL("loadDummyData")).toBool(), true); + QCOMPARE(app->capabilities().size(), 2); + QVERIFY(app->capabilities().startsWith(qSL("cameraAccess"))); + QVERIFY(app->capabilities().endsWith(qSL("locationAccess"))); + + // legacy + QCOMPARE(app->supportedMimeTypes().size(), 2); + QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain"))); + QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto"))); + + delete pkg; +} + +void tst_ApplicationInfo::validApplicationId_data() +{ + QTest::addColumn("appId"); + QTest::addColumn("valid"); + + // passes + QTest::newRow("normal") << "Test" << true; + QTest::newRow("shortest") << "t" << true; + QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+@" << true; + QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << true; + + // failures + QTest::newRow("empty") << "" << false; + QTest::newRow("space-only") << " " << false; + QTest::newRow("space-only2") << " " << false; + QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false; + QTest::newRow("invalid-char<") << "t<" << false; + QTest::newRow("invalid-char>") << "t>" << false; + QTest::newRow("invalid-char:") << "t:" << false; + QTest::newRow("invalid-char-quote") << "t\"" << false; + QTest::newRow("invalid-char/") << "t/" << false; + QTest::newRow("invalid-char\\") << "t\\" << false; + QTest::newRow("invalid-char|") << "t|" << false; + QTest::newRow("invalid-char?") << "t?" << false; + QTest::newRow("invalid-char*") << "t*" << false; + QTest::newRow("control-char") << "t\t" << false; +} + +void tst_ApplicationInfo::validApplicationId() +{ + QFETCH(QString, appId); + QFETCH(bool, valid); + + QString errorString; + bool result = PackageInfo::isValidApplicationId(appId, &errorString); + + QVERIFY2(valid == result, qPrintable(errorString)); +} + +void tst_ApplicationInfo::validIcon_data() +{ + QTest::addColumn("icon"); + QTest::addColumn("isValid"); + + // valid + QTest::newRow("'icon.png' is valid") << "icon.png" << true; + QTest::newRow("'foo.bar' is valid") << "foo.bar" << true; + QTest::newRow("'foo' is valid") << "foo" << true; + + // invalid + QTest::newRow("empty is invalid") << "" << false; + QTest::newRow("'foo/icon.png' is invalid") << "foo/icon.png" << false; + QTest::newRow("'../icon.png' is invalid") << "../icon.png" << false; + QTest::newRow("'icon.png/' is invalid") << "icon.png/" << false; + QTest::newRow("'/foo' is invalid") << "/foo" << false; +} + +void tst_ApplicationInfo::validIcon() +{ + QFETCH(QString, icon); + QFETCH(bool, isValid); + + QString errorString; + bool result = PackageInfo::isValidIcon(icon, &errorString); + + QCOMPARE(result, isValid); +} + +QTEST_APPLESS_MAIN(tst_ApplicationInfo) + +#include "tst_applicationinfo.moc" + diff --git a/tests/auto/applicationinstaller/CMakeLists.txt b/tests/auto/applicationinstaller/CMakeLists.txt new file mode 100644 index 00000000..3da4d358 --- /dev/null +++ b/tests/auto/applicationinstaller/CMakeLists.txt @@ -0,0 +1,25 @@ + +qt_internal_add_test(tst_applicationinstaller + SOURCES + ../error-checking.h + tst_applicationinstaller.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate + Qt::AppManPackagePrivate +) + +#### Keys ignored in scope 1:.:.:applicationinstaller.pro:: +# COVERAGE_RUNTIME = "sudo" + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_applicationinstaller CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/applicationinstaller/applicationinstaller.pro b/tests/auto/applicationinstaller/applicationinstaller.pro new file mode 100644 index 00000000..b84ffac4 --- /dev/null +++ b/tests/auto/applicationinstaller/applicationinstaller.pro @@ -0,0 +1,13 @@ +TARGET = tst_applicationinstaller + +COVERAGE_RUNTIME = sudo + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_application-private \ + appman_package-private \ + appman_manager-private \ + +SOURCES += tst_applicationinstaller.cpp diff --git a/tests/auto/applicationinstaller/tst_applicationinstaller.cpp b/tests/auto/applicationinstaller/tst_applicationinstaller.cpp new file mode 100644 index 00000000..15be7898 --- /dev/null +++ b/tests/auto/applicationinstaller/tst_applicationinstaller.cpp @@ -0,0 +1,793 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include "packagemanager.h" +#include "packagedatabase.h" +#include "package.h" +#include "applicationinfo.h" +#include "sudo.h" +#include "utilities.h" +#include "error.h" +#include "private/packageutilities_p.h" +#include "runtimefactory.h" +#include "qmlinprocessruntime.h" +#include "packageutilities.h" + +#include "../error-checking.h" + +QT_USE_NAMESPACE_AM + +static bool startedSudoServer = false; +static QString sudoServerError; + +static int spyTimeout = 5000; // shorthand for specifying QSignalSpy timeouts + +// RAII to reset the global attribute +class AllowInstallations +{ +public: + enum Type { + AllowUnsinged, + RequireDevSigned, + RequireStoreSigned + }; + + AllowInstallations(Type t) + : m_oldUnsigned(PackageManager::instance()->allowInstallationOfUnsignedPackages()) + , m_oldDevMode(PackageManager::instance()->developmentMode()) + { + switch (t) { + case AllowUnsinged: + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); + PackageManager::instance()->setDevelopmentMode(false); + break; + case RequireDevSigned: + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); + PackageManager::instance()->setDevelopmentMode(true); + break; + case RequireStoreSigned: + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); + PackageManager::instance()->setDevelopmentMode(false); + break; + } + } + ~AllowInstallations() + { + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned); + PackageManager::instance()->setDevelopmentMode(m_oldDevMode); + } +private: + bool m_oldUnsigned; + bool m_oldDevMode; +}; + +class tst_PackageManager : public QObject +{ + Q_OBJECT + +public: + tst_PackageManager(QObject *parent = nullptr); + ~tst_PackageManager(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void init(); + void cleanup(); + + //TODO: test AI::cleanupBrokenInstallations() before calling cleanup() the first time! + + void packageInstallation_data(); + void packageInstallation(); + + void simulateErrorConditions_data(); + void simulateErrorConditions(); + + void cancelPackageInstallation_data(); + void cancelPackageInstallation(); + + void parallelPackageInstallation(); + + void validateDnsName_data(); + void validateDnsName(); + + void compareVersions_data(); + void compareVersions(); + +public: + enum PathLocation { + Internal0, + Documents0, + + PathLocationCount + }; + +private: + QString pathTo(const QString &sub = QString()) + { + return pathTo(PathLocationCount, sub); + } + + QString pathTo(PathLocation pathLocation, const QString &sub = QString()) + { + QString base; + switch (pathLocation) { + case Internal0: base = qSL("internal"); break; + case Documents0: base = qSL("documents"); break; + default: break; + } + + QDir workDir(m_workDir.path()); + + if (base.isEmpty() && sub.isEmpty()) + base = workDir.absolutePath(); + else if (sub.isEmpty()) + base = workDir.absoluteFilePath(base); + else if (base.isEmpty()) + base = workDir.absoluteFilePath(sub); + else + base = workDir.absoluteFilePath(base + '/' + sub); + + if (QDir(base).exists()) + return base + '/'; + else + return base; + } + + void clearSignalSpies() + { + m_startedSpy->clear(); + m_requestingInstallationAcknowledgeSpy->clear(); + m_blockingUntilInstallationAcknowledgeSpy->clear(); + m_progressSpy->clear(); + m_finishedSpy->clear(); + m_failedSpy->clear(); + } + + static bool isDataTag(const char *tag) + { + return !qstrcmp(tag, QTest::currentDataTag()); + } + +private: + SudoClient *m_sudo = nullptr; + bool m_fakeSudo = false; + + QTemporaryDir m_workDir; + QString m_hardwareId; + PackageManager *m_pm = nullptr; + QSignalSpy *m_startedSpy = nullptr; + QSignalSpy *m_requestingInstallationAcknowledgeSpy = nullptr; + QSignalSpy *m_blockingUntilInstallationAcknowledgeSpy = nullptr; + QSignalSpy *m_progressSpy = nullptr; + QSignalSpy *m_finishedSpy = nullptr; + QSignalSpy *m_failedSpy = nullptr; +}; + + +tst_PackageManager::tst_PackageManager(QObject *parent) + : QObject(parent) +{ } + +tst_PackageManager::~tst_PackageManager() +{ + if (m_workDir.isValid()) { + if (m_sudo) + m_sudo->removeRecursive(m_workDir.path()); + else + recursiveOperation(m_workDir.path(), safeRemove); + } + + delete m_failedSpy; + delete m_finishedSpy; + delete m_progressSpy; + delete m_blockingUntilInstallationAcknowledgeSpy; + delete m_requestingInstallationAcknowledgeSpy; + delete m_startedSpy; + + delete m_pm; +} + +void tst_PackageManager::initTestCase() +{ + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); + + bool verbose = qEnvironmentVariableIsSet("AM_VERBOSE_TEST"); + if (!verbose) + QLoggingCategory::setFilterRules(qSL("am.installer.debug=false")); + qInfo() << "Verbose mode is" << (verbose ? "on" : "off") << "(change by (un)setting $AM_VERBOSE_TEST)"; + + spyTimeout *= timeoutFactor(); + + QVERIFY(PackageUtilities::checkCorrectLocale()); + QVERIFY2(startedSudoServer, qPrintable(sudoServerError)); + m_sudo = SudoClient::instance(); + QVERIFY(m_sudo); + m_fakeSudo = m_sudo->isFallbackImplementation(); + + // create a temporary dir (plus sub-dirs) for everything created by this test run + QVERIFY(m_workDir.isValid()); + + // make sure we have a valid hardware-id + m_hardwareId = qSL("foobar"); + + for (int i = 0; i < PathLocationCount; ++i) + QVERIFY(QDir().mkdir(pathTo(PathLocation(i)))); + + // finally, instantiate the PackageManager and a bunch of signal-spies for its signals + try { + PackageDatabase *pdb = new PackageDatabase(QStringList(), pathTo(Internal0)); + m_pm = PackageManager::createInstance(pdb, pathTo(Documents0)); + m_pm->setHardwareId(m_hardwareId); + m_pm->enableInstaller(); + + // simulate the ApplicationManager stopping blocked applications + connect(&m_pm->internalSignals, &PackageManagerInternalSignals::registerApplication, + this, [this](ApplicationInfo *ai, Package *package) { + connect(package, &Package::blockedChanged, this, [ai, package](bool blocked) { + if (package->info()->applications().contains(ai) && blocked) + package->applicationStoppedDueToBlock(ai->id()); + }); + }); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } + + const QVariantMap iloc = m_pm->installationLocation(); + QCOMPARE(iloc.size(), 3); + QCOMPARE(iloc.value(qSL("path")).toString(), pathTo(Internal0)); + QVERIFY(iloc.value(qSL("deviceSize")).toLongLong() > 0); + QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() > 0); + QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() < iloc.value(qSL("deviceSize")).toLongLong()); + + const QVariantMap dloc = m_pm->documentLocation(); + QCOMPARE(dloc.size(), 3); + QCOMPARE(dloc.value(qSL("path")).toString(), pathTo(Documents0)); + QVERIFY(dloc.value(qSL("deviceSize")).toLongLong() > 0); + QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() > 0); + QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() < dloc.value(qSL("deviceSize")).toLongLong()); + + m_startedSpy = new QSignalSpy(m_pm, &PackageManager::taskStarted); + m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskRequestingInstallationAcknowledge); + m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskBlockingUntilInstallationAcknowledge); + m_progressSpy = new QSignalSpy(m_pm, &PackageManager::taskProgressChanged); + m_finishedSpy = new QSignalSpy(m_pm, &PackageManager::taskFinished); + m_failedSpy = new QSignalSpy(m_pm, &PackageManager::taskFailed); + + // crypto stuff - we need to load the root CA and developer CA certificates + + QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt")); + QFile storecaFile(qL1S(AM_TESTDATA_DIR "certificates/store.crt")); + QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt")); + QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); + QVERIFY2(storecaFile.open(QIODevice::ReadOnly), qPrintable(storecaFile.errorString())); + QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(caFile.errorString())); + + QList chainOfTrust; + chainOfTrust << devcaFile.readAll() << caFile.readAll(); + QVERIFY(!chainOfTrust.at(0).isEmpty()); + QVERIFY(!chainOfTrust.at(1).isEmpty()); + m_pm->setCACertificates(chainOfTrust); + + // we do not require valid store signatures for this test run + + m_pm->setDevelopmentMode(true); + + // make sure we have a valid runtime available. The important part is + // that we have a runtime called "native" - the functionality does not matter. + RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("native"))); +} + +void tst_PackageManager::cleanupTestCase() +{ + // the real cleanup happens in ~tst_PackageManager, since we also need + // to call this cleanup from the crash handler +} + +void tst_PackageManager::init() +{ + // start with a fresh App1 dir on each test run + + if (!QDir(pathTo(Internal0)).exists()) + QVERIFY(QDir().mkdir(pathTo(Internal0))); +} + +void tst_PackageManager::cleanup() +{ + // this helps with reducing the amount of cleanup work required + // at the end of each test + + try { + m_pm->cleanupBrokenInstallations(); + } catch (const Exception &e) { + QFAIL(e.what()); + } + + clearSignalSpies(); + recursiveOperation(pathTo(Internal0), safeRemove); +} + +void tst_PackageManager::packageInstallation_data() +{ + QTest::addColumn("packageName"); + QTest::addColumn("updatePackageName"); + QTest::addColumn("devSigned"); + QTest::addColumn("storeSigned"); + QTest::addColumn("expectedSuccess"); + QTest::addColumn("updateExpectedSuccess"); + QTest::addColumn("extraMetaData"); + QTest::addColumn("errorString"); // start with ~ to create a RegExp + + QVariantMap nomd { }; // no meta-data + QVariantMap extramd = QVariantMap { + { "extra", QVariantMap { + { "array", QVariantList { 1, 2 } }, + { "foo", "bar" }, + { "foo2","bar2" }, + { "key", "value" } } }, + { "extraSigned", QVariantMap { + { "sfoo", "sbar" }, + { "sfoo2", "sbar2" }, + { "signed-key", "signed-value" }, + { "signed-object", QVariantMap { { "k1", "v1" }, { "k2", "v2" } } } + } } + }; + + QTest::newRow("normal") \ + << "test.appkg" << "test-update.appkg" + << false << false << true << true << nomd<< ""; + QTest::newRow("no-dev-signed") \ + << "test.appkg" << "" + << true << false << false << false << nomd << "cannot install unsigned packages"; + QTest::newRow("dev-signed") \ + << "test-dev-signed.appkg" << "test-update-dev-signed.appkg" + << true << false << true << true << nomd << ""; + QTest::newRow("no-store-signed") \ + << "test.appkg" << "" + << false << true << false << false << nomd << "cannot install unsigned packages"; + QTest::newRow("no-store-but-dev-signed") \ + << "test-dev-signed.appkg" << "" + << false << true << false << false << nomd << "cannot install development packages on consumer devices"; + QTest::newRow("store-signed") \ + << "test-store-signed.appkg" << "" + << false << true << true << false << nomd << ""; + QTest::newRow("extra-metadata") \ + << "test-extra.appkg" << "" + << false << false << true << false << extramd << ""; + QTest::newRow("extra-metadata-dev-signed") \ + << "test-extra-dev-signed.appkg" << "" + << true << false << true << false << extramd << ""; + QTest::newRow("invalid-file-order") \ + << "test-invalid-file-order.appkg" << "" + << false << false << false << false << nomd << "The package icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'"; + QTest::newRow("invalid-header-format") \ + << "test-invalid-header-formatversion.appkg" << "" + << false << false << false << false << nomd << "metadata has an invalid format specification: wrong header: expected type 'am-package-header', version '2' or type 'am-package-header', version '1', but instead got type 'am-package-header', version '0'"; + QTest::newRow("invalid-header-diskspaceused") \ + << "test-invalid-header-diskspaceused.appkg" << "" + << false << false << false << false << nomd << "metadata has an invalid diskSpaceUsed field (0)"; + QTest::newRow("invalid-header-id") \ + << "test-invalid-header-id.appkg" << "" + << false << false << false << false << nomd << "metadata has an invalid packageId field (:invalid)"; + QTest::newRow("non-matching-header-id") \ + << "test-non-matching-header-id.appkg" << "" + << false << false << false << false << nomd << "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match"; + QTest::newRow("tampered-extra-signed-header") \ + << "test-tampered-extra-signed-header.appkg" << "" + << false << false << false << false << nomd << "~package digest mismatch.*"; + QTest::newRow("invalid-info.yaml") \ + << "test-invalid-info.appkg" << "" + << false << false << false << false << nomd << "~.*did not find expected key.*"; + QTest::newRow("invalid-info.yaml-id") \ + << "test-invalid-info-id.appkg" << "" + << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid package-id: must consist of printable ASCII characters only, except any of .*"; + QTest::newRow("invalid-footer-signature") \ + << "test-invalid-footer-signature.appkg" << "" + << true << false << false << false << nomd << "could not verify the package's developer signature"; +} + +// this test function is a bit of a kitchen sink, but the basic boiler plate +// code of testing the results of an installation is the biggest part and it +// is always the same. +void tst_PackageManager::packageInstallation() +{ + QFETCH(QString, packageName); + QFETCH(QString, updatePackageName); + QFETCH(bool, devSigned); + QFETCH(bool, storeSigned); + QFETCH(bool, expectedSuccess); + QFETCH(bool, updateExpectedSuccess); + QFETCH(QVariantMap, extraMetaData); + QFETCH(QString, errorString); + + QString installationDir = m_pm->installationLocation().value(qSL("path")).toString(); + QString documentDir = m_pm->documentLocation().value(qSL("path")).toString(); + + AllowInstallations allow(storeSigned ? AllowInstallations::RequireStoreSigned + : (devSigned ? AllowInstallations::RequireDevSigned + : AllowInstallations::AllowUnsinged)); + + int lastPass = (updatePackageName.isEmpty() ? 1 : 2); + // pass 1 is the installation / pass 2 is the update (if needed) + for (int pass = 1; pass <= lastPass; ++pass) { + // this makes the results a bit ugly to look at, but it helps with debugging a lot + if (pass > 1) + qInfo("Pass %d", pass); + + // install (or update) the package + + QUrl url = QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/" + (pass == 1 ? packageName : updatePackageName)); + QString taskId = m_pm->startPackageInstallation(url); + QVERIFY(!taskId.isEmpty()); + m_pm->acknowledgePackageInstallation(taskId); + + // check received signals... + + if (pass == 1 ? !expectedSuccess : !updateExpectedSuccess) { + // ...in case of expected failure + + QVERIFY(m_failedSpy->wait(spyTimeout)); + QCOMPARE(m_failedSpy->first()[0].toString(), taskId); + + AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString); + } else { + // ...in case of expected success + + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + QVERIFY(!m_progressSpy->isEmpty()); + QCOMPARE(m_progressSpy->last()[0].toString(), taskId); + QCOMPARE(m_progressSpy->last()[1].toDouble(), double(1)); + + // check files + + //TODO: remove system((QString::fromUtf8("find ") + m_workDir.path()).toLocal8Bit().constData()); + + QVERIFY(QFile::exists(installationDir + qSL("/com.pelagicore.test/.installation-report.yaml"))); + QVERIFY(QDir(documentDir + qSL("/com.pelagicore.test")).exists()); + + QString fileCheckPath = installationDir + "/com.pelagicore.test"; + + // now check the installed files + + QStringList files = QDir(fileCheckPath).entryList(QDir::AllEntries | QDir::NoDotAndDotDot); + files.sort(); + QVERIFY2(files == QStringList({ qSL("icon.png"), qSL("info.yaml"), qSL("test"), QString::fromUtf8("t\xc3\xa4st") }), + qPrintable(files.join(qSL(", ")))); + + QFile f(fileCheckPath + "/test"); + QVERIFY(f.open(QFile::ReadOnly)); + QCOMPARE(f.readAll(), QByteArray(pass == 1 ? "test\n" : "test update\n")); + f.close(); + + // check metadata + QCOMPARE(m_requestingInstallationAcknowledgeSpy->count(), 1); + QVariantMap extra = m_requestingInstallationAcknowledgeSpy->first()[2].toMap(); + QVariantMap extraSigned = m_requestingInstallationAcknowledgeSpy->first()[3].toMap(); + if (extraMetaData.value(qSL("extra")).toMap() != extra) { + qDebug() << "Actual: " << extra; + qDebug() << "Expected: " << extraMetaData.value(qSL("extra")).toMap(); + QVERIFY(extraMetaData == extra); + } + if (extraMetaData.value(qSL("extraSigned")).toMap() != extraSigned) { + qDebug() << "Actual: " << extraSigned; + qDebug() << "Expected: " << extraMetaData.value(qSL("extraSigned")).toMap(); + QVERIFY(extraMetaData == extraSigned); + } + + // check if the meta-data was saved to the installation report correctly + QVERIFY2(m_pm->installedPackageExtraMetaData(qSL("com.pelagicore.test")) == extra, + "Extra meta-data was not correctly saved to installation report"); + QVERIFY2(m_pm->installedPackageExtraSignedMetaData(qSL("com.pelagicore.test")) == extraSigned, + "Extra signed meta-data was not correctly saved to installation report"); + } + if (pass == lastPass && expectedSuccess) { + // remove package again + + clearSignalSpies(); + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); + QVERIFY(!taskId.isEmpty()); + + // check signals + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + } + clearSignalSpies(); + } + // check that all files are gone + + for (PathLocation pl: { Internal0, Documents0 }) { + QStringList entries = QDir(pathTo(pl)).entryList({ qSL("com.pelagicore.test*") }); + QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + qSL(": ") + entries.join(qSL(", ")))); + } +} + + +Q_DECLARE_METATYPE(std::function) +typedef QMultiMap> FunctionMap; +Q_DECLARE_METATYPE(FunctionMap) + +void tst_PackageManager::simulateErrorConditions_data() +{ + QTest::addColumn("testUpdate"); + QTest::addColumn("errorString"); + QTest::addColumn("functions"); + +#ifdef Q_OS_LINUX + QTest::newRow("applications-dir-read-only") \ + << false << "~could not create installation directory .*" \ + << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0000) == 0; } }, + { "after-failed", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0777) == 0; } } }; + + QTest::newRow("documents-dir-read-only") \ + << false << "~could not create the document directory .*" \ + << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0000) == 0; } }, + { "after-failed", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0777) == 0; } } }; +#endif +} + +void tst_PackageManager::simulateErrorConditions() +{ +#ifndef Q_OS_LINUX + QSKIP("Only tested on Linux"); +#endif + + QFETCH(bool, testUpdate); + QFETCH(QString, errorString); + QFETCH(FunctionMap, functions); + + QString taskId; + + if (testUpdate) { + // the check will run when updating a package, so we need to install it first + + taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); + QVERIFY(!taskId.isEmpty()); + m_pm->acknowledgePackageInstallation(taskId); + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + clearSignalSpies(); + } + + foreach (const auto &f, functions.values(qSL("before-start"))) + QVERIFY(f()); + + taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); + + foreach (const auto &f, functions.values(qSL("after-start"))) + QVERIFY(f()); + + m_pm->acknowledgePackageInstallation(taskId); + + QVERIFY(m_failedSpy->wait(spyTimeout)); + QCOMPARE(m_failedSpy->first()[0].toString(), taskId); + AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString); + clearSignalSpies(); + + foreach (const auto &f, functions.values(qSL("after-failed"))) + QVERIFY(f()); + + if (testUpdate) { + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); + + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + } +} + + +void tst_PackageManager::cancelPackageInstallation_data() +{ + QTest::addColumn("expectedResult"); + + // please note that the data tag names are used in the actual test function below! + + QTest::newRow("before-started-signal") << true; + QTest::newRow("after-started-signal") << true; + QTest::newRow("after-blocking-until-installation-acknowledge-signal") << true; + QTest::newRow("after-finished-signal") << false; +} + +void tst_PackageManager::cancelPackageInstallation() +{ + QFETCH(bool, expectedResult); + + QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); + QVERIFY(!taskId.isEmpty()); + + if (isDataTag("before-started-signal")) { + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); + } else if (isDataTag("after-started-signal")) { + QVERIFY(m_startedSpy->wait(spyTimeout)); + QCOMPARE(m_startedSpy->first()[0].toString(), taskId); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); + } else if (isDataTag("after-blocking-until-installation-acknowledge-signal")) { + QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); + QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), taskId); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); + } else if (isDataTag("after-finished-signal")) { + m_pm->acknowledgePackageInstallation(taskId); + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); + } + + if (expectedResult) { + if (!m_startedSpy->isEmpty()) { + QVERIFY(m_failedSpy->wait(spyTimeout)); + QCOMPARE(m_failedSpy->first()[0].toString(), taskId); + QCOMPARE(m_failedSpy->first()[1].toInt(), int(Error::Canceled)); + } + } else { + clearSignalSpies(); + + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); + QVERIFY(!taskId.isEmpty()); + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); + } + clearSignalSpies(); +} + +void tst_PackageManager::parallelPackageInstallation() +{ + QString task1Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); + QVERIFY(!task1Id.isEmpty()); + QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); + QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), task1Id); + + QString task2Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg"))); + QVERIFY(!task2Id.isEmpty()); + m_pm->acknowledgePackageInstallation(task2Id); + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), task2Id); + + clearSignalSpies(); + m_pm->acknowledgePackageInstallation(task1Id); + QVERIFY(m_finishedSpy->wait(spyTimeout)); + QCOMPARE(m_finishedSpy->first()[0].toString(), task1Id); + + clearSignalSpies(); +} + +void tst_PackageManager::validateDnsName_data() +{ + QTest::addColumn("dnsName"); + QTest::addColumn("minParts"); + QTest::addColumn("valid"); + + // passes + QTest::newRow("normal") << "com.pelagicore.test" << 3 << true; + QTest::newRow("shortest") << "c.p.t" << 3 << true; + QTest::newRow("valid-chars") << "1-2.c-d.3.z" << 3 << true; + QTest::newRow("longest-part") << "com.012345678901234567890123456789012345678901234567890123456789012.test" << 3 << true; + QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << 3 << true; + QTest::newRow("max-part-cnt") << "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.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.a.0.12" << 3 << true; + QTest::newRow("one-part-only") << "c" << 1 << true; + + // failures + QTest::newRow("too-few-parts") << "com.pelagicore" << 3 << false; + QTest::newRow("empty-part") << "com..test" << 3 << false; + QTest::newRow("empty") << "" << 3 << false; + QTest::newRow("dot-only") << "." << 3 << false; + QTest::newRow("invalid-char1") << "com.pelagi_core.test" << 3 << false; + QTest::newRow("invalid-char2") << "com.pelagi#core.test" << 3 << false; + QTest::newRow("invalid-char3") << "com.pelagi$core.test" << 3 << false; + QTest::newRow("invalid-char3") << "com.pelagi@core.test" << 3 << false; + QTest::newRow("unicode-char") << QString::fromUtf8("c\xc3\xb6m.pelagicore.test") << 3 << false; + QTest::newRow("upper-case") << "com.Pelagicore.test" << 3 << false; + QTest::newRow("dash-at-start") << "com.-pelagicore.test" << 3 << false; + QTest::newRow("dash-at-end") << "com.pelagicore-.test" << 3 << false; + QTest::newRow("part-too-long") << "com.x012345678901234567890123456789012345678901234567890123456789012.test" << 3 << false; +} + +void tst_PackageManager::validateDnsName() +{ + QFETCH(QString, dnsName); + QFETCH(int, minParts); + QFETCH(bool, valid); + + QString errorString; + bool result = m_pm->validateDnsName(dnsName, minParts); + + QVERIFY2(valid == result, qPrintable(errorString)); +} + +void tst_PackageManager::compareVersions_data() +{ + QTest::addColumn("version1"); + QTest::addColumn("version2"); + QTest::addColumn("result"); + + + QTest::newRow("1") << "" << "" << 0; + QTest::newRow("2") << "0" << "0" << 0; + QTest::newRow("3") << "foo" << "foo" << 0; + QTest::newRow("4") << "1foo" << "1foo" << 0; + QTest::newRow("5") << "foo1" << "foo1" << 0; + QTest::newRow("6") << "13.403.51-alpha2+git" << "13.403.51-alpha2+git" << 0; + QTest::newRow("7") << "1" << "2" << -1; + QTest::newRow("8") << "2" << "1" << 1; + QTest::newRow("9") << "1.0" << "2.0" << -1; + QTest::newRow("10") << "1.99" << "2.0" << -1; + QTest::newRow("11") << "1.9" << "11" << -1; + QTest::newRow("12") << "9" << "10" << -1; + QTest::newRow("12") << "9a" << "10" << -1; + QTest::newRow("13") << "9-a" << "10" << -1; + QTest::newRow("14") << "13.403.51-alpha2+gi" << "13.403.51-alpha2+git" << -1; + QTest::newRow("15") << "13.403.51-alpha1+git" << "13.403.51-alpha2+git" << -1; + QTest::newRow("16") << "13.403.51-alpha2+git" << "13.403.51-beta1+git" << -1; + QTest::newRow("17") << "13.403.51-alpha2+git" << "13.403.52" << -1; + QTest::newRow("18") << "13.403.51-alpha2+git" << "13.403.52-alpha2+git" << -1; + QTest::newRow("19") << "13.403.51-alpha2+git" << "13.404" << -1; + QTest::newRow("20") << "13.402" << "13.403.51-alpha2+git" << -1; + QTest::newRow("21") << "12.403.51-alpha2+git" << "13.403.51-alpha2+git" << -1; +} + +void tst_PackageManager::compareVersions() +{ + QFETCH(QString, version1); + QFETCH(QString, version2); + QFETCH(int, result); + + int cmp = m_pm->compareVersions(version1, version2); + QCOMPARE(cmp, result); + + if (result) { + cmp = m_pm->compareVersions(version2, version1); + QCOMPARE(cmp, -result); + } +} + +static tst_PackageManager *tstPackageManager = nullptr; + +int main(int argc, char **argv) +{ + PackageUtilities::ensureCorrectLocale(); + + try { + Sudo::forkServer(Sudo::DropPrivilegesPermanently); + startedSudoServer = true; + } catch (...) { } + + QCoreApplication a(argc, argv); + tstPackageManager = new tst_PackageManager(&a); + + return QTest::qExec(tstPackageManager, argc, argv); +} + +#include "tst_applicationinstaller.moc" diff --git a/tests/auto/configuration/CMakeLists.txt b/tests/auto/configuration/CMakeLists.txt new file mode 100644 index 00000000..58eeed5f --- /dev/null +++ b/tests/auto/configuration/CMakeLists.txt @@ -0,0 +1,31 @@ + +qt_internal_add_test(tst_configuration + SOURCES + ../error-checking.h + tst_configuration.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate + Qt::AppManMainPrivate +) + +# Resources: +set(qmake_immediate_resource_files + "data/config1.yaml" + "data/config2.yaml" + "data/empty.yaml" +) + +qt_internal_add_resource(tst_configuration "qmake_immediate" + PREFIX + "/" + FILES + ${qmake_immediate_resource_files} +) + +qt_internal_extend_target(tst_configuration CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/configuration/configuration.pro b/tests/auto/configuration/configuration.pro new file mode 100644 index 00000000..da3ff241 --- /dev/null +++ b/tests/auto/configuration/configuration.pro @@ -0,0 +1,12 @@ +TARGET = tst_configuration + +include($$PWD/../tests.pri) + +QT *= appman_common-private appman_main-private + +SOURCES += tst_configuration.cpp + +RESOURCES += \ + data/empty.yaml \ + data/config1.yaml \ + data/config2.yaml \ diff --git a/tests/auto/configuration/data/config1.yaml b/tests/auto/configuration/data/config1.yaml new file mode 100644 index 00000000..06954344 --- /dev/null +++ b/tests/auto/configuration/data/config1.yaml @@ -0,0 +1,98 @@ +formatVersion: 1 +formatType: am-configuration +--- +runtimes: + r-test: + r-parameter: r-value + +containers: + selection: selectionFunction + c-test: + c-parameter: c-value + +intents: + disable: true + timeouts: + disambiguation: 1 + startApplication: 2 + replyFromApplication: 3 + replyFromSystem: 4 + +plugins: + startup: [ s1, s2 ] + container: [ c1, c2 ] + +logging: + dlt: + id: 'dltid' + description: 'dltdesc' + rules: [ lr1, lr2 ] + messagePattern: 'msgPattern' + useAMConsoleLogger: true + +installer: + disable: true + caCertificates: [ cert1, cert2 ] + +dbus: + iface1: + register: 'foobus' + +quicklaunch: + idleLoad: 0.5 + runtimesPerContainer: 5 + +ui: + opengl: + desktopProfile: 'compatibility' + esMajorVersion: 5 + esMinorVersion: 15 + enableTouchEmulation: true + iconThemeSearchPaths: [ itsp1, itsp2 ] + iconThemeName: mytheme + style: mystyle + loadDummyData: true + importPaths: [ ip1, ip2 ] + pluginPaths: [ pp1, pp2 ] + windowIcon: 'icon.png' + fullscreen: true + mainQml: main.qml + resources: [ r1, r2 ] + +applications: + builtinAppsManifestDir: 'builtin-dir' + installationDir: 'installation-dir' + documentDir: 'doc-dir' + +crashAction: + printBacktrace: true + printQmlStack: true + waitForGdbAttach: true + dumpCore: true + +systemProperties: + public: + public-prop: public-value + protected: + protected-prop: protected-value + private: + private-prop: private-value + +flags: + forceSingleProcess: true + forceMultiProcess: true + noSecurity: true + developmentMode: true + noUiWatchdog: true + +wayland: + socketName: "my-wlsock-42" + extraSockets: + - path: path-es1 + permissions: 0440 + userId: 1 + groupId: 2 + - path: path-es2 + permissions: 0222 + userId: 3 + groupId: 4 diff --git a/tests/auto/configuration/data/config2.yaml b/tests/auto/configuration/data/config2.yaml new file mode 100644 index 00000000..cd9d9766 --- /dev/null +++ b/tests/auto/configuration/data/config2.yaml @@ -0,0 +1,88 @@ +formatVersion: 1 +formatType: am-configuration +--- +runtimes: + r-test: + r-parameter: xr-value + r-test2: + r-parameter2: r-value2 + +containers: + selection: + - '2': second + + c-test: + c-parameter: xc-value + c-test2: + c-parameter2: c-value2 + +intents: + timeouts: + disambiguation: 5 + startApplication: 6 + replyFromApplication: 7 + replyFromSystem: 8 + +plugins: + startup: s3 + container: [ c3, c4 ] + +logging: + dlt: + id: 'dltid2' + description: 'dltdesc2' + rules: lr3 + messagePattern: 'msgPattern2' + useAMConsoleLogger: 'auto' + +installer: + disable: true + caCertificates: [ cert3 ] + +dbus: + iface1: + register: 'foobus1' + iface2: + register: 'foobus2' + +quicklaunch: + idleLoad: 0.2 + runtimesPerContainer: 3 + +ui: + opengl: + desktopProfile: 'classic' + esMajorVersion: 1 + esMinorVersion: 0 + enableTouchEmulation: true + iconThemeSearchPaths: [ itsp3 ] + iconThemeName: mytheme2 + style: mystyle2 + loadDummyData: true + importPaths: ip3 + pluginPaths: pp3 + windowIcon: 'icon2.png' + fullscreen: true + mainQml: main2.qml + resources: r3 + +applications: + builtinAppsManifestDir: 'builtin-dir2' + installationDir: 'installation-dir2' + documentDir: 'doc-dir2' + +systemProperties: + public: + public-prop: xpublic-value + public-prop2: public-value2 + protected: + protected-prop: xprotected-value + protected-prop2: protected-value2 + private: + private-prop: xprivate-value + private-prop2: private-value2 + +wayland: + socketName: "other-wlsock-0" + extraSockets: + - path: path-es3 diff --git a/tests/auto/configuration/data/empty.yaml b/tests/auto/configuration/data/empty.yaml new file mode 100644 index 00000000..a87fe348 --- /dev/null +++ b/tests/auto/configuration/data/empty.yaml @@ -0,0 +1,3 @@ +formatVersion: 1 +formatType: am-configuration +--- diff --git a/tests/auto/configuration/tst_configuration.cpp b/tests/auto/configuration/tst_configuration.cpp new file mode 100644 index 00000000..67eeec41 --- /dev/null +++ b/tests/auto/configuration/tst_configuration.cpp @@ -0,0 +1,523 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include + +QT_USE_NAMESPACE_AM + +class tst_Configuration : public QObject +{ + Q_OBJECT + +public: + tst_Configuration(); + +private slots: + void defaultConfig(); + void simpleConfig(); + void mergedConfig(); + void commandLineConfig(); + +private: + QDir pwd; +}; + + +tst_Configuration::tst_Configuration() +{ } + +void tst_Configuration::defaultConfig() +{ + Configuration c; + c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); + + QVERIFY(c.noCache()); + + // command line only + QCOMPARE(c.noFullscreen(), false); + QCOMPARE(c.verbose(), false); + QCOMPARE(c.slowAnimations(), false); + QCOMPARE(c.noDltLogging(), false); + QCOMPARE(c.singleApp(), qSL("")); + QCOMPARE(c.qmlDebugging(), false); + + // values from config file + QCOMPARE(c.mainQmlFile(), qSL("")); + + QCOMPARE(c.builtinAppsManifestDirs(), {}); + QCOMPARE(c.documentDir(), qSL("")); + + QCOMPARE(c.installationDir(), qSL("")); + QCOMPARE(c.disableInstaller(), false); + QCOMPARE(c.disableIntents(), false); + QCOMPARE(c.intentTimeoutForDisambiguation(), 10000); + QCOMPARE(c.intentTimeoutForStartApplication(), 3000); + QCOMPARE(c.intentTimeoutForReplyFromApplication(), 5000); + QCOMPARE(c.intentTimeoutForReplyFromSystem(), 20000); + + QCOMPARE(c.fullscreen(), false); + QCOMPARE(c.windowIcon(), qSL("")); + QCOMPARE(c.importPaths(), {}); + QCOMPARE(c.pluginPaths(), {}); + QCOMPARE(c.loadDummyData(), false); + QCOMPARE(c.noSecurity(), false); + QCOMPARE(c.developmentMode(), false); + QCOMPARE(c.noUiWatchdog(), false); + QCOMPARE(c.forceSingleProcess(), false); + QCOMPARE(c.forceMultiProcess(), false); + QCOMPARE(c.loggingRules(), {}); + QCOMPARE(c.messagePattern(), qSL("")); + QCOMPARE(c.useAMConsoleLogger(), QVariant()); + QCOMPARE(c.style(), qSL("")); + QCOMPARE(c.iconThemeName(), qSL("")); + QCOMPARE(c.iconThemeSearchPaths(), {}); + QCOMPARE(c.enableTouchEmulation(), false); + QCOMPARE(c.dltId(), qSL("")); + QCOMPARE(c.dltDescription(), qSL("")); + QCOMPARE(c.resources(), {}); + + QCOMPARE(c.openGLConfiguration(), QVariantMap {}); + + QCOMPARE(c.installationLocations(), {}); + + QCOMPARE(c.containerSelectionConfiguration(), {}); + QCOMPARE(c.containerConfigurations(), QVariantMap {}); + QCOMPARE(c.runtimeConfigurations(), QVariantMap {}); + + QCOMPARE(c.dbusRegistration("iface1"), qSL("auto")); + + QCOMPARE(c.rawSystemProperties(), QVariantMap {}); + + QCOMPARE(c.quickLaunchIdleLoad(), qreal(0)); + QCOMPARE(c.quickLaunchRuntimesPerContainer(), 0); + + QString defaultWaylandSocketName = +#if defined(Q_OS_LINUX) + qSL("qtam-wayland-0"); +#else + QString(); +#endif + + QCOMPARE(c.waylandSocketName(), defaultWaylandSocketName); + QCOMPARE(c.waylandExtraSockets(), {}); + + QCOMPARE(c.managerCrashAction(), QVariantMap {}); + + QCOMPARE(c.caCertificates(), {}); + + QCOMPARE(c.pluginFilePaths("container"), {}); + QCOMPARE(c.pluginFilePaths("startup"), {}); +} + +void tst_Configuration::simpleConfig() +{ + Configuration c({ qSL(":/data/config1.yaml") }, qSL(":/build-config.yaml")); + c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); + + QVERIFY(c.noCache()); + + // command line only + QCOMPARE(c.noFullscreen(), false); + QCOMPARE(c.verbose(), false); + QCOMPARE(c.slowAnimations(), false); + QCOMPARE(c.noDltLogging(), false); + QCOMPARE(c.singleApp(), qSL("")); + QCOMPARE(c.qmlDebugging(), false); + + // values from config file + QCOMPARE(c.mainQmlFile(), qSL("main.qml")); + + QCOMPARE(c.builtinAppsManifestDirs(), { qSL("builtin-dir") }); + QCOMPARE(c.documentDir(), qSL("doc-dir")); + + QCOMPARE(c.installationDir(), qSL("installation-dir")); + QCOMPARE(c.disableInstaller(), true); + QCOMPARE(c.disableIntents(), true); + QCOMPARE(c.intentTimeoutForDisambiguation(), 1); + QCOMPARE(c.intentTimeoutForStartApplication(), 2); + QCOMPARE(c.intentTimeoutForReplyFromApplication(), 3); + QCOMPARE(c.intentTimeoutForReplyFromSystem(), 4); + + QCOMPARE(c.fullscreen(), true); + QCOMPARE(c.windowIcon(), qSL("icon.png")); + QCOMPARE(c.importPaths(), QStringList({ pwd.absoluteFilePath(qSL("ip1")), pwd.absoluteFilePath(qSL("ip2")) })); + QCOMPARE(c.pluginPaths(), QStringList({ qSL("pp1"), qSL("pp2") })); + QCOMPARE(c.loadDummyData(), true); + QCOMPARE(c.noSecurity(), true); + QCOMPARE(c.developmentMode(), true); + QCOMPARE(c.noUiWatchdog(), true); + QCOMPARE(c.forceSingleProcess(), true); + QCOMPARE(c.forceMultiProcess(), true); + QCOMPARE(c.loggingRules(), QStringList({ qSL("lr1"), qSL("lr2") })); + QCOMPARE(c.messagePattern(), qSL("msgPattern")); + QCOMPARE(c.useAMConsoleLogger(), QVariant(true)); + QCOMPARE(c.style(), qSL("mystyle")); + QCOMPARE(c.iconThemeName(), qSL("mytheme")); + QCOMPARE(c.iconThemeSearchPaths(), QStringList({ qSL("itsp1"), qSL("itsp2") })); + QCOMPARE(c.enableTouchEmulation(), true); + QCOMPARE(c.dltId(), qSL("dltid")); + QCOMPARE(c.dltDescription(), qSL("dltdesc")); + QCOMPARE(c.resources(), QStringList({ qSL("r1"), qSL("r2") })); + + QCOMPARE(c.openGLConfiguration(), QVariantMap + ({ + { qSL("desktopProfile"), qSL("compatibility") }, + { qSL("esMajorVersion"), 5 }, + { qSL("esMinorVersion"), 15 } + })); + + QCOMPARE(c.installationLocations(), {}); + + QList> containerSelectionConfiguration { + { qSL("*"), qSL("selectionFunction") } + }; + QCOMPARE(c.containerSelectionConfiguration(), containerSelectionConfiguration); + QCOMPARE(c.containerConfigurations(), QVariantMap + ({ + { qSL("c-test"), QVariantMap { + { qSL("c-parameter"), qSL("c-value") } + } } + })); + QCOMPARE(c.runtimeConfigurations(), QVariantMap + ({ + { qSL("r-test"), QVariantMap { + { qSL("r-parameter"), qSL("r-value") } + } } + })); + + QCOMPARE(c.dbusRegistration("iface1"), qSL("foobus")); + + QCOMPARE(c.rawSystemProperties(), QVariantMap + ({ + { qSL("public"), QVariantMap { + { qSL("public-prop"), qSL("public-value") } + } }, + { qSL("protected"), QVariantMap { + { qSL("protected-prop"), qSL("protected-value") } + } }, + { qSL("private"), QVariantMap { + { qSL("private-prop"), qSL("private-value") } + } } + })); + + QCOMPARE(c.quickLaunchIdleLoad(), qreal(0.5)); + QCOMPARE(c.quickLaunchRuntimesPerContainer(), 5); + + QCOMPARE(c.waylandSocketName(), qSL("my-wlsock-42")); + + QCOMPARE(c.waylandExtraSockets(), QVariantList + ({ + QVariantMap { + { qSL("path"), qSL("path-es1") }, + { qSL("permissions"), 0440 }, + { qSL("userId"), 1 }, + { qSL("groupId"), 2 } + }, + QVariantMap { + { qSL("path"), qSL("path-es2") }, + { qSL("permissions"), 0222 }, + { qSL("userId"), 3 }, + { qSL("groupId"), 4 } + } + })); + + QCOMPARE(c.managerCrashAction(), QVariantMap + ({ + { qSL("printBacktrace"), true }, + { qSL("printQmlStack"), true }, + { qSL("waitForGdbAttach"), true }, + { qSL("dumpCore"), true } + })); + + QCOMPARE(c.caCertificates(), QStringList({ qSL("cert1"), qSL("cert2") })); + + QCOMPARE(c.pluginFilePaths("startup"), QStringList({ qSL("s1"), qSL("s2") })); + QCOMPARE(c.pluginFilePaths("container"), QStringList({ qSL("c1"), qSL("c2") })); +} + +void tst_Configuration::mergedConfig() +{ + Configuration c({ qSL(":/data/config1.yaml"), qSL(":/data/config2.yaml") }, qSL(":/build-config.yaml")); + c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); + + QVERIFY(c.noCache()); + + // command line only + QCOMPARE(c.noFullscreen(), false); + QCOMPARE(c.verbose(), false); + QCOMPARE(c.slowAnimations(), false); + QCOMPARE(c.noDltLogging(), false); + QCOMPARE(c.singleApp(), qSL("")); + QCOMPARE(c.qmlDebugging(), false); + + // values from config file + QCOMPARE(c.mainQmlFile(), qSL("main2.qml")); + + QCOMPARE(c.builtinAppsManifestDirs(), QStringList({ qSL("builtin-dir"), qSL("builtin-dir2") })); + QCOMPARE(c.documentDir(), qSL("doc-dir2")); + + QCOMPARE(c.installationDir(), qSL("installation-dir2")); + QCOMPARE(c.disableInstaller(), true); + QCOMPARE(c.disableIntents(), true); + QCOMPARE(c.intentTimeoutForDisambiguation(), 5); + QCOMPARE(c.intentTimeoutForStartApplication(), 6); + QCOMPARE(c.intentTimeoutForReplyFromApplication(), 7); + QCOMPARE(c.intentTimeoutForReplyFromSystem(), 8); + + QCOMPARE(c.fullscreen(), true); + QCOMPARE(c.windowIcon(), qSL("icon2.png")); + QCOMPARE(c.importPaths(), QStringList + ({ pwd.absoluteFilePath(qSL("ip1")), + pwd.absoluteFilePath(qSL("ip2")), + pwd.absoluteFilePath(qSL("ip3")) })); + QCOMPARE(c.pluginPaths(), QStringList({ qSL("pp1"), qSL("pp2"), qSL("pp3") })); + QCOMPARE(c.loadDummyData(), true); + QCOMPARE(c.noSecurity(), true); + QCOMPARE(c.developmentMode(), true); + QCOMPARE(c.noUiWatchdog(), true); + QCOMPARE(c.forceSingleProcess(), true); + QCOMPARE(c.forceMultiProcess(), true); + QCOMPARE(c.loggingRules(), QStringList({ qSL("lr1"), qSL("lr2"), qSL("lr3") })); + QCOMPARE(c.messagePattern(), qSL("msgPattern2")); + QCOMPARE(c.useAMConsoleLogger(), QVariant()); + QCOMPARE(c.style(), qSL("mystyle2")); + QCOMPARE(c.iconThemeName(), qSL("mytheme2")); + QCOMPARE(c.iconThemeSearchPaths(), QStringList({ qSL("itsp1"), qSL("itsp2"), qSL("itsp3") })); + QCOMPARE(c.enableTouchEmulation(), true); + QCOMPARE(c.dltId(), qSL("dltid2")); + QCOMPARE(c.dltDescription(), qSL("dltdesc2")); + QCOMPARE(c.resources(), QStringList({ qSL("r1"), qSL("r2"), qSL("r3") })); + + QCOMPARE(c.openGLConfiguration(), QVariantMap + ({ + { qSL("desktopProfile"), qSL("classic") }, + { qSL("esMajorVersion"), 1 }, + { qSL("esMinorVersion"), 0 }, + })); + + QCOMPARE(c.installationLocations(), {}); + + QList> containerSelectionConfiguration { + { qSL("*"), qSL("selectionFunction") }, + { qSL("2"), qSL("second") } + }; + QCOMPARE(c.containerSelectionConfiguration(), containerSelectionConfiguration); + QCOMPARE(c.containerConfigurations(), QVariantMap + ({ + { qSL("c-test"), QVariantMap { + { qSL("c-parameter"), qSL("xc-value") }, + } }, + { qSL("c-test2"), QVariantMap { + { qSL("c-parameter2"), qSL("c-value2") }, + } } + + })); + + QCOMPARE(c.runtimeConfigurations(), QVariantMap + ({ + { qSL("r-test"), QVariantMap { + { qSL("r-parameter"), qSL("xr-value") }, + } }, + { qSL("r-test2"), QVariantMap { + { qSL("r-parameter2"), qSL("r-value2") }, + } } + + })); + + QCOMPARE(c.dbusRegistration("iface1"), qSL("foobus1")); + QCOMPARE(c.dbusRegistration("iface2"), qSL("foobus2")); + + QCOMPARE(c.rawSystemProperties(), QVariantMap + ({ + { qSL("public"), QVariantMap { + { qSL("public-prop"), qSL("xpublic-value") }, + { qSL("public-prop2"), qSL("public-value2") } + } }, + { qSL("protected"), QVariantMap { + { qSL("protected-prop"), qSL("xprotected-value") }, + { qSL("protected-prop2"), qSL("protected-value2") } + } }, + { qSL("private"), QVariantMap { + { qSL("private-prop"), qSL("xprivate-value") }, + { qSL("private-prop2"), qSL("private-value2") } + } } + })); + + QCOMPARE(c.quickLaunchIdleLoad(), qreal(0.2)); + QCOMPARE(c.quickLaunchRuntimesPerContainer(), 3); + + QCOMPARE(c.waylandSocketName(), qSL("other-wlsock-0")); + + QCOMPARE(c.waylandExtraSockets(), QVariantList + ({ + QVariantMap { + { qSL("path"), qSL("path-es1") }, + { qSL("permissions"), 0440 }, + { qSL("userId"), 1 }, + { qSL("groupId"), 2 } + }, + QVariantMap { + { qSL("path"), qSL("path-es2") }, + { qSL("permissions"), 0222 }, + { qSL("userId"), 3 }, + { qSL("groupId"), 4 } + }, + QVariantMap { + { qSL("path"), qSL("path-es3") }, + } + })); + + QCOMPARE(c.managerCrashAction(), QVariantMap + ({ + { qSL("printBacktrace"), true }, + { qSL("printQmlStack"), true }, + { qSL("waitForGdbAttach"), true }, + { qSL("dumpCore"), true } + })); + + QCOMPARE(c.caCertificates(), QStringList({ qSL("cert1"), qSL("cert2"), qSL("cert3") })); + + QCOMPARE(c.pluginFilePaths("container"), QStringList({ qSL("c1"), qSL("c2"), qSL("c3"), qSL("c4") })); + QCOMPARE(c.pluginFilePaths("startup"), QStringList({ qSL("s1"), qSL("s2"), qSL("s3") })); +} + +void tst_Configuration::commandLineConfig() +{ + Configuration c; + QStringList commandLine { qSL("test"), qSL("--no-cache") }; + + commandLine << "--builtin-apps-manifest-dir" << "builtin-dir-cl1" + << "--builtin-apps-manifest-dir" << "builtin-dir-cl2" + << "--installation-dir" << "installation-dir-cl" + << "--document-dir" << "document-dir-cl" + << "--disable-installer" + << "--disable-intents" + << "--dbus" << "system" + << "--no-fullscreen" + << "-I" << "ip-cl1" + << "-I" << "ip-cl2" + << "-v" + << "--slow-animations" + << "--load-dummydata" + << "--no-security" + << "--development-mode" + << "--no-ui-watchdog" + << "--no-dlt-logging" + << "--force-single-process" + << "--force-multi-process" + << "--wayland-socket-name" << "wlsock-1" + << "--single-app" << "appname" + << "--logging-rule" << "cl-lr1" + << "--logging-rule" << "cl-lr2" + << "--qml-debug" + << "--enable-touch-emulation" + << "main-cl.qml"; + + c.parseWithArguments(commandLine); + + QVERIFY(c.noCache()); + + // command line only + QCOMPARE(c.noFullscreen(), true); + QCOMPARE(c.verbose(), true); + QCOMPARE(c.slowAnimations(), true); + QCOMPARE(c.noDltLogging(), true); + QCOMPARE(c.singleApp(), qSL("appname")); + QCOMPARE(c.qmlDebugging(), true); + + // values from config file + QCOMPARE(c.mainQmlFile(), qSL("main-cl.qml")); + + QCOMPARE(c.builtinAppsManifestDirs(), QStringList({ qSL("builtin-dir-cl1"), qSL("builtin-dir-cl2") })); + QCOMPARE(c.documentDir(), qSL("document-dir-cl")); + + QCOMPARE(c.installationDir(), qSL("installation-dir-cl")); + QCOMPARE(c.disableInstaller(), true); + QCOMPARE(c.disableIntents(), true); + QCOMPARE(c.intentTimeoutForDisambiguation(), 10000); + QCOMPARE(c.intentTimeoutForStartApplication(), 3000); + QCOMPARE(c.intentTimeoutForReplyFromApplication(), 5000); + QCOMPARE(c.intentTimeoutForReplyFromSystem(), 20000); + + QCOMPARE(c.fullscreen(), false); + QCOMPARE(c.windowIcon(), qSL("")); + QCOMPARE(c.importPaths(), QStringList({ pwd.absoluteFilePath(qSL("ip-cl1")), + pwd.absoluteFilePath(qSL("ip-cl2")) })); + QCOMPARE(c.pluginPaths(), {}); + QCOMPARE(c.loadDummyData(), true); + QCOMPARE(c.noSecurity(), true); + QCOMPARE(c.developmentMode(), true); + QCOMPARE(c.noUiWatchdog(), true); + QCOMPARE(c.forceSingleProcess(), true); + QCOMPARE(c.forceMultiProcess(), true); + QCOMPARE(c.loggingRules(), QStringList({ qSL("cl-lr1"), qSL("cl-lr2") })); + QCOMPARE(c.messagePattern(), qSL("")); + QCOMPARE(c.useAMConsoleLogger(), QVariant()); + QCOMPARE(c.style(), qSL("")); + QCOMPARE(c.iconThemeName(), qSL("")); + QCOMPARE(c.iconThemeSearchPaths(), {}); + QCOMPARE(c.enableTouchEmulation(), true); + QCOMPARE(c.dltId(), qSL("")); + QCOMPARE(c.dltDescription(), qSL("")); + QCOMPARE(c.resources(), {}); + + QCOMPARE(c.openGLConfiguration(), QVariantMap {}); + + QCOMPARE(c.installationLocations(), {}); + + QCOMPARE(c.containerSelectionConfiguration(), {}); + QCOMPARE(c.containerConfigurations(), QVariantMap{}); + QCOMPARE(c.runtimeConfigurations(), QVariantMap{}); + + QCOMPARE(c.dbusRegistration("iface1"), qSL("system")); + + QCOMPARE(c.rawSystemProperties(), QVariantMap {}); + + QCOMPARE(c.quickLaunchIdleLoad(), qreal(0)); + QCOMPARE(c.quickLaunchRuntimesPerContainer(), 0); + + QCOMPARE(c.waylandSocketName(), qSL("wlsock-1")); + QCOMPARE(c.waylandExtraSockets(), {}); + + QCOMPARE(c.managerCrashAction(), QVariantMap {}); + + QCOMPARE(c.caCertificates(), {}); + + QCOMPARE(c.pluginFilePaths("container"), {}); + QCOMPARE(c.pluginFilePaths("startup"), {}); +} + + +QTEST_MAIN(tst_Configuration) + +#include "tst_configuration.moc" diff --git a/tests/auto/cryptography/CMakeLists.txt b/tests/auto/cryptography/CMakeLists.txt new file mode 100644 index 00000000..4cc87a7d --- /dev/null +++ b/tests/auto/cryptography/CMakeLists.txt @@ -0,0 +1,20 @@ + +qt_internal_add_test(tst_cryptography + SOURCES + ../error-checking.h + tst_cryptography.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate + Qt::AppManCryptoPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_cryptography CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/cryptography/cryptography.pro b/tests/auto/cryptography/cryptography.pro new file mode 100644 index 00000000..d18f6441 --- /dev/null +++ b/tests/auto/cryptography/cryptography.pro @@ -0,0 +1,7 @@ +TARGET = tst_cryptography + +include($$PWD/../tests.pri) + +QT *= appman_common-private appman_crypto-private + +SOURCES += tst_cryptography.cpp diff --git a/tests/auto/cryptography/tst_cryptography.cpp b/tests/auto/cryptography/tst_cryptography.cpp new file mode 100644 index 00000000..ff8c2ae6 --- /dev/null +++ b/tests/auto/cryptography/tst_cryptography.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "cryptography.h" + +QT_USE_NAMESPACE_AM + +class tst_Cryptography : public QObject +{ + Q_OBJECT + +public: + tst_Cryptography(); + +private slots: + void random(); +}; + +tst_Cryptography::tst_Cryptography() +{ } + +void tst_Cryptography::random() +{ + QVERIFY(Cryptography::generateRandomBytes(-1).isEmpty()); + QVERIFY(Cryptography::generateRandomBytes(0).isEmpty()); + QVERIFY(!Cryptography::generateRandomBytes(1).isEmpty()); + QCOMPARE(Cryptography::generateRandomBytes(128).size(), 128); +} + +QTEST_APPLESS_MAIN(tst_Cryptography) + +#include "tst_cryptography.moc" diff --git a/tests/auto/debugwrapper/CMakeLists.txt b/tests/auto/debugwrapper/CMakeLists.txt new file mode 100644 index 00000000..fc041f88 --- /dev/null +++ b/tests/auto/debugwrapper/CMakeLists.txt @@ -0,0 +1,19 @@ + +qt_internal_add_test(tst_debugwrapper + SOURCES + ../error-checking.h + tst_debugwrapper.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManManagerPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_debugwrapper CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/debugwrapper/debugwrapper.pro b/tests/auto/debugwrapper/debugwrapper.pro new file mode 100644 index 00000000..b7e9128a --- /dev/null +++ b/tests/auto/debugwrapper/debugwrapper.pro @@ -0,0 +1,8 @@ +TARGET = tst_debugwrapper + +include($$PWD/../tests.pri) + +QT *= \ + appman_manager-private + +SOURCES += tst_debugwrapper.cpp diff --git a/tests/auto/debugwrapper/tst_debugwrapper.cpp b/tests/auto/debugwrapper/tst_debugwrapper.cpp new file mode 100644 index 00000000..8037bb31 --- /dev/null +++ b/tests/auto/debugwrapper/tst_debugwrapper.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include "../error-checking.h" + +QT_USE_NAMESPACE_AM + +class tst_DebugWrapper : public QObject +{ + Q_OBJECT + +public: + tst_DebugWrapper(QObject *parent = nullptr); + ~tst_DebugWrapper(); + +private slots: + void specification_data(); + void specification(); + + void substitute_data(); + void substitute(); +}; + + +tst_DebugWrapper::tst_DebugWrapper(QObject *parent) + : QObject(parent) +{ } + +tst_DebugWrapper::~tst_DebugWrapper() +{ } + +typedef QMap StringMap; +Q_DECLARE_METATYPE(StringMap) + +void tst_DebugWrapper::specification_data() +{ + QTest::addColumn("spec"); + QTest::addColumn("valid"); + QTest::addColumn("env"); + QTest::addColumn("cmd"); + + QMap noenv; + + QTest::newRow("empty") << "" << false << noenv << QStringList(); + QTest::newRow("empty2") << " " << false << noenv << QStringList(); + + QTest::newRow("nocmd") << "foo=bar" << true << StringMap {{ "foo", "bar" }} << QStringList { "%program%", "%arguments%" }; + QTest::newRow("nocmd2") << "foo=bar " << true << StringMap {{ "foo", "bar" }} << QStringList { "%program%", "%arguments%" }; + + QTest::newRow("1") << "foo" << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; + QTest::newRow("2") << " foo" << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; + QTest::newRow("3") << "foo " << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; + QTest::newRow("4") << "foo bar" << true << noenv << QStringList { "foo", "bar", "%program%", "%arguments%" }; + QTest::newRow("5") << "foo bar" << true << noenv << QStringList { "foo", "bar", "%program%", "%arguments%" }; + QTest::newRow("6") << "foo bar baz" << true << noenv << QStringList { "foo", "bar", "baz", "%program%", "%arguments%" }; + QTest::newRow("7") << "fo\\ o b\\nar b\\\\az" << true << noenv << QStringList { "fo o", "b\nar", "b\\az", "%program%", "%arguments%" }; + QTest::newRow("8") << "foo=bar baz" << true << StringMap {{ "foo", "bar" }} << QStringList { "baz", "%program%", "%arguments%" }; + QTest::newRow("9") << "foo=bar a= baz zab" << true << StringMap {{ "foo", "bar" }, { "a", QString() }} << QStringList { "baz", "zab", "%program%", "%arguments%" }; + QTest::newRow("a") << "foo=b\\ a=\\n baz z\\ ab" << true << StringMap {{ "foo", "b a=\n" }} << QStringList { "baz", "z ab", "%program%", "%arguments%" }; + QTest::newRow("b") << "a=b c d=e" << true << StringMap {{ "a", "b" }} << QStringList { "c", "d=e", "%program%", "%arguments%" }; + + QTest::newRow("z") << "a=b %program% c %arguments% d" << true << StringMap {{ "a", "b" }} << QStringList { "%program%", "c", "%arguments%", "d" }; + QTest::newRow("y") << "a=b %program% c d" << true << StringMap {{ "a", "b" }} << QStringList { "%program%", "c", "d", "%arguments%" }; + QTest::newRow("x") << "a=b %arguments%" << true << StringMap {{ "a", "b" }} << QStringList { "%arguments%", "%program%" }; + QTest::newRow("w") << "%program% %arguments%" << true << noenv << QStringList { "%program%", "%arguments%" }; + QTest::newRow("w") << "%program% foo-%program% foo-%arguments%-bar %arguments%" << true << noenv << QStringList { "%program%", "foo-%program%", "foo-%arguments%-bar", "%arguments%" }; +} + +void tst_DebugWrapper::specification() +{ + QFETCH(QString, spec); + QFETCH(bool, valid); + QFETCH(StringMap, env); + QFETCH(QStringList, cmd); + + StringMap resultEnv; + QStringList resultCmd; + QCOMPARE(DebugWrapper::parseSpecification(spec, resultCmd, resultEnv), valid); + QCOMPARE(cmd, resultCmd); + QCOMPARE(env, resultEnv); +} + +void tst_DebugWrapper::substitute_data() +{ + QTest::addColumn("cmd"); + QTest::addColumn("program"); + QTest::addColumn("arguments"); + QTest::addColumn("result"); + + QTest::newRow("1") << QStringList { "%program%", "%arguments%" } + << QString("prg") << QStringList { "arg1", "arg2" } + << QStringList { "prg", "arg1", "arg2" }; + + QTest::newRow("2") << QStringList { "%program%" } + << QString("prg") << QStringList { "arg1", "arg2" } + << QStringList { "prg" }; + + QTest::newRow("3") << QStringList { "%program%", "\"x-%program%\"", "%arguments%", "x-%arguments%" } + << QString("prg") << QStringList { "arg1", "arg2" } + << QStringList { "prg", "\"x-prg\"", "arg1", "arg2", "x-arg1 arg2" }; + + QTest::newRow("4") << QStringList { "foo", "%arguments%", "bar", "%program%", "baz", "%arguments%", "foo2" } + << QString("prg") << QStringList { "a1", "a2", "a3" } + << QStringList { "foo", "a1", "a2", "a3", "bar", "prg", "baz", "a1", "a2", "a3", "foo2" }; +} + +void tst_DebugWrapper::substitute() +{ + QFETCH(QStringList, cmd); + QFETCH(QString, program); + QFETCH(QStringList, arguments); + QFETCH(QStringList, result); + + QCOMPARE(DebugWrapper::substituteCommand(cmd, program, arguments), result); +} + +QTEST_APPLESS_MAIN(tst_DebugWrapper) + +#include "tst_debugwrapper.moc" diff --git a/tests/auto/error-checking.h b/tests/auto/error-checking.h new file mode 100644 index 00000000..e80cdde5 --- /dev/null +++ b/tests/auto/error-checking.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include + +// sadly this has to be a define for QVERIFY2() to work +#define AM_CHECK_ERRORSTRING(_actual_errstr, _expected_errstr) do { \ + if (_expected_errstr.startsWith(QLatin1String("~"))) { \ + QRegularExpression re(_expected_errstr.mid(1)); \ + QVERIFY2(re.match(_actual_errstr).hasMatch(), \ + qPrintable("\n Got : " + _actual_errstr.toLocal8Bit() + \ + "\n Expected: " + _expected_errstr.toLocal8Bit())); \ + } else { \ + QCOMPARE(_actual_errstr, _expected_errstr); \ + } \ +} while (false) diff --git a/tests/auto/installationreport/CMakeLists.txt b/tests/auto/installationreport/CMakeLists.txt new file mode 100644 index 00000000..f0204d00 --- /dev/null +++ b/tests/auto/installationreport/CMakeLists.txt @@ -0,0 +1,21 @@ + +qt_internal_add_test(tst_installationreport + SOURCES + ../error-checking.h + tst_installationreport.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManCryptoPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_installationreport CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/installationreport/installationreport.pro b/tests/auto/installationreport/installationreport.pro new file mode 100644 index 00000000..ce1aa46b --- /dev/null +++ b/tests/auto/installationreport/installationreport.pro @@ -0,0 +1,10 @@ +TARGET = tst_installationreport + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_crypto-private \ + appman_application-private \ + +SOURCES += tst_installationreport.cpp diff --git a/tests/auto/installationreport/tst_installationreport.cpp b/tests/auto/installationreport/tst_installationreport.cpp new file mode 100644 index 00000000..edb1b35a --- /dev/null +++ b/tests/auto/installationreport/tst_installationreport.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "global.h" +#include "exception.h" +#include "installationreport.h" + +QT_USE_NAMESPACE_AM + +class tst_InstallationReport : public QObject +{ + Q_OBJECT + +public: + tst_InstallationReport(); + +private slots: + void test(); +}; + +tst_InstallationReport::tst_InstallationReport() +{ } + +void tst_InstallationReport::test() +{ + QStringList files { qSL("test"), qSL("more/test"), qSL("another/test/file") }; + + InstallationReport ir(qSL("com.pelagicore.test")); + QVERIFY(!ir.isValid()); + ir.addFile(files.first()); + QVERIFY(!ir.isValid()); + ir.setDiskSpaceUsed(42); + QVERIFY(!ir.isValid()); + ir.setDigest("##digest##"); + QVERIFY(ir.isValid()); + ir.addFiles(files.mid(1)); + ir.setDeveloperSignature("%%dev-sig%%"); + ir.setStoreSignature("$$store-sig$$"); + + QVERIFY(ir.isValid()); + QCOMPARE(ir.packageId(), qSL("com.pelagicore.test")); + QCOMPARE(ir.files(), files); + QCOMPARE(ir.diskSpaceUsed(), 42ULL); + QCOMPARE(ir.digest().constData(), "##digest##"); + QCOMPARE(ir.developerSignature().constData(), "%%dev-sig%%"); + QCOMPARE(ir.storeSignature().constData(), "$$store-sig$$"); + + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + QVERIFY(ir.serialize(&buffer)); + buffer.seek(0); + + InstallationReport ir2; + try { + ir2.deserialize(&buffer); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } + buffer.seek(0); + + QVERIFY(ir2.isValid()); + QCOMPARE(ir2.packageId(), qSL("com.pelagicore.test")); + QCOMPARE(ir2.files(), files); + QCOMPARE(ir2.diskSpaceUsed(), 42ULL); + QCOMPARE(ir2.digest().constData(), "##digest##"); + QCOMPARE(ir2.developerSignature().constData(), "%%dev-sig%%"); + QCOMPARE(ir2.storeSignature().constData(), "$$store-sig$$"); + + QByteArray &yaml = buffer.buffer(); + QVERIFY(!yaml.isEmpty()); + + int pos = yaml.lastIndexOf("\n---\nhmac: '"); + QVERIFY(pos > 0); + pos += 12; + QByteArray hmac = QMessageAuthenticationCode::hash("data", "key", QCryptographicHash::Sha256).toHex(); + yaml.replace(pos, hmac.size(), hmac); + QCOMPARE(yaml.mid(pos + hmac.size(), 2).constData(), "'\n"); + + try { + ir2.deserialize(&buffer); + QVERIFY(false); + } catch (...) { + } +} + +QTEST_APPLESS_MAIN(tst_InstallationReport) + +#include "tst_installationreport.moc" diff --git a/tests/auto/main/CMakeLists.txt b/tests/auto/main/CMakeLists.txt new file mode 100644 index 00000000..05e6d2cd --- /dev/null +++ b/tests/auto/main/CMakeLists.txt @@ -0,0 +1,39 @@ + +qt_internal_add_test(tst_main + SOURCES + ../error-checking.h + tst_main.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManIntentServerPrivate + Qt::AppManMainPrivate + Qt::AppManManagerPrivate +) + +# Resources: +set(main_resource_files + "dummy.qml" +) + +qt_internal_add_resource(tst_main "main" + PREFIX + "/foo" + FILES + ${main_resource_files} +) + + +#### Keys ignored in scope 1:.:.:main.pro:: +# OTHER_FILES = "am-config.yaml" + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_main CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/main/am-config.yaml b/tests/auto/main/am-config.yaml new file mode 100644 index 00000000..ff538f1b --- /dev/null +++ b/tests/auto/main/am-config.yaml @@ -0,0 +1,10 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/builtin-apps" + installationDir: "/tmp/am-test-main/apps" + documentDir: "/tmp/am-test-main/docs" + +ui: + mainQml: "${CONFIG_PWD}/dummy.qml" diff --git a/tests/auto/main/builtin-apps/hello-world.red/icon.png b/tests/auto/main/builtin-apps/hello-world.red/icon.png new file mode 100644 index 00000000..04ca44dd Binary files /dev/null and b/tests/auto/main/builtin-apps/hello-world.red/icon.png differ diff --git a/tests/auto/main/builtin-apps/hello-world.red/info.yaml b/tests/auto/main/builtin-apps/hello-world.red/info.yaml new file mode 100644 index 00000000..fa52180e --- /dev/null +++ b/tests/auto/main/builtin-apps/hello-world.red/info.yaml @@ -0,0 +1,24 @@ +formatVersion: 1 +formatType: am-package +--- +id: 'hello-world.red' +icon: 'icon.png' +name: + en: 'Hello Red' + +applications: +- id: red1 + runtime: 'qml' + code: 'main.qml' + +- id: red2 + runtime: 'qml' + code: 'main2.qml' + +intents: +- id: red.intent1 + handlingApplicationId: red1 + categories: [ launcher, one ] +- id: red.intent2 + handlingApplicationId: red2 + categories: [ launcher, two ] diff --git a/tests/auto/main/builtin-apps/hello-world.red/main.qml b/tests/auto/main/builtin-apps/hello-world.red/main.qml new file mode 100644 index 00000000..b225bdfc --- /dev/null +++ b/tests/auto/main/builtin-apps/hello-world.red/main.qml @@ -0,0 +1,11 @@ +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + color: "red" + + Text { + anchors.centerIn: parent + text: "Hello World!" + } +} diff --git a/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml new file mode 100644 index 00000000..ec57b3d7 --- /dev/null +++ b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +formatType: 'am-installation-report' +formatVersion: 3 +--- +packageId: 'hello-world.red' +digest: '45ca0f9dfbddca129687900ae3260fe4a35ca09efd189581e196c0a75da47a0f' +diskSpaceUsed: 575488 +files: +- 'info.yaml' +- 'icon.png' +- 'main.qml' +--- +hmac: '48fce75b29a2b621f1a1462b434e6de0cac78837fe733bc12ab8e727363c5226' diff --git a/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/icon.png b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/icon.png new file mode 100644 index 00000000..04ca44dd Binary files /dev/null and b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/icon.png differ diff --git a/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml new file mode 100644 index 00000000..af6a9f70 --- /dev/null +++ b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'hello-world.red' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'Hello Updated Red' diff --git a/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/main.qml b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/main.qml new file mode 100644 index 00000000..29b2e715 --- /dev/null +++ b/tests/auto/main/dir-with-update-already-installed/apps/hello-world.red/main.qml @@ -0,0 +1,11 @@ +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + color: "crimson" + + Text { + anchors.centerIn: parent + text: "Hello Updated World!" + } +} diff --git a/tests/auto/main/dir-with-update-already-installed/docs/hello-world.red/placeholder b/tests/auto/main/dir-with-update-already-installed/docs/hello-world.red/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png b/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png new file mode 100644 index 00000000..04ca44dd Binary files /dev/null and b/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png differ diff --git a/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml b/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml new file mode 100644 index 00000000..af6a9f70 --- /dev/null +++ b/tests/auto/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'hello-world.red' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'Hello Updated Red' diff --git a/tests/auto/main/dummy.qml b/tests/auto/main/dummy.qml new file mode 100644 index 00000000..2d95c818 --- /dev/null +++ b/tests/auto/main/dummy.qml @@ -0,0 +1,3 @@ +import QtQml 2.0 + +QtObject { } diff --git a/tests/auto/main/main.pro b/tests/auto/main/main.pro new file mode 100644 index 00000000..e60ec75f --- /dev/null +++ b/tests/auto/main/main.pro @@ -0,0 +1,20 @@ +TARGET = tst_main + +include($$PWD/../tests.pri) + +# this test keeps crashing in a VirtualBox based CI environment, when executed +# via ssh (which gets the test run in Window's session 0 (no visible desktop) +luxoft-ci:CONFIG *= insignificant_test + +QT *= appman_manager-private \ + appman_application-private \ + appman_common-private \ + appman_main-private \ + appman_intent_server-private \ + +SOURCES += tst_main.cpp + +RESOURCES = main.qrc + +OTHER_FILES += am-config.yaml + diff --git a/tests/auto/main/main.qrc b/tests/auto/main/main.qrc new file mode 100644 index 00000000..8cae2bbb --- /dev/null +++ b/tests/auto/main/main.qrc @@ -0,0 +1,5 @@ + + + dummy.qml + + diff --git a/tests/auto/main/tst_main.cpp b/tests/auto/main/tst_main.cpp new file mode 100644 index 00000000..9d9f04a5 --- /dev/null +++ b/tests/auto/main/tst_main.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "packagemanager.h" +#include "package.h" +#include "applicationmanager.h" +#include "logging.h" +#include "main.h" +#include "intentserver.h" +#include "intent.h" +#include + + +QT_USE_NAMESPACE_AM + +class tst_Main : public QObject +{ + Q_OBJECT + +public: + tst_Main(); + ~tst_Main(); + +private slots: + void initTestCase(); + void init(); + void cleanup(); + void installAndRemoveUpdateForBuiltIn(); + void updateForBuiltInAlreadyInstalled(); + void loadDatabaseWithUpdatedBuiltInApp(); + void mainQmlFile_data(); + void mainQmlFile(); + +private: + void cleanUpInstallationDir(); + void installPackage(const QString &path); + void removePackage(const QString &id); + void initMain(); + void destroyMain(); + void copyRecursively(const QString &sourceDir, const QString &destDir); + int argc; + char **argv; + Main *main{nullptr}; + DefaultConfiguration *config{nullptr}; + bool m_verbose = false; +}; + +tst_Main::tst_Main() +{ + argc = 4; + argv = new char*[argc + 1]; + argv[0] = qstrdup("tst_Main"); + argv[1] = qstrdup("--dbus"); + argv[2] = qstrdup("none"); + argv[3] = qstrdup("--no-cache"); + argv[4] = nullptr; +} + +tst_Main::~tst_Main() +{ + for (int i = 0; i < argc; ++i) + delete []argv[i]; + delete []argv; +} + +void tst_Main::initTestCase() +{ + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); + + m_verbose = qEnvironmentVariableIsSet("AM_VERBOSE_TEST"); + qInfo() << "Verbose mode is" << (m_verbose ? "on" : "off") << "(change by (un)setting $AM_VERBOSE_TEST)"; +} + +void tst_Main::copyRecursively(const QString &sourcePath, const QString &destPath) +{ + QDir sourceDir(sourcePath); + QDir destDir(destPath); + + QStringList subdirNames = sourceDir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs); + for (auto subdirName : subdirNames) { + destDir.mkdir(subdirName); + copyRecursively(sourceDir.filePath(subdirName), destDir.filePath(subdirName)); + } + + QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Hidden); + for (auto fileName : fileNames) + QFile::copy(sourceDir.filePath(fileName), destDir.filePath(fileName)); +} + +void tst_Main::cleanUpInstallationDir() +{ + { + QDir testTmpDir("/tmp/am-test-main"); + if (testTmpDir.exists()) + testTmpDir.removeRecursively(); + } + QDir tmpDir("/tmp"); + tmpDir.mkdir("am-test-main"); +} + +void tst_Main::init() +{ + cleanUpInstallationDir(); +} + +void tst_Main::initMain() +{ + main = new Main(argc, argv); + + QString amConfigPath = QFINDTESTDATA("am-config.yaml"); + auto pathList = QStringList(amConfigPath); + + config = new DefaultConfiguration(pathList, QString()); + config->parseWithArguments(QCoreApplication::arguments()); + if (m_verbose) + config->setForceVerbose(true); + + main->setup(config); + + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); +} + +void tst_Main::destroyMain() +{ + if (main) { + main->shutDown(); + main->exec(); + delete main; + main = nullptr; + } + if (config) { + delete config; + config = nullptr; + } +} + +void tst_Main::cleanup() +{ + destroyMain(); + + delete config; + config = nullptr; +} + +void tst_Main::installPackage(const QString &pkgPath) +{ + auto packageManager = PackageManager::instance(); + + bool installationFinished = false; + + connect(packageManager, &PackageManager::taskRequestingInstallationAcknowledge, + this, [packageManager](const QString &taskId, Package *, + const QVariantMap &, const QVariantMap &) { + packageManager->acknowledgePackageInstallation(taskId); + }); + + connect(packageManager, &PackageManager::taskFinished, + this, [&installationFinished](const QString &) { + installationFinished = true; + }); + + packageManager->startPackageInstallation(QUrl::fromLocalFile(pkgPath)); + + QTRY_VERIFY(installationFinished); +} + +void tst_Main::removePackage(const QString &id) +{ + auto packageManager = PackageManager::instance(); + + bool removalFinished = false; + + connect(packageManager, &PackageManager::taskFinished, + this, [this, &removalFinished](const QString &) { + Q_UNUSED(this); // gcc 9.2 bug: without capturing 'this', broken code will be generated + removalFinished = true; + }); + + packageManager->removePackage(id, false /* keepDocuments */); + + QTRY_VERIFY(removalFinished); +} + +/* + Install an application with the same id of an existing, builtin, one. + Then remove it. + At all stages ApplicationManager should contain the same Application + object. All that changes is the contents of that Application: + from original, to updated, and then back to original. + */ +void tst_Main::installAndRemoveUpdateForBuiltIn() +{ + initMain(); + + auto appMan = ApplicationManager::instance(); + QCOMPARE(appMan->count(), 2); + auto intents = IntentServer::instance(); + QCOMPARE(intents->count(), 2); + + auto app1 = appMan->application(0); + QCOMPARE(app1->name(qSL("en")), qSL("Hello Red")); + QCOMPARE(app1->id(), qSL("red1")); + auto app2 = appMan->application(1); + QCOMPARE(app2->name(qSL("en")), qSL("Hello Red")); + QCOMPARE(app2->id(), qSL("red2")); + + auto intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); + QVERIFY(intent1); + QCOMPARE(intent1->intentId(), qSL("red.intent1")); + QCOMPARE(intent1->applicationId(), qSL("red1")); + QCOMPARE(intent1->packageId(), qSL("hello-world.red")); + QVERIFY(intent1->categories().contains(qSL("one"))); + QVERIFY(intent1->categories().contains(qSL("launcher"))); + + auto intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2")); + QVERIFY(intent2); + QCOMPARE(intent2->intentId(), qSL("red.intent2")); + QCOMPARE(intent2->applicationId(), qSL("red2")); + QCOMPARE(intent2->packageId(), qSL("hello-world.red")); + QVERIFY(intent2->categories().contains(qSL("two"))); + QVERIFY(intent2->categories().contains(qSL("launcher"))); + + installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg")); + + QCOMPARE(appMan->count(), 1); + QCOMPARE(intents->count(), 0); + + // it must still be a different Application instance as before the installation, but quite + // often we get the same pointer back because it's a delete/new back-to-back + app1 = appMan->application(0); + + // but with different contents + QCOMPARE(app1->name(qSL("en")), qSL("Hello Updated Red")); + intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); + QVERIFY(!intent1); + + removePackage(qSL("hello-world.red")); + + // After removal of the updated version all data in Application should be as before the + // installation took place. + QCOMPARE(appMan->count(), 2); + QCOMPARE(intents->count(), 2); + + app1 = appMan->application(0); + QCOMPARE(app1->name(qSL("en")), qSL("Hello Red")); + intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); + QVERIFY(intent1); + QCOMPARE(intent1->intentId(), qSL("red.intent1")); + intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2")); + QVERIFY(intent2); + QCOMPARE(intent2->intentId(), qSL("red.intent2")); +} + +/* + Situation: there's already an update installed for a built-in application and there's no database + file yet (or a database rebuild has been requested, in which case any existing database file is + ignored). + + Check that ApplicationManager ends up with only one ApplicationObject as both entries + (the built-in and the installed one) share the same applicaion id. And check also that + this ApplicationObject is showing data from the installed update. + */ +void tst_Main::updateForBuiltInAlreadyInstalled() +{ + copyRecursively(QFINDTESTDATA("dir-with-update-already-installed"), "/tmp/am-test-main"); + + initMain(); + + auto appMan = ApplicationManager::instance(); + QCOMPARE(appMan->count(), 1); + + auto app = appMan->application(0); + QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red")); +} + +/* + Install an update for a built-in app and quit Main. A database will be generated. + + Then, on next iteration of Main, Applications will be created from that database. + Check that ApplicationManager shows only one, updated, built-in app. + */ +void tst_Main::loadDatabaseWithUpdatedBuiltInApp() +{ + initMain(); + installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg")); + destroyMain(); + + initMain(); + + auto appMan = ApplicationManager::instance(); + QCOMPARE(appMan->count(), 1); + + auto app = appMan->application(0); + QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red")); +} + +void tst_Main::mainQmlFile_data() +{ + QTest::addColumn("mainQml"); + QTest::addColumn("expectedErrorMsg"); + + QTest::newRow("none") << "" << "No main QML file specified"; + + QTest::newRow("invalid") << "foo/bar.qml" << "Invalid main QML file specified: foo/bar.qml"; + QTest::newRow("invalid-dir") << "." << "Invalid main QML file specified: ."; + QTest::newRow("invalid-qrc1") << ":/bar.qml" << "Invalid main QML file specified: :/bar.qml"; + // "://bar.qml" yields an absolute file path of ":" and QFile::exists() would always return true + QTest::newRow("invalid-qrc2") << "://bar.qml" << "Invalid main QML file specified: ://bar.qml"; + QTest::newRow("invalid-qrc-dir") << ":/foo" << "Invalid main QML file specified: :/foo"; + + QTest::newRow("valid-native") << QFINDTESTDATA("dummy.qml") << ""; + QTest::newRow("valid-qrc-file") << ":/foo/dummy.qml" << ""; + QTest::newRow("valid-qrc-url") << "qrc:///foo/dummy.qml" << ""; + + // Passes unchecked: + QTest::newRow("https") << "https://www.qt.io/foo/bar.qml" << ""; + QTest::newRow("assets") << "assets:///foo/bar.qml" << ""; +} + +void tst_Main::mainQmlFile() +{ + QFETCH(QString, mainQml); + QFETCH(QString, expectedErrorMsg); + + QStringList arguments; + arguments << "tst_Main"; + arguments << "--dbus"; + arguments << "none"; + arguments << mainQml; + + main = new Main(argc, argv); + + config = new DefaultConfiguration(QStringList(QFINDTESTDATA("am-config.yaml")), QString()); + config->parseWithArguments(arguments); + + try { + main->setup(config); + QVERIFY2(expectedErrorMsg.isEmpty(), "Exception was expected, but none was thrown"); + } catch (const std::exception &e) { + QCOMPARE(e.what(), expectedErrorMsg); + } + + delete config; + config = nullptr; + delete main; + main = nullptr; +} + +QTEST_APPLESS_MAIN(tst_Main) + +#include "tst_main.moc" diff --git a/tests/auto/packagecreator/CMakeLists.txt b/tests/auto/packagecreator/CMakeLists.txt new file mode 100644 index 00000000..a9cf00d8 --- /dev/null +++ b/tests/auto/packagecreator/CMakeLists.txt @@ -0,0 +1,21 @@ + +qt_internal_add_test(tst_packagecreator + SOURCES + ../error-checking.h + tst_packagecreator.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManPackagePrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_packagecreator CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/packagecreator/packagecreator.pro b/tests/auto/packagecreator/packagecreator.pro new file mode 100644 index 00000000..269c12c7 --- /dev/null +++ b/tests/auto/packagecreator/packagecreator.pro @@ -0,0 +1,10 @@ +TARGET = tst_packagecreator + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_application-private \ + appman_package-private + +SOURCES += tst_packagecreator.cpp diff --git a/tests/auto/packagecreator/tst_packagecreator.cpp b/tests/auto/packagecreator/tst_packagecreator.cpp new file mode 100644 index 00000000..1cd237b6 --- /dev/null +++ b/tests/auto/packagecreator/tst_packagecreator.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "global.h" +#include "installationreport.h" +#include "packageutilities.h" +#include "packagecreator.h" +#include "utilities.h" + +#include "../error-checking.h" + +QT_USE_NAMESPACE_AM + +static int processTimeout = 3000; + +class tst_PackageCreator : public QObject +{ + Q_OBJECT + +public: + tst_PackageCreator(); + +private slots: + void initTestCase(); + + void createAndVerify_data(); + void createAndVerify(); + +private: + QString escapeFilename(const QString &name); + +private: + QDir m_baseDir; + bool m_tarAvailable = false; + bool m_isCygwin = false; +}; + +tst_PackageCreator::tst_PackageCreator() + : m_baseDir(qSL(AM_TESTDATA_DIR)) +{ } + +void tst_PackageCreator::initTestCase() +{ + processTimeout *= timeoutFactor(); + + // check if tar command is available at all + QProcess tar; + tar.start(qSL("tar"), { qSL("--version") }); + m_tarAvailable = tar.waitForStarted(processTimeout) + && tar.waitForFinished(processTimeout) + && (tar.exitStatus() == QProcess::NormalExit); + + m_isCygwin = tar.readAllStandardOutput().contains("Cygwin"); + + QVERIFY(PackageUtilities::checkCorrectLocale()); + + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); +} + +void tst_PackageCreator::createAndVerify_data() +{ + QTest::addColumn("files"); + QTest::addColumn("expectedSuccess"); + QTest::addColumn("errorString"); + + QTest::newRow("basic") << QStringList { qSL("testfile") } << true << QString(); + QTest::newRow("no-such-file") << QStringList { qSL("tastfile") } << false << qSL("~file not found: .*"); +} + +void tst_PackageCreator::createAndVerify() +{ + QFETCH(QStringList, files); + QFETCH(bool, expectedSuccess); + QFETCH(QString, errorString); + + QTemporaryFile output; + QVERIFY(output.open()); + + InstallationReport report(qSL("com.pelagicore.test")); + report.addFiles(files); + + PackageCreator creator(m_baseDir, &output, report); + bool result = creator.create(); + output.close(); + + if (expectedSuccess) { + QVERIFY2(result, qPrintable(creator.errorString())); + } else { + QVERIFY(creator.errorCode() != Error::None); + QVERIFY(creator.errorCode() != Error::Canceled); + QVERIFY(!creator.wasCanceled()); + + AM_CHECK_ERRORSTRING(creator.errorString(), errorString); + return; + } + + // check the tar listing + if (!m_tarAvailable) + QSKIP("No tar command found in PATH - skipping the verification part of the test!"); + + QProcess tar; + tar.start(qSL("tar"), { qSL("-tzf"), escapeFilename(output.fileName()) }); + QVERIFY2(tar.waitForStarted(processTimeout) && + tar.waitForFinished(processTimeout) && + (tar.exitStatus() == QProcess::NormalExit) && + (tar.exitCode() == 0), qPrintable(tar.errorString())); + + QStringList expectedContents = files; + expectedContents.sort(); + expectedContents.prepend(qSL("--PACKAGE-HEADER--")); + expectedContents.append(qSL("--PACKAGE-FOOTER--")); + + QStringList actualContents = QString::fromLocal8Bit(tar.readAllStandardOutput()).split(qL1C('\n'), Qt::SkipEmptyParts); +#if defined(Q_OS_WIN) + actualContents.replaceInStrings(qSL("\r"), QString()); +#endif + QCOMPARE(actualContents, expectedContents); + + // check the contents of the files + + for (const QString &file : qAsConst(files)) { + QFile src(m_baseDir.absoluteFilePath(file)); + QVERIFY2(src.open(QFile::ReadOnly), qPrintable(src.errorString())); + QByteArray data = src.readAll(); + + tar.start(qSL("tar"), { qSL("-xzOf"), escapeFilename(output.fileName()), file }); + QVERIFY2(tar.waitForStarted(processTimeout) && + tar.waitForFinished(processTimeout) && + (tar.exitStatus() == QProcess::NormalExit) && + (tar.exitCode() == 0), qPrintable(tar.errorString())); + + QCOMPARE(tar.readAllStandardOutput(), data); + } +} + +QString tst_PackageCreator::escapeFilename(const QString &name) +{ + if (!m_isCygwin) { + return name; + } else { + QString s = QFileInfo(name).absoluteFilePath(); + QString t = qSL("/cygdrive/"); + t.append(s.at(0)); + return t + s.mid(2); + } +} + +int main(int argc, char *argv[]) +{ + PackageUtilities::ensureCorrectLocale(); + QCoreApplication app(argc, argv); + app.setAttribute(Qt::AA_Use96Dpi, true); + tst_PackageCreator tc; + QTEST_SET_MAIN_SOURCE_PATH + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_packagecreator.moc" diff --git a/tests/auto/packageextractor/CMakeLists.txt b/tests/auto/packageextractor/CMakeLists.txt new file mode 100644 index 00000000..9775d7a3 --- /dev/null +++ b/tests/auto/packageextractor/CMakeLists.txt @@ -0,0 +1,21 @@ + +qt_internal_add_test(tst_packageextractor + SOURCES + ../error-checking.h + tst_packageextractor.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManPackagePrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_packageextractor CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/packageextractor/packageextractor.pro b/tests/auto/packageextractor/packageextractor.pro new file mode 100644 index 00000000..761720cf --- /dev/null +++ b/tests/auto/packageextractor/packageextractor.pro @@ -0,0 +1,10 @@ +TARGET = tst_packageextractor + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_application-private \ + appman_package-private + +SOURCES += tst_packageextractor.cpp diff --git a/tests/auto/packageextractor/tst_packageextractor.cpp b/tests/auto/packageextractor/tst_packageextractor.cpp new file mode 100644 index 00000000..50dd78a6 --- /dev/null +++ b/tests/auto/packageextractor/tst_packageextractor.cpp @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#if defined(Q_OS_UNIX) +# include +# include +# include +#endif + +#include "global.h" +#include "packageextractor.h" +#include "installationreport.h" +#include "packageutilities.h" + +#include "../error-checking.h" + +QT_USE_NAMESPACE_AM + +class tst_PackageExtractor : public QObject +{ + Q_OBJECT + +public: + tst_PackageExtractor(); + +private slots: + void initTestCase(); + void init(); + void cleanup(); + + void extractAndVerify_data(); + void extractAndVerify(); + + void cancelExtraction(); + + void extractFromFifo(); + +private: + QString m_taest; + QScopedPointer m_extractDir; +}; + +tst_PackageExtractor::tst_PackageExtractor() + : m_taest(QString::fromUtf8("t\xc3\xa4st")) +{ } + +void tst_PackageExtractor::initTestCase() +{ + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); + + QVERIFY(PackageUtilities::checkCorrectLocale()); +} + +void tst_PackageExtractor::init() +{ + m_extractDir.reset(new QTemporaryDir()); + QVERIFY(m_extractDir->isValid()); +} + +void tst_PackageExtractor::cleanup() +{ + m_extractDir.reset(); +} + +void tst_PackageExtractor::extractAndVerify_data() +{ + QTest::addColumn("path"); + QTest::addColumn("expectedSuccess"); + QTest::addColumn("errorString"); + QTest::addColumn("entries"); + QTest::addColumn>("content"); + QTest::addColumn>("sizes"); + + QStringList noEntries; + QMap noContent; + QMap noSizes; + + QTest::newRow("normal") << "packages/test.appkg" + << true << QString() + << QStringList { + "info.yaml", + "icon.png", + "test", + m_taest } + << QMap { + { "test", "test\n" }, + { m_taest, "test with umlaut\n" } } + << noSizes; + + QTest::newRow("big") << "packages/bigtest.appkg" + << true << QString() + << QStringList { + "info.yaml", + "icon.png", + "test", + m_taest, + "bigtest" } + << QMap { + { "test", "test\n" }, + { m_taest, "test with umlaut\n" } } + << QMap { + // { "info.yaml", 213 }, // this is different on Windows: \n vs. \r\n + { "icon.png", 1157 }, + { "bigtest", 5*1024*1024 }, + { "test", 5 }, + { m_taest, 17 } }; + + QTest::newRow("invalid-url") << "packages/no-such-file.appkg" + << false << "~Error opening .*: (No such file or directory|The system cannot find the file specified\\.)" + << noEntries << noContent << noSizes; + QTest::newRow("invalid-format") << "packages/test-invalid-format.appkg" + << false << "~.* could not open archive: Unrecognized archive format" + << noEntries << noContent << noSizes; + QTest::newRow("invalid-digest") << "packages/test-invalid-footer-digest.appkg" + << false << "~package digest mismatch.*" + << noEntries << noContent << noSizes; + QTest::newRow("invalid-path") << "packages/test-invalid-path.appkg" + << false << "~invalid archive entry .*: pointing outside of extraction directory" + << noEntries << noContent << noSizes; +} + +void tst_PackageExtractor::extractAndVerify() +{ + // macros are stupid... + typedef QMap ByteArrayMap; + typedef QMap IntMap; + + QFETCH(QString, path); + QFETCH(bool, expectedSuccess); + QFETCH(QString, errorString); + QFETCH(QStringList, entries); + QFETCH(ByteArrayMap, content); + QFETCH(IntMap, sizes); + + PackageExtractor extractor(QUrl::fromLocalFile(AM_TESTDATA_DIR + path), m_extractDir->path()); + bool result = extractor.extract(); + + if (expectedSuccess) { + QVERIFY2(result, qPrintable(extractor.errorString())); + } else { + QVERIFY(extractor.errorCode() != Error::None); + QVERIFY(extractor.errorCode() != Error::Canceled); + QVERIFY(!extractor.wasCanceled()); + + AM_CHECK_ERRORSTRING(extractor.errorString(), errorString); + return; + } + + QStringList checkEntries(entries); + QDirIterator it(m_extractDir->path(), QDir::NoDotAndDotDot | QDir::AllEntries, QDirIterator::Subdirectories); + while (it.hasNext()) { + QString entry = it.next(); + entry = entry.mid(m_extractDir->path().size() + 1); + + QVERIFY2(checkEntries.contains(entry), qPrintable(entry)); + + if (content.contains(entry)) { + QVERIFY(QDir(m_extractDir->path()).exists(entry)); + QFile f(QDir(m_extractDir->path()).absoluteFilePath(entry)); + QVERIFY(f.open(QFile::ReadOnly)); + QCOMPARE(f.readAll(), content.value(entry)); + } + + if (sizes.contains(entry)) { + QVERIFY(QDir(m_extractDir->path()).exists(entry)); + QFile f(QDir(m_extractDir->path()).absoluteFilePath(entry)); + QCOMPARE(f.size(), sizes.value(entry)); + } + + QVERIFY(checkEntries.removeOne(entry)); + } + + QVERIFY2(checkEntries.isEmpty(), qPrintable(checkEntries.join(qL1C(' ')))); + + QStringList reportEntries = extractor.installationReport().files(); + reportEntries.sort(); + entries.sort(); + QCOMPARE(reportEntries, entries); +} + +void tst_PackageExtractor::cancelExtraction() +{ + { + PackageExtractor extractor(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test.appkg")), m_extractDir->path()); + extractor.cancel(); + QVERIFY(!extractor.extract()); + QVERIFY(extractor.wasCanceled()); + QVERIFY(extractor.errorCode() == Error::Canceled); + QVERIFY(extractor.hasFailed()); + } + { + PackageExtractor extractor(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test.appkg")), m_extractDir->path()); + connect(&extractor, &PackageExtractor::progress, this, [&extractor](qreal p) { + if (p >= 0.1) + extractor.cancel(); + }); + QVERIFY(!extractor.extract()); + QVERIFY(extractor.wasCanceled()); + QVERIFY(extractor.errorCode() == Error::Canceled); + QVERIFY(extractor.hasFailed()); + } +} + +class FifoSource : public QThread // clazy:exclude=missing-qobject-macro +{ +public: + FifoSource(const QString &file) + : m_file(file) + { + m_fifoPath = QDir::temp().absoluteFilePath(qSL("autotext-package-extractor-%1.fifo")) + .arg(QCoreApplication::applicationPid()) + .toLocal8Bit(); +#ifdef Q_OS_UNIX + QVERIFY2(m_file.open(QFile::ReadOnly), qPrintable(m_file.errorString())); + QVERIFY2(::mkfifo(m_fifoPath, 0600) == 0, ::strerror(errno)); +#endif + } + + ~FifoSource() + { +#ifdef Q_OS_UNIX + ::unlink(m_fifoPath); +#endif + } + + QString path() const + { + return QString::fromLocal8Bit(m_fifoPath); + } + + void run() override + { +#ifdef Q_OS_UNIX + int fifoFd = QT_OPEN(m_fifoPath, O_WRONLY); + QVERIFY2(fifoFd >= 0, ::strerror(errno)); + + QByteArray buffer; + buffer.resize(1024 * 1024); + + while (!m_file.atEnd()) { + qint64 bytesRead = m_file.read(buffer.data(), buffer.size()); + QVERIFY(bytesRead >= 0); + qint64 bytesWritten = QT_WRITE(fifoFd, buffer.constData(), bytesRead); + QCOMPARE(bytesRead, bytesWritten); + } + QT_CLOSE(fifoFd); +#endif + } + +private: + QFile m_file; + QByteArray m_fifoPath; +}; + +void tst_PackageExtractor::extractFromFifo() +{ +#if !defined(Q_OS_UNIX) + QSKIP("No FIFO support on this platform"); +#endif + + FifoSource fifo(qL1S(AM_TESTDATA_DIR "packages/test.appkg")); + fifo.start(); + + PackageExtractor extractor(QUrl::fromLocalFile(fifo.path()), m_extractDir->path()); + QVERIFY2(extractor.extract(), qPrintable(extractor.errorString())); + QTRY_VERIFY(fifo.isFinished()); +} + +int main(int argc, char *argv[]) +{ + PackageUtilities::ensureCorrectLocale(); + QCoreApplication app(argc, argv); + app.setAttribute(Qt::AA_Use96Dpi, true); + tst_PackageExtractor tc; + QTEST_SET_MAIN_SOURCE_PATH + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_packageextractor.moc" diff --git a/tests/auto/packager-tool/CMakeLists.txt b/tests/auto/packager-tool/CMakeLists.txt new file mode 100644 index 00000000..8521f7f1 --- /dev/null +++ b/tests/auto/packager-tool/CMakeLists.txt @@ -0,0 +1,23 @@ + +qt_internal_add_test(tst_packager-tool + SOURCES + ../../../src/tools/packager/packagingjob.cpp + ../error-checking.h + tst_packager-tool.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + INCLUDE_DIRECTORIES + ../../../src/tools/packager + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManCryptoPrivate + Qt::AppManManagerPrivate + Qt::AppManPackagePrivate +) + +qt_internal_extend_target(tst_packager-tool CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/packager-tool/packager-tool.pro b/tests/auto/packager-tool/packager-tool.pro new file mode 100644 index 00000000..08876ac6 --- /dev/null +++ b/tests/auto/packager-tool/packager-tool.pro @@ -0,0 +1,15 @@ +TARGET = tst_packager-tool + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_crypto-private \ + appman_application-private \ + appman_package-private \ + appman_manager-private \ + +INCLUDEPATH += $$PWD/../../src/tools/packager +SOURCES += $$PWD/../../src/tools/packager/packagingjob.cpp + +SOURCES += tst_packager-tool.cpp diff --git a/tests/auto/packager-tool/tst_packager-tool.cpp b/tests/auto/packager-tool/tst_packager-tool.cpp new file mode 100644 index 00000000..7826caee --- /dev/null +++ b/tests/auto/packager-tool/tst_packager-tool.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "global.h" +#include "applicationmanager.h" +#include "application.h" +#include "qtyaml.h" +#include "exception.h" +#include "packagedatabase.h" +#include "packagemanager.h" +#include "packagingjob.h" +#include "qmlinprocessruntime.h" +#include "runtimefactory.h" +#include "utilities.h" + +#include "../error-checking.h" + +QT_USE_NAMESPACE_AM + +static int spyTimeout = 5000; // shorthand for specifying QSignalSpy timeouts + +class tst_PackagerTool : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanup(); + + void test(); + void brokenMetadata_data(); + void brokenMetadata(); + void iconFileName(); + +private: + QString pathTo(const char *file) + { + return QDir(m_workDir.path()).absoluteFilePath(QLatin1String(file)); + } + + bool createInfoYaml(QTemporaryDir &tmp, const QString &changeField = QString(), const QVariant &toValue = QVariant()); + bool createIconPng(QTemporaryDir &tmp); + bool createCode(QTemporaryDir &tmp); + void createDummyFile(QTemporaryDir &tmp, const QString &fileName, const char *data); + + void installPackage(const QString &filePath); + + PackageManager *m_pm = nullptr; + QTemporaryDir m_workDir; + + QString m_devPassword; + QString m_devCertificate; + QString m_storePassword; + QString m_storeCertificate; + QStringList m_caFiles; + QString m_hardwareId; +}; + +void tst_PackagerTool::initTestCase() +{ + if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) + QSKIP("No test packages available in the data/ directory"); + + spyTimeout *= timeoutFactor(); + + QVERIFY(m_workDir.isValid()); + QVERIFY(QDir::root().mkpath(pathTo("internal-0"))); + QVERIFY(QDir::root().mkpath(pathTo("documents-0"))); + + m_hardwareId = qSL("foobar"); + + PackageDatabase *pdb = new PackageDatabase({}, pathTo("internal-0")); + try { + m_pm = PackageManager::createInstance(pdb, pathTo("documents-0")); + m_pm->setHardwareId(m_hardwareId); + m_pm->enableInstaller(); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } + + QVERIFY(ApplicationManager::createInstance(true)); + + + // crypto stuff - we need to load the root CA and developer CA certificates + + QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt")); + QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt")); + QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); + QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); + + QList chainOfTrust; + chainOfTrust << devcaFile.readAll() << caFile.readAll(); + QVERIFY(!chainOfTrust.at(0).isEmpty()); + QVERIFY(!chainOfTrust.at(1).isEmpty()); + m_pm->setCACertificates(chainOfTrust); + + m_caFiles << devcaFile.fileName() << caFile.fileName(); + + m_devPassword = qSL("password"); + m_devCertificate = qL1S(AM_TESTDATA_DIR "certificates/dev1.p12"); + m_storePassword = qSL("password"); + m_storeCertificate = qL1S(AM_TESTDATA_DIR "certificates/store.p12"); + + RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("qml"))); +} + +void tst_PackagerTool::cleanup() +{ + recursiveOperation(pathTo("internal-0"), safeRemove); + recursiveOperation(pathTo("documents-0"), safeRemove); + + QDir dir(m_workDir.path()); + QStringList fileNames = dir.entryList(QDir::Files); + for (auto fileName : fileNames) + dir.remove(fileName); +} + +// exceptions are nice -- just not for unit testing :) +static bool packagerCheck(PackagingJob *p, QString &errorString) +{ + bool result = false; + try { + p->execute(); + errorString.clear(); + result = (p->resultCode() == 0); + if (!result) + errorString = p->output(); + } catch (const Exception &e) { \ + errorString = e.errorString(); + } + delete p; + return result; +} + +void tst_PackagerTool::test() +{ + QTemporaryDir tmp; + QString errorString; + + // no valid destination + QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), pathTo("test.appkg")), errorString)); + QVERIFY2(errorString.contains(qL1S("is not a directory")), qPrintable(errorString)); + + // no valid info.yaml + QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); + QVERIFY2(errorString.contains(qL1S("Cannot open for reading")), qPrintable(errorString)); + + // add an info.yaml file + createInfoYaml(tmp); + + // no icon + QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); + QVERIFY2(errorString.contains(qL1S("missing the file referenced by the 'icon' field")), qPrintable(errorString)); + + // add an icon + createIconPng(tmp); + + // no valid code + QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); + QVERIFY2(errorString.contains(qL1S("missing the file referenced by the 'code' field")), qPrintable(errorString)); + + // add a code file + createCode(tmp); + + // invalid destination + QVERIFY(!packagerCheck(PackagingJob::create(tmp.path(), tmp.path()), errorString)); + QVERIFY2(errorString.contains(qL1S("could not create package file")), qPrintable(errorString)); + + // now everything is correct - try again + QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString), qPrintable(errorString)); + + // invalid source package + QVERIFY(!packagerCheck(PackagingJob::developerSign( + pathTo("no-such-file"), + pathTo("test.dev-signed.appkg"), + m_devCertificate, + m_devPassword), errorString)); + QVERIFY2(errorString.contains(qL1S("does not exist")), qPrintable(errorString)); + + // invalid destination package + QVERIFY(!packagerCheck(PackagingJob::developerSign( + pathTo("test.appkg"), + pathTo("."), + m_devCertificate, + m_devPassword), errorString)); + QVERIFY2(errorString.contains(qL1S("could not create package file")), qPrintable(errorString)); + + + // invalid dev key + QVERIFY(!packagerCheck(PackagingJob::developerSign( + pathTo("test.appkg"), + pathTo("test.dev-signed.appkg"), + m_devCertificate, + qSL("wrong-password")), errorString)); + QVERIFY2(errorString.contains(qL1S("could not create signature")), qPrintable(errorString)); + + // invalid store key + QVERIFY(!packagerCheck(PackagingJob::storeSign( + pathTo("test.appkg"), + pathTo("test.store-signed.appkg"), + m_storeCertificate, + qSL("wrong-password"), + m_hardwareId), errorString)); + QVERIFY2(errorString.contains(qL1S("could not create signature")), qPrintable(errorString)); + + // sign + QVERIFY2(packagerCheck(PackagingJob::developerSign( + pathTo("test.appkg"), + pathTo("test.dev-signed.appkg"), + m_devCertificate, + m_devPassword), errorString), qPrintable(errorString)); + + QVERIFY2(packagerCheck(PackagingJob::storeSign( + pathTo("test.appkg"), + pathTo("test.store-signed.appkg"), + m_storeCertificate, + m_storePassword, + m_hardwareId), errorString), qPrintable(errorString)); + + // verify + QVERIFY2(packagerCheck(PackagingJob::developerVerify( + pathTo("test.dev-signed.appkg"), + m_caFiles), errorString), qPrintable(errorString)); + + QVERIFY2(packagerCheck(PackagingJob::storeVerify( + pathTo("test.store-signed.appkg"), + m_caFiles, + m_hardwareId), errorString), qPrintable(errorString)); + + // now that we have it, see if the package actually installs correctly + + installPackage(pathTo("test.dev-signed.appkg")); + + QDir checkDir(pathTo("internal-0")); + QVERIFY(checkDir.cd(qSL("com.pelagicore.test"))); + + for (const QString &file : { qSL("info.yaml"), qSL("icon.png"), qSL("test.qml") }) { + QVERIFY(checkDir.exists(file)); + QFile src(QDir(tmp.path()).absoluteFilePath(file)); + QVERIFY(src.open(QFile::ReadOnly)); + QFile dst(checkDir.absoluteFilePath(file)); + QVERIFY(dst.open(QFile::ReadOnly)); + QCOMPARE(src.readAll(), dst.readAll()); + } +} + +void tst_PackagerTool::brokenMetadata_data() +{ + QTest::addColumn("yamlField"); + QTest::addColumn("yamlValue"); + QTest::addColumn("errorString"); + + QTest::newRow("missing-name") << qSL("name") << QVariant() << "~.*Required fields are missing: name.*"; + QTest::newRow("missing-runtime") << qSL("runtime") << QVariant() << "~.*Required fields are missing: runtime"; + QTest::newRow("missing-identifier") << qSL("id") << QVariant() << "~.*Required fields are missing: id"; + QTest::newRow("missing-code") << qSL("code") << QVariant() << "~.*Required fields are missing: code"; +} + +void tst_PackagerTool::brokenMetadata() +{ + QFETCH(QString, yamlField); + QFETCH(QVariant, yamlValue); + QFETCH(QString, errorString); + + QTemporaryDir tmp; + + createCode(tmp); + createIconPng(tmp); + createInfoYaml(tmp, yamlField, yamlValue); + + // check if packaging actually fails with the expected error + + QString error; + QVERIFY2(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error), qPrintable(error)); + AM_CHECK_ERRORSTRING(error, errorString); +} + +/* + Specify an icon whose name is different from "icon.png". + Packaging should work fine + */ +void tst_PackagerTool::iconFileName() +{ + QTemporaryDir tmp; + QString errorString; + + createInfoYaml(tmp, qSL("icon"), qSL("foo.bar")); + createCode(tmp); + createDummyFile(tmp, qSL("foo.bar"), "this-is-a-dummy-icon-file"); + + QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test-foobar-icon.appkg"), tmp.path()), errorString), + qPrintable(errorString)); + + // see if the package installs correctly + + m_pm->setAllowInstallationOfUnsignedPackages(true); + installPackage(pathTo("test-foobar-icon.appkg")); + m_pm->setAllowInstallationOfUnsignedPackages(false); + + QDir checkDir(pathTo("internal-0")); + QVERIFY(checkDir.cd(qSL("com.pelagicore.test"))); + + for (const QString &file : { qSL("info.yaml"), qSL("foo.bar"), qSL("test.qml") }) { + QVERIFY(checkDir.exists(file)); + QFile src(QDir(tmp.path()).absoluteFilePath(file)); + QVERIFY(src.open(QFile::ReadOnly)); + QFile dst(checkDir.absoluteFilePath(file)); + QVERIFY(dst.open(QFile::ReadOnly)); + QCOMPARE(src.readAll(), dst.readAll()); + } +} + + +bool tst_PackagerTool::createInfoYaml(QTemporaryDir &tmp, const QString &changeField, const QVariant &toValue) +{ + QByteArray yaml = + "formatVersion: 1\n" + "formatType: am-application\n" + "---\n" + "id: com.pelagicore.test\n" + "name: { en_US: 'test' }\n" + "icon: icon.png\n" + "code: test.qml\n" + "runtime: qml\n"; + + if (!changeField.isEmpty()) { + QVector docs; + try { + docs = YamlParser::parseAllDocuments(yaml); + } catch (...) { + } + + QVariantMap map = docs.at(1).toMap(); + if (!toValue.isValid()) + map.remove(changeField); + else + map[changeField] = toValue; + yaml = QtYaml::yamlFromVariantDocuments({ docs.at(0), map }); + } + + QFile infoYaml(QDir(tmp.path()).absoluteFilePath(qSL("info.yaml"))); + return infoYaml.open(QFile::WriteOnly) && infoYaml.write(yaml) == yaml.size(); +} + +bool tst_PackagerTool::createIconPng(QTemporaryDir &tmp) +{ + QFile iconPng(QDir(tmp.path()).absoluteFilePath(qSL("icon.png"))); + return iconPng.open(QFile::WriteOnly) && iconPng.write("\x89PNG") == 4; +} + +bool tst_PackagerTool::createCode(QTemporaryDir &tmp) +{ + QFile code(QDir(tmp.path()).absoluteFilePath(qSL("test.qml"))); + return code.open(QFile::WriteOnly) && code.write("// test") == 7LL; +} + +void tst_PackagerTool::createDummyFile(QTemporaryDir &tmp, const QString &fileName, const char *data) +{ + QFile code(QDir(tmp.path()).absoluteFilePath(fileName)); + QVERIFY(code.open(QFile::WriteOnly)); + + auto written = code.write(data); + + QCOMPARE(written, static_cast(strlen(data))); +} + +void tst_PackagerTool::installPackage(const QString &filePath) +{ + QSignalSpy finishedSpy(m_pm, &PackageManager::taskFinished); + + m_pm->setDevelopmentMode(true); // allow packages without store signature + + QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(filePath)); + m_pm->acknowledgePackageInstallation(taskId); + + QVERIFY(finishedSpy.wait(2 * spyTimeout)); + QCOMPARE(finishedSpy.first()[0].toString(), taskId); + + m_pm->setDevelopmentMode(false); +} + +QTEST_GUILESS_MAIN(tst_PackagerTool) + +#include "tst_packager-tool.moc" diff --git a/tests/auto/processreader/CMakeLists.txt b/tests/auto/processreader/CMakeLists.txt new file mode 100644 index 00000000..5e60adfc --- /dev/null +++ b/tests/auto/processreader/CMakeLists.txt @@ -0,0 +1,23 @@ + +qt_internal_add_test(tst_processreader + SOURCES + ../error-checking.h + tst_processreader.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate + Qt::AppManMonitorPrivate + Qt::AppManWindowPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_processreader CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/processreader/advanced.smaps b/tests/auto/processreader/advanced.smaps new file mode 100644 index 00000000..61212565 --- /dev/null +++ b/tests/auto/processreader/advanced.smaps @@ -0,0 +1,252 @@ +55e362f85000-55e36315a000 r-xp 00000000 08:05 20988510 /qtbase/bin/appman +Size: 1876 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 1704 kB +Pss: 1704 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 1704 kB +Private_Dirty: 0 kB +Referenced: 1704 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 1704 kB +VmFlags: rd ex mr mw me dw ?? sd +55e36315b000-55e363162000 r--p 001d5000 08:05 20988510 /qtbase/bin/appman +Size: 28 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 28 kB +Pss: 28 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 28 kB +Referenced: 28 kB +Anonymous: 28 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 28 kB +VmFlags: rd mr mw me dw ac ?? sd +55e363162000-55e363164000 rw-p 001dc000 08:05 20988510 /qtbase/bin/appman +Size: 8 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 8 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 8 kB +VmFlags: rd wr mr mw me dw ac ?? sd +55e363164000-55e363166000 rw-p 00000000 00:00 0 +Size: 8 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 4 kB +VmFlags: rd wr mr mw me ac sd +55e3645eb000-55e364c57000 rw-p 00000000 00:00 0 [heap] +Size: 6576 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 6288 kB +Pss: 6288 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 6288 kB +Referenced: 6288 kB +Anonymous: 6288 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 6288 kB +VmFlags: rd wr mr mw me ac sd +7f85d0000000-7f85d093a000 rw-p 00000000 00:00 0 +Size: 9448 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 9448 kB +Pss: 9448 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 9448 kB +Referenced: 9448 kB +Anonymous: 9448 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 9448 kB +VmFlags: rd wr mr mw me nr sd +7f85d093a000-7f85d4000000 ---p 00000000 00:00 0 +Size: 56088 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: mr mw me nr sd +7f85d5fef000-7f85d632d000 rw-s 00000000 00:2e 19336830 /run/user/1000/wayland-cursor-shared-jzyii9 (deleted) +Size: 3320 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd wr sh mr mw me ms sd +7f85d63c5000-7f85d63fc000 r-xp 00000000 08:01 4984507 /lib/x86_64-linux-gnu/libnss_systemd.so.2 +Size: 220 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 64 kB +Pss: 3 kB +Shared_Clean: 64 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 64 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 3 kB +VmFlags: rd ex mr mw me sd +7ffd75741000-7ffd75763000 rw-p 00000000 00:00 0 [stack] +Size: 136 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 64 kB +Pss: 64 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 64 kB +Referenced: 64 kB +Anonymous: 64 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 64 kB +VmFlags: rd wr mr mw me gd ac +7ffd757e9000-7ffd757ec000 r--p 00000000 00:00 0 [vvar] +Size: 12 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd mr pf io de dd sd +7ffd757ec000-7ffd757ee000 r-xp 00000000 00:00 0 [vdso] +Size: 8 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 4 kB +Pss: 0 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd ex mr mw me de sd diff --git a/tests/auto/processreader/basic.smaps b/tests/auto/processreader/basic.smaps new file mode 100644 index 00000000..00640230 --- /dev/null +++ b/tests/auto/processreader/basic.smaps @@ -0,0 +1,352 @@ +00400000-00413000 r-xp 00000000 b3:01 266877 application +Size: 76 kB +Rss: 76 kB +Pss: 38 kB +Shared_Clean: 76 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 76 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex mr mw me dw +00422000-00423000 rw-p 00012000 b3:01 266877 application +Size: 4 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me dw ac +00423000-004ec000 rw-p 00000000 00:00 0 [heap] +Size: 804 kB +Rss: 796 kB +Pss: 796 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 796 kB +Referenced: 796 kB +Anonymous: 796 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +004ed000-00bc9000 rw-p 00000000 00:00 0 [heap] +Size: 7024 kB +Rss: 6700 kB +Pss: 6700 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 6700 kB +Referenced: 6700 kB +Anonymous: 6700 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +7f54000000-7f54021000 rw-p 00000000 00:00 0 +Size: 132 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me nr +7f54021000-7f58000000 ---p 00000000 00:00 0 +Size: 65404 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: mr mw me nr +7f5c000000-7f5c00a000 rw-p 00000000 00:00 0 +Size: 40 kB +Rss: 40 kB +Pss: 40 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 40 kB +Referenced: 40 kB +Anonymous: 40 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me nr +7f600d1000-7f604d1000 rw-s 00000000 00:09 12516 anon_inode:dmabuf +Size: 4096 kB +Rss: 1656 kB +Pss: 828 kB +Shared_Clean: 0 kB +Shared_Dirty: 1656 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 1656 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr sh mr mw me ms dc de dd +7f604d1000-7f608d1000 rw-s 00000000 00:09 12516 anon_inode:dmabuf +Size: 4096 kB +Rss: 4084 kB +Pss: 2042 kB +Shared_Clean: 0 kB +Shared_Dirty: 4084 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4084 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr sh mr mw me ms dc de dd +7f614d2000-7f6168a000 r-xp 00000000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so +Size: 1760 kB +Rss: 1448 kB +Pss: 726 kB +Shared_Clean: 1444 kB +Shared_Dirty: 0 kB +Private_Clean: 4 kB +Private_Dirty: 0 kB +Referenced: 1448 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex mr mw me +7f6168a000-7f61699000 ---p 001b8000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so +Size: 60 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: mr mw me +7f61699000-7f616a0000 rw-p 001b7000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so +Size: 28 kB +Rss: 28 kB +Pss: 28 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 28 kB +Referenced: 28 kB +Anonymous: 28 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +7f61925000-7f61ef7000 r-xp 00000000 b3:01 13766 /linelength98/linelen.so +Size: 5960 kB +Rss: 4356 kB +Pss: 1554 kB +Shared_Clean: 4264 kB +Shared_Dirty: 0 kB +Private_Clean: 92 kB +Private_Dirty: 0 kB +Referenced: 4356 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex mr mw me +7f61ef7000-7f61f07000 ---p 005d2000 b3:01 13766 /linelength99/lineleng.so +Size: 64 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: mr mw me +7f61f07000-7f6204c000 rw-p 005d2000 b3:01 13766 /linelength100/lineleng.so +Size: 1300 kB +Rss: 1084 kB +Pss: 986 kB +Shared_Clean: 156 kB +Shared_Dirty: 0 kB +Private_Clean: 24 kB +Private_Dirty: 904 kB +Referenced: 1084 kB +Anonymous: 904 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +7f74146000-7f74945000 rw-p 00000000 00:00 0 [stack:3396] +Size: 8188 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 8 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +7f74946000-7f75145000 rw-p 00000000 00:00 0 [stack:3116] +Size: 8188 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 8 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac +7f78fff000-7f79001000 rw-s 00000000 00:16 37047 /tmp/.gl3LHuLJ (deleted) +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr sh mr mw me ms +7f79001000-7f79003000 r-xs 00000000 00:16 37047 /tmp/.gl3LHuLJ (deleted) +Size: 8 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex sh mr mw me ms +7f79005000-7f79006000 r--p 00000000 00:00 0 [vvar] +Size: 4 kB +Rss: 4 kB +Pss: 0 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd mr de +7f79006000-7f79007000 r-xp 00000000 00:00 0 [vdso] +Size: 4 kB +Rss: 4 kB +Pss: 0 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex mr mw me de +7ffc8f6000-7ffc917000 rw-p 00000000 00:00 0 [stack] +Size: 136 kB +Rss: 44 kB +Pss: 44 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 44 kB +Referenced: 44 kB +Anonymous: 44 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me gd ac diff --git a/tests/auto/processreader/invalid.smaps b/tests/auto/processreader/invalid.smaps new file mode 100644 index 00000000..146a42b8 --- /dev/null +++ b/tests/auto/processreader/invalid.smaps @@ -0,0 +1,16 @@ +00400000-00413000 r-xp 00000000 b3:01 266877 application +Size: #missing +Rss: 76 kB +Pss: 38 kB +Shared_Clean: 76 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 76 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +VmFlags: rd ex mr mw me dw diff --git a/tests/auto/processreader/processreader.pro b/tests/auto/processreader/processreader.pro new file mode 100644 index 00000000..c5caa674 --- /dev/null +++ b/tests/auto/processreader/processreader.pro @@ -0,0 +1,11 @@ +TARGET = tst_processreader + +include($$PWD/../tests.pri) + +QT *= appman_monitor-private \ + appman_manager-private \ + appman_window-private \ + appman_application-private \ + appman_common-private + +SOURCES += tst_processreader.cpp diff --git a/tests/auto/processreader/tst_processreader.cpp b/tests/auto/processreader/tst_processreader.cpp new file mode 100644 index 00000000..baec84cb --- /dev/null +++ b/tests/auto/processreader/tst_processreader.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +QT_USE_NAMESPACE_AM + +class tst_ProcessReader : public QObject +{ + Q_OBJECT + +public: + tst_ProcessReader(); + +private slots: + void memInvalid_data(); + void memInvalid(); + void memTestProcess(); + void memBasic(); + void memAdvanced(); + +private: + void printMem(const ProcessReader &reader); + ProcessReader reader; +}; + +tst_ProcessReader::tst_ProcessReader() +{} + +void tst_ProcessReader::memInvalid_data() +{ + QTest::addColumn("file"); + + QTest::newRow("arbitrary") << QFINDTESTDATA("tst_processreader.cpp"); + QTest::newRow("binary") << QFINDTESTDATA("tst_processreader"); + QTest::newRow("missingvalue") << QFINDTESTDATA("invalid.smaps"); +} + +void tst_ProcessReader::memInvalid() +{ + QFETCH(QString, file); + + reader.testReadSmaps(file.toLocal8Bit()); + + QCOMPARE(reader.memory.totalVm, 0u); + QCOMPARE(reader.memory.totalRss, 0u); + QCOMPARE(reader.memory.totalPss, 0u); + QCOMPARE(reader.memory.textVm, 0u); + QCOMPARE(reader.memory.textRss, 0u); + QCOMPARE(reader.memory.textPss, 0u); + QCOMPARE(reader.memory.heapVm, 0u); + QCOMPARE(reader.memory.heapRss, 0u); + QCOMPARE(reader.memory.heapPss, 0u); +} + +void tst_ProcessReader::memTestProcess() +{ + const QByteArray file = "/proc/" + QByteArray::number(QCoreApplication::applicationPid()) + "/smaps"; + + QVERIFY(reader.testReadSmaps(file)); + //printMem(reader); + QVERIFY(reader.memory.totalVm >= reader.memory.totalRss); + QVERIFY(reader.memory.totalRss >= reader.memory.totalPss); + QVERIFY(reader.memory.textVm >= reader.memory.textRss); + QVERIFY(reader.memory.textRss >= reader.memory.textPss); + QVERIFY(reader.memory.heapVm >= reader.memory.heapRss); + QVERIFY(reader.memory.heapRss >= reader.memory.heapPss); +} + +void tst_ProcessReader::memBasic() +{ + QVERIFY(reader.testReadSmaps(QFINDTESTDATA("basic.smaps").toLocal8Bit())); + //printMem(reader); + QCOMPARE(reader.memory.totalVm, 107384u); + QCOMPARE(reader.memory.totalRss, 20352u); + QCOMPARE(reader.memory.totalPss, 13814u); + QCOMPARE(reader.memory.textVm, 7800u); + QCOMPARE(reader.memory.textRss, 5884u); + QCOMPARE(reader.memory.textPss, 2318u); + QCOMPARE(reader.memory.heapVm, 24376u); + QCOMPARE(reader.memory.heapRss, 7556u); + QCOMPARE(reader.memory.heapPss, 7556u); +} + +void tst_ProcessReader::memAdvanced() +{ + QVERIFY(reader.testReadSmaps(QFINDTESTDATA("advanced.smaps").toLocal8Bit())); + //printMem(reader); + QCOMPARE(reader.memory.totalVm, 77728u); + QCOMPARE(reader.memory.totalRss, 17612u); + QCOMPARE(reader.memory.totalPss, 17547u); + QCOMPARE(reader.memory.textVm, 2104u); + QCOMPARE(reader.memory.textRss, 1772u); + QCOMPARE(reader.memory.textPss, 1707u); + QCOMPARE(reader.memory.heapVm, 16032u); + QCOMPARE(reader.memory.heapRss, 15740u); + QCOMPARE(reader.memory.heapPss, 15740u); +} + +void tst_ProcessReader::printMem(const ProcessReader &reader) +{ + qDebug() << "totalVm:" << reader.memory.totalVm; + qDebug() << "totalRss:" << reader.memory.totalRss; + qDebug() << "totalPss:" << reader.memory.totalPss; + qDebug() << "textVm:" << reader.memory.textVm; + qDebug() << "textRss:" << reader.memory.textRss; + qDebug() << "textPss:" << reader.memory.textPss; + qDebug() << "heapVm:" << reader.memory.heapVm; + qDebug() << "heapRss:" << reader.memory.heapRss; + qDebug() << "heapPss:" << reader.memory.heapPss; +} + +QTEST_APPLESS_MAIN(tst_ProcessReader) + +#include "tst_processreader.moc" diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt new file mode 100644 index 00000000..73ee13fe --- /dev/null +++ b/tests/auto/qml/CMakeLists.txt @@ -0,0 +1,18 @@ +# Generated from qml.pro. + +add_subdirectory(simple) +add_subdirectory(windowmanager) +add_subdirectory(windowmapping) +add_subdirectory(windowitem) +add_subdirectory(windowitem2) +add_subdirectory(installer) +add_subdirectory(quicklaunch) +add_subdirectory(intents) +add_subdirectory(configs) +add_subdirectory(lifecycle) +add_subdirectory(resources) +if(multi-process) + add_subdirectory(crash/apps/tld.test.crash/terminator2) + add_subdirectory(crash) + add_subdirectory(processtitle) +endif() diff --git a/tests/auto/qml/configs/CMakeLists.txt b/tests/auto/qml/configs/CMakeLists.txt new file mode 100644 index 00000000..8bc54456 --- /dev/null +++ b/tests/auto/qml/configs/CMakeLists.txt @@ -0,0 +1,23 @@ +# Generated from configs.pro. + +##################################################################### +## configs Binary: +##################################################################### + +qt_internal_add_executable(configs + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:configs.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "test.configs.app" +# TEST_CONFIGURATIONS = "--force-single-process" "--force-single-process --single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" +# TEST_FILES = "tst_configs.qml" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:configs.pro:multi-process: +# TEST_CONFIGURATIONS = "--force-multi-process" "-c $$_PRO_FILE_PWD_/am-config-nodbus.yaml --dbus none" "--single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" "--disable-installer --wayland-socket-name wayland-am" diff --git a/tests/auto/qml/configs/am-config-nodbus.yaml b/tests/auto/qml/configs/am-config-nodbus.yaml new file mode 100644 index 00000000..78030bf0 --- /dev/null +++ b/tests/auto/qml/configs/am-config-nodbus.yaml @@ -0,0 +1,6 @@ +formatVersion: 1 +formatType: am-configuration +--- +systemProperties: + private: + nodbus: yes diff --git a/tests/auto/qml/configs/am-config.yaml b/tests/auto/qml/configs/am-config.yaml new file mode 100644 index 00000000..5333dae3 --- /dev/null +++ b/tests/auto/qml/configs/am-config.yaml @@ -0,0 +1,11 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +# Workaround for a crash in the mesa software renderer (llvmpipe) +runtimes: + qml: + environmentVariables: + QT_QUICK_BACKEND: "software" diff --git a/tests/auto/qml/configs/apps/test.configs.app/app.qml b/tests/auto/qml/configs/apps/test.configs.app/app.qml new file mode 100644 index 00000000..07a5f413 --- /dev/null +++ b/tests/auto/qml/configs/apps/test.configs.app/app.qml @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager 2.0 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + + onWindowPropertyChanged: { + if (name === "trigger" && value === "now") + root.setWindowProperty("ack", "done"); + } + + Notification { + id: notification + summary: "Test" + timeout: 20 + } + + ApplicationInterfaceExtension { + id: extension + name: "test.configs.interface" + + } + + Connections { + target: extension.object + function onTrigger(type) { + if (type === "Notification") { + if (target.func("bar") === 42) + notification.show(); + } else if (type === "PropertyChange") { + root.setWindowProperty("prop1", "bar"); + } + } + } + + Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } + } + + Component.onCompleted: { + setWindowProperty("prop1", "foo"); + } +} diff --git a/tests/auto/qml/configs/apps/test.configs.app/icon.png b/tests/auto/qml/configs/apps/test.configs.app/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/configs/apps/test.configs.app/icon.png differ diff --git a/tests/auto/qml/configs/apps/test.configs.app/info.yaml b/tests/auto/qml/configs/apps/test.configs.app/info.yaml new file mode 100644 index 00000000..401ed395 --- /dev/null +++ b/tests/auto/qml/configs/apps/test.configs.app/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.configs.app' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +name: + en: 'ApplicationManager Application' diff --git a/tests/auto/qml/configs/configs.pro b/tests/auto/qml/configs/configs.pro new file mode 100644 index 00000000..86604d5e --- /dev/null +++ b/tests/auto/qml/configs/configs.pro @@ -0,0 +1,15 @@ +load(am-config) + +AM_CONFIG = am-config.yaml +TEST_FILES = tst_configs.qml +TEST_APPS = test.configs.app +TEST_CONFIGURATIONS = "--force-single-process" \ + "--force-single-process --single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" +multi-process { + TEST_CONFIGURATIONS += "--force-multi-process" \ + "-c $$_PRO_FILE_PWD_/am-config-nodbus.yaml --dbus none" \ + "--single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" \ + "--disable-installer --wayland-socket-name wayland-am" +} + +load(am-qml-testcase) diff --git a/tests/auto/qml/configs/tst_configs.qml b/tests/auto/qml/configs/tst_configs.qml new file mode 100644 index 00000000..88c7bd48 --- /dev/null +++ b/tests/auto/qml/configs/tst_configs.qml @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + + +TestCase { + id: testCase + when: windowShown + name: "Configs" + visible: true + + + ApplicationIPCInterface { + id: appif + signal trigger(string type) + readonly property var _decltype_func: { "int": [ "string" ] } + function func(str) { return str === "bar" ? 42: 0; } + Component.onCompleted: ApplicationIPCManager.registerInterface(this, "test.configs.interface", {}); + } + + SignalSpy { + id: windowAddedSpy + target: WindowManager + signalName: "windowAdded" + } + + SignalSpy { + id: windowPropertyChangedSpy + // Workaround to flush Wayland messages, see https://bugreports.qt.io/browse/AUTOSUITE-709 + // A proper solution in QtWayland is sought here: https://bugreports.qt.io/browse/QTBUG-83422 + function aboutToBlockWait(timeout) + { + AmTest.aboutToBlock(); + wait(timeout); + } + target: WindowManager + signalName: "windowPropertyChanged" + } + +    SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + + function cleanup() { + runStateChangedSpy.clear(); + ApplicationManager.stopApplication("test.configs.app"); + runStateChangedSpy.wait(); + runStateChangedSpy.wait(); + compare(runStateChangedSpy.signalArguments[1][1], ApplicationObject.NotRunning); + } + + function test_basic_ipc() { + compare(NotificationManager.count, 0); + compare(windowAddedSpy.count, 0); + verify(ApplicationManager.startApplication("test.configs.app")) + windowAddedSpy.wait(); + compare(windowAddedSpy.count, 1); + var window = windowAddedSpy.signalArguments[0][0]; + compare(window.windowProperty("prop1"), "foo"); + appif.trigger("PropertyChange"); + windowPropertyChangedSpy.wait(); + compare(windowPropertyChangedSpy.count, 1); + compare(windowPropertyChangedSpy.signalArguments[0][0], window); + compare(window.windowProperty("prop1"), "bar"); + windowPropertyChangedSpy.clear(); + + if (!ApplicationManager.systemProperties.nodbus) { + appif.trigger("Notification"); + tryVerify(function() { return NotificationManager.count === 1; }); + compare(NotificationManager.get(0).summary, "Test"); + } + + window.setWindowProperty("trigger", "now"); + windowPropertyChangedSpy.aboutToBlockWait(); + compare(windowPropertyChangedSpy.signalArguments[0][0], window); + compare(window.windowProperty("trigger"), "now"); + + windowPropertyChangedSpy.wait(); + compare(windowPropertyChangedSpy.signalArguments[1][0], window); + compare(window.windowProperty("ack"), "done"); + } +} diff --git a/tests/auto/qml/crash/CMakeLists.txt b/tests/auto/qml/crash/CMakeLists.txt new file mode 100644 index 00000000..2ba8b4a4 --- /dev/null +++ b/tests/auto/qml/crash/CMakeLists.txt @@ -0,0 +1,17 @@ +# Generated from crash.pro. + +##################################################################### +## crash Binary: +##################################################################### + +qt_internal_add_executable(crash + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:crash.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "tld.test.crash" +# TEST_CONFIGURATIONS = "--force-multi-process" +# TEST_FILES = "tst_crash.qml" diff --git a/tests/auto/qml/crash/am-config.yaml b/tests/auto/qml/crash/am-config.yaml new file mode 100644 index 00000000..61b2bfb2 --- /dev/null +++ b/tests/auto/qml/crash/am-config.yaml @@ -0,0 +1,8 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +flags: + noUiWatchdog: yes diff --git a/tests/auto/qml/crash/apps/tld.test.crash/app.qml b/tests/auto/qml/crash/apps/tld.test.crash/app.qml new file mode 100644 index 00000000..a97c60f2 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/app.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtApplicationManager.Application 2.0 +import Terminator 2.0 + +ApplicationManagerWindow { + function accessIllegalMemory() + { + Terminator.accessIllegalMemory(); + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "illegalMemory": accessIllegalMemory(); break; + case "illegalMemoryInThread": Terminator.accessIllegalMemoryInThread(); break; + case "stackOverflow": Terminator.forceStackOverflow(); break; + case "divideByZero": Terminator.divideByZero(); break; + case "unhandledException": Terminator.throwUnhandledException(); break; + case "abort": Terminator.abort(); break; + case "raise": Terminator.raise(7); break; + case "gracefully": Terminator.exitGracefully(); break; + } + } + } +} diff --git a/tests/auto/qml/crash/apps/tld.test.crash/icon.png b/tests/auto/qml/crash/apps/tld.test.crash/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/crash/apps/tld.test.crash/icon.png differ diff --git a/tests/auto/qml/crash/apps/tld.test.crash/info.yaml b/tests/auto/qml/crash/apps/tld.test.crash/info.yaml new file mode 100644 index 00000000..77ca2e76 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/info.yaml @@ -0,0 +1,12 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'tld.test.crash' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +version: '1.0' +name: + en: 'Crash test' +runtimeParameters: + importPaths: [ "terminator2" ] diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/CMakeLists.txt b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/CMakeLists.txt new file mode 100644 index 00000000..21646c82 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated from terminator2.pro. + +##################################################################### +## terminator2plugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(terminator2plugin + MODULE + INSTALL_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Terminator" + EXCEPTIONS + OUTPUT_DIRECTORY "$$_PRO_FILE_PWD_/Terminator" + SOURCES + qmlterminator2.cpp qmlterminator2.h + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick +) + +#### Keys ignored in scope 1:.:.:terminator2.pro:: +# INSTALLS = "target" "qmldir" +# OTHER_FILES = "qmldir" +# QMAKE_POST_LINK = "$$QMAKE_COPY" "$$replace($$list $$quote $$PWD/qmldir $$DESTDIR , /, $$QMAKE_DIR_SEP)" +# TEMPLATE = "lib" +# qmldir.files = "$$PWD/qmldir" +# qmldir.path = "$$DESTDIR" +# target.path = "$$DESTDIR" + +qt_autogen_tools_initial_setup(terminator2plugin) diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/Terminator/qmldir b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/Terminator/qmldir new file mode 100644 index 00000000..ac15a495 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/Terminator/qmldir @@ -0,0 +1,2 @@ +module Terminator +plugin terminator2plugin diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmldir b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmldir new file mode 100644 index 00000000..ac15a495 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmldir @@ -0,0 +1,2 @@ +module Terminator +plugin terminator2plugin diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp new file mode 100644 index 00000000..5a90dc49 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qmlterminator2.h" + +#include + + +static QObject *terminator_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(scriptEngine) + return new Terminator(engine); +} + +void TerminatorPlugin::registerTypes(const char *uri) +{ + qmlRegisterSingletonType(uri, 2, 0, "Terminator", terminator_provider); +} + + +static void abortWithVeryLongSymbolNameOnTheStack800CharactersLong_CallMeIshmaelSomeYearsAgoNeverMindHowLongPreciselyHavingLittleOrNoMoneyInMyPurseAndNothingParticularToInterestMeOnShoreIThoughIWouldSailAboutALittlAndSeeTheWateryPartOfTheWorldItIsAWayIHaveOfDrivingOffTheSpleenAndRegulatingTheCirculationWhenenverIFindMyselfGrowingGrimAboutTheMouthWheneverItIsADampDrizzlyNovemberInMySoulWheneverIFindMyselfInvoluntarilyPausingBeforeCoffinWarehousesAndBringingUpTheRearOfEveryFuneralIMeetAndEspeciallyWheneverMyHyposGetSuchAnUpperHandOfMeThatItRequiresAStrongMoralPrincipleToPreventMeFromDeliberatelySteppingIntoTheStreetAndMethodicallyKnockingPeoplesHatsOffThenIAccountItHighTimeToGetToSeaAsSoonAsICanThisIsMySubstituteForPistolAndBallWithAPhilosophicalFlourishCatoThrowsHimselfUponHisSwordIQuietlyTakeToTheShip() +{ + ::abort(); +} + +void Terminator::accessIllegalMemory() const +{ + *(int*)1 = 42; +} + +void Terminator::accessIllegalMemoryInThread() +{ + TerminatorThread *t = new TerminatorThread(this); + t->start(); +} + +void Terminator::forceStackOverflow() const +{ + static constexpr int len = 100000; + volatile char buf[len]; + buf[len-1] = 42; + if (buf[len-1] == 42) + forceStackOverflow(); +} + +void Terminator::divideByZero() const +{ + int d = 0; + volatile int x = 42 / d; + Q_UNUSED(x) +} + +void Terminator::abort() const +{ + abortWithVeryLongSymbolNameOnTheStack800CharactersLong_CallMeIshmaelSomeYearsAgoNeverMindHowLongPreciselyHavingLittleOrNoMoneyInMyPurseAndNothingParticularToInterestMeOnShoreIThoughIWouldSailAboutALittlAndSeeTheWateryPartOfTheWorldItIsAWayIHaveOfDrivingOffTheSpleenAndRegulatingTheCirculationWhenenverIFindMyselfGrowingGrimAboutTheMouthWheneverItIsADampDrizzlyNovemberInMySoulWheneverIFindMyselfInvoluntarilyPausingBeforeCoffinWarehousesAndBringingUpTheRearOfEveryFuneralIMeetAndEspeciallyWheneverMyHyposGetSuchAnUpperHandOfMeThatItRequiresAStrongMoralPrincipleToPreventMeFromDeliberatelySteppingIntoTheStreetAndMethodicallyKnockingPeoplesHatsOffThenIAccountItHighTimeToGetToSeaAsSoonAsICanThisIsMySubstituteForPistolAndBallWithAPhilosophicalFlourishCatoThrowsHimselfUponHisSwordIQuietlyTakeToTheShip(); +} + +void Terminator::raise(int sig) const +{ + ::raise(sig); +} + +void Terminator::throwUnhandledException() const +{ + throw 42; +} + +void Terminator::exitGracefully() const +{ + exit(5); +} + + +TerminatorThread::TerminatorThread(Terminator *parent) + : QThread(parent), m_terminator(parent) +{ +} + +void TerminatorThread::run() +{ + m_terminator->accessIllegalMemory(); +} + +#include "moc_qmlterminator2.cpp" diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h new file mode 100644 index 00000000..27bc8e28 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include +#include + + +class TerminatorPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) override; +}; + + +class Terminator : public QObject +{ + Q_OBJECT + +public: + Terminator(QObject *parent) : QObject(parent) {} + + Q_INVOKABLE void accessIllegalMemory() const; + Q_INVOKABLE void accessIllegalMemoryInThread(); + Q_INVOKABLE void forceStackOverflow() const; + Q_INVOKABLE void divideByZero() const; + Q_INVOKABLE void abort() const; + Q_INVOKABLE void raise(int sig) const; + Q_INVOKABLE void throwUnhandledException() const; + Q_INVOKABLE void exitGracefully() const; +}; + + +class TerminatorThread : public QThread +{ + Q_OBJECT + +public: + explicit TerminatorThread(Terminator *parent); + +private: + void run() override; + Terminator *m_terminator; +}; diff --git a/tests/auto/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro new file mode 100644 index 00000000..3c482379 --- /dev/null +++ b/tests/auto/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro @@ -0,0 +1,18 @@ +TEMPLATE = lib +CONFIG += plugin exceptions +QT += qml quick + +TARGET = $$qtLibraryTarget(terminator2plugin) + +HEADERS += qmlterminator2.h +SOURCES += qmlterminator2.cpp + +DESTDIR = $$_PRO_FILE_PWD_/Terminator +target.path=$$DESTDIR +qmldir.files=$$PWD/qmldir +qmldir.path=$$DESTDIR +INSTALLS += target qmldir + +OTHER_FILES += qmldir + +QMAKE_POST_LINK += $$QMAKE_COPY $$replace($$list($$quote($$PWD/qmldir) $$DESTDIR), /, $$QMAKE_DIR_SEP) diff --git a/tests/auto/qml/crash/crash.pro b/tests/auto/qml/crash/crash.pro new file mode 100644 index 00000000..c1c7d869 --- /dev/null +++ b/tests/auto/qml/crash/crash.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_crash.qml +TEST_APPS = tld.test.crash +TEST_CONFIGURATIONS = "--force-multi-process" +load(am-qml-testcase) diff --git a/tests/auto/qml/crash/tst_crash.qml b/tests/auto/qml/crash/tst_crash.qml new file mode 100644 index 00000000..cc7f42d2 --- /dev/null +++ b/tests/auto/qml/crash/tst_crash.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "Crashtest" + + property string appId: "tld.test.crash" + property var app: ApplicationManager.application(appId); + + SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + function initTestCase() { + compare(app.lastExitStatus, ApplicationObject.NormalExit) + } + + function test_crash_data() { + return [ { tag: "gracefully" }, + { tag: "illegalMemory" }, + { tag: "illegalMemoryInThread" }, + { tag: "unhandledException" }, + { tag: "abort" } ]; + //{ tag: "stackOverflow" }, + //{ tag: "divideByZero" }, + //{ tag: "raise" } ]; + } + + function test_crash(data) { + ApplicationManager.startApplication(appId); + runStateChangedSpy.wait(3000); + runStateChangedSpy.wait(3000); + compare(app.runState, ApplicationObject.Running); + ApplicationManager.startApplication(appId, data.tag); + runStateChangedSpy.wait(3000); + compare(app.runState, ApplicationObject.NotRunning); + if (data.tag === "gracefully") { + compare(app.lastExitStatus, ApplicationObject.NormalExit); + compare(app.lastExitCode, 5); + } else { + compare(app.lastExitStatus, ApplicationObject.CrashExit); + console.info("================================"); + console.info("=== INTENDED CRASH (TESTING) ==="); + console.info("================================"); + } + } +} diff --git a/tests/auto/qml/installer/CMakeLists.txt b/tests/auto/qml/installer/CMakeLists.txt new file mode 100644 index 00000000..6daf54ee --- /dev/null +++ b/tests/auto/qml/installer/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from installer.pro. + +##################################################################### +## installer Binary: +##################################################################### + +qt_internal_add_executable(installer + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:installer.pro:: +# AM_CONFIG = "am-config.yaml" +# AM_TESTDATA_DIR = "\"$$PWD/../../data/\"" +# TEST_FILES = "tst_installer.qml" diff --git a/tests/auto/qml/installer/am-config.yaml b/tests/auto/qml/installer/am-config.yaml new file mode 100644 index 00000000..d0e12789 --- /dev/null +++ b/tests/auto/qml/installer/am-config.yaml @@ -0,0 +1,10 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + installationDir: "/tmp/am-installer-test/apps" + documentDir: "/tmp/am-installer-test/docs" + +flags: + noSecurity: yes diff --git a/tests/auto/qml/installer/apps/hello-world.red/app1.qml b/tests/auto/qml/installer/apps/hello-world.red/app1.qml new file mode 100644 index 00000000..7e6ba025 --- /dev/null +++ b/tests/auto/qml/installer/apps/hello-world.red/app1.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + color: "green" +} diff --git a/tests/auto/qml/installer/apps/hello-world.red/icon1.png b/tests/auto/qml/installer/apps/hello-world.red/icon1.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/installer/apps/hello-world.red/icon1.png differ diff --git a/tests/auto/qml/installer/apps/hello-world.red/info.yaml b/tests/auto/qml/installer/apps/hello-world.red/info.yaml new file mode 100644 index 00000000..1b628d1e --- /dev/null +++ b/tests/auto/qml/installer/apps/hello-world.red/info.yaml @@ -0,0 +1,10 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'hello-world.red' +version: 'v1' +icon: 'icon1.png' +code: 'app1.qml' +runtime: 'qml' +name: + en: 'Builtin Installation Test App v1' diff --git a/tests/auto/qml/installer/installer.pro b/tests/auto/qml/installer/installer.pro new file mode 100644 index 00000000..2adfb2a4 --- /dev/null +++ b/tests/auto/qml/installer/installer.pro @@ -0,0 +1,6 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_installer.qml + +AM_TESTDATA_DIR=\"$$PWD/../../data/\" + +load(am-qml-testcase) diff --git a/tests/auto/qml/installer/tst_installer.qml b/tests/auto/qml/installer/tst_installer.qml new file mode 100644 index 00000000..d3443ee7 --- /dev/null +++ b/tests/auto/qml/installer/tst_installer.qml @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + name: "Installer" + when: windowShown + + property var stateList: [] + property int spyTimeout: 5000 * AmTest.timeoutFactor + + SignalSpy { + id: taskFinishedSpy + target: PackageManager + signalName: "taskFinished" + } + + SignalSpy { + id: taskFailedSpy + target: PackageManager + signalName: "taskFailed" + } + + SignalSpy { + id: taskStateChangedSpy + target: PackageManager + signalName: "taskStateChanged" + } + + SignalSpy { + id: taskRequestingInstallationAcknowledgeSpy + target: PackageManager + signalName: "taskRequestingInstallationAcknowledge" + } + + SignalSpy { +        id: applicationChangedSpy +        target: ApplicationManager +        signalName: "applicationChanged" +    } + + + function init() { + // Remove previous installations + + for (var pkg of [ "hello-world.red", "com.pelagicore.test" ]) { + var po = PackageManager.package(pkg) + if (!po || (po.builtIn && !po.builtInHasRemovableUpdate)) + continue + if (PackageManager.removePackage(pkg, false, true)) { + taskFinishedSpy.wait(spyTimeout); + compare(taskFinishedSpy.count, 1); + taskFinishedSpy.clear(); + } + } + } + + function test_1states() { + PackageManager.packageAdded.connect(function(pkgId) { + var pkg = PackageManager.package(pkgId); + stateList.push(pkg.state) + pkg.stateChanged.connect(function(state) { + compare(state, pkg.state) + stateList.push(state) + }) + }) + + taskStateChangedSpy.clear(); + var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/test-dev-signed.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + compare(taskRequestingInstallationAcknowledgeSpy.count, 1); + compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); + var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.acknowledgePackageInstallation(id); + + if (!taskFinishedSpy.count) + taskFinishedSpy.wait(spyTimeout); + compare(taskFinishedSpy.count, 1); + taskFinishedSpy.clear(); + + compare(stateList.length, 2); + compare(stateList[0], PackageObject.BeingInstalled) + compare(stateList[1], PackageObject.Installed) + stateList = [] + + compare(PackageManager.package(pkgId).version, "1.0"); + + id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/test-update-dev-signed.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + compare(taskRequestingInstallationAcknowledgeSpy.count, 1); + compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.acknowledgePackageInstallation(id); + + taskFinishedSpy.wait(spyTimeout); + compare(taskFinishedSpy.count, 1); + taskFinishedSpy.clear(); + + compare(stateList[0], PackageObject.BeingUpdated) + compare(stateList[1], PackageObject.Installed) + stateList = [] + + compare(PackageManager.package(pkgId).version, "2.0"); + + id = PackageManager.removePackage(pkgId, false, false); + + taskFinishedSpy.wait(spyTimeout); + compare(taskFinishedSpy.count, 1); + taskFinishedSpy.clear(); + + compare(stateList[0], PackageObject.BeingRemoved) + stateList = [] + // Cannot compare app.state any more, since app might already be dead + + verify(taskStateChangedSpy.count > 10); + var taskStates = [ PackageManager.Executing, + PackageManager.AwaitingAcknowledge, + PackageManager.Installing, + PackageManager.CleaningUp, + PackageManager.Finished, + PackageManager.Executing, + PackageManager.AwaitingAcknowledge, + PackageManager.Installing, + PackageManager.CleaningUp, + PackageManager.Finished, + PackageManager.Executing ] + for (var i = 0; i < taskStates.length; i++) + compare(taskStateChangedSpy.signalArguments[i][1], taskStates[i], "- index: " + i); + } + + function test_2cancel_update() { + var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/test-dev-signed.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + compare(taskRequestingInstallationAcknowledgeSpy.count, 1); + compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); + var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id + compare(pkgId, "com.pelagicore.test"); + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.acknowledgePackageInstallation(id); + + taskFinishedSpy.wait(spyTimeout); + taskFinishedSpy.clear(); + + var pkg = PackageManager.package(pkgId); + compare(pkg.version, "1.0"); + + id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/test-update-dev-signed.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id + compare(pkgId, "com.pelagicore.test"); + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.cancelTask(id); + + taskFailedSpy.wait(spyTimeout); + taskFailedSpy.clear(); + + compare(pkg.version, "1.0"); + } + + function test_3cancel_builtin_update() { + taskStateChangedSpy.clear() + var pkg = PackageManager.package("hello-world.red"); + verify(pkg.builtIn); + compare(pkg.icon.toString().slice(-9), "icon1.png") + compare(pkg.version, "v1"); + + var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/hello-world.red.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + compare(taskRequestingInstallationAcknowledgeSpy.count, 1); + compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.cancelTask(id); + + taskFailedSpy.wait(spyTimeout); + taskFailedSpy.clear(); + + verify(pkg.builtIn); + compare(pkg.icon.toString().slice(-9), "icon1.png") + compare(pkg.version, "v1"); + } + + function test_4builtin_update_downgrade() { + taskStateChangedSpy.clear() + + var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR + + "/packages/hello-world.red.appkg") + taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); + compare(taskRequestingInstallationAcknowledgeSpy.count, 1); + compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); + taskRequestingInstallationAcknowledgeSpy.clear(); + PackageManager.acknowledgePackageInstallation(id); + + taskFinishedSpy.wait(spyTimeout); + var pkg = PackageManager.package("hello-world.red") + compare(pkg.version, "red"); + taskFinishedSpy.clear(); + applicationChangedSpy.clear(); + + // remvove is a downgrade + verify(pkg.builtIn) + verify(pkg.builtInHasRemovableUpdate) + verify(PackageManager.removePackage("hello-world.red", false, true)); + taskFinishedSpy.wait(spyTimeout); + compare(taskFinishedSpy.count, 1); + taskFinishedSpy.clear(); + + compare(applicationChangedSpy.count, 3); + compare(applicationChangedSpy.signalArguments[0][0], "hello-world.red"); + compare(applicationChangedSpy.signalArguments[0][1], ["isBlocked"]); + compare(applicationChangedSpy.signalArguments[2][1], []); + + verify(!pkg.blocked) + compare(pkg.version, "v1"); + } +} diff --git a/tests/auto/qml/intents/CMakeLists.txt b/tests/auto/qml/intents/CMakeLists.txt new file mode 100644 index 00000000..20543415 --- /dev/null +++ b/tests/auto/qml/intents/CMakeLists.txt @@ -0,0 +1,23 @@ +# Generated from intents.pro. + +##################################################################### +## intents Binary: +##################################################################### + +qt_internal_add_executable(intents + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:intents.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "intents1" "intents2" "cannot-start" +# TEST_CONFIGURATIONS = "--force-single-process" +# TEST_FILES = "tst_intents.qml" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:intents.pro:multi-process: +# TEST_CONFIGURATIONS = "--force-multi-process" "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" diff --git a/tests/auto/qml/intents/am-config-quick.yaml b/tests/auto/qml/intents/am-config-quick.yaml new file mode 100644 index 00000000..96b3098c --- /dev/null +++ b/tests/auto/qml/intents/am-config-quick.yaml @@ -0,0 +1,6 @@ +formatVersion: 1 +formatType: am-configuration +--- +quicklaunch: + runtimesPerContainer: 1 + idleLoad: 1.0 diff --git a/tests/auto/qml/intents/am-config.yaml b/tests/auto/qml/intents/am-config.yaml new file mode 100644 index 00000000..1667c123 --- /dev/null +++ b/tests/auto/qml/intents/am-config.yaml @@ -0,0 +1,23 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +ui: + fullscreen: no + +flags: + noSecurity: yes + noUiWatchdog: yes + +runtimes: + qml: + quitTime: 1000 + +intents: + timeouts: + disambiguation: 1000 + startApplication: 1000 + replyFromApplication: 1000 + replyFromSystem: 2000 diff --git a/tests/auto/qml/intents/apps/cannot-start/cannot-start b/tests/auto/qml/intents/apps/cannot-start/cannot-start new file mode 100644 index 00000000..5c3118dc --- /dev/null +++ b/tests/auto/qml/intents/apps/cannot-start/cannot-start @@ -0,0 +1 @@ +dummy file diff --git a/tests/auto/qml/intents/apps/cannot-start/icon.png b/tests/auto/qml/intents/apps/cannot-start/icon.png new file mode 100644 index 00000000..adb840ce Binary files /dev/null and b/tests/auto/qml/intents/apps/cannot-start/icon.png differ diff --git a/tests/auto/qml/intents/apps/cannot-start/info.yaml b/tests/auto/qml/intents/apps/cannot-start/info.yaml new file mode 100644 index 00000000..64c81589 --- /dev/null +++ b/tests/auto/qml/intents/apps/cannot-start/info.yaml @@ -0,0 +1,12 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'cannot-start' +icon: 'icon.png' +code: 'cannot-start' +runtime: 'native' +name: + en: 'Cannot start' + +intents: +- id: cannot-start-intent diff --git a/tests/auto/qml/intents/apps/intents1/icon.png b/tests/auto/qml/intents/apps/intents1/icon.png new file mode 100644 index 00000000..adb840ce Binary files /dev/null and b/tests/auto/qml/intents/apps/intents1/icon.png differ diff --git a/tests/auto/qml/intents/apps/intents1/info.yaml b/tests/auto/qml/intents/apps/intents1/info.yaml new file mode 100644 index 00000000..d5f72561 --- /dev/null +++ b/tests/auto/qml/intents/apps/intents1/info.yaml @@ -0,0 +1,20 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'intents1' +icon: 'icon.png' +code: 'intents1.qml' +runtime: 'qml' +name: + en: 'Intents1' + +intents: +- id: only1 +- id: both +- id: match + parameterMatch: + list: [ 'a', 'b' ] + int: 42 + string: "^foo_.*_bar$" + complex: { 'a': 1 } +- id: custom-error diff --git a/tests/auto/qml/intents/apps/intents1/intents1.qml b/tests/auto/qml/intents/apps/intents1/intents1.qml new file mode 100644 index 00000000..d9e80183 --- /dev/null +++ b/tests/auto/qml/intents/apps/intents1/intents1.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml 2.2 +import QtApplicationManager 2.0 +import QtApplicationManager.Application 2.0 + +QtObject { + id: root + + property var connections: Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } + } + + property var handler: IntentHandler { + intentIds: [ "only1", "both", "match" ] + onRequestReceived: { + request.sendReply({ "from": ApplicationInterface.applicationId, "in": request.parameters}) + } + } + + property var customErrorHandler: IntentHandler { + intentIds: [ "custom-error" ] + onRequestReceived: { + request.sendErrorReply("custom error") + } + } +} diff --git a/tests/auto/qml/intents/apps/intents2/icon.png b/tests/auto/qml/intents/apps/intents2/icon.png new file mode 100644 index 00000000..adb840ce Binary files /dev/null and b/tests/auto/qml/intents/apps/intents2/icon.png differ diff --git a/tests/auto/qml/intents/apps/intents2/info.yaml b/tests/auto/qml/intents/apps/intents2/info.yaml new file mode 100644 index 00000000..209ab30c --- /dev/null +++ b/tests/auto/qml/intents/apps/intents2/info.yaml @@ -0,0 +1,16 @@ +formatVersion: 1 +formatType: am-package +--- +id: 'intents2' +icon: 'icon.png' +name: + en: 'Intents2' +applications: + - id: 'intents2.1' + code: 'intents2.qml' + runtime: 'qml' + +intents: +- id: only2 +- id: both +- id: only1 # declared here, but no handler to provoke an error diff --git a/tests/auto/qml/intents/apps/intents2/intents2.qml b/tests/auto/qml/intents/apps/intents2/intents2.qml new file mode 100644 index 00000000..2545a3f5 --- /dev/null +++ b/tests/auto/qml/intents/apps/intents2/intents2.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml 2.2 +import QtApplicationManager 2.0 +import QtApplicationManager.Application 2.0 + +QtObject { + id: root + + property var connections: Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } + } + + property var handler: IntentHandler { + intentIds: [ "both", "only2" ] + onRequestReceived: { + Qt.callLater(function() { + request.sendReply({ "from": ApplicationInterface.applicationId, "in": request.parameters}) + }) + } + } +} diff --git a/tests/auto/qml/intents/intents.pro b/tests/auto/qml/intents/intents.pro new file mode 100644 index 00000000..a05a7b72 --- /dev/null +++ b/tests/auto/qml/intents/intents.pro @@ -0,0 +1,12 @@ +load(am-config) + +AM_CONFIG = am-config.yaml +TEST_FILES = tst_intents.qml +TEST_APPS = intents1 intents2 cannot-start +TEST_CONFIGURATIONS = "--force-single-process" +multi-process { + TEST_CONFIGURATIONS += "--force-multi-process" \ + "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" +} + +load(am-qml-testcase) diff --git a/tests/auto/qml/intents/tst_intents.qml b/tests/auto/qml/intents/tst_intents.qml new file mode 100644 index 00000000..2caccfcb --- /dev/null +++ b/tests/auto/qml/intents/tst_intents.qml @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtTest 1.0 +import QtApplicationManager 2.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "Intents" + + property var stdParams: { "para": "meter" } + property var matchParams: { "list": "a", "int": 42, "string": "foo_x_bar", "complex": { "a": 1 } } + + ListView { + id: listView + model: ApplicationManager + delegate: Item { + property var modelData: model + } + } + + function initTestCase() { + verify(ApplicationManager.application("intents1")) + verify(ApplicationManager.application("intents2.1")) + if (!ApplicationManager.singleProcess) + verify(ApplicationManager.application("cannot-start")) + } + + SignalSpy { + id: requestSpy + target: null + signalName: "replyReceived" + } + + function test_intent_object() { + verify(IntentServer.count> 0) + + // test intent properties + var intent = IntentServer.applicationIntent("both", "intents1") + verify(intent) + compare(intent.intentId, "both") + compare(intent.applicationId, "intents1") + compare(intent.visibility, IntentObject.Public) + compare(intent.requiredCapabilities, []) + compare(intent.parameterMatch, {}) + + verify(!IntentServer.applicationIntent("both", "intents3")) + verify(!IntentServer.applicationIntent("bothx", "intents1")) + verify(!IntentServer.applicationIntent("both", "")) + verify(!IntentServer.applicationIntent("", "intents1")) + verify(!IntentServer.applicationIntent("", "")) + } + + + function test_match() { + // first, check the matching on the server API + var intent = IntentServer.applicationIntent("match", "intents1") + verify(!intent) + intent = IntentServer.applicationIntent("match", "intents1", matchParams) + verify(intent) + compare(intent.parameterMatch, { "list": [ "a", "b" ], "int": 42, "string": "^foo_.*_bar$", "complex": { "a": 1 } }) + + var params = matchParams + params.list = "c" + verify(!IntentServer.applicationIntent("match", "intents1", params)) + params.list = "b" + verify(IntentServer.applicationIntent("match", "intents1", params)) + + params.int = 2 + verify(!IntentServer.applicationIntent("match", "intents1", params)) + params.int = 42 + + params.string = "foo" + verify(!IntentServer.applicationIntent("match", "intents1", params)) + params.string = "foo_test_bar" + verify(IntentServer.applicationIntent("match", "intents1", params)) + + params.complex = "string" + verify(!IntentServer.applicationIntent("match", "intents1", params)) + params.complex = matchParams.complex + } + + + function test_intents_data() { + return [ + {tag: "1-1", intentId: "only1", appId: "intents1", succeeding: true }, + {tag: "2-2", intentId: "only2", appId: "intents2.1", succeeding: true }, + {tag: "1-2", intentId: "only1", appId: "intents2.1", succeeding: false, + errorMessage: "No matching IntentHandler found." }, + {tag: "2-1", intentId: "only2", appId: "intents1", succeeding: false, + errorMessage: "No matching intent handler registered.", + ignoreWarning: 'Unknown intent "only2" was requested from application ":sysui:"' }, + {tag: "match-1", intentId: "match", appId: "intents1", succeeding: true, params: matchParams }, + {tag: "match-2", intentId: "match", appId: "intents1", succeeding: false, + params: function() { var x = Object.assign({}, matchParams); x.int = 1; return x }(), + errorMessage: "No matching intent handler registered.", + ignoreWarning: 'Unknown intent "match" was requested from application ":sysui:"' }, + {tag: "match-3", intentId: "match", appId: "intents1", succeeding: false, params: {}, + errorMessage: "No matching intent handler registered.", + ignoreWarning: 'Unknown intent "match" was requested from application ":sysui:"' }, + {tag: "unknown-1", intentId: "unknown", appId: "intents1", succeeding: false, + errorMessage: "No matching intent handler registered.", + ignoreWarning: 'Unknown intent "unknown" was requested from application ":sysui:"' }, + {tag: "unknown-2", intentId: "unknown", appId: "", succeeding: false, + errorMessage: "No matching intent handler registered.", + ignoreWarning: 'Unknown intent "unknown" was requested from application ":sysui:"' }, + {tag: "custom-error", intentId: "custom-error", appId: "intents1", succeeding: false, + errorMessage: "custom error" }, + {tag: "cannot-start", intentId: "cannot-start-intent", appId: "cannot-start", succeeding: false, + errorMessage: /Starting handler application timed out after .*/ }, + ]; + } + + function test_intents(data) { + if (data.appId && !ApplicationManager.application(data.appId)) + skip("Application \"" + data.appId + "\" is not available") + + if (data.ignoreWarning) + ignoreWarning(data.ignoreWarning) + + var params = ("params" in data) ? data.params : stdParams + + var req = IntentClient.sendIntentRequest(data.intentId, data.appId, params) + verify(req) + requestSpy.target = req + tryCompare(requestSpy, "count", 1, 1000) + compare(req.succeeded, data.succeeding) + if (req.succeeded) { + compare(req.result, { "from": data.appId, "in": params }) + } else { + if (data.errorMessage instanceof RegExp) + verify(data.errorMessage.test(req.errorMessage)) + else + compare(req.errorMessage, data.errorMessage) + } + requestSpy.clear() + requestSpy.target = null + } + + function test_disambiguate_data() { + return [ + {tag: "no-signal", action: "none", succeeding: true }, + {tag: "reject", action: "reject", succeeding: false, + errorMessage: "Disambiguation was rejected" }, + {tag: "timeout", action: "timeout", succeeding: false, + errorMessage: /Disambiguation timed out after .*/ }, + {tag: "ack-invalid", action: "acknowledge", acknowledgeIntentId: "only1", succeeding: false, + errorMessage: "Failed to disambiguate", + ignoreWarning: /IntentServer::acknowledgeDisambiguationRequest for intent .* tried to disambiguate to the intent "only1" which was not in the list of potential disambiguations/ }, + {tag: "ack-valid", action: "acknowledge", succeeding: true } + ]; + } + + SignalSpy { + id: disambiguateSpy + target: IntentServer + } + + function test_disambiguate(data) { + var intentId = "both" + + if (data.ignoreWarning) + ignoreWarning(data.ignoreWarning) + + disambiguateSpy.signalName = data.action === "none" ? "" : "disambiguationRequest"; + + var req = IntentClient.sendIntentRequest("both", stdParams) + verify(req) + requestSpy.target = req + + if (data.action !== "none") { + tryCompare(disambiguateSpy, "count", 1, 1000) + var possibleIntents = disambiguateSpy.signalArguments[0][1] + compare(possibleIntents.length, 2) + compare(possibleIntents[0].intentId, intentId) + compare(possibleIntents[1].intentId, intentId) + compare(possibleIntents[0].applicationId, "intents1") + compare(possibleIntents[1].applicationId, "intents2.1") + compare(disambiguateSpy.signalArguments[0][2], stdParams) + + switch (data.action) { + case "reject": + IntentServer.rejectDisambiguationRequest(disambiguateSpy.signalArguments[0][0]) + break + case "acknowledge": + var intent = data.acknowledgeIntentId ? IntentServer.applicationIntent(data.acknowledgeIntentId, + possibleIntents[0].applicationId) + : possibleIntents[1] + IntentServer.acknowledgeDisambiguationRequest(disambiguateSpy.signalArguments[0][0], intent) + break + } + disambiguateSpy.clear() + } + + tryCompare(requestSpy, "count", 1, data.action === "timeout" ? 15000 : 1000) + var succeeding = data.succeeding + compare(req.succeeded, succeeding) + if (succeeding) { + compare(req.errorMessage, "") + verify(req.result !== {}) + } else { + if (data.errorMessage instanceof RegExp) + verify(data.errorMessage.test(req.errorMessage)) + else + compare(req.errorMessage, data.errorMessage) + compare(req.result, {}) + } + requestSpy.clear() + } +} diff --git a/tests/auto/qml/lifecycle/CMakeLists.txt b/tests/auto/qml/lifecycle/CMakeLists.txt new file mode 100644 index 00000000..36b09f7c --- /dev/null +++ b/tests/auto/qml/lifecycle/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from lifecycle.pro. + +##################################################################### +## lifecycle Binary: +##################################################################### + +qt_internal_add_executable(lifecycle + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:lifecycle.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "tld.test.lifecycle" +# TEST_FILES = "tst_lifecycle.qml" diff --git a/tests/auto/qml/lifecycle/am-config.yaml b/tests/auto/qml/lifecycle/am-config.yaml new file mode 100644 index 00000000..61b2bfb2 --- /dev/null +++ b/tests/auto/qml/lifecycle/am-config.yaml @@ -0,0 +1,8 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +flags: + noUiWatchdog: yes diff --git a/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/app.qml b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/app.qml new file mode 100644 index 00000000..a5f21ad0 --- /dev/null +++ b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/app.qml @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + Image { + anchors.centerIn: parent + source: ApplicationInterface.icon + } +} diff --git a/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/icon.png b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/icon.png differ diff --git a/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/info.yaml b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/info.yaml new file mode 100644 index 00000000..198cbe51 --- /dev/null +++ b/tests/auto/qml/lifecycle/apps/tld.test.lifecycle/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'tld.test.lifecycle' +name: + en: 'Lifecycle Tests' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' diff --git a/tests/auto/qml/lifecycle/lifecycle.pro b/tests/auto/qml/lifecycle/lifecycle.pro new file mode 100644 index 00000000..98ab9709 --- /dev/null +++ b/tests/auto/qml/lifecycle/lifecycle.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_lifecycle.qml +TEST_APPS = tld.test.lifecycle + +load(am-qml-testcase) diff --git a/tests/auto/qml/lifecycle/tst_lifecycle.qml b/tests/auto/qml/lifecycle/tst_lifecycle.qml new file mode 100644 index 00000000..d75584e2 --- /dev/null +++ b/tests/auto/qml/lifecycle/tst_lifecycle.qml @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "LifeCycleTest" + visible: true + + property var app: ApplicationManager.application("tld.test.lifecycle"); + + + WindowItem { + id: chrome + anchors.fill: parent + } + + Connections { + target: WindowManager + function onWindowAdded(window) { + chrome.window = window; + } + } + + Connections { + target: chrome.window + function onContentStateChanged() { + if (chrome.window.contentState === WindowObject.NoSurface) + chrome.window = null; + } + } + + + SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + SignalSpy { +        id: objectDestroyedSpy +        target: AmTest +        signalName: "objectDestroyed" +    } + + Timer { + id: stopTimer + interval: 1 + onTriggered: app.stop(); + } + + + function cleanup() { + objectDestroyedSpy.clear(); + var index = AmTest.observeObjectDestroyed(app.runtime); + app.stop(); + while (app.runState !== ApplicationObject.NotRunning) + runStateChangedSpy.wait(); + objectDestroyedSpy.wait(); + compare(objectDestroyedSpy.signalArguments[0][0], index); + } + + + // Start followed by quick stop/start in single-porcess mode caused an abort in the past + function test_fast_stop_start() { + app.start(); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.StartingUp); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.Running); + + objectDestroyedSpy.clear(); + var index = AmTest.observeObjectDestroyed(app.runtime); + + app.stop(); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.ShuttingDown); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.NotRunning); + + app.start(); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.StartingUp); + runStateChangedSpy.wait(); + compare(app.runState, ApplicationObject.Running); + + objectDestroyedSpy.wait(); + compare(objectDestroyedSpy.signalArguments[0][0], index); + } + + // Quick start/stop followd by start in single-process mode caused an abort in the past + function test_fast_start_stop() { + app.start(); + stopTimer.start(); + + while (app.runState !== ApplicationObject.NotRunning) + runStateChangedSpy.wait(); + + app.start(); + while (app.runState !== ApplicationObject.Running) + runStateChangedSpy.wait(); + } +} diff --git a/tests/auto/qml/processtitle/CMakeLists.txt b/tests/auto/qml/processtitle/CMakeLists.txt new file mode 100644 index 00000000..55cd61b9 --- /dev/null +++ b/tests/auto/qml/processtitle/CMakeLists.txt @@ -0,0 +1,17 @@ +# Generated from processtitle.pro. + +##################################################################### +## processtitle Binary: +##################################################################### + +qt_internal_add_executable(processtitle + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:processtitle.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "test.processtitle.app" +# TEST_CONFIGURATIONS = "--force-multi-process" "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" +# TEST_FILES = "tst_processtitle.qml" diff --git a/tests/auto/qml/processtitle/am-config-quick.yaml b/tests/auto/qml/processtitle/am-config-quick.yaml new file mode 100644 index 00000000..a21a1dea --- /dev/null +++ b/tests/auto/qml/processtitle/am-config-quick.yaml @@ -0,0 +1,10 @@ +formatVersion: 1 +formatType: am-configuration +--- +quicklaunch: + runtimesPerContainer: 1 + idleLoad: 1.0 + +systemProperties: + private: + quickLaunch: true diff --git a/tests/auto/qml/processtitle/am-config.yaml b/tests/auto/qml/processtitle/am-config.yaml new file mode 100644 index 00000000..4ab6878e --- /dev/null +++ b/tests/auto/qml/processtitle/am-config.yaml @@ -0,0 +1,5 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" diff --git a/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml new file mode 100644 index 00000000..7371a7c8 --- /dev/null +++ b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2020 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtApplicationManager.Application 2.0 + +Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } +} diff --git a/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png differ diff --git a/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml new file mode 100644 index 00000000..2e1cae3b --- /dev/null +++ b/tests/auto/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +name: + en: 'Large App' diff --git a/tests/auto/qml/processtitle/apps/test.processtitle.app/app.qml b/tests/auto/qml/processtitle/apps/test.processtitle.app/app.qml new file mode 100644 index 00000000..7371a7c8 --- /dev/null +++ b/tests/auto/qml/processtitle/apps/test.processtitle.app/app.qml @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2020 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtApplicationManager.Application 2.0 + +Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } +} diff --git a/tests/auto/qml/processtitle/apps/test.processtitle.app/icon.png b/tests/auto/qml/processtitle/apps/test.processtitle.app/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/processtitle/apps/test.processtitle.app/icon.png differ diff --git a/tests/auto/qml/processtitle/apps/test.processtitle.app/info.yaml b/tests/auto/qml/processtitle/apps/test.processtitle.app/info.yaml new file mode 100644 index 00000000..e178aa04 --- /dev/null +++ b/tests/auto/qml/processtitle/apps/test.processtitle.app/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.processtitle.app' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +name: + en: 'Small App' diff --git a/tests/auto/qml/processtitle/processtitle.pro b/tests/auto/qml/processtitle/processtitle.pro new file mode 100644 index 00000000..e78b54a1 --- /dev/null +++ b/tests/auto/qml/processtitle/processtitle.pro @@ -0,0 +1,7 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_processtitle.qml +TEST_APPS = test.processtitle.app +TEST_CONFIGURATIONS = "--force-multi-process" \ + "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" + +load(am-qml-testcase) diff --git a/tests/auto/qml/processtitle/tst_processtitle.qml b/tests/auto/qml/processtitle/tst_processtitle.qml new file mode 100644 index 00000000..acb3646e --- /dev/null +++ b/tests/auto/qml/processtitle/tst_processtitle.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2020 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + + +TestCase { + id: testCase + when: windowShown + name: "ProcessTitle" + visible: true + + property int sysuiPid + + ProcessStatus { + id: processStatus + applicationId: "" + Component.onCompleted: sysuiPid = processId; + } + + +    SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + function test_launcher_qml_data() { + return [ { tag: "small", appId: "test.processtitle.app", resId: "test.processtitle.app" }, + { tag: "large", appId: "appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7", + resId: "appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appa" } ]; + } + + function test_launcher_qml(data) { + const executable = "appman-launcher-qml"; + var sigIdx; + var quickArg; + var pid + if (ApplicationManager.systemProperties.quickLaunch) { + sigIdx = 0; + quickArg = " --quicklaunch" + tryVerify(function() { + pid = AmTest.findChildProcess(sysuiPid, executable + quickArg); + return pid + }); + wait(250); + verify(AmTest.cmdLine(pid).endsWith(executable + quickArg)); + } else { + sigIdx = 1; + quickArg = "" + } + + runStateChangedSpy.clear(); + verify(ApplicationManager.startApplication(data.appId)); + runStateChangedSpy.wait(); + if (sigIdx === 1) + runStateChangedSpy.wait(); + + compare(runStateChangedSpy.signalArguments[sigIdx][0], data.appId); + compare(runStateChangedSpy.signalArguments[sigIdx][1], ApplicationObject.Running); + + processStatus.applicationId = data.appId; + pid = processStatus.processId; + verify(AmTest.ps(pid).endsWith(executable + ": " + data.resId + quickArg)); + verify(AmTest.cmdLine(pid).endsWith(executable + ": " + data.resId + quickArg)); + verify(AmTest.environment(pid).includes("AM_CONFIG=%YAML")); + verify(AmTest.environment(pid).includes("AM_NO_DLT_LOGGING=1")); + verify(AmTest.environment(pid).includes("WAYLAND_DISPLAY=")); + + runStateChangedSpy.clear(); + ApplicationManager.stopAllApplications(); + runStateChangedSpy.wait(); + runStateChangedSpy.wait(); + compare(runStateChangedSpy.signalArguments[1][1], ApplicationObject.NotRunning); + } +} diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro new file mode 100644 index 00000000..902ab2f1 --- /dev/null +++ b/tests/auto/qml/qml.pro @@ -0,0 +1,20 @@ +load(am-config) + +TEMPLATE = subdirs +SUBDIRS = \ + simple \ + windowmanager \ + windowmapping \ + windowitem \ + windowitem2 \ + installer \ + quicklaunch \ + intents \ + configs \ + lifecycle \ + resources + +multi-process: SUBDIRS += \ + crash/apps/tld.test.crash/terminator2 \ + crash \ + processtitle diff --git a/tests/auto/qml/quicklaunch/CMakeLists.txt b/tests/auto/qml/quicklaunch/CMakeLists.txt new file mode 100644 index 00000000..9fcb8aeb --- /dev/null +++ b/tests/auto/qml/quicklaunch/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from quicklaunch.pro. + +##################################################################### +## quicklaunch Binary: +##################################################################### + +qt_internal_add_executable(quicklaunch + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:quicklaunch.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "tld.test.quicklaunch" +# TEST_FILES = "tst_quicklaunch.qml" diff --git a/tests/auto/qml/quicklaunch/am-config.yaml b/tests/auto/qml/quicklaunch/am-config.yaml new file mode 100644 index 00000000..e8de3d00 --- /dev/null +++ b/tests/auto/qml/quicklaunch/am-config.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +quicklaunch: + runtimesPerContainer: 2 + idleLoad: 1.0 diff --git a/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml new file mode 100644 index 00000000..571288d1 --- /dev/null +++ b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + width: 320 + height: 240 + + ApplicationInterfaceExtension { + name: "quicklaunch.interface" + onReadyChanged: object.acknowledge(); + } +} diff --git a/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png differ diff --git a/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml new file mode 100644 index 00000000..e898a02b --- /dev/null +++ b/tests/auto/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml @@ -0,0 +1,10 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'tld.test.quicklaunch' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +version: '1.0' +name: + en: 'Quicklaunch' diff --git a/tests/auto/qml/quicklaunch/quicklaunch.pro b/tests/auto/qml/quicklaunch/quicklaunch.pro new file mode 100644 index 00000000..2d990a4b --- /dev/null +++ b/tests/auto/qml/quicklaunch/quicklaunch.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_quicklaunch.qml +TEST_APPS = tld.test.quicklaunch + +load(am-qml-testcase) diff --git a/tests/auto/qml/quicklaunch/tst_quicklaunch.qml b/tests/auto/qml/quicklaunch/tst_quicklaunch.qml new file mode 100644 index 00000000..d9744eec --- /dev/null +++ b/tests/auto/qml/quicklaunch/tst_quicklaunch.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +// Tests are meaningless in single-process mode, but still work + +TestCase { + id: testCase + when: windowShown + name: "Quicklaunch" + + property bool acknowledged: false + + SignalSpy { + id: windowAddedSpy + target: WindowManager + signalName: "windowAdded" + } + + SignalSpy { +        id: runStateChangedSpy +        signalName: "runStateChanged" +    } + + ApplicationIPCInterface { + function acknowledge() { acknowledged = true; } + Component.onCompleted: ApplicationIPCManager.registerInterface(this, "quicklaunch.interface", {}); + } + + + function test_quicklaunch() { + var app = ApplicationManager.application("tld.test.quicklaunch"); + runStateChangedSpy.target = app; + + wait(1000); + // Check for quick-launching is done every second in appman. After 1s now, this test + // sometimes caused some race where the app would not be started at all in the past: + app.start(); + windowAddedSpy.wait(3000); + tryCompare(testCase, "acknowledged", true); + runStateChangedSpy.clear(); + app.stop(true); + runStateChangedSpy.wait(3000); // wait for ShuttingDown + runStateChangedSpy.wait(3000); // wait for NotRunning + + wait(1000); + // Unfortunately there is no reliable means to determine, whether a quicklaunch process + // is running, but after at least 2s now, there should be a process that can be attached to. + acknowledged = false; + app.start(); + windowAddedSpy.wait(3000); + tryCompare(testCase, "acknowledged", true); + runStateChangedSpy.clear(); + app.stop(true); + runStateChangedSpy.wait(3000); // wait for ShuttingDown + runStateChangedSpy.wait(3000); // wait for NotRunning + } +} diff --git a/tests/auto/qml/resources/CMakeLists.txt b/tests/auto/qml/resources/CMakeLists.txt new file mode 100644 index 00000000..0893a7ac --- /dev/null +++ b/tests/auto/qml/resources/CMakeLists.txt @@ -0,0 +1,37 @@ +# Generated from resources.pro. + +##################################################################### +## systemuiplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(systemuiplugin + MODULE + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +# Resources: +set(systemuiplugin_resource_files + "qml/widgets/MagentaRect.qml" +) + +qt_internal_add_resource(systemuiplugin "systemuiplugin" + PREFIX + "/" + FILES + ${systemuiplugin_resource_files} +) + + +#### Keys ignored in scope 2:.:.:test.pro:: +# AM_CONFIG = "am-config.yaml" +# DIRECTORIES = "apps/app2/qml" "relative" +# FILES = "am-config.yaml" "apps/app1/icon.png" "apps/app1/info.yaml" "apps/app2/icon.png" "apps/app2/info.yaml" +# RESOURCE_SOURCE = "systemuifile.qrc" +# TEMPLATE = "lib" +# TEST_APPS = "app1" "app2" +# TEST_FILES = "tst_resource.qml" + +qt_autogen_tools_initial_setup(systemuiplugin) +add_subdirectory(appcommon) +add_subdirectory(apps/app1) +add_subdirectory(apps/app2) diff --git a/tests/auto/qml/resources/am-config.yaml b/tests/auto/qml/resources/am-config.yaml new file mode 100644 index 00000000..a06cb076 --- /dev/null +++ b/tests/auto/qml/resources/am-config.yaml @@ -0,0 +1,22 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + installationDir: "/tmp/am-resource-test/apps" + +quicklaunch: + runtimesPerContainer: 1 + idleLoad: 1.0 + +runtimes: + qml: + resources: "appcommon/appcommonfile.rcc" + importPaths: [ "qrc:/appcommon/qml", "relative" ] + quicklaunchQml: "qrc:/appcommon/Quicklaunch.qml" + +ui: + importPaths: "qrc:///qml" + resources: + - "systemuifile.rcc" + - "${CONFIG_PWD}/systemuiplugin" # libsystemuiplugin.so would only work on Linux diff --git a/tests/auto/qml/resources/appcommon/CMakeLists.txt b/tests/auto/qml/resources/appcommon/CMakeLists.txt new file mode 100644 index 00000000..45d12696 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from appcommon.pro. + diff --git a/tests/auto/qml/resources/appcommon/Quicklaunch.qml b/tests/auto/qml/resources/appcommon/Quicklaunch.qml new file mode 100644 index 00000000..e9cc4144 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/Quicklaunch.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import common 1.0 + +CommonObj { + Component.onCompleted: console.info("Quicklaunch - meaning: " + meaning); +} diff --git a/tests/auto/qml/resources/appcommon/appcommon.pro b/tests/auto/qml/resources/appcommon/appcommon.pro new file mode 100644 index 00000000..47028775 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/appcommon.pro @@ -0,0 +1,7 @@ +TEMPLATE = aux + +OTHER_FILES += Quicklaunch.qml \ + qml/common/CommonObj.qml + +RESOURCE_SOURCE = appcommonfile.qrc +load(generate-resource) diff --git a/tests/auto/qml/resources/appcommon/appcommonfile.qrc b/tests/auto/qml/resources/appcommon/appcommonfile.qrc new file mode 100644 index 00000000..4dc15f85 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/appcommonfile.qrc @@ -0,0 +1,7 @@ + + + qml/common/CommonObj.qml + qml/common/qmldir + Quicklaunch.qml + + diff --git a/tests/auto/qml/resources/appcommon/qml/common/CommonObj.qml b/tests/auto/qml/resources/appcommon/qml/common/CommonObj.qml new file mode 100644 index 00000000..1b181488 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/qml/common/CommonObj.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +QtObject { + property int meaning: 42 +} diff --git a/tests/auto/qml/resources/appcommon/qml/common/qmldir b/tests/auto/qml/resources/appcommon/qml/common/qmldir new file mode 100644 index 00000000..5458b257 --- /dev/null +++ b/tests/auto/qml/resources/appcommon/qml/common/qmldir @@ -0,0 +1,2 @@ +module common +CommonObj 1.0 CommonObj.qml diff --git a/tests/auto/qml/resources/apps/app1/CMakeLists.txt b/tests/auto/qml/resources/apps/app1/CMakeLists.txt new file mode 100644 index 00000000..7ff28b4a --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/CMakeLists.txt @@ -0,0 +1,32 @@ +# Generated from app1.pro. + +##################################################################### +## app1plugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(app1plugin + MODULE + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui +) + +# Resources: +set(app1plugin_resource_files + "qml/forms/AquaRect.qml" +) + +qt_internal_add_resource(app1plugin "app1plugin" + PREFIX + "/app1" + FILES + ${app1plugin_resource_files} +) + + +#### Keys ignored in scope 1:.:.:app1.pro:: +# OTHER_FILES = "info.yaml" "icon.png" +# RESOURCE_SOURCE = "app1file.qrc" +# TEMPLATE = "lib" + +qt_autogen_tools_initial_setup(app1plugin) diff --git a/tests/auto/qml/resources/apps/app1/app1.pro b/tests/auto/qml/resources/apps/app1/app1.pro new file mode 100644 index 00000000..cbbb4758 --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/app1.pro @@ -0,0 +1,11 @@ +TEMPLATE = lib +TARGET = app1plugin +CONFIG += plugin +RESOURCES = app1plugin.qrc + +RESOURCE_SOURCE = app1file.qrc +load(generate-resource) + +OTHER_FILES += \ + info.yaml \ + icon.png diff --git a/tests/auto/qml/resources/apps/app1/app1.qml b/tests/auto/qml/resources/apps/app1/app1.qml new file mode 100644 index 00000000..d519f3ac --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/app1.qml @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtApplicationManager.Application 2.0 +import forms 1.0 +import elements 1.0 + +ApplicationManagerWindow { + YellowRect {} + AquaRect {} + LinenRect {} +} diff --git a/tests/auto/qml/resources/apps/app1/app1file.qrc b/tests/auto/qml/resources/apps/app1/app1file.qrc new file mode 100644 index 00000000..6c958e89 --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/app1file.qrc @@ -0,0 +1,7 @@ + + + app1.qml + qml/forms/YellowRect.qml + qml/forms/qmldir + + diff --git a/tests/auto/qml/resources/apps/app1/app1plugin.qrc b/tests/auto/qml/resources/apps/app1/app1plugin.qrc new file mode 100644 index 00000000..6c4e2ae3 --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/app1plugin.qrc @@ -0,0 +1,5 @@ + + + qml/forms/AquaRect.qml + + diff --git a/tests/auto/qml/resources/apps/app1/icon.png b/tests/auto/qml/resources/apps/app1/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/resources/apps/app1/icon.png differ diff --git a/tests/auto/qml/resources/apps/app1/info.yaml b/tests/auto/qml/resources/apps/app1/info.yaml new file mode 100644 index 00000000..a5287f2c --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/info.yaml @@ -0,0 +1,17 @@ +formatVersion: 1 +formatType: am-package +--- +id: 'app1' +icon: 'icon.png' +name: + en: 'Resource Test App 1' + +applications: + - id: 'app1' + code: 'qrc:///app1/app1.qml' + runtime: 'qml' + runtimeParameters: + importPaths: "qrc:///app1/qml" + resources: + - app1file.rcc + - app1plugin # libapp1plugin.so would only work on Linux diff --git a/tests/auto/qml/resources/apps/app1/qml/forms/AquaRect.qml b/tests/auto/qml/resources/apps/app1/qml/forms/AquaRect.qml new file mode 100644 index 00000000..cefb485c --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/qml/forms/AquaRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "aqua" +} diff --git a/tests/auto/qml/resources/apps/app1/qml/forms/YellowRect.qml b/tests/auto/qml/resources/apps/app1/qml/forms/YellowRect.qml new file mode 100644 index 00000000..b1c91a1f --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/qml/forms/YellowRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "yellow" +} diff --git a/tests/auto/qml/resources/apps/app1/qml/forms/qmldir b/tests/auto/qml/resources/apps/app1/qml/forms/qmldir new file mode 100644 index 00000000..12a5506b --- /dev/null +++ b/tests/auto/qml/resources/apps/app1/qml/forms/qmldir @@ -0,0 +1,4 @@ +module forms +YellowRect 1.0 qrc:///app1/qml/forms/YellowRect.qml +# :/app1/qml/forms/YellowRect.qml would not work +AquaRect 1.0 AquaRect.qml diff --git a/tests/auto/qml/resources/apps/app2/BlueRect.qml b/tests/auto/qml/resources/apps/app2/BlueRect.qml new file mode 100644 index 00000000..138bdff4 --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/BlueRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "blue" +} diff --git a/tests/auto/qml/resources/apps/app2/CMakeLists.txt b/tests/auto/qml/resources/apps/app2/CMakeLists.txt new file mode 100644 index 00000000..03a5a5a1 --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from app2.pro. + diff --git a/tests/auto/qml/resources/apps/app2/app2.pro b/tests/auto/qml/resources/apps/app2/app2.pro new file mode 100644 index 00000000..7a5190df --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/app2.pro @@ -0,0 +1,8 @@ +TEMPLATE = aux + +RESOURCE_SOURCE = app2.qrc +load(generate-resource) + +OTHER_FILES += \ + info.yaml \ + icon.png diff --git a/tests/auto/qml/resources/apps/app2/app2.qml b/tests/auto/qml/resources/apps/app2/app2.qml new file mode 100644 index 00000000..c0310ee0 --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/app2.qml @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtApplicationManager.Application 2.0 +import QtQuick 2.11 +import appwidgets 1.0 +import common 1.0 + +ApplicationManagerWindow { + CommonObj { id: common } + BlueRect { } + GreenRect { } + + Timer { + running: true + interval: 20 + onTriggered: setWindowProperty("meaning", common.meaning); + } +} diff --git a/tests/auto/qml/resources/apps/app2/app2.qrc b/tests/auto/qml/resources/apps/app2/app2.qrc new file mode 100644 index 00000000..80bc560c --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/app2.qrc @@ -0,0 +1,6 @@ + + + app2.qml + BlueRect.qml + + diff --git a/tests/auto/qml/resources/apps/app2/icon.png b/tests/auto/qml/resources/apps/app2/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/resources/apps/app2/icon.png differ diff --git a/tests/auto/qml/resources/apps/app2/info.yaml b/tests/auto/qml/resources/apps/app2/info.yaml new file mode 100644 index 00000000..6eda565b --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/info.yaml @@ -0,0 +1,15 @@ +formatVersion: 1 +formatType: am-package +--- +id: 'app2' +icon: 'icon.png' +name: + en: 'Resource Test App 2' + +applications: + - id: 'app2' + code: ':/app2.qml' + runtime: 'qml' + runtimeParameters: + importPaths: "qml" + resources: "app2.rcc" diff --git a/tests/auto/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml b/tests/auto/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml new file mode 100644 index 00000000..7bf8d3a3 --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "green" +} diff --git a/tests/auto/qml/resources/apps/app2/qml/appwidgets/qmldir b/tests/auto/qml/resources/apps/app2/qml/appwidgets/qmldir new file mode 100644 index 00000000..a158bf25 --- /dev/null +++ b/tests/auto/qml/resources/apps/app2/qml/appwidgets/qmldir @@ -0,0 +1,2 @@ +module appwidgets +GreenRect 1.0 GreenRect.qml diff --git a/tests/auto/qml/resources/qml/widgets/MagentaRect.qml b/tests/auto/qml/resources/qml/widgets/MagentaRect.qml new file mode 100644 index 00000000..511cea95 --- /dev/null +++ b/tests/auto/qml/resources/qml/widgets/MagentaRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "magenta" +} diff --git a/tests/auto/qml/resources/qml/widgets/RedRect.qml b/tests/auto/qml/resources/qml/widgets/RedRect.qml new file mode 100644 index 00000000..a27122e7 --- /dev/null +++ b/tests/auto/qml/resources/qml/widgets/RedRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "red" +} diff --git a/tests/auto/qml/resources/qml/widgets/qmldir b/tests/auto/qml/resources/qml/widgets/qmldir new file mode 100644 index 00000000..be36132a --- /dev/null +++ b/tests/auto/qml/resources/qml/widgets/qmldir @@ -0,0 +1,3 @@ +module widgets +RedRect 1.0 RedRect.qml +MagentaRect 1.0 MagentaRect.qml diff --git a/tests/auto/qml/resources/relative/elements/LinenRect.qml b/tests/auto/qml/resources/relative/elements/LinenRect.qml new file mode 100644 index 00000000..1fdf9205 --- /dev/null +++ b/tests/auto/qml/resources/relative/elements/LinenRect.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2020 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +Rectangle { + color: "linen" +} diff --git a/tests/auto/qml/resources/relative/elements/qmldir b/tests/auto/qml/resources/relative/elements/qmldir new file mode 100644 index 00000000..16a01e45 --- /dev/null +++ b/tests/auto/qml/resources/relative/elements/qmldir @@ -0,0 +1,2 @@ +module elements +LinenRect 1.0 LinenRect.qml diff --git a/tests/auto/qml/resources/resources.pro b/tests/auto/qml/resources/resources.pro new file mode 100644 index 00000000..6da64f00 --- /dev/null +++ b/tests/auto/qml/resources/resources.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = test.pro \ + appcommon \ + apps/app1 \ + apps/app2 diff --git a/tests/auto/qml/resources/systemuifile.qrc b/tests/auto/qml/resources/systemuifile.qrc new file mode 100644 index 00000000..ce48e1a4 --- /dev/null +++ b/tests/auto/qml/resources/systemuifile.qrc @@ -0,0 +1,6 @@ + + + qml/widgets/RedRect.qml + qml/widgets/qmldir + + diff --git a/tests/auto/qml/resources/systemuiplugin.qrc b/tests/auto/qml/resources/systemuiplugin.qrc new file mode 100644 index 00000000..7fe63a54 --- /dev/null +++ b/tests/auto/qml/resources/systemuiplugin.qrc @@ -0,0 +1,5 @@ + + + qml/widgets/MagentaRect.qml + + diff --git a/tests/auto/qml/resources/test.pro b/tests/auto/qml/resources/test.pro new file mode 100644 index 00000000..3553c02a --- /dev/null +++ b/tests/auto/qml/resources/test.pro @@ -0,0 +1,18 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_resource.qml +TEST_APPS = app1 app2 + +DIRECTORIES = apps/app2/qml relative +FILES = am-config.yaml \ + apps/app1/icon.png apps/app1/info.yaml \ + apps/app2/icon.png apps/app2/info.yaml +DESTDIR = $$OUT_PWD +load(am-qml-testcase) + +RESOURCE_SOURCE = systemuifile.qrc +load(generate-resource) + +TEMPLATE = lib +TARGET = systemuiplugin +CONFIG += plugin +RESOURCES = systemuiplugin.qrc diff --git a/tests/auto/qml/resources/tst_resource.qml b/tests/auto/qml/resources/tst_resource.qml new file mode 100644 index 00000000..8eb0e406 --- /dev/null +++ b/tests/auto/qml/resources/tst_resource.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 +import widgets 1.0 + +TestCase { + id: testCase + when: windowShown + name: "ResourceTest" + + RedRect {} + MagentaRect {} + + SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + SignalSpy { + id: windowPropertyChangedSpy + target: WindowManager + signalName: "windowPropertyChanged" + } + + function test_basic_data() { + return [ { tag: "app1" }, + { tag: "app2" } ]; + } + + function test_basic(data) { + wait(1200); // wait for quicklaunch + + var app = ApplicationManager.application(data.tag); + windowPropertyChangedSpy.clear(); + + app.start(); + while (app.runState !== ApplicationObject.Running) + runStateChangedSpy.wait(3000); + + if (data.tag === "app2") { + windowPropertyChangedSpy.wait(2000); + compare(windowPropertyChangedSpy.count, 1); + compare(windowPropertyChangedSpy.signalArguments[0][0].windowProperty("meaning"), 42); + } + + app.stop(); + while (app.runState !== ApplicationObject.NotRunning) + runStateChangedSpy.wait(3000); + } +} diff --git a/tests/auto/qml/simple/CMakeLists.txt b/tests/auto/qml/simple/CMakeLists.txt new file mode 100644 index 00000000..9e793676 --- /dev/null +++ b/tests/auto/qml/simple/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from simple.pro. + +##################################################################### +## simple Binary: +##################################################################### + +qt_internal_add_executable(simple + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:simple.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "tld.test.simple1" "tld.test.simple2" +# TEST_FILES = "tst_applicationmanager.qml" diff --git a/tests/auto/qml/simple/am-config.yaml b/tests/auto/qml/simple/am-config.yaml new file mode 100644 index 00000000..2a515905 --- /dev/null +++ b/tests/auto/qml/simple/am-config.yaml @@ -0,0 +1,56 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +ui: + fullscreen: no + +systemProperties: + ignored: 42 + public: + pub1: 'pub1' + pubandpro: 'pub2' + pubandpri: 'pub3' + inall: 'public' + protected: + pro1: 'pro1' + pubandpro: 'pro2' + proandpri: 'pro4' + inall: 'protected' + nested: + level2: + level31: 'overwritten' + level32: 'hidden' + private: + booleanTest: on + stringTest: "pelagicore" + nullTest: ~ + intTest: -1 + floatTest: .5 + arrayTest: [ + "value1", + "value2" + ] + mapTest: { + "key1" : "1", + "key2" : "2" + } + nested: + level2: + level31: 31 + level21: 21 + level22: 22 + pubandpri: 'pri3' + proandpri: 'pri4' + inall: 'private' + +# development setup: +flags: + noSecurity: yes + noUiWatchdog: yes + +runtimes: + qml: + quitTime: 5000 diff --git a/tests/auto/qml/simple/apps/tld.test.simple1/app1.qml b/tests/auto/qml/simple/apps/tld.test.simple1/app1.qml new file mode 100644 index 00000000..11c7ad78 --- /dev/null +++ b/tests/auto/qml/simple/apps/tld.test.simple1/app1.qml @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + + Rectangle { + anchors.centerIn: parent + width: 180; height: 180; radius: width/4 + color: "red" + } + + Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } + } +} diff --git a/tests/auto/qml/simple/apps/tld.test.simple1/icon.png b/tests/auto/qml/simple/apps/tld.test.simple1/icon.png new file mode 100644 index 00000000..adb840ce Binary files /dev/null and b/tests/auto/qml/simple/apps/tld.test.simple1/icon.png differ diff --git a/tests/auto/qml/simple/apps/tld.test.simple1/info.yaml b/tests/auto/qml/simple/apps/tld.test.simple1/info.yaml new file mode 100644 index 00000000..49a0e1e4 --- /dev/null +++ b/tests/auto/qml/simple/apps/tld.test.simple1/info.yaml @@ -0,0 +1,23 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'tld.test.simple1' +icon: 'icon.png' +code: 'app1.qml' +runtime: 'qml' +version: '1.0' +name: + en: 'Simple1' +applicationProperties: + ignored: 42 + protected: + pro1: 'pro1' + proandpri: 'pro2' + private: + pri1: 'pri1' + proandpri: 'pri2' + +mimeTypes: [ + "x-scheme-handler/x-test", + "text/plain" + ] diff --git a/tests/auto/qml/simple/apps/tld.test.simple2/app.qml b/tests/auto/qml/simple/apps/tld.test.simple2/app.qml new file mode 100644 index 00000000..4f046770 --- /dev/null +++ b/tests/auto/qml/simple/apps/tld.test.simple2/app.qml @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + + Rectangle { + anchors.centerIn: parent + width: 180; height: 180; radius: width/4 + color: "red" + } + + Connections { + target: ApplicationInterface + function onQuit() { + //Do nothing, so we get killed by appman + } + } +} diff --git a/tests/auto/qml/simple/apps/tld.test.simple2/icon.png b/tests/auto/qml/simple/apps/tld.test.simple2/icon.png new file mode 100644 index 00000000..adb840ce Binary files /dev/null and b/tests/auto/qml/simple/apps/tld.test.simple2/icon.png differ diff --git a/tests/auto/qml/simple/apps/tld.test.simple2/info.yaml b/tests/auto/qml/simple/apps/tld.test.simple2/info.yaml new file mode 100644 index 00000000..f3366712 --- /dev/null +++ b/tests/auto/qml/simple/apps/tld.test.simple2/info.yaml @@ -0,0 +1,13 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'tld.test.simple2' +icon: 'icon.png' +code: 'app.qml' +runtime: 'qml' +name: + en: 'Caps' + +capabilities: +- cameraAccess +- locationAccess diff --git a/tests/auto/qml/simple/simple.pro b/tests/auto/qml/simple/simple.pro new file mode 100644 index 00000000..72dbea95 --- /dev/null +++ b/tests/auto/qml/simple/simple.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_applicationmanager.qml +TEST_APPS = tld.test.simple1 tld.test.simple2 + +load(am-qml-testcase) diff --git a/tests/auto/qml/simple/text-file.txt b/tests/auto/qml/simple/text-file.txt new file mode 100644 index 00000000..0a05cde5 --- /dev/null +++ b/tests/auto/qml/simple/text-file.txt @@ -0,0 +1 @@ +mimeType test diff --git a/tests/auto/qml/simple/tst_applicationmanager.qml b/tests/auto/qml/simple/tst_applicationmanager.qml new file mode 100644 index 00000000..ce3db553 --- /dev/null +++ b/tests/auto/qml/simple/tst_applicationmanager.qml @@ -0,0 +1,487 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Window 2.0 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "ApplicationManager" + + property var simpleApplication + property var capsApplication + // Either appman is build in single-process mode or it was started with --force-single-process + property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1 + || buildConfig[0].CONFIG.indexOf("multi-process") === -1 + property QtObject windowHandler: QtObject { + function windowAddedHandler(window) { + // console.info("window " + window + " added"); + } + + function windowContentStateChangedHandler(window) { + // console.info("window content state = " + window.contentState); + } + } + + ListView { + id: listView + model: ApplicationManager + delegate: Item { + property var modelData: model + } + } + + ApplicationModel { + id: appModel + sortFunction: function(la, ra) { return la.id > ra.id } + } + + function initTestCase() { + //Wait for the debugging wrappers to be setup. + wait(2000); + WindowManager.windowAdded.connect(windowHandler.windowAddedHandler) + WindowManager.windowContentStateChanged.connect(windowHandler.windowContentStateChangedHandler) + + compare(ApplicationManager.count, 2) + simpleApplication = ApplicationManager.application(0); + capsApplication = ApplicationManager.application(1); + } + + function test_properties() { + // Only true for the dummyimports + compare(ApplicationManager.dummy, false) + // Disabled in the am-config.yaml + compare(ApplicationManager.securityChecksEnabled, false) + + compare(ApplicationManager.singleProcess, singleProcess) + } + + function test_systemProperties() { + compare(ApplicationManager.systemProperties.ignored, undefined) + compare(ApplicationManager.systemProperties.booleanTest, true) + compare(ApplicationManager.systemProperties.stringTest, "pelagicore") + compare(ApplicationManager.systemProperties.intTest, -1) + compare(ApplicationManager.systemProperties.floatTest, .5) + compare(ApplicationManager.systemProperties.arrayTest[0], "value1") + compare(ApplicationManager.systemProperties.arrayTest[1], "value2") + compare(ApplicationManager.systemProperties.mapTest["key1"], "1") + compare(ApplicationManager.systemProperties.mapTest["key2"], "2") + compare(ApplicationManager.systemProperties.nested.level21, 21) + compare(ApplicationManager.systemProperties.nested.level2.level31, 31) + compare(ApplicationManager.systemProperties.nested.level2.level32, undefined) + compare(ApplicationManager.systemProperties.nested.level21, 21) + compare(ApplicationManager.systemProperties.nested.level22, 22) + compare(ApplicationManager.systemProperties.pub1, 'pub1') + compare(ApplicationManager.systemProperties.pro1, 'pro1') + compare(ApplicationManager.systemProperties.pubandpro, 'pro2') + compare(ApplicationManager.systemProperties.pubandpri, 'pri3') + compare(ApplicationManager.systemProperties.proandpri, 'pri4') + compare(ApplicationManager.systemProperties.inall, 'private') + compare(ApplicationManager.systemProperties.nullTest, null) + } + + function test_package() { + compare(PackageManager.count, 2) + verify(simpleApplication.package !== capsApplication.package) + compare(simpleApplication.package, PackageManager.package("tld.test.simple1")) + compare(simpleApplication.package.id, "tld.test.simple1") + compare(simpleApplication.package.applications.length, 1) + compare(simpleApplication.package.applications[0], simpleApplication) + } + + function test_application() { + var id = simpleApplication.id; + compare(simpleApplication.id, "tld.test.simple1") + compare(simpleApplication.runtimeName, "qml") + compare(simpleApplication.icon.toString(), Qt.resolvedUrl("apps/tld.test.simple1/icon.png")) + compare(simpleApplication.documentUrl, "") + compare(simpleApplication.builtIn, true) + compare(simpleApplication.alias, false) + compare(simpleApplication.nonAliased, simpleApplication) + compare(simpleApplication.capabilities.length, 0) + compare(simpleApplication.supportedMimeTypes.length, 2) + compare(simpleApplication.categories.length, 0) + //Why is runtime null ? we should document this, as this is not really clear + compare(simpleApplication.runtime, null) + compare(simpleApplication.lastExitCode, 0) + compare(simpleApplication.lastExitStatus, Am.NormalExit) + compare(simpleApplication.version, "1.0") + + // Test the name getter and verify that it's returning the same object + compare(simpleApplication, ApplicationManager.application(id)) + } + + function test_applicationProperties() { + compare(simpleApplication.applicationProperties.ignored, undefined) + compare(simpleApplication.applicationProperties.pro1, "pro1") + compare(simpleApplication.applicationProperties.proandpri, "pro2") + compare(simpleApplication.applicationProperties.pri1, undefined) + } + + function test_indexOfApplication() { + // Test index of + compare(ApplicationManager.indexOfApplication(simpleApplication.id), 0) + compare(ApplicationManager.indexOfApplication(capsApplication.id), 1) + compare(ApplicationManager.indexOfApplication("error"), -1) + } + + function test_applicationIds() { + // Test app ids + var apps = ApplicationManager.applicationIds() + compare(apps.length, ApplicationManager.count) + compare(ApplicationManager.applicationIds()[0], simpleApplication.id) + compare(ApplicationManager.applicationIds()[1], capsApplication.id) + } + + function test_capabilities() { + var emptyCaps = ApplicationManager.capabilities(simpleApplication.id) + compare(emptyCaps.length, 0) + var caps = ApplicationManager.capabilities(capsApplication.id) + compare(caps.length, 2) + } + + function test_modelData() { + compare(listView.count, ApplicationManager.count) + listView.currentIndex = 0; + compare(listView.currentItem.modelData.application, simpleApplication) + compare(listView.currentItem.modelData.applicationId, simpleApplication.id) + compare(listView.currentItem.modelData.name, "Simple1") + compare(listView.currentItem.modelData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon)) + compare(listView.currentItem.modelData.runtimeName, "qml") + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isShuttingDown, false) + compare(listView.currentItem.modelData.isBlocked, false) + compare(listView.currentItem.modelData.isUpdating, false) + compare(listView.currentItem.modelData.isRemovable, false) + compare(listView.currentItem.modelData.updateProgress, 0.0) + verify(listView.currentItem.modelData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1) + compare(listView.currentItem.modelData.capabilities, simpleApplication.capabilities) + compare(listView.currentItem.modelData.version, "1.0") + } + + SignalSpy { + id: appModelCountSpy + target: appModel + signalName: "countChanged" + } + + function test_applicationModel() { + compare(appModel.count, 2); + compare(appModel.indexOfApplication(capsApplication.id), 0); + compare(appModel.indexOfApplication(simpleApplication.id), 1); + compare(appModel.mapToSource(0), ApplicationManager.indexOfApplication(capsApplication.id)); + compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 1); + + appModel.sortFunction = undefined; + compare(appModel.indexOfApplication(simpleApplication.id), + ApplicationManager.indexOfApplication(simpleApplication.id)); + compare(appModel.indexOfApplication(capsApplication.id), + ApplicationManager.indexOfApplication(capsApplication.id)); + + appModelCountSpy.clear(); + appModel.filterFunction = function(app) { return app.capabilities.indexOf("cameraAccess") >= 0; }; + appModelCountSpy.wait(1000); + compare(appModelCountSpy.count, 1); + compare(appModel.count, 1); + compare(appModel.indexOfApplication(capsApplication.id), 0); + compare(appModel.indexOfApplication(simpleApplication.id), -1); + + listView.model = appModel; + listView.currentIndex = 0; + compare(listView.currentItem.modelData.name, "Caps"); + listView.model = ApplicationManager; + + appModel.filterFunction = function() {}; + compare(appModel.count, 0); + + appModel.filterFunction = undefined; + compare(appModel.count, 2); + } + + function test_get_data() { + return [ + {tag: "get(row)", argument: 0 }, + {tag: "get(id)", argument: simpleApplication.id }, + ]; + } + + function test_get(data) { + var appData = ApplicationManager.get(data.argument); + + compare(appData.application, simpleApplication) + compare(appData.applicationId, simpleApplication.id) + compare(appData.name, "Simple1") + compare(appData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon)) + compare(appData.runtimeName, "qml") + compare(appData.isRunning, false) + compare(appData.isStartingUp, false) + compare(appData.isShuttingDown, false) + compare(appData.isBlocked, false) + compare(appData.isUpdating, false) + compare(appData.isRemovable, false) + compare(appData.updateProgress, 0.0) + verify(appData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1) + compare(appData.capabilities, simpleApplication.capabilities) + compare(appData.version, "1.0") + } + + function test_application_object_ownership() { + // Check that the returned Application is not owned by javascript and deleted + // by the garbage collector + var app = ApplicationManager.application(0); + var id = app.id + app = null; + // app gets deleted now as there is now javascript reference anymore + gc() + // Test that the Application in the ApplicationManager is still valid + // by accessing one of it's properties + compare(id, ApplicationManager.application(0).id) + } + + SignalSpy { + id: runStateChangedSpy + target: ApplicationManager + signalName: "applicationRunStateChanged" + } + + function checkApplicationState(id, state) { + if (runStateChangedSpy.count < 1) + runStateChangedSpy.wait(10000); + verify(runStateChangedSpy.count) + compare(runStateChangedSpy.signalArguments[0][0], id) + compare(runStateChangedSpy.signalArguments[0][1], state) + compare(ApplicationManager.application(id).runState, state); + runStateChangedSpy.clear(); + } + + function test_startAndStopApplication_data() { + return [ + {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false, + exitCode: 0, exitStatus: Am.NormalExit }, + {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false, + exitCode: 0, exitStatus: Am.NormalExit }, + {tag: "ForceKill", appId: "tld.test.simple2", index: 1, forceKill: true, + exitCode: Qt.platform.os !== 'windows' ? 9 : 0, + exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }, + {tag: "AutoTerminate", appId: "tld.test.simple2", index: 1, forceKill: false, + exitCode: Qt.platform.os !== 'windows' ? 15 : 0, + exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit } + ]; + } + + function test_startAndStopApplication(data) { + compare(ApplicationManager.application(data.appId).runState, Am.NotRunning); + + var started = false; + if (data.tag === "Debug") { + if (singleProcess) + ignoreWarning("Using debug-wrappers is not supported when the application manager is running in single-process mode."); + started = ApplicationManager.debugApplication(data.appId, "%program% %arguments%"); + if (singleProcess) { + verify(!started); + return; + } + } else { + started = ApplicationManager.startApplication(data.appId); + } + verify(started); + + checkApplicationState(data.appId, Am.StartingUp); + listView.currentIndex = data.index; + compare(listView.currentItem.modelData.isStartingUp, true) + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isShuttingDown, false) + checkApplicationState(data.appId, Am.Running); + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isRunning, true) + compare(listView.currentItem.modelData.isShuttingDown, false) + + ApplicationManager.stopApplication(data.appId, data.forceKill); + + checkApplicationState(data.appId, Am.ShuttingDown); + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isShuttingDown, true) + checkApplicationState(data.appId, Am.NotRunning); + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isShuttingDown, false) + compare(listView.currentItem.modelData.application.lastExitCode, data.exitCode) + compare(listView.currentItem.modelData.application.lastExitStatus, data.exitStatus) + } + + function test_startAndStopAllApplications_data() { + return [ + {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0, + appId2: "tld.test.simple2", index2: 1, forceKill: false, exitCode: 0, + exitStatus: Am.NormalExit } + ]; + } + + function test_startAndStopAllApplications(data) { + compare(ApplicationManager.application(data.appId1).runState, Am.NotRunning); + compare(ApplicationManager.application(data.appId2).runState, Am.NotRunning); + + var started = false; + + started = ApplicationManager.startApplication(data.appId1); + verify(started); + + + checkApplicationState(data.appId1, Am.StartingUp); + listView.currentIndex = data.index1; + compare(listView.currentItem.modelData.isStartingUp, true) + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isShuttingDown, false) + checkApplicationState(data.appId1, Am.Running); + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isRunning, true) + compare(listView.currentItem.modelData.isShuttingDown, false) + + started = ApplicationManager.startApplication(data.appId2); + verify(started); + + checkApplicationState(data.appId2, Am.StartingUp); + listView.currentIndex = data.index2; + compare(listView.currentItem.modelData.isStartingUp, true) + compare(listView.currentItem.modelData.isRunning, false) + compare(listView.currentItem.modelData.isShuttingDown, false) + checkApplicationState(data.appId2, Am.Running); + compare(listView.currentItem.modelData.isStartingUp, false) + compare(listView.currentItem.modelData.isRunning, true) + compare(listView.currentItem.modelData.isShuttingDown, false) + + ApplicationManager.stopAllApplications(data.forceKill); + + while (runStateChangedSpy.count < 4) + runStateChangedSpy.wait(10000); + + var args = runStateChangedSpy.signalArguments + + for (var i = 0; i < 4; ++i) { + var id = args[i][0] + var state = args[i][1] + + var atPos = id.indexOf('@') + if (atPos >= 0) + id = id.substring(0, atPos) + + // not perfect, but the basic signal sequence is already tested in test_startAndStopApplication + verify(id === data.appId1 || id === data.appId2, "id = " + id) + verify(state === Am.ShuttingDown || state === Am.NotRunning) + } + runStateChangedSpy.clear() + } + + function test_errors() { + ignoreWarning("ApplicationManager::application(index): invalid index: -1"); + verify(!ApplicationManager.application(-1)); + verify(!ApplicationManager.application("invalidApplication")); + ignoreWarning("ApplicationManager::get(index): invalid index: -1"); + compare(ApplicationManager.get(-1), {}); + compare(ApplicationManager.get("invalidApplication"), {}); + compare(ApplicationManager.applicationRunState("invalidApplication"), Am.NotRunning); + + ignoreWarning("Cannot start application: id 'invalidApplication' is not known"); + verify(!ApplicationManager.startApplication("invalidApplication")) + + //All following tests don't work in single-process mode + if (singleProcess) + return; + + ignoreWarning("Tried to start application tld.test.simple1 using an invalid debug-wrapper specification: "); + verify(!ApplicationManager.debugApplication(simpleApplication.id, " ")) + + verify(ApplicationManager.startApplication(simpleApplication.id)); + checkApplicationState(simpleApplication.id, Am.StartingUp); + checkApplicationState(simpleApplication.id, Am.Running); + ignoreWarning("Application tld.test.simple1 is already running - cannot start with debug-wrapper: %program% %arguments%"); + verify(!ApplicationManager.debugApplication(simpleApplication.id, "%program% %arguments%")) + ApplicationManager.stopApplication(simpleApplication.id, true); + checkApplicationState(simpleApplication.id, Am.ShuttingDown); + checkApplicationState(simpleApplication.id, Am.NotRunning); + } + + function test_openUrl_data() { + return [ + {tag: "customMimeType", url: "x-test://12345", expectedApp: simpleApplication.id }, + {tag: "text/plain", url: "file://text-file.txt", expectedApp: simpleApplication.id } + ]; + } + + function test_openUrl(data) { + verify(ApplicationManager.openUrl(data.url)); + checkApplicationState(data.expectedApp, Am.StartingUp); + checkApplicationState(data.expectedApp, Am.Running); + ApplicationManager.stopApplication(data.expectedApp, true); + checkApplicationState(data.expectedApp, Am.ShuttingDown); + checkApplicationState(data.expectedApp, Am.NotRunning); + + Qt.openUrlExternally(data.url); + checkApplicationState(data.expectedApp, Am.StartingUp); + checkApplicationState(data.expectedApp, Am.Running); + ApplicationManager.stopApplication(data.expectedApp, true); + checkApplicationState(data.expectedApp, Am.ShuttingDown); + checkApplicationState(data.expectedApp, Am.NotRunning); + } + + property bool containerSelectionCalled: false + property string containerSelectionAppId + property string containerSelectionConId + function containerSelection(appId, containerId) { + containerSelectionCalled = true; + containerSelectionAppId = appId; + containerSelectionConId = containerId; + + return containerId; + } + + function test_containerSelectionFunction() { + if (singleProcess) + skip("The containerSelectionFunction doesn't work in single-process mode"); + + compare(ApplicationManager.containerSelectionFunction, undefined); + ApplicationManager.containerSelectionFunction = containerSelection; + ApplicationManager.startApplication(simpleApplication.id); + checkApplicationState(simpleApplication.id, Am.StartingUp); + checkApplicationState(simpleApplication.id, Am.Running); + ApplicationManager.stopApplication(simpleApplication.id, true); + checkApplicationState(simpleApplication.id, Am.ShuttingDown); + checkApplicationState(simpleApplication.id, Am.NotRunning); + verify(containerSelectionCalled); + compare(containerSelectionAppId, simpleApplication.id); + compare(containerSelectionConId, "process"); + } +} diff --git a/tests/auto/qml/windowitem/CMakeLists.txt b/tests/auto/qml/windowitem/CMakeLists.txt new file mode 100644 index 00000000..271566ee --- /dev/null +++ b/tests/auto/qml/windowitem/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from windowitem.pro. + +##################################################################### +## windowitem Binary: +##################################################################### + +qt_internal_add_executable(windowitem + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:windowitem.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "test.windowitem.app" "test.windowitem.multiwin" +# TEST_FILES = "tst_windowitem.qml" diff --git a/tests/auto/qml/windowitem/am-config.yaml b/tests/auto/qml/windowitem/am-config.yaml new file mode 100644 index 00000000..aa82540b --- /dev/null +++ b/tests/auto/qml/windowitem/am-config.yaml @@ -0,0 +1,13 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + installationDir: "/tmp/am/apps" + documentDir: "/tmp/am/docs" + +# Workaround for a crash in the mesa software renderer (llvmpipe) +runtimes: + qml: + environmentVariables: + QT_QUICK_BACKEND: "software" diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.app/icon.png b/tests/auto/qml/windowitem/apps/test.windowitem.app/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowitem/apps/test.windowitem.app/icon.png differ diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.app/info.yaml b/tests/auto/qml/windowitem/apps/test.windowitem.app/info.yaml new file mode 100644 index 00000000..1ef6fd93 --- /dev/null +++ b/tests/auto/qml/windowitem/apps/test.windowitem.app/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.windowitem.app' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'WindowItem Test App' diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.app/main.qml b/tests/auto/qml/windowitem/apps/test.windowitem.app/main.qml new file mode 100644 index 00000000..0fec1364 --- /dev/null +++ b/tests/auto/qml/windowitem/apps/test.windowitem.app/main.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + color: "red" + + width: 123 + height: 321 + + MouseArea { + id: mouseArea + property int clickCount: 0 + anchors.fill: parent + onClicked: { + clickCount += 1; + root.setWindowProperty("clickCount", clickCount); + } + } + + // A way for test code to trigger ApplicationManagerWindow's size changes from + // the client side + onWindowPropertyChanged: { + if (name === "requestedWidth") + root.width = value; + else if (name === "requestedHeight") + root.height = value; + } + + Component.onCompleted: { + root.setWindowProperty("clickCount", mouseArea.clickCount); + } +} diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/icon.png b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/icon.png differ diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/info.yaml b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/info.yaml new file mode 100644 index 00000000..2c44d5d3 --- /dev/null +++ b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.windowitem.multiwin' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'Multiple Windows Test App' diff --git a/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/main.qml b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/main.qml new file mode 100644 index 00000000..c3e0607d --- /dev/null +++ b/tests/auto/qml/windowitem/apps/test.windowitem.multiwin/main.qml @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +/* + A simple test app that displays two windows +*/ +QtObject { + property var blueWindow: ApplicationManagerWindow { + color: "blue" + width: 123 + height: 321 + } + property var orangeWindow: ApplicationManagerWindow { + color: "orange" + width: 321 + height: 123 + } +} diff --git a/tests/auto/qml/windowitem/tst_windowitem.qml b/tests/auto/qml/windowitem/tst_windowitem.qml new file mode 100644 index 00000000..1ad7d319 --- /dev/null +++ b/tests/auto/qml/windowitem/tst_windowitem.qml @@ -0,0 +1,482 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +Item { + id: root + width: 500 + height: 500 + visible: true + + Repeater { + id: windowItemsRepeater + model: ListModel { id: windowItemsModel } + delegate: WindowItem { + id: windowItem + window: model.window + + property int clickCount: 0 + property alias mouseAreaVisible: mouseArea.visible + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: windowItem.clickCount += 1; + z: -100 // some arbitrary, negative, Z + } + } + } + Repeater { + id: sizedWindowItemsRepeater + model: ListModel { id: sizedWindowItemsModel } + delegate: WindowItem { + width: 200 + height: 100 + window: model.window + } + } + Repeater { + id: noResizeWindowItemsRepeater + model: ListModel { id: noResizeWindowItemsModel } + delegate: WindowItem { + width: 200 + height: 100 + objectFollowsItemSize: false + window: model.window + } + } + property var chosenModel + Connections { + target: WindowManager + function onWindowAdded(window) { + root.chosenModel.append({"window":window}); + } + } + + // Force redraws so that pings and other events are quickly processed between + // wayland client and server. + Rectangle { + width: 10 + height: 10 + color: "brown" + RotationAnimator on rotation { + from: 0; to: 360; duration: 1000 + loops: Animation.Infinite + running: true + } + } + + SignalSpy { +        id: objectDestroyedSpy +        target: AmTest +        signalName: "objectDestroyed" +    } + + TestCase { + id: testCase + when: windowShown + name: "WindowItem" + + property var app: null + + function init() { + compare(windowItemsModel.count, 0); + compare(sizedWindowItemsModel.count, 0); + compare(noResizeWindowItemsRepeater.count, 0); + compare(WindowManager.count, 0); + } + + function cleanup() { + windowItemsModel.clear(); + sizedWindowItemsModel.clear(); + noResizeWindowItemsModel.clear(); + + if (app) + app.stop(); + + waitUntilAllAppsAreStopped(); + } + + function waitUntilAllAppsAreStopped() { + while (true) { + var numRunningApps = 0; + for (var i = 0; i < ApplicationManager.count; i++) { + var app = ApplicationManager.application(i); + if (app.runState !== Am.NotRunning) + numRunningApps += 1; + } + + if (numRunningApps > 0) { + wait(50); + } else + break; + } + } + + function initWindowItemsModel() { + root.chosenModel = windowItemsModel; + startAppAndCheckWindow(); + } + + function initSizedWindowItemsModel() { + root.chosenModel = sizedWindowItemsModel; + startAppAndCheckWindow(); + } + + function startAppAndCheckWindow() { + app = ApplicationManager.application("test.windowitem.app"); + app.start(); + + tryCompare(root.chosenModel, "count", 1); + tryCompare(WindowManager, "count", 1); + } + + /* + The first WindowItem showing a window have primary==true, from the + second onwards they should have primary==false + */ + function test_onlyFirstItemIsPrimary() { + initWindowItemsModel(); + var firstWindowItem = windowItemsRepeater.itemAt(0); + compare(firstWindowItem.primary, true); + + // Add a second view for the same WindowObject + windowItemsModel.append({"window":firstWindowItem.window}); + + var secondWindowItem = windowItemsRepeater.itemAt(1); + compare(secondWindowItem.primary, false); + } + + /* + Turn a secondary WindowItem (primary == false) into the primary one. + + Check that the previously primary is now secondary and vice-versa. + */ + function test_turnSecondaryIntoPrimary() { + initWindowItemsModel(); + var firstWindowItem = windowItemsRepeater.itemAt(0); + + // Add a second view for the same WindowObject + windowItemsModel.append({"window":firstWindowItem.window}); + + var secondWindowItem = windowItemsRepeater.itemAt(1); + + compare(firstWindowItem.primary, true); + compare(secondWindowItem.primary, false); + + // give primary role to the second WindowItem + secondWindowItem.makePrimary(); + + compare(firstWindowItem.primary, false); + compare(secondWindowItem.primary, true); + + // and take it back + firstWindowItem.makePrimary(); + + compare(firstWindowItem.primary, true); + compare(secondWindowItem.primary, false); + } + + /* + You have two WindowItems for the same WindowObject + + Check that once the primary WindowItem is destroyed, + the remaining one takes over the primary role. + */ + function test_destroyPrimaryRemainingTakesOver() { + initWindowItemsModel(); + var firstWindowItem = windowItemsRepeater.itemAt(0); + + // Add a second view for the same WindowObject + windowItemsModel.append({"window":firstWindowItem.window}); + + var secondWindowItem = windowItemsRepeater.itemAt(1); + + compare(firstWindowItem.primary, true); + compare(secondWindowItem.primary, false); + + compare(windowItemsModel.count, 2); + + // destroy the first WindowItem + windowItemsModel.remove(0 /*index*/, 1 /*count*/); + firstWindowItem = null; + + compare(windowItemsModel.count, 1); + + // And the remaining item takes over the primary role. + tryCompare(secondWindowItem, "primary", true); + } + + /* + Check that a WindowObject with state NoSurface is destroyed + only once all WindowItems using it are gone. + */ + function test_surfacelessObjectStaysUntilAllItemsAreGone() { + initWindowItemsModel(); + var firstWindowItem = windowItemsRepeater.itemAt(0); + + // Add a second view for the same WindowObject + windowItemsModel.append({"window":firstWindowItem.window}); + + var secondWindowItem = windowItemsRepeater.itemAt(1); + + var window = WindowManager.get(0).window; + objectDestroyedSpy.clear(); + var destroyId = AmTest.observeObjectDestroyed(window); + + compare(window.contentState, WindowObject.SurfaceWithContent); + app.stop(); + + // The WindowObject should still exist, albeit without a surface, even though + // no longer present in WindowManager's model. + tryCompare(WindowManager, "count", 0); + compare(objectDestroyedSpy.count, 0) + tryCompare(window, "contentState", WindowObject.NoSurface); + + // Destroy all WindowItems + firstWindowItem = null; + secondWindowItem = null; + windowItemsModel.clear(); + + // Now that there are no WindowItems using that WindowObject anymore, it should + // eventually be deleted by WindowManager + objectDestroyedSpy.wait(); + compare(objectDestroyedSpy.signalArguments[0][0], destroyId); + } + + /* + Checks that the implicit size of a WindowItem matches the explicit size of the client's ApplicationManagerWindow + */ + function test_implicitSize() { + initWindowItemsModel(); + var windowItem = windowItemsRepeater.itemAt(0); + var window = windowItem.window + + // Must match the ApplicationManagerWindow size defined in apps/test.windowitem.app/mail.qml + compare(window.size.width, 123); + compare(window.size.height, 321); + compare(windowItem.width, 123); + compare(windowItem.height, 321); + + // Avoid a race condition where the item's implicit size (and therefore the item's + // size itself as no explicit width or height was assigned) would be set to match + // the window's size while at the same time an item's resize would make the item resize the window. + // In short: item size depending on window size while at the same time window size is + // depending on item size. + windowItem.objectFollowsItemSize = false; + + var width = 130; + var height = 330; + var i; + for (i = 0; i < 20; i += 1) { + window.setWindowProperty("requestedWidth", width); + window.setWindowProperty("requestedHeight", height); + + tryCompare(window, "size", Qt.size(width,height)); + tryCompare(windowItem, "width", width); + tryCompare(windowItem, "height", height); + + width += 5; + height += 5; + wait(10); + } + } + + /* + Checks that once a Window is assinged to a WindowItem its underlying surface + gets resized to match that WindowItem's size (considering it's the first, + primary, one) + */ + function test_initialResize() { + initSizedWindowItemsModel(); + var windowItem = sizedWindowItemsRepeater.itemAt(0); + var window = windowItem.window + + tryCompare(window, "size", Qt.size(windowItem.width, windowItem.height)); + } + + /* + By default a WindowItem will resize the WindowObject it's displaying to match his own size. + So resizing a WindowItem will cause his WindowObject to follow suit, so that both always + have matching sizes. + */ + function test_objectFollowsItemSize() { + initSizedWindowItemsModel(); + var windowItem = sizedWindowItemsRepeater.itemAt(0); + var window = windowItem.window; + + windowItem.width = 200; + windowItem.height = 100; + tryCompare(window, "size", Qt.size(200, 100)); + + windowItem.width = 201; + windowItem.height = 101; + tryCompare(window, "size", Qt.size(201, 101)); + + windowItem.width = 202; + windowItem.height = 102; + tryCompare(window, "size", Qt.size(202, 102)); + } + + /* + When WindowItem.objectFollowsItemSize is false, resizing the WindowItem will have no effect + over the WindowObject's size. + */ + function test_windowDoesNotFolowItemSize() { + root.chosenModel = noResizeWindowItemsModel; + startAppAndCheckWindow(); + + var windowItem = noResizeWindowItemsRepeater.itemAt(0); + var window = windowItem.window; + + windowItem.width = 200; + windowItem.height = 100; + tryCompare(window, "size", Qt.size(123, 321)); + + windowItem.width = 201; + windowItem.height = 101; + tryCompare(window, "size", Qt.size(123, 321)); + + windowItem.width = 202; + windowItem.height = 102; + tryCompare(window, "size", Qt.size(123, 321)); + } + + /* + Checks that calling close() on an empty WindowObject won't cause a crash (particularly + in multi-process) + */ + function test_closeEmptyWindow() { + initWindowItemsModel(); + + var windowItem = windowItemsRepeater.itemAt(0); + var window = windowItem.window; + + app.stop(); + + tryCompare(window, "contentState", WindowObject.NoSurface); + + window.close(); + } + + /* + Regression test for https://bugreports.qt.io/browse/AUTOSUITE-652 + + - Start an application that has two windows. + - Call close() on the first one. It should vanish. Application should keep running normally. + - Call close() on the second one. It should vanish as well and, being the app's last window, it should + also cause the application to quit. + */ + function test_closeWindows() { + root.chosenModel = windowItemsModel; + + app = ApplicationManager.application("test.windowitem.multiwin"); + app.start(); + + tryCompare(windowItemsModel, "count", 2); + tryCompare(WindowManager, "count", 2); + + var firstWindow = windowItemsModel.get(0).window; + var secondWindow = windowItemsModel.get(1).window; + + compare(app.runState, Am.Running); + compare(firstWindow.contentState, WindowObject.SurfaceWithContent); + + firstWindow.close(); + + tryCompare(firstWindow, "contentState", WindowObject.NoSurface); + windowItemsModel.remove(0); + firstWindow = null; + + wait(100); + + compare(app.runState, Am.Running); + compare(secondWindow.contentState, WindowObject.SurfaceWithContent); + + secondWindow.close(); + + tryCompare(secondWindow, "contentState", WindowObject.NoSurface); + tryCompare(app, "runState", Am.NotRunning); + } + + /* + Children added by System UI code must always stay in front of WindowItem's own private children. + */ + function test_childrenZOrder() { + initWindowItemsModel(); + + var windowItem = windowItemsRepeater.itemAt(0); + var window = windowItem.window; + + windowItem.mouseAreaVisible = false; + + touchEvent(windowItem).press(0).commit(); + touchEvent(windowItem).release(0).commit(); + + // There's nothing in front of the wayland item (at least nothing visible). + // The touch event will reach it. + tryVerify(function() { return window.windowProperty("clickCount") === 1; }); + compare(windowItem.clickCount, 0); + + windowItem.mouseAreaVisible = true; + + touchEvent(windowItem).press(0).commit(); + touchEvent(windowItem).release(0).commit(); + + // Since a visible MouseArea is now in front of WindowItem's internal wayland item + // the second touch event was caught by that MouseArea instead. + tryCompare(windowItem, "clickCount", 1); + compare(window.windowProperty("clickCount"), 1); + + } + + // Checks that window properties are kept even when contentState is WindowObject.NoSurface + // Regression test for https://bugreports.qt.io/browse/AUTOSUITE-694 + function test_window_keep_properties_when_nosurface() { + initWindowItemsModel(); + + var window = windowItemsModel.get(0).window; + + compare(window.contentState, WindowObject.SurfaceWithContent); + + window.setWindowProperty("foo", "bar"); + compare(window.windowProperty("foo"), "bar"); + + app.stop(); + + tryCompare(window, "contentState", WindowObject.NoSurface); + compare(window.windowProperty("foo"), "bar"); + } + } +} diff --git a/tests/auto/qml/windowitem/windowitem.pro b/tests/auto/qml/windowitem/windowitem.pro new file mode 100644 index 00000000..fcc1b1f6 --- /dev/null +++ b/tests/auto/qml/windowitem/windowitem.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_windowitem.qml +TEST_APPS = test.windowitem.app test.windowitem.multiwin + +load(am-qml-testcase) diff --git a/tests/auto/qml/windowitem2/CMakeLists.txt b/tests/auto/qml/windowitem2/CMakeLists.txt new file mode 100644 index 00000000..482405d9 --- /dev/null +++ b/tests/auto/qml/windowitem2/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from windowitem2.pro. + +##################################################################### +## windowitem2 Binary: +##################################################################### + +qt_internal_add_executable(windowitem2 + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:windowitem2.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "test.windowitem2.app" +# TEST_FILES = "tst_windowitem2.qml" diff --git a/tests/auto/qml/windowitem2/am-config.yaml b/tests/auto/qml/windowitem2/am-config.yaml new file mode 100644 index 00000000..5333dae3 --- /dev/null +++ b/tests/auto/qml/windowitem2/am-config.yaml @@ -0,0 +1,11 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +# Workaround for a crash in the mesa software renderer (llvmpipe) +runtimes: + qml: + environmentVariables: + QT_QUICK_BACKEND: "software" diff --git a/tests/auto/qml/windowitem2/apps/test.windowitem2.app/icon.png b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/icon.png differ diff --git a/tests/auto/qml/windowitem2/apps/test.windowitem2.app/info.yaml b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/info.yaml new file mode 100644 index 00000000..34198c88 --- /dev/null +++ b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.windowitem2.app' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'WindowItem2 Test App' diff --git a/tests/auto/qml/windowitem2/apps/test.windowitem2.app/main.qml b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/main.qml new file mode 100644 index 00000000..a0c453aa --- /dev/null +++ b/tests/auto/qml/windowitem2/apps/test.windowitem2.app/main.qml @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + color: "red" + + width: 123 + height: 321 +} diff --git a/tests/auto/qml/windowitem2/tst_windowitem2.qml b/tests/auto/qml/windowitem2/tst_windowitem2.qml new file mode 100644 index 00000000..51759539 --- /dev/null +++ b/tests/auto/qml/windowitem2/tst_windowitem2.qml @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +Item { + id: root + width: 500 + height: 500 + visible: true + + WindowItem { + id: windowItem + } + + Connections { + target: WindowManager + function onWindowAdded(window) { + windowItem.window = window; + } + + function onWindowAboutToBeRemoved(window) { + if (window === windowItem.window) { + windowItem.window = null; + } + } + } + + // Force redraws so that pings and other events are quickly processed between + // wayland client and server. + Rectangle { + width: 10 + height: 10 + color: "brown" + RotationAnimator on rotation { + from: 0; to: 360; duration: 1000 + loops: Animation.Infinite + running: true + } + } + + TestCase { + id: testCase + when: windowShown + name: "WindowItem2" + + function init() { + } + + function cleanup() { + waitUntilAllAppsAreStopped(); + } + + function waitUntilAllAppsAreStopped() { + while (true) { + var numRunningApps = 0; + for (var i = 0; i < ApplicationManager.count; i++) { + var app = ApplicationManager.application(i); + if (app.runState !== Am.NotRunning) + numRunningApps += 1; + } + + if (numRunningApps > 0) { + wait(50); + } else + break; + } + } + + /* + The sequence below only takes place if WindowManager has direct connections to + Window::isBeingDisplayedChanged and Window::contentStateChanged and those connections call + WindowManager::removeWindow: + + 1. When Window.contentState changes to Window::NoSurface, WindowManager calls removeWindow() on it. + 2. Inside WindowManager::removeWindow, windowAboutToBeRemoved gets emitted. + 3. The onWindowAboutToBeRemoved signal handler above is called and sets WindowItem.window to null + 4. That causes Window.isBeingDisplayedChanged to turn to false, which in turn gets + WindowManager to call removeWindow() on that same window once again. + 5. The innermost removeWindow() from 4 successfuly executes and removes the window from WindowManager's + internal vector + 6. once the outermost removeWindow() from 1. finally goes past the signal emission from 2. and tries + to remove the item from for index it previously collected, that index is no longer valid as the vector + already changed. Then you either are removing the wrong item or trying to remove a now invalid index, + which causes a crash. + + This is a regression test for such crash + */ + function test_triggerNestedRemoval() { + var app = ApplicationManager.application("test.windowitem2.app"); + app.start(); + + tryVerify(function() { return windowItem.window !== null }); + wait(50); + + app.stop(); + } + + } +} diff --git a/tests/auto/qml/windowitem2/windowitem2.pro b/tests/auto/qml/windowitem2/windowitem2.pro new file mode 100644 index 00000000..022ea053 --- /dev/null +++ b/tests/auto/qml/windowitem2/windowitem2.pro @@ -0,0 +1,5 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_windowitem2.qml +TEST_APPS = test.windowitem2.app + +load(am-qml-testcase) diff --git a/tests/auto/qml/windowmanager/CMakeLists.txt b/tests/auto/qml/windowmanager/CMakeLists.txt new file mode 100644 index 00000000..4f0d2d91 --- /dev/null +++ b/tests/auto/qml/windowmanager/CMakeLists.txt @@ -0,0 +1,15 @@ +# Generated from windowmanager.pro. + +##################################################################### +## windowmanager Binary: +##################################################################### + +qt_internal_add_executable(windowmanager + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:windowmanager.pro:: +# OTHER_FILES = "IviApplicationExtension.qml" +# TEST_FILES = "tst_windowmanager.qml" diff --git a/tests/auto/qml/windowmanager/IviApplicationExtension.qml b/tests/auto/qml/windowmanager/IviApplicationExtension.qml new file mode 100644 index 00000000..08486dc4 --- /dev/null +++ b/tests/auto/qml/windowmanager/IviApplicationExtension.qml @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtApplicationManager.SystemUI 2.0 +import QtWayland.Compositor 1.1 + +QtObject { + property Component iviComp: Component { + IviApplication {} + } + + function addExtension() { + return WindowManager.addExtension(iviComp); + } +} diff --git a/tests/auto/qml/windowmanager/tst_windowmanager.qml b/tests/auto/qml/windowmanager/tst_windowmanager.qml new file mode 100644 index 00000000..5927fae1 --- /dev/null +++ b/tests/auto/qml/windowmanager/tst_windowmanager.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "WindowManager" + visible: true + + Component { + id: textComp + Text {} + } + + SignalSpy { + id: windowManagerCompositorReadyChangedSpy + target: ApplicationManager + signalName: "windowManagerCompositorReadyChanged" + } + + function test_addExtension() { + if (!ApplicationManager.singleProcess) { + if (!ApplicationManager.windowManagerCompositorReady) { + var extnull = Qt.createComponent("IviApplicationExtension.qml").createObject(null).addExtension(); + compare(extnull, null); + windowManagerCompositorReadyChangedSpy.wait(2000); + verify(ApplicationManager.windowManagerCompositorReady); + } + var extension = Qt.createComponent("IviApplicationExtension.qml").createObject(null).addExtension(); + verify(extension); + verify(extension.hasOwnProperty('iviSurfaceCreated')); + } + compare(WindowManager.addExtension(textComp), null); + } +} diff --git a/tests/auto/qml/windowmanager/windowmanager.pro b/tests/auto/qml/windowmanager/windowmanager.pro new file mode 100644 index 00000000..21cd8a91 --- /dev/null +++ b/tests/auto/qml/windowmanager/windowmanager.pro @@ -0,0 +1,5 @@ +TEST_FILES = tst_windowmanager.qml + +OTHER_FILES += IviApplicationExtension.qml + +load(am-qml-testcase) diff --git a/tests/auto/qml/windowmapping/CMakeLists.txt b/tests/auto/qml/windowmapping/CMakeLists.txt new file mode 100644 index 00000000..d071c8e1 --- /dev/null +++ b/tests/auto/qml/windowmapping/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from windowmapping.pro. + +##################################################################### +## windowmapping Binary: +##################################################################### + +qt_internal_add_executable(windowmapping + GUI + PUBLIC_LIBRARIES + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:windowmapping.pro:: +# AM_CONFIG = "am-config.yaml" +# TEST_APPS = "test.winmap.amwin" "test.winmap.amwin2" "test.winmap.loader" "test.winmap.ping" "test.winmap.qtobject" "test.winmap.rectangle" "test.winmap.window" +# TEST_FILES = "tst_windowmapping.qml" diff --git a/tests/auto/qml/windowmapping/am-config.yaml b/tests/auto/qml/windowmapping/am-config.yaml new file mode 100644 index 00000000..5333dae3 --- /dev/null +++ b/tests/auto/qml/windowmapping/am-config.yaml @@ -0,0 +1,11 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +# Workaround for a crash in the mesa software renderer (llvmpipe) +runtimes: + qml: + environmentVariables: + QT_QUICK_BACKEND: "software" diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin/amwin.qml b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/amwin.qml new file mode 100644 index 00000000..05e56276 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/amwin.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + + ApplicationManagerWindow { + id: sub + visible: false + Component.onCompleted: setWindowProperty("type", "sub"); + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-main": root.visible = true; root.setWindowProperty("key1", "val1"); break; + case "hide-main": root.visible = false; break; + case "show-sub": sub.visible = true; break; + case "hide-sub": sub.visible = false; break; + } + } + } + + Component.onCompleted: setWindowProperty("objectName", 42); +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/info.yaml new file mode 100644 index 00000000..78c26e03 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.amwin/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.amwin' +icon: 'icon.png' +code: 'amwin.qml' +runtime: 'qml' +name: + en: 'ApplicationManagerWindow Root' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml new file mode 100644 index 00000000..f6d58131 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + visible: false + + ApplicationManagerWindow { + id: sub + visible: false + Component.onCompleted: setWindowProperty("type", "sub"); + } + + Rectangle { + anchors.fill: parent + visible: false + + ApplicationManagerWindow { + id: sub2 + visible: false + Component.onCompleted: setWindowProperty("type", "sub2"); + } + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-main": root.visible = true; break; + case "hide-main": root.visible = false; break; + case "show-sub": sub.visible = true; break; + case "hide-sub": sub.visible = false; break; + case "show-sub2": sub2.visible = true; break; + case "hide-sub2": sub2.visible = false; break; + } + } + } +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/info.yaml new file mode 100644 index 00000000..041524a8 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.amwin2/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.amwin2' +icon: 'icon.png' +code: 'amwin2.qml' +runtime: 'qml' +name: + en: 'ApplicationManagerWindow Advanced' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.loader/SubWin.qml b/tests/auto/qml/windowmapping/apps/test.winmap.loader/SubWin.qml new file mode 100644 index 00000000..a39ebc53 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.loader/SubWin.qml @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + Component.onCompleted: setWindowProperty("type", "sub"); +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.loader/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.loader/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.loader/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.loader/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.loader/info.yaml new file mode 100644 index 00000000..6e486078 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.loader/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.loader' +icon: 'icon.png' +code: 'loader.qml' +runtime: 'qml' +name: + en: 'Dynamic loading' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.loader/loader.qml b/tests/auto/qml/windowmapping/apps/test.winmap.loader/loader.qml new file mode 100644 index 00000000..d1394ce4 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.loader/loader.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + visible: true + + Loader { + id: ldr + active: false + source: "SubWin.qml" + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-sub": ldr.active = true; break; + case "hide-sub": ldr.active = false; break; + } + } + } +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.ping/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.ping/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.ping/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.ping/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.ping/info.yaml new file mode 100644 index 00000000..3f4e822e --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.ping/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.ping' +icon: 'icon.png' +code: 'ping.qml' +runtime: 'qml' +name: + en: 'Wayland ping-pong' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.ping/ping.qml b/tests/auto/qml/windowmapping/apps/test.winmap.ping/ping.qml new file mode 100644 index 00000000..c6e6c02d --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.ping/ping.qml @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + Timer { + id: tim + interval: 100 + running: true + onTriggered: { + while (true); // application hangs + } + } +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/info.yaml new file mode 100644 index 00000000..98926746 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.qtobject' +icon: 'icon.png' +code: 'qtobject.qml' +runtime: 'qml' +name: + en: 'QtObject Root' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml new file mode 100644 index 00000000..203b0f56 --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +QtObject { + id: root + + property ApplicationManagerWindow mainWin: ApplicationManagerWindow { + id: main + visible: false + } + + property ApplicationManagerWindow subWin: ApplicationManagerWindow { + id: sub + visible: false + Component.onCompleted: setWindowProperty("type", "sub"); + } + + property Connections con: Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-main": main.visible = true; break; + case "hide-main": main.visible = false; break; + case "show-sub": sub.visible = true; break; + case "hide-sub": sub.visible = false; break; + } + } + } +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/info.yaml new file mode 100644 index 00000000..0981b53d --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.rectangle' +icon: 'icon.png' +code: 'rectangle.qml' +runtime: 'qml' +name: + en: 'Rectangle Root' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml new file mode 100644 index 00000000..8e11e72c --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +Rectangle { + id: root + + ApplicationManagerWindow { + id: sub + visible: false + Component.onCompleted: setWindowProperty("type", "sub"); + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-main": root.visible = true; break; + case "hide-main": root.visible = false; break; + case "show-sub": sub.visible = true; break; + case "hide-sub": sub.visible = false; break; + } + } + } +} diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.window/icon.png b/tests/auto/qml/windowmapping/apps/test.winmap.window/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/auto/qml/windowmapping/apps/test.winmap.window/icon.png differ diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.window/info.yaml b/tests/auto/qml/windowmapping/apps/test.winmap.window/info.yaml new file mode 100644 index 00000000..c527475d --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.window/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'test.winmap.window' +icon: 'icon.png' +code: 'window.qml' +runtime: 'qml' +name: + en: 'Window Root' diff --git a/tests/auto/qml/windowmapping/apps/test.winmap.window/window.qml b/tests/auto/qml/windowmapping/apps/test.winmap.window/window.qml new file mode 100644 index 00000000..588f33ce --- /dev/null +++ b/tests/auto/qml/windowmapping/apps/test.winmap.window/window.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Window 2.0 +import QtApplicationManager.Application 2.0 + +Window { + id: root + visible: true // explicitly set, since false by default + + ApplicationManagerWindow { + id: sub + visible: false + Component.onCompleted: setWindowProperty("type", "sub"); + } + + Connections { + target: ApplicationInterface + function onOpenDocument(documentUrl) { + switch (documentUrl) { + case "show-main": root.visible = true; break; + case "hide-main": root.visible = false; break; + case "show-sub": sub.visible = true; break; + case "hide-sub": sub.visible = false; break; + } + } + } +} diff --git a/tests/auto/qml/windowmapping/tst_windowmapping.qml b/tests/auto/qml/windowmapping/tst_windowmapping.qml new file mode 100644 index 00000000..140665c5 --- /dev/null +++ b/tests/auto/qml/windowmapping/tst_windowmapping.qml @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtApplicationManager.SystemUI 2.0 + +TestCase { + id: testCase + when: windowShown + name: "WindowMapping" + visible: true + + property var lastWindowAdded; + + WindowItem { + id: chrome + anchors.fill: parent + + Connections { + target: chrome.window + function onContentStateChanged() { + if (chrome.window.contentState === WindowObject.NoSurface) + chrome.window = null; + } + } + + WindowItem { + id: subChrome + anchors.fill: parent + Connections { + target: subChrome.window + function onContentStateChanged() { + if (subChrome.window.contentState === WindowObject.NoSurface) + subChrome.window = null; + } + } + } + } + + Connections { + target: WindowManager + function onWindowAdded(window) { + if (window.windowProperty("type") === "sub") + subChrome.window = window; + else + chrome.window = window; + + testCase.lastWindowAdded = window; + } + } + + + SignalSpy { + id: windowAddedSpy + target: WindowManager + signalName: "windowAdded" + } + + SignalSpy { + id: windowAboutToBeRemovedSpy + target: WindowManager + signalName: "windowAboutToBeRemoved" + } + + SignalSpy { + id: windowPropertyChangedSpy + target: WindowManager + signalName: "windowPropertyChanged" + } + +    SignalSpy { +        id: runStateChangedSpy +        target: ApplicationManager +        signalName: "applicationRunStateChanged" +    } + + function cleanup() { + runStateChangedSpy.clear(); + ApplicationManager.stopAllApplications(); + + while (true) { + var numRunningApps = 0; + for (var i = 0; i < ApplicationManager.count; i++) { + var app = ApplicationManager.application(i); + if (app.runState !== Am.NotRunning) + numRunningApps += 1; + } + + if (numRunningApps > 0) { + wait(2000); + } else + break; + } + + windowAddedSpy.clear(); + windowAboutToBeRemovedSpy.clear(); + } + + function test_windowmanager_added_removed_signals() { + var app = ApplicationManager.application("test.winmap.amwin"); + + compare(windowAddedSpy.count, 0); + app.start("show-main"); + tryCompare(windowAddedSpy, "count", 1); + + compare(windowAboutToBeRemovedSpy.count, 0); + app.stop(); + tryCompare(windowAboutToBeRemovedSpy, "count", 1); + } + + function test_amwin_advanced() { + var app = ApplicationManager.application("test.winmap.amwin2"); + app.start("show-sub"); + wait(2000); + compare(WindowManager.count, 0); + + app.start("show-main"); + tryCompare(WindowManager, "count", 2); + } + + function test_amwin_loader() { + tryCompare(WindowManager, "count", 0); + + var app = ApplicationManager.application("test.winmap.loader"); + + app.start("show-sub"); + tryCompare(WindowManager, "count", 2); + + app.start("hide-sub"); + tryCompare(WindowManager, "count", 1); + + app.start("show-sub"); + tryCompare(WindowManager, "count", 2); + } + + function test_amwin_peculiarities() { + var app = ApplicationManager.application("test.winmap.amwin2"); + + tryCompare(WindowManager, "count", 0); + + app.start("show-main"); + tryCompare(WindowManager, "count", 1); + + app.start("show-sub"); + tryCompare(WindowManager, "count", 2); + + // Single- vs. multiprocess difference: + app.start("show-sub2"); + var expectedWindowCount; + // A Window's effective visible state solely depends on Window hierarchy. + expectedWindowCount = 3; + tryCompare(WindowManager, "count", expectedWindowCount); + + app.start("hide-sub"); + expectedWindowCount -= 1; + tryCompare(WindowManager, "count", expectedWindowCount); + + // Make child (sub) window visible again, parent (main) window is still visible + app.start("show-sub"); + expectedWindowCount += 1; + tryCompare(WindowManager, "count", expectedWindowCount); + + // This is weird Window behavior: a child window becomes only visible, when the parent + // window is visible, but when you change the parent window back to invisible, the child + // will NOT become invisible. + app.start("hide-main"); + expectedWindowCount -= 1; + tryCompare(WindowManager, "count", expectedWindowCount); + + // Single- vs. multiprocess difference: + app.start("hide-sub"); + if (ApplicationManager.singleProcess) { + expectedWindowCount -= 1; + } else { + // This is even more weird Window behavior: when the parent window is invisible, it is + // not possible any more to explicitly set the child window to invisible. + wait(50); + } + tryCompare(WindowManager, "count", expectedWindowCount); + } + + function test_default_data() { + return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" }, + // skipping QtObject, as it doesn't show anything + { tag: "Rectangle", appId: "test.winmap.rectangle" }, + { tag: "Window", appId: "test.winmap.window" } ]; + } + + function test_default(data) { + if (ApplicationManager.singleProcess && data.tag === "Window") + skip("Window root element is not properly supported in single process mode."); + + compare(WindowManager.count, 0); + + var app = ApplicationManager.application(data.appId); + verify(chrome.window === null); + app.start(); + tryCompare(WindowManager, "count", 1); + tryVerify(function () { return chrome.window !== null }); + + app.stop(); + tryCompare(WindowManager, "count", 0); + } + + function test_mapping_data() { + return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" }, + { tag: "QtObject", appId: "test.winmap.qtobject" }, + { tag: "Rectangle", appId: "test.winmap.rectangle" }, + { tag: "Window", appId: "test.winmap.window" } ]; + } + + function test_mapping(data) { + if (ApplicationManager.singleProcess && data.tag === "Window") + skip("Window root element is not properly supported in single process mode."); + + var app = ApplicationManager.application(data.appId); + + compare(WindowManager.count, 0); + + app.start("show-main"); + tryCompare(WindowManager, "count", 1); + + app.start("show-sub"); + tryCompare(WindowManager, "count", 2); + + app.start("hide-sub"); + tryCompare(WindowManager, "count", 1); + + app.stop(); + tryCompare(WindowManager, "count", 0); + } + + function test_wayland_ping_pong() { + var app = ApplicationManager.application("test.winmap.ping"); + + if (ApplicationManager.singleProcess) + skip("Wayland ping-pong is only supported in multi-process mode"); + + AmTest.ignoreMessage(AmTest.CriticalMsg, /Stopping application.*because we did not receive a Wayland-Pong/); + app.start(); + tryCompare(app, "runState", Am.Running); + runStateChangedSpy.clear(); + wait(2200); + runStateChangedSpy.wait(2000); + compare(runStateChangedSpy.signalArguments[0][1], Am.ShuttingDown); + runStateChangedSpy.wait(2000); + compare(runStateChangedSpy.signalArguments[1][1], Am.NotRunning); + } + + function test_window_properties() { + var app = ApplicationManager.application("test.winmap.amwin"); + + windowPropertyChangedSpy.clear(); + app.start(); + tryCompare(WindowManager, "count", 1); + + app.start("show-main"); + windowPropertyChangedSpy.wait(2000); + compare(windowPropertyChangedSpy.count, 1); + + compare(lastWindowAdded.windowProperty("key1"), "val1"); + compare(lastWindowAdded.windowProperty("objectName"), 42); + + lastWindowAdded.setWindowProperty("key2", "val2"); + windowPropertyChangedSpy.wait(2000); + compare(windowPropertyChangedSpy.count, 2); + + var allProps = lastWindowAdded.windowProperties() + compare(Object.keys(allProps).length, 3); + compare(allProps.key1, "val1"); + compare(allProps.key2, "val2"); + compare(allProps.objectName, 42); + } + + // Checks that window properties survive show/hide cycles + // Regression test for https://bugreports.qt.io/browse/AUTOSUITE-447 + function test_window_properties_survive_show_hide() { + var app = ApplicationManager.application("test.winmap.amwin"); + + app.start("show-main"); + tryCompare(WindowManager, "count", 1); + + compare(lastWindowAdded.windowProperty("objectName"), 42); + + app.start("hide-main"); + tryCompare(WindowManager, "count", 0); + app.start("show-main"); + tryCompare(WindowManager, "count", 1); + + compare(lastWindowAdded.windowProperty("objectName"), 42); + } +} diff --git a/tests/auto/qml/windowmapping/windowmapping.pro b/tests/auto/qml/windowmapping/windowmapping.pro new file mode 100644 index 00000000..e29aba28 --- /dev/null +++ b/tests/auto/qml/windowmapping/windowmapping.pro @@ -0,0 +1,12 @@ +AM_CONFIG = am-config.yaml +TEST_FILES = tst_windowmapping.qml +TEST_APPS = \ + test.winmap.amwin \ + test.winmap.amwin2 \ + test.winmap.loader \ + test.winmap.ping \ + test.winmap.qtobject \ + test.winmap.rectangle \ + test.winmap.window \ + +load(am-qml-testcase) diff --git a/tests/auto/runtime/CMakeLists.txt b/tests/auto/runtime/CMakeLists.txt new file mode 100644 index 00000000..d3973556 --- /dev/null +++ b/tests/auto/runtime/CMakeLists.txt @@ -0,0 +1,22 @@ + +qt_internal_add_test(tst_runtime + SOURCES + ../error-checking.h + tst_runtime.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::Qml + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_runtime CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/runtime/runtime.pro b/tests/auto/runtime/runtime.pro new file mode 100644 index 00000000..64c550cc --- /dev/null +++ b/tests/auto/runtime/runtime.pro @@ -0,0 +1,11 @@ +TARGET = tst_runtime + +include($$PWD/../tests.pri) + +QT *= qml +QT *= \ + appman_common-private \ + appman_application-private \ + appman_manager-private \ + +SOURCES += tst_runtime.cpp diff --git a/tests/auto/runtime/tst_runtime.cpp b/tests/auto/runtime/tst_runtime.cpp new file mode 100644 index 00000000..ee62e5d4 --- /dev/null +++ b/tests/auto/runtime/tst_runtime.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "application.h" +#include "package.h" +#include "abstractruntime.h" +#include "runtimefactory.h" +#include "exception.h" + +QT_USE_NAMESPACE_AM + +class tst_Runtime : public QObject +{ + Q_OBJECT + +public: + tst_Runtime(); + +private slots: + void factory(); +}; + +class TestRuntimeManager; + +class TestRuntime : public AbstractRuntime +{ + Q_OBJECT + +public: + explicit TestRuntime(AbstractContainer *container, Application *app, AbstractRuntimeManager *manager) + : AbstractRuntime(container, app, manager) + { } + + void setSlowAnimations(bool) override {} + + qint64 applicationProcessId() const override + { + return m_state == Am::Running ? 1 : 0; + } + +public slots: + bool start() override + { + m_state = Am::Running; + return true; + } + + void stop(bool forceKill) override + { + Q_UNUSED(forceKill); + m_state = Am::NotRunning; + } +}; + +class TestRuntimeManager : public AbstractRuntimeManager +{ + Q_OBJECT + +public: + TestRuntimeManager(const QString &id, QObject *parent) + : AbstractRuntimeManager(id, parent) + { } + + static QString defaultIdentifier() { return qSL("foo"); } + + bool inProcess() const override + { + return !AbstractRuntimeManager::inProcess(); + } + + TestRuntime *create(AbstractContainer *container, Application *app) override + { + return new TestRuntime(container, app, this); + } +}; + + +tst_Runtime::tst_Runtime() +{ } + +void tst_Runtime::factory() +{ + RuntimeFactory *rf = RuntimeFactory::instance(); + + QVERIFY(rf); + QVERIFY(rf == RuntimeFactory::instance()); + QVERIFY(rf->runtimeIds().isEmpty()); + + QVERIFY(rf->registerRuntime(new TestRuntimeManager(qSL("foo"), qApp))); + QVERIFY(rf->runtimeIds() == QStringList() << qSL("foo")); + + QVERIFY(!rf->create(nullptr, nullptr)); + + QByteArray yaml = + "formatVersion: 1\n" + "formatType: am-application\n" + "---\n" + "id: com.pelagicore.test\n" + "name: { en_US: 'Test' }\n" + "icon: icon.png\n" + "code: test.foo\n" + "runtime: foo\n"; + + QTemporaryFile temp; + QVERIFY(temp.open()); + QCOMPARE(temp.write(yaml), yaml.size()); + temp.close(); + + Application *a = nullptr; + try { + PackageInfo *pi = PackageInfo::fromManifest(temp.fileName()); + QVERIFY(pi); + Package *p = new Package(pi); + a = new Application(pi->applications().first(), p); + } catch (const Exception &e) { + QVERIFY2(false, qPrintable(e.errorString())); + } + QVERIFY(a); + + AbstractRuntime *r = rf->create(nullptr, a); + QVERIFY(r); + QVERIFY(r->application() == a); + QVERIFY(r->manager()->inProcess()); + QVERIFY(r->state() == Am::NotRunning); + QVERIFY(r->applicationProcessId() == 0); + { + QScopedPointer engine(new QQmlEngine()); + QVERIFY(!r->inProcessQmlEngine()); + r->setInProcessQmlEngine(engine.data()); + QVERIFY(r->inProcessQmlEngine() == engine.data()); + r->setInProcessQmlEngine(nullptr); + } + QVERIFY(r->start()); + QVERIFY(r->state() == Am::Running); + QVERIFY(r->applicationProcessId() == 1); + r->stop(); + QVERIFY(r->state() == Am::NotRunning); + QVERIFY(!r->securityToken().isEmpty()); + + delete r; + delete rf; + delete a; +} + +QTEST_MAIN(tst_Runtime) + +#include "tst_runtime.moc" diff --git a/tests/auto/signature/CMakeLists.txt b/tests/auto/signature/CMakeLists.txt new file mode 100644 index 00000000..4a102b45 --- /dev/null +++ b/tests/auto/signature/CMakeLists.txt @@ -0,0 +1,41 @@ + +qt_internal_add_test(tst_signature + SOURCES + ../error-checking.h + tst_signature.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate + Qt::AppManCryptoPrivate +) + +# Resources: +set(tst_signature_resource_files + "signature-openssl.p7" + "signature-securityframework.p7" + "signature-wincrypt.p7" + "signing-no-key.p12" + "signing.p12" + "verifying.crt" +) + +qt_internal_add_resource(tst_signature "tst_signature" + PREFIX + "/" + FILES + ${tst_signature_resource_files} +) + + +#### Keys ignored in scope 1:.:.:signature.pro:: +# OTHER_FILES = "create-test-data.sh" + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_signature CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/signature/create-test-data.sh b/tests/auto/signature/create-test-data.sh new file mode 100644 index 00000000..68f05575 --- /dev/null +++ b/tests/auto/signature/create-test-data.sh @@ -0,0 +1,40 @@ +#!/bin/sh +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Copyright (C) 2019 Luxoft Sweden AB +## Copyright (C) 2018 Pelagicore AG +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the QtApplicationManager module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +echo "Recreating test data" + +certdir="../data/certificates/" + +[ -f $certdir/dev1.p12 ] || { echo "Please generate test certificates in $certdir first"; exit 1; } + +cp $certdir/dev1.p12 signing.p12 +openssl pkcs12 -export -out signing-no-key.p12 -password pass:password -inkey $certdir/dev1-priv.key -nodes -certfile $certdir/ca.crt -in $certdir/dev1.crt -name "Developer 1 Certificate (no key)" -nokeys +cat $certdir/ca.crt $certdir/devca.crt >verifying.crt diff --git a/tests/auto/signature/signature-openssl.p7 b/tests/auto/signature/signature-openssl.p7 new file mode 100644 index 00000000..294310cf Binary files /dev/null and b/tests/auto/signature/signature-openssl.p7 differ diff --git a/tests/auto/signature/signature-securityframework.p7 b/tests/auto/signature/signature-securityframework.p7 new file mode 100644 index 00000000..ded48dd8 Binary files /dev/null and b/tests/auto/signature/signature-securityframework.p7 differ diff --git a/tests/auto/signature/signature-wincrypt.p7 b/tests/auto/signature/signature-wincrypt.p7 new file mode 100644 index 00000000..e3ef40d3 Binary files /dev/null and b/tests/auto/signature/signature-wincrypt.p7 differ diff --git a/tests/auto/signature/signature.pro b/tests/auto/signature/signature.pro new file mode 100644 index 00000000..43bb3d47 --- /dev/null +++ b/tests/auto/signature/signature.pro @@ -0,0 +1,11 @@ +TARGET = tst_signature + +include($$PWD/../tests.pri) + +QT *= appman_common-private appman_crypto-private + +SOURCES += tst_signature.cpp + +OTHER_FILES += create-test-data.sh + +RESOURCES += tst_signature.qrc diff --git a/tests/auto/signature/signing-no-key.p12 b/tests/auto/signature/signing-no-key.p12 new file mode 100644 index 00000000..57705d79 Binary files /dev/null and b/tests/auto/signature/signing-no-key.p12 differ diff --git a/tests/auto/signature/signing.p12 b/tests/auto/signature/signing.p12 new file mode 100644 index 00000000..5d752759 Binary files /dev/null and b/tests/auto/signature/signing.p12 differ diff --git a/tests/auto/signature/tst_signature.cpp b/tests/auto/signature/tst_signature.cpp new file mode 100644 index 00000000..ea4f471d --- /dev/null +++ b/tests/auto/signature/tst_signature.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "global.h" +#include "signature.h" + +QT_USE_NAMESPACE_AM + +class tst_Signature : public QObject +{ + Q_OBJECT + +public: + tst_Signature(); + +private slots: + void initTestCase(); + void check(); + void crossPlatform(); + +private: + QByteArray m_signingP12; + QByteArray m_signingNoKeyP12; + QByteArray m_signingPassword; + QList m_verifyingPEM; +}; + +tst_Signature::tst_Signature() +{ } + +void tst_Signature::initTestCase() +{ + QFile s(qSL(":/signing.p12")); + QVERIFY(s.open(QIODevice::ReadOnly)); + m_signingP12 = s.readAll(); + QVERIFY(!m_signingP12.isEmpty()); + + QFile snk(qSL(":/signing-no-key.p12")); + QVERIFY(snk.open(QIODevice::ReadOnly)); + m_signingNoKeyP12 = snk.readAll(); + QVERIFY(!m_signingNoKeyP12.isEmpty()); + + QFile v(qSL(":/verifying.crt")); + QVERIFY(v.open(QIODevice::ReadOnly)); + m_verifyingPEM << v.readAll(); + QVERIFY(!m_verifyingPEM.first().isEmpty()); + + m_signingPassword = "password"; +} + +void tst_Signature::check() +{ + QByteArray hash("foo"); + Signature s(hash); + QVERIFY(s.errorString().isEmpty()); + QByteArray signature = s.create(m_signingP12, m_signingPassword); + QVERIFY2(!signature.isEmpty(), qPrintable(s.errorString())); + + Signature s2(hash + "bar"); + QByteArray signature2 = s2.create(m_signingP12, m_signingPassword); + QVERIFY2(!signature2.isEmpty(), qPrintable(s2.errorString())); + QVERIFY(signature != signature2); + + QVERIFY2(s.verify(signature, m_verifyingPEM), qPrintable(s.errorString())); + QVERIFY2(s2.verify(signature2, m_verifyingPEM), qPrintable(s2.errorString())); + QVERIFY(!s.verify(signature2, m_verifyingPEM)); + QVERIFY(!s2.verify(signature, m_verifyingPEM)); + + QVERIFY(s.create(m_signingP12, m_signingPassword + "not").isEmpty()); + QVERIFY2(s.errorString().contains(qSL("not parse")), qPrintable(s.errorString())); + + QVERIFY(s.create(QByteArray(), m_signingPassword).isEmpty()); + QVERIFY2(s.errorString().contains(qSL("not read")), qPrintable(s.errorString())); + + Signature s3(QByteArray(4096, 'x')); + QVERIFY(!s3.create(m_signingP12, m_signingPassword).isEmpty()); + + QVERIFY(!s.verify(signature, QList())); + QVERIFY2(s.errorString().contains(qSL("Failed to verify")), qPrintable(s.errorString())); + QVERIFY(!s.verify(signature, QList() << m_signingP12)); + QVERIFY2(s.errorString().contains(qSL("not load")), qPrintable(s.errorString())); + QVERIFY(!s.verify(hash, QList() << m_signingP12)); + QVERIFY2(s.errorString().contains(qSL("not read")), qPrintable(s.errorString())); + + Signature s4 { QByteArray() }; + QVERIFY(s4.create(m_signingP12, m_signingPassword).isEmpty()); + + QVERIFY(s.create(m_signingNoKeyP12, m_signingPassword).isEmpty()); + QVERIFY2(s.errorString().contains(qSL("private key")), qPrintable(s.errorString())); +} + +void tst_Signature::crossPlatform() +{ + QByteArray hash = "hello\nworld!"; + + QFile fileOpenSsl(qSL(":/signature-openssl.p7")); + QFile fileWinCrypt(qSL(":/signature-wincrypt.p7")); + QFile fileSecurityFramework(qSL(":/signature-securityframework.p7")); + + if (qEnvironmentVariableIsSet("AM_CREATE_SIGNATURE_FILE")) { + QFile *nativeFile = nullptr; +#if defined(AM_USE_LIBCRYPTO) + nativeFile = &fileOpenSsl; +#elif defined(Q_OS_WIN) + nativeFile = &fileWinCrypt; +#elif defined(Q_OS_OSX) + nativeFile = &fileSecurityFramework; +#endif + QVERIFY(nativeFile); + QFile f(qL1S(AM_TESTDATA_DIR "/../signature") + nativeFile->fileName().mid(1)); + QVERIFY2(f.open(QFile::WriteOnly | QFile::Truncate), qPrintable(f.errorString())); + + Signature s(hash); + QByteArray signature = s.create(m_signingP12, m_signingPassword); + QVERIFY2(!signature.isEmpty(), qPrintable(s.errorString())); + QCOMPARE(f.write(signature), signature.size()); + + qInfo() << "Only creating signature file" << f.fileName() << "because $AM_CREATE_SIGNATURE_FILE is set."; + return; + } + + QVERIFY(fileOpenSsl.open(QIODevice::ReadOnly)); + QByteArray sigOpenSsl = fileOpenSsl.readAll(); + QVERIFY(!sigOpenSsl.isEmpty()); + QVERIFY(fileWinCrypt.open(QIODevice::ReadOnly)); + QByteArray sigWinCrypt = fileWinCrypt.readAll(); + QVERIFY(!sigWinCrypt.isEmpty()); + QVERIFY(fileSecurityFramework.open(QIODevice::ReadOnly)); + QByteArray sigSecurityFramework = fileSecurityFramework.readAll(); + QVERIFY(!sigSecurityFramework.isEmpty()); + + Signature s(hash); + QVERIFY2(s.verify(sigOpenSsl, m_verifyingPEM), qPrintable(s.errorString())); + QVERIFY2(s.verify(sigWinCrypt, m_verifyingPEM), qPrintable(s.errorString())); + QVERIFY2(s.verify(sigSecurityFramework, m_verifyingPEM), qPrintable(s.errorString())); +} + +QTEST_APPLESS_MAIN(tst_Signature) + +#include "tst_signature.moc" + diff --git a/tests/auto/signature/tst_signature.qrc b/tests/auto/signature/tst_signature.qrc new file mode 100644 index 00000000..f063bca7 --- /dev/null +++ b/tests/auto/signature/tst_signature.qrc @@ -0,0 +1,10 @@ + + + signing.p12 + signing-no-key.p12 + verifying.crt + signature-openssl.p7 + signature-wincrypt.p7 + signature-securityframework.p7 + + diff --git a/tests/auto/signature/verifying.crt b/tests/auto/signature/verifying.crt new file mode 100644 index 00000000..de7dcc07 --- /dev/null +++ b/tests/auto/signature/verifying.crt @@ -0,0 +1,105 @@ +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIJAOGN7P3anRxmMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV +BAYTAkRFMRYwFAYDVQQKDA1QZWxhZ2ljb3JlIEFHMRIwEAYDVQQLDAlBcHAgU3Rv +cmUxIDAeBgNVBAMMF1BlbGFnaWNvcmUgQXBwIFN0b3JlIENBMSIwIAYJKoZIhvcN +AQkBFhNpbmZvQHBlbGFnaWNvcmUuY29tMB4XDTE1MDMxMTAxMTk0NloXDTI1MDMw +ODAxMTk0NlowfzELMAkGA1UEBhMCREUxFjAUBgNVBAoMDVBlbGFnaWNvcmUgQUcx +EjAQBgNVBAsMCUFwcCBTdG9yZTEgMB4GA1UEAwwXUGVsYWdpY29yZSBBcHAgU3Rv +cmUgQ0ExIjAgBgkqhkiG9w0BCQEWE2luZm9AcGVsYWdpY29yZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkAz3WPxmzXt53bDimMy3ieAVXYtV1 +tJTzBBpAv7emrsa1JxOp/NsaTt18cXCrpNnBiGnlcdFtkULj53U8BRwd2CNmraRG +QR09uq0H98vF1NwPQ4vFZ3NEOdofjtAgDipqcAHSH+T0lxj2xvWLP44fo7UvmG4Q +CUAA7JhIwjFDJugZ3JFcTQl9eCt2CfvysvHC4sBmZTRAk+sL/oBZvasS4NAgqSRX +WCZKXIoSdgir1BAvB/u/mF/RT+zkP4ntoeBSB/yjqWOmghA6nbCQk33nGT4cBMD5 +0QPliXioSqjIrIhIrKzqtW5yqOcUhKc9g8oWKSekMg25hcq6XF08uS7ZAgMBAAGj +YDBeMB0GA1UdDgQWBBT0CdSIj6UvzW6R6tFaBeOL6yijwTAfBgNVHSMEGDAWgBT0 +CdSIj6UvzW6R6tFaBeOL6yijwTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAQEAYXr+Eans7BbTMRvf0iZdCdTAneNCrF5oz7V0 +xwWqJBzL1rwhvHbruKvF7I0bSoURmSVd+P9Ge0rYvW+HXuLlgmwAfl9n4zWsHohs +zDFSPQIfb97TP5HE21DrCGCauQirUGaA91inGDmGW80RWbzL1gogWZYpP7IOwu5G +nr+3AgxqZVOS8H0Ppf8aMqtiuamR63SCE5OoHJCNeQ6OmoFrnW8vF9eMScoc1Txb +F4uMqSPny6kgmarwfGnurhM2NOn8OpELEU9mwd7XpzpHpvYVm76tZpd5gMhYFsjp +lyDFPVFQ5pVv5Cc7xhxzYrcn7JQt/GYhYuChM0us5a5urV/l+g== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=DE, O=Pelagicore AG, OU=App Store, CN=Pelagicore App Store CA/emailAddress=info@pelagicore.com + Validity + Not Before: Mar 11 01:19:46 2015 GMT + Not After : Mar 8 01:19:46 2025 GMT + Subject: C=DE, O=Pelagicore AG, OU=Developer Relations, CN=Pelagicore Developer CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d7:88:7d:35:92:04:9c:58:b1:c9:7e:e0:eb:09: + 10:78:6f:cb:78:f6:1b:38:5a:54:8b:5e:b5:b2:92: + 45:9c:b7:6c:01:0f:b2:16:66:66:24:0a:ed:37:83: + ad:79:27:b0:e8:ff:49:db:68:f6:26:b5:61:d9:7b: + ea:46:7a:e2:55:df:fc:cc:af:2e:45:ce:f7:59:52: + 19:9c:6c:39:d6:5c:68:9e:73:45:71:ac:b2:1d:e6: + 98:0e:7f:18:06:cd:09:49:c7:d6:b6:5c:e1:e9:4f: + 6b:80:ac:4a:c7:36:21:c7:2a:e8:bc:ae:87:f2:49: + 05:62:f9:01:24:c0:93:5b:85:1a:bb:d1:81:19:aa: + 31:09:cd:5b:e2:5a:61:76:4d:50:8d:45:60:70:ca: + 64:64:bc:1f:25:bf:64:2e:65:16:95:1c:ee:29:bb: + a7:31:ec:20:39:81:eb:48:df:93:ca:48:6c:be:9e: + df:5e:05:8a:db:8e:c4:07:cc:fc:c8:08:16:1e:e3: + 04:51:d9:0b:6f:28:1a:e4:38:93:05:00:59:49:60: + 81:12:bc:48:f9:81:08:ff:fb:59:95:ad:f3:54:85: + 1b:70:5f:cf:eb:0f:ea:45:20:39:b0:74:55:0c:94: + d7:3f:88:85:b8:71:ac:b0:e7:99:70:cc:f5:c2:89: + 6b:af + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 8B:2D:DE:5A:18:A5:71:A9:73:03:54:69:56:87:A0:17:BF:C2:73:4E + X509v3 Authority Key Identifier: + keyid:F4:09:D4:88:8F:A5:2F:CD:6E:91:EA:D1:5A:05:E3:8B:EB:28:A3:C1 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 3a:5f:21:dc:b5:f8:a7:e5:23:89:fa:53:e2:cd:b7:e1:51:53: + d6:0d:e7:78:f7:3c:cc:85:b3:83:be:76:c8:3e:0d:e2:ab:ca: + ca:aa:41:c9:23:cc:d6:8c:53:71:72:70:43:04:48:85:28:54: + ab:b0:2a:e2:08:89:22:d5:ce:0b:79:e5:3d:61:42:db:4a:70: + c4:64:21:48:07:c4:a9:33:e4:0a:c9:a0:d6:0d:73:ef:d0:80: + d8:8c:59:c4:51:fa:5a:54:79:94:0f:ca:ff:28:0a:7e:b9:99: + 2d:8e:ca:5d:d8:4c:8f:fe:6f:e6:fd:ea:17:7f:90:f7:b1:76: + de:7f:14:82:20:c3:23:0f:ca:b5:1c:2c:34:b9:de:9f:ce:06: + 04:14:ff:6c:0b:67:ab:7c:b3:5a:51:dc:0c:66:37:56:bf:a7: + ab:12:33:03:98:c3:40:e2:4d:8d:ad:3f:19:18:41:cc:e3:ec: + 6d:5f:9e:90:df:d9:84:5b:ad:60:93:dc:24:1a:42:ce:8b:15: + 8f:42:21:f9:35:68:a6:cc:f7:4e:8d:c2:6b:b9:e6:20:30:d1: + c6:1d:86:f8:33:3b:40:cc:9f:4c:2d:5d:0a:ca:66:1c:8d:bc: + 87:3b:0b:39:e4:17:73:34:35:85:ba:22:31:a2:8b:d0:65:54: + cc:c2:c6:32 +-----BEGIN CERTIFICATE----- +MIIDvzCCAqegAwIBAgIBAjANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJERTEW +MBQGA1UECgwNUGVsYWdpY29yZSBBRzESMBAGA1UECwwJQXBwIFN0b3JlMSAwHgYD +VQQDDBdQZWxhZ2ljb3JlIEFwcCBTdG9yZSBDQTEiMCAGCSqGSIb3DQEJARYTaW5m +b0BwZWxhZ2ljb3JlLmNvbTAeFw0xNTAzMTEwMTE5NDZaFw0yNTAzMDgwMTE5NDZa +MGUxCzAJBgNVBAYTAkRFMRYwFAYDVQQKDA1QZWxhZ2ljb3JlIEFHMRwwGgYDVQQL +DBNEZXZlbG9wZXIgUmVsYXRpb25zMSAwHgYDVQQDDBdQZWxhZ2ljb3JlIERldmVs +b3BlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANeIfTWSBJxY +scl+4OsJEHhvy3j2GzhaVItetbKSRZy3bAEPshZmZiQK7TeDrXknsOj/Sdto9ia1 +Ydl76kZ64lXf/MyvLkXO91lSGZxsOdZcaJ5zRXGssh3mmA5/GAbNCUnH1rZc4elP +a4CsSsc2Iccq6Lyuh/JJBWL5ASTAk1uFGrvRgRmqMQnNW+JaYXZNUI1FYHDKZGS8 +HyW/ZC5lFpUc7im7pzHsIDmB60jfk8pIbL6e314FituOxAfM/MgIFh7jBFHZC28o +GuQ4kwUAWUlggRK8SPmBCP/7WZWt81SFG3Bfz+sP6kUgObB0VQyU1z+IhbhxrLDn +mXDM9cKJa68CAwEAAaNgMF4wHQYDVR0OBBYEFIst3loYpXGpcwNUaVaHoBe/wnNO +MB8GA1UdIwQYMBaAFPQJ1IiPpS/NbpHq0VoF44vrKKPBMA8GA1UdEwEB/wQFMAMB +Af8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQA6XyHctfin5SOJ+lPi +zbfhUVPWDed49zzMhbODvnbIPg3iq8rKqkHJI8zWjFNxcnBDBEiFKFSrsCriCIki +1c4LeeU9YULbSnDEZCFIB8SpM+QKyaDWDXPv0IDYjFnEUfpaVHmUD8r/KAp+uZkt +jspd2EyP/m/m/eoXf5D3sXbefxSCIMMjD8q1HCw0ud6fzgYEFP9sC2erfLNaUdwM +ZjdWv6erEjMDmMNA4k2NrT8ZGEHM4+xtX56Q39mEW61gk9wkGkLOixWPQiH5NWim +zPdOjcJrueYgMNHGHYb4MztAzJ9MLV0KymYcjbyHOws55BdzNDWFuiIxoovQZVTM +wsYy +-----END CERTIFICATE----- diff --git a/tests/auto/sudo/CMakeLists.txt b/tests/auto/sudo/CMakeLists.txt new file mode 100644 index 00000000..5f64939c --- /dev/null +++ b/tests/auto/sudo/CMakeLists.txt @@ -0,0 +1,23 @@ + +qt_internal_add_test(tst_sudo + SOURCES + ../error-checking.h + tst_sudo.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate +) + +#### Keys ignored in scope 1:.:.:sudo.pro:: +# COVERAGE_RUNTIME = "sudo" + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_sudo CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/sudo/sudo.pro b/tests/auto/sudo/sudo.pro new file mode 100644 index 00000000..95be319b --- /dev/null +++ b/tests/auto/sudo/sudo.pro @@ -0,0 +1,11 @@ +TARGET = tst_sudo + +COVERAGE_RUNTIME = sudo + +include($$PWD/../tests.pri) + +QT *= \ + appman_common-private \ + appman_manager-private \ + +SOURCES += tst_sudo.cpp diff --git a/tests/auto/sudo/tst_sudo.cpp b/tests/auto/sudo/tst_sudo.cpp new file mode 100644 index 00000000..c6472152 --- /dev/null +++ b/tests/auto/sudo/tst_sudo.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#if !defined(Q_OS_LINUX) +# error "This test is Linux specific!" +#endif + +#include "utilities.h" +#include "sudo.h" + +QT_USE_NAMESPACE_AM + +static int processTimeout = 3000; + +static bool startedSudoServer = false; +static QString sudoServerError; + +// sudo RAII style +class ScopedRootPrivileges +{ +public: + ScopedRootPrivileges() + { + m_uid = getuid(); + m_gid = getgid(); + if (setresuid(0, 0, 0) || setresgid(0, 0, 0)) + QFAIL("cannot re-gain root privileges"); + } + ~ScopedRootPrivileges() + { + if (setresgid(m_gid, m_gid, 0) || setresuid(m_uid, m_uid, 0)) + QFAIL("cannot drop root privileges"); + } +private: + uid_t m_uid; + gid_t m_gid; +}; + + +class tst_Sudo : public QObject +{ + Q_OBJECT + +public: + tst_Sudo(QObject *parent = nullptr); + ~tst_Sudo(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void privileges(); + +private: + SudoClient *m_sudo = nullptr; +}; + +tst_Sudo::tst_Sudo(QObject *parent) + : QObject(parent) +{ } + +tst_Sudo::~tst_Sudo() +{ } + +void tst_Sudo::initTestCase() +{ + processTimeout *= timeoutFactor(); + + QVERIFY2(startedSudoServer, qPrintable(sudoServerError)); + m_sudo = SudoClient::instance(); + QVERIFY(m_sudo); + if (m_sudo->isFallbackImplementation()) + QSKIP("Not running with root privileges - neither directly, or SUID-root, or sudo"); +} + +void tst_Sudo::privileges() +{ + ScopedRootPrivileges sudo; +} + +void tst_Sudo::cleanupTestCase() +{ + // the real cleanup happens in ~tst_Installer, since we also need + // to call this cleanup from the crash handler +} + +static tst_Sudo *tstSudo = nullptr; + +int main(int argc, char **argv) +{ + try { + Sudo::forkServer(Sudo::DropPrivilegesRegainable); + startedSudoServer = true; + } catch (...) { } + + QCoreApplication a(argc, argv); + tstSudo = new tst_Sudo(&a); + +#ifdef Q_OS_LINUX + auto crashHandler = [](int sigNum) -> void { + // we are doing very unsafe things from a within a signal handler, but + // we've crashed anyway at this point and the alternative is that we are + // leaking mounts and attached loopback devices. + + tstSudo->~tst_Sudo(); + + if (sigNum != -1) + exit(1); + }; + + signal(SIGABRT, crashHandler); + signal(SIGSEGV, crashHandler); + signal(SIGINT, crashHandler); +#endif // Q_OS_LINUX + + return QTest::qExec(tstSudo, argc, argv); +} + +#include "tst_sudo.moc" diff --git a/tests/auto/systemreader/CMakeLists.txt b/tests/auto/systemreader/CMakeLists.txt new file mode 100644 index 00000000..ca78937f --- /dev/null +++ b/tests/auto/systemreader/CMakeLists.txt @@ -0,0 +1,23 @@ + +qt_internal_add_test(tst_systemreader + SOURCES + ../error-checking.h + tst_systemreader.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManApplicationPrivate + Qt::AppManCommonPrivate + Qt::AppManManagerPrivate + Qt::AppManMonitorPrivate + Qt::AppManWindowPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_systemreader CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/systemreader/root/proc/1234/cgroup b/tests/auto/systemreader/root/proc/1234/cgroup new file mode 100644 index 00000000..cd5fc256 --- /dev/null +++ b/tests/auto/systemreader/root/proc/1234/cgroup @@ -0,0 +1,13 @@ +12:devices:/system.slice/run-u5853.scope +11:freezer:/ +10:memory:/system.slice/run-u5853.scope +9:net_cls,net_prio:/ +8:cpuset:/ +7:rdma:/ +6:blkio:/ +5:hugetlb:/ +4:cpu,cpuacct:/ +3:perf_event:/ +2:pids:/system.slice/run-u5853.scope +1:name=systemd:/system.slice/run-u5853.scope +0::/system.slice/run-u5853.scope diff --git a/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes b/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes new file mode 100644 index 00000000..469ca93f --- /dev/null +++ b/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes @@ -0,0 +1 @@ +524288000 diff --git a/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat b/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat new file mode 100644 index 00000000..e5fe0114 --- /dev/null +++ b/tests/auto/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat @@ -0,0 +1,33 @@ +cache 10346496 +rss 66809856 +rss_huge 0 +shmem 10067968 +mapped_file 7139328 +dirty 0 +writeback 0 +pgpgin 20165 +pgpgout 1328 +pgfault 23446 +pgmajfault 2 +inactive_anon 10047488 +active_anon 66793472 +inactive_file 278528 +active_file 0 +unevictable 0 +hierarchical_memory_limit 524288000 +total_cache 10346496 +total_rss 66809856 +total_rss_huge 0 +total_shmem 10067968 +total_mapped_file 7139328 +total_dirty 0 +total_writeback 0 +total_pgpgin 20165 +total_pgpgout 1328 +total_pgfault 23446 +total_pgmajfault 2 +total_inactive_anon 10047488 +total_active_anon 66793472 +total_inactive_file 278528 +total_active_file 0 +total_unevictable 0 diff --git a/tests/auto/systemreader/systemreader.pro b/tests/auto/systemreader/systemreader.pro new file mode 100644 index 00000000..5955d5f1 --- /dev/null +++ b/tests/auto/systemreader/systemreader.pro @@ -0,0 +1,11 @@ +TARGET = tst_systemreader + +include($$PWD/../tests.pri) + +QT *= appman_monitor-private \ + appman_manager-private \ + appman_window-private \ + appman_application-private \ + appman_common-private + +SOURCES += tst_systemreader.cpp diff --git a/tests/auto/systemreader/tst_systemreader.cpp b/tests/auto/systemreader/tst_systemreader.cpp new file mode 100644 index 00000000..6f83409a --- /dev/null +++ b/tests/auto/systemreader/tst_systemreader.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "systemreader.h" + +QT_USE_NAMESPACE_AM + +class tst_SystemReader : public QObject +{ + Q_OBJECT + +public: + tst_SystemReader(); + +private slots: + void cgroupProcessInfo(); + void memoryReaderReadUsedValue(); + void memoryReaderGroupLimit(); +}; + +tst_SystemReader::tst_SystemReader() +{ + g_systemRootDir = qL1S(AM_TESTDATA_DIR "/root"); +} + +void tst_SystemReader::cgroupProcessInfo() +{ + auto map = fetchCGroupProcessInfo(1234); + QCOMPARE(map["memory"], QByteArray("/system.slice/run-u5853.scope")); +} + +void tst_SystemReader::memoryReaderReadUsedValue() +{ + MemoryReader memoryReader(qSL("/system.slice/run-u5853.scope")); + quint64 value = memoryReader.readUsedValue(); + QCOMPARE(value, Q_UINT64_C(66809856)); +} + +void tst_SystemReader::memoryReaderGroupLimit() +{ + MemoryReader memoryReader(qSL("/system.slice/run-u5853.scope")); + quint64 value = memoryReader.groupLimit(); + QCOMPARE(value, Q_UINT64_C(524288000)); +} + +QTEST_APPLESS_MAIN(tst_SystemReader) + +#include "tst_systemreader.moc" diff --git a/tests/auto/tests.pri b/tests/auto/tests.pri new file mode 100644 index 00000000..64ec6309 --- /dev/null +++ b/tests/auto/tests.pri @@ -0,0 +1,11 @@ +load(am-config) + +CONFIG *= console testcase +QT = core network testlib +qtHaveModule(dbus):QT *= dbus + +DEFINES *= AM_TESTDATA_DIR=\\\"$$PWD/data/\\\" +DEFINES -= QT_NO_CAST_FROM_ASCII + +HEADERS += \ + $$PWD/error-checking.h \ diff --git a/tests/auto/tests.pro b/tests/auto/tests.pro new file mode 100644 index 00000000..3bfd9083 --- /dev/null +++ b/tests/auto/tests.pro @@ -0,0 +1,56 @@ +TEMPLATE = subdirs + +load(am-config) +requires(!disable-installer) + +SUBDIRS = \ + manual \ + application \ + applicationinfo \ + main \ + runtime \ + cryptography \ + signature \ + utilities \ + installationreport \ + packagecreator \ + packageextractor \ + packager-tool \ + applicationinstaller \ + debugwrapper \ + qml \ + yaml \ + configuration \ + +linux*:SUBDIRS += \ + sudo \ + processreader \ + systemreader \ + +OTHER_FILES += \ + tests.pri \ + data/create-test-packages.sh \ + data/certificates/create-test-certificates.sh \ + data/utilities.sh \ + +# sadly, the appman-packager is too complex to build as a host tool +!cross_compile { + prepareRecursiveTarget(check) + qtPrepareTool(APPMAN_PACKAGER, appman-packager) + + unix { + macos:ctype=UTF-8 + else:ctype=C.UTF-8 + + # create test data on the fly - this is needed for the CI server + testdata.target = testdata + testdata.depends = $$PWD/data/create-test-packages.sh $$APPMAN_PACKAGER_EXE + testdata.commands = (cd $$PWD/data ; LC_CTYPE=$$ctype ./create-test-packages.sh $$APPMAN_PACKAGER) + QMAKE_EXTRA_TARGETS += testdata + + # qmake would create a default check target implicitly, but since we need 'testdata' as an + # dependency, we have to set it up explicitly + check.depends = testdata $$check.depends + } + QMAKE_EXTRA_TARGETS *= check +} diff --git a/tests/auto/utilities/CMakeLists.txt b/tests/auto/utilities/CMakeLists.txt new file mode 100644 index 00000000..7e533078 --- /dev/null +++ b/tests/auto/utilities/CMakeLists.txt @@ -0,0 +1,19 @@ + +qt_internal_add_test(tst_utilities + SOURCES + ../error-checking.h + tst_utilities.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_utilities CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/utilities/tst_utilities.cpp b/tests/auto/utilities/tst_utilities.cpp new file mode 100644 index 00000000..94487932 --- /dev/null +++ b/tests/auto/utilities/tst_utilities.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "utilities.h" + +QT_USE_NAMESPACE_AM + +class tst_Utilities : public QObject +{ + Q_OBJECT + +public: + tst_Utilities(); + +private slots: +}; + + +tst_Utilities::tst_Utilities() +{ } + +QTEST_APPLESS_MAIN(tst_Utilities) + +#include "tst_utilities.moc" diff --git a/tests/auto/utilities/utilities.pro b/tests/auto/utilities/utilities.pro new file mode 100644 index 00000000..9a7c2bc0 --- /dev/null +++ b/tests/auto/utilities/utilities.pro @@ -0,0 +1,7 @@ +TARGET = tst_utilities + +include($$PWD/../tests.pri) + +QT *= appman_common-private + +SOURCES += tst_utilities.cpp diff --git a/tests/auto/yaml/CMakeLists.txt b/tests/auto/yaml/CMakeLists.txt new file mode 100644 index 00000000..74d63318 --- /dev/null +++ b/tests/auto/yaml/CMakeLists.txt @@ -0,0 +1,34 @@ + +qt_internal_add_test(tst_yaml + SOURCES + ../error-checking.h + tst_yaml.cpp + DEFINES + AM_TESTDATA_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\\\" + PUBLIC_LIBRARIES + Qt::Network + Qt::AppManCommonPrivate +) + +# Resources: +set(qmake_immediate_resource_files + "data/cache1.yaml" + "data/cache2.yaml" + "data/test.yaml" +) + +qt_internal_add_resource(tst_yaml "qmake_immediate" + PREFIX + "/" + FILES + ${qmake_immediate_resource_files} +) + + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_yaml CONDITION TARGET Qt::DBus + PUBLIC_LIBRARIES + Qt::DBus +) diff --git a/tests/auto/yaml/data/cache1.yaml b/tests/auto/yaml/data/cache1.yaml new file mode 100644 index 00000000..b3fcddb9 --- /dev/null +++ b/tests/auto/yaml/data/cache1.yaml @@ -0,0 +1,13 @@ +name: cache1 +file: ${FILE} + +## content for a merge test +#bool: true +#list: [ 1, 2 ] +#map: +# key1: value1 +# key2: value2 +# key3: +# key31: value31 +# key32: value32 +# key4: 4 diff --git a/tests/auto/yaml/data/cache2.yaml b/tests/auto/yaml/data/cache2.yaml new file mode 100644 index 00000000..8ce7bae3 --- /dev/null +++ b/tests/auto/yaml/data/cache2.yaml @@ -0,0 +1,14 @@ +name: cache2 +file: ${FILE} + +## content for a merge test +#bool: false +#list: [ 3, 4, 5 ] +#map: +# key1: value1 +# key2: not-value2 +# key3: +# key31: [ 5, 6 ] +# key32: not-value32 +# key33: true +# key5: 5 diff --git a/tests/auto/yaml/data/test.yaml b/tests/auto/yaml/data/test.yaml new file mode 100644 index 00000000..b16e3d39 --- /dev/null +++ b/tests/auto/yaml/data/test.yaml @@ -0,0 +1,45 @@ +formatVersion: 42 +formatType: testfile +--- +dec: 10 +hex: 0x10 +oct: 010 +bin: 0b10 +float1: 10.10 +float2: 0.10 +float3: .10 +number-separators: 1_234_567 +bool-true: true +bool-yes: yes +bool-false: false +bool-no: no +null-literal: null +null-tilde: ~ +string-unquoted: unquoted +string-singlequoted: 'singlequoted' +string-doublequoted: "doublequoted" +list-int: +- 1 +- 2 +- 3 +list-mixed: +- 1 +- two +- [yes, ~] +map1: + a: 1 + b: two + c: [ 1, 2, 3] + +extended: + ext-string: 'ext string' + +stringlist-string: string +stringlist-list1: [ string ] +stringlist-list2: [ string1, string2 ] + +list-of-maps: +- index: 1 + name: '1' +- index: 2 + name: '2' diff --git a/tests/auto/yaml/tst_yaml.cpp b/tests/auto/yaml/tst_yaml.cpp new file mode 100644 index 00000000..b07b5274 --- /dev/null +++ b/tests/auto/yaml/tst_yaml.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "qtyaml.h" +#include "configcache.h" +#include "exception.h" +#include "global.h" + +QT_USE_NAMESPACE_AM + +class tst_Yaml : public QObject +{ + Q_OBJECT + +public: + tst_Yaml(); + +private slots: + void parser(); + void documentParser(); + void cache(); + void mergedCache(); + void parallel(); +}; + + +tst_Yaml::tst_Yaml() +{ } + +void tst_Yaml::parser() +{ + static const QVariant vnull = QVariant::fromValue(nullptr); + + QVector> tests = { + { "dec", QVariant::fromValue(10) }, + { "hex", QVariant::fromValue(16) }, + { "bin", QVariant::fromValue(2) }, + { "oct", QVariant::fromValue(8) }, + { "float1", QVariant::fromValue(10.1) }, + { "float2", QVariant::fromValue(.1) }, + { "float3", QVariant::fromValue(.1) }, + { "number-separators", QVariant::fromValue(1234567) }, + { "bool-true", true }, + { "bool-yes", true }, + { "bool-false", false }, + { "bool-no", false }, + { "null-literal", vnull }, + { "null-tilde", vnull }, + { "string-unquoted", QVariant::fromValue("unquoted") }, + { "string-singlequoted", QVariant::fromValue("singlequoted") }, + { "string-doublequoted", QVariant::fromValue("doublequoted") }, + { "list-int", QVariantList { 1, 2, 3 } }, + { "list-mixed", QVariantList { 1, "two", QVariantList { true, vnull } } }, + { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } } + }; + + try { + QFile f(":/data/test.yaml"); + QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); + QByteArray ba = f.readAll(); + QVERIFY(!ba.isEmpty()); + YamlParser p(ba); + auto header = p.parseHeader(); + + QCOMPARE(header.first, "testfile"); + QCOMPARE(header.second, 42); + + QVERIFY(p.nextDocument()); + + YamlParser::Fields fields; + for (const auto &pair : tests) { + YamlParser::FieldType type = YamlParser::Scalar; + if (pair.second.metaType() == QMetaType::fromType()) + type = YamlParser::List; + else if (pair.second.metaType() == QMetaType::fromType()) + type = YamlParser::Map; + QVariant value = pair.second; + + fields.emplace_back(pair.first, true, type, [type, value](YamlParser *p) { + switch (type) { + case YamlParser::Scalar: { + QVERIFY(p->isScalar()); + QVariant v = p->parseScalar(); + QCOMPARE(int(v.metaType().id()), value.metaType().id()); + QVERIFY(v == value); + break; + } + case YamlParser::List: { + QVERIFY(p->isList()); + QVariantList vl = p->parseList(); + QVERIFY(vl == value.toList()); + break; + } + case YamlParser::Map: { + QVERIFY(p->isMap()); + QVariantMap vm = p->parseMap(); + QVERIFY(vm == value.toMap()); + break; + } + } + }); + } + fields.emplace_back("extended", true, YamlParser::Map, [](YamlParser *p) { + YamlParser::Fields extFields = { + { "ext-string", true, YamlParser::Scalar, [](YamlParser *p) { + QVERIFY(p->isScalar()); + QVariant v = p->parseScalar(); + QCOMPARE(v.metaType(), QMetaType::fromType()); + QCOMPARE(v.toString(), "ext string"); + } } + }; + p->parseFields(extFields); + }); + + fields.emplace_back("stringlist-string", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { + QCOMPARE(p->parseStringOrStringList(), QStringList { "string" }); + }); + fields.emplace_back("stringlist-list1", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { + QCOMPARE(p->parseStringOrStringList(), QStringList { "string" }); + }); + fields.emplace_back("stringlist-list2", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { + QCOMPARE(p->parseStringOrStringList(), QStringList({ "string1", "string2" })); + }); + + fields.emplace_back("list-of-maps", true, YamlParser::List, [](YamlParser *p) { + int index = 0; + p->parseList([&index](YamlParser *p) { + ++index; + YamlParser::Fields lomFields = { + { "index", true, YamlParser::Scalar, [&index](YamlParser *p) { + QCOMPARE(p->parseScalar().toInt(), index); + } }, + { "name", true, YamlParser::Scalar, [&index](YamlParser *p) { + QCOMPARE(p->parseScalar().toString(), QString::number(index)); + } } + }; + p->parseFields(lomFields); + }); + QCOMPARE(index, 2); + }); + + p.parseFields(fields); + + QVERIFY(!p.nextDocument()); + + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } +} + +static const QVariant vnull = QVariant::fromValue(nullptr); + +static const QVariantMap testHeaderDoc = { + { "formatVersion", 42 }, { "formatType", "testfile" } +}; + +static const QVariantMap testMainDoc = { + { "dec", 10 }, + { "hex", 16 }, + { "bin", 2 }, + { "oct", 8 }, + { "float1", 10.1 }, + { "float2", .1 }, + { "float3", .1 }, + { "number-separators", 1234567 }, + { "bool-true", true }, + { "bool-yes", true }, + { "bool-false", false }, + { "bool-no", false }, + { "null-literal", vnull }, + { "null-tilde", vnull }, + { "string-unquoted", "unquoted" }, + { "string-singlequoted", "singlequoted" }, + { "string-doublequoted", "doublequoted" }, + { "list-int", QVariantList { 1, 2, 3 } }, + { "list-mixed", QVariantList { 1, qSL("two"), QVariantList { true, vnull } } }, + { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } }, + + + { "extended", QVariantMap { { "ext-string", "ext string" } } }, + + { "stringlist-string", "string" }, + { "stringlist-list1", QVariantList { "string" } }, + { "stringlist-list2", QVariantList { "string1", "string2" } }, + + { "list-of-maps", QVariantList { QVariantMap { { "index", 1 }, { "name", "1" } }, + QVariantMap { { "index", 2 }, { "name", "2" } } } } +}; + +void tst_Yaml::documentParser() +{ + try { + QFile f(":/data/test.yaml"); + QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); + QByteArray ba = f.readAll(); + QVERIFY(!ba.isEmpty()); + QVector docs = YamlParser::parseAllDocuments(ba); + QCOMPARE(docs.size(), 2); + QCOMPARE(docs.at(0).toMap().size(), 2); + + QCOMPARE(testHeaderDoc, docs.at(0).toMap()); + QCOMPARE(testMainDoc, docs.at(1).toMap()); + + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } +} +struct CacheTest +{ + QString name; + QString file; +}; + +// GCC < 7 bug, currently still in RHEL7, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +// this should simply be: +// template<> class QT_PREPEND_NAMESPACE_AM(ConfigCacheAdaptor) + +QT_BEGIN_NAMESPACE_AM +template<> class ConfigCacheAdaptor +{ +public: + CacheTest *loadFromSource(QIODevice *source, const QString &fileName) + { + std::unique_ptr ct(new CacheTest); + YamlParser p(source->readAll(), fileName); + p.nextDocument(); + p.parseFields({ { "name", true, YamlParser::Scalar, [&ct](YamlParser *p) { + ct->name = p->parseScalar().toString(); } }, + { "file", true, YamlParser::Scalar, [&ct](YamlParser *p) { + ct->file = p->parseScalar().toString(); } } + }); + return ct.release(); + } + CacheTest *loadFromCache(QDataStream &ds) + { + CacheTest *ct = new CacheTest; + ds >> ct->name >> ct->file; + return ct; + } + void saveToCache(QDataStream &ds, const CacheTest *ct) + { + ds << ct->name << ct->file; + } + + void merge(CacheTest *ct1, const CacheTest *ct2) + { + ct1->name = ct2->name; + ct1->file = ct1->file + qSL(",") + ct2->file; + } + void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName) + { + sourceContent.replace("${FILE}", fileName.toUtf8()); + } +}; +QT_END_NAMESPACE_AM + +void tst_Yaml::cache() +{ + QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" }; + + for (int step = 0; step < 2; ++step) { + try { + ConfigCache cache(files, "cache-test", "CTST", 1, + step == 0 ? AbstractConfigCache::ClearCache + : AbstractConfigCache::None); + cache.parse(); + QVERIFY(cache.parseReadFromCache() == (step == 1)); + QVERIFY(cache.parseWroteToCache() == (step == 0)); + CacheTest *ct1 = cache.takeResult(0); + QVERIFY(ct1); + QCOMPARE(ct1->name, "cache1"); + QCOMPARE(ct1->file, ":/data/cache1.yaml"); + CacheTest *ct2 = cache.takeResult(1); + QVERIFY(ct2); + QCOMPARE(ct2->name, "cache2"); + QCOMPARE(ct2->file, ":/data/cache2.yaml"); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } + } + + ConfigCache wrongVersion(files, "cache-test", "CTST", 2, AbstractConfigCache::None); + QTest::ignoreMessage(QtWarningMsg, "Failed to read cache: failed to parse cache header"); + wrongVersion.parse(); + QVERIFY(!wrongVersion.parseReadFromCache()); + + ConfigCache wrongType(files, "cache-test", "XTST", 1, AbstractConfigCache::None); + QTest::ignoreMessage(QtWarningMsg, "Failed to read cache: failed to parse cache header"); + wrongType.parse(); + QVERIFY(!wrongType.parseReadFromCache()); +} + +void tst_Yaml::mergedCache() +{ + QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" }; + + for (int step = 0; step < 4; ++step) { + AbstractConfigCache::Options options = AbstractConfigCache::MergedResult; + if (step % 2 == 0) + options |= AbstractConfigCache::ClearCache; + if (step == 2) + std::reverse(files.begin(), files.end()); + + try { + ConfigCache cache(files, "cache-test", "MTST", 1, options); + cache.parse(); + QVERIFY(cache.parseReadFromCache() == (step % 2 == 1)); + QVERIFY(cache.parseWroteToCache() == (step % 2 == 0)); + CacheTest *ct = cache.takeMergedResult(); + QVERIFY(ct); + QCOMPARE(ct->name, QFileInfo(files.last()).baseName()); + QCOMPARE(ct->file, files.join(qSL(","))); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } + } +} + +class YamlRunnable : public QRunnable +{ +public: + YamlRunnable(const QByteArray &yaml, QAtomicInt &success, QAtomicInt &fail) + : m_yaml(yaml) + , m_success(success) + , m_fail(fail) + { } + + void run() override + { + QVector docs; + try { + docs = YamlParser::parseAllDocuments(m_yaml); + } catch (...) { + docs.clear(); + } + if ((docs.size() == 2) + && (docs.at(0).toMap().size() == 2) + && (testHeaderDoc == docs.at(0).toMap()) + && (testMainDoc == docs.at(1).toMap())) { + m_success.fetchAndAddOrdered(1); + } else { + m_fail.fetchAndAddOrdered(1); + } + } +private: + const QByteArray m_yaml; + QAtomicInt &m_success; + QAtomicInt &m_fail; +}; + +void tst_Yaml::parallel() +{ + QFile f(":/data/test.yaml"); + QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); + QByteArray ba = f.readAll(); + QVERIFY(!ba.isEmpty()); + + constexpr int threadCount = 16; + + QAtomicInt success; + QAtomicInt fail; + + QThreadPool tp; + if (tp.maxThreadCount() < threadCount) + tp.setMaxThreadCount(threadCount); + + for (int i = 0; i < threadCount; ++i) + tp.start(new YamlRunnable(ba, success, fail)); + + QVERIFY(tp.waitForDone(5000)); + QCOMPARE(fail.loadAcquire(), 0); + QCOMPARE(success.loadAcquire(), threadCount); +} + +QTEST_MAIN(tst_Yaml) + +#include "tst_yaml.moc" diff --git a/tests/auto/yaml/yaml.pro b/tests/auto/yaml/yaml.pro new file mode 100644 index 00000000..5cc4bbb5 --- /dev/null +++ b/tests/auto/yaml/yaml.pro @@ -0,0 +1,12 @@ +TARGET = tst_yaml + +include($$PWD/../tests.pri) + +QT *= appman_common-private + +SOURCES += tst_yaml.cpp + +RESOURCES += \ + data/test.yaml \ + data/cache1.yaml \ + data/cache2.yaml \ diff --git a/tests/benchmarks/CMakeLists.txt b/tests/benchmarks/CMakeLists.txt new file mode 100644 index 00000000..1e87168e --- /dev/null +++ b/tests/benchmarks/CMakeLists.txt @@ -0,0 +1,2 @@ + +# add_subdirectory(appman-bench) diff --git a/tests/benchmarks/appman-bench/CMakeLists.txt b/tests/benchmarks/appman-bench/CMakeLists.txt new file mode 100644 index 00000000..61526436 --- /dev/null +++ b/tests/benchmarks/appman-bench/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from appman-bench.pro. + diff --git a/tests/benchmarks/appman-bench/README b/tests/benchmarks/appman-bench/README new file mode 100644 index 00000000..0af954ee --- /dev/null +++ b/tests/benchmarks/appman-bench/README @@ -0,0 +1,21 @@ +The appman-bench is a tool using a known, minimal System UI +environment to benchmark the application manager itself and +apps started by it. + +The benchmark tests the following: +* cpu load +* gpu load +* memory consumption +* fps + +The bench provides a collection of small qml test files. +These qml test files are loaded in a System UI, as well +as in every app which is started. +The System UI waits for all apps to be started and starts +measuring while keeping them running for some time. + +The bench provides a way to change what runtime is used +for testing and enables us to see differences between the +appman-launcher-qml and qmlscene binaries. +New tests can be added by writing a qml file and putting it into +the test folder. diff --git a/tests/benchmarks/appman-bench/am-config.yaml b/tests/benchmarks/appman-bench/am-config.yaml new file mode 100644 index 00000000..21d47daf --- /dev/null +++ b/tests/benchmarks/appman-bench/am-config.yaml @@ -0,0 +1,24 @@ +formatVersion: 1 +formatType: am-configuration +--- +applications: + builtinAppsManifestDir: "${CONFIG_PWD}/apps" + +runtimes: + qml: + quitTime: 2000 + +logging: + rules: + - "*=false" + - "*.critical=true" + - "am.bench*=true" + +ui: + fullscreen: no + mainQml: "${CONFIG_PWD}/system-ui/main.qml" + +# development setup: +flags: + noSecurity: yes + noUiWatchdog: yes diff --git a/tests/benchmarks/appman-bench/appman-bench.pro b/tests/benchmarks/appman-bench/appman-bench.pro new file mode 100644 index 00000000..2baae5e2 --- /dev/null +++ b/tests/benchmarks/appman-bench/appman-bench.pro @@ -0,0 +1,10 @@ +TEMPLATE = aux + +OTHER_FILES = \ + README \ + run.sh \ + am-config.yaml \ + tests/* \ + system-ui/*.qml \ + templates/appman-qml/* \ + templates/qmlscene/* \ diff --git a/tests/benchmarks/appman-bench/run.sh b/tests/benchmarks/appman-bench/run.sh new file mode 100644 index 00000000..d6a3242c --- /dev/null +++ b/tests/benchmarks/appman-bench/run.sh @@ -0,0 +1,139 @@ +#!/bin/bash +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Copyright (C) 2019 Luxoft Sweden AB +## Copyright (C) 2018 Pelagicore AG +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the QtApplicationManager module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## BSD License Usage +## Alternatively, you may use this file under the terms of the BSD license +## as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * 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. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +## OWNER 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." +## +## $QT_END_LICENSE$ +## +############################################################################# + + +SCRIPT=$(dirname $0) +usage() +{ + echo "$0 [-n ][-r ][-q ][-t ] " + echo "" + echo "This script will execute a benchmark using the appman binary provided by ." + echo "It uses templates for defining the runtime used and also templates for the test to be executed." + echo "" + echo "The following options are accepted:" + echo "-n : Defines how many applications are executed at the same time." + echo "-r : Defines which runtime template is used. Possible values are:" + echo " 'appman-qml' : Starts a normal appman qml runtime using appman-launcher-qml" + echo " 'qmlscene' : Starts a native runtime using qmlscene for interpreting the qml code" + echo "-q : Defines which Qt is used. This is required by the qmlscene runtime-template." + echo "-t : Only executes this given single test. If not provided all tests in the 'tests' folder are executed" + echo "" + exit 1 +} + + +TEMPLATE=appman-qml +APPS=4 +QT_FOLDER= +TEST= + +while getopts ":n:r:q:t:" option +do +case "${option}" +in +n) APPS=${OPTARG};; +r) TEMPLATE=${OPTARG};; +q) QT_FOLDER="${OPTARG}/bin/";; +t) TEST=${OPTARG};; +*) usage;; +esac +done + +[ "$#" -lt 1 ] && usage +APPMAN="${@: -1}" +[ ! -e "$APPMAN" ] && usage + +trap exit INT QUIT 0 +run_test() +{ + temp_folder=$(mktemp -d) + temp_app_folder="$temp_folder/apps" + mkdir -p $temp_folder + + cp -a system-ui $temp_folder/ + cp -a am-config.yaml $temp_folder/ + + mkdir -p $temp_app_folder + + for (( i=1; i<=$APPS; i++ )) + do + appid="app$i" + mkdir -p $temp_app_folder/$appid + cp -a templates/$TEMPLATE/* $temp_app_folder/$appid/ + sed -i -e "s/TEST_ID/$appid/g" $temp_app_folder/$appid/info.yaml + sed -i -e "s|QT_FOLDER/|$QT_FOLDER|g" $temp_app_folder/$appid/info.yaml + done + + echo "Running $test_qml in $temp_folder" + cp $test_qml $temp_folder/test.qml + (cd $temp_folder && $APPMAN -c am-config.yaml --clear-cache --no-dlt-logging) +} + +if [ -n "$TEST" ] +then + echo "RUNNING SINGLE TEST" + if [ ! -e "tests/$TEST" ]; then + echo "Test doesn't exist" + exit 1 + fi + test_qml="tests/$TEST" + run_test +else + echo "RUNNING ALL TESTS" + for test_qml in tests/* + do + run_test + done +fi + + diff --git a/tests/benchmarks/appman-bench/system-ui/main.qml b/tests/benchmarks/appman-bench/system-ui/main.qml new file mode 100644 index 00000000..20843986 --- /dev/null +++ b/tests/benchmarks/appman-bench/system-ui/main.qml @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Window 2.2 +import QtApplicationManager 2.0 +import QtApplicationManager.SystemUI 2.0 + +Window { + id: root + width: 1024 + height: 640 + + LoggingCategory { + id: benchCategory + name: "am.bench" + } + + Loader { + anchors.fill: parent + source: "../test.qml" + } + + Rectangle { + width: 10 + height: 10 + color: "red" + NumberAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + } + } + + Grid { + id: grid + anchors.fill: parent + + columns: Math.ceil(Math.sqrt(ApplicationManager.count)) + + Repeater { + id: windows + model: WindowManager + + Item { + property alias processMonitor: appProcessMonitor + property alias frameTimer: appFrameTimer + + width: root.width / grid.columns; + height: root.height / Math.ceil(ApplicationManager.count / grid.columns) + + WindowItem { + anchors.fill: parent + anchors.margins: 3 + anchors.topMargin: 25 + window: model.window + } + + MonitorModel { + id: appProcessMonitor + maximumCount: 100 + running: true + interval: 100 + + ProcessStatus { + applicationId: model.window.application.id + } + + FrameTimer { + id: appFrameTimer + window: model.window + } + } + } + } + } + + Connections { + target: WindowManager + function onWindowAdded(window) { + console.log("System UI: onWindowAdded: " + window); + if (WindowManager.count >= ApplicationManager.count) + statsTimer.start(); + } + } + + MonitorModel { + id: systemUiMonitor + maximumCount: 100 + running: true + interval: 100 + + ProcessStatus { + applicationId: "" + } + + FrameTimer { + id: systemFrameTimer + window: root + } + + GpuStatus {} + } + + Timer { + id: statsTimer + interval: 2000 + onTriggered: { + systemUiMonitor.running = false; + var load = avg(systemUiMonitor, systemUiMonitor.count, "cpuLoad"); + var rss = "System UI RSS Max: " + format((max(systemUiMonitor, systemUiMonitor.count, "memoryRss.total") + / 1e6).toFixed(0)) + " MB"; + var pss = "System UI PSS Max: " + format((max(systemUiMonitor, systemUiMonitor.count, "memoryPss.total") + / 1e6).toFixed(0)) + " MB"; + var fps = "System UI FPS Avg: " + format(systemFrameTimer.averageFps.toFixed(1)) + " fps"; + var cpuLoad = "System UI CPU Load Avg: " + format((load * 100).toFixed(1)) + " %"; + var gpuLoad = "System GPU Load Avg: " + format((avg(systemUiMonitor, systemUiMonitor.count, "gpuLoad") + * 100).toFixed(0)) + " %"; + + var totalAppRSS = 0; + var totalAppPSS = 0; + var totalAppFPS = 0; + var totalCPULoad = load; + for (var i = 0; i < windows.count; i++) { + var chrome = windows.itemAt(i); + chrome.processMonitor.running = false; + totalAppRSS += max(chrome.processMonitor, chrome.processMonitor.count, "memoryRss.total"); + totalAppPSS += max(chrome.processMonitor, chrome.processMonitor.count, "memoryPss.total"); + totalAppFPS += chrome.processMonitor.get(chrome.processMonitor.count - 1).averageFps ; + totalCPULoad += avg(chrome.processMonitor, chrome.processMonitor.count, "cpuLoad"); + ApplicationManager.stopApplication(ApplicationManager.application(i).id); + } + + var appRSS = "App RSS Max: " + format((totalAppRSS / ApplicationManager.count / 1e6).toFixed(0)) + " MB"; + var appPSS = "App PSS Max: " + format((totalAppPSS / ApplicationManager.count / 1e6).toFixed(0)) + " MB"; + var appFPS = "App FPS Avg: " + format((totalAppFPS / ApplicationManager.count ).toFixed(1)) + " fps"; + + var accCpuLoad = "Acc. CPU Load Avg: " + format((totalCPULoad * 100).toFixed(1)) + " %"; + + console.log(benchCategory, "System UI Resolution: " + root.width + "x" + root.height + " | App Resolution: " + + windows.itemAt(0).width + "x" + windows.itemAt(0).height); + console.log(benchCategory, cpuLoad + " | " + accCpuLoad + " | " + gpuLoad + " | " + fps + " | " + rss + + " | " + pss + " | " + appFPS + " | " + appRSS + " | " + appPSS); + Qt.quit(); + } + } + + function max(monitor, size, key) { + var value = 0; + for (var i = 0; i < size; i++) { + var val = eval("monitor.get(i)." + key); + if (val) + value = Math.max(val, value); + } + return value; + } + + function avg(monitor, size, key) { + var sum = 0; + for (var i = 0; i < size; i++) { + var val = eval("monitor.get(i)." + key) + if (val == undefined) + break; + sum += val; + } + return sum / size; + } + + function format(n) { + return String(" " + n).slice(-6); + } + + Connections { + target: ApplicationManager + function onWindowManagerCompositorReadyChanged() { + for (var i = 0; i < ApplicationManager.count; i++) + ApplicationManager.application(i).start(); + } + } +} diff --git a/tests/benchmarks/appman-bench/templates/appman-qml/icon.png b/tests/benchmarks/appman-bench/templates/appman-qml/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/benchmarks/appman-bench/templates/appman-qml/icon.png differ diff --git a/tests/benchmarks/appman-bench/templates/appman-qml/info.yaml b/tests/benchmarks/appman-bench/templates/appman-qml/info.yaml new file mode 100644 index 00000000..6d82c3d0 --- /dev/null +++ b/tests/benchmarks/appman-bench/templates/appman-qml/info.yaml @@ -0,0 +1,9 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'TEST_ID' +icon: 'icon.png' +code: 'main.qml' +runtime: 'qml' +name: + en: 'ApplicationManagerBench Test' diff --git a/tests/benchmarks/appman-bench/templates/appman-qml/main.qml b/tests/benchmarks/appman-bench/templates/appman-qml/main.qml new file mode 100644 index 00000000..07cc3de5 --- /dev/null +++ b/tests/benchmarks/appman-bench/templates/appman-qml/main.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtApplicationManager.Application 2.0 + +ApplicationManagerWindow { + id: root + Loader { + anchors.fill: parent + source: "../../test.qml" + } + Rectangle { + width: 10 + height: 10 + color: "red" + NumberAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + } + } + + Connections { + target: ApplicationInterface + function onQuit() { + target.acknowledgeQuit(); + } + } +} diff --git a/tests/benchmarks/appman-bench/templates/qmlscene/icon.png b/tests/benchmarks/appman-bench/templates/qmlscene/icon.png new file mode 100644 index 00000000..c1397153 Binary files /dev/null and b/tests/benchmarks/appman-bench/templates/qmlscene/icon.png differ diff --git a/tests/benchmarks/appman-bench/templates/qmlscene/info.yaml b/tests/benchmarks/appman-bench/templates/qmlscene/info.yaml new file mode 100644 index 00000000..3ecadf30 --- /dev/null +++ b/tests/benchmarks/appman-bench/templates/qmlscene/info.yaml @@ -0,0 +1,13 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'TEST_ID' +icon: 'icon.png' +code: 'QT_FOLDER/qmlscene' +runtimeParameters: + arguments: ['main.qml'] + environmentVariables: + QT_LOGGING_RULES: "*=false;*.critical=true" +runtime: 'native' +name: + en: 'ApplicationManagerBench Test' diff --git a/tests/benchmarks/appman-bench/templates/qmlscene/main.qml b/tests/benchmarks/appman-bench/templates/qmlscene/main.qml new file mode 100644 index 00000000..6b7c0f27 --- /dev/null +++ b/tests/benchmarks/appman-bench/templates/qmlscene/main.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Window 2.0 + +Window { + id: root + Loader { + anchors.fill: parent + source: "../../test.qml" + } + Rectangle { + width: 10 + height: 10 + color: "red" + NumberAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + } + } +} diff --git a/tests/benchmarks/appman-bench/tests/controls2.qml b/tests/benchmarks/appman-bench/tests/controls2.qml new file mode 100644 index 00000000..b0f3bff6 --- /dev/null +++ b/tests/benchmarks/appman-bench/tests/controls2.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick.Controls 2.0 + +Button { + text: "Button " + Math.random() +} diff --git a/tests/benchmarks/appman-bench/tests/rect.qml b/tests/benchmarks/appman-bench/tests/rect.qml new file mode 100644 index 00000000..39f9cd10 --- /dev/null +++ b/tests/benchmarks/appman-bench/tests/rect.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Rectangle { + color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); +} diff --git a/tests/benchmarks/appman-bench/tests/repeater.qml b/tests/benchmarks/appman-bench/tests/repeater.qml new file mode 100644 index 00000000..35a57980 --- /dev/null +++ b/tests/benchmarks/appman-bench/tests/repeater.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Grid { + id: grid + property int count: 10000 + columns: Math.ceil(Math.sqrt(count)) + + Repeater { + model: grid.count + + Rectangle { + width: grid.width / grid.columns; + height: grid.height / Math.ceil(grid.count / grid.columns) + + color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); + } + } +} diff --git a/tests/benchmarks/appman-bench/tests/shader.qml b/tests/benchmarks/appman-bench/tests/shader.qml new file mode 100644 index 00000000..6ea1aabe --- /dev/null +++ b/tests/benchmarks/appman-bench/tests/shader.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtApplicationManager module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtGraphicalEffects 1.0 + +Item { + Grid { + id: grid + + anchors.fill: parent + + property int count: 10000 + columns: Math.ceil(Math.sqrt(count)) + + Repeater { + model: grid.count + + Rectangle { + width: grid.width / grid.columns; + height: grid.height / Math.ceil(grid.count / grid.columns) + + color: Qt.rgba(Math.random(),Math.random(),Math.random(),1); + + NumberAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + } + } + } + } + + GaussianBlur { + anchors.fill: grid + source: grid + radius: 100 + samples: 100 + } +} diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro new file mode 100644 index 00000000..ca7d4f1f --- /dev/null +++ b/tests/benchmarks/benchmarks.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + appman-bench \ + diff --git a/tests/configuration/configuration.pro b/tests/configuration/configuration.pro deleted file mode 100644 index da3ff241..00000000 --- a/tests/configuration/configuration.pro +++ /dev/null @@ -1,12 +0,0 @@ -TARGET = tst_configuration - -include($$PWD/../tests.pri) - -QT *= appman_common-private appman_main-private - -SOURCES += tst_configuration.cpp - -RESOURCES += \ - data/empty.yaml \ - data/config1.yaml \ - data/config2.yaml \ diff --git a/tests/configuration/data/config1.yaml b/tests/configuration/data/config1.yaml deleted file mode 100644 index 06954344..00000000 --- a/tests/configuration/data/config1.yaml +++ /dev/null @@ -1,98 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -runtimes: - r-test: - r-parameter: r-value - -containers: - selection: selectionFunction - c-test: - c-parameter: c-value - -intents: - disable: true - timeouts: - disambiguation: 1 - startApplication: 2 - replyFromApplication: 3 - replyFromSystem: 4 - -plugins: - startup: [ s1, s2 ] - container: [ c1, c2 ] - -logging: - dlt: - id: 'dltid' - description: 'dltdesc' - rules: [ lr1, lr2 ] - messagePattern: 'msgPattern' - useAMConsoleLogger: true - -installer: - disable: true - caCertificates: [ cert1, cert2 ] - -dbus: - iface1: - register: 'foobus' - -quicklaunch: - idleLoad: 0.5 - runtimesPerContainer: 5 - -ui: - opengl: - desktopProfile: 'compatibility' - esMajorVersion: 5 - esMinorVersion: 15 - enableTouchEmulation: true - iconThemeSearchPaths: [ itsp1, itsp2 ] - iconThemeName: mytheme - style: mystyle - loadDummyData: true - importPaths: [ ip1, ip2 ] - pluginPaths: [ pp1, pp2 ] - windowIcon: 'icon.png' - fullscreen: true - mainQml: main.qml - resources: [ r1, r2 ] - -applications: - builtinAppsManifestDir: 'builtin-dir' - installationDir: 'installation-dir' - documentDir: 'doc-dir' - -crashAction: - printBacktrace: true - printQmlStack: true - waitForGdbAttach: true - dumpCore: true - -systemProperties: - public: - public-prop: public-value - protected: - protected-prop: protected-value - private: - private-prop: private-value - -flags: - forceSingleProcess: true - forceMultiProcess: true - noSecurity: true - developmentMode: true - noUiWatchdog: true - -wayland: - socketName: "my-wlsock-42" - extraSockets: - - path: path-es1 - permissions: 0440 - userId: 1 - groupId: 2 - - path: path-es2 - permissions: 0222 - userId: 3 - groupId: 4 diff --git a/tests/configuration/data/config2.yaml b/tests/configuration/data/config2.yaml deleted file mode 100644 index cd9d9766..00000000 --- a/tests/configuration/data/config2.yaml +++ /dev/null @@ -1,88 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -runtimes: - r-test: - r-parameter: xr-value - r-test2: - r-parameter2: r-value2 - -containers: - selection: - - '2': second - - c-test: - c-parameter: xc-value - c-test2: - c-parameter2: c-value2 - -intents: - timeouts: - disambiguation: 5 - startApplication: 6 - replyFromApplication: 7 - replyFromSystem: 8 - -plugins: - startup: s3 - container: [ c3, c4 ] - -logging: - dlt: - id: 'dltid2' - description: 'dltdesc2' - rules: lr3 - messagePattern: 'msgPattern2' - useAMConsoleLogger: 'auto' - -installer: - disable: true - caCertificates: [ cert3 ] - -dbus: - iface1: - register: 'foobus1' - iface2: - register: 'foobus2' - -quicklaunch: - idleLoad: 0.2 - runtimesPerContainer: 3 - -ui: - opengl: - desktopProfile: 'classic' - esMajorVersion: 1 - esMinorVersion: 0 - enableTouchEmulation: true - iconThemeSearchPaths: [ itsp3 ] - iconThemeName: mytheme2 - style: mystyle2 - loadDummyData: true - importPaths: ip3 - pluginPaths: pp3 - windowIcon: 'icon2.png' - fullscreen: true - mainQml: main2.qml - resources: r3 - -applications: - builtinAppsManifestDir: 'builtin-dir2' - installationDir: 'installation-dir2' - documentDir: 'doc-dir2' - -systemProperties: - public: - public-prop: xpublic-value - public-prop2: public-value2 - protected: - protected-prop: xprotected-value - protected-prop2: protected-value2 - private: - private-prop: xprivate-value - private-prop2: private-value2 - -wayland: - socketName: "other-wlsock-0" - extraSockets: - - path: path-es3 diff --git a/tests/configuration/data/empty.yaml b/tests/configuration/data/empty.yaml deleted file mode 100644 index a87fe348..00000000 --- a/tests/configuration/data/empty.yaml +++ /dev/null @@ -1,3 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- diff --git a/tests/configuration/tst_configuration.cpp b/tests/configuration/tst_configuration.cpp deleted file mode 100644 index 67eeec41..00000000 --- a/tests/configuration/tst_configuration.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include -#include -#include - -QT_USE_NAMESPACE_AM - -class tst_Configuration : public QObject -{ - Q_OBJECT - -public: - tst_Configuration(); - -private slots: - void defaultConfig(); - void simpleConfig(); - void mergedConfig(); - void commandLineConfig(); - -private: - QDir pwd; -}; - - -tst_Configuration::tst_Configuration() -{ } - -void tst_Configuration::defaultConfig() -{ - Configuration c; - c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); - - QVERIFY(c.noCache()); - - // command line only - QCOMPARE(c.noFullscreen(), false); - QCOMPARE(c.verbose(), false); - QCOMPARE(c.slowAnimations(), false); - QCOMPARE(c.noDltLogging(), false); - QCOMPARE(c.singleApp(), qSL("")); - QCOMPARE(c.qmlDebugging(), false); - - // values from config file - QCOMPARE(c.mainQmlFile(), qSL("")); - - QCOMPARE(c.builtinAppsManifestDirs(), {}); - QCOMPARE(c.documentDir(), qSL("")); - - QCOMPARE(c.installationDir(), qSL("")); - QCOMPARE(c.disableInstaller(), false); - QCOMPARE(c.disableIntents(), false); - QCOMPARE(c.intentTimeoutForDisambiguation(), 10000); - QCOMPARE(c.intentTimeoutForStartApplication(), 3000); - QCOMPARE(c.intentTimeoutForReplyFromApplication(), 5000); - QCOMPARE(c.intentTimeoutForReplyFromSystem(), 20000); - - QCOMPARE(c.fullscreen(), false); - QCOMPARE(c.windowIcon(), qSL("")); - QCOMPARE(c.importPaths(), {}); - QCOMPARE(c.pluginPaths(), {}); - QCOMPARE(c.loadDummyData(), false); - QCOMPARE(c.noSecurity(), false); - QCOMPARE(c.developmentMode(), false); - QCOMPARE(c.noUiWatchdog(), false); - QCOMPARE(c.forceSingleProcess(), false); - QCOMPARE(c.forceMultiProcess(), false); - QCOMPARE(c.loggingRules(), {}); - QCOMPARE(c.messagePattern(), qSL("")); - QCOMPARE(c.useAMConsoleLogger(), QVariant()); - QCOMPARE(c.style(), qSL("")); - QCOMPARE(c.iconThemeName(), qSL("")); - QCOMPARE(c.iconThemeSearchPaths(), {}); - QCOMPARE(c.enableTouchEmulation(), false); - QCOMPARE(c.dltId(), qSL("")); - QCOMPARE(c.dltDescription(), qSL("")); - QCOMPARE(c.resources(), {}); - - QCOMPARE(c.openGLConfiguration(), QVariantMap {}); - - QCOMPARE(c.installationLocations(), {}); - - QCOMPARE(c.containerSelectionConfiguration(), {}); - QCOMPARE(c.containerConfigurations(), QVariantMap {}); - QCOMPARE(c.runtimeConfigurations(), QVariantMap {}); - - QCOMPARE(c.dbusRegistration("iface1"), qSL("auto")); - - QCOMPARE(c.rawSystemProperties(), QVariantMap {}); - - QCOMPARE(c.quickLaunchIdleLoad(), qreal(0)); - QCOMPARE(c.quickLaunchRuntimesPerContainer(), 0); - - QString defaultWaylandSocketName = -#if defined(Q_OS_LINUX) - qSL("qtam-wayland-0"); -#else - QString(); -#endif - - QCOMPARE(c.waylandSocketName(), defaultWaylandSocketName); - QCOMPARE(c.waylandExtraSockets(), {}); - - QCOMPARE(c.managerCrashAction(), QVariantMap {}); - - QCOMPARE(c.caCertificates(), {}); - - QCOMPARE(c.pluginFilePaths("container"), {}); - QCOMPARE(c.pluginFilePaths("startup"), {}); -} - -void tst_Configuration::simpleConfig() -{ - Configuration c({ qSL(":/data/config1.yaml") }, qSL(":/build-config.yaml")); - c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); - - QVERIFY(c.noCache()); - - // command line only - QCOMPARE(c.noFullscreen(), false); - QCOMPARE(c.verbose(), false); - QCOMPARE(c.slowAnimations(), false); - QCOMPARE(c.noDltLogging(), false); - QCOMPARE(c.singleApp(), qSL("")); - QCOMPARE(c.qmlDebugging(), false); - - // values from config file - QCOMPARE(c.mainQmlFile(), qSL("main.qml")); - - QCOMPARE(c.builtinAppsManifestDirs(), { qSL("builtin-dir") }); - QCOMPARE(c.documentDir(), qSL("doc-dir")); - - QCOMPARE(c.installationDir(), qSL("installation-dir")); - QCOMPARE(c.disableInstaller(), true); - QCOMPARE(c.disableIntents(), true); - QCOMPARE(c.intentTimeoutForDisambiguation(), 1); - QCOMPARE(c.intentTimeoutForStartApplication(), 2); - QCOMPARE(c.intentTimeoutForReplyFromApplication(), 3); - QCOMPARE(c.intentTimeoutForReplyFromSystem(), 4); - - QCOMPARE(c.fullscreen(), true); - QCOMPARE(c.windowIcon(), qSL("icon.png")); - QCOMPARE(c.importPaths(), QStringList({ pwd.absoluteFilePath(qSL("ip1")), pwd.absoluteFilePath(qSL("ip2")) })); - QCOMPARE(c.pluginPaths(), QStringList({ qSL("pp1"), qSL("pp2") })); - QCOMPARE(c.loadDummyData(), true); - QCOMPARE(c.noSecurity(), true); - QCOMPARE(c.developmentMode(), true); - QCOMPARE(c.noUiWatchdog(), true); - QCOMPARE(c.forceSingleProcess(), true); - QCOMPARE(c.forceMultiProcess(), true); - QCOMPARE(c.loggingRules(), QStringList({ qSL("lr1"), qSL("lr2") })); - QCOMPARE(c.messagePattern(), qSL("msgPattern")); - QCOMPARE(c.useAMConsoleLogger(), QVariant(true)); - QCOMPARE(c.style(), qSL("mystyle")); - QCOMPARE(c.iconThemeName(), qSL("mytheme")); - QCOMPARE(c.iconThemeSearchPaths(), QStringList({ qSL("itsp1"), qSL("itsp2") })); - QCOMPARE(c.enableTouchEmulation(), true); - QCOMPARE(c.dltId(), qSL("dltid")); - QCOMPARE(c.dltDescription(), qSL("dltdesc")); - QCOMPARE(c.resources(), QStringList({ qSL("r1"), qSL("r2") })); - - QCOMPARE(c.openGLConfiguration(), QVariantMap - ({ - { qSL("desktopProfile"), qSL("compatibility") }, - { qSL("esMajorVersion"), 5 }, - { qSL("esMinorVersion"), 15 } - })); - - QCOMPARE(c.installationLocations(), {}); - - QList> containerSelectionConfiguration { - { qSL("*"), qSL("selectionFunction") } - }; - QCOMPARE(c.containerSelectionConfiguration(), containerSelectionConfiguration); - QCOMPARE(c.containerConfigurations(), QVariantMap - ({ - { qSL("c-test"), QVariantMap { - { qSL("c-parameter"), qSL("c-value") } - } } - })); - QCOMPARE(c.runtimeConfigurations(), QVariantMap - ({ - { qSL("r-test"), QVariantMap { - { qSL("r-parameter"), qSL("r-value") } - } } - })); - - QCOMPARE(c.dbusRegistration("iface1"), qSL("foobus")); - - QCOMPARE(c.rawSystemProperties(), QVariantMap - ({ - { qSL("public"), QVariantMap { - { qSL("public-prop"), qSL("public-value") } - } }, - { qSL("protected"), QVariantMap { - { qSL("protected-prop"), qSL("protected-value") } - } }, - { qSL("private"), QVariantMap { - { qSL("private-prop"), qSL("private-value") } - } } - })); - - QCOMPARE(c.quickLaunchIdleLoad(), qreal(0.5)); - QCOMPARE(c.quickLaunchRuntimesPerContainer(), 5); - - QCOMPARE(c.waylandSocketName(), qSL("my-wlsock-42")); - - QCOMPARE(c.waylandExtraSockets(), QVariantList - ({ - QVariantMap { - { qSL("path"), qSL("path-es1") }, - { qSL("permissions"), 0440 }, - { qSL("userId"), 1 }, - { qSL("groupId"), 2 } - }, - QVariantMap { - { qSL("path"), qSL("path-es2") }, - { qSL("permissions"), 0222 }, - { qSL("userId"), 3 }, - { qSL("groupId"), 4 } - } - })); - - QCOMPARE(c.managerCrashAction(), QVariantMap - ({ - { qSL("printBacktrace"), true }, - { qSL("printQmlStack"), true }, - { qSL("waitForGdbAttach"), true }, - { qSL("dumpCore"), true } - })); - - QCOMPARE(c.caCertificates(), QStringList({ qSL("cert1"), qSL("cert2") })); - - QCOMPARE(c.pluginFilePaths("startup"), QStringList({ qSL("s1"), qSL("s2") })); - QCOMPARE(c.pluginFilePaths("container"), QStringList({ qSL("c1"), qSL("c2") })); -} - -void tst_Configuration::mergedConfig() -{ - Configuration c({ qSL(":/data/config1.yaml"), qSL(":/data/config2.yaml") }, qSL(":/build-config.yaml")); - c.parseWithArguments({ qSL("test"), qSL("--no-cache") }); - - QVERIFY(c.noCache()); - - // command line only - QCOMPARE(c.noFullscreen(), false); - QCOMPARE(c.verbose(), false); - QCOMPARE(c.slowAnimations(), false); - QCOMPARE(c.noDltLogging(), false); - QCOMPARE(c.singleApp(), qSL("")); - QCOMPARE(c.qmlDebugging(), false); - - // values from config file - QCOMPARE(c.mainQmlFile(), qSL("main2.qml")); - - QCOMPARE(c.builtinAppsManifestDirs(), QStringList({ qSL("builtin-dir"), qSL("builtin-dir2") })); - QCOMPARE(c.documentDir(), qSL("doc-dir2")); - - QCOMPARE(c.installationDir(), qSL("installation-dir2")); - QCOMPARE(c.disableInstaller(), true); - QCOMPARE(c.disableIntents(), true); - QCOMPARE(c.intentTimeoutForDisambiguation(), 5); - QCOMPARE(c.intentTimeoutForStartApplication(), 6); - QCOMPARE(c.intentTimeoutForReplyFromApplication(), 7); - QCOMPARE(c.intentTimeoutForReplyFromSystem(), 8); - - QCOMPARE(c.fullscreen(), true); - QCOMPARE(c.windowIcon(), qSL("icon2.png")); - QCOMPARE(c.importPaths(), QStringList - ({ pwd.absoluteFilePath(qSL("ip1")), - pwd.absoluteFilePath(qSL("ip2")), - pwd.absoluteFilePath(qSL("ip3")) })); - QCOMPARE(c.pluginPaths(), QStringList({ qSL("pp1"), qSL("pp2"), qSL("pp3") })); - QCOMPARE(c.loadDummyData(), true); - QCOMPARE(c.noSecurity(), true); - QCOMPARE(c.developmentMode(), true); - QCOMPARE(c.noUiWatchdog(), true); - QCOMPARE(c.forceSingleProcess(), true); - QCOMPARE(c.forceMultiProcess(), true); - QCOMPARE(c.loggingRules(), QStringList({ qSL("lr1"), qSL("lr2"), qSL("lr3") })); - QCOMPARE(c.messagePattern(), qSL("msgPattern2")); - QCOMPARE(c.useAMConsoleLogger(), QVariant()); - QCOMPARE(c.style(), qSL("mystyle2")); - QCOMPARE(c.iconThemeName(), qSL("mytheme2")); - QCOMPARE(c.iconThemeSearchPaths(), QStringList({ qSL("itsp1"), qSL("itsp2"), qSL("itsp3") })); - QCOMPARE(c.enableTouchEmulation(), true); - QCOMPARE(c.dltId(), qSL("dltid2")); - QCOMPARE(c.dltDescription(), qSL("dltdesc2")); - QCOMPARE(c.resources(), QStringList({ qSL("r1"), qSL("r2"), qSL("r3") })); - - QCOMPARE(c.openGLConfiguration(), QVariantMap - ({ - { qSL("desktopProfile"), qSL("classic") }, - { qSL("esMajorVersion"), 1 }, - { qSL("esMinorVersion"), 0 }, - })); - - QCOMPARE(c.installationLocations(), {}); - - QList> containerSelectionConfiguration { - { qSL("*"), qSL("selectionFunction") }, - { qSL("2"), qSL("second") } - }; - QCOMPARE(c.containerSelectionConfiguration(), containerSelectionConfiguration); - QCOMPARE(c.containerConfigurations(), QVariantMap - ({ - { qSL("c-test"), QVariantMap { - { qSL("c-parameter"), qSL("xc-value") }, - } }, - { qSL("c-test2"), QVariantMap { - { qSL("c-parameter2"), qSL("c-value2") }, - } } - - })); - - QCOMPARE(c.runtimeConfigurations(), QVariantMap - ({ - { qSL("r-test"), QVariantMap { - { qSL("r-parameter"), qSL("xr-value") }, - } }, - { qSL("r-test2"), QVariantMap { - { qSL("r-parameter2"), qSL("r-value2") }, - } } - - })); - - QCOMPARE(c.dbusRegistration("iface1"), qSL("foobus1")); - QCOMPARE(c.dbusRegistration("iface2"), qSL("foobus2")); - - QCOMPARE(c.rawSystemProperties(), QVariantMap - ({ - { qSL("public"), QVariantMap { - { qSL("public-prop"), qSL("xpublic-value") }, - { qSL("public-prop2"), qSL("public-value2") } - } }, - { qSL("protected"), QVariantMap { - { qSL("protected-prop"), qSL("xprotected-value") }, - { qSL("protected-prop2"), qSL("protected-value2") } - } }, - { qSL("private"), QVariantMap { - { qSL("private-prop"), qSL("xprivate-value") }, - { qSL("private-prop2"), qSL("private-value2") } - } } - })); - - QCOMPARE(c.quickLaunchIdleLoad(), qreal(0.2)); - QCOMPARE(c.quickLaunchRuntimesPerContainer(), 3); - - QCOMPARE(c.waylandSocketName(), qSL("other-wlsock-0")); - - QCOMPARE(c.waylandExtraSockets(), QVariantList - ({ - QVariantMap { - { qSL("path"), qSL("path-es1") }, - { qSL("permissions"), 0440 }, - { qSL("userId"), 1 }, - { qSL("groupId"), 2 } - }, - QVariantMap { - { qSL("path"), qSL("path-es2") }, - { qSL("permissions"), 0222 }, - { qSL("userId"), 3 }, - { qSL("groupId"), 4 } - }, - QVariantMap { - { qSL("path"), qSL("path-es3") }, - } - })); - - QCOMPARE(c.managerCrashAction(), QVariantMap - ({ - { qSL("printBacktrace"), true }, - { qSL("printQmlStack"), true }, - { qSL("waitForGdbAttach"), true }, - { qSL("dumpCore"), true } - })); - - QCOMPARE(c.caCertificates(), QStringList({ qSL("cert1"), qSL("cert2"), qSL("cert3") })); - - QCOMPARE(c.pluginFilePaths("container"), QStringList({ qSL("c1"), qSL("c2"), qSL("c3"), qSL("c4") })); - QCOMPARE(c.pluginFilePaths("startup"), QStringList({ qSL("s1"), qSL("s2"), qSL("s3") })); -} - -void tst_Configuration::commandLineConfig() -{ - Configuration c; - QStringList commandLine { qSL("test"), qSL("--no-cache") }; - - commandLine << "--builtin-apps-manifest-dir" << "builtin-dir-cl1" - << "--builtin-apps-manifest-dir" << "builtin-dir-cl2" - << "--installation-dir" << "installation-dir-cl" - << "--document-dir" << "document-dir-cl" - << "--disable-installer" - << "--disable-intents" - << "--dbus" << "system" - << "--no-fullscreen" - << "-I" << "ip-cl1" - << "-I" << "ip-cl2" - << "-v" - << "--slow-animations" - << "--load-dummydata" - << "--no-security" - << "--development-mode" - << "--no-ui-watchdog" - << "--no-dlt-logging" - << "--force-single-process" - << "--force-multi-process" - << "--wayland-socket-name" << "wlsock-1" - << "--single-app" << "appname" - << "--logging-rule" << "cl-lr1" - << "--logging-rule" << "cl-lr2" - << "--qml-debug" - << "--enable-touch-emulation" - << "main-cl.qml"; - - c.parseWithArguments(commandLine); - - QVERIFY(c.noCache()); - - // command line only - QCOMPARE(c.noFullscreen(), true); - QCOMPARE(c.verbose(), true); - QCOMPARE(c.slowAnimations(), true); - QCOMPARE(c.noDltLogging(), true); - QCOMPARE(c.singleApp(), qSL("appname")); - QCOMPARE(c.qmlDebugging(), true); - - // values from config file - QCOMPARE(c.mainQmlFile(), qSL("main-cl.qml")); - - QCOMPARE(c.builtinAppsManifestDirs(), QStringList({ qSL("builtin-dir-cl1"), qSL("builtin-dir-cl2") })); - QCOMPARE(c.documentDir(), qSL("document-dir-cl")); - - QCOMPARE(c.installationDir(), qSL("installation-dir-cl")); - QCOMPARE(c.disableInstaller(), true); - QCOMPARE(c.disableIntents(), true); - QCOMPARE(c.intentTimeoutForDisambiguation(), 10000); - QCOMPARE(c.intentTimeoutForStartApplication(), 3000); - QCOMPARE(c.intentTimeoutForReplyFromApplication(), 5000); - QCOMPARE(c.intentTimeoutForReplyFromSystem(), 20000); - - QCOMPARE(c.fullscreen(), false); - QCOMPARE(c.windowIcon(), qSL("")); - QCOMPARE(c.importPaths(), QStringList({ pwd.absoluteFilePath(qSL("ip-cl1")), - pwd.absoluteFilePath(qSL("ip-cl2")) })); - QCOMPARE(c.pluginPaths(), {}); - QCOMPARE(c.loadDummyData(), true); - QCOMPARE(c.noSecurity(), true); - QCOMPARE(c.developmentMode(), true); - QCOMPARE(c.noUiWatchdog(), true); - QCOMPARE(c.forceSingleProcess(), true); - QCOMPARE(c.forceMultiProcess(), true); - QCOMPARE(c.loggingRules(), QStringList({ qSL("cl-lr1"), qSL("cl-lr2") })); - QCOMPARE(c.messagePattern(), qSL("")); - QCOMPARE(c.useAMConsoleLogger(), QVariant()); - QCOMPARE(c.style(), qSL("")); - QCOMPARE(c.iconThemeName(), qSL("")); - QCOMPARE(c.iconThemeSearchPaths(), {}); - QCOMPARE(c.enableTouchEmulation(), true); - QCOMPARE(c.dltId(), qSL("")); - QCOMPARE(c.dltDescription(), qSL("")); - QCOMPARE(c.resources(), {}); - - QCOMPARE(c.openGLConfiguration(), QVariantMap {}); - - QCOMPARE(c.installationLocations(), {}); - - QCOMPARE(c.containerSelectionConfiguration(), {}); - QCOMPARE(c.containerConfigurations(), QVariantMap{}); - QCOMPARE(c.runtimeConfigurations(), QVariantMap{}); - - QCOMPARE(c.dbusRegistration("iface1"), qSL("system")); - - QCOMPARE(c.rawSystemProperties(), QVariantMap {}); - - QCOMPARE(c.quickLaunchIdleLoad(), qreal(0)); - QCOMPARE(c.quickLaunchRuntimesPerContainer(), 0); - - QCOMPARE(c.waylandSocketName(), qSL("wlsock-1")); - QCOMPARE(c.waylandExtraSockets(), {}); - - QCOMPARE(c.managerCrashAction(), QVariantMap {}); - - QCOMPARE(c.caCertificates(), {}); - - QCOMPARE(c.pluginFilePaths("container"), {}); - QCOMPARE(c.pluginFilePaths("startup"), {}); -} - - -QTEST_MAIN(tst_Configuration) - -#include "tst_configuration.moc" diff --git a/tests/cryptography/cryptography.pro b/tests/cryptography/cryptography.pro deleted file mode 100644 index d18f6441..00000000 --- a/tests/cryptography/cryptography.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = tst_cryptography - -include($$PWD/../tests.pri) - -QT *= appman_common-private appman_crypto-private - -SOURCES += tst_cryptography.cpp diff --git a/tests/cryptography/tst_cryptography.cpp b/tests/cryptography/tst_cryptography.cpp deleted file mode 100644 index ff8c2ae6..00000000 --- a/tests/cryptography/tst_cryptography.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "cryptography.h" - -QT_USE_NAMESPACE_AM - -class tst_Cryptography : public QObject -{ - Q_OBJECT - -public: - tst_Cryptography(); - -private slots: - void random(); -}; - -tst_Cryptography::tst_Cryptography() -{ } - -void tst_Cryptography::random() -{ - QVERIFY(Cryptography::generateRandomBytes(-1).isEmpty()); - QVERIFY(Cryptography::generateRandomBytes(0).isEmpty()); - QVERIFY(!Cryptography::generateRandomBytes(1).isEmpty()); - QCOMPARE(Cryptography::generateRandomBytes(128).size(), 128); -} - -QTEST_APPLESS_MAIN(tst_Cryptography) - -#include "tst_cryptography.moc" diff --git a/tests/data/certificates/create-test-certificates.sh b/tests/data/certificates/create-test-certificates.sh old mode 100644 new mode 100755 diff --git a/tests/data/create-test-packages.sh b/tests/data/create-test-packages.sh old mode 100644 new mode 100755 diff --git a/tests/debugwrapper/debugwrapper.pro b/tests/debugwrapper/debugwrapper.pro deleted file mode 100644 index b7e9128a..00000000 --- a/tests/debugwrapper/debugwrapper.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = tst_debugwrapper - -include($$PWD/../tests.pri) - -QT *= \ - appman_manager-private - -SOURCES += tst_debugwrapper.cpp diff --git a/tests/debugwrapper/tst_debugwrapper.cpp b/tests/debugwrapper/tst_debugwrapper.cpp deleted file mode 100644 index 8037bb31..00000000 --- a/tests/debugwrapper/tst_debugwrapper.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include - -#include "../error-checking.h" - -QT_USE_NAMESPACE_AM - -class tst_DebugWrapper : public QObject -{ - Q_OBJECT - -public: - tst_DebugWrapper(QObject *parent = nullptr); - ~tst_DebugWrapper(); - -private slots: - void specification_data(); - void specification(); - - void substitute_data(); - void substitute(); -}; - - -tst_DebugWrapper::tst_DebugWrapper(QObject *parent) - : QObject(parent) -{ } - -tst_DebugWrapper::~tst_DebugWrapper() -{ } - -typedef QMap StringMap; -Q_DECLARE_METATYPE(StringMap) - -void tst_DebugWrapper::specification_data() -{ - QTest::addColumn("spec"); - QTest::addColumn("valid"); - QTest::addColumn("env"); - QTest::addColumn("cmd"); - - QMap noenv; - - QTest::newRow("empty") << "" << false << noenv << QStringList(); - QTest::newRow("empty2") << " " << false << noenv << QStringList(); - - QTest::newRow("nocmd") << "foo=bar" << true << StringMap {{ "foo", "bar" }} << QStringList { "%program%", "%arguments%" }; - QTest::newRow("nocmd2") << "foo=bar " << true << StringMap {{ "foo", "bar" }} << QStringList { "%program%", "%arguments%" }; - - QTest::newRow("1") << "foo" << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; - QTest::newRow("2") << " foo" << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; - QTest::newRow("3") << "foo " << true << noenv << QStringList { "foo", "%program%", "%arguments%" }; - QTest::newRow("4") << "foo bar" << true << noenv << QStringList { "foo", "bar", "%program%", "%arguments%" }; - QTest::newRow("5") << "foo bar" << true << noenv << QStringList { "foo", "bar", "%program%", "%arguments%" }; - QTest::newRow("6") << "foo bar baz" << true << noenv << QStringList { "foo", "bar", "baz", "%program%", "%arguments%" }; - QTest::newRow("7") << "fo\\ o b\\nar b\\\\az" << true << noenv << QStringList { "fo o", "b\nar", "b\\az", "%program%", "%arguments%" }; - QTest::newRow("8") << "foo=bar baz" << true << StringMap {{ "foo", "bar" }} << QStringList { "baz", "%program%", "%arguments%" }; - QTest::newRow("9") << "foo=bar a= baz zab" << true << StringMap {{ "foo", "bar" }, { "a", QString() }} << QStringList { "baz", "zab", "%program%", "%arguments%" }; - QTest::newRow("a") << "foo=b\\ a=\\n baz z\\ ab" << true << StringMap {{ "foo", "b a=\n" }} << QStringList { "baz", "z ab", "%program%", "%arguments%" }; - QTest::newRow("b") << "a=b c d=e" << true << StringMap {{ "a", "b" }} << QStringList { "c", "d=e", "%program%", "%arguments%" }; - - QTest::newRow("z") << "a=b %program% c %arguments% d" << true << StringMap {{ "a", "b" }} << QStringList { "%program%", "c", "%arguments%", "d" }; - QTest::newRow("y") << "a=b %program% c d" << true << StringMap {{ "a", "b" }} << QStringList { "%program%", "c", "d", "%arguments%" }; - QTest::newRow("x") << "a=b %arguments%" << true << StringMap {{ "a", "b" }} << QStringList { "%arguments%", "%program%" }; - QTest::newRow("w") << "%program% %arguments%" << true << noenv << QStringList { "%program%", "%arguments%" }; - QTest::newRow("w") << "%program% foo-%program% foo-%arguments%-bar %arguments%" << true << noenv << QStringList { "%program%", "foo-%program%", "foo-%arguments%-bar", "%arguments%" }; -} - -void tst_DebugWrapper::specification() -{ - QFETCH(QString, spec); - QFETCH(bool, valid); - QFETCH(StringMap, env); - QFETCH(QStringList, cmd); - - StringMap resultEnv; - QStringList resultCmd; - QCOMPARE(DebugWrapper::parseSpecification(spec, resultCmd, resultEnv), valid); - QCOMPARE(cmd, resultCmd); - QCOMPARE(env, resultEnv); -} - -void tst_DebugWrapper::substitute_data() -{ - QTest::addColumn("cmd"); - QTest::addColumn("program"); - QTest::addColumn("arguments"); - QTest::addColumn("result"); - - QTest::newRow("1") << QStringList { "%program%", "%arguments%" } - << QString("prg") << QStringList { "arg1", "arg2" } - << QStringList { "prg", "arg1", "arg2" }; - - QTest::newRow("2") << QStringList { "%program%" } - << QString("prg") << QStringList { "arg1", "arg2" } - << QStringList { "prg" }; - - QTest::newRow("3") << QStringList { "%program%", "\"x-%program%\"", "%arguments%", "x-%arguments%" } - << QString("prg") << QStringList { "arg1", "arg2" } - << QStringList { "prg", "\"x-prg\"", "arg1", "arg2", "x-arg1 arg2" }; - - QTest::newRow("4") << QStringList { "foo", "%arguments%", "bar", "%program%", "baz", "%arguments%", "foo2" } - << QString("prg") << QStringList { "a1", "a2", "a3" } - << QStringList { "foo", "a1", "a2", "a3", "bar", "prg", "baz", "a1", "a2", "a3", "foo2" }; -} - -void tst_DebugWrapper::substitute() -{ - QFETCH(QStringList, cmd); - QFETCH(QString, program); - QFETCH(QStringList, arguments); - QFETCH(QStringList, result); - - QCOMPARE(DebugWrapper::substituteCommand(cmd, program, arguments), result); -} - -QTEST_APPLESS_MAIN(tst_DebugWrapper) - -#include "tst_debugwrapper.moc" diff --git a/tests/error-checking.h b/tests/error-checking.h deleted file mode 100644 index e80cdde5..00000000 --- a/tests/error-checking.h +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#pragma once - -#include - -// sadly this has to be a define for QVERIFY2() to work -#define AM_CHECK_ERRORSTRING(_actual_errstr, _expected_errstr) do { \ - if (_expected_errstr.startsWith(QLatin1String("~"))) { \ - QRegularExpression re(_expected_errstr.mid(1)); \ - QVERIFY2(re.match(_actual_errstr).hasMatch(), \ - qPrintable("\n Got : " + _actual_errstr.toLocal8Bit() + \ - "\n Expected: " + _expected_errstr.toLocal8Bit())); \ - } else { \ - QCOMPARE(_actual_errstr, _expected_errstr); \ - } \ -} while (false) diff --git a/tests/installationreport/installationreport.pro b/tests/installationreport/installationreport.pro deleted file mode 100644 index ce1aa46b..00000000 --- a/tests/installationreport/installationreport.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = tst_installationreport - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_crypto-private \ - appman_application-private \ - -SOURCES += tst_installationreport.cpp diff --git a/tests/installationreport/tst_installationreport.cpp b/tests/installationreport/tst_installationreport.cpp deleted file mode 100644 index edb1b35a..00000000 --- a/tests/installationreport/tst_installationreport.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "global.h" -#include "exception.h" -#include "installationreport.h" - -QT_USE_NAMESPACE_AM - -class tst_InstallationReport : public QObject -{ - Q_OBJECT - -public: - tst_InstallationReport(); - -private slots: - void test(); -}; - -tst_InstallationReport::tst_InstallationReport() -{ } - -void tst_InstallationReport::test() -{ - QStringList files { qSL("test"), qSL("more/test"), qSL("another/test/file") }; - - InstallationReport ir(qSL("com.pelagicore.test")); - QVERIFY(!ir.isValid()); - ir.addFile(files.first()); - QVERIFY(!ir.isValid()); - ir.setDiskSpaceUsed(42); - QVERIFY(!ir.isValid()); - ir.setDigest("##digest##"); - QVERIFY(ir.isValid()); - ir.addFiles(files.mid(1)); - ir.setDeveloperSignature("%%dev-sig%%"); - ir.setStoreSignature("$$store-sig$$"); - - QVERIFY(ir.isValid()); - QCOMPARE(ir.packageId(), qSL("com.pelagicore.test")); - QCOMPARE(ir.files(), files); - QCOMPARE(ir.diskSpaceUsed(), 42ULL); - QCOMPARE(ir.digest().constData(), "##digest##"); - QCOMPARE(ir.developerSignature().constData(), "%%dev-sig%%"); - QCOMPARE(ir.storeSignature().constData(), "$$store-sig$$"); - - QBuffer buffer; - buffer.open(QIODevice::ReadWrite); - QVERIFY(ir.serialize(&buffer)); - buffer.seek(0); - - InstallationReport ir2; - try { - ir2.deserialize(&buffer); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - buffer.seek(0); - - QVERIFY(ir2.isValid()); - QCOMPARE(ir2.packageId(), qSL("com.pelagicore.test")); - QCOMPARE(ir2.files(), files); - QCOMPARE(ir2.diskSpaceUsed(), 42ULL); - QCOMPARE(ir2.digest().constData(), "##digest##"); - QCOMPARE(ir2.developerSignature().constData(), "%%dev-sig%%"); - QCOMPARE(ir2.storeSignature().constData(), "$$store-sig$$"); - - QByteArray &yaml = buffer.buffer(); - QVERIFY(!yaml.isEmpty()); - - int pos = yaml.lastIndexOf("\n---\nhmac: '"); - QVERIFY(pos > 0); - pos += 12; - QByteArray hmac = QMessageAuthenticationCode::hash("data", "key", QCryptographicHash::Sha256).toHex(); - yaml.replace(pos, hmac.size(), hmac); - QCOMPARE(yaml.mid(pos + hmac.size(), 2).constData(), "'\n"); - - try { - ir2.deserialize(&buffer); - QVERIFY(false); - } catch (...) { - } -} - -QTEST_APPLESS_MAIN(tst_InstallationReport) - -#include "tst_installationreport.moc" diff --git a/tests/main/am-config.yaml b/tests/main/am-config.yaml deleted file mode 100644 index ff538f1b..00000000 --- a/tests/main/am-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/builtin-apps" - installationDir: "/tmp/am-test-main/apps" - documentDir: "/tmp/am-test-main/docs" - -ui: - mainQml: "${CONFIG_PWD}/dummy.qml" diff --git a/tests/main/builtin-apps/hello-world.red/icon.png b/tests/main/builtin-apps/hello-world.red/icon.png deleted file mode 100644 index 04ca44dd..00000000 Binary files a/tests/main/builtin-apps/hello-world.red/icon.png and /dev/null differ diff --git a/tests/main/builtin-apps/hello-world.red/info.yaml b/tests/main/builtin-apps/hello-world.red/info.yaml deleted file mode 100644 index fa52180e..00000000 --- a/tests/main/builtin-apps/hello-world.red/info.yaml +++ /dev/null @@ -1,24 +0,0 @@ -formatVersion: 1 -formatType: am-package ---- -id: 'hello-world.red' -icon: 'icon.png' -name: - en: 'Hello Red' - -applications: -- id: red1 - runtime: 'qml' - code: 'main.qml' - -- id: red2 - runtime: 'qml' - code: 'main2.qml' - -intents: -- id: red.intent1 - handlingApplicationId: red1 - categories: [ launcher, one ] -- id: red.intent2 - handlingApplicationId: red2 - categories: [ launcher, two ] diff --git a/tests/main/builtin-apps/hello-world.red/main.qml b/tests/main/builtin-apps/hello-world.red/main.qml deleted file mode 100644 index b225bdfc..00000000 --- a/tests/main/builtin-apps/hello-world.red/main.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - color: "red" - - Text { - anchors.centerIn: parent - text: "Hello World!" - } -} diff --git a/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml b/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml deleted file mode 100644 index ec57b3d7..00000000 --- a/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml +++ /dev/null @@ -1,14 +0,0 @@ -%YAML 1.1 ---- -formatType: 'am-installation-report' -formatVersion: 3 ---- -packageId: 'hello-world.red' -digest: '45ca0f9dfbddca129687900ae3260fe4a35ca09efd189581e196c0a75da47a0f' -diskSpaceUsed: 575488 -files: -- 'info.yaml' -- 'icon.png' -- 'main.qml' ---- -hmac: '48fce75b29a2b621f1a1462b434e6de0cac78837fe733bc12ab8e727363c5226' diff --git a/tests/main/dir-with-update-already-installed/apps/hello-world.red/icon.png b/tests/main/dir-with-update-already-installed/apps/hello-world.red/icon.png deleted file mode 100644 index 04ca44dd..00000000 Binary files a/tests/main/dir-with-update-already-installed/apps/hello-world.red/icon.png and /dev/null differ diff --git a/tests/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml b/tests/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml deleted file mode 100644 index af6a9f70..00000000 --- a/tests/main/dir-with-update-already-installed/apps/hello-world.red/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'hello-world.red' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'Hello Updated Red' diff --git a/tests/main/dir-with-update-already-installed/apps/hello-world.red/main.qml b/tests/main/dir-with-update-already-installed/apps/hello-world.red/main.qml deleted file mode 100644 index 29b2e715..00000000 --- a/tests/main/dir-with-update-already-installed/apps/hello-world.red/main.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - color: "crimson" - - Text { - anchors.centerIn: parent - text: "Hello Updated World!" - } -} diff --git a/tests/main/dir-with-update-already-installed/docs/hello-world.red/placeholder b/tests/main/dir-with-update-already-installed/docs/hello-world.red/placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png b/tests/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png deleted file mode 100644 index 04ca44dd..00000000 Binary files a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/icon.png and /dev/null differ diff --git a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml b/tests/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml deleted file mode 100644 index af6a9f70..00000000 --- a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'hello-world.red' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'Hello Updated Red' diff --git a/tests/main/dummy.qml b/tests/main/dummy.qml deleted file mode 100644 index 2d95c818..00000000 --- a/tests/main/dummy.qml +++ /dev/null @@ -1,3 +0,0 @@ -import QtQml 2.0 - -QtObject { } diff --git a/tests/main/main.pro b/tests/main/main.pro deleted file mode 100644 index e60ec75f..00000000 --- a/tests/main/main.pro +++ /dev/null @@ -1,20 +0,0 @@ -TARGET = tst_main - -include($$PWD/../tests.pri) - -# this test keeps crashing in a VirtualBox based CI environment, when executed -# via ssh (which gets the test run in Window's session 0 (no visible desktop) -luxoft-ci:CONFIG *= insignificant_test - -QT *= appman_manager-private \ - appman_application-private \ - appman_common-private \ - appman_main-private \ - appman_intent_server-private \ - -SOURCES += tst_main.cpp - -RESOURCES = main.qrc - -OTHER_FILES += am-config.yaml - diff --git a/tests/main/main.qrc b/tests/main/main.qrc deleted file mode 100644 index 8cae2bbb..00000000 --- a/tests/main/main.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - dummy.qml - - diff --git a/tests/main/tst_main.cpp b/tests/main/tst_main.cpp deleted file mode 100644 index 9d9f04a5..00000000 --- a/tests/main/tst_main.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#include "packagemanager.h" -#include "package.h" -#include "applicationmanager.h" -#include "logging.h" -#include "main.h" -#include "intentserver.h" -#include "intent.h" -#include - - -QT_USE_NAMESPACE_AM - -class tst_Main : public QObject -{ - Q_OBJECT - -public: - tst_Main(); - ~tst_Main(); - -private slots: - void initTestCase(); - void init(); - void cleanup(); - void installAndRemoveUpdateForBuiltIn(); - void updateForBuiltInAlreadyInstalled(); - void loadDatabaseWithUpdatedBuiltInApp(); - void mainQmlFile_data(); - void mainQmlFile(); - -private: - void cleanUpInstallationDir(); - void installPackage(const QString &path); - void removePackage(const QString &id); - void initMain(); - void destroyMain(); - void copyRecursively(const QString &sourceDir, const QString &destDir); - int argc; - char **argv; - Main *main{nullptr}; - DefaultConfiguration *config{nullptr}; - bool m_verbose = false; -}; - -tst_Main::tst_Main() -{ - argc = 4; - argv = new char*[argc + 1]; - argv[0] = qstrdup("tst_Main"); - argv[1] = qstrdup("--dbus"); - argv[2] = qstrdup("none"); - argv[3] = qstrdup("--no-cache"); - argv[4] = nullptr; -} - -tst_Main::~tst_Main() -{ - for (int i = 0; i < argc; ++i) - delete []argv[i]; - delete []argv; -} - -void tst_Main::initTestCase() -{ - if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) - QSKIP("No test packages available in the data/ directory"); - - m_verbose = qEnvironmentVariableIsSet("AM_VERBOSE_TEST"); - qInfo() << "Verbose mode is" << (m_verbose ? "on" : "off") << "(change by (un)setting $AM_VERBOSE_TEST)"; -} - -void tst_Main::copyRecursively(const QString &sourcePath, const QString &destPath) -{ - QDir sourceDir(sourcePath); - QDir destDir(destPath); - - QStringList subdirNames = sourceDir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs); - for (auto subdirName : subdirNames) { - destDir.mkdir(subdirName); - copyRecursively(sourceDir.filePath(subdirName), destDir.filePath(subdirName)); - } - - QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Hidden); - for (auto fileName : fileNames) - QFile::copy(sourceDir.filePath(fileName), destDir.filePath(fileName)); -} - -void tst_Main::cleanUpInstallationDir() -{ - { - QDir testTmpDir("/tmp/am-test-main"); - if (testTmpDir.exists()) - testTmpDir.removeRecursively(); - } - QDir tmpDir("/tmp"); - tmpDir.mkdir("am-test-main"); -} - -void tst_Main::init() -{ - cleanUpInstallationDir(); -} - -void tst_Main::initMain() -{ - main = new Main(argc, argv); - - QString amConfigPath = QFINDTESTDATA("am-config.yaml"); - auto pathList = QStringList(amConfigPath); - - config = new DefaultConfiguration(pathList, QString()); - config->parseWithArguments(QCoreApplication::arguments()); - if (m_verbose) - config->setForceVerbose(true); - - main->setup(config); - - PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); -} - -void tst_Main::destroyMain() -{ - if (main) { - main->shutDown(); - main->exec(); - delete main; - main = nullptr; - } - if (config) { - delete config; - config = nullptr; - } -} - -void tst_Main::cleanup() -{ - destroyMain(); - - delete config; - config = nullptr; -} - -void tst_Main::installPackage(const QString &pkgPath) -{ - auto packageManager = PackageManager::instance(); - - bool installationFinished = false; - - connect(packageManager, &PackageManager::taskRequestingInstallationAcknowledge, - this, [packageManager](const QString &taskId, Package *, - const QVariantMap &, const QVariantMap &) { - packageManager->acknowledgePackageInstallation(taskId); - }); - - connect(packageManager, &PackageManager::taskFinished, - this, [&installationFinished](const QString &) { - installationFinished = true; - }); - - packageManager->startPackageInstallation(QUrl::fromLocalFile(pkgPath)); - - QTRY_VERIFY(installationFinished); -} - -void tst_Main::removePackage(const QString &id) -{ - auto packageManager = PackageManager::instance(); - - bool removalFinished = false; - - connect(packageManager, &PackageManager::taskFinished, - this, [this, &removalFinished](const QString &) { - Q_UNUSED(this); // gcc 9.2 bug: without capturing 'this', broken code will be generated - removalFinished = true; - }); - - packageManager->removePackage(id, false /* keepDocuments */); - - QTRY_VERIFY(removalFinished); -} - -/* - Install an application with the same id of an existing, builtin, one. - Then remove it. - At all stages ApplicationManager should contain the same Application - object. All that changes is the contents of that Application: - from original, to updated, and then back to original. - */ -void tst_Main::installAndRemoveUpdateForBuiltIn() -{ - initMain(); - - auto appMan = ApplicationManager::instance(); - QCOMPARE(appMan->count(), 2); - auto intents = IntentServer::instance(); - QCOMPARE(intents->count(), 2); - - auto app1 = appMan->application(0); - QCOMPARE(app1->name(qSL("en")), qSL("Hello Red")); - QCOMPARE(app1->id(), qSL("red1")); - auto app2 = appMan->application(1); - QCOMPARE(app2->name(qSL("en")), qSL("Hello Red")); - QCOMPARE(app2->id(), qSL("red2")); - - auto intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); - QVERIFY(intent1); - QCOMPARE(intent1->intentId(), qSL("red.intent1")); - QCOMPARE(intent1->applicationId(), qSL("red1")); - QCOMPARE(intent1->packageId(), qSL("hello-world.red")); - QVERIFY(intent1->categories().contains(qSL("one"))); - QVERIFY(intent1->categories().contains(qSL("launcher"))); - - auto intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2")); - QVERIFY(intent2); - QCOMPARE(intent2->intentId(), qSL("red.intent2")); - QCOMPARE(intent2->applicationId(), qSL("red2")); - QCOMPARE(intent2->packageId(), qSL("hello-world.red")); - QVERIFY(intent2->categories().contains(qSL("two"))); - QVERIFY(intent2->categories().contains(qSL("launcher"))); - - installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg")); - - QCOMPARE(appMan->count(), 1); - QCOMPARE(intents->count(), 0); - - // it must still be a different Application instance as before the installation, but quite - // often we get the same pointer back because it's a delete/new back-to-back - app1 = appMan->application(0); - - // but with different contents - QCOMPARE(app1->name(qSL("en")), qSL("Hello Updated Red")); - intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); - QVERIFY(!intent1); - - removePackage(qSL("hello-world.red")); - - // After removal of the updated version all data in Application should be as before the - // installation took place. - QCOMPARE(appMan->count(), 2); - QCOMPARE(intents->count(), 2); - - app1 = appMan->application(0); - QCOMPARE(app1->name(qSL("en")), qSL("Hello Red")); - intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1")); - QVERIFY(intent1); - QCOMPARE(intent1->intentId(), qSL("red.intent1")); - intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2")); - QVERIFY(intent2); - QCOMPARE(intent2->intentId(), qSL("red.intent2")); -} - -/* - Situation: there's already an update installed for a built-in application and there's no database - file yet (or a database rebuild has been requested, in which case any existing database file is - ignored). - - Check that ApplicationManager ends up with only one ApplicationObject as both entries - (the built-in and the installed one) share the same applicaion id. And check also that - this ApplicationObject is showing data from the installed update. - */ -void tst_Main::updateForBuiltInAlreadyInstalled() -{ - copyRecursively(QFINDTESTDATA("dir-with-update-already-installed"), "/tmp/am-test-main"); - - initMain(); - - auto appMan = ApplicationManager::instance(); - QCOMPARE(appMan->count(), 1); - - auto app = appMan->application(0); - QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red")); -} - -/* - Install an update for a built-in app and quit Main. A database will be generated. - - Then, on next iteration of Main, Applications will be created from that database. - Check that ApplicationManager shows only one, updated, built-in app. - */ -void tst_Main::loadDatabaseWithUpdatedBuiltInApp() -{ - initMain(); - installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg")); - destroyMain(); - - initMain(); - - auto appMan = ApplicationManager::instance(); - QCOMPARE(appMan->count(), 1); - - auto app = appMan->application(0); - QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red")); -} - -void tst_Main::mainQmlFile_data() -{ - QTest::addColumn("mainQml"); - QTest::addColumn("expectedErrorMsg"); - - QTest::newRow("none") << "" << "No main QML file specified"; - - QTest::newRow("invalid") << "foo/bar.qml" << "Invalid main QML file specified: foo/bar.qml"; - QTest::newRow("invalid-dir") << "." << "Invalid main QML file specified: ."; - QTest::newRow("invalid-qrc1") << ":/bar.qml" << "Invalid main QML file specified: :/bar.qml"; - // "://bar.qml" yields an absolute file path of ":" and QFile::exists() would always return true - QTest::newRow("invalid-qrc2") << "://bar.qml" << "Invalid main QML file specified: ://bar.qml"; - QTest::newRow("invalid-qrc-dir") << ":/foo" << "Invalid main QML file specified: :/foo"; - - QTest::newRow("valid-native") << QFINDTESTDATA("dummy.qml") << ""; - QTest::newRow("valid-qrc-file") << ":/foo/dummy.qml" << ""; - QTest::newRow("valid-qrc-url") << "qrc:///foo/dummy.qml" << ""; - - // Passes unchecked: - QTest::newRow("https") << "https://www.qt.io/foo/bar.qml" << ""; - QTest::newRow("assets") << "assets:///foo/bar.qml" << ""; -} - -void tst_Main::mainQmlFile() -{ - QFETCH(QString, mainQml); - QFETCH(QString, expectedErrorMsg); - - QStringList arguments; - arguments << "tst_Main"; - arguments << "--dbus"; - arguments << "none"; - arguments << mainQml; - - main = new Main(argc, argv); - - config = new DefaultConfiguration(QStringList(QFINDTESTDATA("am-config.yaml")), QString()); - config->parseWithArguments(arguments); - - try { - main->setup(config); - QVERIFY2(expectedErrorMsg.isEmpty(), "Exception was expected, but none was thrown"); - } catch (const std::exception &e) { - QCOMPARE(e.what(), expectedErrorMsg); - } - - delete config; - config = nullptr; - delete main; - main = nullptr; -} - -QTEST_APPLESS_MAIN(tst_Main) - -#include "tst_main.moc" diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt new file mode 100644 index 00000000..12298f87 --- /dev/null +++ b/tests/manual/CMakeLists.txt @@ -0,0 +1,2 @@ + +# add_subdirectory(monitormodel) diff --git a/tests/manual/monitormodel/CMakeLists.txt b/tests/manual/monitormodel/CMakeLists.txt new file mode 100644 index 00000000..e6fa5b92 --- /dev/null +++ b/tests/manual/monitormodel/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from monitormodel.pro. + diff --git a/tests/packagecreator/packagecreator.pro b/tests/packagecreator/packagecreator.pro deleted file mode 100644 index 269c12c7..00000000 --- a/tests/packagecreator/packagecreator.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = tst_packagecreator - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_application-private \ - appman_package-private - -SOURCES += tst_packagecreator.cpp diff --git a/tests/packagecreator/tst_packagecreator.cpp b/tests/packagecreator/tst_packagecreator.cpp deleted file mode 100644 index 4882a871..00000000 --- a/tests/packagecreator/tst_packagecreator.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#include "global.h" -#include "installationreport.h" -#include "packageutilities.h" -#include "packagecreator.h" -#include "utilities.h" - -#include "../error-checking.h" - -QT_USE_NAMESPACE_AM - -static int processTimeout = 3000; - -class tst_PackageCreator : public QObject -{ - Q_OBJECT - -public: - tst_PackageCreator(); - -private slots: - void initTestCase(); - - void createAndVerify_data(); - void createAndVerify(); - -private: - QString escapeFilename(const QString &name); - -private: - QDir m_baseDir; - bool m_tarAvailable = false; - bool m_isCygwin = false; -}; - -tst_PackageCreator::tst_PackageCreator() - : m_baseDir(qSL(AM_TESTDATA_DIR)) -{ } - -void tst_PackageCreator::initTestCase() -{ - processTimeout *= timeoutFactor(); - - // check if tar command is available at all - QProcess tar; - tar.start(qSL("tar"), { qSL("--version") }); - m_tarAvailable = tar.waitForStarted(processTimeout) - && tar.waitForFinished(processTimeout) - && (tar.exitStatus() == QProcess::NormalExit); - - m_isCygwin = tar.readAllStandardOutput().contains("Cygwin"); - - QVERIFY(PackageUtilities::checkCorrectLocale()); -} - -void tst_PackageCreator::createAndVerify_data() -{ - QTest::addColumn("files"); - QTest::addColumn("expectedSuccess"); - QTest::addColumn("errorString"); - - QTest::newRow("basic") << QStringList { qSL("testfile") } << true << QString(); - QTest::newRow("no-such-file") << QStringList { qSL("tastfile") } << false << qSL("~file not found: .*"); -} - -void tst_PackageCreator::createAndVerify() -{ - QFETCH(QStringList, files); - QFETCH(bool, expectedSuccess); - QFETCH(QString, errorString); - - QTemporaryFile output; - QVERIFY(output.open()); - - InstallationReport report(qSL("com.pelagicore.test")); - report.addFiles(files); - - PackageCreator creator(m_baseDir, &output, report); - bool result = creator.create(); - output.close(); - - if (expectedSuccess) { - QVERIFY2(result, qPrintable(creator.errorString())); - } else { - QVERIFY(creator.errorCode() != Error::None); - QVERIFY(creator.errorCode() != Error::Canceled); - QVERIFY(!creator.wasCanceled()); - - AM_CHECK_ERRORSTRING(creator.errorString(), errorString); - return; - } - - // check the tar listing - if (!m_tarAvailable) - QSKIP("No tar command found in PATH - skipping the verification part of the test!"); - - QProcess tar; - tar.start(qSL("tar"), { qSL("-tzf"), escapeFilename(output.fileName()) }); - QVERIFY2(tar.waitForStarted(processTimeout) && - tar.waitForFinished(processTimeout) && - (tar.exitStatus() == QProcess::NormalExit) && - (tar.exitCode() == 0), qPrintable(tar.errorString())); - - QStringList expectedContents = files; - expectedContents.sort(); - expectedContents.prepend(qSL("--PACKAGE-HEADER--")); - expectedContents.append(qSL("--PACKAGE-FOOTER--")); - - QStringList actualContents = QString::fromLocal8Bit(tar.readAllStandardOutput()).split(qL1C('\n'), Qt::SkipEmptyParts); -#if defined(Q_OS_WIN) - actualContents.replaceInStrings(qSL("\r"), QString()); -#endif - QCOMPARE(actualContents, expectedContents); - - // check the contents of the files - - for (const QString &file : qAsConst(files)) { - QFile src(m_baseDir.absoluteFilePath(file)); - QVERIFY2(src.open(QFile::ReadOnly), qPrintable(src.errorString())); - QByteArray data = src.readAll(); - - tar.start(qSL("tar"), { qSL("-xzOf"), escapeFilename(output.fileName()), file }); - QVERIFY2(tar.waitForStarted(processTimeout) && - tar.waitForFinished(processTimeout) && - (tar.exitStatus() == QProcess::NormalExit) && - (tar.exitCode() == 0), qPrintable(tar.errorString())); - - QCOMPARE(tar.readAllStandardOutput(), data); - } -} - -QString tst_PackageCreator::escapeFilename(const QString &name) -{ - if (!m_isCygwin) { - return name; - } else { - QString s = QFileInfo(name).absoluteFilePath(); - QString t = qSL("/cygdrive/"); - t.append(s.at(0)); - return t + s.mid(2); - } -} - -int main(int argc, char *argv[]) -{ - PackageUtilities::ensureCorrectLocale(); - QCoreApplication app(argc, argv); - app.setAttribute(Qt::AA_Use96Dpi, true); - tst_PackageCreator tc; - QTEST_SET_MAIN_SOURCE_PATH - return QTest::qExec(&tc, argc, argv); -} - -#include "tst_packagecreator.moc" diff --git a/tests/packageextractor/packageextractor.pro b/tests/packageextractor/packageextractor.pro deleted file mode 100644 index 761720cf..00000000 --- a/tests/packageextractor/packageextractor.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = tst_packageextractor - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_application-private \ - appman_package-private - -SOURCES += tst_packageextractor.cpp diff --git a/tests/packageextractor/tst_packageextractor.cpp b/tests/packageextractor/tst_packageextractor.cpp deleted file mode 100644 index 50dd78a6..00000000 --- a/tests/packageextractor/tst_packageextractor.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#if defined(Q_OS_UNIX) -# include -# include -# include -#endif - -#include "global.h" -#include "packageextractor.h" -#include "installationreport.h" -#include "packageutilities.h" - -#include "../error-checking.h" - -QT_USE_NAMESPACE_AM - -class tst_PackageExtractor : public QObject -{ - Q_OBJECT - -public: - tst_PackageExtractor(); - -private slots: - void initTestCase(); - void init(); - void cleanup(); - - void extractAndVerify_data(); - void extractAndVerify(); - - void cancelExtraction(); - - void extractFromFifo(); - -private: - QString m_taest; - QScopedPointer m_extractDir; -}; - -tst_PackageExtractor::tst_PackageExtractor() - : m_taest(QString::fromUtf8("t\xc3\xa4st")) -{ } - -void tst_PackageExtractor::initTestCase() -{ - if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) - QSKIP("No test packages available in the data/ directory"); - - QVERIFY(PackageUtilities::checkCorrectLocale()); -} - -void tst_PackageExtractor::init() -{ - m_extractDir.reset(new QTemporaryDir()); - QVERIFY(m_extractDir->isValid()); -} - -void tst_PackageExtractor::cleanup() -{ - m_extractDir.reset(); -} - -void tst_PackageExtractor::extractAndVerify_data() -{ - QTest::addColumn("path"); - QTest::addColumn("expectedSuccess"); - QTest::addColumn("errorString"); - QTest::addColumn("entries"); - QTest::addColumn>("content"); - QTest::addColumn>("sizes"); - - QStringList noEntries; - QMap noContent; - QMap noSizes; - - QTest::newRow("normal") << "packages/test.appkg" - << true << QString() - << QStringList { - "info.yaml", - "icon.png", - "test", - m_taest } - << QMap { - { "test", "test\n" }, - { m_taest, "test with umlaut\n" } } - << noSizes; - - QTest::newRow("big") << "packages/bigtest.appkg" - << true << QString() - << QStringList { - "info.yaml", - "icon.png", - "test", - m_taest, - "bigtest" } - << QMap { - { "test", "test\n" }, - { m_taest, "test with umlaut\n" } } - << QMap { - // { "info.yaml", 213 }, // this is different on Windows: \n vs. \r\n - { "icon.png", 1157 }, - { "bigtest", 5*1024*1024 }, - { "test", 5 }, - { m_taest, 17 } }; - - QTest::newRow("invalid-url") << "packages/no-such-file.appkg" - << false << "~Error opening .*: (No such file or directory|The system cannot find the file specified\\.)" - << noEntries << noContent << noSizes; - QTest::newRow("invalid-format") << "packages/test-invalid-format.appkg" - << false << "~.* could not open archive: Unrecognized archive format" - << noEntries << noContent << noSizes; - QTest::newRow("invalid-digest") << "packages/test-invalid-footer-digest.appkg" - << false << "~package digest mismatch.*" - << noEntries << noContent << noSizes; - QTest::newRow("invalid-path") << "packages/test-invalid-path.appkg" - << false << "~invalid archive entry .*: pointing outside of extraction directory" - << noEntries << noContent << noSizes; -} - -void tst_PackageExtractor::extractAndVerify() -{ - // macros are stupid... - typedef QMap ByteArrayMap; - typedef QMap IntMap; - - QFETCH(QString, path); - QFETCH(bool, expectedSuccess); - QFETCH(QString, errorString); - QFETCH(QStringList, entries); - QFETCH(ByteArrayMap, content); - QFETCH(IntMap, sizes); - - PackageExtractor extractor(QUrl::fromLocalFile(AM_TESTDATA_DIR + path), m_extractDir->path()); - bool result = extractor.extract(); - - if (expectedSuccess) { - QVERIFY2(result, qPrintable(extractor.errorString())); - } else { - QVERIFY(extractor.errorCode() != Error::None); - QVERIFY(extractor.errorCode() != Error::Canceled); - QVERIFY(!extractor.wasCanceled()); - - AM_CHECK_ERRORSTRING(extractor.errorString(), errorString); - return; - } - - QStringList checkEntries(entries); - QDirIterator it(m_extractDir->path(), QDir::NoDotAndDotDot | QDir::AllEntries, QDirIterator::Subdirectories); - while (it.hasNext()) { - QString entry = it.next(); - entry = entry.mid(m_extractDir->path().size() + 1); - - QVERIFY2(checkEntries.contains(entry), qPrintable(entry)); - - if (content.contains(entry)) { - QVERIFY(QDir(m_extractDir->path()).exists(entry)); - QFile f(QDir(m_extractDir->path()).absoluteFilePath(entry)); - QVERIFY(f.open(QFile::ReadOnly)); - QCOMPARE(f.readAll(), content.value(entry)); - } - - if (sizes.contains(entry)) { - QVERIFY(QDir(m_extractDir->path()).exists(entry)); - QFile f(QDir(m_extractDir->path()).absoluteFilePath(entry)); - QCOMPARE(f.size(), sizes.value(entry)); - } - - QVERIFY(checkEntries.removeOne(entry)); - } - - QVERIFY2(checkEntries.isEmpty(), qPrintable(checkEntries.join(qL1C(' ')))); - - QStringList reportEntries = extractor.installationReport().files(); - reportEntries.sort(); - entries.sort(); - QCOMPARE(reportEntries, entries); -} - -void tst_PackageExtractor::cancelExtraction() -{ - { - PackageExtractor extractor(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test.appkg")), m_extractDir->path()); - extractor.cancel(); - QVERIFY(!extractor.extract()); - QVERIFY(extractor.wasCanceled()); - QVERIFY(extractor.errorCode() == Error::Canceled); - QVERIFY(extractor.hasFailed()); - } - { - PackageExtractor extractor(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test.appkg")), m_extractDir->path()); - connect(&extractor, &PackageExtractor::progress, this, [&extractor](qreal p) { - if (p >= 0.1) - extractor.cancel(); - }); - QVERIFY(!extractor.extract()); - QVERIFY(extractor.wasCanceled()); - QVERIFY(extractor.errorCode() == Error::Canceled); - QVERIFY(extractor.hasFailed()); - } -} - -class FifoSource : public QThread // clazy:exclude=missing-qobject-macro -{ -public: - FifoSource(const QString &file) - : m_file(file) - { - m_fifoPath = QDir::temp().absoluteFilePath(qSL("autotext-package-extractor-%1.fifo")) - .arg(QCoreApplication::applicationPid()) - .toLocal8Bit(); -#ifdef Q_OS_UNIX - QVERIFY2(m_file.open(QFile::ReadOnly), qPrintable(m_file.errorString())); - QVERIFY2(::mkfifo(m_fifoPath, 0600) == 0, ::strerror(errno)); -#endif - } - - ~FifoSource() - { -#ifdef Q_OS_UNIX - ::unlink(m_fifoPath); -#endif - } - - QString path() const - { - return QString::fromLocal8Bit(m_fifoPath); - } - - void run() override - { -#ifdef Q_OS_UNIX - int fifoFd = QT_OPEN(m_fifoPath, O_WRONLY); - QVERIFY2(fifoFd >= 0, ::strerror(errno)); - - QByteArray buffer; - buffer.resize(1024 * 1024); - - while (!m_file.atEnd()) { - qint64 bytesRead = m_file.read(buffer.data(), buffer.size()); - QVERIFY(bytesRead >= 0); - qint64 bytesWritten = QT_WRITE(fifoFd, buffer.constData(), bytesRead); - QCOMPARE(bytesRead, bytesWritten); - } - QT_CLOSE(fifoFd); -#endif - } - -private: - QFile m_file; - QByteArray m_fifoPath; -}; - -void tst_PackageExtractor::extractFromFifo() -{ -#if !defined(Q_OS_UNIX) - QSKIP("No FIFO support on this platform"); -#endif - - FifoSource fifo(qL1S(AM_TESTDATA_DIR "packages/test.appkg")); - fifo.start(); - - PackageExtractor extractor(QUrl::fromLocalFile(fifo.path()), m_extractDir->path()); - QVERIFY2(extractor.extract(), qPrintable(extractor.errorString())); - QTRY_VERIFY(fifo.isFinished()); -} - -int main(int argc, char *argv[]) -{ - PackageUtilities::ensureCorrectLocale(); - QCoreApplication app(argc, argv); - app.setAttribute(Qt::AA_Use96Dpi, true); - tst_PackageExtractor tc; - QTEST_SET_MAIN_SOURCE_PATH - return QTest::qExec(&tc, argc, argv); -} - -#include "tst_packageextractor.moc" diff --git a/tests/packager-tool/packager-tool.pro b/tests/packager-tool/packager-tool.pro deleted file mode 100644 index 08876ac6..00000000 --- a/tests/packager-tool/packager-tool.pro +++ /dev/null @@ -1,15 +0,0 @@ -TARGET = tst_packager-tool - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_crypto-private \ - appman_application-private \ - appman_package-private \ - appman_manager-private \ - -INCLUDEPATH += $$PWD/../../src/tools/packager -SOURCES += $$PWD/../../src/tools/packager/packagingjob.cpp - -SOURCES += tst_packager-tool.cpp diff --git a/tests/packager-tool/tst_packager-tool.cpp b/tests/packager-tool/tst_packager-tool.cpp deleted file mode 100644 index 7826caee..00000000 --- a/tests/packager-tool/tst_packager-tool.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "global.h" -#include "applicationmanager.h" -#include "application.h" -#include "qtyaml.h" -#include "exception.h" -#include "packagedatabase.h" -#include "packagemanager.h" -#include "packagingjob.h" -#include "qmlinprocessruntime.h" -#include "runtimefactory.h" -#include "utilities.h" - -#include "../error-checking.h" - -QT_USE_NAMESPACE_AM - -static int spyTimeout = 5000; // shorthand for specifying QSignalSpy timeouts - -class tst_PackagerTool : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void initTestCase(); - void cleanup(); - - void test(); - void brokenMetadata_data(); - void brokenMetadata(); - void iconFileName(); - -private: - QString pathTo(const char *file) - { - return QDir(m_workDir.path()).absoluteFilePath(QLatin1String(file)); - } - - bool createInfoYaml(QTemporaryDir &tmp, const QString &changeField = QString(), const QVariant &toValue = QVariant()); - bool createIconPng(QTemporaryDir &tmp); - bool createCode(QTemporaryDir &tmp); - void createDummyFile(QTemporaryDir &tmp, const QString &fileName, const char *data); - - void installPackage(const QString &filePath); - - PackageManager *m_pm = nullptr; - QTemporaryDir m_workDir; - - QString m_devPassword; - QString m_devCertificate; - QString m_storePassword; - QString m_storeCertificate; - QStringList m_caFiles; - QString m_hardwareId; -}; - -void tst_PackagerTool::initTestCase() -{ - if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) - QSKIP("No test packages available in the data/ directory"); - - spyTimeout *= timeoutFactor(); - - QVERIFY(m_workDir.isValid()); - QVERIFY(QDir::root().mkpath(pathTo("internal-0"))); - QVERIFY(QDir::root().mkpath(pathTo("documents-0"))); - - m_hardwareId = qSL("foobar"); - - PackageDatabase *pdb = new PackageDatabase({}, pathTo("internal-0")); - try { - m_pm = PackageManager::createInstance(pdb, pathTo("documents-0")); - m_pm->setHardwareId(m_hardwareId); - m_pm->enableInstaller(); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - - QVERIFY(ApplicationManager::createInstance(true)); - - - // crypto stuff - we need to load the root CA and developer CA certificates - - QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt")); - QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt")); - QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); - QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); - - QList chainOfTrust; - chainOfTrust << devcaFile.readAll() << caFile.readAll(); - QVERIFY(!chainOfTrust.at(0).isEmpty()); - QVERIFY(!chainOfTrust.at(1).isEmpty()); - m_pm->setCACertificates(chainOfTrust); - - m_caFiles << devcaFile.fileName() << caFile.fileName(); - - m_devPassword = qSL("password"); - m_devCertificate = qL1S(AM_TESTDATA_DIR "certificates/dev1.p12"); - m_storePassword = qSL("password"); - m_storeCertificate = qL1S(AM_TESTDATA_DIR "certificates/store.p12"); - - RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("qml"))); -} - -void tst_PackagerTool::cleanup() -{ - recursiveOperation(pathTo("internal-0"), safeRemove); - recursiveOperation(pathTo("documents-0"), safeRemove); - - QDir dir(m_workDir.path()); - QStringList fileNames = dir.entryList(QDir::Files); - for (auto fileName : fileNames) - dir.remove(fileName); -} - -// exceptions are nice -- just not for unit testing :) -static bool packagerCheck(PackagingJob *p, QString &errorString) -{ - bool result = false; - try { - p->execute(); - errorString.clear(); - result = (p->resultCode() == 0); - if (!result) - errorString = p->output(); - } catch (const Exception &e) { \ - errorString = e.errorString(); - } - delete p; - return result; -} - -void tst_PackagerTool::test() -{ - QTemporaryDir tmp; - QString errorString; - - // no valid destination - QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), pathTo("test.appkg")), errorString)); - QVERIFY2(errorString.contains(qL1S("is not a directory")), qPrintable(errorString)); - - // no valid info.yaml - QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); - QVERIFY2(errorString.contains(qL1S("Cannot open for reading")), qPrintable(errorString)); - - // add an info.yaml file - createInfoYaml(tmp); - - // no icon - QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); - QVERIFY2(errorString.contains(qL1S("missing the file referenced by the 'icon' field")), qPrintable(errorString)); - - // add an icon - createIconPng(tmp); - - // no valid code - QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString)); - QVERIFY2(errorString.contains(qL1S("missing the file referenced by the 'code' field")), qPrintable(errorString)); - - // add a code file - createCode(tmp); - - // invalid destination - QVERIFY(!packagerCheck(PackagingJob::create(tmp.path(), tmp.path()), errorString)); - QVERIFY2(errorString.contains(qL1S("could not create package file")), qPrintable(errorString)); - - // now everything is correct - try again - QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), errorString), qPrintable(errorString)); - - // invalid source package - QVERIFY(!packagerCheck(PackagingJob::developerSign( - pathTo("no-such-file"), - pathTo("test.dev-signed.appkg"), - m_devCertificate, - m_devPassword), errorString)); - QVERIFY2(errorString.contains(qL1S("does not exist")), qPrintable(errorString)); - - // invalid destination package - QVERIFY(!packagerCheck(PackagingJob::developerSign( - pathTo("test.appkg"), - pathTo("."), - m_devCertificate, - m_devPassword), errorString)); - QVERIFY2(errorString.contains(qL1S("could not create package file")), qPrintable(errorString)); - - - // invalid dev key - QVERIFY(!packagerCheck(PackagingJob::developerSign( - pathTo("test.appkg"), - pathTo("test.dev-signed.appkg"), - m_devCertificate, - qSL("wrong-password")), errorString)); - QVERIFY2(errorString.contains(qL1S("could not create signature")), qPrintable(errorString)); - - // invalid store key - QVERIFY(!packagerCheck(PackagingJob::storeSign( - pathTo("test.appkg"), - pathTo("test.store-signed.appkg"), - m_storeCertificate, - qSL("wrong-password"), - m_hardwareId), errorString)); - QVERIFY2(errorString.contains(qL1S("could not create signature")), qPrintable(errorString)); - - // sign - QVERIFY2(packagerCheck(PackagingJob::developerSign( - pathTo("test.appkg"), - pathTo("test.dev-signed.appkg"), - m_devCertificate, - m_devPassword), errorString), qPrintable(errorString)); - - QVERIFY2(packagerCheck(PackagingJob::storeSign( - pathTo("test.appkg"), - pathTo("test.store-signed.appkg"), - m_storeCertificate, - m_storePassword, - m_hardwareId), errorString), qPrintable(errorString)); - - // verify - QVERIFY2(packagerCheck(PackagingJob::developerVerify( - pathTo("test.dev-signed.appkg"), - m_caFiles), errorString), qPrintable(errorString)); - - QVERIFY2(packagerCheck(PackagingJob::storeVerify( - pathTo("test.store-signed.appkg"), - m_caFiles, - m_hardwareId), errorString), qPrintable(errorString)); - - // now that we have it, see if the package actually installs correctly - - installPackage(pathTo("test.dev-signed.appkg")); - - QDir checkDir(pathTo("internal-0")); - QVERIFY(checkDir.cd(qSL("com.pelagicore.test"))); - - for (const QString &file : { qSL("info.yaml"), qSL("icon.png"), qSL("test.qml") }) { - QVERIFY(checkDir.exists(file)); - QFile src(QDir(tmp.path()).absoluteFilePath(file)); - QVERIFY(src.open(QFile::ReadOnly)); - QFile dst(checkDir.absoluteFilePath(file)); - QVERIFY(dst.open(QFile::ReadOnly)); - QCOMPARE(src.readAll(), dst.readAll()); - } -} - -void tst_PackagerTool::brokenMetadata_data() -{ - QTest::addColumn("yamlField"); - QTest::addColumn("yamlValue"); - QTest::addColumn("errorString"); - - QTest::newRow("missing-name") << qSL("name") << QVariant() << "~.*Required fields are missing: name.*"; - QTest::newRow("missing-runtime") << qSL("runtime") << QVariant() << "~.*Required fields are missing: runtime"; - QTest::newRow("missing-identifier") << qSL("id") << QVariant() << "~.*Required fields are missing: id"; - QTest::newRow("missing-code") << qSL("code") << QVariant() << "~.*Required fields are missing: code"; -} - -void tst_PackagerTool::brokenMetadata() -{ - QFETCH(QString, yamlField); - QFETCH(QVariant, yamlValue); - QFETCH(QString, errorString); - - QTemporaryDir tmp; - - createCode(tmp); - createIconPng(tmp); - createInfoYaml(tmp, yamlField, yamlValue); - - // check if packaging actually fails with the expected error - - QString error; - QVERIFY2(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error), qPrintable(error)); - AM_CHECK_ERRORSTRING(error, errorString); -} - -/* - Specify an icon whose name is different from "icon.png". - Packaging should work fine - */ -void tst_PackagerTool::iconFileName() -{ - QTemporaryDir tmp; - QString errorString; - - createInfoYaml(tmp, qSL("icon"), qSL("foo.bar")); - createCode(tmp); - createDummyFile(tmp, qSL("foo.bar"), "this-is-a-dummy-icon-file"); - - QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test-foobar-icon.appkg"), tmp.path()), errorString), - qPrintable(errorString)); - - // see if the package installs correctly - - m_pm->setAllowInstallationOfUnsignedPackages(true); - installPackage(pathTo("test-foobar-icon.appkg")); - m_pm->setAllowInstallationOfUnsignedPackages(false); - - QDir checkDir(pathTo("internal-0")); - QVERIFY(checkDir.cd(qSL("com.pelagicore.test"))); - - for (const QString &file : { qSL("info.yaml"), qSL("foo.bar"), qSL("test.qml") }) { - QVERIFY(checkDir.exists(file)); - QFile src(QDir(tmp.path()).absoluteFilePath(file)); - QVERIFY(src.open(QFile::ReadOnly)); - QFile dst(checkDir.absoluteFilePath(file)); - QVERIFY(dst.open(QFile::ReadOnly)); - QCOMPARE(src.readAll(), dst.readAll()); - } -} - - -bool tst_PackagerTool::createInfoYaml(QTemporaryDir &tmp, const QString &changeField, const QVariant &toValue) -{ - QByteArray yaml = - "formatVersion: 1\n" - "formatType: am-application\n" - "---\n" - "id: com.pelagicore.test\n" - "name: { en_US: 'test' }\n" - "icon: icon.png\n" - "code: test.qml\n" - "runtime: qml\n"; - - if (!changeField.isEmpty()) { - QVector docs; - try { - docs = YamlParser::parseAllDocuments(yaml); - } catch (...) { - } - - QVariantMap map = docs.at(1).toMap(); - if (!toValue.isValid()) - map.remove(changeField); - else - map[changeField] = toValue; - yaml = QtYaml::yamlFromVariantDocuments({ docs.at(0), map }); - } - - QFile infoYaml(QDir(tmp.path()).absoluteFilePath(qSL("info.yaml"))); - return infoYaml.open(QFile::WriteOnly) && infoYaml.write(yaml) == yaml.size(); -} - -bool tst_PackagerTool::createIconPng(QTemporaryDir &tmp) -{ - QFile iconPng(QDir(tmp.path()).absoluteFilePath(qSL("icon.png"))); - return iconPng.open(QFile::WriteOnly) && iconPng.write("\x89PNG") == 4; -} - -bool tst_PackagerTool::createCode(QTemporaryDir &tmp) -{ - QFile code(QDir(tmp.path()).absoluteFilePath(qSL("test.qml"))); - return code.open(QFile::WriteOnly) && code.write("// test") == 7LL; -} - -void tst_PackagerTool::createDummyFile(QTemporaryDir &tmp, const QString &fileName, const char *data) -{ - QFile code(QDir(tmp.path()).absoluteFilePath(fileName)); - QVERIFY(code.open(QFile::WriteOnly)); - - auto written = code.write(data); - - QCOMPARE(written, static_cast(strlen(data))); -} - -void tst_PackagerTool::installPackage(const QString &filePath) -{ - QSignalSpy finishedSpy(m_pm, &PackageManager::taskFinished); - - m_pm->setDevelopmentMode(true); // allow packages without store signature - - QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(filePath)); - m_pm->acknowledgePackageInstallation(taskId); - - QVERIFY(finishedSpy.wait(2 * spyTimeout)); - QCOMPARE(finishedSpy.first()[0].toString(), taskId); - - m_pm->setDevelopmentMode(false); -} - -QTEST_GUILESS_MAIN(tst_PackagerTool) - -#include "tst_packager-tool.moc" diff --git a/tests/processreader/advanced.smaps b/tests/processreader/advanced.smaps deleted file mode 100644 index 61212565..00000000 --- a/tests/processreader/advanced.smaps +++ /dev/null @@ -1,252 +0,0 @@ -55e362f85000-55e36315a000 r-xp 00000000 08:05 20988510 /qtbase/bin/appman -Size: 1876 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 1704 kB -Pss: 1704 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 1704 kB -Private_Dirty: 0 kB -Referenced: 1704 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 1704 kB -VmFlags: rd ex mr mw me dw ?? sd -55e36315b000-55e363162000 r--p 001d5000 08:05 20988510 /qtbase/bin/appman -Size: 28 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 28 kB -Pss: 28 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 28 kB -Referenced: 28 kB -Anonymous: 28 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 28 kB -VmFlags: rd mr mw me dw ac ?? sd -55e363162000-55e363164000 rw-p 001dc000 08:05 20988510 /qtbase/bin/appman -Size: 8 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 8 kB -Pss: 8 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 8 kB -Referenced: 8 kB -Anonymous: 8 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 8 kB -VmFlags: rd wr mr mw me dw ac ?? sd -55e363164000-55e363166000 rw-p 00000000 00:00 0 -Size: 8 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 4 kB -Pss: 4 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 4 kB -Referenced: 4 kB -Anonymous: 4 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 4 kB -VmFlags: rd wr mr mw me ac sd -55e3645eb000-55e364c57000 rw-p 00000000 00:00 0 [heap] -Size: 6576 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 6288 kB -Pss: 6288 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 6288 kB -Referenced: 6288 kB -Anonymous: 6288 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 6288 kB -VmFlags: rd wr mr mw me ac sd -7f85d0000000-7f85d093a000 rw-p 00000000 00:00 0 -Size: 9448 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 9448 kB -Pss: 9448 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 9448 kB -Referenced: 9448 kB -Anonymous: 9448 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 9448 kB -VmFlags: rd wr mr mw me nr sd -7f85d093a000-7f85d4000000 ---p 00000000 00:00 0 -Size: 56088 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: mr mw me nr sd -7f85d5fef000-7f85d632d000 rw-s 00000000 00:2e 19336830 /run/user/1000/wayland-cursor-shared-jzyii9 (deleted) -Size: 3320 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd wr sh mr mw me ms sd -7f85d63c5000-7f85d63fc000 r-xp 00000000 08:01 4984507 /lib/x86_64-linux-gnu/libnss_systemd.so.2 -Size: 220 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 64 kB -Pss: 3 kB -Shared_Clean: 64 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 64 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 3 kB -VmFlags: rd ex mr mw me sd -7ffd75741000-7ffd75763000 rw-p 00000000 00:00 0 [stack] -Size: 136 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 64 kB -Pss: 64 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 64 kB -Referenced: 64 kB -Anonymous: 64 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 64 kB -VmFlags: rd wr mr mw me gd ac -7ffd757e9000-7ffd757ec000 r--p 00000000 00:00 0 [vvar] -Size: 12 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd mr pf io de dd sd -7ffd757ec000-7ffd757ee000 r-xp 00000000 00:00 0 [vdso] -Size: 8 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 4 kB -Pss: 0 kB -Shared_Clean: 4 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 4 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd ex mr mw me de sd diff --git a/tests/processreader/basic.smaps b/tests/processreader/basic.smaps deleted file mode 100644 index 00640230..00000000 --- a/tests/processreader/basic.smaps +++ /dev/null @@ -1,352 +0,0 @@ -00400000-00413000 r-xp 00000000 b3:01 266877 application -Size: 76 kB -Rss: 76 kB -Pss: 38 kB -Shared_Clean: 76 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 76 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex mr mw me dw -00422000-00423000 rw-p 00012000 b3:01 266877 application -Size: 4 kB -Rss: 4 kB -Pss: 4 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 4 kB -Referenced: 4 kB -Anonymous: 4 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me dw ac -00423000-004ec000 rw-p 00000000 00:00 0 [heap] -Size: 804 kB -Rss: 796 kB -Pss: 796 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 796 kB -Referenced: 796 kB -Anonymous: 796 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -004ed000-00bc9000 rw-p 00000000 00:00 0 [heap] -Size: 7024 kB -Rss: 6700 kB -Pss: 6700 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 6700 kB -Referenced: 6700 kB -Anonymous: 6700 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -7f54000000-7f54021000 rw-p 00000000 00:00 0 -Size: 132 kB -Rss: 4 kB -Pss: 4 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 4 kB -Referenced: 4 kB -Anonymous: 4 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me nr -7f54021000-7f58000000 ---p 00000000 00:00 0 -Size: 65404 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: mr mw me nr -7f5c000000-7f5c00a000 rw-p 00000000 00:00 0 -Size: 40 kB -Rss: 40 kB -Pss: 40 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 40 kB -Referenced: 40 kB -Anonymous: 40 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me nr -7f600d1000-7f604d1000 rw-s 00000000 00:09 12516 anon_inode:dmabuf -Size: 4096 kB -Rss: 1656 kB -Pss: 828 kB -Shared_Clean: 0 kB -Shared_Dirty: 1656 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 1656 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr sh mr mw me ms dc de dd -7f604d1000-7f608d1000 rw-s 00000000 00:09 12516 anon_inode:dmabuf -Size: 4096 kB -Rss: 4084 kB -Pss: 2042 kB -Shared_Clean: 0 kB -Shared_Dirty: 4084 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 4084 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr sh mr mw me ms dc de dd -7f614d2000-7f6168a000 r-xp 00000000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so -Size: 1760 kB -Rss: 1448 kB -Pss: 726 kB -Shared_Clean: 1444 kB -Shared_Dirty: 0 kB -Private_Clean: 4 kB -Private_Dirty: 0 kB -Referenced: 1448 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex mr mw me -7f6168a000-7f61699000 ---p 001b8000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so -Size: 60 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: mr mw me -7f61699000-7f616a0000 rw-p 001b7000 b3:01 12487 /verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/verylonglibrarypathname/lib.so -Size: 28 kB -Rss: 28 kB -Pss: 28 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 28 kB -Referenced: 28 kB -Anonymous: 28 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -7f61925000-7f61ef7000 r-xp 00000000 b3:01 13766 /linelength98/linelen.so -Size: 5960 kB -Rss: 4356 kB -Pss: 1554 kB -Shared_Clean: 4264 kB -Shared_Dirty: 0 kB -Private_Clean: 92 kB -Private_Dirty: 0 kB -Referenced: 4356 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex mr mw me -7f61ef7000-7f61f07000 ---p 005d2000 b3:01 13766 /linelength99/lineleng.so -Size: 64 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: mr mw me -7f61f07000-7f6204c000 rw-p 005d2000 b3:01 13766 /linelength100/lineleng.so -Size: 1300 kB -Rss: 1084 kB -Pss: 986 kB -Shared_Clean: 156 kB -Shared_Dirty: 0 kB -Private_Clean: 24 kB -Private_Dirty: 904 kB -Referenced: 1084 kB -Anonymous: 904 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -7f74146000-7f74945000 rw-p 00000000 00:00 0 [stack:3396] -Size: 8188 kB -Rss: 8 kB -Pss: 8 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 8 kB -Referenced: 8 kB -Anonymous: 8 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -7f74946000-7f75145000 rw-p 00000000 00:00 0 [stack:3116] -Size: 8188 kB -Rss: 8 kB -Pss: 8 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 8 kB -Referenced: 8 kB -Anonymous: 8 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac -7f78fff000-7f79001000 rw-s 00000000 00:16 37047 /tmp/.gl3LHuLJ (deleted) -Size: 8 kB -Rss: 8 kB -Pss: 8 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 8 kB -Referenced: 8 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr sh mr mw me ms -7f79001000-7f79003000 r-xs 00000000 00:16 37047 /tmp/.gl3LHuLJ (deleted) -Size: 8 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex sh mr mw me ms -7f79005000-7f79006000 r--p 00000000 00:00 0 [vvar] -Size: 4 kB -Rss: 4 kB -Pss: 0 kB -Shared_Clean: 4 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 4 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd mr de -7f79006000-7f79007000 r-xp 00000000 00:00 0 [vdso] -Size: 4 kB -Rss: 4 kB -Pss: 0 kB -Shared_Clean: 4 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 4 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex mr mw me de -7ffc8f6000-7ffc917000 rw-p 00000000 00:00 0 [stack] -Size: 136 kB -Rss: 44 kB -Pss: 44 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 44 kB -Referenced: 44 kB -Anonymous: 44 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me gd ac diff --git a/tests/processreader/invalid.smaps b/tests/processreader/invalid.smaps deleted file mode 100644 index 146a42b8..00000000 --- a/tests/processreader/invalid.smaps +++ /dev/null @@ -1,16 +0,0 @@ -00400000-00413000 r-xp 00000000 b3:01 266877 application -Size: #missing -Rss: 76 kB -Pss: 38 kB -Shared_Clean: 76 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 76 kB -Anonymous: 0 kB -AnonHugePages: 0 kB -Swap: 0 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Locked: 0 kB -VmFlags: rd ex mr mw me dw diff --git a/tests/processreader/processreader.pro b/tests/processreader/processreader.pro deleted file mode 100644 index c5caa674..00000000 --- a/tests/processreader/processreader.pro +++ /dev/null @@ -1,11 +0,0 @@ -TARGET = tst_processreader - -include($$PWD/../tests.pri) - -QT *= appman_monitor-private \ - appman_manager-private \ - appman_window-private \ - appman_application-private \ - appman_common-private - -SOURCES += tst_processreader.cpp diff --git a/tests/processreader/tst_processreader.cpp b/tests/processreader/tst_processreader.cpp deleted file mode 100644 index baec84cb..00000000 --- a/tests/processreader/tst_processreader.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -QT_USE_NAMESPACE_AM - -class tst_ProcessReader : public QObject -{ - Q_OBJECT - -public: - tst_ProcessReader(); - -private slots: - void memInvalid_data(); - void memInvalid(); - void memTestProcess(); - void memBasic(); - void memAdvanced(); - -private: - void printMem(const ProcessReader &reader); - ProcessReader reader; -}; - -tst_ProcessReader::tst_ProcessReader() -{} - -void tst_ProcessReader::memInvalid_data() -{ - QTest::addColumn("file"); - - QTest::newRow("arbitrary") << QFINDTESTDATA("tst_processreader.cpp"); - QTest::newRow("binary") << QFINDTESTDATA("tst_processreader"); - QTest::newRow("missingvalue") << QFINDTESTDATA("invalid.smaps"); -} - -void tst_ProcessReader::memInvalid() -{ - QFETCH(QString, file); - - reader.testReadSmaps(file.toLocal8Bit()); - - QCOMPARE(reader.memory.totalVm, 0u); - QCOMPARE(reader.memory.totalRss, 0u); - QCOMPARE(reader.memory.totalPss, 0u); - QCOMPARE(reader.memory.textVm, 0u); - QCOMPARE(reader.memory.textRss, 0u); - QCOMPARE(reader.memory.textPss, 0u); - QCOMPARE(reader.memory.heapVm, 0u); - QCOMPARE(reader.memory.heapRss, 0u); - QCOMPARE(reader.memory.heapPss, 0u); -} - -void tst_ProcessReader::memTestProcess() -{ - const QByteArray file = "/proc/" + QByteArray::number(QCoreApplication::applicationPid()) + "/smaps"; - - QVERIFY(reader.testReadSmaps(file)); - //printMem(reader); - QVERIFY(reader.memory.totalVm >= reader.memory.totalRss); - QVERIFY(reader.memory.totalRss >= reader.memory.totalPss); - QVERIFY(reader.memory.textVm >= reader.memory.textRss); - QVERIFY(reader.memory.textRss >= reader.memory.textPss); - QVERIFY(reader.memory.heapVm >= reader.memory.heapRss); - QVERIFY(reader.memory.heapRss >= reader.memory.heapPss); -} - -void tst_ProcessReader::memBasic() -{ - QVERIFY(reader.testReadSmaps(QFINDTESTDATA("basic.smaps").toLocal8Bit())); - //printMem(reader); - QCOMPARE(reader.memory.totalVm, 107384u); - QCOMPARE(reader.memory.totalRss, 20352u); - QCOMPARE(reader.memory.totalPss, 13814u); - QCOMPARE(reader.memory.textVm, 7800u); - QCOMPARE(reader.memory.textRss, 5884u); - QCOMPARE(reader.memory.textPss, 2318u); - QCOMPARE(reader.memory.heapVm, 24376u); - QCOMPARE(reader.memory.heapRss, 7556u); - QCOMPARE(reader.memory.heapPss, 7556u); -} - -void tst_ProcessReader::memAdvanced() -{ - QVERIFY(reader.testReadSmaps(QFINDTESTDATA("advanced.smaps").toLocal8Bit())); - //printMem(reader); - QCOMPARE(reader.memory.totalVm, 77728u); - QCOMPARE(reader.memory.totalRss, 17612u); - QCOMPARE(reader.memory.totalPss, 17547u); - QCOMPARE(reader.memory.textVm, 2104u); - QCOMPARE(reader.memory.textRss, 1772u); - QCOMPARE(reader.memory.textPss, 1707u); - QCOMPARE(reader.memory.heapVm, 16032u); - QCOMPARE(reader.memory.heapRss, 15740u); - QCOMPARE(reader.memory.heapPss, 15740u); -} - -void tst_ProcessReader::printMem(const ProcessReader &reader) -{ - qDebug() << "totalVm:" << reader.memory.totalVm; - qDebug() << "totalRss:" << reader.memory.totalRss; - qDebug() << "totalPss:" << reader.memory.totalPss; - qDebug() << "textVm:" << reader.memory.textVm; - qDebug() << "textRss:" << reader.memory.textRss; - qDebug() << "textPss:" << reader.memory.textPss; - qDebug() << "heapVm:" << reader.memory.heapVm; - qDebug() << "heapRss:" << reader.memory.heapRss; - qDebug() << "heapPss:" << reader.memory.heapPss; -} - -QTEST_APPLESS_MAIN(tst_ProcessReader) - -#include "tst_processreader.moc" diff --git a/tests/qml/configs/am-config-nodbus.yaml b/tests/qml/configs/am-config-nodbus.yaml deleted file mode 100644 index 78030bf0..00000000 --- a/tests/qml/configs/am-config-nodbus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -systemProperties: - private: - nodbus: yes diff --git a/tests/qml/configs/am-config.yaml b/tests/qml/configs/am-config.yaml deleted file mode 100644 index 5333dae3..00000000 --- a/tests/qml/configs/am-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -# Workaround for a crash in the mesa software renderer (llvmpipe) -runtimes: - qml: - environmentVariables: - QT_QUICK_BACKEND: "software" diff --git a/tests/qml/configs/apps/test.configs.app/app.qml b/tests/qml/configs/apps/test.configs.app/app.qml deleted file mode 100644 index 07a5f413..00000000 --- a/tests/qml/configs/apps/test.configs.app/app.qml +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager 2.0 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - - onWindowPropertyChanged: { - if (name === "trigger" && value === "now") - root.setWindowProperty("ack", "done"); - } - - Notification { - id: notification - summary: "Test" - timeout: 20 - } - - ApplicationInterfaceExtension { - id: extension - name: "test.configs.interface" - - } - - Connections { - target: extension.object - function onTrigger(type) { - if (type === "Notification") { - if (target.func("bar") === 42) - notification.show(); - } else if (type === "PropertyChange") { - root.setWindowProperty("prop1", "bar"); - } - } - } - - Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } - } - - Component.onCompleted: { - setWindowProperty("prop1", "foo"); - } -} diff --git a/tests/qml/configs/apps/test.configs.app/icon.png b/tests/qml/configs/apps/test.configs.app/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/configs/apps/test.configs.app/icon.png and /dev/null differ diff --git a/tests/qml/configs/apps/test.configs.app/info.yaml b/tests/qml/configs/apps/test.configs.app/info.yaml deleted file mode 100644 index 401ed395..00000000 --- a/tests/qml/configs/apps/test.configs.app/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.configs.app' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -name: - en: 'ApplicationManager Application' diff --git a/tests/qml/configs/configs.pro b/tests/qml/configs/configs.pro deleted file mode 100644 index 86604d5e..00000000 --- a/tests/qml/configs/configs.pro +++ /dev/null @@ -1,15 +0,0 @@ -load(am-config) - -AM_CONFIG = am-config.yaml -TEST_FILES = tst_configs.qml -TEST_APPS = test.configs.app -TEST_CONFIGURATIONS = "--force-single-process" \ - "--force-single-process --single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" -multi-process { - TEST_CONFIGURATIONS += "--force-multi-process" \ - "-c $$_PRO_FILE_PWD_/am-config-nodbus.yaml --dbus none" \ - "--single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" \ - "--disable-installer --wayland-socket-name wayland-am" -} - -load(am-qml-testcase) diff --git a/tests/qml/configs/tst_configs.qml b/tests/qml/configs/tst_configs.qml deleted file mode 100644 index 88c7bd48..00000000 --- a/tests/qml/configs/tst_configs.qml +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - - -TestCase { - id: testCase - when: windowShown - name: "Configs" - visible: true - - - ApplicationIPCInterface { - id: appif - signal trigger(string type) - readonly property var _decltype_func: { "int": [ "string" ] } - function func(str) { return str === "bar" ? 42: 0; } - Component.onCompleted: ApplicationIPCManager.registerInterface(this, "test.configs.interface", {}); - } - - SignalSpy { - id: windowAddedSpy - target: WindowManager - signalName: "windowAdded" - } - - SignalSpy { - id: windowPropertyChangedSpy - // Workaround to flush Wayland messages, see https://bugreports.qt.io/browse/AUTOSUITE-709 - // A proper solution in QtWayland is sought here: https://bugreports.qt.io/browse/QTBUG-83422 - function aboutToBlockWait(timeout) - { - AmTest.aboutToBlock(); - wait(timeout); - } - target: WindowManager - signalName: "windowPropertyChanged" - } - -    SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - - function cleanup() { - runStateChangedSpy.clear(); - ApplicationManager.stopApplication("test.configs.app"); - runStateChangedSpy.wait(); - runStateChangedSpy.wait(); - compare(runStateChangedSpy.signalArguments[1][1], ApplicationObject.NotRunning); - } - - function test_basic_ipc() { - compare(NotificationManager.count, 0); - compare(windowAddedSpy.count, 0); - verify(ApplicationManager.startApplication("test.configs.app")) - windowAddedSpy.wait(); - compare(windowAddedSpy.count, 1); - var window = windowAddedSpy.signalArguments[0][0]; - compare(window.windowProperty("prop1"), "foo"); - appif.trigger("PropertyChange"); - windowPropertyChangedSpy.wait(); - compare(windowPropertyChangedSpy.count, 1); - compare(windowPropertyChangedSpy.signalArguments[0][0], window); - compare(window.windowProperty("prop1"), "bar"); - windowPropertyChangedSpy.clear(); - - if (!ApplicationManager.systemProperties.nodbus) { - appif.trigger("Notification"); - tryVerify(function() { return NotificationManager.count === 1; }); - compare(NotificationManager.get(0).summary, "Test"); - } - - window.setWindowProperty("trigger", "now"); - windowPropertyChangedSpy.aboutToBlockWait(); - compare(windowPropertyChangedSpy.signalArguments[0][0], window); - compare(window.windowProperty("trigger"), "now"); - - windowPropertyChangedSpy.wait(); - compare(windowPropertyChangedSpy.signalArguments[1][0], window); - compare(window.windowProperty("ack"), "done"); - } -} diff --git a/tests/qml/crash/am-config.yaml b/tests/qml/crash/am-config.yaml deleted file mode 100644 index 61b2bfb2..00000000 --- a/tests/qml/crash/am-config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -flags: - noUiWatchdog: yes diff --git a/tests/qml/crash/apps/tld.test.crash/app.qml b/tests/qml/crash/apps/tld.test.crash/app.qml deleted file mode 100644 index a97c60f2..00000000 --- a/tests/qml/crash/apps/tld.test.crash/app.qml +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtApplicationManager.Application 2.0 -import Terminator 2.0 - -ApplicationManagerWindow { - function accessIllegalMemory() - { - Terminator.accessIllegalMemory(); - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "illegalMemory": accessIllegalMemory(); break; - case "illegalMemoryInThread": Terminator.accessIllegalMemoryInThread(); break; - case "stackOverflow": Terminator.forceStackOverflow(); break; - case "divideByZero": Terminator.divideByZero(); break; - case "unhandledException": Terminator.throwUnhandledException(); break; - case "abort": Terminator.abort(); break; - case "raise": Terminator.raise(7); break; - case "gracefully": Terminator.exitGracefully(); break; - } - } - } -} diff --git a/tests/qml/crash/apps/tld.test.crash/icon.png b/tests/qml/crash/apps/tld.test.crash/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/crash/apps/tld.test.crash/icon.png and /dev/null differ diff --git a/tests/qml/crash/apps/tld.test.crash/info.yaml b/tests/qml/crash/apps/tld.test.crash/info.yaml deleted file mode 100644 index 77ca2e76..00000000 --- a/tests/qml/crash/apps/tld.test.crash/info.yaml +++ /dev/null @@ -1,12 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'tld.test.crash' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -version: '1.0' -name: - en: 'Crash test' -runtimeParameters: - importPaths: [ "terminator2" ] diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmldir b/tests/qml/crash/apps/tld.test.crash/terminator2/qmldir deleted file mode 100644 index ac15a495..00000000 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module Terminator -plugin terminator2plugin diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp deleted file mode 100644 index 5a90dc49..00000000 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qmlterminator2.h" - -#include - - -static QObject *terminator_provider(QQmlEngine *engine, QJSEngine *scriptEngine) -{ - Q_UNUSED(scriptEngine) - return new Terminator(engine); -} - -void TerminatorPlugin::registerTypes(const char *uri) -{ - qmlRegisterSingletonType(uri, 2, 0, "Terminator", terminator_provider); -} - - -static void abortWithVeryLongSymbolNameOnTheStack800CharactersLong_CallMeIshmaelSomeYearsAgoNeverMindHowLongPreciselyHavingLittleOrNoMoneyInMyPurseAndNothingParticularToInterestMeOnShoreIThoughIWouldSailAboutALittlAndSeeTheWateryPartOfTheWorldItIsAWayIHaveOfDrivingOffTheSpleenAndRegulatingTheCirculationWhenenverIFindMyselfGrowingGrimAboutTheMouthWheneverItIsADampDrizzlyNovemberInMySoulWheneverIFindMyselfInvoluntarilyPausingBeforeCoffinWarehousesAndBringingUpTheRearOfEveryFuneralIMeetAndEspeciallyWheneverMyHyposGetSuchAnUpperHandOfMeThatItRequiresAStrongMoralPrincipleToPreventMeFromDeliberatelySteppingIntoTheStreetAndMethodicallyKnockingPeoplesHatsOffThenIAccountItHighTimeToGetToSeaAsSoonAsICanThisIsMySubstituteForPistolAndBallWithAPhilosophicalFlourishCatoThrowsHimselfUponHisSwordIQuietlyTakeToTheShip() -{ - ::abort(); -} - -void Terminator::accessIllegalMemory() const -{ - *(int*)1 = 42; -} - -void Terminator::accessIllegalMemoryInThread() -{ - TerminatorThread *t = new TerminatorThread(this); - t->start(); -} - -void Terminator::forceStackOverflow() const -{ - static constexpr int len = 100000; - volatile char buf[len]; - buf[len-1] = 42; - if (buf[len-1] == 42) - forceStackOverflow(); -} - -void Terminator::divideByZero() const -{ - int d = 0; - volatile int x = 42 / d; - Q_UNUSED(x) -} - -void Terminator::abort() const -{ - abortWithVeryLongSymbolNameOnTheStack800CharactersLong_CallMeIshmaelSomeYearsAgoNeverMindHowLongPreciselyHavingLittleOrNoMoneyInMyPurseAndNothingParticularToInterestMeOnShoreIThoughIWouldSailAboutALittlAndSeeTheWateryPartOfTheWorldItIsAWayIHaveOfDrivingOffTheSpleenAndRegulatingTheCirculationWhenenverIFindMyselfGrowingGrimAboutTheMouthWheneverItIsADampDrizzlyNovemberInMySoulWheneverIFindMyselfInvoluntarilyPausingBeforeCoffinWarehousesAndBringingUpTheRearOfEveryFuneralIMeetAndEspeciallyWheneverMyHyposGetSuchAnUpperHandOfMeThatItRequiresAStrongMoralPrincipleToPreventMeFromDeliberatelySteppingIntoTheStreetAndMethodicallyKnockingPeoplesHatsOffThenIAccountItHighTimeToGetToSeaAsSoonAsICanThisIsMySubstituteForPistolAndBallWithAPhilosophicalFlourishCatoThrowsHimselfUponHisSwordIQuietlyTakeToTheShip(); -} - -void Terminator::raise(int sig) const -{ - ::raise(sig); -} - -void Terminator::throwUnhandledException() const -{ - throw 42; -} - -void Terminator::exitGracefully() const -{ - exit(5); -} - - -TerminatorThread::TerminatorThread(Terminator *parent) - : QThread(parent), m_terminator(parent) -{ -} - -void TerminatorThread::run() -{ - m_terminator->accessIllegalMemory(); -} - -#include "moc_qmlterminator2.cpp" diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h deleted file mode 100644 index 27bc8e28..00000000 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#pragma once - -#include -#include - - -class TerminatorPlugin : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") - -public: - void registerTypes(const char *uri) override; -}; - - -class Terminator : public QObject -{ - Q_OBJECT - -public: - Terminator(QObject *parent) : QObject(parent) {} - - Q_INVOKABLE void accessIllegalMemory() const; - Q_INVOKABLE void accessIllegalMemoryInThread(); - Q_INVOKABLE void forceStackOverflow() const; - Q_INVOKABLE void divideByZero() const; - Q_INVOKABLE void abort() const; - Q_INVOKABLE void raise(int sig) const; - Q_INVOKABLE void throwUnhandledException() const; - Q_INVOKABLE void exitGracefully() const; -}; - - -class TerminatorThread : public QThread -{ - Q_OBJECT - -public: - explicit TerminatorThread(Terminator *parent); - -private: - void run() override; - Terminator *m_terminator; -}; diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro b/tests/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro deleted file mode 100644 index 3c482379..00000000 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/terminator2.pro +++ /dev/null @@ -1,18 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin exceptions -QT += qml quick - -TARGET = $$qtLibraryTarget(terminator2plugin) - -HEADERS += qmlterminator2.h -SOURCES += qmlterminator2.cpp - -DESTDIR = $$_PRO_FILE_PWD_/Terminator -target.path=$$DESTDIR -qmldir.files=$$PWD/qmldir -qmldir.path=$$DESTDIR -INSTALLS += target qmldir - -OTHER_FILES += qmldir - -QMAKE_POST_LINK += $$QMAKE_COPY $$replace($$list($$quote($$PWD/qmldir) $$DESTDIR), /, $$QMAKE_DIR_SEP) diff --git a/tests/qml/crash/crash.pro b/tests/qml/crash/crash.pro deleted file mode 100644 index c1c7d869..00000000 --- a/tests/qml/crash/crash.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_crash.qml -TEST_APPS = tld.test.crash -TEST_CONFIGURATIONS = "--force-multi-process" -load(am-qml-testcase) diff --git a/tests/qml/crash/tst_crash.qml b/tests/qml/crash/tst_crash.qml deleted file mode 100644 index cc7f42d2..00000000 --- a/tests/qml/crash/tst_crash.qml +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "Crashtest" - - property string appId: "tld.test.crash" - property var app: ApplicationManager.application(appId); - - SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - function initTestCase() { - compare(app.lastExitStatus, ApplicationObject.NormalExit) - } - - function test_crash_data() { - return [ { tag: "gracefully" }, - { tag: "illegalMemory" }, - { tag: "illegalMemoryInThread" }, - { tag: "unhandledException" }, - { tag: "abort" } ]; - //{ tag: "stackOverflow" }, - //{ tag: "divideByZero" }, - //{ tag: "raise" } ]; - } - - function test_crash(data) { - ApplicationManager.startApplication(appId); - runStateChangedSpy.wait(3000); - runStateChangedSpy.wait(3000); - compare(app.runState, ApplicationObject.Running); - ApplicationManager.startApplication(appId, data.tag); - runStateChangedSpy.wait(3000); - compare(app.runState, ApplicationObject.NotRunning); - if (data.tag === "gracefully") { - compare(app.lastExitStatus, ApplicationObject.NormalExit); - compare(app.lastExitCode, 5); - } else { - compare(app.lastExitStatus, ApplicationObject.CrashExit); - console.info("================================"); - console.info("=== INTENDED CRASH (TESTING) ==="); - console.info("================================"); - } - } -} diff --git a/tests/qml/installer/am-config.yaml b/tests/qml/installer/am-config.yaml deleted file mode 100644 index d0e12789..00000000 --- a/tests/qml/installer/am-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - installationDir: "/tmp/am-installer-test/apps" - documentDir: "/tmp/am-installer-test/docs" - -flags: - noSecurity: yes diff --git a/tests/qml/installer/apps/hello-world.red/app1.qml b/tests/qml/installer/apps/hello-world.red/app1.qml deleted file mode 100644 index 7e6ba025..00000000 --- a/tests/qml/installer/apps/hello-world.red/app1.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - color: "green" -} diff --git a/tests/qml/installer/apps/hello-world.red/icon1.png b/tests/qml/installer/apps/hello-world.red/icon1.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/installer/apps/hello-world.red/icon1.png and /dev/null differ diff --git a/tests/qml/installer/apps/hello-world.red/info.yaml b/tests/qml/installer/apps/hello-world.red/info.yaml deleted file mode 100644 index 1b628d1e..00000000 --- a/tests/qml/installer/apps/hello-world.red/info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'hello-world.red' -version: 'v1' -icon: 'icon1.png' -code: 'app1.qml' -runtime: 'qml' -name: - en: 'Builtin Installation Test App v1' diff --git a/tests/qml/installer/installer.pro b/tests/qml/installer/installer.pro deleted file mode 100644 index 2adfb2a4..00000000 --- a/tests/qml/installer/installer.pro +++ /dev/null @@ -1,6 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_installer.qml - -AM_TESTDATA_DIR=\"$$PWD/../../data/\" - -load(am-qml-testcase) diff --git a/tests/qml/installer/tst_installer.qml b/tests/qml/installer/tst_installer.qml deleted file mode 100644 index d3443ee7..00000000 --- a/tests/qml/installer/tst_installer.qml +++ /dev/null @@ -1,252 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - name: "Installer" - when: windowShown - - property var stateList: [] - property int spyTimeout: 5000 * AmTest.timeoutFactor - - SignalSpy { - id: taskFinishedSpy - target: PackageManager - signalName: "taskFinished" - } - - SignalSpy { - id: taskFailedSpy - target: PackageManager - signalName: "taskFailed" - } - - SignalSpy { - id: taskStateChangedSpy - target: PackageManager - signalName: "taskStateChanged" - } - - SignalSpy { - id: taskRequestingInstallationAcknowledgeSpy - target: PackageManager - signalName: "taskRequestingInstallationAcknowledge" - } - - SignalSpy { -        id: applicationChangedSpy -        target: ApplicationManager -        signalName: "applicationChanged" -    } - - - function init() { - // Remove previous installations - - for (var pkg of [ "hello-world.red", "com.pelagicore.test" ]) { - var po = PackageManager.package(pkg) - if (!po || (po.builtIn && !po.builtInHasRemovableUpdate)) - continue - if (PackageManager.removePackage(pkg, false, true)) { - taskFinishedSpy.wait(spyTimeout); - compare(taskFinishedSpy.count, 1); - taskFinishedSpy.clear(); - } - } - } - - function test_1states() { - PackageManager.packageAdded.connect(function(pkgId) { - var pkg = PackageManager.package(pkgId); - stateList.push(pkg.state) - pkg.stateChanged.connect(function(state) { - compare(state, pkg.state) - stateList.push(state) - }) - }) - - taskStateChangedSpy.clear(); - var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/test-dev-signed.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - compare(taskRequestingInstallationAcknowledgeSpy.count, 1); - compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); - var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.acknowledgePackageInstallation(id); - - if (!taskFinishedSpy.count) - taskFinishedSpy.wait(spyTimeout); - compare(taskFinishedSpy.count, 1); - taskFinishedSpy.clear(); - - compare(stateList.length, 2); - compare(stateList[0], PackageObject.BeingInstalled) - compare(stateList[1], PackageObject.Installed) - stateList = [] - - compare(PackageManager.package(pkgId).version, "1.0"); - - id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/test-update-dev-signed.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - compare(taskRequestingInstallationAcknowledgeSpy.count, 1); - compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.acknowledgePackageInstallation(id); - - taskFinishedSpy.wait(spyTimeout); - compare(taskFinishedSpy.count, 1); - taskFinishedSpy.clear(); - - compare(stateList[0], PackageObject.BeingUpdated) - compare(stateList[1], PackageObject.Installed) - stateList = [] - - compare(PackageManager.package(pkgId).version, "2.0"); - - id = PackageManager.removePackage(pkgId, false, false); - - taskFinishedSpy.wait(spyTimeout); - compare(taskFinishedSpy.count, 1); - taskFinishedSpy.clear(); - - compare(stateList[0], PackageObject.BeingRemoved) - stateList = [] - // Cannot compare app.state any more, since app might already be dead - - verify(taskStateChangedSpy.count > 10); - var taskStates = [ PackageManager.Executing, - PackageManager.AwaitingAcknowledge, - PackageManager.Installing, - PackageManager.CleaningUp, - PackageManager.Finished, - PackageManager.Executing, - PackageManager.AwaitingAcknowledge, - PackageManager.Installing, - PackageManager.CleaningUp, - PackageManager.Finished, - PackageManager.Executing ] - for (var i = 0; i < taskStates.length; i++) - compare(taskStateChangedSpy.signalArguments[i][1], taskStates[i], "- index: " + i); - } - - function test_2cancel_update() { - var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/test-dev-signed.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - compare(taskRequestingInstallationAcknowledgeSpy.count, 1); - compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); - var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id - compare(pkgId, "com.pelagicore.test"); - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.acknowledgePackageInstallation(id); - - taskFinishedSpy.wait(spyTimeout); - taskFinishedSpy.clear(); - - var pkg = PackageManager.package(pkgId); - compare(pkg.version, "1.0"); - - id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/test-update-dev-signed.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id - compare(pkgId, "com.pelagicore.test"); - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.cancelTask(id); - - taskFailedSpy.wait(spyTimeout); - taskFailedSpy.clear(); - - compare(pkg.version, "1.0"); - } - - function test_3cancel_builtin_update() { - taskStateChangedSpy.clear() - var pkg = PackageManager.package("hello-world.red"); - verify(pkg.builtIn); - compare(pkg.icon.toString().slice(-9), "icon1.png") - compare(pkg.version, "v1"); - - var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/hello-world.red.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - compare(taskRequestingInstallationAcknowledgeSpy.count, 1); - compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.cancelTask(id); - - taskFailedSpy.wait(spyTimeout); - taskFailedSpy.clear(); - - verify(pkg.builtIn); - compare(pkg.icon.toString().slice(-9), "icon1.png") - compare(pkg.version, "v1"); - } - - function test_4builtin_update_downgrade() { - taskStateChangedSpy.clear() - - var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR - + "/packages/hello-world.red.appkg") - taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout); - compare(taskRequestingInstallationAcknowledgeSpy.count, 1); - compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id); - taskRequestingInstallationAcknowledgeSpy.clear(); - PackageManager.acknowledgePackageInstallation(id); - - taskFinishedSpy.wait(spyTimeout); - var pkg = PackageManager.package("hello-world.red") - compare(pkg.version, "red"); - taskFinishedSpy.clear(); - applicationChangedSpy.clear(); - - // remvove is a downgrade - verify(pkg.builtIn) - verify(pkg.builtInHasRemovableUpdate) - verify(PackageManager.removePackage("hello-world.red", false, true)); - taskFinishedSpy.wait(spyTimeout); - compare(taskFinishedSpy.count, 1); - taskFinishedSpy.clear(); - - compare(applicationChangedSpy.count, 3); - compare(applicationChangedSpy.signalArguments[0][0], "hello-world.red"); - compare(applicationChangedSpy.signalArguments[0][1], ["isBlocked"]); - compare(applicationChangedSpy.signalArguments[2][1], []); - - verify(!pkg.blocked) - compare(pkg.version, "v1"); - } -} diff --git a/tests/qml/intents/am-config-quick.yaml b/tests/qml/intents/am-config-quick.yaml deleted file mode 100644 index 96b3098c..00000000 --- a/tests/qml/intents/am-config-quick.yaml +++ /dev/null @@ -1,6 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -quicklaunch: - runtimesPerContainer: 1 - idleLoad: 1.0 diff --git a/tests/qml/intents/am-config.yaml b/tests/qml/intents/am-config.yaml deleted file mode 100644 index 1667c123..00000000 --- a/tests/qml/intents/am-config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -ui: - fullscreen: no - -flags: - noSecurity: yes - noUiWatchdog: yes - -runtimes: - qml: - quitTime: 1000 - -intents: - timeouts: - disambiguation: 1000 - startApplication: 1000 - replyFromApplication: 1000 - replyFromSystem: 2000 diff --git a/tests/qml/intents/apps/cannot-start/cannot-start b/tests/qml/intents/apps/cannot-start/cannot-start deleted file mode 100644 index 5c3118dc..00000000 --- a/tests/qml/intents/apps/cannot-start/cannot-start +++ /dev/null @@ -1 +0,0 @@ -dummy file diff --git a/tests/qml/intents/apps/cannot-start/icon.png b/tests/qml/intents/apps/cannot-start/icon.png deleted file mode 100644 index adb840ce..00000000 Binary files a/tests/qml/intents/apps/cannot-start/icon.png and /dev/null differ diff --git a/tests/qml/intents/apps/cannot-start/info.yaml b/tests/qml/intents/apps/cannot-start/info.yaml deleted file mode 100644 index 64c81589..00000000 --- a/tests/qml/intents/apps/cannot-start/info.yaml +++ /dev/null @@ -1,12 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'cannot-start' -icon: 'icon.png' -code: 'cannot-start' -runtime: 'native' -name: - en: 'Cannot start' - -intents: -- id: cannot-start-intent diff --git a/tests/qml/intents/apps/intents1/icon.png b/tests/qml/intents/apps/intents1/icon.png deleted file mode 100644 index adb840ce..00000000 Binary files a/tests/qml/intents/apps/intents1/icon.png and /dev/null differ diff --git a/tests/qml/intents/apps/intents1/info.yaml b/tests/qml/intents/apps/intents1/info.yaml deleted file mode 100644 index d5f72561..00000000 --- a/tests/qml/intents/apps/intents1/info.yaml +++ /dev/null @@ -1,20 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'intents1' -icon: 'icon.png' -code: 'intents1.qml' -runtime: 'qml' -name: - en: 'Intents1' - -intents: -- id: only1 -- id: both -- id: match - parameterMatch: - list: [ 'a', 'b' ] - int: 42 - string: "^foo_.*_bar$" - complex: { 'a': 1 } -- id: custom-error diff --git a/tests/qml/intents/apps/intents1/intents1.qml b/tests/qml/intents/apps/intents1/intents1.qml deleted file mode 100644 index d9e80183..00000000 --- a/tests/qml/intents/apps/intents1/intents1.qml +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQml 2.2 -import QtApplicationManager 2.0 -import QtApplicationManager.Application 2.0 - -QtObject { - id: root - - property var connections: Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } - } - - property var handler: IntentHandler { - intentIds: [ "only1", "both", "match" ] - onRequestReceived: { - request.sendReply({ "from": ApplicationInterface.applicationId, "in": request.parameters}) - } - } - - property var customErrorHandler: IntentHandler { - intentIds: [ "custom-error" ] - onRequestReceived: { - request.sendErrorReply("custom error") - } - } -} diff --git a/tests/qml/intents/apps/intents2/icon.png b/tests/qml/intents/apps/intents2/icon.png deleted file mode 100644 index adb840ce..00000000 Binary files a/tests/qml/intents/apps/intents2/icon.png and /dev/null differ diff --git a/tests/qml/intents/apps/intents2/info.yaml b/tests/qml/intents/apps/intents2/info.yaml deleted file mode 100644 index 209ab30c..00000000 --- a/tests/qml/intents/apps/intents2/info.yaml +++ /dev/null @@ -1,16 +0,0 @@ -formatVersion: 1 -formatType: am-package ---- -id: 'intents2' -icon: 'icon.png' -name: - en: 'Intents2' -applications: - - id: 'intents2.1' - code: 'intents2.qml' - runtime: 'qml' - -intents: -- id: only2 -- id: both -- id: only1 # declared here, but no handler to provoke an error diff --git a/tests/qml/intents/apps/intents2/intents2.qml b/tests/qml/intents/apps/intents2/intents2.qml deleted file mode 100644 index 2545a3f5..00000000 --- a/tests/qml/intents/apps/intents2/intents2.qml +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQml 2.2 -import QtApplicationManager 2.0 -import QtApplicationManager.Application 2.0 - -QtObject { - id: root - - property var connections: Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } - } - - property var handler: IntentHandler { - intentIds: [ "both", "only2" ] - onRequestReceived: { - Qt.callLater(function() { - request.sendReply({ "from": ApplicationInterface.applicationId, "in": request.parameters}) - }) - } - } -} diff --git a/tests/qml/intents/intents.pro b/tests/qml/intents/intents.pro deleted file mode 100644 index a05a7b72..00000000 --- a/tests/qml/intents/intents.pro +++ /dev/null @@ -1,12 +0,0 @@ -load(am-config) - -AM_CONFIG = am-config.yaml -TEST_FILES = tst_intents.qml -TEST_APPS = intents1 intents2 cannot-start -TEST_CONFIGURATIONS = "--force-single-process" -multi-process { - TEST_CONFIGURATIONS += "--force-multi-process" \ - "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" -} - -load(am-qml-testcase) diff --git a/tests/qml/intents/tst_intents.qml b/tests/qml/intents/tst_intents.qml deleted file mode 100644 index 2caccfcb..00000000 --- a/tests/qml/intents/tst_intents.qml +++ /dev/null @@ -1,241 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtTest 1.0 -import QtApplicationManager 2.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "Intents" - - property var stdParams: { "para": "meter" } - property var matchParams: { "list": "a", "int": 42, "string": "foo_x_bar", "complex": { "a": 1 } } - - ListView { - id: listView - model: ApplicationManager - delegate: Item { - property var modelData: model - } - } - - function initTestCase() { - verify(ApplicationManager.application("intents1")) - verify(ApplicationManager.application("intents2.1")) - if (!ApplicationManager.singleProcess) - verify(ApplicationManager.application("cannot-start")) - } - - SignalSpy { - id: requestSpy - target: null - signalName: "replyReceived" - } - - function test_intent_object() { - verify(IntentServer.count> 0) - - // test intent properties - var intent = IntentServer.applicationIntent("both", "intents1") - verify(intent) - compare(intent.intentId, "both") - compare(intent.applicationId, "intents1") - compare(intent.visibility, IntentObject.Public) - compare(intent.requiredCapabilities, []) - compare(intent.parameterMatch, {}) - - verify(!IntentServer.applicationIntent("both", "intents3")) - verify(!IntentServer.applicationIntent("bothx", "intents1")) - verify(!IntentServer.applicationIntent("both", "")) - verify(!IntentServer.applicationIntent("", "intents1")) - verify(!IntentServer.applicationIntent("", "")) - } - - - function test_match() { - // first, check the matching on the server API - var intent = IntentServer.applicationIntent("match", "intents1") - verify(!intent) - intent = IntentServer.applicationIntent("match", "intents1", matchParams) - verify(intent) - compare(intent.parameterMatch, { "list": [ "a", "b" ], "int": 42, "string": "^foo_.*_bar$", "complex": { "a": 1 } }) - - var params = matchParams - params.list = "c" - verify(!IntentServer.applicationIntent("match", "intents1", params)) - params.list = "b" - verify(IntentServer.applicationIntent("match", "intents1", params)) - - params.int = 2 - verify(!IntentServer.applicationIntent("match", "intents1", params)) - params.int = 42 - - params.string = "foo" - verify(!IntentServer.applicationIntent("match", "intents1", params)) - params.string = "foo_test_bar" - verify(IntentServer.applicationIntent("match", "intents1", params)) - - params.complex = "string" - verify(!IntentServer.applicationIntent("match", "intents1", params)) - params.complex = matchParams.complex - } - - - function test_intents_data() { - return [ - {tag: "1-1", intentId: "only1", appId: "intents1", succeeding: true }, - {tag: "2-2", intentId: "only2", appId: "intents2.1", succeeding: true }, - {tag: "1-2", intentId: "only1", appId: "intents2.1", succeeding: false, - errorMessage: "No matching IntentHandler found." }, - {tag: "2-1", intentId: "only2", appId: "intents1", succeeding: false, - errorMessage: "No matching intent handler registered.", - ignoreWarning: 'Unknown intent "only2" was requested from application ":sysui:"' }, - {tag: "match-1", intentId: "match", appId: "intents1", succeeding: true, params: matchParams }, - {tag: "match-2", intentId: "match", appId: "intents1", succeeding: false, - params: function() { var x = Object.assign({}, matchParams); x.int = 1; return x }(), - errorMessage: "No matching intent handler registered.", - ignoreWarning: 'Unknown intent "match" was requested from application ":sysui:"' }, - {tag: "match-3", intentId: "match", appId: "intents1", succeeding: false, params: {}, - errorMessage: "No matching intent handler registered.", - ignoreWarning: 'Unknown intent "match" was requested from application ":sysui:"' }, - {tag: "unknown-1", intentId: "unknown", appId: "intents1", succeeding: false, - errorMessage: "No matching intent handler registered.", - ignoreWarning: 'Unknown intent "unknown" was requested from application ":sysui:"' }, - {tag: "unknown-2", intentId: "unknown", appId: "", succeeding: false, - errorMessage: "No matching intent handler registered.", - ignoreWarning: 'Unknown intent "unknown" was requested from application ":sysui:"' }, - {tag: "custom-error", intentId: "custom-error", appId: "intents1", succeeding: false, - errorMessage: "custom error" }, - {tag: "cannot-start", intentId: "cannot-start-intent", appId: "cannot-start", succeeding: false, - errorMessage: /Starting handler application timed out after .*/ }, - ]; - } - - function test_intents(data) { - if (data.appId && !ApplicationManager.application(data.appId)) - skip("Application \"" + data.appId + "\" is not available") - - if (data.ignoreWarning) - ignoreWarning(data.ignoreWarning) - - var params = ("params" in data) ? data.params : stdParams - - var req = IntentClient.sendIntentRequest(data.intentId, data.appId, params) - verify(req) - requestSpy.target = req - tryCompare(requestSpy, "count", 1, 1000) - compare(req.succeeded, data.succeeding) - if (req.succeeded) { - compare(req.result, { "from": data.appId, "in": params }) - } else { - if (data.errorMessage instanceof RegExp) - verify(data.errorMessage.test(req.errorMessage)) - else - compare(req.errorMessage, data.errorMessage) - } - requestSpy.clear() - requestSpy.target = null - } - - function test_disambiguate_data() { - return [ - {tag: "no-signal", action: "none", succeeding: true }, - {tag: "reject", action: "reject", succeeding: false, - errorMessage: "Disambiguation was rejected" }, - {tag: "timeout", action: "timeout", succeeding: false, - errorMessage: /Disambiguation timed out after .*/ }, - {tag: "ack-invalid", action: "acknowledge", acknowledgeIntentId: "only1", succeeding: false, - errorMessage: "Failed to disambiguate", - ignoreWarning: /IntentServer::acknowledgeDisambiguationRequest for intent .* tried to disambiguate to the intent "only1" which was not in the list of potential disambiguations/ }, - {tag: "ack-valid", action: "acknowledge", succeeding: true } - ]; - } - - SignalSpy { - id: disambiguateSpy - target: IntentServer - } - - function test_disambiguate(data) { - var intentId = "both" - - if (data.ignoreWarning) - ignoreWarning(data.ignoreWarning) - - disambiguateSpy.signalName = data.action === "none" ? "" : "disambiguationRequest"; - - var req = IntentClient.sendIntentRequest("both", stdParams) - verify(req) - requestSpy.target = req - - if (data.action !== "none") { - tryCompare(disambiguateSpy, "count", 1, 1000) - var possibleIntents = disambiguateSpy.signalArguments[0][1] - compare(possibleIntents.length, 2) - compare(possibleIntents[0].intentId, intentId) - compare(possibleIntents[1].intentId, intentId) - compare(possibleIntents[0].applicationId, "intents1") - compare(possibleIntents[1].applicationId, "intents2.1") - compare(disambiguateSpy.signalArguments[0][2], stdParams) - - switch (data.action) { - case "reject": - IntentServer.rejectDisambiguationRequest(disambiguateSpy.signalArguments[0][0]) - break - case "acknowledge": - var intent = data.acknowledgeIntentId ? IntentServer.applicationIntent(data.acknowledgeIntentId, - possibleIntents[0].applicationId) - : possibleIntents[1] - IntentServer.acknowledgeDisambiguationRequest(disambiguateSpy.signalArguments[0][0], intent) - break - } - disambiguateSpy.clear() - } - - tryCompare(requestSpy, "count", 1, data.action === "timeout" ? 15000 : 1000) - var succeeding = data.succeeding - compare(req.succeeded, succeeding) - if (succeeding) { - compare(req.errorMessage, "") - verify(req.result !== {}) - } else { - if (data.errorMessage instanceof RegExp) - verify(data.errorMessage.test(req.errorMessage)) - else - compare(req.errorMessage, data.errorMessage) - compare(req.result, {}) - } - requestSpy.clear() - } -} diff --git a/tests/qml/lifecycle/am-config.yaml b/tests/qml/lifecycle/am-config.yaml deleted file mode 100644 index 61b2bfb2..00000000 --- a/tests/qml/lifecycle/am-config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -flags: - noUiWatchdog: yes diff --git a/tests/qml/lifecycle/apps/tld.test.lifecycle/app.qml b/tests/qml/lifecycle/apps/tld.test.lifecycle/app.qml deleted file mode 100644 index a5f21ad0..00000000 --- a/tests/qml/lifecycle/apps/tld.test.lifecycle/app.qml +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - Image { - anchors.centerIn: parent - source: ApplicationInterface.icon - } -} diff --git a/tests/qml/lifecycle/apps/tld.test.lifecycle/icon.png b/tests/qml/lifecycle/apps/tld.test.lifecycle/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/lifecycle/apps/tld.test.lifecycle/icon.png and /dev/null differ diff --git a/tests/qml/lifecycle/apps/tld.test.lifecycle/info.yaml b/tests/qml/lifecycle/apps/tld.test.lifecycle/info.yaml deleted file mode 100644 index 198cbe51..00000000 --- a/tests/qml/lifecycle/apps/tld.test.lifecycle/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'tld.test.lifecycle' -name: - en: 'Lifecycle Tests' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' diff --git a/tests/qml/lifecycle/lifecycle.pro b/tests/qml/lifecycle/lifecycle.pro deleted file mode 100644 index 98ab9709..00000000 --- a/tests/qml/lifecycle/lifecycle.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_lifecycle.qml -TEST_APPS = tld.test.lifecycle - -load(am-qml-testcase) diff --git a/tests/qml/lifecycle/tst_lifecycle.qml b/tests/qml/lifecycle/tst_lifecycle.qml deleted file mode 100644 index d75584e2..00000000 --- a/tests/qml/lifecycle/tst_lifecycle.qml +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "LifeCycleTest" - visible: true - - property var app: ApplicationManager.application("tld.test.lifecycle"); - - - WindowItem { - id: chrome - anchors.fill: parent - } - - Connections { - target: WindowManager - function onWindowAdded(window) { - chrome.window = window; - } - } - - Connections { - target: chrome.window - function onContentStateChanged() { - if (chrome.window.contentState === WindowObject.NoSurface) - chrome.window = null; - } - } - - - SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - SignalSpy { -        id: objectDestroyedSpy -        target: AmTest -        signalName: "objectDestroyed" -    } - - Timer { - id: stopTimer - interval: 1 - onTriggered: app.stop(); - } - - - function cleanup() { - objectDestroyedSpy.clear(); - var index = AmTest.observeObjectDestroyed(app.runtime); - app.stop(); - while (app.runState !== ApplicationObject.NotRunning) - runStateChangedSpy.wait(); - objectDestroyedSpy.wait(); - compare(objectDestroyedSpy.signalArguments[0][0], index); - } - - - // Start followed by quick stop/start in single-porcess mode caused an abort in the past - function test_fast_stop_start() { - app.start(); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.StartingUp); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.Running); - - objectDestroyedSpy.clear(); - var index = AmTest.observeObjectDestroyed(app.runtime); - - app.stop(); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.ShuttingDown); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.NotRunning); - - app.start(); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.StartingUp); - runStateChangedSpy.wait(); - compare(app.runState, ApplicationObject.Running); - - objectDestroyedSpy.wait(); - compare(objectDestroyedSpy.signalArguments[0][0], index); - } - - // Quick start/stop followd by start in single-process mode caused an abort in the past - function test_fast_start_stop() { - app.start(); - stopTimer.start(); - - while (app.runState !== ApplicationObject.NotRunning) - runStateChangedSpy.wait(); - - app.start(); - while (app.runState !== ApplicationObject.Running) - runStateChangedSpy.wait(); - } -} diff --git a/tests/qml/processtitle/am-config-quick.yaml b/tests/qml/processtitle/am-config-quick.yaml deleted file mode 100644 index a21a1dea..00000000 --- a/tests/qml/processtitle/am-config-quick.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -quicklaunch: - runtimesPerContainer: 1 - idleLoad: 1.0 - -systemProperties: - private: - quickLaunch: true diff --git a/tests/qml/processtitle/am-config.yaml b/tests/qml/processtitle/am-config.yaml deleted file mode 100644 index 4ab6878e..00000000 --- a/tests/qml/processtitle/am-config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" diff --git a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml b/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml deleted file mode 100644 index 7371a7c8..00000000 --- a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/app.qml +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2020 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.15 -import QtApplicationManager.Application 2.0 - -Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } -} diff --git a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png b/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/icon.png and /dev/null differ diff --git a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml b/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml deleted file mode 100644 index 2e1cae3b..00000000 --- a/tests/qml/processtitle/apps/appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -name: - en: 'Large App' diff --git a/tests/qml/processtitle/apps/test.processtitle.app/app.qml b/tests/qml/processtitle/apps/test.processtitle.app/app.qml deleted file mode 100644 index 7371a7c8..00000000 --- a/tests/qml/processtitle/apps/test.processtitle.app/app.qml +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2020 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.15 -import QtApplicationManager.Application 2.0 - -Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } -} diff --git a/tests/qml/processtitle/apps/test.processtitle.app/icon.png b/tests/qml/processtitle/apps/test.processtitle.app/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/processtitle/apps/test.processtitle.app/icon.png and /dev/null differ diff --git a/tests/qml/processtitle/apps/test.processtitle.app/info.yaml b/tests/qml/processtitle/apps/test.processtitle.app/info.yaml deleted file mode 100644 index e178aa04..00000000 --- a/tests/qml/processtitle/apps/test.processtitle.app/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.processtitle.app' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -name: - en: 'Small App' diff --git a/tests/qml/processtitle/processtitle.pro b/tests/qml/processtitle/processtitle.pro deleted file mode 100644 index e78b54a1..00000000 --- a/tests/qml/processtitle/processtitle.pro +++ /dev/null @@ -1,7 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_processtitle.qml -TEST_APPS = test.processtitle.app -TEST_CONFIGURATIONS = "--force-multi-process" \ - "--force-multi-process -c $$_PRO_FILE_PWD_/am-config-quick.yaml" - -load(am-qml-testcase) diff --git a/tests/qml/processtitle/tst_processtitle.qml b/tests/qml/processtitle/tst_processtitle.qml deleted file mode 100644 index acb3646e..00000000 --- a/tests/qml/processtitle/tst_processtitle.qml +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2020 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.15 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - - -TestCase { - id: testCase - when: windowShown - name: "ProcessTitle" - visible: true - - property int sysuiPid - - ProcessStatus { - id: processStatus - applicationId: "" - Component.onCompleted: sysuiPid = processId; - } - - -    SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - function test_launcher_qml_data() { - return [ { tag: "small", appId: "test.processtitle.app", resId: "test.processtitle.app" }, - { tag: "large", appId: "appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appappapp7", - resId: "appappapp1appappapp2appappapp3appappapp4appappapp5appappapp6appa" } ]; - } - - function test_launcher_qml(data) { - const executable = "appman-launcher-qml"; - var sigIdx; - var quickArg; - var pid - if (ApplicationManager.systemProperties.quickLaunch) { - sigIdx = 0; - quickArg = " --quicklaunch" - tryVerify(function() { - pid = AmTest.findChildProcess(sysuiPid, executable + quickArg); - return pid - }); - wait(250); - verify(AmTest.cmdLine(pid).endsWith(executable + quickArg)); - } else { - sigIdx = 1; - quickArg = "" - } - - runStateChangedSpy.clear(); - verify(ApplicationManager.startApplication(data.appId)); - runStateChangedSpy.wait(); - if (sigIdx === 1) - runStateChangedSpy.wait(); - - compare(runStateChangedSpy.signalArguments[sigIdx][0], data.appId); - compare(runStateChangedSpy.signalArguments[sigIdx][1], ApplicationObject.Running); - - processStatus.applicationId = data.appId; - pid = processStatus.processId; - verify(AmTest.ps(pid).endsWith(executable + ": " + data.resId + quickArg)); - verify(AmTest.cmdLine(pid).endsWith(executable + ": " + data.resId + quickArg)); - verify(AmTest.environment(pid).includes("AM_CONFIG=%YAML")); - verify(AmTest.environment(pid).includes("AM_NO_DLT_LOGGING=1")); - verify(AmTest.environment(pid).includes("WAYLAND_DISPLAY=")); - - runStateChangedSpy.clear(); - ApplicationManager.stopAllApplications(); - runStateChangedSpy.wait(); - runStateChangedSpy.wait(); - compare(runStateChangedSpy.signalArguments[1][1], ApplicationObject.NotRunning); - } -} diff --git a/tests/qml/qml.pro b/tests/qml/qml.pro deleted file mode 100644 index 902ab2f1..00000000 --- a/tests/qml/qml.pro +++ /dev/null @@ -1,20 +0,0 @@ -load(am-config) - -TEMPLATE = subdirs -SUBDIRS = \ - simple \ - windowmanager \ - windowmapping \ - windowitem \ - windowitem2 \ - installer \ - quicklaunch \ - intents \ - configs \ - lifecycle \ - resources - -multi-process: SUBDIRS += \ - crash/apps/tld.test.crash/terminator2 \ - crash \ - processtitle diff --git a/tests/qml/quicklaunch/am-config.yaml b/tests/qml/quicklaunch/am-config.yaml deleted file mode 100644 index e8de3d00..00000000 --- a/tests/qml/quicklaunch/am-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -quicklaunch: - runtimesPerContainer: 2 - idleLoad: 1.0 diff --git a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml deleted file mode 100644 index 571288d1..00000000 --- a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - width: 320 - height: 240 - - ApplicationInterfaceExtension { - name: "quicklaunch.interface" - onReadyChanged: object.acknowledge(); - } -} diff --git a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/icon.png and /dev/null differ diff --git a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml deleted file mode 100644 index e898a02b..00000000 --- a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'tld.test.quicklaunch' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -version: '1.0' -name: - en: 'Quicklaunch' diff --git a/tests/qml/quicklaunch/quicklaunch.pro b/tests/qml/quicklaunch/quicklaunch.pro deleted file mode 100644 index 2d990a4b..00000000 --- a/tests/qml/quicklaunch/quicklaunch.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_quicklaunch.qml -TEST_APPS = tld.test.quicklaunch - -load(am-qml-testcase) diff --git a/tests/qml/quicklaunch/tst_quicklaunch.qml b/tests/qml/quicklaunch/tst_quicklaunch.qml deleted file mode 100644 index d9744eec..00000000 --- a/tests/qml/quicklaunch/tst_quicklaunch.qml +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -// Tests are meaningless in single-process mode, but still work - -TestCase { - id: testCase - when: windowShown - name: "Quicklaunch" - - property bool acknowledged: false - - SignalSpy { - id: windowAddedSpy - target: WindowManager - signalName: "windowAdded" - } - - SignalSpy { -        id: runStateChangedSpy -        signalName: "runStateChanged" -    } - - ApplicationIPCInterface { - function acknowledge() { acknowledged = true; } - Component.onCompleted: ApplicationIPCManager.registerInterface(this, "quicklaunch.interface", {}); - } - - - function test_quicklaunch() { - var app = ApplicationManager.application("tld.test.quicklaunch"); - runStateChangedSpy.target = app; - - wait(1000); - // Check for quick-launching is done every second in appman. After 1s now, this test - // sometimes caused some race where the app would not be started at all in the past: - app.start(); - windowAddedSpy.wait(3000); - tryCompare(testCase, "acknowledged", true); - runStateChangedSpy.clear(); - app.stop(true); - runStateChangedSpy.wait(3000); // wait for ShuttingDown - runStateChangedSpy.wait(3000); // wait for NotRunning - - wait(1000); - // Unfortunately there is no reliable means to determine, whether a quicklaunch process - // is running, but after at least 2s now, there should be a process that can be attached to. - acknowledged = false; - app.start(); - windowAddedSpy.wait(3000); - tryCompare(testCase, "acknowledged", true); - runStateChangedSpy.clear(); - app.stop(true); - runStateChangedSpy.wait(3000); // wait for ShuttingDown - runStateChangedSpy.wait(3000); // wait for NotRunning - } -} diff --git a/tests/qml/resources/am-config.yaml b/tests/qml/resources/am-config.yaml deleted file mode 100644 index a06cb076..00000000 --- a/tests/qml/resources/am-config.yaml +++ /dev/null @@ -1,22 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - installationDir: "/tmp/am-resource-test/apps" - -quicklaunch: - runtimesPerContainer: 1 - idleLoad: 1.0 - -runtimes: - qml: - resources: "appcommon/appcommonfile.rcc" - importPaths: [ "qrc:/appcommon/qml", "relative" ] - quicklaunchQml: "qrc:/appcommon/Quicklaunch.qml" - -ui: - importPaths: "qrc:///qml" - resources: - - "systemuifile.rcc" - - "${CONFIG_PWD}/systemuiplugin" # libsystemuiplugin.so would only work on Linux diff --git a/tests/qml/resources/appcommon/Quicklaunch.qml b/tests/qml/resources/appcommon/Quicklaunch.qml deleted file mode 100644 index e9cc4144..00000000 --- a/tests/qml/resources/appcommon/Quicklaunch.qml +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import common 1.0 - -CommonObj { - Component.onCompleted: console.info("Quicklaunch - meaning: " + meaning); -} diff --git a/tests/qml/resources/appcommon/appcommon.pro b/tests/qml/resources/appcommon/appcommon.pro deleted file mode 100644 index 47028775..00000000 --- a/tests/qml/resources/appcommon/appcommon.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = aux - -OTHER_FILES += Quicklaunch.qml \ - qml/common/CommonObj.qml - -RESOURCE_SOURCE = appcommonfile.qrc -load(generate-resource) diff --git a/tests/qml/resources/appcommon/appcommonfile.qrc b/tests/qml/resources/appcommon/appcommonfile.qrc deleted file mode 100644 index 4dc15f85..00000000 --- a/tests/qml/resources/appcommon/appcommonfile.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - qml/common/CommonObj.qml - qml/common/qmldir - Quicklaunch.qml - - diff --git a/tests/qml/resources/appcommon/qml/common/CommonObj.qml b/tests/qml/resources/appcommon/qml/common/CommonObj.qml deleted file mode 100644 index 1b181488..00000000 --- a/tests/qml/resources/appcommon/qml/common/CommonObj.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -QtObject { - property int meaning: 42 -} diff --git a/tests/qml/resources/appcommon/qml/common/qmldir b/tests/qml/resources/appcommon/qml/common/qmldir deleted file mode 100644 index 5458b257..00000000 --- a/tests/qml/resources/appcommon/qml/common/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module common -CommonObj 1.0 CommonObj.qml diff --git a/tests/qml/resources/apps/app1/app1.pro b/tests/qml/resources/apps/app1/app1.pro deleted file mode 100644 index cbbb4758..00000000 --- a/tests/qml/resources/apps/app1/app1.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = lib -TARGET = app1plugin -CONFIG += plugin -RESOURCES = app1plugin.qrc - -RESOURCE_SOURCE = app1file.qrc -load(generate-resource) - -OTHER_FILES += \ - info.yaml \ - icon.png diff --git a/tests/qml/resources/apps/app1/app1.qml b/tests/qml/resources/apps/app1/app1.qml deleted file mode 100644 index d519f3ac..00000000 --- a/tests/qml/resources/apps/app1/app1.qml +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtApplicationManager.Application 2.0 -import forms 1.0 -import elements 1.0 - -ApplicationManagerWindow { - YellowRect {} - AquaRect {} - LinenRect {} -} diff --git a/tests/qml/resources/apps/app1/app1file.qrc b/tests/qml/resources/apps/app1/app1file.qrc deleted file mode 100644 index 6c958e89..00000000 --- a/tests/qml/resources/apps/app1/app1file.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - app1.qml - qml/forms/YellowRect.qml - qml/forms/qmldir - - diff --git a/tests/qml/resources/apps/app1/app1plugin.qrc b/tests/qml/resources/apps/app1/app1plugin.qrc deleted file mode 100644 index 6c4e2ae3..00000000 --- a/tests/qml/resources/apps/app1/app1plugin.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - qml/forms/AquaRect.qml - - diff --git a/tests/qml/resources/apps/app1/icon.png b/tests/qml/resources/apps/app1/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/resources/apps/app1/icon.png and /dev/null differ diff --git a/tests/qml/resources/apps/app1/info.yaml b/tests/qml/resources/apps/app1/info.yaml deleted file mode 100644 index a5287f2c..00000000 --- a/tests/qml/resources/apps/app1/info.yaml +++ /dev/null @@ -1,17 +0,0 @@ -formatVersion: 1 -formatType: am-package ---- -id: 'app1' -icon: 'icon.png' -name: - en: 'Resource Test App 1' - -applications: - - id: 'app1' - code: 'qrc:///app1/app1.qml' - runtime: 'qml' - runtimeParameters: - importPaths: "qrc:///app1/qml" - resources: - - app1file.rcc - - app1plugin # libapp1plugin.so would only work on Linux diff --git a/tests/qml/resources/apps/app1/qml/forms/AquaRect.qml b/tests/qml/resources/apps/app1/qml/forms/AquaRect.qml deleted file mode 100644 index cefb485c..00000000 --- a/tests/qml/resources/apps/app1/qml/forms/AquaRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "aqua" -} diff --git a/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml b/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml deleted file mode 100644 index b1c91a1f..00000000 --- a/tests/qml/resources/apps/app1/qml/forms/YellowRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "yellow" -} diff --git a/tests/qml/resources/apps/app1/qml/forms/qmldir b/tests/qml/resources/apps/app1/qml/forms/qmldir deleted file mode 100644 index 12a5506b..00000000 --- a/tests/qml/resources/apps/app1/qml/forms/qmldir +++ /dev/null @@ -1,4 +0,0 @@ -module forms -YellowRect 1.0 qrc:///app1/qml/forms/YellowRect.qml -# :/app1/qml/forms/YellowRect.qml would not work -AquaRect 1.0 AquaRect.qml diff --git a/tests/qml/resources/apps/app2/BlueRect.qml b/tests/qml/resources/apps/app2/BlueRect.qml deleted file mode 100644 index 138bdff4..00000000 --- a/tests/qml/resources/apps/app2/BlueRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "blue" -} diff --git a/tests/qml/resources/apps/app2/app2.pro b/tests/qml/resources/apps/app2/app2.pro deleted file mode 100644 index 7a5190df..00000000 --- a/tests/qml/resources/apps/app2/app2.pro +++ /dev/null @@ -1,8 +0,0 @@ -TEMPLATE = aux - -RESOURCE_SOURCE = app2.qrc -load(generate-resource) - -OTHER_FILES += \ - info.yaml \ - icon.png diff --git a/tests/qml/resources/apps/app2/app2.qml b/tests/qml/resources/apps/app2/app2.qml deleted file mode 100644 index c0310ee0..00000000 --- a/tests/qml/resources/apps/app2/app2.qml +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtApplicationManager.Application 2.0 -import QtQuick 2.11 -import appwidgets 1.0 -import common 1.0 - -ApplicationManagerWindow { - CommonObj { id: common } - BlueRect { } - GreenRect { } - - Timer { - running: true - interval: 20 - onTriggered: setWindowProperty("meaning", common.meaning); - } -} diff --git a/tests/qml/resources/apps/app2/app2.qrc b/tests/qml/resources/apps/app2/app2.qrc deleted file mode 100644 index 80bc560c..00000000 --- a/tests/qml/resources/apps/app2/app2.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - app2.qml - BlueRect.qml - - diff --git a/tests/qml/resources/apps/app2/icon.png b/tests/qml/resources/apps/app2/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/resources/apps/app2/icon.png and /dev/null differ diff --git a/tests/qml/resources/apps/app2/info.yaml b/tests/qml/resources/apps/app2/info.yaml deleted file mode 100644 index 6eda565b..00000000 --- a/tests/qml/resources/apps/app2/info.yaml +++ /dev/null @@ -1,15 +0,0 @@ -formatVersion: 1 -formatType: am-package ---- -id: 'app2' -icon: 'icon.png' -name: - en: 'Resource Test App 2' - -applications: - - id: 'app2' - code: ':/app2.qml' - runtime: 'qml' - runtimeParameters: - importPaths: "qml" - resources: "app2.rcc" diff --git a/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml b/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml deleted file mode 100644 index 7bf8d3a3..00000000 --- a/tests/qml/resources/apps/app2/qml/appwidgets/GreenRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "green" -} diff --git a/tests/qml/resources/apps/app2/qml/appwidgets/qmldir b/tests/qml/resources/apps/app2/qml/appwidgets/qmldir deleted file mode 100644 index a158bf25..00000000 --- a/tests/qml/resources/apps/app2/qml/appwidgets/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module appwidgets -GreenRect 1.0 GreenRect.qml diff --git a/tests/qml/resources/qml/widgets/MagentaRect.qml b/tests/qml/resources/qml/widgets/MagentaRect.qml deleted file mode 100644 index 511cea95..00000000 --- a/tests/qml/resources/qml/widgets/MagentaRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "magenta" -} diff --git a/tests/qml/resources/qml/widgets/RedRect.qml b/tests/qml/resources/qml/widgets/RedRect.qml deleted file mode 100644 index a27122e7..00000000 --- a/tests/qml/resources/qml/widgets/RedRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "red" -} diff --git a/tests/qml/resources/qml/widgets/qmldir b/tests/qml/resources/qml/widgets/qmldir deleted file mode 100644 index be36132a..00000000 --- a/tests/qml/resources/qml/widgets/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module widgets -RedRect 1.0 RedRect.qml -MagentaRect 1.0 MagentaRect.qml diff --git a/tests/qml/resources/relative/elements/LinenRect.qml b/tests/qml/resources/relative/elements/LinenRect.qml deleted file mode 100644 index 1fdf9205..00000000 --- a/tests/qml/resources/relative/elements/LinenRect.qml +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2020 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 - -Rectangle { - color: "linen" -} diff --git a/tests/qml/resources/relative/elements/qmldir b/tests/qml/resources/relative/elements/qmldir deleted file mode 100644 index 16a01e45..00000000 --- a/tests/qml/resources/relative/elements/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module elements -LinenRect 1.0 LinenRect.qml diff --git a/tests/qml/resources/resources.pro b/tests/qml/resources/resources.pro deleted file mode 100644 index 6da64f00..00000000 --- a/tests/qml/resources/resources.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = test.pro \ - appcommon \ - apps/app1 \ - apps/app2 diff --git a/tests/qml/resources/systemuifile.qrc b/tests/qml/resources/systemuifile.qrc deleted file mode 100644 index ce48e1a4..00000000 --- a/tests/qml/resources/systemuifile.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - qml/widgets/RedRect.qml - qml/widgets/qmldir - - diff --git a/tests/qml/resources/systemuiplugin.qrc b/tests/qml/resources/systemuiplugin.qrc deleted file mode 100644 index 7fe63a54..00000000 --- a/tests/qml/resources/systemuiplugin.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - qml/widgets/MagentaRect.qml - - diff --git a/tests/qml/resources/test.pro b/tests/qml/resources/test.pro deleted file mode 100644 index 3553c02a..00000000 --- a/tests/qml/resources/test.pro +++ /dev/null @@ -1,18 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_resource.qml -TEST_APPS = app1 app2 - -DIRECTORIES = apps/app2/qml relative -FILES = am-config.yaml \ - apps/app1/icon.png apps/app1/info.yaml \ - apps/app2/icon.png apps/app2/info.yaml -DESTDIR = $$OUT_PWD -load(am-qml-testcase) - -RESOURCE_SOURCE = systemuifile.qrc -load(generate-resource) - -TEMPLATE = lib -TARGET = systemuiplugin -CONFIG += plugin -RESOURCES = systemuiplugin.qrc diff --git a/tests/qml/resources/tst_resource.qml b/tests/qml/resources/tst_resource.qml deleted file mode 100644 index 8eb0e406..00000000 --- a/tests/qml/resources/tst_resource.qml +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 -import widgets 1.0 - -TestCase { - id: testCase - when: windowShown - name: "ResourceTest" - - RedRect {} - MagentaRect {} - - SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - SignalSpy { - id: windowPropertyChangedSpy - target: WindowManager - signalName: "windowPropertyChanged" - } - - function test_basic_data() { - return [ { tag: "app1" }, - { tag: "app2" } ]; - } - - function test_basic(data) { - wait(1200); // wait for quicklaunch - - var app = ApplicationManager.application(data.tag); - windowPropertyChangedSpy.clear(); - - app.start(); - while (app.runState !== ApplicationObject.Running) - runStateChangedSpy.wait(3000); - - if (data.tag === "app2") { - windowPropertyChangedSpy.wait(2000); - compare(windowPropertyChangedSpy.count, 1); - compare(windowPropertyChangedSpy.signalArguments[0][0].windowProperty("meaning"), 42); - } - - app.stop(); - while (app.runState !== ApplicationObject.NotRunning) - runStateChangedSpy.wait(3000); - } -} diff --git a/tests/qml/simple/am-config.yaml b/tests/qml/simple/am-config.yaml deleted file mode 100644 index 2a515905..00000000 --- a/tests/qml/simple/am-config.yaml +++ /dev/null @@ -1,56 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -ui: - fullscreen: no - -systemProperties: - ignored: 42 - public: - pub1: 'pub1' - pubandpro: 'pub2' - pubandpri: 'pub3' - inall: 'public' - protected: - pro1: 'pro1' - pubandpro: 'pro2' - proandpri: 'pro4' - inall: 'protected' - nested: - level2: - level31: 'overwritten' - level32: 'hidden' - private: - booleanTest: on - stringTest: "pelagicore" - nullTest: ~ - intTest: -1 - floatTest: .5 - arrayTest: [ - "value1", - "value2" - ] - mapTest: { - "key1" : "1", - "key2" : "2" - } - nested: - level2: - level31: 31 - level21: 21 - level22: 22 - pubandpri: 'pri3' - proandpri: 'pri4' - inall: 'private' - -# development setup: -flags: - noSecurity: yes - noUiWatchdog: yes - -runtimes: - qml: - quitTime: 5000 diff --git a/tests/qml/simple/apps/tld.test.simple1/app1.qml b/tests/qml/simple/apps/tld.test.simple1/app1.qml deleted file mode 100644 index 11c7ad78..00000000 --- a/tests/qml/simple/apps/tld.test.simple1/app1.qml +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - - Rectangle { - anchors.centerIn: parent - width: 180; height: 180; radius: width/4 - color: "red" - } - - Connections { - target: ApplicationInterface - function onQuit() { - target.acknowledgeQuit(); - } - } -} diff --git a/tests/qml/simple/apps/tld.test.simple1/icon.png b/tests/qml/simple/apps/tld.test.simple1/icon.png deleted file mode 100644 index adb840ce..00000000 Binary files a/tests/qml/simple/apps/tld.test.simple1/icon.png and /dev/null differ diff --git a/tests/qml/simple/apps/tld.test.simple1/info.yaml b/tests/qml/simple/apps/tld.test.simple1/info.yaml deleted file mode 100644 index 49a0e1e4..00000000 --- a/tests/qml/simple/apps/tld.test.simple1/info.yaml +++ /dev/null @@ -1,23 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'tld.test.simple1' -icon: 'icon.png' -code: 'app1.qml' -runtime: 'qml' -version: '1.0' -name: - en: 'Simple1' -applicationProperties: - ignored: 42 - protected: - pro1: 'pro1' - proandpri: 'pro2' - private: - pri1: 'pri1' - proandpri: 'pri2' - -mimeTypes: [ - "x-scheme-handler/x-test", - "text/plain" - ] diff --git a/tests/qml/simple/apps/tld.test.simple2/app.qml b/tests/qml/simple/apps/tld.test.simple2/app.qml deleted file mode 100644 index 4f046770..00000000 --- a/tests/qml/simple/apps/tld.test.simple2/app.qml +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - - Rectangle { - anchors.centerIn: parent - width: 180; height: 180; radius: width/4 - color: "red" - } - - Connections { - target: ApplicationInterface - function onQuit() { - //Do nothing, so we get killed by appman - } - } -} diff --git a/tests/qml/simple/apps/tld.test.simple2/icon.png b/tests/qml/simple/apps/tld.test.simple2/icon.png deleted file mode 100644 index adb840ce..00000000 Binary files a/tests/qml/simple/apps/tld.test.simple2/icon.png and /dev/null differ diff --git a/tests/qml/simple/apps/tld.test.simple2/info.yaml b/tests/qml/simple/apps/tld.test.simple2/info.yaml deleted file mode 100644 index f3366712..00000000 --- a/tests/qml/simple/apps/tld.test.simple2/info.yaml +++ /dev/null @@ -1,13 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'tld.test.simple2' -icon: 'icon.png' -code: 'app.qml' -runtime: 'qml' -name: - en: 'Caps' - -capabilities: -- cameraAccess -- locationAccess diff --git a/tests/qml/simple/simple.pro b/tests/qml/simple/simple.pro deleted file mode 100644 index 72dbea95..00000000 --- a/tests/qml/simple/simple.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_applicationmanager.qml -TEST_APPS = tld.test.simple1 tld.test.simple2 - -load(am-qml-testcase) diff --git a/tests/qml/simple/text-file.txt b/tests/qml/simple/text-file.txt deleted file mode 100644 index 0a05cde5..00000000 --- a/tests/qml/simple/text-file.txt +++ /dev/null @@ -1 +0,0 @@ -mimeType test diff --git a/tests/qml/simple/tst_applicationmanager.qml b/tests/qml/simple/tst_applicationmanager.qml deleted file mode 100644 index ce3db553..00000000 --- a/tests/qml/simple/tst_applicationmanager.qml +++ /dev/null @@ -1,487 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtQuick.Window 2.0 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "ApplicationManager" - - property var simpleApplication - property var capsApplication - // Either appman is build in single-process mode or it was started with --force-single-process - property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1 - || buildConfig[0].CONFIG.indexOf("multi-process") === -1 - property QtObject windowHandler: QtObject { - function windowAddedHandler(window) { - // console.info("window " + window + " added"); - } - - function windowContentStateChangedHandler(window) { - // console.info("window content state = " + window.contentState); - } - } - - ListView { - id: listView - model: ApplicationManager - delegate: Item { - property var modelData: model - } - } - - ApplicationModel { - id: appModel - sortFunction: function(la, ra) { return la.id > ra.id } - } - - function initTestCase() { - //Wait for the debugging wrappers to be setup. - wait(2000); - WindowManager.windowAdded.connect(windowHandler.windowAddedHandler) - WindowManager.windowContentStateChanged.connect(windowHandler.windowContentStateChangedHandler) - - compare(ApplicationManager.count, 2) - simpleApplication = ApplicationManager.application(0); - capsApplication = ApplicationManager.application(1); - } - - function test_properties() { - // Only true for the dummyimports - compare(ApplicationManager.dummy, false) - // Disabled in the am-config.yaml - compare(ApplicationManager.securityChecksEnabled, false) - - compare(ApplicationManager.singleProcess, singleProcess) - } - - function test_systemProperties() { - compare(ApplicationManager.systemProperties.ignored, undefined) - compare(ApplicationManager.systemProperties.booleanTest, true) - compare(ApplicationManager.systemProperties.stringTest, "pelagicore") - compare(ApplicationManager.systemProperties.intTest, -1) - compare(ApplicationManager.systemProperties.floatTest, .5) - compare(ApplicationManager.systemProperties.arrayTest[0], "value1") - compare(ApplicationManager.systemProperties.arrayTest[1], "value2") - compare(ApplicationManager.systemProperties.mapTest["key1"], "1") - compare(ApplicationManager.systemProperties.mapTest["key2"], "2") - compare(ApplicationManager.systemProperties.nested.level21, 21) - compare(ApplicationManager.systemProperties.nested.level2.level31, 31) - compare(ApplicationManager.systemProperties.nested.level2.level32, undefined) - compare(ApplicationManager.systemProperties.nested.level21, 21) - compare(ApplicationManager.systemProperties.nested.level22, 22) - compare(ApplicationManager.systemProperties.pub1, 'pub1') - compare(ApplicationManager.systemProperties.pro1, 'pro1') - compare(ApplicationManager.systemProperties.pubandpro, 'pro2') - compare(ApplicationManager.systemProperties.pubandpri, 'pri3') - compare(ApplicationManager.systemProperties.proandpri, 'pri4') - compare(ApplicationManager.systemProperties.inall, 'private') - compare(ApplicationManager.systemProperties.nullTest, null) - } - - function test_package() { - compare(PackageManager.count, 2) - verify(simpleApplication.package !== capsApplication.package) - compare(simpleApplication.package, PackageManager.package("tld.test.simple1")) - compare(simpleApplication.package.id, "tld.test.simple1") - compare(simpleApplication.package.applications.length, 1) - compare(simpleApplication.package.applications[0], simpleApplication) - } - - function test_application() { - var id = simpleApplication.id; - compare(simpleApplication.id, "tld.test.simple1") - compare(simpleApplication.runtimeName, "qml") - compare(simpleApplication.icon.toString(), Qt.resolvedUrl("apps/tld.test.simple1/icon.png")) - compare(simpleApplication.documentUrl, "") - compare(simpleApplication.builtIn, true) - compare(simpleApplication.alias, false) - compare(simpleApplication.nonAliased, simpleApplication) - compare(simpleApplication.capabilities.length, 0) - compare(simpleApplication.supportedMimeTypes.length, 2) - compare(simpleApplication.categories.length, 0) - //Why is runtime null ? we should document this, as this is not really clear - compare(simpleApplication.runtime, null) - compare(simpleApplication.lastExitCode, 0) - compare(simpleApplication.lastExitStatus, Am.NormalExit) - compare(simpleApplication.version, "1.0") - - // Test the name getter and verify that it's returning the same object - compare(simpleApplication, ApplicationManager.application(id)) - } - - function test_applicationProperties() { - compare(simpleApplication.applicationProperties.ignored, undefined) - compare(simpleApplication.applicationProperties.pro1, "pro1") - compare(simpleApplication.applicationProperties.proandpri, "pro2") - compare(simpleApplication.applicationProperties.pri1, undefined) - } - - function test_indexOfApplication() { - // Test index of - compare(ApplicationManager.indexOfApplication(simpleApplication.id), 0) - compare(ApplicationManager.indexOfApplication(capsApplication.id), 1) - compare(ApplicationManager.indexOfApplication("error"), -1) - } - - function test_applicationIds() { - // Test app ids - var apps = ApplicationManager.applicationIds() - compare(apps.length, ApplicationManager.count) - compare(ApplicationManager.applicationIds()[0], simpleApplication.id) - compare(ApplicationManager.applicationIds()[1], capsApplication.id) - } - - function test_capabilities() { - var emptyCaps = ApplicationManager.capabilities(simpleApplication.id) - compare(emptyCaps.length, 0) - var caps = ApplicationManager.capabilities(capsApplication.id) - compare(caps.length, 2) - } - - function test_modelData() { - compare(listView.count, ApplicationManager.count) - listView.currentIndex = 0; - compare(listView.currentItem.modelData.application, simpleApplication) - compare(listView.currentItem.modelData.applicationId, simpleApplication.id) - compare(listView.currentItem.modelData.name, "Simple1") - compare(listView.currentItem.modelData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon)) - compare(listView.currentItem.modelData.runtimeName, "qml") - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isShuttingDown, false) - compare(listView.currentItem.modelData.isBlocked, false) - compare(listView.currentItem.modelData.isUpdating, false) - compare(listView.currentItem.modelData.isRemovable, false) - compare(listView.currentItem.modelData.updateProgress, 0.0) - verify(listView.currentItem.modelData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1) - compare(listView.currentItem.modelData.capabilities, simpleApplication.capabilities) - compare(listView.currentItem.modelData.version, "1.0") - } - - SignalSpy { - id: appModelCountSpy - target: appModel - signalName: "countChanged" - } - - function test_applicationModel() { - compare(appModel.count, 2); - compare(appModel.indexOfApplication(capsApplication.id), 0); - compare(appModel.indexOfApplication(simpleApplication.id), 1); - compare(appModel.mapToSource(0), ApplicationManager.indexOfApplication(capsApplication.id)); - compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 1); - - appModel.sortFunction = undefined; - compare(appModel.indexOfApplication(simpleApplication.id), - ApplicationManager.indexOfApplication(simpleApplication.id)); - compare(appModel.indexOfApplication(capsApplication.id), - ApplicationManager.indexOfApplication(capsApplication.id)); - - appModelCountSpy.clear(); - appModel.filterFunction = function(app) { return app.capabilities.indexOf("cameraAccess") >= 0; }; - appModelCountSpy.wait(1000); - compare(appModelCountSpy.count, 1); - compare(appModel.count, 1); - compare(appModel.indexOfApplication(capsApplication.id), 0); - compare(appModel.indexOfApplication(simpleApplication.id), -1); - - listView.model = appModel; - listView.currentIndex = 0; - compare(listView.currentItem.modelData.name, "Caps"); - listView.model = ApplicationManager; - - appModel.filterFunction = function() {}; - compare(appModel.count, 0); - - appModel.filterFunction = undefined; - compare(appModel.count, 2); - } - - function test_get_data() { - return [ - {tag: "get(row)", argument: 0 }, - {tag: "get(id)", argument: simpleApplication.id }, - ]; - } - - function test_get(data) { - var appData = ApplicationManager.get(data.argument); - - compare(appData.application, simpleApplication) - compare(appData.applicationId, simpleApplication.id) - compare(appData.name, "Simple1") - compare(appData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon)) - compare(appData.runtimeName, "qml") - compare(appData.isRunning, false) - compare(appData.isStartingUp, false) - compare(appData.isShuttingDown, false) - compare(appData.isBlocked, false) - compare(appData.isUpdating, false) - compare(appData.isRemovable, false) - compare(appData.updateProgress, 0.0) - verify(appData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1) - compare(appData.capabilities, simpleApplication.capabilities) - compare(appData.version, "1.0") - } - - function test_application_object_ownership() { - // Check that the returned Application is not owned by javascript and deleted - // by the garbage collector - var app = ApplicationManager.application(0); - var id = app.id - app = null; - // app gets deleted now as there is now javascript reference anymore - gc() - // Test that the Application in the ApplicationManager is still valid - // by accessing one of it's properties - compare(id, ApplicationManager.application(0).id) - } - - SignalSpy { - id: runStateChangedSpy - target: ApplicationManager - signalName: "applicationRunStateChanged" - } - - function checkApplicationState(id, state) { - if (runStateChangedSpy.count < 1) - runStateChangedSpy.wait(10000); - verify(runStateChangedSpy.count) - compare(runStateChangedSpy.signalArguments[0][0], id) - compare(runStateChangedSpy.signalArguments[0][1], state) - compare(ApplicationManager.application(id).runState, state); - runStateChangedSpy.clear(); - } - - function test_startAndStopApplication_data() { - return [ - {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false, - exitCode: 0, exitStatus: Am.NormalExit }, - {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false, - exitCode: 0, exitStatus: Am.NormalExit }, - {tag: "ForceKill", appId: "tld.test.simple2", index: 1, forceKill: true, - exitCode: Qt.platform.os !== 'windows' ? 9 : 0, - exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }, - {tag: "AutoTerminate", appId: "tld.test.simple2", index: 1, forceKill: false, - exitCode: Qt.platform.os !== 'windows' ? 15 : 0, - exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit } - ]; - } - - function test_startAndStopApplication(data) { - compare(ApplicationManager.application(data.appId).runState, Am.NotRunning); - - var started = false; - if (data.tag === "Debug") { - if (singleProcess) - ignoreWarning("Using debug-wrappers is not supported when the application manager is running in single-process mode."); - started = ApplicationManager.debugApplication(data.appId, "%program% %arguments%"); - if (singleProcess) { - verify(!started); - return; - } - } else { - started = ApplicationManager.startApplication(data.appId); - } - verify(started); - - checkApplicationState(data.appId, Am.StartingUp); - listView.currentIndex = data.index; - compare(listView.currentItem.modelData.isStartingUp, true) - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isShuttingDown, false) - checkApplicationState(data.appId, Am.Running); - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isRunning, true) - compare(listView.currentItem.modelData.isShuttingDown, false) - - ApplicationManager.stopApplication(data.appId, data.forceKill); - - checkApplicationState(data.appId, Am.ShuttingDown); - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isShuttingDown, true) - checkApplicationState(data.appId, Am.NotRunning); - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isShuttingDown, false) - compare(listView.currentItem.modelData.application.lastExitCode, data.exitCode) - compare(listView.currentItem.modelData.application.lastExitStatus, data.exitStatus) - } - - function test_startAndStopAllApplications_data() { - return [ - {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0, - appId2: "tld.test.simple2", index2: 1, forceKill: false, exitCode: 0, - exitStatus: Am.NormalExit } - ]; - } - - function test_startAndStopAllApplications(data) { - compare(ApplicationManager.application(data.appId1).runState, Am.NotRunning); - compare(ApplicationManager.application(data.appId2).runState, Am.NotRunning); - - var started = false; - - started = ApplicationManager.startApplication(data.appId1); - verify(started); - - - checkApplicationState(data.appId1, Am.StartingUp); - listView.currentIndex = data.index1; - compare(listView.currentItem.modelData.isStartingUp, true) - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isShuttingDown, false) - checkApplicationState(data.appId1, Am.Running); - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isRunning, true) - compare(listView.currentItem.modelData.isShuttingDown, false) - - started = ApplicationManager.startApplication(data.appId2); - verify(started); - - checkApplicationState(data.appId2, Am.StartingUp); - listView.currentIndex = data.index2; - compare(listView.currentItem.modelData.isStartingUp, true) - compare(listView.currentItem.modelData.isRunning, false) - compare(listView.currentItem.modelData.isShuttingDown, false) - checkApplicationState(data.appId2, Am.Running); - compare(listView.currentItem.modelData.isStartingUp, false) - compare(listView.currentItem.modelData.isRunning, true) - compare(listView.currentItem.modelData.isShuttingDown, false) - - ApplicationManager.stopAllApplications(data.forceKill); - - while (runStateChangedSpy.count < 4) - runStateChangedSpy.wait(10000); - - var args = runStateChangedSpy.signalArguments - - for (var i = 0; i < 4; ++i) { - var id = args[i][0] - var state = args[i][1] - - var atPos = id.indexOf('@') - if (atPos >= 0) - id = id.substring(0, atPos) - - // not perfect, but the basic signal sequence is already tested in test_startAndStopApplication - verify(id === data.appId1 || id === data.appId2, "id = " + id) - verify(state === Am.ShuttingDown || state === Am.NotRunning) - } - runStateChangedSpy.clear() - } - - function test_errors() { - ignoreWarning("ApplicationManager::application(index): invalid index: -1"); - verify(!ApplicationManager.application(-1)); - verify(!ApplicationManager.application("invalidApplication")); - ignoreWarning("ApplicationManager::get(index): invalid index: -1"); - compare(ApplicationManager.get(-1), {}); - compare(ApplicationManager.get("invalidApplication"), {}); - compare(ApplicationManager.applicationRunState("invalidApplication"), Am.NotRunning); - - ignoreWarning("Cannot start application: id 'invalidApplication' is not known"); - verify(!ApplicationManager.startApplication("invalidApplication")) - - //All following tests don't work in single-process mode - if (singleProcess) - return; - - ignoreWarning("Tried to start application tld.test.simple1 using an invalid debug-wrapper specification: "); - verify(!ApplicationManager.debugApplication(simpleApplication.id, " ")) - - verify(ApplicationManager.startApplication(simpleApplication.id)); - checkApplicationState(simpleApplication.id, Am.StartingUp); - checkApplicationState(simpleApplication.id, Am.Running); - ignoreWarning("Application tld.test.simple1 is already running - cannot start with debug-wrapper: %program% %arguments%"); - verify(!ApplicationManager.debugApplication(simpleApplication.id, "%program% %arguments%")) - ApplicationManager.stopApplication(simpleApplication.id, true); - checkApplicationState(simpleApplication.id, Am.ShuttingDown); - checkApplicationState(simpleApplication.id, Am.NotRunning); - } - - function test_openUrl_data() { - return [ - {tag: "customMimeType", url: "x-test://12345", expectedApp: simpleApplication.id }, - {tag: "text/plain", url: "file://text-file.txt", expectedApp: simpleApplication.id } - ]; - } - - function test_openUrl(data) { - verify(ApplicationManager.openUrl(data.url)); - checkApplicationState(data.expectedApp, Am.StartingUp); - checkApplicationState(data.expectedApp, Am.Running); - ApplicationManager.stopApplication(data.expectedApp, true); - checkApplicationState(data.expectedApp, Am.ShuttingDown); - checkApplicationState(data.expectedApp, Am.NotRunning); - - Qt.openUrlExternally(data.url); - checkApplicationState(data.expectedApp, Am.StartingUp); - checkApplicationState(data.expectedApp, Am.Running); - ApplicationManager.stopApplication(data.expectedApp, true); - checkApplicationState(data.expectedApp, Am.ShuttingDown); - checkApplicationState(data.expectedApp, Am.NotRunning); - } - - property bool containerSelectionCalled: false - property string containerSelectionAppId - property string containerSelectionConId - function containerSelection(appId, containerId) { - containerSelectionCalled = true; - containerSelectionAppId = appId; - containerSelectionConId = containerId; - - return containerId; - } - - function test_containerSelectionFunction() { - if (singleProcess) - skip("The containerSelectionFunction doesn't work in single-process mode"); - - compare(ApplicationManager.containerSelectionFunction, undefined); - ApplicationManager.containerSelectionFunction = containerSelection; - ApplicationManager.startApplication(simpleApplication.id); - checkApplicationState(simpleApplication.id, Am.StartingUp); - checkApplicationState(simpleApplication.id, Am.Running); - ApplicationManager.stopApplication(simpleApplication.id, true); - checkApplicationState(simpleApplication.id, Am.ShuttingDown); - checkApplicationState(simpleApplication.id, Am.NotRunning); - verify(containerSelectionCalled); - compare(containerSelectionAppId, simpleApplication.id); - compare(containerSelectionConId, "process"); - } -} diff --git a/tests/qml/windowitem/am-config.yaml b/tests/qml/windowitem/am-config.yaml deleted file mode 100644 index aa82540b..00000000 --- a/tests/qml/windowitem/am-config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - installationDir: "/tmp/am/apps" - documentDir: "/tmp/am/docs" - -# Workaround for a crash in the mesa software renderer (llvmpipe) -runtimes: - qml: - environmentVariables: - QT_QUICK_BACKEND: "software" diff --git a/tests/qml/windowitem/apps/test.windowitem.app/icon.png b/tests/qml/windowitem/apps/test.windowitem.app/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowitem/apps/test.windowitem.app/icon.png and /dev/null differ diff --git a/tests/qml/windowitem/apps/test.windowitem.app/info.yaml b/tests/qml/windowitem/apps/test.windowitem.app/info.yaml deleted file mode 100644 index 1ef6fd93..00000000 --- a/tests/qml/windowitem/apps/test.windowitem.app/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.windowitem.app' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'WindowItem Test App' diff --git a/tests/qml/windowitem/apps/test.windowitem.app/main.qml b/tests/qml/windowitem/apps/test.windowitem.app/main.qml deleted file mode 100644 index 0fec1364..00000000 --- a/tests/qml/windowitem/apps/test.windowitem.app/main.qml +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - color: "red" - - width: 123 - height: 321 - - MouseArea { - id: mouseArea - property int clickCount: 0 - anchors.fill: parent - onClicked: { - clickCount += 1; - root.setWindowProperty("clickCount", clickCount); - } - } - - // A way for test code to trigger ApplicationManagerWindow's size changes from - // the client side - onWindowPropertyChanged: { - if (name === "requestedWidth") - root.width = value; - else if (name === "requestedHeight") - root.height = value; - } - - Component.onCompleted: { - root.setWindowProperty("clickCount", mouseArea.clickCount); - } -} diff --git a/tests/qml/windowitem/apps/test.windowitem.multiwin/icon.png b/tests/qml/windowitem/apps/test.windowitem.multiwin/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowitem/apps/test.windowitem.multiwin/icon.png and /dev/null differ diff --git a/tests/qml/windowitem/apps/test.windowitem.multiwin/info.yaml b/tests/qml/windowitem/apps/test.windowitem.multiwin/info.yaml deleted file mode 100644 index 2c44d5d3..00000000 --- a/tests/qml/windowitem/apps/test.windowitem.multiwin/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.windowitem.multiwin' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'Multiple Windows Test App' diff --git a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml b/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml deleted file mode 100644 index c3e0607d..00000000 --- a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -/* - A simple test app that displays two windows -*/ -QtObject { - property var blueWindow: ApplicationManagerWindow { - color: "blue" - width: 123 - height: 321 - } - property var orangeWindow: ApplicationManagerWindow { - color: "orange" - width: 321 - height: 123 - } -} diff --git a/tests/qml/windowitem/tst_windowitem.qml b/tests/qml/windowitem/tst_windowitem.qml deleted file mode 100644 index 1ad7d319..00000000 --- a/tests/qml/windowitem/tst_windowitem.qml +++ /dev/null @@ -1,482 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -Item { - id: root - width: 500 - height: 500 - visible: true - - Repeater { - id: windowItemsRepeater - model: ListModel { id: windowItemsModel } - delegate: WindowItem { - id: windowItem - window: model.window - - property int clickCount: 0 - property alias mouseAreaVisible: mouseArea.visible - - MouseArea { - id: mouseArea - anchors.fill: parent - onClicked: windowItem.clickCount += 1; - z: -100 // some arbitrary, negative, Z - } - } - } - Repeater { - id: sizedWindowItemsRepeater - model: ListModel { id: sizedWindowItemsModel } - delegate: WindowItem { - width: 200 - height: 100 - window: model.window - } - } - Repeater { - id: noResizeWindowItemsRepeater - model: ListModel { id: noResizeWindowItemsModel } - delegate: WindowItem { - width: 200 - height: 100 - objectFollowsItemSize: false - window: model.window - } - } - property var chosenModel - Connections { - target: WindowManager - function onWindowAdded(window) { - root.chosenModel.append({"window":window}); - } - } - - // Force redraws so that pings and other events are quickly processed between - // wayland client and server. - Rectangle { - width: 10 - height: 10 - color: "brown" - RotationAnimator on rotation { - from: 0; to: 360; duration: 1000 - loops: Animation.Infinite - running: true - } - } - - SignalSpy { -        id: objectDestroyedSpy -        target: AmTest -        signalName: "objectDestroyed" -    } - - TestCase { - id: testCase - when: windowShown - name: "WindowItem" - - property var app: null - - function init() { - compare(windowItemsModel.count, 0); - compare(sizedWindowItemsModel.count, 0); - compare(noResizeWindowItemsRepeater.count, 0); - compare(WindowManager.count, 0); - } - - function cleanup() { - windowItemsModel.clear(); - sizedWindowItemsModel.clear(); - noResizeWindowItemsModel.clear(); - - if (app) - app.stop(); - - waitUntilAllAppsAreStopped(); - } - - function waitUntilAllAppsAreStopped() { - while (true) { - var numRunningApps = 0; - for (var i = 0; i < ApplicationManager.count; i++) { - var app = ApplicationManager.application(i); - if (app.runState !== Am.NotRunning) - numRunningApps += 1; - } - - if (numRunningApps > 0) { - wait(50); - } else - break; - } - } - - function initWindowItemsModel() { - root.chosenModel = windowItemsModel; - startAppAndCheckWindow(); - } - - function initSizedWindowItemsModel() { - root.chosenModel = sizedWindowItemsModel; - startAppAndCheckWindow(); - } - - function startAppAndCheckWindow() { - app = ApplicationManager.application("test.windowitem.app"); - app.start(); - - tryCompare(root.chosenModel, "count", 1); - tryCompare(WindowManager, "count", 1); - } - - /* - The first WindowItem showing a window have primary==true, from the - second onwards they should have primary==false - */ - function test_onlyFirstItemIsPrimary() { - initWindowItemsModel(); - var firstWindowItem = windowItemsRepeater.itemAt(0); - compare(firstWindowItem.primary, true); - - // Add a second view for the same WindowObject - windowItemsModel.append({"window":firstWindowItem.window}); - - var secondWindowItem = windowItemsRepeater.itemAt(1); - compare(secondWindowItem.primary, false); - } - - /* - Turn a secondary WindowItem (primary == false) into the primary one. - - Check that the previously primary is now secondary and vice-versa. - */ - function test_turnSecondaryIntoPrimary() { - initWindowItemsModel(); - var firstWindowItem = windowItemsRepeater.itemAt(0); - - // Add a second view for the same WindowObject - windowItemsModel.append({"window":firstWindowItem.window}); - - var secondWindowItem = windowItemsRepeater.itemAt(1); - - compare(firstWindowItem.primary, true); - compare(secondWindowItem.primary, false); - - // give primary role to the second WindowItem - secondWindowItem.makePrimary(); - - compare(firstWindowItem.primary, false); - compare(secondWindowItem.primary, true); - - // and take it back - firstWindowItem.makePrimary(); - - compare(firstWindowItem.primary, true); - compare(secondWindowItem.primary, false); - } - - /* - You have two WindowItems for the same WindowObject - - Check that once the primary WindowItem is destroyed, - the remaining one takes over the primary role. - */ - function test_destroyPrimaryRemainingTakesOver() { - initWindowItemsModel(); - var firstWindowItem = windowItemsRepeater.itemAt(0); - - // Add a second view for the same WindowObject - windowItemsModel.append({"window":firstWindowItem.window}); - - var secondWindowItem = windowItemsRepeater.itemAt(1); - - compare(firstWindowItem.primary, true); - compare(secondWindowItem.primary, false); - - compare(windowItemsModel.count, 2); - - // destroy the first WindowItem - windowItemsModel.remove(0 /*index*/, 1 /*count*/); - firstWindowItem = null; - - compare(windowItemsModel.count, 1); - - // And the remaining item takes over the primary role. - tryCompare(secondWindowItem, "primary", true); - } - - /* - Check that a WindowObject with state NoSurface is destroyed - only once all WindowItems using it are gone. - */ - function test_surfacelessObjectStaysUntilAllItemsAreGone() { - initWindowItemsModel(); - var firstWindowItem = windowItemsRepeater.itemAt(0); - - // Add a second view for the same WindowObject - windowItemsModel.append({"window":firstWindowItem.window}); - - var secondWindowItem = windowItemsRepeater.itemAt(1); - - var window = WindowManager.get(0).window; - objectDestroyedSpy.clear(); - var destroyId = AmTest.observeObjectDestroyed(window); - - compare(window.contentState, WindowObject.SurfaceWithContent); - app.stop(); - - // The WindowObject should still exist, albeit without a surface, even though - // no longer present in WindowManager's model. - tryCompare(WindowManager, "count", 0); - compare(objectDestroyedSpy.count, 0) - tryCompare(window, "contentState", WindowObject.NoSurface); - - // Destroy all WindowItems - firstWindowItem = null; - secondWindowItem = null; - windowItemsModel.clear(); - - // Now that there are no WindowItems using that WindowObject anymore, it should - // eventually be deleted by WindowManager - objectDestroyedSpy.wait(); - compare(objectDestroyedSpy.signalArguments[0][0], destroyId); - } - - /* - Checks that the implicit size of a WindowItem matches the explicit size of the client's ApplicationManagerWindow - */ - function test_implicitSize() { - initWindowItemsModel(); - var windowItem = windowItemsRepeater.itemAt(0); - var window = windowItem.window - - // Must match the ApplicationManagerWindow size defined in apps/test.windowitem.app/mail.qml - compare(window.size.width, 123); - compare(window.size.height, 321); - compare(windowItem.width, 123); - compare(windowItem.height, 321); - - // Avoid a race condition where the item's implicit size (and therefore the item's - // size itself as no explicit width or height was assigned) would be set to match - // the window's size while at the same time an item's resize would make the item resize the window. - // In short: item size depending on window size while at the same time window size is - // depending on item size. - windowItem.objectFollowsItemSize = false; - - var width = 130; - var height = 330; - var i; - for (i = 0; i < 20; i += 1) { - window.setWindowProperty("requestedWidth", width); - window.setWindowProperty("requestedHeight", height); - - tryCompare(window, "size", Qt.size(width,height)); - tryCompare(windowItem, "width", width); - tryCompare(windowItem, "height", height); - - width += 5; - height += 5; - wait(10); - } - } - - /* - Checks that once a Window is assinged to a WindowItem its underlying surface - gets resized to match that WindowItem's size (considering it's the first, - primary, one) - */ - function test_initialResize() { - initSizedWindowItemsModel(); - var windowItem = sizedWindowItemsRepeater.itemAt(0); - var window = windowItem.window - - tryCompare(window, "size", Qt.size(windowItem.width, windowItem.height)); - } - - /* - By default a WindowItem will resize the WindowObject it's displaying to match his own size. - So resizing a WindowItem will cause his WindowObject to follow suit, so that both always - have matching sizes. - */ - function test_objectFollowsItemSize() { - initSizedWindowItemsModel(); - var windowItem = sizedWindowItemsRepeater.itemAt(0); - var window = windowItem.window; - - windowItem.width = 200; - windowItem.height = 100; - tryCompare(window, "size", Qt.size(200, 100)); - - windowItem.width = 201; - windowItem.height = 101; - tryCompare(window, "size", Qt.size(201, 101)); - - windowItem.width = 202; - windowItem.height = 102; - tryCompare(window, "size", Qt.size(202, 102)); - } - - /* - When WindowItem.objectFollowsItemSize is false, resizing the WindowItem will have no effect - over the WindowObject's size. - */ - function test_windowDoesNotFolowItemSize() { - root.chosenModel = noResizeWindowItemsModel; - startAppAndCheckWindow(); - - var windowItem = noResizeWindowItemsRepeater.itemAt(0); - var window = windowItem.window; - - windowItem.width = 200; - windowItem.height = 100; - tryCompare(window, "size", Qt.size(123, 321)); - - windowItem.width = 201; - windowItem.height = 101; - tryCompare(window, "size", Qt.size(123, 321)); - - windowItem.width = 202; - windowItem.height = 102; - tryCompare(window, "size", Qt.size(123, 321)); - } - - /* - Checks that calling close() on an empty WindowObject won't cause a crash (particularly - in multi-process) - */ - function test_closeEmptyWindow() { - initWindowItemsModel(); - - var windowItem = windowItemsRepeater.itemAt(0); - var window = windowItem.window; - - app.stop(); - - tryCompare(window, "contentState", WindowObject.NoSurface); - - window.close(); - } - - /* - Regression test for https://bugreports.qt.io/browse/AUTOSUITE-652 - - - Start an application that has two windows. - - Call close() on the first one. It should vanish. Application should keep running normally. - - Call close() on the second one. It should vanish as well and, being the app's last window, it should - also cause the application to quit. - */ - function test_closeWindows() { - root.chosenModel = windowItemsModel; - - app = ApplicationManager.application("test.windowitem.multiwin"); - app.start(); - - tryCompare(windowItemsModel, "count", 2); - tryCompare(WindowManager, "count", 2); - - var firstWindow = windowItemsModel.get(0).window; - var secondWindow = windowItemsModel.get(1).window; - - compare(app.runState, Am.Running); - compare(firstWindow.contentState, WindowObject.SurfaceWithContent); - - firstWindow.close(); - - tryCompare(firstWindow, "contentState", WindowObject.NoSurface); - windowItemsModel.remove(0); - firstWindow = null; - - wait(100); - - compare(app.runState, Am.Running); - compare(secondWindow.contentState, WindowObject.SurfaceWithContent); - - secondWindow.close(); - - tryCompare(secondWindow, "contentState", WindowObject.NoSurface); - tryCompare(app, "runState", Am.NotRunning); - } - - /* - Children added by System UI code must always stay in front of WindowItem's own private children. - */ - function test_childrenZOrder() { - initWindowItemsModel(); - - var windowItem = windowItemsRepeater.itemAt(0); - var window = windowItem.window; - - windowItem.mouseAreaVisible = false; - - touchEvent(windowItem).press(0).commit(); - touchEvent(windowItem).release(0).commit(); - - // There's nothing in front of the wayland item (at least nothing visible). - // The touch event will reach it. - tryVerify(function() { return window.windowProperty("clickCount") === 1; }); - compare(windowItem.clickCount, 0); - - windowItem.mouseAreaVisible = true; - - touchEvent(windowItem).press(0).commit(); - touchEvent(windowItem).release(0).commit(); - - // Since a visible MouseArea is now in front of WindowItem's internal wayland item - // the second touch event was caught by that MouseArea instead. - tryCompare(windowItem, "clickCount", 1); - compare(window.windowProperty("clickCount"), 1); - - } - - // Checks that window properties are kept even when contentState is WindowObject.NoSurface - // Regression test for https://bugreports.qt.io/browse/AUTOSUITE-694 - function test_window_keep_properties_when_nosurface() { - initWindowItemsModel(); - - var window = windowItemsModel.get(0).window; - - compare(window.contentState, WindowObject.SurfaceWithContent); - - window.setWindowProperty("foo", "bar"); - compare(window.windowProperty("foo"), "bar"); - - app.stop(); - - tryCompare(window, "contentState", WindowObject.NoSurface); - compare(window.windowProperty("foo"), "bar"); - } - } -} diff --git a/tests/qml/windowitem/windowitem.pro b/tests/qml/windowitem/windowitem.pro deleted file mode 100644 index fcc1b1f6..00000000 --- a/tests/qml/windowitem/windowitem.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_windowitem.qml -TEST_APPS = test.windowitem.app test.windowitem.multiwin - -load(am-qml-testcase) diff --git a/tests/qml/windowitem2/am-config.yaml b/tests/qml/windowitem2/am-config.yaml deleted file mode 100644 index 5333dae3..00000000 --- a/tests/qml/windowitem2/am-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -# Workaround for a crash in the mesa software renderer (llvmpipe) -runtimes: - qml: - environmentVariables: - QT_QUICK_BACKEND: "software" diff --git a/tests/qml/windowitem2/apps/test.windowitem2.app/icon.png b/tests/qml/windowitem2/apps/test.windowitem2.app/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowitem2/apps/test.windowitem2.app/icon.png and /dev/null differ diff --git a/tests/qml/windowitem2/apps/test.windowitem2.app/info.yaml b/tests/qml/windowitem2/apps/test.windowitem2.app/info.yaml deleted file mode 100644 index 34198c88..00000000 --- a/tests/qml/windowitem2/apps/test.windowitem2.app/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.windowitem2.app' -icon: 'icon.png' -code: 'main.qml' -runtime: 'qml' -name: - en: 'WindowItem2 Test App' diff --git a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml b/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml deleted file mode 100644 index a0c453aa..00000000 --- a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - color: "red" - - width: 123 - height: 321 -} diff --git a/tests/qml/windowitem2/tst_windowitem2.qml b/tests/qml/windowitem2/tst_windowitem2.qml deleted file mode 100644 index 51759539..00000000 --- a/tests/qml/windowitem2/tst_windowitem2.qml +++ /dev/null @@ -1,130 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -Item { - id: root - width: 500 - height: 500 - visible: true - - WindowItem { - id: windowItem - } - - Connections { - target: WindowManager - function onWindowAdded(window) { - windowItem.window = window; - } - - function onWindowAboutToBeRemoved(window) { - if (window === windowItem.window) { - windowItem.window = null; - } - } - } - - // Force redraws so that pings and other events are quickly processed between - // wayland client and server. - Rectangle { - width: 10 - height: 10 - color: "brown" - RotationAnimator on rotation { - from: 0; to: 360; duration: 1000 - loops: Animation.Infinite - running: true - } - } - - TestCase { - id: testCase - when: windowShown - name: "WindowItem2" - - function init() { - } - - function cleanup() { - waitUntilAllAppsAreStopped(); - } - - function waitUntilAllAppsAreStopped() { - while (true) { - var numRunningApps = 0; - for (var i = 0; i < ApplicationManager.count; i++) { - var app = ApplicationManager.application(i); - if (app.runState !== Am.NotRunning) - numRunningApps += 1; - } - - if (numRunningApps > 0) { - wait(50); - } else - break; - } - } - - /* - The sequence below only takes place if WindowManager has direct connections to - Window::isBeingDisplayedChanged and Window::contentStateChanged and those connections call - WindowManager::removeWindow: - - 1. When Window.contentState changes to Window::NoSurface, WindowManager calls removeWindow() on it. - 2. Inside WindowManager::removeWindow, windowAboutToBeRemoved gets emitted. - 3. The onWindowAboutToBeRemoved signal handler above is called and sets WindowItem.window to null - 4. That causes Window.isBeingDisplayedChanged to turn to false, which in turn gets - WindowManager to call removeWindow() on that same window once again. - 5. The innermost removeWindow() from 4 successfuly executes and removes the window from WindowManager's - internal vector - 6. once the outermost removeWindow() from 1. finally goes past the signal emission from 2. and tries - to remove the item from for index it previously collected, that index is no longer valid as the vector - already changed. Then you either are removing the wrong item or trying to remove a now invalid index, - which causes a crash. - - This is a regression test for such crash - */ - function test_triggerNestedRemoval() { - var app = ApplicationManager.application("test.windowitem2.app"); - app.start(); - - tryVerify(function() { return windowItem.window !== null }); - wait(50); - - app.stop(); - } - - } -} diff --git a/tests/qml/windowitem2/windowitem2.pro b/tests/qml/windowitem2/windowitem2.pro deleted file mode 100644 index 022ea053..00000000 --- a/tests/qml/windowitem2/windowitem2.pro +++ /dev/null @@ -1,5 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_windowitem2.qml -TEST_APPS = test.windowitem2.app - -load(am-qml-testcase) diff --git a/tests/qml/windowmanager/IviApplicationExtension.qml b/tests/qml/windowmanager/IviApplicationExtension.qml deleted file mode 100644 index 08486dc4..00000000 --- a/tests/qml/windowmanager/IviApplicationExtension.qml +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import QtApplicationManager.SystemUI 2.0 -import QtWayland.Compositor 1.1 - -QtObject { - property Component iviComp: Component { - IviApplication {} - } - - function addExtension() { - return WindowManager.addExtension(iviComp); - } -} diff --git a/tests/qml/windowmanager/tst_windowmanager.qml b/tests/qml/windowmanager/tst_windowmanager.qml deleted file mode 100644 index 5927fae1..00000000 --- a/tests/qml/windowmanager/tst_windowmanager.qml +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.11 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "WindowManager" - visible: true - - Component { - id: textComp - Text {} - } - - SignalSpy { - id: windowManagerCompositorReadyChangedSpy - target: ApplicationManager - signalName: "windowManagerCompositorReadyChanged" - } - - function test_addExtension() { - if (!ApplicationManager.singleProcess) { - if (!ApplicationManager.windowManagerCompositorReady) { - var extnull = Qt.createComponent("IviApplicationExtension.qml").createObject(null).addExtension(); - compare(extnull, null); - windowManagerCompositorReadyChangedSpy.wait(2000); - verify(ApplicationManager.windowManagerCompositorReady); - } - var extension = Qt.createComponent("IviApplicationExtension.qml").createObject(null).addExtension(); - verify(extension); - verify(extension.hasOwnProperty('iviSurfaceCreated')); - } - compare(WindowManager.addExtension(textComp), null); - } -} diff --git a/tests/qml/windowmanager/windowmanager.pro b/tests/qml/windowmanager/windowmanager.pro deleted file mode 100644 index 21cd8a91..00000000 --- a/tests/qml/windowmanager/windowmanager.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEST_FILES = tst_windowmanager.qml - -OTHER_FILES += IviApplicationExtension.qml - -load(am-qml-testcase) diff --git a/tests/qml/windowmapping/am-config.yaml b/tests/qml/windowmapping/am-config.yaml deleted file mode 100644 index 5333dae3..00000000 --- a/tests/qml/windowmapping/am-config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -formatVersion: 1 -formatType: am-configuration ---- -applications: - builtinAppsManifestDir: "${CONFIG_PWD}/apps" - -# Workaround for a crash in the mesa software renderer (llvmpipe) -runtimes: - qml: - environmentVariables: - QT_QUICK_BACKEND: "software" diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml b/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml deleted file mode 100644 index 05e56276..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - - ApplicationManagerWindow { - id: sub - visible: false - Component.onCompleted: setWindowProperty("type", "sub"); - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-main": root.visible = true; root.setWindowProperty("key1", "val1"); break; - case "hide-main": root.visible = false; break; - case "show-sub": sub.visible = true; break; - case "hide-sub": sub.visible = false; break; - } - } - } - - Component.onCompleted: setWindowProperty("objectName", 42); -} diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin/icon.png b/tests/qml/windowmapping/apps/test.winmap.amwin/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.amwin/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin/info.yaml b/tests/qml/windowmapping/apps/test.winmap.amwin/info.yaml deleted file mode 100644 index 78c26e03..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.amwin/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.amwin' -icon: 'icon.png' -code: 'amwin.qml' -runtime: 'qml' -name: - en: 'ApplicationManagerWindow Root' diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml b/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml deleted file mode 100644 index f6d58131..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - visible: false - - ApplicationManagerWindow { - id: sub - visible: false - Component.onCompleted: setWindowProperty("type", "sub"); - } - - Rectangle { - anchors.fill: parent - visible: false - - ApplicationManagerWindow { - id: sub2 - visible: false - Component.onCompleted: setWindowProperty("type", "sub2"); - } - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-main": root.visible = true; break; - case "hide-main": root.visible = false; break; - case "show-sub": sub.visible = true; break; - case "hide-sub": sub.visible = false; break; - case "show-sub2": sub2.visible = true; break; - case "hide-sub2": sub2.visible = false; break; - } - } - } -} diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin2/icon.png b/tests/qml/windowmapping/apps/test.winmap.amwin2/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.amwin2/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin2/info.yaml b/tests/qml/windowmapping/apps/test.winmap.amwin2/info.yaml deleted file mode 100644 index 041524a8..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.amwin2/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.amwin2' -icon: 'icon.png' -code: 'amwin2.qml' -runtime: 'qml' -name: - en: 'ApplicationManagerWindow Advanced' diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml deleted file mode 100644 index a39ebc53..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - Component.onCompleted: setWindowProperty("type", "sub"); -} diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/icon.png b/tests/qml/windowmapping/apps/test.winmap.loader/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.loader/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml b/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml deleted file mode 100644 index 6e486078..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.loader' -icon: 'icon.png' -code: 'loader.qml' -runtime: 'qml' -name: - en: 'Dynamic loading' diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml deleted file mode 100644 index d1394ce4..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - id: root - visible: true - - Loader { - id: ldr - active: false - source: "SubWin.qml" - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-sub": ldr.active = true; break; - case "hide-sub": ldr.active = false; break; - } - } - } -} diff --git a/tests/qml/windowmapping/apps/test.winmap.ping/icon.png b/tests/qml/windowmapping/apps/test.winmap.ping/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.ping/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.ping/info.yaml b/tests/qml/windowmapping/apps/test.winmap.ping/info.yaml deleted file mode 100644 index 3f4e822e..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.ping/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.ping' -icon: 'icon.png' -code: 'ping.qml' -runtime: 'qml' -name: - en: 'Wayland ping-pong' diff --git a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml b/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml deleted file mode 100644 index c6e6c02d..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -ApplicationManagerWindow { - Timer { - id: tim - interval: 100 - running: true - onTriggered: { - while (true); // application hangs - } - } -} diff --git a/tests/qml/windowmapping/apps/test.winmap.qtobject/icon.png b/tests/qml/windowmapping/apps/test.winmap.qtobject/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.qtobject/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.qtobject/info.yaml b/tests/qml/windowmapping/apps/test.winmap.qtobject/info.yaml deleted file mode 100644 index 98926746..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.qtobject/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.qtobject' -icon: 'icon.png' -code: 'qtobject.qml' -runtime: 'qml' -name: - en: 'QtObject Root' diff --git a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml b/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml deleted file mode 100644 index 203b0f56..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -QtObject { - id: root - - property ApplicationManagerWindow mainWin: ApplicationManagerWindow { - id: main - visible: false - } - - property ApplicationManagerWindow subWin: ApplicationManagerWindow { - id: sub - visible: false - Component.onCompleted: setWindowProperty("type", "sub"); - } - - property Connections con: Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-main": main.visible = true; break; - case "hide-main": main.visible = false; break; - case "show-sub": sub.visible = true; break; - case "hide-sub": sub.visible = false; break; - } - } - } -} diff --git a/tests/qml/windowmapping/apps/test.winmap.rectangle/icon.png b/tests/qml/windowmapping/apps/test.winmap.rectangle/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.rectangle/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.rectangle/info.yaml b/tests/qml/windowmapping/apps/test.winmap.rectangle/info.yaml deleted file mode 100644 index 0981b53d..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.rectangle/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.rectangle' -icon: 'icon.png' -code: 'rectangle.qml' -runtime: 'qml' -name: - en: 'Rectangle Root' diff --git a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml b/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml deleted file mode 100644 index 8e11e72c..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtApplicationManager.Application 2.0 - -Rectangle { - id: root - - ApplicationManagerWindow { - id: sub - visible: false - Component.onCompleted: setWindowProperty("type", "sub"); - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-main": root.visible = true; break; - case "hide-main": root.visible = false; break; - case "show-sub": sub.visible = true; break; - case "hide-sub": sub.visible = false; break; - } - } - } -} diff --git a/tests/qml/windowmapping/apps/test.winmap.window/icon.png b/tests/qml/windowmapping/apps/test.winmap.window/icon.png deleted file mode 100644 index c1397153..00000000 Binary files a/tests/qml/windowmapping/apps/test.winmap.window/icon.png and /dev/null differ diff --git a/tests/qml/windowmapping/apps/test.winmap.window/info.yaml b/tests/qml/windowmapping/apps/test.winmap.window/info.yaml deleted file mode 100644 index c527475d..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.window/info.yaml +++ /dev/null @@ -1,9 +0,0 @@ -formatVersion: 1 -formatType: am-application ---- -id: 'test.winmap.window' -icon: 'icon.png' -code: 'window.qml' -runtime: 'qml' -name: - en: 'Window Root' diff --git a/tests/qml/windowmapping/apps/test.winmap.window/window.qml b/tests/qml/windowmapping/apps/test.winmap.window/window.qml deleted file mode 100644 index 588f33ce..00000000 --- a/tests/qml/windowmapping/apps/test.winmap.window/window.qml +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.4 -import QtQuick.Window 2.0 -import QtApplicationManager.Application 2.0 - -Window { - id: root - visible: true // explicitly set, since false by default - - ApplicationManagerWindow { - id: sub - visible: false - Component.onCompleted: setWindowProperty("type", "sub"); - } - - Connections { - target: ApplicationInterface - function onOpenDocument(documentUrl) { - switch (documentUrl) { - case "show-main": root.visible = true; break; - case "hide-main": root.visible = false; break; - case "show-sub": sub.visible = true; break; - case "hide-sub": sub.visible = false; break; - } - } - } -} diff --git a/tests/qml/windowmapping/tst_windowmapping.qml b/tests/qml/windowmapping/tst_windowmapping.qml deleted file mode 100644 index 140665c5..00000000 --- a/tests/qml/windowmapping/tst_windowmapping.qml +++ /dev/null @@ -1,321 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.3 -import QtTest 1.0 -import QtApplicationManager.SystemUI 2.0 - -TestCase { - id: testCase - when: windowShown - name: "WindowMapping" - visible: true - - property var lastWindowAdded; - - WindowItem { - id: chrome - anchors.fill: parent - - Connections { - target: chrome.window - function onContentStateChanged() { - if (chrome.window.contentState === WindowObject.NoSurface) - chrome.window = null; - } - } - - WindowItem { - id: subChrome - anchors.fill: parent - Connections { - target: subChrome.window - function onContentStateChanged() { - if (subChrome.window.contentState === WindowObject.NoSurface) - subChrome.window = null; - } - } - } - } - - Connections { - target: WindowManager - function onWindowAdded(window) { - if (window.windowProperty("type") === "sub") - subChrome.window = window; - else - chrome.window = window; - - testCase.lastWindowAdded = window; - } - } - - - SignalSpy { - id: windowAddedSpy - target: WindowManager - signalName: "windowAdded" - } - - SignalSpy { - id: windowAboutToBeRemovedSpy - target: WindowManager - signalName: "windowAboutToBeRemoved" - } - - SignalSpy { - id: windowPropertyChangedSpy - target: WindowManager - signalName: "windowPropertyChanged" - } - -    SignalSpy { -        id: runStateChangedSpy -        target: ApplicationManager -        signalName: "applicationRunStateChanged" -    } - - function cleanup() { - runStateChangedSpy.clear(); - ApplicationManager.stopAllApplications(); - - while (true) { - var numRunningApps = 0; - for (var i = 0; i < ApplicationManager.count; i++) { - var app = ApplicationManager.application(i); - if (app.runState !== Am.NotRunning) - numRunningApps += 1; - } - - if (numRunningApps > 0) { - wait(2000); - } else - break; - } - - windowAddedSpy.clear(); - windowAboutToBeRemovedSpy.clear(); - } - - function test_windowmanager_added_removed_signals() { - var app = ApplicationManager.application("test.winmap.amwin"); - - compare(windowAddedSpy.count, 0); - app.start("show-main"); - tryCompare(windowAddedSpy, "count", 1); - - compare(windowAboutToBeRemovedSpy.count, 0); - app.stop(); - tryCompare(windowAboutToBeRemovedSpy, "count", 1); - } - - function test_amwin_advanced() { - var app = ApplicationManager.application("test.winmap.amwin2"); - app.start("show-sub"); - wait(2000); - compare(WindowManager.count, 0); - - app.start("show-main"); - tryCompare(WindowManager, "count", 2); - } - - function test_amwin_loader() { - tryCompare(WindowManager, "count", 0); - - var app = ApplicationManager.application("test.winmap.loader"); - - app.start("show-sub"); - tryCompare(WindowManager, "count", 2); - - app.start("hide-sub"); - tryCompare(WindowManager, "count", 1); - - app.start("show-sub"); - tryCompare(WindowManager, "count", 2); - } - - function test_amwin_peculiarities() { - var app = ApplicationManager.application("test.winmap.amwin2"); - - tryCompare(WindowManager, "count", 0); - - app.start("show-main"); - tryCompare(WindowManager, "count", 1); - - app.start("show-sub"); - tryCompare(WindowManager, "count", 2); - - // Single- vs. multiprocess difference: - app.start("show-sub2"); - var expectedWindowCount; - // A Window's effective visible state solely depends on Window hierarchy. - expectedWindowCount = 3; - tryCompare(WindowManager, "count", expectedWindowCount); - - app.start("hide-sub"); - expectedWindowCount -= 1; - tryCompare(WindowManager, "count", expectedWindowCount); - - // Make child (sub) window visible again, parent (main) window is still visible - app.start("show-sub"); - expectedWindowCount += 1; - tryCompare(WindowManager, "count", expectedWindowCount); - - // This is weird Window behavior: a child window becomes only visible, when the parent - // window is visible, but when you change the parent window back to invisible, the child - // will NOT become invisible. - app.start("hide-main"); - expectedWindowCount -= 1; - tryCompare(WindowManager, "count", expectedWindowCount); - - // Single- vs. multiprocess difference: - app.start("hide-sub"); - if (ApplicationManager.singleProcess) { - expectedWindowCount -= 1; - } else { - // This is even more weird Window behavior: when the parent window is invisible, it is - // not possible any more to explicitly set the child window to invisible. - wait(50); - } - tryCompare(WindowManager, "count", expectedWindowCount); - } - - function test_default_data() { - return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" }, - // skipping QtObject, as it doesn't show anything - { tag: "Rectangle", appId: "test.winmap.rectangle" }, - { tag: "Window", appId: "test.winmap.window" } ]; - } - - function test_default(data) { - if (ApplicationManager.singleProcess && data.tag === "Window") - skip("Window root element is not properly supported in single process mode."); - - compare(WindowManager.count, 0); - - var app = ApplicationManager.application(data.appId); - verify(chrome.window === null); - app.start(); - tryCompare(WindowManager, "count", 1); - tryVerify(function () { return chrome.window !== null }); - - app.stop(); - tryCompare(WindowManager, "count", 0); - } - - function test_mapping_data() { - return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" }, - { tag: "QtObject", appId: "test.winmap.qtobject" }, - { tag: "Rectangle", appId: "test.winmap.rectangle" }, - { tag: "Window", appId: "test.winmap.window" } ]; - } - - function test_mapping(data) { - if (ApplicationManager.singleProcess && data.tag === "Window") - skip("Window root element is not properly supported in single process mode."); - - var app = ApplicationManager.application(data.appId); - - compare(WindowManager.count, 0); - - app.start("show-main"); - tryCompare(WindowManager, "count", 1); - - app.start("show-sub"); - tryCompare(WindowManager, "count", 2); - - app.start("hide-sub"); - tryCompare(WindowManager, "count", 1); - - app.stop(); - tryCompare(WindowManager, "count", 0); - } - - function test_wayland_ping_pong() { - var app = ApplicationManager.application("test.winmap.ping"); - - if (ApplicationManager.singleProcess) - skip("Wayland ping-pong is only supported in multi-process mode"); - - AmTest.ignoreMessage(AmTest.CriticalMsg, /Stopping application.*because we did not receive a Wayland-Pong/); - app.start(); - tryCompare(app, "runState", Am.Running); - runStateChangedSpy.clear(); - wait(2200); - runStateChangedSpy.wait(2000); - compare(runStateChangedSpy.signalArguments[0][1], Am.ShuttingDown); - runStateChangedSpy.wait(2000); - compare(runStateChangedSpy.signalArguments[1][1], Am.NotRunning); - } - - function test_window_properties() { - var app = ApplicationManager.application("test.winmap.amwin"); - - windowPropertyChangedSpy.clear(); - app.start(); - tryCompare(WindowManager, "count", 1); - - app.start("show-main"); - windowPropertyChangedSpy.wait(2000); - compare(windowPropertyChangedSpy.count, 1); - - compare(lastWindowAdded.windowProperty("key1"), "val1"); - compare(lastWindowAdded.windowProperty("objectName"), 42); - - lastWindowAdded.setWindowProperty("key2", "val2"); - windowPropertyChangedSpy.wait(2000); - compare(windowPropertyChangedSpy.count, 2); - - var allProps = lastWindowAdded.windowProperties() - compare(Object.keys(allProps).length, 3); - compare(allProps.key1, "val1"); - compare(allProps.key2, "val2"); - compare(allProps.objectName, 42); - } - - // Checks that window properties survive show/hide cycles - // Regression test for https://bugreports.qt.io/browse/AUTOSUITE-447 - function test_window_properties_survive_show_hide() { - var app = ApplicationManager.application("test.winmap.amwin"); - - app.start("show-main"); - tryCompare(WindowManager, "count", 1); - - compare(lastWindowAdded.windowProperty("objectName"), 42); - - app.start("hide-main"); - tryCompare(WindowManager, "count", 0); - app.start("show-main"); - tryCompare(WindowManager, "count", 1); - - compare(lastWindowAdded.windowProperty("objectName"), 42); - } -} diff --git a/tests/qml/windowmapping/windowmapping.pro b/tests/qml/windowmapping/windowmapping.pro deleted file mode 100644 index e29aba28..00000000 --- a/tests/qml/windowmapping/windowmapping.pro +++ /dev/null @@ -1,12 +0,0 @@ -AM_CONFIG = am-config.yaml -TEST_FILES = tst_windowmapping.qml -TEST_APPS = \ - test.winmap.amwin \ - test.winmap.amwin2 \ - test.winmap.loader \ - test.winmap.ping \ - test.winmap.qtobject \ - test.winmap.rectangle \ - test.winmap.window \ - -load(am-qml-testcase) diff --git a/tests/runtime/runtime.pro b/tests/runtime/runtime.pro deleted file mode 100644 index 64c550cc..00000000 --- a/tests/runtime/runtime.pro +++ /dev/null @@ -1,11 +0,0 @@ -TARGET = tst_runtime - -include($$PWD/../tests.pri) - -QT *= qml -QT *= \ - appman_common-private \ - appman_application-private \ - appman_manager-private \ - -SOURCES += tst_runtime.cpp diff --git a/tests/runtime/tst_runtime.cpp b/tests/runtime/tst_runtime.cpp deleted file mode 100644 index ee62e5d4..00000000 --- a/tests/runtime/tst_runtime.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "application.h" -#include "package.h" -#include "abstractruntime.h" -#include "runtimefactory.h" -#include "exception.h" - -QT_USE_NAMESPACE_AM - -class tst_Runtime : public QObject -{ - Q_OBJECT - -public: - tst_Runtime(); - -private slots: - void factory(); -}; - -class TestRuntimeManager; - -class TestRuntime : public AbstractRuntime -{ - Q_OBJECT - -public: - explicit TestRuntime(AbstractContainer *container, Application *app, AbstractRuntimeManager *manager) - : AbstractRuntime(container, app, manager) - { } - - void setSlowAnimations(bool) override {} - - qint64 applicationProcessId() const override - { - return m_state == Am::Running ? 1 : 0; - } - -public slots: - bool start() override - { - m_state = Am::Running; - return true; - } - - void stop(bool forceKill) override - { - Q_UNUSED(forceKill); - m_state = Am::NotRunning; - } -}; - -class TestRuntimeManager : public AbstractRuntimeManager -{ - Q_OBJECT - -public: - TestRuntimeManager(const QString &id, QObject *parent) - : AbstractRuntimeManager(id, parent) - { } - - static QString defaultIdentifier() { return qSL("foo"); } - - bool inProcess() const override - { - return !AbstractRuntimeManager::inProcess(); - } - - TestRuntime *create(AbstractContainer *container, Application *app) override - { - return new TestRuntime(container, app, this); - } -}; - - -tst_Runtime::tst_Runtime() -{ } - -void tst_Runtime::factory() -{ - RuntimeFactory *rf = RuntimeFactory::instance(); - - QVERIFY(rf); - QVERIFY(rf == RuntimeFactory::instance()); - QVERIFY(rf->runtimeIds().isEmpty()); - - QVERIFY(rf->registerRuntime(new TestRuntimeManager(qSL("foo"), qApp))); - QVERIFY(rf->runtimeIds() == QStringList() << qSL("foo")); - - QVERIFY(!rf->create(nullptr, nullptr)); - - QByteArray yaml = - "formatVersion: 1\n" - "formatType: am-application\n" - "---\n" - "id: com.pelagicore.test\n" - "name: { en_US: 'Test' }\n" - "icon: icon.png\n" - "code: test.foo\n" - "runtime: foo\n"; - - QTemporaryFile temp; - QVERIFY(temp.open()); - QCOMPARE(temp.write(yaml), yaml.size()); - temp.close(); - - Application *a = nullptr; - try { - PackageInfo *pi = PackageInfo::fromManifest(temp.fileName()); - QVERIFY(pi); - Package *p = new Package(pi); - a = new Application(pi->applications().first(), p); - } catch (const Exception &e) { - QVERIFY2(false, qPrintable(e.errorString())); - } - QVERIFY(a); - - AbstractRuntime *r = rf->create(nullptr, a); - QVERIFY(r); - QVERIFY(r->application() == a); - QVERIFY(r->manager()->inProcess()); - QVERIFY(r->state() == Am::NotRunning); - QVERIFY(r->applicationProcessId() == 0); - { - QScopedPointer engine(new QQmlEngine()); - QVERIFY(!r->inProcessQmlEngine()); - r->setInProcessQmlEngine(engine.data()); - QVERIFY(r->inProcessQmlEngine() == engine.data()); - r->setInProcessQmlEngine(nullptr); - } - QVERIFY(r->start()); - QVERIFY(r->state() == Am::Running); - QVERIFY(r->applicationProcessId() == 1); - r->stop(); - QVERIFY(r->state() == Am::NotRunning); - QVERIFY(!r->securityToken().isEmpty()); - - delete r; - delete rf; - delete a; -} - -QTEST_MAIN(tst_Runtime) - -#include "tst_runtime.moc" diff --git a/tests/signature/create-test-data.sh b/tests/signature/create-test-data.sh deleted file mode 100644 index 68f05575..00000000 --- a/tests/signature/create-test-data.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -############################################################################# -## -## Copyright (C) 2021 The Qt Company Ltd. -## Copyright (C) 2019 Luxoft Sweden AB -## Copyright (C) 2018 Pelagicore AG -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the QtApplicationManager module of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -echo "Recreating test data" - -certdir="../data/certificates/" - -[ -f $certdir/dev1.p12 ] || { echo "Please generate test certificates in $certdir first"; exit 1; } - -cp $certdir/dev1.p12 signing.p12 -openssl pkcs12 -export -out signing-no-key.p12 -password pass:password -inkey $certdir/dev1-priv.key -nodes -certfile $certdir/ca.crt -in $certdir/dev1.crt -name "Developer 1 Certificate (no key)" -nokeys -cat $certdir/ca.crt $certdir/devca.crt >verifying.crt diff --git a/tests/signature/signature-openssl.p7 b/tests/signature/signature-openssl.p7 deleted file mode 100644 index 294310cf..00000000 Binary files a/tests/signature/signature-openssl.p7 and /dev/null differ diff --git a/tests/signature/signature-securityframework.p7 b/tests/signature/signature-securityframework.p7 deleted file mode 100644 index ded48dd8..00000000 Binary files a/tests/signature/signature-securityframework.p7 and /dev/null differ diff --git a/tests/signature/signature-wincrypt.p7 b/tests/signature/signature-wincrypt.p7 deleted file mode 100644 index e3ef40d3..00000000 Binary files a/tests/signature/signature-wincrypt.p7 and /dev/null differ diff --git a/tests/signature/signature.pro b/tests/signature/signature.pro deleted file mode 100644 index 43bb3d47..00000000 --- a/tests/signature/signature.pro +++ /dev/null @@ -1,11 +0,0 @@ -TARGET = tst_signature - -include($$PWD/../tests.pri) - -QT *= appman_common-private appman_crypto-private - -SOURCES += tst_signature.cpp - -OTHER_FILES += create-test-data.sh - -RESOURCES += tst_signature.qrc diff --git a/tests/signature/signing-no-key.p12 b/tests/signature/signing-no-key.p12 deleted file mode 100644 index 57705d79..00000000 Binary files a/tests/signature/signing-no-key.p12 and /dev/null differ diff --git a/tests/signature/signing.p12 b/tests/signature/signing.p12 deleted file mode 100644 index 5d752759..00000000 Binary files a/tests/signature/signing.p12 and /dev/null differ diff --git a/tests/signature/tst_signature.cpp b/tests/signature/tst_signature.cpp deleted file mode 100644 index ea4f471d..00000000 --- a/tests/signature/tst_signature.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "global.h" -#include "signature.h" - -QT_USE_NAMESPACE_AM - -class tst_Signature : public QObject -{ - Q_OBJECT - -public: - tst_Signature(); - -private slots: - void initTestCase(); - void check(); - void crossPlatform(); - -private: - QByteArray m_signingP12; - QByteArray m_signingNoKeyP12; - QByteArray m_signingPassword; - QList m_verifyingPEM; -}; - -tst_Signature::tst_Signature() -{ } - -void tst_Signature::initTestCase() -{ - QFile s(qSL(":/signing.p12")); - QVERIFY(s.open(QIODevice::ReadOnly)); - m_signingP12 = s.readAll(); - QVERIFY(!m_signingP12.isEmpty()); - - QFile snk(qSL(":/signing-no-key.p12")); - QVERIFY(snk.open(QIODevice::ReadOnly)); - m_signingNoKeyP12 = snk.readAll(); - QVERIFY(!m_signingNoKeyP12.isEmpty()); - - QFile v(qSL(":/verifying.crt")); - QVERIFY(v.open(QIODevice::ReadOnly)); - m_verifyingPEM << v.readAll(); - QVERIFY(!m_verifyingPEM.first().isEmpty()); - - m_signingPassword = "password"; -} - -void tst_Signature::check() -{ - QByteArray hash("foo"); - Signature s(hash); - QVERIFY(s.errorString().isEmpty()); - QByteArray signature = s.create(m_signingP12, m_signingPassword); - QVERIFY2(!signature.isEmpty(), qPrintable(s.errorString())); - - Signature s2(hash + "bar"); - QByteArray signature2 = s2.create(m_signingP12, m_signingPassword); - QVERIFY2(!signature2.isEmpty(), qPrintable(s2.errorString())); - QVERIFY(signature != signature2); - - QVERIFY2(s.verify(signature, m_verifyingPEM), qPrintable(s.errorString())); - QVERIFY2(s2.verify(signature2, m_verifyingPEM), qPrintable(s2.errorString())); - QVERIFY(!s.verify(signature2, m_verifyingPEM)); - QVERIFY(!s2.verify(signature, m_verifyingPEM)); - - QVERIFY(s.create(m_signingP12, m_signingPassword + "not").isEmpty()); - QVERIFY2(s.errorString().contains(qSL("not parse")), qPrintable(s.errorString())); - - QVERIFY(s.create(QByteArray(), m_signingPassword).isEmpty()); - QVERIFY2(s.errorString().contains(qSL("not read")), qPrintable(s.errorString())); - - Signature s3(QByteArray(4096, 'x')); - QVERIFY(!s3.create(m_signingP12, m_signingPassword).isEmpty()); - - QVERIFY(!s.verify(signature, QList())); - QVERIFY2(s.errorString().contains(qSL("Failed to verify")), qPrintable(s.errorString())); - QVERIFY(!s.verify(signature, QList() << m_signingP12)); - QVERIFY2(s.errorString().contains(qSL("not load")), qPrintable(s.errorString())); - QVERIFY(!s.verify(hash, QList() << m_signingP12)); - QVERIFY2(s.errorString().contains(qSL("not read")), qPrintable(s.errorString())); - - Signature s4 { QByteArray() }; - QVERIFY(s4.create(m_signingP12, m_signingPassword).isEmpty()); - - QVERIFY(s.create(m_signingNoKeyP12, m_signingPassword).isEmpty()); - QVERIFY2(s.errorString().contains(qSL("private key")), qPrintable(s.errorString())); -} - -void tst_Signature::crossPlatform() -{ - QByteArray hash = "hello\nworld!"; - - QFile fileOpenSsl(qSL(":/signature-openssl.p7")); - QFile fileWinCrypt(qSL(":/signature-wincrypt.p7")); - QFile fileSecurityFramework(qSL(":/signature-securityframework.p7")); - - if (qEnvironmentVariableIsSet("AM_CREATE_SIGNATURE_FILE")) { - QFile *nativeFile = nullptr; -#if defined(AM_USE_LIBCRYPTO) - nativeFile = &fileOpenSsl; -#elif defined(Q_OS_WIN) - nativeFile = &fileWinCrypt; -#elif defined(Q_OS_OSX) - nativeFile = &fileSecurityFramework; -#endif - QVERIFY(nativeFile); - QFile f(qL1S(AM_TESTDATA_DIR "/../signature") + nativeFile->fileName().mid(1)); - QVERIFY2(f.open(QFile::WriteOnly | QFile::Truncate), qPrintable(f.errorString())); - - Signature s(hash); - QByteArray signature = s.create(m_signingP12, m_signingPassword); - QVERIFY2(!signature.isEmpty(), qPrintable(s.errorString())); - QCOMPARE(f.write(signature), signature.size()); - - qInfo() << "Only creating signature file" << f.fileName() << "because $AM_CREATE_SIGNATURE_FILE is set."; - return; - } - - QVERIFY(fileOpenSsl.open(QIODevice::ReadOnly)); - QByteArray sigOpenSsl = fileOpenSsl.readAll(); - QVERIFY(!sigOpenSsl.isEmpty()); - QVERIFY(fileWinCrypt.open(QIODevice::ReadOnly)); - QByteArray sigWinCrypt = fileWinCrypt.readAll(); - QVERIFY(!sigWinCrypt.isEmpty()); - QVERIFY(fileSecurityFramework.open(QIODevice::ReadOnly)); - QByteArray sigSecurityFramework = fileSecurityFramework.readAll(); - QVERIFY(!sigSecurityFramework.isEmpty()); - - Signature s(hash); - QVERIFY2(s.verify(sigOpenSsl, m_verifyingPEM), qPrintable(s.errorString())); - QVERIFY2(s.verify(sigWinCrypt, m_verifyingPEM), qPrintable(s.errorString())); - QVERIFY2(s.verify(sigSecurityFramework, m_verifyingPEM), qPrintable(s.errorString())); -} - -QTEST_APPLESS_MAIN(tst_Signature) - -#include "tst_signature.moc" - diff --git a/tests/signature/tst_signature.qrc b/tests/signature/tst_signature.qrc deleted file mode 100644 index f063bca7..00000000 --- a/tests/signature/tst_signature.qrc +++ /dev/null @@ -1,10 +0,0 @@ - - - signing.p12 - signing-no-key.p12 - verifying.crt - signature-openssl.p7 - signature-wincrypt.p7 - signature-securityframework.p7 - - diff --git a/tests/signature/verifying.crt b/tests/signature/verifying.crt deleted file mode 100644 index de7dcc07..00000000 --- a/tests/signature/verifying.crt +++ /dev/null @@ -1,105 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID4TCCAsmgAwIBAgIJAOGN7P3anRxmMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV -BAYTAkRFMRYwFAYDVQQKDA1QZWxhZ2ljb3JlIEFHMRIwEAYDVQQLDAlBcHAgU3Rv -cmUxIDAeBgNVBAMMF1BlbGFnaWNvcmUgQXBwIFN0b3JlIENBMSIwIAYJKoZIhvcN -AQkBFhNpbmZvQHBlbGFnaWNvcmUuY29tMB4XDTE1MDMxMTAxMTk0NloXDTI1MDMw -ODAxMTk0NlowfzELMAkGA1UEBhMCREUxFjAUBgNVBAoMDVBlbGFnaWNvcmUgQUcx -EjAQBgNVBAsMCUFwcCBTdG9yZTEgMB4GA1UEAwwXUGVsYWdpY29yZSBBcHAgU3Rv -cmUgQ0ExIjAgBgkqhkiG9w0BCQEWE2luZm9AcGVsYWdpY29yZS5jb20wggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkAz3WPxmzXt53bDimMy3ieAVXYtV1 -tJTzBBpAv7emrsa1JxOp/NsaTt18cXCrpNnBiGnlcdFtkULj53U8BRwd2CNmraRG -QR09uq0H98vF1NwPQ4vFZ3NEOdofjtAgDipqcAHSH+T0lxj2xvWLP44fo7UvmG4Q -CUAA7JhIwjFDJugZ3JFcTQl9eCt2CfvysvHC4sBmZTRAk+sL/oBZvasS4NAgqSRX -WCZKXIoSdgir1BAvB/u/mF/RT+zkP4ntoeBSB/yjqWOmghA6nbCQk33nGT4cBMD5 -0QPliXioSqjIrIhIrKzqtW5yqOcUhKc9g8oWKSekMg25hcq6XF08uS7ZAgMBAAGj -YDBeMB0GA1UdDgQWBBT0CdSIj6UvzW6R6tFaBeOL6yijwTAfBgNVHSMEGDAWgBT0 -CdSIj6UvzW6R6tFaBeOL6yijwTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB -BjANBgkqhkiG9w0BAQsFAAOCAQEAYXr+Eans7BbTMRvf0iZdCdTAneNCrF5oz7V0 -xwWqJBzL1rwhvHbruKvF7I0bSoURmSVd+P9Ge0rYvW+HXuLlgmwAfl9n4zWsHohs -zDFSPQIfb97TP5HE21DrCGCauQirUGaA91inGDmGW80RWbzL1gogWZYpP7IOwu5G -nr+3AgxqZVOS8H0Ppf8aMqtiuamR63SCE5OoHJCNeQ6OmoFrnW8vF9eMScoc1Txb -F4uMqSPny6kgmarwfGnurhM2NOn8OpELEU9mwd7XpzpHpvYVm76tZpd5gMhYFsjp -lyDFPVFQ5pVv5Cc7xhxzYrcn7JQt/GYhYuChM0us5a5urV/l+g== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 2 (0x2) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=DE, O=Pelagicore AG, OU=App Store, CN=Pelagicore App Store CA/emailAddress=info@pelagicore.com - Validity - Not Before: Mar 11 01:19:46 2015 GMT - Not After : Mar 8 01:19:46 2025 GMT - Subject: C=DE, O=Pelagicore AG, OU=Developer Relations, CN=Pelagicore Developer CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:d7:88:7d:35:92:04:9c:58:b1:c9:7e:e0:eb:09: - 10:78:6f:cb:78:f6:1b:38:5a:54:8b:5e:b5:b2:92: - 45:9c:b7:6c:01:0f:b2:16:66:66:24:0a:ed:37:83: - ad:79:27:b0:e8:ff:49:db:68:f6:26:b5:61:d9:7b: - ea:46:7a:e2:55:df:fc:cc:af:2e:45:ce:f7:59:52: - 19:9c:6c:39:d6:5c:68:9e:73:45:71:ac:b2:1d:e6: - 98:0e:7f:18:06:cd:09:49:c7:d6:b6:5c:e1:e9:4f: - 6b:80:ac:4a:c7:36:21:c7:2a:e8:bc:ae:87:f2:49: - 05:62:f9:01:24:c0:93:5b:85:1a:bb:d1:81:19:aa: - 31:09:cd:5b:e2:5a:61:76:4d:50:8d:45:60:70:ca: - 64:64:bc:1f:25:bf:64:2e:65:16:95:1c:ee:29:bb: - a7:31:ec:20:39:81:eb:48:df:93:ca:48:6c:be:9e: - df:5e:05:8a:db:8e:c4:07:cc:fc:c8:08:16:1e:e3: - 04:51:d9:0b:6f:28:1a:e4:38:93:05:00:59:49:60: - 81:12:bc:48:f9:81:08:ff:fb:59:95:ad:f3:54:85: - 1b:70:5f:cf:eb:0f:ea:45:20:39:b0:74:55:0c:94: - d7:3f:88:85:b8:71:ac:b0:e7:99:70:cc:f5:c2:89: - 6b:af - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 8B:2D:DE:5A:18:A5:71:A9:73:03:54:69:56:87:A0:17:BF:C2:73:4E - X509v3 Authority Key Identifier: - keyid:F4:09:D4:88:8F:A5:2F:CD:6E:91:EA:D1:5A:05:E3:8B:EB:28:A3:C1 - - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: - Certificate Sign, CRL Sign - Signature Algorithm: sha256WithRSAEncryption - 3a:5f:21:dc:b5:f8:a7:e5:23:89:fa:53:e2:cd:b7:e1:51:53: - d6:0d:e7:78:f7:3c:cc:85:b3:83:be:76:c8:3e:0d:e2:ab:ca: - ca:aa:41:c9:23:cc:d6:8c:53:71:72:70:43:04:48:85:28:54: - ab:b0:2a:e2:08:89:22:d5:ce:0b:79:e5:3d:61:42:db:4a:70: - c4:64:21:48:07:c4:a9:33:e4:0a:c9:a0:d6:0d:73:ef:d0:80: - d8:8c:59:c4:51:fa:5a:54:79:94:0f:ca:ff:28:0a:7e:b9:99: - 2d:8e:ca:5d:d8:4c:8f:fe:6f:e6:fd:ea:17:7f:90:f7:b1:76: - de:7f:14:82:20:c3:23:0f:ca:b5:1c:2c:34:b9:de:9f:ce:06: - 04:14:ff:6c:0b:67:ab:7c:b3:5a:51:dc:0c:66:37:56:bf:a7: - ab:12:33:03:98:c3:40:e2:4d:8d:ad:3f:19:18:41:cc:e3:ec: - 6d:5f:9e:90:df:d9:84:5b:ad:60:93:dc:24:1a:42:ce:8b:15: - 8f:42:21:f9:35:68:a6:cc:f7:4e:8d:c2:6b:b9:e6:20:30:d1: - c6:1d:86:f8:33:3b:40:cc:9f:4c:2d:5d:0a:ca:66:1c:8d:bc: - 87:3b:0b:39:e4:17:73:34:35:85:ba:22:31:a2:8b:d0:65:54: - cc:c2:c6:32 ------BEGIN CERTIFICATE----- -MIIDvzCCAqegAwIBAgIBAjANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJERTEW -MBQGA1UECgwNUGVsYWdpY29yZSBBRzESMBAGA1UECwwJQXBwIFN0b3JlMSAwHgYD -VQQDDBdQZWxhZ2ljb3JlIEFwcCBTdG9yZSBDQTEiMCAGCSqGSIb3DQEJARYTaW5m -b0BwZWxhZ2ljb3JlLmNvbTAeFw0xNTAzMTEwMTE5NDZaFw0yNTAzMDgwMTE5NDZa -MGUxCzAJBgNVBAYTAkRFMRYwFAYDVQQKDA1QZWxhZ2ljb3JlIEFHMRwwGgYDVQQL -DBNEZXZlbG9wZXIgUmVsYXRpb25zMSAwHgYDVQQDDBdQZWxhZ2ljb3JlIERldmVs -b3BlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANeIfTWSBJxY -scl+4OsJEHhvy3j2GzhaVItetbKSRZy3bAEPshZmZiQK7TeDrXknsOj/Sdto9ia1 -Ydl76kZ64lXf/MyvLkXO91lSGZxsOdZcaJ5zRXGssh3mmA5/GAbNCUnH1rZc4elP -a4CsSsc2Iccq6Lyuh/JJBWL5ASTAk1uFGrvRgRmqMQnNW+JaYXZNUI1FYHDKZGS8 -HyW/ZC5lFpUc7im7pzHsIDmB60jfk8pIbL6e314FituOxAfM/MgIFh7jBFHZC28o -GuQ4kwUAWUlggRK8SPmBCP/7WZWt81SFG3Bfz+sP6kUgObB0VQyU1z+IhbhxrLDn -mXDM9cKJa68CAwEAAaNgMF4wHQYDVR0OBBYEFIst3loYpXGpcwNUaVaHoBe/wnNO -MB8GA1UdIwQYMBaAFPQJ1IiPpS/NbpHq0VoF44vrKKPBMA8GA1UdEwEB/wQFMAMB -Af8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQA6XyHctfin5SOJ+lPi -zbfhUVPWDed49zzMhbODvnbIPg3iq8rKqkHJI8zWjFNxcnBDBEiFKFSrsCriCIki -1c4LeeU9YULbSnDEZCFIB8SpM+QKyaDWDXPv0IDYjFnEUfpaVHmUD8r/KAp+uZkt -jspd2EyP/m/m/eoXf5D3sXbefxSCIMMjD8q1HCw0ud6fzgYEFP9sC2erfLNaUdwM -ZjdWv6erEjMDmMNA4k2NrT8ZGEHM4+xtX56Q39mEW61gk9wkGkLOixWPQiH5NWim -zPdOjcJrueYgMNHGHYb4MztAzJ9MLV0KymYcjbyHOws55BdzNDWFuiIxoovQZVTM -wsYy ------END CERTIFICATE----- diff --git a/tests/sudo/sudo.pro b/tests/sudo/sudo.pro deleted file mode 100644 index 95be319b..00000000 --- a/tests/sudo/sudo.pro +++ /dev/null @@ -1,11 +0,0 @@ -TARGET = tst_sudo - -COVERAGE_RUNTIME = sudo - -include($$PWD/../tests.pri) - -QT *= \ - appman_common-private \ - appman_manager-private \ - -SOURCES += tst_sudo.cpp diff --git a/tests/sudo/tst_sudo.cpp b/tests/sudo/tst_sudo.cpp deleted file mode 100644 index c6472152..00000000 --- a/tests/sudo/tst_sudo.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#if !defined(Q_OS_LINUX) -# error "This test is Linux specific!" -#endif - -#include "utilities.h" -#include "sudo.h" - -QT_USE_NAMESPACE_AM - -static int processTimeout = 3000; - -static bool startedSudoServer = false; -static QString sudoServerError; - -// sudo RAII style -class ScopedRootPrivileges -{ -public: - ScopedRootPrivileges() - { - m_uid = getuid(); - m_gid = getgid(); - if (setresuid(0, 0, 0) || setresgid(0, 0, 0)) - QFAIL("cannot re-gain root privileges"); - } - ~ScopedRootPrivileges() - { - if (setresgid(m_gid, m_gid, 0) || setresuid(m_uid, m_uid, 0)) - QFAIL("cannot drop root privileges"); - } -private: - uid_t m_uid; - gid_t m_gid; -}; - - -class tst_Sudo : public QObject -{ - Q_OBJECT - -public: - tst_Sudo(QObject *parent = nullptr); - ~tst_Sudo(); - -private slots: - void initTestCase(); - void cleanupTestCase(); - - void privileges(); - -private: - SudoClient *m_sudo = nullptr; -}; - -tst_Sudo::tst_Sudo(QObject *parent) - : QObject(parent) -{ } - -tst_Sudo::~tst_Sudo() -{ } - -void tst_Sudo::initTestCase() -{ - processTimeout *= timeoutFactor(); - - QVERIFY2(startedSudoServer, qPrintable(sudoServerError)); - m_sudo = SudoClient::instance(); - QVERIFY(m_sudo); - if (m_sudo->isFallbackImplementation()) - QSKIP("Not running with root privileges - neither directly, or SUID-root, or sudo"); -} - -void tst_Sudo::privileges() -{ - ScopedRootPrivileges sudo; -} - -void tst_Sudo::cleanupTestCase() -{ - // the real cleanup happens in ~tst_Installer, since we also need - // to call this cleanup from the crash handler -} - -static tst_Sudo *tstSudo = nullptr; - -int main(int argc, char **argv) -{ - try { - Sudo::forkServer(Sudo::DropPrivilegesRegainable); - startedSudoServer = true; - } catch (...) { } - - QCoreApplication a(argc, argv); - tstSudo = new tst_Sudo(&a); - -#ifdef Q_OS_LINUX - auto crashHandler = [](int sigNum) -> void { - // we are doing very unsafe things from a within a signal handler, but - // we've crashed anyway at this point and the alternative is that we are - // leaking mounts and attached loopback devices. - - tstSudo->~tst_Sudo(); - - if (sigNum != -1) - exit(1); - }; - - signal(SIGABRT, crashHandler); - signal(SIGSEGV, crashHandler); - signal(SIGINT, crashHandler); -#endif // Q_OS_LINUX - - return QTest::qExec(tstSudo, argc, argv); -} - -#include "tst_sudo.moc" diff --git a/tests/systemreader/root/proc/1234/cgroup b/tests/systemreader/root/proc/1234/cgroup deleted file mode 100644 index cd5fc256..00000000 --- a/tests/systemreader/root/proc/1234/cgroup +++ /dev/null @@ -1,13 +0,0 @@ -12:devices:/system.slice/run-u5853.scope -11:freezer:/ -10:memory:/system.slice/run-u5853.scope -9:net_cls,net_prio:/ -8:cpuset:/ -7:rdma:/ -6:blkio:/ -5:hugetlb:/ -4:cpu,cpuacct:/ -3:perf_event:/ -2:pids:/system.slice/run-u5853.scope -1:name=systemd:/system.slice/run-u5853.scope -0::/system.slice/run-u5853.scope diff --git a/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes b/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes deleted file mode 100644 index 469ca93f..00000000 --- a/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.limit_in_bytes +++ /dev/null @@ -1 +0,0 @@ -524288000 diff --git a/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat b/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat deleted file mode 100644 index e5fe0114..00000000 --- a/tests/systemreader/root/sys/fs/cgroup/memory/system.slice/run-u5853.scope/memory.stat +++ /dev/null @@ -1,33 +0,0 @@ -cache 10346496 -rss 66809856 -rss_huge 0 -shmem 10067968 -mapped_file 7139328 -dirty 0 -writeback 0 -pgpgin 20165 -pgpgout 1328 -pgfault 23446 -pgmajfault 2 -inactive_anon 10047488 -active_anon 66793472 -inactive_file 278528 -active_file 0 -unevictable 0 -hierarchical_memory_limit 524288000 -total_cache 10346496 -total_rss 66809856 -total_rss_huge 0 -total_shmem 10067968 -total_mapped_file 7139328 -total_dirty 0 -total_writeback 0 -total_pgpgin 20165 -total_pgpgout 1328 -total_pgfault 23446 -total_pgmajfault 2 -total_inactive_anon 10047488 -total_active_anon 66793472 -total_inactive_file 278528 -total_active_file 0 -total_unevictable 0 diff --git a/tests/systemreader/systemreader.pro b/tests/systemreader/systemreader.pro deleted file mode 100644 index 5955d5f1..00000000 --- a/tests/systemreader/systemreader.pro +++ /dev/null @@ -1,11 +0,0 @@ -TARGET = tst_systemreader - -include($$PWD/../tests.pri) - -QT *= appman_monitor-private \ - appman_manager-private \ - appman_window-private \ - appman_application-private \ - appman_common-private - -SOURCES += tst_systemreader.cpp diff --git a/tests/systemreader/tst_systemreader.cpp b/tests/systemreader/tst_systemreader.cpp deleted file mode 100644 index dc62884c..00000000 --- a/tests/systemreader/tst_systemreader.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "systemreader.h" - -QT_USE_NAMESPACE_AM - -class tst_SystemReader : public QObject -{ - Q_OBJECT - -public: - tst_SystemReader(); - -private slots: - void cgroupProcessInfo(); - void memoryReaderReadUsedValue(); - void memoryReaderGroupLimit(); -}; - -tst_SystemReader::tst_SystemReader() -{ - g_systemRootDir = QFINDTESTDATA("root"); -} - -void tst_SystemReader::cgroupProcessInfo() -{ - auto map = fetchCGroupProcessInfo(1234); - QCOMPARE(map["memory"], QByteArray("/system.slice/run-u5853.scope")); -} - -void tst_SystemReader::memoryReaderReadUsedValue() -{ - MemoryReader memoryReader(qSL("/system.slice/run-u5853.scope")); - quint64 value = memoryReader.readUsedValue(); - QCOMPARE(value, Q_UINT64_C(66809856)); -} - -void tst_SystemReader::memoryReaderGroupLimit() -{ - MemoryReader memoryReader(qSL("/system.slice/run-u5853.scope")); - quint64 value = memoryReader.groupLimit(); - QCOMPARE(value, Q_UINT64_C(524288000)); -} - -QTEST_APPLESS_MAIN(tst_SystemReader) - -#include "tst_systemreader.moc" diff --git a/tests/tests.pri b/tests/tests.pri deleted file mode 100644 index 64ec6309..00000000 --- a/tests/tests.pri +++ /dev/null @@ -1,11 +0,0 @@ -load(am-config) - -CONFIG *= console testcase -QT = core network testlib -qtHaveModule(dbus):QT *= dbus - -DEFINES *= AM_TESTDATA_DIR=\\\"$$PWD/data/\\\" -DEFINES -= QT_NO_CAST_FROM_ASCII - -HEADERS += \ - $$PWD/error-checking.h \ diff --git a/tests/tests.pro b/tests/tests.pro deleted file mode 100644 index 3bfd9083..00000000 --- a/tests/tests.pro +++ /dev/null @@ -1,56 +0,0 @@ -TEMPLATE = subdirs - -load(am-config) -requires(!disable-installer) - -SUBDIRS = \ - manual \ - application \ - applicationinfo \ - main \ - runtime \ - cryptography \ - signature \ - utilities \ - installationreport \ - packagecreator \ - packageextractor \ - packager-tool \ - applicationinstaller \ - debugwrapper \ - qml \ - yaml \ - configuration \ - -linux*:SUBDIRS += \ - sudo \ - processreader \ - systemreader \ - -OTHER_FILES += \ - tests.pri \ - data/create-test-packages.sh \ - data/certificates/create-test-certificates.sh \ - data/utilities.sh \ - -# sadly, the appman-packager is too complex to build as a host tool -!cross_compile { - prepareRecursiveTarget(check) - qtPrepareTool(APPMAN_PACKAGER, appman-packager) - - unix { - macos:ctype=UTF-8 - else:ctype=C.UTF-8 - - # create test data on the fly - this is needed for the CI server - testdata.target = testdata - testdata.depends = $$PWD/data/create-test-packages.sh $$APPMAN_PACKAGER_EXE - testdata.commands = (cd $$PWD/data ; LC_CTYPE=$$ctype ./create-test-packages.sh $$APPMAN_PACKAGER) - QMAKE_EXTRA_TARGETS += testdata - - # qmake would create a default check target implicitly, but since we need 'testdata' as an - # dependency, we have to set it up explicitly - check.depends = testdata $$check.depends - } - QMAKE_EXTRA_TARGETS *= check -} diff --git a/tests/utilities/tst_utilities.cpp b/tests/utilities/tst_utilities.cpp deleted file mode 100644 index 94487932..00000000 --- a/tests/utilities/tst_utilities.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "utilities.h" - -QT_USE_NAMESPACE_AM - -class tst_Utilities : public QObject -{ - Q_OBJECT - -public: - tst_Utilities(); - -private slots: -}; - - -tst_Utilities::tst_Utilities() -{ } - -QTEST_APPLESS_MAIN(tst_Utilities) - -#include "tst_utilities.moc" diff --git a/tests/utilities/utilities.pro b/tests/utilities/utilities.pro deleted file mode 100644 index 9a7c2bc0..00000000 --- a/tests/utilities/utilities.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = tst_utilities - -include($$PWD/../tests.pri) - -QT *= appman_common-private - -SOURCES += tst_utilities.cpp diff --git a/tests/yaml/data/cache1.yaml b/tests/yaml/data/cache1.yaml deleted file mode 100644 index b3fcddb9..00000000 --- a/tests/yaml/data/cache1.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: cache1 -file: ${FILE} - -## content for a merge test -#bool: true -#list: [ 1, 2 ] -#map: -# key1: value1 -# key2: value2 -# key3: -# key31: value31 -# key32: value32 -# key4: 4 diff --git a/tests/yaml/data/cache2.yaml b/tests/yaml/data/cache2.yaml deleted file mode 100644 index 8ce7bae3..00000000 --- a/tests/yaml/data/cache2.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: cache2 -file: ${FILE} - -## content for a merge test -#bool: false -#list: [ 3, 4, 5 ] -#map: -# key1: value1 -# key2: not-value2 -# key3: -# key31: [ 5, 6 ] -# key32: not-value32 -# key33: true -# key5: 5 diff --git a/tests/yaml/data/test.yaml b/tests/yaml/data/test.yaml deleted file mode 100644 index b16e3d39..00000000 --- a/tests/yaml/data/test.yaml +++ /dev/null @@ -1,45 +0,0 @@ -formatVersion: 42 -formatType: testfile ---- -dec: 10 -hex: 0x10 -oct: 010 -bin: 0b10 -float1: 10.10 -float2: 0.10 -float3: .10 -number-separators: 1_234_567 -bool-true: true -bool-yes: yes -bool-false: false -bool-no: no -null-literal: null -null-tilde: ~ -string-unquoted: unquoted -string-singlequoted: 'singlequoted' -string-doublequoted: "doublequoted" -list-int: -- 1 -- 2 -- 3 -list-mixed: -- 1 -- two -- [yes, ~] -map1: - a: 1 - b: two - c: [ 1, 2, 3] - -extended: - ext-string: 'ext string' - -stringlist-string: string -stringlist-list1: [ string ] -stringlist-list2: [ string1, string2 ] - -list-of-maps: -- index: 1 - name: '1' -- index: 2 - name: '2' diff --git a/tests/yaml/tst_yaml.cpp b/tests/yaml/tst_yaml.cpp deleted file mode 100644 index 7d5a2233..00000000 --- a/tests/yaml/tst_yaml.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtApplicationManager module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -#include "qtyaml.h" -#include "configcache.h" -#include "exception.h" -#include "global.h" - -QT_USE_NAMESPACE_AM - -class tst_Yaml : public QObject -{ - Q_OBJECT - -public: - tst_Yaml(); - -private slots: - void parser(); - void documentParser(); - void cache(); - void mergedCache(); - void parallel(); -}; - - -tst_Yaml::tst_Yaml() -{ } - -void tst_Yaml::parser() -{ - static const QVariant vnull = QVariant::fromValue(nullptr); - - QVector> tests = { - { "dec", QVariant::fromValue(10) }, - { "hex", QVariant::fromValue(16) }, - { "bin", QVariant::fromValue(2) }, - { "oct", QVariant::fromValue(8) }, - { "float1", QVariant::fromValue(10.1) }, - { "float2", QVariant::fromValue(.1) }, - { "float3", QVariant::fromValue(.1) }, - { "number-separators", QVariant::fromValue(1234567) }, - { "bool-true", true }, - { "bool-yes", true }, - { "bool-false", false }, - { "bool-no", false }, - { "null-literal", vnull }, - { "null-tilde", vnull }, - { "string-unquoted", QVariant::fromValue("unquoted") }, - { "string-singlequoted", QVariant::fromValue("singlequoted") }, - { "string-doublequoted", QVariant::fromValue("doublequoted") }, - { "list-int", QVariantList { 1, 2, 3 } }, - { "list-mixed", QVariantList { 1, "two", QVariantList { true, vnull } } }, - { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } } - }; - - try { - QFile f(":/data/test.yaml"); - QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); - QByteArray ba = f.readAll(); - QVERIFY(!ba.isEmpty()); - YamlParser p(ba); - auto header = p.parseHeader(); - - QCOMPARE(header.first, "testfile"); - QCOMPARE(header.second, 42); - - QVERIFY(p.nextDocument()); - - YamlParser::Fields fields; - for (const auto &pair : tests) { - YamlParser::FieldType type = YamlParser::Scalar; - if (pair.second.metaType() == QMetaType::fromType()) - type = YamlParser::List; - else if (pair.second.metaType() == QMetaType::fromType()) - type = YamlParser::Map; - QVariant value = pair.second; - - fields.emplace_back(pair.first, true, type, [type, value](YamlParser *p) { - switch (type) { - case YamlParser::Scalar: { - QVERIFY(p->isScalar()); - QVariant v = p->parseScalar(); - QCOMPARE(int(v.metaType().id()), value.metaType().id()); - QVERIFY(v == value); - break; - } - case YamlParser::List: { - QVERIFY(p->isList()); - QVariantList vl = p->parseList(); - QVERIFY(vl == value.toList()); - break; - } - case YamlParser::Map: { - QVERIFY(p->isMap()); - QVariantMap vm = p->parseMap(); - QVERIFY(vm == value.toMap()); - break; - } - } - }); - } - fields.emplace_back("extended", true, YamlParser::Map, [](YamlParser *p) { - YamlParser::Fields extFields = { - { "ext-string", true, YamlParser::Scalar, [](YamlParser *p) { - QVERIFY(p->isScalar()); - QVariant v = p->parseScalar(); - QCOMPARE(v.metaType(), QMetaType::fromType()); - QCOMPARE(v.toString(), "ext string"); - } } - }; - p->parseFields(extFields); - }); - - fields.emplace_back("stringlist-string", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { - QCOMPARE(p->parseStringOrStringList(), QStringList { "string" }); - }); - fields.emplace_back("stringlist-list1", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { - QCOMPARE(p->parseStringOrStringList(), QStringList { "string" }); - }); - fields.emplace_back("stringlist-list2", true, YamlParser::Scalar | YamlParser::List, [](YamlParser *p) { - QCOMPARE(p->parseStringOrStringList(), QStringList({ "string1", "string2" })); - }); - - fields.emplace_back("list-of-maps", true, YamlParser::List, [](YamlParser *p) { - int index = 0; - p->parseList([&index](YamlParser *p) { - ++index; - YamlParser::Fields lomFields = { - { "index", true, YamlParser::Scalar, [&index](YamlParser *p) { - QCOMPARE(p->parseScalar().toInt(), index); - } }, - { "name", true, YamlParser::Scalar, [&index](YamlParser *p) { - QCOMPARE(p->parseScalar().toString(), QString::number(index)); - } } - }; - p->parseFields(lomFields); - }); - QCOMPARE(index, 2); - }); - - p.parseFields(fields); - - QVERIFY(!p.nextDocument()); - - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } -} - -static const QVariant vnull = QVariant::fromValue(nullptr); - -static const QVariantMap testHeaderDoc = { - { "formatVersion", 42 }, { "formatType", "testfile" } -}; - -static const QVariantMap testMainDoc = { - { "dec", 10 }, - { "hex", 16 }, - { "bin", 2 }, - { "oct", 8 }, - { "float1", 10.1 }, - { "float2", .1 }, - { "float3", .1 }, - { "number-separators", 1234567 }, - { "bool-true", true }, - { "bool-yes", true }, - { "bool-false", false }, - { "bool-no", false }, - { "null-literal", vnull }, - { "null-tilde", vnull }, - { "string-unquoted", "unquoted" }, - { "string-singlequoted", "singlequoted" }, - { "string-doublequoted", "doublequoted" }, - { "list-int", QVariantList { 1, 2, 3 } }, - { "list-mixed", QVariantList { 1, qSL("two"), QVariantList { true, vnull } } }, - { "map1", QVariantMap { { "a", 1 }, { "b", "two" }, { "c", QVariantList { 1, 2, 3 } } } }, - - - { "extended", QVariantMap { { "ext-string", "ext string" } } }, - - { "stringlist-string", "string" }, - { "stringlist-list1", QVariantList { "string" } }, - { "stringlist-list2", QVariantList { "string1", "string2" } }, - - { "list-of-maps", QVariantList { QVariantMap { { "index", 1 }, { "name", "1" } }, - QVariantMap { { "index", 2 }, { "name", "2" } } } } -}; - -void tst_Yaml::documentParser() -{ - try { - QFile f(":/data/test.yaml"); - QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); - QByteArray ba = f.readAll(); - QVERIFY(!ba.isEmpty()); - QVector docs = YamlParser::parseAllDocuments(ba); - QCOMPARE(docs.size(), 2); - QCOMPARE(docs.at(0).toMap().size(), 2); - - QCOMPARE(testHeaderDoc, docs.at(0).toMap()); - QCOMPARE(testMainDoc, docs.at(1).toMap()); - - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } -} -struct CacheTest -{ - QString name; - QString file; -}; - -// GCC < 7 bug, currently still in RHEL7, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 -// this should simply be: -// template<> class QT_PREPEND_NAMESPACE_AM(ConfigCacheAdaptor) - -QT_BEGIN_NAMESPACE_AM -template<> class ConfigCacheAdaptor -{ -public: - CacheTest *loadFromSource(QIODevice *source, const QString &fileName) - { - QScopedPointer ct(new CacheTest); - YamlParser p(source->readAll(), fileName); - p.nextDocument(); - p.parseFields({ { "name", true, YamlParser::Scalar, [&ct](YamlParser *p) { - ct->name = p->parseScalar().toString(); } }, - { "file", true, YamlParser::Scalar, [&ct](YamlParser *p) { - ct->file = p->parseScalar().toString(); } } - }); - return ct.take(); - } - CacheTest *loadFromCache(QDataStream &ds) - { - CacheTest *ct = new CacheTest; - ds >> ct->name >> ct->file; - return ct; - } - void saveToCache(QDataStream &ds, const CacheTest *ct) - { - ds << ct->name << ct->file; - } - - void merge(CacheTest *ct1, const CacheTest *ct2) - { - ct1->name = ct2->name; - ct1->file = ct1->file + qSL(",") + ct2->file; - } - void preProcessSourceContent(QByteArray &sourceContent, const QString &fileName) - { - sourceContent.replace("${FILE}", fileName.toUtf8()); - } -}; -QT_END_NAMESPACE_AM - -void tst_Yaml::cache() -{ - QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" }; - - for (int step = 0; step < 2; ++step) { - try { - ConfigCache cache(files, "cache-test", "CTST", 1, - step == 0 ? AbstractConfigCache::ClearCache - : AbstractConfigCache::None); - cache.parse(); - QVERIFY(cache.parseReadFromCache() == (step == 1)); - QVERIFY(cache.parseWroteToCache() == (step == 0)); - CacheTest *ct1 = cache.takeResult(0); - QVERIFY(ct1); - QCOMPARE(ct1->name, "cache1"); - QCOMPARE(ct1->file, ":/data/cache1.yaml"); - CacheTest *ct2 = cache.takeResult(1); - QVERIFY(ct2); - QCOMPARE(ct2->name, "cache2"); - QCOMPARE(ct2->file, ":/data/cache2.yaml"); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - } - - ConfigCache wrongVersion(files, "cache-test", "CTST", 2, AbstractConfigCache::None); - QTest::ignoreMessage(QtWarningMsg, "Failed to read cache: failed to parse cache header"); - wrongVersion.parse(); - QVERIFY(!wrongVersion.parseReadFromCache()); - - ConfigCache wrongType(files, "cache-test", "XTST", 1, AbstractConfigCache::None); - QTest::ignoreMessage(QtWarningMsg, "Failed to read cache: failed to parse cache header"); - wrongType.parse(); - QVERIFY(!wrongType.parseReadFromCache()); -} - -void tst_Yaml::mergedCache() -{ - QStringList files = { ":/data/cache1.yaml", ":/data/cache2.yaml" }; - - for (int step = 0; step < 4; ++step) { - AbstractConfigCache::Options options = AbstractConfigCache::MergedResult; - if (step % 2 == 0) - options |= AbstractConfigCache::ClearCache; - if (step == 2) - std::reverse(files.begin(), files.end()); - - try { - ConfigCache cache(files, "cache-test", "MTST", 1, options); - cache.parse(); - QVERIFY(cache.parseReadFromCache() == (step % 2 == 1)); - QVERIFY(cache.parseWroteToCache() == (step % 2 == 0)); - CacheTest *ct = cache.takeMergedResult(); - QVERIFY(ct); - QCOMPARE(ct->name, QFileInfo(files.last()).baseName()); - QCOMPARE(ct->file, files.join(qSL(","))); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - } -} - -class YamlRunnable : public QRunnable -{ -public: - YamlRunnable(const QByteArray &yaml, QAtomicInt &success, QAtomicInt &fail) - : m_yaml(yaml) - , m_success(success) - , m_fail(fail) - { } - - void run() override - { - QVector docs; - try { - docs = YamlParser::parseAllDocuments(m_yaml); - } catch (...) { - docs.clear(); - } - if ((docs.size() == 2) - && (docs.at(0).toMap().size() == 2) - && (testHeaderDoc == docs.at(0).toMap()) - && (testMainDoc == docs.at(1).toMap())) { - m_success.fetchAndAddOrdered(1); - } else { - m_fail.fetchAndAddOrdered(1); - } - } -private: - const QByteArray m_yaml; - QAtomicInt &m_success; - QAtomicInt &m_fail; -}; - -void tst_Yaml::parallel() -{ - QFile f(":/data/test.yaml"); - QVERIFY2(f.open(QFile::ReadOnly), qPrintable(f.errorString())); - QByteArray ba = f.readAll(); - QVERIFY(!ba.isEmpty()); - - constexpr int threadCount = 16; - - QAtomicInt success; - QAtomicInt fail; - - QThreadPool tp; - if (tp.maxThreadCount() < threadCount) - tp.setMaxThreadCount(threadCount); - - for (int i = 0; i < threadCount; ++i) - tp.start(new YamlRunnable(ba, success, fail)); - - QVERIFY(tp.waitForDone(5000)); - QCOMPARE(fail.loadAcquire(), 0); - QCOMPARE(success.loadAcquire(), threadCount); -} - -QTEST_MAIN(tst_Yaml) - -#include "tst_yaml.moc" diff --git a/tests/yaml/yaml.pro b/tests/yaml/yaml.pro deleted file mode 100644 index 5cc4bbb5..00000000 --- a/tests/yaml/yaml.pro +++ /dev/null @@ -1,12 +0,0 @@ -TARGET = tst_yaml - -include($$PWD/../tests.pri) - -QT *= appman_common-private - -SOURCES += tst_yaml.cpp - -RESOURCES += \ - data/test.yaml \ - data/cache1.yaml \ - data/cache2.yaml \ -- cgit v1.2.3