mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-30 20:35:03 +01:00
Compare commits
96
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e6399fe39 | ||
|
|
b362b6b6c8 | ||
|
|
bf0db64e03 | ||
|
|
f7f48005fb | ||
|
|
32d12677ff | ||
|
|
0ab05345fb | ||
|
|
5a5e7883a3 | ||
|
|
a2d45189b9 | ||
|
|
7c5c37ac8f | ||
|
|
f7e6b9f128 | ||
|
|
6c36e5dd0c | ||
|
|
a2f6f2d001 | ||
|
|
2862a33bdd | ||
|
|
6c9dd75283 | ||
|
|
5c4e558ab4 | ||
|
|
c4f53a1adb | ||
|
|
9d3e842358 | ||
|
|
c2e2bfbd9e | ||
|
|
933abe4a19 | ||
|
|
ecec541087 | ||
|
|
e6b96891ef | ||
|
|
82cee749b5 | ||
|
|
0b18e4842c | ||
|
|
0e9fc21ec0 | ||
|
|
9afc16c4e8 | ||
|
|
e91e8b785b | ||
|
|
15b39c1df3 | ||
|
|
4613405fd6 | ||
|
|
4586c4f500 | ||
|
|
9f959a9837 | ||
|
|
fbb71f3a14 | ||
|
|
e87a5dd805 | ||
|
|
78b90c34c3 | ||
|
|
fd02eb5592 | ||
|
|
4967e14ba2 | ||
|
|
eb5a6f5f9f | ||
|
|
35cee6a901 | ||
|
|
60026b0636 | ||
|
|
4fc17862cb | ||
|
|
9b0808259a | ||
|
|
c4530d6e5f | ||
|
|
8a7adde307 | ||
|
|
90e14aa082 | ||
|
|
c106ed3325 | ||
|
|
ae7c74cfa5 | ||
|
|
ab91dd76ff | ||
|
|
e8acfa0be3 | ||
|
|
751971e554 | ||
|
|
23bc592b8f | ||
|
|
798b7b161a | ||
|
|
341d92aef0 | ||
|
|
95e9c54b39 | ||
|
|
575644144d | ||
|
|
35c2729211 | ||
|
|
4d9c4ecf6a | ||
|
|
f936833911 | ||
|
|
37edc07ede | ||
|
|
74176002ff | ||
|
|
dec0bf8096 | ||
|
|
74aa5e2a7b | ||
|
|
882b9f3f22 | ||
|
|
a24b044a1e | ||
|
|
956fb94dd6 | ||
|
|
cf411e5ed3 | ||
|
|
e8043c76e3 | ||
|
|
93b7f9301c | ||
|
|
7f6d09003a | ||
|
|
ee6c7bf50b | ||
|
|
31dcdee20a | ||
|
|
cb8e164fbb | ||
|
|
b74bb7f011 | ||
|
|
d2b7937c2c | ||
|
|
ef280c2e5f | ||
|
|
6cb9cfffa8 | ||
|
|
78b4f77518 | ||
|
|
88fcdcb08a | ||
|
|
fb30987533 | ||
|
|
6e06a07978 | ||
|
|
6b0086795d | ||
|
|
3afa8f08bc | ||
|
|
cd91df3292 | ||
|
|
5f2744d520 | ||
|
|
a3b66c4bf0 | ||
|
|
881ba70c1a | ||
|
|
ebda0be762 | ||
|
|
a7ad643719 | ||
|
|
9880ce0765 | ||
|
|
1ed60133f6 | ||
|
|
b6dc660155 | ||
|
|
a0146592cd | ||
|
|
ebc96321e7 | ||
|
|
e375421e24 | ||
|
|
1aaec1978a | ||
|
|
dfe803fdbc | ||
|
|
ef6b3c5888 | ||
|
|
a8f9845e39 |
No files matched your search
@@ -51,6 +51,26 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20250310: caroot bundle updated
|
||||
OLD_FILES+=usr/share/certs/trusted/Entrust_Root_Certification_Authority_-_G4.pem
|
||||
OLD_FILES+=usr/share/certs/trusted/SecureSign_RootCA11.pem
|
||||
OLD_FILES+=usr/share/certs/trusted/Security_Communication_RootCA3.pem
|
||||
OLD_FILES+=usr/share/certs/trusted/SwissSign_Silver_CA_-_G2.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/AddTrust_External_Root.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/AddTrust_Low-Value_Services_Root.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_Root_CA_-_G2.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Cybertrust_Global_Root.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/DST_Root_CA_X3.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/GlobalSign_Root_CA_-_R2.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/QuoVadis_Root_CA.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Sonera_Class_2_Root_CA.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Global_CA.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_EV_Root_CA.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/E-Tugra_Certification_Authority.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Hongkong_Post_Root_CA_1.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Security_Communication_Root_CA.pem
|
||||
OLD_FILES+=usr/share/certs/blacklisted/Trustis_FPS_Root_CA.pem
|
||||
|
||||
# 20241201: new clang import which bumps version from 18 to 19
|
||||
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_builtin_vars.h
|
||||
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_cmath.h
|
||||
@@ -347,6 +367,7 @@ OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-i386.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64le.a
|
||||
@@ -365,6 +386,7 @@ OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
|
||||
|
||||
@@ -12,6 +12,134 @@ Items affecting the ports and packages system can be found in
|
||||
/usr/ports/UPDATING. Please read that file before updating system packages
|
||||
and/or ports.
|
||||
|
||||
20260430:
|
||||
13.5-RELEASE-p14 EN-26:11.dhclient
|
||||
|
||||
dhclient(8) lease validation is too strict. [EN-26:11.dhclient]
|
||||
|
||||
20260429:
|
||||
13.5-RELEASE-p13 SA-26:12.dhclient
|
||||
SA-26:13.exec
|
||||
SA-26:14.pf
|
||||
SA-26:15.dhclient
|
||||
SA-26:16.libnv
|
||||
SA-26:17.libnv
|
||||
EN-26:09.tzdata
|
||||
|
||||
Remote code execution via malicious DHCP options. [SA-26:12.dhclient]
|
||||
|
||||
Local privilege escalation via execve(). [SA-26:13.exec]
|
||||
|
||||
pf can overflow the stack parsing crafted SCTP packets. [SA-26:14.pf]
|
||||
|
||||
Remotely triggerable out-of-bounds heap write in dhclient. [SA-26:15.dhclient]
|
||||
|
||||
Stack overflow via select() file descriptor set overflow. [SA-26:16.libnv]
|
||||
|
||||
Heap overflow in libnv. [SA-26:17.libnv]
|
||||
|
||||
Timezone database information update. [EN-26:09.tzdata]
|
||||
|
||||
20260421:
|
||||
13.5-RELEASE-p12 SA-26:10.tty
|
||||
SA-26:11.amd64
|
||||
EN-26:05.vm
|
||||
|
||||
Kernel use-after-free bug in the TIOCNOTTY handler. [SA-26:10.tty]
|
||||
|
||||
Missing large page handling in pmap_pkru_update_range(). [SA-26:11.amd64]
|
||||
|
||||
The page fault handler fails to zero memory. [EN-26:05.vm]
|
||||
|
||||
20260325:
|
||||
13.5-RELEASE-p11 SA-26:08.rpcsec_gss
|
||||
|
||||
Remote code execution via RPCSEC_GSS packet validation. [SA-26:08.rpcsec_gss]
|
||||
|
||||
20260224:
|
||||
13.5-RELEASE-p10 SA-26:04.jail
|
||||
SA-26:05.route
|
||||
|
||||
Jail chroot escape via fd exchange with a different jail. [SA-26:04.jail]
|
||||
|
||||
Local DoS and possible privilege escalation via routing sockets. [SA-26:05.route]
|
||||
|
||||
20260127:
|
||||
13.5-RELEASE-p9 SA-26:01.openssl
|
||||
SA-26:02.jail
|
||||
EN-26:03.vm
|
||||
|
||||
Fix multiple vulnerabilities in OpenSSL. [SA-26:01.openssl]
|
||||
|
||||
Jail escape by a privileged user via nullfs. [SA-26:02.jail]
|
||||
|
||||
The page fault handler fails to zero memory. [EN-26:03.vm]
|
||||
|
||||
20251216:
|
||||
13.5-RELEASE-p8 SA-25:11.ipfw
|
||||
SA-25:12.rtsold
|
||||
|
||||
ipfw denial of service. [SA-25:11.ipfw]
|
||||
|
||||
Remote code execution via ND6 Router Advertisements. [SA-25:12.rtsold]
|
||||
|
||||
20251126:
|
||||
13.5-RELEASE-p7 SA-25:10.unbound
|
||||
|
||||
Fix cache poison in local-unbound service. [SA-25:10.unbound]
|
||||
|
||||
20251022:
|
||||
13.5-RELEASE-p6 SA-25:09.netinet
|
||||
|
||||
SO_REUSEPORT_LB breaks connect(2) for UDP sockets. [SA-25:09.netinet]
|
||||
|
||||
20250930:
|
||||
13.5-RELEASE-p5 EN-25:18.freebsd-update
|
||||
SA-25:08.openssl
|
||||
|
||||
Fix freebsd-update(8) installing libraries in incorrect order. [EN-25:18.freebsd-update]
|
||||
|
||||
Fix multiple vulnerabilities in OpenSSL. [SA-25:08.openssl]
|
||||
|
||||
20250916:
|
||||
13.5-RELEASE-p4 EN-25:15.arm64
|
||||
|
||||
Fix arm64 syscall(2) allows unprivileged user to panic kernel. [EN-25:15.arm64]
|
||||
|
||||
20250808:
|
||||
13.5-RELEASE-p3 SA-25:07.libarchive
|
||||
|
||||
Update libarchive to 3.8.1 to fix integer overflow leading to double
|
||||
free. [SA-25:07.libarchive]
|
||||
|
||||
20250702:
|
||||
13.5-RELEASE-p2 EN-25:09.libc
|
||||
EN-25:10.zfs
|
||||
EN-25:11.ena
|
||||
SA-25:06.xz
|
||||
|
||||
Fix dynamically-loaded C++ libraries crashing at exit [EN-25:09.libc]
|
||||
|
||||
Fix corruption in ZFS replication streams from encrypted datasets [EN-25:10.zfs]
|
||||
|
||||
Fix ena resets and kernel panic on Nitro v4 or newer instances [EN-25:11.ena]
|
||||
|
||||
Fix use-after-free in multi-threaded xz decoder [SA-25:06.xz]
|
||||
|
||||
20250410:
|
||||
13.5-RELEASE-p1 EN-25:04.tzdata
|
||||
EN-25:05.expat
|
||||
EN-25:08.caroot
|
||||
|
||||
Timezone database information update [EN-25:04.tzdata]
|
||||
|
||||
Update expat to 2.7.1 [EN-25:05.expat]
|
||||
|
||||
Root certificate bundle update [EN-25:08.caroot]
|
||||
|
||||
20250311:
|
||||
13.5-RELEASE.
|
||||
|
||||
20250117:
|
||||
The layout of NFS file handles for the cd9660 and ext2fs file systems
|
||||
has changed. An NFS server that exports any of these file systems will
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
|
||||
Copyright (c) 2001-2022 Expat maintainers
|
||||
Copyright (c) 2001-2025 Expat maintainers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
+121
-2
@@ -11,16 +11,23 @@
|
||||
!! The following topics need *additional skilled C developers* to progress !!
|
||||
!! in a timely manner or at all (loosely ordered by descending priority): !!
|
||||
!! !!
|
||||
!! - <blink>fixing a complex non-public security issue</blink>, !!
|
||||
!! - teaming up on researching and fixing future security reports and !!
|
||||
!! ClusterFuzz findings with few-days-max response times in communication !!
|
||||
!! in order to (1) have a sound fix ready before the end of a 90 days !!
|
||||
!! grace period and (2) in a sustainable manner, !!
|
||||
!! - helping CPython Expat bindings with supporting Expat's billion laughs !!
|
||||
!! attack protection API (https://github.com/python/cpython/issues/90949): !!
|
||||
!! - XML_SetBillionLaughsAttackProtectionActivationThreshold !!
|
||||
!! - XML_SetBillionLaughsAttackProtectionMaximumAmplification !!
|
||||
!! - helping Perl's XML::Parser Expat bindings with supporting Expat's !!
|
||||
!! security API (https://github.com/cpan-authors/XML-Parser/issues/102): !!
|
||||
!! - XML_SetBillionLaughsAttackProtectionActivationThreshold !!
|
||||
!! - XML_SetBillionLaughsAttackProtectionMaximumAmplification !!
|
||||
!! - XML_SetReparseDeferralEnabled !!
|
||||
!! - implementing and auto-testing XML 1.0r5 support !!
|
||||
!! (needs discussion before pull requests), !!
|
||||
!! - smart ideas on fixing the Autotools CMake files generation issue !!
|
||||
!! without breaking CI (needs discussion before pull requests), !!
|
||||
!! - the Windows binaries topic (needs requirements engineering first), !!
|
||||
!! - pushing migration from `int` to `size_t` further !!
|
||||
!! including edge-cases test coverage (needs discussion before anything). !!
|
||||
!! !!
|
||||
@@ -30,6 +37,116 @@
|
||||
!! THANK YOU! Sebastian Pipping -- Berlin, 2024-03-09 !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
Release 2.7.1 Thu March 27 2025
|
||||
Bug fixes:
|
||||
#980 #989 Restore event pointer behavior from Expat 2.6.4
|
||||
(that the fix to CVE-2024-8176 changed in 2.7.0);
|
||||
affected API functions are:
|
||||
- XML_GetCurrentByteCount
|
||||
- XML_GetCurrentByteIndex
|
||||
- XML_GetCurrentColumnNumber
|
||||
- XML_GetCurrentLineNumber
|
||||
- XML_GetInputContext
|
||||
|
||||
Other changes:
|
||||
#976 #977 Autotools: Integrate files "fuzz/xml_lpm_fuzzer.{cpp,proto}"
|
||||
with Automake that were missing from 2.7.0 release tarballs
|
||||
#983 #984 Fix printf format specifiers for 32bit Emscripten
|
||||
#992 docs: Promote OpenSSF Best Practices self-certification
|
||||
#978 tests/benchmark: Resolve mistaken double close
|
||||
#986 Address compiler warnings
|
||||
#990 #993 Version info bumped from 11:1:10 (libexpat*.so.1.10.1)
|
||||
to 11:2:10 (libexpat*.so.1.10.2); see https://verbump.de/
|
||||
for what these numbers do
|
||||
|
||||
Infrastructure:
|
||||
#982 CI: Start running Perl XML::Parser integration tests
|
||||
#987 CI: Enforce Clang Static Analyzer clean code
|
||||
#991 CI: Re-enable warning clang-analyzer-valist.Uninitialized
|
||||
for clang-tidy
|
||||
#981 CI: Cover compilation with musl
|
||||
#983 #984 CI: Cover compilation with 32bit Emscripten
|
||||
#976 #977 CI: Protect against fuzzer files missing from future
|
||||
release archives
|
||||
|
||||
Special thanks to:
|
||||
Berkay Eren Ürün
|
||||
Matthew Fernandez
|
||||
and
|
||||
Perl XML::Parser
|
||||
|
||||
Release 2.7.0 Thu March 13 2025
|
||||
Security fixes:
|
||||
#893 #973 CVE-2024-8176 -- Fix crash from chaining a large number
|
||||
of entities caused by stack overflow by resolving use of
|
||||
recursion, for all three uses of entities:
|
||||
- general entities in character data ("<e>&g1;</e>")
|
||||
- general entities in attribute values ("<e k1='&g1;'/>")
|
||||
- parameter entities ("%p1;")
|
||||
Known impact is (reliable and easy) denial of service:
|
||||
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C
|
||||
(Base Score: 7.5, Temporal Score: 7.2)
|
||||
Please note that a layer of compression around XML can
|
||||
significantly reduce the minimum attack payload size.
|
||||
|
||||
Other changes:
|
||||
#935 #937 Autotools: Make generated CMake files look for
|
||||
libexpat.@[email protected] on macOS
|
||||
#925 Autotools: Sync CMake templates with CMake 3.29
|
||||
#945 #962 #966 CMake: Drop support for CMake <3.13
|
||||
#942 CMake: Small fuzzing related improvements
|
||||
#921 docs: Add missing documentation of error code
|
||||
XML_ERROR_NOT_STARTED that was introduced with 2.6.4
|
||||
#941 docs: Document need for C++11 compiler for use from C++
|
||||
#959 tests/benchmark: Fix a (harmless) TOCTTOU
|
||||
#944 Windows: Fix installer target location of file xmlwf.xml
|
||||
for CMake
|
||||
#953 Windows: Address warning -Wunknown-warning-option
|
||||
about -Wno-pedantic-ms-format from LLVM MinGW
|
||||
#971 Address Cppcheck warnings
|
||||
#969 #970 Mass-migrate links from http:// to https://
|
||||
#947 #958 ..
|
||||
#974 #975 Document changes since the previous release
|
||||
#974 #975 Version info bumped from 11:0:10 (libexpat*.so.1.10.0)
|
||||
to 11:1:10 (libexpat*.so.1.10.1); see https://verbump.de/
|
||||
for what these numbers do
|
||||
|
||||
Infrastructure:
|
||||
#926 tests: Increase robustness
|
||||
#927 #932 ..
|
||||
#930 #933 tests: Increase test coverage
|
||||
#617 #950 ..
|
||||
#951 #952 ..
|
||||
#954 #955 .. Fuzzing: Add new fuzzer "xml_lpm_fuzzer" based on
|
||||
#961 Google's libprotobuf-mutator ("LPM")
|
||||
#957 Fuzzing|CI: Start producing fuzzing code coverage reports
|
||||
#936 CI: Pass -q -q for LCOV >=2.1 in coverage.sh
|
||||
#942 CI: Small fuzzing related improvements
|
||||
#139 #203 ..
|
||||
#791 #946 CI: Make GitHub Actions build using MSVC on Windows and
|
||||
produce 32bit and 64bit Windows binaries
|
||||
#956 CI: Get off of about-to-be-removed Ubuntu 20.04
|
||||
#960 #964 CI: Start uploading to Coverity Scan for static analysis
|
||||
#972 CI: Stop loading DTD from the internet to address flaky CI
|
||||
#971 CI: Adapt to breaking changes in Cppcheck
|
||||
|
||||
Special thanks to:
|
||||
Alexander Gieringer
|
||||
Berkay Eren Ürün
|
||||
Hanno Böck
|
||||
Jann Horn
|
||||
Mark Brand
|
||||
Sebastian Andrzej Siewior
|
||||
Snild Dolkow
|
||||
Thomas Pröll
|
||||
Tomas Korbar
|
||||
valord577
|
||||
and
|
||||
Google Project Zero
|
||||
Linutronix
|
||||
Red Hat
|
||||
Siemens
|
||||
|
||||
Release 2.6.4 Wed November 6 2024
|
||||
Security fixes:
|
||||
#915 CVE-2024-50602 -- Fix crash within function XML_ResumeParser
|
||||
@@ -46,6 +163,8 @@ Release 2.6.4 Wed November 6 2024
|
||||
#904 tests: Resolve duplicate handler
|
||||
#317 #918 tests: Improve tests on doctype closing (ex CVE-2019-15903)
|
||||
#914 Fix signedness of format strings
|
||||
#915 For use from C++, expat.h started requiring C++11 due to
|
||||
use of C99 features
|
||||
#919 #920 Version info bumped from 10:3:9 (libexpat*.so.1.9.3)
|
||||
to 11:0:10 (libexpat*.so.1.10.0); see https://verbump.de/
|
||||
for what these numbers do
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# \___/_/\_\ .__/ \__,_|\__|
|
||||
# |_| XML parser
|
||||
#
|
||||
# Copyright (c) 2017-2023 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2018 KangLin <[email protected]>
|
||||
# Copyright (c) 2022 Johnny Jazeix <[email protected]>
|
||||
# Copyright (c) 2023 Sony Corporation / Snild Dolkow <[email protected]>
|
||||
@@ -96,6 +96,8 @@ EXTRA_DIST = \
|
||||
conftools/expat.m4 \
|
||||
conftools/get-version.sh \
|
||||
\
|
||||
fuzz/xml_lpm_fuzzer.cpp \
|
||||
fuzz/xml_lpm_fuzzer.proto \
|
||||
fuzz/xml_parsebuffer_fuzzer.c \
|
||||
fuzz/xml_parse_fuzzer.c \
|
||||
\
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# \___/_/\_\ .__/ \__,_|\__|
|
||||
# |_| XML parser
|
||||
#
|
||||
# Copyright (c) 2017-2023 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2018 KangLin <[email protected]>
|
||||
# Copyright (c) 2022 Johnny Jazeix <[email protected]>
|
||||
# Copyright (c) 2023 Sony Corporation / Snild Dolkow <[email protected]>
|
||||
@@ -494,6 +494,8 @@ EXTRA_DIST = \
|
||||
conftools/expat.m4 \
|
||||
conftools/get-version.sh \
|
||||
\
|
||||
fuzz/xml_lpm_fuzzer.cpp \
|
||||
fuzz/xml_lpm_fuzzer.proto \
|
||||
fuzz/xml_parsebuffer_fuzzer.c \
|
||||
fuzz/xml_parse_fuzzer.c \
|
||||
\
|
||||
|
||||
+7
-11
@@ -3,6 +3,7 @@
|
||||
[](https://repology.org/metapackage/expat/versions)
|
||||
[](https://sourceforge.net/projects/expat/files/)
|
||||
[](https://github.com/libexpat/libexpat/releases)
|
||||
[](https://www.bestpractices.dev/projects/10205)
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
@@ -11,7 +12,7 @@
|
||||
> at the top of the `Changes` file.
|
||||
|
||||
|
||||
# Expat, Release 2.6.4
|
||||
# Expat, Release 2.7.1
|
||||
|
||||
This is Expat, a C99 library for parsing
|
||||
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
|
||||
@@ -22,9 +23,9 @@ are called when the parser discovers the associated structures in the
|
||||
document being parsed. A start tag is an example of the kind of
|
||||
structures for which you may register handlers.
|
||||
|
||||
Expat supports the following compilers:
|
||||
Expat supports the following C99 compilers:
|
||||
|
||||
- GNU GCC >=4.5
|
||||
- GNU GCC >=4.5 (for use from C) or GNU GCC >=4.8.1 (for use from C++)
|
||||
- LLVM Clang >=3.5
|
||||
- Microsoft Visual Studio >=16.0/2019 (rolling `${today} minus 5 years`)
|
||||
|
||||
@@ -52,7 +53,7 @@ This approach leverages CMake's own [module `FindEXPAT`](https://cmake.org/cmake
|
||||
Notice the *uppercase* `EXPAT` in the following example:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.0) # or 3.10, see below
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(hello VERSION 1.0.0)
|
||||
|
||||
@@ -62,12 +63,7 @@ add_executable(hello
|
||||
hello.c
|
||||
)
|
||||
|
||||
# a) for CMake >=3.10 (see CMake's FindEXPAT docs)
|
||||
target_link_libraries(hello PUBLIC EXPAT::EXPAT)
|
||||
|
||||
# b) for CMake >=3.0
|
||||
target_include_directories(hello PRIVATE ${EXPAT_INCLUDE_DIRS})
|
||||
target_link_libraries(hello PUBLIC ${EXPAT_LIBRARIES})
|
||||
```
|
||||
|
||||
### b) `find_package` with Config Mode
|
||||
@@ -85,7 +81,7 @@ or
|
||||
Notice the *lowercase* `expat` in the following example:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(hello VERSION 1.0.0)
|
||||
|
||||
@@ -295,7 +291,7 @@ EXPAT_ENABLE_INSTALL:BOOL=ON
|
||||
// Use /MT flag (static CRT) when compiling in MSVC
|
||||
EXPAT_MSVC_STATIC_CRT:BOOL=OFF
|
||||
|
||||
// Build fuzzers via ossfuzz for the expat library
|
||||
// Build fuzzers via OSS-Fuzz for the expat library
|
||||
EXPAT_OSSFUZZ_BUILD:BOOL=OFF
|
||||
|
||||
// Build a shared expat library
|
||||
|
||||
@@ -11,7 +11,7 @@ dnl Copyright (c) 2000 Clark Cooper <[email protected]>
|
||||
dnl Copyright (c) 2000-2005 Fred L. Drake, Jr. <[email protected]>
|
||||
dnl Copyright (c) 2001-2003 Greg Stein <[email protected]>
|
||||
dnl Copyright (c) 2006-2012 Karl Waclawek <[email protected]>
|
||||
dnl Copyright (c) 2016-2024 Sebastian Pipping <[email protected]>
|
||||
dnl Copyright (c) 2016-2025 Sebastian Pipping <[email protected]>
|
||||
dnl Copyright (c) 2017 S. P. Zeidler <[email protected]>
|
||||
dnl Copyright (c) 2017 Stephen Groat <[email protected]>
|
||||
dnl Copyright (c) 2017-2020 Joe Orton <[email protected]>
|
||||
@@ -85,7 +85,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
|
||||
dnl
|
||||
|
||||
LIBCURRENT=11 # sync
|
||||
LIBREVISION=0 # with
|
||||
LIBREVISION=2 # with
|
||||
LIBAGE=10 # CMakeLists.txt!
|
||||
|
||||
AC_CONFIG_HEADERS([expat_config.h])
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
Copyright (c) 2000 Clark Cooper <[email protected]>
|
||||
Copyright (c) 2000-2004 Fred L. Drake, Jr. <[email protected]>
|
||||
Copyright (c) 2002-2012 Karl Waclawek <[email protected]>
|
||||
Copyright (c) 2017-2024 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2017 Jakub Wilk <[email protected]>
|
||||
Copyright (c) 2021 Tomas Korbar <[email protected]>
|
||||
Copyright (c) 2021 Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
|
||||
@@ -52,7 +52,7 @@
|
||||
<div>
|
||||
<h1>
|
||||
The Expat XML Parser
|
||||
<small>Release 2.6.4</small>
|
||||
<small>Release 2.7.1</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
@@ -1267,6 +1267,11 @@ call-backs, except when parsing an external parameter entity and
|
||||
<code>XML_STATUS_ERROR</code> otherwise. The possible error codes
|
||||
are:</p>
|
||||
<dl>
|
||||
<dt><code>XML_ERROR_NOT_STARTED</code></dt>
|
||||
<dd>
|
||||
when stopping or suspending a parser before it has started,
|
||||
added in Expat 2.6.4.
|
||||
</dd>
|
||||
<dt><code>XML_ERROR_SUSPENDED</code></dt>
|
||||
<dd>when suspending an already suspended parser.</dd>
|
||||
<dt><code>XML_ERROR_FINISHED</code></dt>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
\\$2 \(la\\$1\(ra\\$3
|
||||
..
|
||||
.if \n(.g .mso www.tmac
|
||||
.TH XMLWF 1 "November 6, 2024" "" ""
|
||||
.TH XMLWF 1 "March 27, 2025" "" ""
|
||||
.SH NAME
|
||||
xmlwf \- Determines if an XML document is well-formed
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
Copyright (c) 2001 Scott Bronson <[email protected]>
|
||||
Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
|
||||
Copyright (c) 2009 Karl Waclawek <[email protected]>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2016 Ardo van Rangelrooij <[email protected]>
|
||||
Copyright (c) 2017 Rhodri James <[email protected]>
|
||||
Copyright (c) 2020 Joe Orton <[email protected]>
|
||||
@@ -21,7 +21,7 @@
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
|
||||
<!ENTITY dhsurname "<surname>Bronson</surname>">
|
||||
<!ENTITY dhdate "<date>November 6, 2024</date>">
|
||||
<!ENTITY dhdate "<date>March 27, 2025</date>">
|
||||
<!-- Please adjust this^^ date whenever cutting a new release. -->
|
||||
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
|
||||
<!ENTITY dhemail "<email>[email protected]</email>">
|
||||
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
| __// \| |_) | (_| | |_
|
||||
\___/_/\_\ .__/ \__,_|\__|
|
||||
|_| XML parser
|
||||
|
||||
Copyright (c) 2022 Mark Brand <markbrand@google.com>
|
||||
Copyright (c) 2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Licensed under the MIT license:
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# undef NDEBUG // because checks below rely on assert(...)
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "expat.h"
|
||||
#include "xml_lpm_fuzzer.pb.h"
|
||||
#include "src/libfuzzer/libfuzzer_macro.h"
|
||||
|
||||
static const char *g_encoding = nullptr;
|
||||
static const char *g_external_entity = nullptr;
|
||||
static size_t g_external_entity_size = 0;
|
||||
|
||||
void
|
||||
SetEncoding(const xml_lpm_fuzzer::Encoding &e) {
|
||||
switch (e) {
|
||||
case xml_lpm_fuzzer::Encoding::UTF8:
|
||||
g_encoding = "UTF-8";
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Encoding::UTF16:
|
||||
g_encoding = "UTF-16";
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Encoding::ISO88591:
|
||||
g_encoding = "ISO-8859-1";
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Encoding::ASCII:
|
||||
g_encoding = "US-ASCII";
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Encoding::NONE:
|
||||
g_encoding = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_encoding = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int g_allocation_count = 0;
|
||||
static std::vector<int> g_fail_allocations = {};
|
||||
|
||||
void *
|
||||
MallocHook(size_t size) {
|
||||
g_allocation_count += 1;
|
||||
for (auto index : g_fail_allocations) {
|
||||
if (index == g_allocation_count) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *
|
||||
ReallocHook(void *ptr, size_t size) {
|
||||
g_allocation_count += 1;
|
||||
for (auto index : g_fail_allocations) {
|
||||
if (index == g_allocation_count) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
void
|
||||
FreeHook(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
XML_Memory_Handling_Suite memory_handling_suite
|
||||
= {MallocHook, ReallocHook, FreeHook};
|
||||
|
||||
void InitializeParser(XML_Parser parser);
|
||||
|
||||
// We want a parse function that supports resumption, so that we can cover the
|
||||
// suspend/resume code.
|
||||
enum XML_Status
|
||||
Parse(XML_Parser parser, const char *input, int input_len, int is_final) {
|
||||
enum XML_Status status = XML_Parse(parser, input, input_len, is_final);
|
||||
while (status == XML_STATUS_SUSPENDED) {
|
||||
status = XML_ResumeParser(parser);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// When the fuzzer is compiled with instrumentation such as ASan, then the
|
||||
// accesses in TouchString will fault if they access invalid memory (ie. detect
|
||||
// either a use-after-free or buffer-overflow). By calling TouchString in each
|
||||
// of the callbacks, we can check that the arguments meet the API specifications
|
||||
// in terms of length/null-termination. no_optimize is used to ensure that the
|
||||
// compiler has to emit actual memory reads, instead of removing them.
|
||||
static volatile size_t no_optimize = 0;
|
||||
static void
|
||||
TouchString(const XML_Char *ptr, int len = -1) {
|
||||
if (! ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == -1) {
|
||||
for (XML_Char value = *ptr++; value; value = *ptr++) {
|
||||
no_optimize += value;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
no_optimize += ptr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TouchNodeAndRecurse(XML_Content *content) {
|
||||
switch (content->type) {
|
||||
case XML_CTYPE_EMPTY:
|
||||
case XML_CTYPE_ANY:
|
||||
assert(content->quant == XML_CQUANT_NONE);
|
||||
assert(content->name == NULL);
|
||||
assert(content->numchildren == 0);
|
||||
assert(content->children == NULL);
|
||||
break;
|
||||
|
||||
case XML_CTYPE_MIXED:
|
||||
assert(content->quant == XML_CQUANT_NONE
|
||||
|| content->quant == XML_CQUANT_REP);
|
||||
assert(content->name == NULL);
|
||||
for (unsigned int i = 0; i < content->numchildren; ++i) {
|
||||
assert(content->children[i].type == XML_CTYPE_NAME);
|
||||
assert(content->children[i].quant == XML_CQUANT_NONE);
|
||||
assert(content->children[i].numchildren == 0);
|
||||
assert(content->children[i].children == NULL);
|
||||
TouchString(content->children[i].name);
|
||||
}
|
||||
break;
|
||||
|
||||
case XML_CTYPE_NAME:
|
||||
assert((content->quant == XML_CQUANT_NONE)
|
||||
|| (content->quant == XML_CQUANT_OPT)
|
||||
|| (content->quant == XML_CQUANT_REP)
|
||||
|| (content->quant == XML_CQUANT_PLUS));
|
||||
assert(content->numchildren == 0);
|
||||
assert(content->children == NULL);
|
||||
TouchString(content->name);
|
||||
break;
|
||||
|
||||
case XML_CTYPE_CHOICE:
|
||||
case XML_CTYPE_SEQ:
|
||||
assert((content->quant == XML_CQUANT_NONE)
|
||||
|| (content->quant == XML_CQUANT_OPT)
|
||||
|| (content->quant == XML_CQUANT_REP)
|
||||
|| (content->quant == XML_CQUANT_PLUS));
|
||||
assert(content->name == NULL);
|
||||
for (unsigned int i = 0; i < content->numchildren; ++i) {
|
||||
TouchNodeAndRecurse(&content->children[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
ElementDeclHandler(void *userData, const XML_Char *name, XML_Content *model) {
|
||||
TouchString(name);
|
||||
TouchNodeAndRecurse(model);
|
||||
XML_FreeContentModel((XML_Parser)userData, model);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
AttlistDeclHandler(void *userData, const XML_Char *elname,
|
||||
const XML_Char *attname, const XML_Char *atttype,
|
||||
const XML_Char *dflt, int isrequired) {
|
||||
(void)userData;
|
||||
TouchString(elname);
|
||||
TouchString(attname);
|
||||
TouchString(atttype);
|
||||
TouchString(dflt);
|
||||
(void)isrequired;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
XmlDeclHandler(void *userData, const XML_Char *version,
|
||||
const XML_Char *encoding, int standalone) {
|
||||
(void)userData;
|
||||
TouchString(version);
|
||||
TouchString(encoding);
|
||||
(void)standalone;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
StartElementHandler(void *userData, const XML_Char *name,
|
||||
const XML_Char **atts) {
|
||||
(void)userData;
|
||||
TouchString(name);
|
||||
for (size_t i = 0; atts[i] != NULL; ++i) {
|
||||
TouchString(atts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
EndElementHandler(void *userData, const XML_Char *name) {
|
||||
(void)userData;
|
||||
TouchString(name);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
CharacterDataHandler(void *userData, const XML_Char *s, int len) {
|
||||
(void)userData;
|
||||
TouchString(s, len);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
ProcessingInstructionHandler(void *userData, const XML_Char *target,
|
||||
const XML_Char *data) {
|
||||
(void)userData;
|
||||
TouchString(target);
|
||||
TouchString(data);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
CommentHandler(void *userData, const XML_Char *data) {
|
||||
TouchString(data);
|
||||
// Use the comment handler to trigger parser suspend, so that we can get
|
||||
// coverage of that code.
|
||||
XML_StopParser((XML_Parser)userData, XML_TRUE);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
StartCdataSectionHandler(void *userData) {
|
||||
(void)userData;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
EndCdataSectionHandler(void *userData) {
|
||||
(void)userData;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
DefaultHandler(void *userData, const XML_Char *s, int len) {
|
||||
(void)userData;
|
||||
TouchString(s, len);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
StartDoctypeDeclHandler(void *userData, const XML_Char *doctypeName,
|
||||
const XML_Char *sysid, const XML_Char *pubid,
|
||||
int has_internal_subset) {
|
||||
(void)userData;
|
||||
TouchString(doctypeName);
|
||||
TouchString(sysid);
|
||||
TouchString(pubid);
|
||||
(void)has_internal_subset;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
EndDoctypeDeclHandler(void *userData) {
|
||||
(void)userData;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
EntityDeclHandler(void *userData, const XML_Char *entityName,
|
||||
int is_parameter_entity, const XML_Char *value,
|
||||
int value_length, const XML_Char *base,
|
||||
const XML_Char *systemId, const XML_Char *publicId,
|
||||
const XML_Char *notationName) {
|
||||
(void)userData;
|
||||
TouchString(entityName);
|
||||
(void)is_parameter_entity;
|
||||
TouchString(value, value_length);
|
||||
TouchString(base);
|
||||
TouchString(systemId);
|
||||
TouchString(publicId);
|
||||
TouchString(notationName);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
NotationDeclHandler(void *userData, const XML_Char *notationName,
|
||||
const XML_Char *base, const XML_Char *systemId,
|
||||
const XML_Char *publicId) {
|
||||
(void)userData;
|
||||
TouchString(notationName);
|
||||
TouchString(base);
|
||||
TouchString(systemId);
|
||||
TouchString(publicId);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
StartNamespaceDeclHandler(void *userData, const XML_Char *prefix,
|
||||
const XML_Char *uri) {
|
||||
(void)userData;
|
||||
TouchString(prefix);
|
||||
TouchString(uri);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
EndNamespaceDeclHandler(void *userData, const XML_Char *prefix) {
|
||||
(void)userData;
|
||||
TouchString(prefix);
|
||||
}
|
||||
|
||||
static int XMLCALL
|
||||
NotStandaloneHandler(void *userData) {
|
||||
(void)userData;
|
||||
return XML_STATUS_OK;
|
||||
}
|
||||
|
||||
static int XMLCALL
|
||||
ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context,
|
||||
const XML_Char *base, const XML_Char *systemId,
|
||||
const XML_Char *publicId) {
|
||||
int rc = XML_STATUS_ERROR;
|
||||
TouchString(context);
|
||||
TouchString(base);
|
||||
TouchString(systemId);
|
||||
TouchString(publicId);
|
||||
|
||||
if (g_external_entity) {
|
||||
XML_Parser ext_parser
|
||||
= XML_ExternalEntityParserCreate(parser, context, g_encoding);
|
||||
rc = Parse(ext_parser, g_external_entity, g_external_entity_size, 1);
|
||||
XML_ParserFree(ext_parser);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
SkippedEntityHandler(void *userData, const XML_Char *entityName,
|
||||
int is_parameter_entity) {
|
||||
(void)userData;
|
||||
TouchString(entityName);
|
||||
(void)is_parameter_entity;
|
||||
}
|
||||
|
||||
static int XMLCALL
|
||||
UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name,
|
||||
XML_Encoding *info) {
|
||||
(void)encodingHandlerData;
|
||||
TouchString(name);
|
||||
(void)info;
|
||||
return XML_STATUS_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
InitializeParser(XML_Parser parser) {
|
||||
XML_SetUserData(parser, (void *)parser);
|
||||
XML_SetHashSalt(parser, 0x41414141);
|
||||
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
|
||||
XML_SetElementDeclHandler(parser, ElementDeclHandler);
|
||||
XML_SetAttlistDeclHandler(parser, AttlistDeclHandler);
|
||||
XML_SetXmlDeclHandler(parser, XmlDeclHandler);
|
||||
XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
|
||||
XML_SetCharacterDataHandler(parser, CharacterDataHandler);
|
||||
XML_SetProcessingInstructionHandler(parser, ProcessingInstructionHandler);
|
||||
XML_SetCommentHandler(parser, CommentHandler);
|
||||
XML_SetCdataSectionHandler(parser, StartCdataSectionHandler,
|
||||
EndCdataSectionHandler);
|
||||
// XML_SetDefaultHandler disables entity expansion
|
||||
XML_SetDefaultHandlerExpand(parser, DefaultHandler);
|
||||
XML_SetDoctypeDeclHandler(parser, StartDoctypeDeclHandler,
|
||||
EndDoctypeDeclHandler);
|
||||
// Note: This is mutually exclusive with XML_SetUnparsedEntityDeclHandler,
|
||||
// and there isn't any significant code change between the two.
|
||||
XML_SetEntityDeclHandler(parser, EntityDeclHandler);
|
||||
XML_SetNotationDeclHandler(parser, NotationDeclHandler);
|
||||
XML_SetNamespaceDeclHandler(parser, StartNamespaceDeclHandler,
|
||||
EndNamespaceDeclHandler);
|
||||
XML_SetNotStandaloneHandler(parser, NotStandaloneHandler);
|
||||
XML_SetExternalEntityRefHandler(parser, ExternalEntityRefHandler);
|
||||
XML_SetSkippedEntityHandler(parser, SkippedEntityHandler);
|
||||
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, (void *)parser);
|
||||
}
|
||||
|
||||
DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase &testcase) {
|
||||
g_external_entity = nullptr;
|
||||
|
||||
if (! testcase.actions_size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_allocation_count = 0;
|
||||
g_fail_allocations.clear();
|
||||
for (int i = 0; i < testcase.fail_allocations_size(); ++i) {
|
||||
g_fail_allocations.push_back(testcase.fail_allocations(i));
|
||||
}
|
||||
|
||||
SetEncoding(testcase.encoding());
|
||||
XML_Parser parser
|
||||
= XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|");
|
||||
InitializeParser(parser);
|
||||
|
||||
for (int i = 0; i < testcase.actions_size(); ++i) {
|
||||
const auto &action = testcase.actions(i);
|
||||
switch (action.action_case()) {
|
||||
case xml_lpm_fuzzer::Action::kChunk:
|
||||
if (XML_STATUS_ERROR
|
||||
== Parse(parser, action.chunk().data(), action.chunk().size(), 0)) {
|
||||
// Force a reset after parse error.
|
||||
XML_ParserReset(parser, g_encoding);
|
||||
InitializeParser(parser);
|
||||
}
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Action::kLastChunk:
|
||||
Parse(parser, action.last_chunk().data(), action.last_chunk().size(), 1);
|
||||
XML_ParserReset(parser, g_encoding);
|
||||
InitializeParser(parser);
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Action::kReset:
|
||||
XML_ParserReset(parser, g_encoding);
|
||||
InitializeParser(parser);
|
||||
break;
|
||||
|
||||
case xml_lpm_fuzzer::Action::kExternalEntity:
|
||||
g_external_entity = action.external_entity().data();
|
||||
g_external_entity_size = action.external_entity().size();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
| __// \| |_) | (_| | |_
|
||||
\___/_/\_\ .__/ \__,_|\__|
|
||||
|_| XML parser
|
||||
|
||||
Copyright (c) 2022 Mark Brand <[email protected]>
|
||||
Copyright (c) 2025 Sebastian Pipping <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
package xml_lpm_fuzzer;
|
||||
|
||||
enum Encoding {
|
||||
UTF8 = 0;
|
||||
UTF16 = 1;
|
||||
ISO88591 = 2;
|
||||
ASCII = 3;
|
||||
UNKNOWN = 4;
|
||||
NONE = 5;
|
||||
}
|
||||
|
||||
message Action {
|
||||
oneof action {
|
||||
string chunk = 1;
|
||||
string last_chunk = 2;
|
||||
bool reset = 3;
|
||||
string external_entity = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message Testcase {
|
||||
required Encoding encoding = 1;
|
||||
repeated Action actions = 2;
|
||||
repeated int32 fail_allocations = 3;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
|
||||
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016 Cristian Rodríguez <crrodriguez@opensuse.org>
|
||||
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
|
||||
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
@@ -1067,8 +1067,8 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
|
||||
See https://semver.org
|
||||
*/
|
||||
#define XML_MAJOR_VERSION 2
|
||||
#define XML_MINOR_VERSION 6
|
||||
#define XML_MICRO_VERSION 4
|
||||
#define XML_MINOR_VERSION 7
|
||||
#define XML_MICRO_VERSION 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
|
||||
Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
|
||||
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
||||
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
@@ -127,6 +127,9 @@
|
||||
# elif ULONG_MAX == 18446744073709551615u // 2^64-1
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
|
||||
# elif defined(EMSCRIPTEN) // 32bit mode Emscripten
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu"
|
||||
# else
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
|
||||
|
||||
+428
-158
@@ -1,4 +1,4 @@
|
||||
/* c5625880f4bf417c1463deee4eb92d86ff413f802048621c57e25fe483eb59e4 (2.6.4+)
|
||||
/* d19ae032c224863c1527ba44d228cc34b99192c3a4c5a27af1f4e054d45ee031 (2.7.1+)
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
@@ -13,7 +13,7 @@
|
||||
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
|
||||
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
|
||||
Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
|
||||
@@ -39,7 +39,7 @@
|
||||
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
|
||||
Copyright (c) 2023 Owain Davies <owaind@bath.edu>
|
||||
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Copyright (c) 2024 Berkay Eren Ürün <berkay.ueruen@siemens.com>
|
||||
Copyright (c) 2024-2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
|
||||
Copyright (c) 2024 Hanno Böck <hanno@gentoo.org>
|
||||
Licensed under the MIT license:
|
||||
|
||||
@@ -325,6 +325,10 @@ typedef struct {
|
||||
const XML_Char *publicId;
|
||||
const XML_Char *notation;
|
||||
XML_Bool open;
|
||||
XML_Bool hasMore; /* true if entity has not been completely processed */
|
||||
/* An entity can be open while being already completely processed (hasMore ==
|
||||
XML_FALSE). The reason is the delayed closing of entities until their inner
|
||||
entities are processed and closed */
|
||||
XML_Bool is_param;
|
||||
XML_Bool is_internal; /* true if declared in internal subset outside PE */
|
||||
} ENTITY;
|
||||
@@ -415,6 +419,12 @@ typedef struct {
|
||||
int *scaffIndex;
|
||||
} DTD;
|
||||
|
||||
enum EntityType {
|
||||
ENTITY_INTERNAL,
|
||||
ENTITY_ATTRIBUTE,
|
||||
ENTITY_VALUE,
|
||||
};
|
||||
|
||||
typedef struct open_internal_entity {
|
||||
const char *internalEventPtr;
|
||||
const char *internalEventEndPtr;
|
||||
@@ -422,6 +432,7 @@ typedef struct open_internal_entity {
|
||||
ENTITY *entity;
|
||||
int startTagLevel;
|
||||
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
|
||||
enum EntityType type;
|
||||
} OPEN_INTERNAL_ENTITY;
|
||||
|
||||
enum XML_Account {
|
||||
@@ -481,8 +492,8 @@ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
|
||||
const char *next, const char **nextPtr,
|
||||
XML_Bool haveMore, XML_Bool allowClosingDoctype,
|
||||
enum XML_Account account);
|
||||
static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
|
||||
XML_Bool betweenDecl);
|
||||
static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity,
|
||||
XML_Bool betweenDecl, enum EntityType type);
|
||||
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
|
||||
const ENCODING *enc, const char *start,
|
||||
const char *end, const char **endPtr,
|
||||
@@ -513,18 +524,22 @@ static enum XML_Error storeAttributeValue(XML_Parser parser,
|
||||
const char *ptr, const char *end,
|
||||
STRING_POOL *pool,
|
||||
enum XML_Account account);
|
||||
static enum XML_Error appendAttributeValue(XML_Parser parser,
|
||||
const ENCODING *enc,
|
||||
XML_Bool isCdata, const char *ptr,
|
||||
const char *end, STRING_POOL *pool,
|
||||
enum XML_Account account);
|
||||
static enum XML_Error
|
||||
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
const char *ptr, const char *end, STRING_POOL *pool,
|
||||
enum XML_Account account, const char **nextPtr);
|
||||
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
|
||||
const char *start, const char *end);
|
||||
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType);
|
||||
#if XML_GE == 1
|
||||
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
const char *start, const char *end,
|
||||
enum XML_Account account);
|
||||
enum XML_Account account,
|
||||
const char **nextPtr);
|
||||
static enum XML_Error callStoreEntityValue(XML_Parser parser,
|
||||
const ENCODING *enc,
|
||||
const char *start, const char *end,
|
||||
enum XML_Account account);
|
||||
#else
|
||||
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
|
||||
#endif
|
||||
@@ -709,6 +724,10 @@ struct XML_ParserStruct {
|
||||
const char *m_positionPtr;
|
||||
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
|
||||
OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
|
||||
OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
|
||||
OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
|
||||
OPEN_INTERNAL_ENTITY *m_openValueEntities;
|
||||
OPEN_INTERNAL_ENTITY *m_freeValueEntities;
|
||||
XML_Bool m_defaultExpandInternalEntities;
|
||||
int m_tagLevel;
|
||||
ENTITY *m_declEntity;
|
||||
@@ -756,6 +775,7 @@ struct XML_ParserStruct {
|
||||
ACCOUNTING m_accounting;
|
||||
ENTITY_STATS m_entity_stats;
|
||||
#endif
|
||||
XML_Bool m_reenter;
|
||||
};
|
||||
|
||||
#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
|
||||
@@ -1028,7 +1048,29 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
#if defined(XML_TESTING)
|
||||
g_bytesScanned += (unsigned)have_now;
|
||||
#endif
|
||||
const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
|
||||
// Run in a loop to eliminate dangerous recursion depths
|
||||
enum XML_Error ret;
|
||||
*endPtr = start;
|
||||
while (1) {
|
||||
// Use endPtr as the new start in each iteration, since it will
|
||||
// be set to the next start point by m_processor.
|
||||
ret = parser->m_processor(parser, *endPtr, end, endPtr);
|
||||
|
||||
// Make parsing status (and in particular XML_SUSPENDED) take
|
||||
// precedence over re-enter flag when they disagree
|
||||
if (parser->m_parsingStatus.parsing != XML_PARSING) {
|
||||
parser->m_reenter = XML_FALSE;
|
||||
}
|
||||
|
||||
if (! parser->m_reenter) {
|
||||
break;
|
||||
}
|
||||
|
||||
parser->m_reenter = XML_FALSE;
|
||||
if (ret != XML_ERROR_NONE)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == XML_ERROR_NONE) {
|
||||
// if we consumed nothing, remember what we had on this parse attempt.
|
||||
if (*endPtr == start) {
|
||||
@@ -1139,6 +1181,8 @@ parserCreate(const XML_Char *encodingName,
|
||||
parser->m_freeBindingList = NULL;
|
||||
parser->m_freeTagList = NULL;
|
||||
parser->m_freeInternalEntities = NULL;
|
||||
parser->m_freeAttributeEntities = NULL;
|
||||
parser->m_freeValueEntities = NULL;
|
||||
|
||||
parser->m_groupSize = 0;
|
||||
parser->m_groupConnector = NULL;
|
||||
@@ -1241,6 +1285,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
|
||||
parser->m_eventEndPtr = NULL;
|
||||
parser->m_positionPtr = NULL;
|
||||
parser->m_openInternalEntities = NULL;
|
||||
parser->m_openAttributeEntities = NULL;
|
||||
parser->m_openValueEntities = NULL;
|
||||
parser->m_defaultExpandInternalEntities = XML_TRUE;
|
||||
parser->m_tagLevel = 0;
|
||||
parser->m_tagStack = NULL;
|
||||
@@ -1251,6 +1297,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
|
||||
parser->m_unknownEncodingData = NULL;
|
||||
parser->m_parentParser = NULL;
|
||||
parser->m_parsingStatus.parsing = XML_INITIALIZED;
|
||||
// Reentry can only be triggered inside m_processor calls
|
||||
parser->m_reenter = XML_FALSE;
|
||||
#ifdef XML_DTD
|
||||
parser->m_isParamEntity = XML_FALSE;
|
||||
parser->m_useForeignDTD = XML_FALSE;
|
||||
@@ -1310,6 +1358,24 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
|
||||
openEntity->next = parser->m_freeInternalEntities;
|
||||
parser->m_freeInternalEntities = openEntity;
|
||||
}
|
||||
/* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
|
||||
* for attributes) */
|
||||
openEntityList = parser->m_openAttributeEntities;
|
||||
while (openEntityList) {
|
||||
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
|
||||
openEntityList = openEntity->next;
|
||||
openEntity->next = parser->m_freeAttributeEntities;
|
||||
parser->m_freeAttributeEntities = openEntity;
|
||||
}
|
||||
/* move m_openValueEntities to m_freeValueEntities (i.e. same task but
|
||||
* for value entities) */
|
||||
openEntityList = parser->m_openValueEntities;
|
||||
while (openEntityList) {
|
||||
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
|
||||
openEntityList = openEntity->next;
|
||||
openEntity->next = parser->m_freeValueEntities;
|
||||
parser->m_freeValueEntities = openEntity;
|
||||
}
|
||||
moveToFreeBindingList(parser, parser->m_inheritedBindings);
|
||||
FREE(parser, parser->m_unknownEncodingMem);
|
||||
if (parser->m_unknownEncodingRelease)
|
||||
@@ -1323,6 +1389,19 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
|
||||
return XML_TRUE;
|
||||
}
|
||||
|
||||
static XML_Bool
|
||||
parserBusy(XML_Parser parser) {
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_PARSING:
|
||||
case XML_SUSPENDED:
|
||||
return XML_TRUE;
|
||||
case XML_INITIALIZED:
|
||||
case XML_FINISHED:
|
||||
default:
|
||||
return XML_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
enum XML_Status XMLCALL
|
||||
XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
|
||||
if (parser == NULL)
|
||||
@@ -1331,8 +1410,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
|
||||
XXX There's no way for the caller to determine which of the
|
||||
XXX possible error cases caused the XML_STATUS_ERROR return.
|
||||
*/
|
||||
if (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parserBusy(parser))
|
||||
return XML_STATUS_ERROR;
|
||||
|
||||
/* Get rid of any previous encoding name */
|
||||
@@ -1569,7 +1647,34 @@ XML_ParserFree(XML_Parser parser) {
|
||||
entityList = entityList->next;
|
||||
FREE(parser, openEntity);
|
||||
}
|
||||
|
||||
/* free m_openAttributeEntities and m_freeAttributeEntities */
|
||||
entityList = parser->m_openAttributeEntities;
|
||||
for (;;) {
|
||||
OPEN_INTERNAL_ENTITY *openEntity;
|
||||
if (entityList == NULL) {
|
||||
if (parser->m_freeAttributeEntities == NULL)
|
||||
break;
|
||||
entityList = parser->m_freeAttributeEntities;
|
||||
parser->m_freeAttributeEntities = NULL;
|
||||
}
|
||||
openEntity = entityList;
|
||||
entityList = entityList->next;
|
||||
FREE(parser, openEntity);
|
||||
}
|
||||
/* free m_openValueEntities and m_freeValueEntities */
|
||||
entityList = parser->m_openValueEntities;
|
||||
for (;;) {
|
||||
OPEN_INTERNAL_ENTITY *openEntity;
|
||||
if (entityList == NULL) {
|
||||
if (parser->m_freeValueEntities == NULL)
|
||||
break;
|
||||
entityList = parser->m_freeValueEntities;
|
||||
parser->m_freeValueEntities = NULL;
|
||||
}
|
||||
openEntity = entityList;
|
||||
entityList = entityList->next;
|
||||
FREE(parser, openEntity);
|
||||
}
|
||||
destroyBindings(parser->m_freeBindingList, parser);
|
||||
destroyBindings(parser->m_inheritedBindings, parser);
|
||||
poolDestroy(&parser->m_tempPool);
|
||||
@@ -1611,8 +1716,7 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) {
|
||||
return XML_ERROR_INVALID_ARGUMENT;
|
||||
#ifdef XML_DTD
|
||||
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||
if (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parserBusy(parser))
|
||||
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
|
||||
parser->m_useForeignDTD = useDTD;
|
||||
return XML_ERROR_NONE;
|
||||
@@ -1627,8 +1731,7 @@ XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) {
|
||||
if (parser == NULL)
|
||||
return;
|
||||
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||
if (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parserBusy(parser))
|
||||
return;
|
||||
parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
|
||||
}
|
||||
@@ -1897,8 +2000,7 @@ XML_SetParamEntityParsing(XML_Parser parser,
|
||||
if (parser == NULL)
|
||||
return 0;
|
||||
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||
if (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parserBusy(parser))
|
||||
return 0;
|
||||
#ifdef XML_DTD
|
||||
parser->m_paramEntityParsing = peParsing;
|
||||
@@ -1915,8 +2017,7 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
|
||||
if (parser->m_parentParser)
|
||||
return XML_SetHashSalt(parser->m_parentParser, hash_salt);
|
||||
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||
if (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parserBusy(parser))
|
||||
return 0;
|
||||
parser->m_hash_secret_salt = hash_salt;
|
||||
return 1;
|
||||
@@ -2230,6 +2331,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
||||
return parser->m_bufferEnd;
|
||||
}
|
||||
|
||||
static void
|
||||
triggerReenter(XML_Parser parser) {
|
||||
parser->m_reenter = XML_TRUE;
|
||||
}
|
||||
|
||||
enum XML_Status XMLCALL
|
||||
XML_StopParser(XML_Parser parser, XML_Bool resumable) {
|
||||
if (parser == NULL)
|
||||
@@ -2704,8 +2810,9 @@ static enum XML_Error PTRCALL
|
||||
contentProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
const char **endPtr) {
|
||||
enum XML_Error result = doContent(
|
||||
parser, 0, parser->m_encoding, start, end, endPtr,
|
||||
(XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
|
||||
parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, start, end,
|
||||
endPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
||||
XML_ACCOUNT_DIRECT);
|
||||
if (result == XML_ERROR_NONE) {
|
||||
if (! storeRawNames(parser))
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
@@ -2793,6 +2900,11 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
start = next;
|
||||
}
|
||||
@@ -2966,7 +3078,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
reportDefault(parser, enc, s, next);
|
||||
break;
|
||||
}
|
||||
result = processInternalEntity(parser, entity, XML_FALSE);
|
||||
result = processEntity(parser, entity, XML_FALSE, ENTITY_INTERNAL);
|
||||
if (result != XML_ERROR_NONE)
|
||||
return result;
|
||||
} else if (parser->m_externalEntityRefHandler) {
|
||||
@@ -3092,7 +3204,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
}
|
||||
if ((parser->m_tagLevel == 0)
|
||||
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
|
||||
if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parser->m_parsingStatus.parsing == XML_SUSPENDED
|
||||
|| (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
&& parser->m_reenter))
|
||||
parser->m_processor = epilogProcessor;
|
||||
else
|
||||
return epilogProcessor(parser, next, end, nextPtr);
|
||||
@@ -3153,7 +3267,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
}
|
||||
if ((parser->m_tagLevel == 0)
|
||||
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
|
||||
if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
|
||||
if (parser->m_parsingStatus.parsing == XML_SUSPENDED
|
||||
|| (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
&& parser->m_reenter))
|
||||
parser->m_processor = epilogProcessor;
|
||||
else
|
||||
return epilogProcessor(parser, next, end, nextPtr);
|
||||
@@ -3286,14 +3402,22 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
break;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
*eventPP = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
*eventPP = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
*eventPP = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
*eventPP = s = next;
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
@@ -4210,14 +4334,21 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
*eventPP = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
*eventPP = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
*eventPP = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
*eventPP = s = next;
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
@@ -4549,7 +4680,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
}
|
||||
/* found end of entity value - can store it now */
|
||||
return storeEntityValue(parser, parser->m_encoding, s, end,
|
||||
XML_ACCOUNT_DIRECT);
|
||||
XML_ACCOUNT_DIRECT, NULL);
|
||||
} else if (tok == XML_TOK_XML_DECL) {
|
||||
enum XML_Error result;
|
||||
result = processXmlDecl(parser, 0, start, next);
|
||||
@@ -4676,7 +4807,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
break;
|
||||
}
|
||||
/* found end of entity value - can store it now */
|
||||
return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
|
||||
return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT, NULL);
|
||||
}
|
||||
start = next;
|
||||
}
|
||||
@@ -5119,9 +5250,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
||||
#if XML_GE == 1
|
||||
// This will store the given replacement text in
|
||||
// parser->m_declEntity->textPtr.
|
||||
enum XML_Error result
|
||||
= storeEntityValue(parser, enc, s + enc->minBytesPerChar,
|
||||
next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
|
||||
enum XML_Error result = callStoreEntityValue(
|
||||
parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar,
|
||||
XML_ACCOUNT_NONE);
|
||||
if (parser->m_declEntity) {
|
||||
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
|
||||
parser->m_declEntity->textLen
|
||||
@@ -5546,7 +5677,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
||||
enum XML_Error result;
|
||||
XML_Bool betweenDecl
|
||||
= (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
|
||||
result = processInternalEntity(parser, entity, betweenDecl);
|
||||
result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL);
|
||||
if (result != XML_ERROR_NONE)
|
||||
return result;
|
||||
handleDefault = XML_FALSE;
|
||||
@@ -5751,6 +5882,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
s = next;
|
||||
tok = XmlPrologTok(enc, s, end, &next);
|
||||
@@ -5818,28 +5955,58 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
default:
|
||||
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
|
||||
}
|
||||
parser->m_eventPtr = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
parser->m_eventPtr = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
parser->m_eventPtr = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
parser->m_eventPtr = s = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static enum XML_Error
|
||||
processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
||||
const char *textStart, *textEnd;
|
||||
const char *next;
|
||||
enum XML_Error result;
|
||||
OPEN_INTERNAL_ENTITY *openEntity;
|
||||
processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
|
||||
enum EntityType type) {
|
||||
OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList;
|
||||
switch (type) {
|
||||
case ENTITY_INTERNAL:
|
||||
parser->m_processor = internalEntityProcessor;
|
||||
openEntityList = &parser->m_openInternalEntities;
|
||||
freeEntityList = &parser->m_freeInternalEntities;
|
||||
break;
|
||||
case ENTITY_ATTRIBUTE:
|
||||
openEntityList = &parser->m_openAttributeEntities;
|
||||
freeEntityList = &parser->m_freeAttributeEntities;
|
||||
break;
|
||||
case ENTITY_VALUE:
|
||||
openEntityList = &parser->m_openValueEntities;
|
||||
freeEntityList = &parser->m_freeValueEntities;
|
||||
break;
|
||||
/* default case serves merely as a safety net in case of a
|
||||
* wrong entityType. Therefore we exclude the following lines
|
||||
* from the test coverage.
|
||||
*
|
||||
* LCOV_EXCL_START
|
||||
*/
|
||||
default:
|
||||
// Should not reach here
|
||||
assert(0);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (parser->m_freeInternalEntities) {
|
||||
openEntity = parser->m_freeInternalEntities;
|
||||
parser->m_freeInternalEntities = openEntity->next;
|
||||
if (*freeEntityList) {
|
||||
openEntity = *freeEntityList;
|
||||
*freeEntityList = openEntity->next;
|
||||
} else {
|
||||
openEntity
|
||||
= (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
|
||||
@@ -5847,55 +6014,34 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
entity->open = XML_TRUE;
|
||||
entity->hasMore = XML_TRUE;
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
#endif
|
||||
entity->processed = 0;
|
||||
openEntity->next = parser->m_openInternalEntities;
|
||||
parser->m_openInternalEntities = openEntity;
|
||||
openEntity->next = *openEntityList;
|
||||
*openEntityList = openEntity;
|
||||
openEntity->entity = entity;
|
||||
openEntity->type = type;
|
||||
openEntity->startTagLevel = parser->m_tagLevel;
|
||||
openEntity->betweenDecl = betweenDecl;
|
||||
openEntity->internalEventPtr = NULL;
|
||||
openEntity->internalEventEndPtr = NULL;
|
||||
textStart = (const char *)entity->textPtr;
|
||||
textEnd = (const char *)(entity->textPtr + entity->textLen);
|
||||
/* Set a safe default value in case 'next' does not get set */
|
||||
next = textStart;
|
||||
|
||||
if (entity->is_param) {
|
||||
int tok
|
||||
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
|
||||
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
|
||||
tok, next, &next, XML_FALSE, XML_FALSE,
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
} else {
|
||||
result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
|
||||
textStart, textEnd, &next, XML_FALSE,
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
// Only internal entities make use of the reenter flag
|
||||
// therefore no need to set it for other entity types
|
||||
if (type == ENTITY_INTERNAL) {
|
||||
triggerReenter(parser);
|
||||
}
|
||||
|
||||
if (result == XML_ERROR_NONE) {
|
||||
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
||||
entity->processed = (int)(next - textStart);
|
||||
parser->m_processor = internalEntityProcessor;
|
||||
} else if (parser->m_openInternalEntities->entity == entity) {
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
#endif /* XML_GE == 1 */
|
||||
entity->open = XML_FALSE;
|
||||
parser->m_openInternalEntities = openEntity->next;
|
||||
/* put openEntity back in list of free instances */
|
||||
openEntity->next = parser->m_freeInternalEntities;
|
||||
parser->m_freeInternalEntities = openEntity;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
|
||||
static enum XML_Error PTRCALL
|
||||
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
const char **nextPtr) {
|
||||
UNUSED_P(s);
|
||||
UNUSED_P(end);
|
||||
UNUSED_P(nextPtr);
|
||||
ENTITY *entity;
|
||||
const char *textStart, *textEnd;
|
||||
const char *next;
|
||||
@@ -5905,68 +6051,67 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
return XML_ERROR_UNEXPECTED_STATE;
|
||||
|
||||
entity = openEntity->entity;
|
||||
textStart = ((const char *)entity->textPtr) + entity->processed;
|
||||
textEnd = (const char *)(entity->textPtr + entity->textLen);
|
||||
/* Set a safe default value in case 'next' does not get set */
|
||||
next = textStart;
|
||||
|
||||
if (entity->is_param) {
|
||||
int tok
|
||||
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
|
||||
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
|
||||
tok, next, &next, XML_FALSE, XML_TRUE,
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
} else {
|
||||
result = doContent(parser, openEntity->startTagLevel,
|
||||
parser->m_internalEncoding, textStart, textEnd, &next,
|
||||
XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
}
|
||||
// This will return early
|
||||
if (entity->hasMore) {
|
||||
textStart = ((const char *)entity->textPtr) + entity->processed;
|
||||
textEnd = (const char *)(entity->textPtr + entity->textLen);
|
||||
/* Set a safe default value in case 'next' does not get set */
|
||||
next = textStart;
|
||||
|
||||
if (result != XML_ERROR_NONE)
|
||||
if (entity->is_param) {
|
||||
int tok
|
||||
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
|
||||
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
|
||||
tok, next, &next, XML_FALSE, XML_FALSE,
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
} else {
|
||||
result = doContent(parser, openEntity->startTagLevel,
|
||||
parser->m_internalEncoding, textStart, textEnd, &next,
|
||||
XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
}
|
||||
|
||||
if (result != XML_ERROR_NONE)
|
||||
return result;
|
||||
// Check if entity is complete, if not, mark down how much of it is
|
||||
// processed
|
||||
if (textEnd != next
|
||||
&& (parser->m_parsingStatus.parsing == XML_SUSPENDED
|
||||
|| (parser->m_parsingStatus.parsing == XML_PARSING
|
||||
&& parser->m_reenter))) {
|
||||
entity->processed = (int)(next - (const char *)entity->textPtr);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Entity is complete. We cannot close it here since we need to first
|
||||
// process its possible inner entities (which are added to the
|
||||
// m_openInternalEntities during doProlog or doContent calls above)
|
||||
entity->hasMore = XML_FALSE;
|
||||
triggerReenter(parser);
|
||||
return result;
|
||||
} // End of entity processing, "if" block will return here
|
||||
|
||||
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
||||
entity->processed = (int)(next - (const char *)entity->textPtr);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Remove fully processed openEntity from open entity list.
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
#endif
|
||||
// openEntity is m_openInternalEntities' head, as we set it at the start of
|
||||
// this function and we skipped doProlog and doContent calls with hasMore set
|
||||
// to false. This means we can directly remove the head of
|
||||
// m_openInternalEntities
|
||||
assert(parser->m_openInternalEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
parser->m_openInternalEntities = openEntity->next;
|
||||
parser->m_openInternalEntities = parser->m_openInternalEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
openEntity->next = parser->m_freeInternalEntities;
|
||||
parser->m_freeInternalEntities = openEntity;
|
||||
|
||||
// If there are more open entities we want to stop right here and have the
|
||||
// upcoming call to XML_ResumeParser continue with entity content, or it would
|
||||
// be ignored altogether.
|
||||
if (parser->m_openInternalEntities != NULL
|
||||
&& parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
|
||||
if (entity->is_param) {
|
||||
int tok;
|
||||
parser->m_processor = prologProcessor;
|
||||
tok = XmlPrologTok(parser->m_encoding, s, end, &next);
|
||||
return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
|
||||
(XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
|
||||
XML_ACCOUNT_DIRECT);
|
||||
} else {
|
||||
parser->m_processor = contentProcessor;
|
||||
/* see externalEntityContentProcessor vs contentProcessor */
|
||||
result = doContent(parser, parser->m_parentParser ? 1 : 0,
|
||||
parser->m_encoding, s, end, nextPtr,
|
||||
(XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
||||
XML_ACCOUNT_DIRECT);
|
||||
if (result == XML_ERROR_NONE) {
|
||||
if (! storeRawNames(parser))
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
return result;
|
||||
if (parser->m_openInternalEntities == NULL) {
|
||||
parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
|
||||
}
|
||||
triggerReenter(parser);
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
|
||||
static enum XML_Error PTRCALL
|
||||
@@ -5982,8 +6127,70 @@ static enum XML_Error
|
||||
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
const char *ptr, const char *end, STRING_POOL *pool,
|
||||
enum XML_Account account) {
|
||||
enum XML_Error result
|
||||
= appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
|
||||
const char *next = ptr;
|
||||
enum XML_Error result = XML_ERROR_NONE;
|
||||
|
||||
while (1) {
|
||||
if (! parser->m_openAttributeEntities) {
|
||||
result = appendAttributeValue(parser, enc, isCdata, next, end, pool,
|
||||
account, &next);
|
||||
} else {
|
||||
OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openAttributeEntities;
|
||||
if (! openEntity)
|
||||
return XML_ERROR_UNEXPECTED_STATE;
|
||||
|
||||
ENTITY *const entity = openEntity->entity;
|
||||
const char *const textStart
|
||||
= ((const char *)entity->textPtr) + entity->processed;
|
||||
const char *const textEnd
|
||||
= (const char *)(entity->textPtr + entity->textLen);
|
||||
/* Set a safe default value in case 'next' does not get set */
|
||||
const char *nextInEntity = textStart;
|
||||
if (entity->hasMore) {
|
||||
result = appendAttributeValue(
|
||||
parser, parser->m_internalEncoding, isCdata, textStart, textEnd,
|
||||
pool, XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
|
||||
if (result != XML_ERROR_NONE)
|
||||
break;
|
||||
// Check if entity is complete, if not, mark down how much of it is
|
||||
// processed. A XML_SUSPENDED check here is not required as
|
||||
// appendAttributeValue will never suspend the parser.
|
||||
if (textEnd != nextInEntity) {
|
||||
entity->processed
|
||||
= (int)(nextInEntity - (const char *)entity->textPtr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Entity is complete. We cannot close it here since we need to first
|
||||
// process its possible inner entities (which are added to the
|
||||
// m_openAttributeEntities during appendAttributeValue)
|
||||
entity->hasMore = XML_FALSE;
|
||||
continue;
|
||||
} // End of entity processing, "if" block skips the rest
|
||||
|
||||
// Remove fully processed openEntity from open entity list.
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
#endif
|
||||
// openEntity is m_openAttributeEntities' head, since we set it at the
|
||||
// start of this function and because we skipped appendAttributeValue call
|
||||
// with hasMore set to false. This means we can directly remove the head
|
||||
// of m_openAttributeEntities
|
||||
assert(parser->m_openAttributeEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
openEntity->next = parser->m_freeAttributeEntities;
|
||||
parser->m_freeAttributeEntities = openEntity;
|
||||
}
|
||||
|
||||
// Break if an error occurred or there is nothing left to process
|
||||
if (result || (parser->m_openAttributeEntities == NULL && end == next)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
|
||||
@@ -5996,7 +6203,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
static enum XML_Error
|
||||
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
const char *ptr, const char *end, STRING_POOL *pool,
|
||||
enum XML_Account account) {
|
||||
enum XML_Account account, const char **nextPtr) {
|
||||
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
||||
#ifndef XML_DTD
|
||||
UNUSED_P(account);
|
||||
@@ -6014,6 +6221,9 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
#endif
|
||||
switch (tok) {
|
||||
case XML_TOK_NONE:
|
||||
if (nextPtr) {
|
||||
*nextPtr = next;
|
||||
}
|
||||
return XML_ERROR_NONE;
|
||||
case XML_TOK_INVALID:
|
||||
if (enc == parser->m_encoding)
|
||||
@@ -6154,21 +6364,11 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
|
||||
} else {
|
||||
enum XML_Error result;
|
||||
const XML_Char *textEnd = entity->textPtr + entity->textLen;
|
||||
entity->open = XML_TRUE;
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
#endif
|
||||
result = appendAttributeValue(parser, parser->m_internalEncoding,
|
||||
isCdata, (const char *)entity->textPtr,
|
||||
(const char *)textEnd, pool,
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
#endif
|
||||
entity->open = XML_FALSE;
|
||||
if (result)
|
||||
return result;
|
||||
result = processEntity(parser, entity, XML_FALSE, ENTITY_ATTRIBUTE);
|
||||
if ((result == XML_ERROR_NONE) && (nextPtr != NULL)) {
|
||||
*nextPtr = next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
@@ -6197,7 +6397,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
static enum XML_Error
|
||||
storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
const char *entityTextPtr, const char *entityTextEnd,
|
||||
enum XML_Account account) {
|
||||
enum XML_Account account, const char **nextPtr) {
|
||||
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
||||
STRING_POOL *pool = &(dtd->entityValuePool);
|
||||
enum XML_Error result = XML_ERROR_NONE;
|
||||
@@ -6215,8 +6415,9 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
const char *next;
|
||||
for (;;) {
|
||||
const char *next
|
||||
next
|
||||
= entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
|
||||
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
|
||||
|
||||
@@ -6278,16 +6479,8 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
} else
|
||||
dtd->keepProcessing = dtd->standalone;
|
||||
} else {
|
||||
entity->open = XML_TRUE;
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
result = storeEntityValue(
|
||||
parser, parser->m_internalEncoding, (const char *)entity->textPtr,
|
||||
(const char *)(entity->textPtr + entity->textLen),
|
||||
XML_ACCOUNT_ENTITY_EXPANSION);
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
entity->open = XML_FALSE;
|
||||
if (result)
|
||||
goto endEntityValue;
|
||||
result = processEntity(parser, entity, XML_FALSE, ENTITY_VALUE);
|
||||
goto endEntityValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -6375,6 +6568,81 @@ endEntityValue:
|
||||
# ifdef XML_DTD
|
||||
parser->m_prologState.inEntityValue = oldInEntityValue;
|
||||
# endif /* XML_DTD */
|
||||
// If 'nextPtr' is given, it should be updated during the processing
|
||||
if (nextPtr != NULL) {
|
||||
*nextPtr = next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum XML_Error
|
||||
callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
const char *entityTextPtr, const char *entityTextEnd,
|
||||
enum XML_Account account) {
|
||||
const char *next = entityTextPtr;
|
||||
enum XML_Error result = XML_ERROR_NONE;
|
||||
while (1) {
|
||||
if (! parser->m_openValueEntities) {
|
||||
result
|
||||
= storeEntityValue(parser, enc, next, entityTextEnd, account, &next);
|
||||
} else {
|
||||
OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openValueEntities;
|
||||
if (! openEntity)
|
||||
return XML_ERROR_UNEXPECTED_STATE;
|
||||
|
||||
ENTITY *const entity = openEntity->entity;
|
||||
const char *const textStart
|
||||
= ((const char *)entity->textPtr) + entity->processed;
|
||||
const char *const textEnd
|
||||
= (const char *)(entity->textPtr + entity->textLen);
|
||||
/* Set a safe default value in case 'next' does not get set */
|
||||
const char *nextInEntity = textStart;
|
||||
if (entity->hasMore) {
|
||||
result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
|
||||
textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
|
||||
&nextInEntity);
|
||||
if (result != XML_ERROR_NONE)
|
||||
break;
|
||||
// Check if entity is complete, if not, mark down how much of it is
|
||||
// processed. A XML_SUSPENDED check here is not required as
|
||||
// appendAttributeValue will never suspend the parser.
|
||||
if (textEnd != nextInEntity) {
|
||||
entity->processed
|
||||
= (int)(nextInEntity - (const char *)entity->textPtr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Entity is complete. We cannot close it here since we need to first
|
||||
// process its possible inner entities (which are added to the
|
||||
// m_openValueEntities during storeEntityValue)
|
||||
entity->hasMore = XML_FALSE;
|
||||
continue;
|
||||
} // End of entity processing, "if" block skips the rest
|
||||
|
||||
// Remove fully processed openEntity from open entity list.
|
||||
# if XML_GE == 1
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
# endif
|
||||
// openEntity is m_openValueEntities' head, since we set it at the
|
||||
// start of this function and because we skipped storeEntityValue call
|
||||
// with hasMore set to false. This means we can directly remove the head
|
||||
// of m_openValueEntities
|
||||
assert(parser->m_openValueEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
parser->m_openValueEntities = parser->m_openValueEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
openEntity->next = parser->m_freeValueEntities;
|
||||
parser->m_freeValueEntities = openEntity;
|
||||
}
|
||||
|
||||
// Break if an error occurred or there is nothing left to process
|
||||
if (result
|
||||
|| (parser->m_openValueEntities == NULL && entityTextEnd == next)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -7983,7 +8251,7 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
|
||||
(void *)rootParser, rootParser->m_entity_stats.countEverOpened,
|
||||
rootParser->m_entity_stats.currentDepth,
|
||||
rootParser->m_entity_stats.maximumDepthSeen,
|
||||
(rootParser->m_entity_stats.currentDepth - 1) * 2, "",
|
||||
((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "",
|
||||
entity->is_param ? "%" : "&", entityName, action, entity->textLen,
|
||||
sourceLine);
|
||||
}
|
||||
@@ -8542,11 +8810,13 @@ unsignedCharToPrintable(unsigned char c) {
|
||||
return "\\xFE";
|
||||
case 255:
|
||||
return "\\xFF";
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
assert(0); /* never gets here */
|
||||
return "dead code";
|
||||
}
|
||||
assert(0); /* never gets here */
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
#endif /* XML_GE == 1 */
|
||||
|
||||
@@ -360,13 +360,16 @@ END_TEST
|
||||
START_TEST(test_helper_unsigned_char_to_printable) {
|
||||
// Smoke test
|
||||
unsigned char uc = 0;
|
||||
for (; uc < (unsigned char)-1; uc++) {
|
||||
for (;; uc++) {
|
||||
set_subtest("char %u", (unsigned)uc);
|
||||
const char *const printable = unsignedCharToPrintable(uc);
|
||||
if (printable == NULL)
|
||||
fail("unsignedCharToPrintable returned NULL");
|
||||
else if (strlen(printable) < (size_t)1)
|
||||
fail("unsignedCharToPrintable returned empty string");
|
||||
if (uc == (unsigned char)-1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Two concrete samples
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
|
||||
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
||||
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Copyright (c) 2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -450,6 +451,31 @@ START_TEST(test_alloc_internal_entity) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_alloc_parameter_entity) {
|
||||
const char *text = "<!DOCTYPE foo ["
|
||||
"<!ENTITY % param1 \"<!ENTITY internal 'some_text'>\">"
|
||||
"%param1;"
|
||||
"]> <foo>&internal;content</foo>";
|
||||
int i;
|
||||
const int alloc_test_max_repeats = 30;
|
||||
|
||||
for (i = 0; i < alloc_test_max_repeats; i++) {
|
||||
g_allocation_count = i;
|
||||
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
!= XML_STATUS_ERROR)
|
||||
break;
|
||||
alloc_teardown();
|
||||
alloc_setup();
|
||||
}
|
||||
g_allocation_count = -1;
|
||||
if (i == 0)
|
||||
fail("Parameter entity processed despite duff allocator");
|
||||
if (i == alloc_test_max_repeats)
|
||||
fail("Parameter entity not processed at max allocation count");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Test the robustness against allocation failure of element handling
|
||||
* Based on test_dtd_default_handling().
|
||||
*/
|
||||
@@ -2079,6 +2105,7 @@ make_alloc_test_case(Suite *s) {
|
||||
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_external_entity);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_ext_entity_set_encoding);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_internal_entity);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_parameter_entity);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
|
||||
tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
|
||||
tcase_add_test(tc_alloc, test_alloc_set_base);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
|
||||
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
|
||||
@@ -19,6 +19,7 @@
|
||||
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
|
||||
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
||||
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Copyright (c) 2024-2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -1191,6 +1192,22 @@ START_TEST(test_not_standalone_handler_accept) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_entity_start_tag_level_greater_than_one) {
|
||||
const char *const text = "<!DOCTYPE t1 [\n"
|
||||
" <!ENTITY e1 'hello'>\n"
|
||||
"]>\n"
|
||||
"<t1>\n"
|
||||
" <t2>&e1;</t2>\n"
|
||||
"</t1>\n";
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text),
|
||||
/*isFinal*/ XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_wfc_no_recursive_entity_refs) {
|
||||
const char *text = "<!DOCTYPE doc [\n"
|
||||
" <!ENTITY entity '&entity;'>\n"
|
||||
@@ -1202,6 +1219,93 @@ START_TEST(test_wfc_no_recursive_entity_refs) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_indirectly_recursive_entity_refs) {
|
||||
struct TestCase {
|
||||
const char *doc;
|
||||
bool usesParameterEntities;
|
||||
};
|
||||
|
||||
const struct TestCase cases[] = {
|
||||
// general entity + character data
|
||||
{"<!DOCTYPE a [\n"
|
||||
" <!ENTITY e1 '&e2;'>\n"
|
||||
" <!ENTITY e2 '&e1;'>\n"
|
||||
"]><a>&e2;</a>\n",
|
||||
false},
|
||||
|
||||
// general entity + attribute value
|
||||
{"<!DOCTYPE a [\n"
|
||||
" <!ENTITY e1 '&e2;'>\n"
|
||||
" <!ENTITY e2 '&e1;'>\n"
|
||||
"]><a k1='&e2;' />\n",
|
||||
false},
|
||||
|
||||
// parameter entity
|
||||
{"<!DOCTYPE doc [\n"
|
||||
" <!ENTITY % p1 '%p2;'>\n"
|
||||
" <!ENTITY % p2 '%p1;'>\n"
|
||||
" <!ENTITY % define_g \"<!ENTITY g '%p2;'>\">\n"
|
||||
" %define_g;\n"
|
||||
"]>\n"
|
||||
"<doc/>\n",
|
||||
true},
|
||||
};
|
||||
const XML_Bool reset_or_not[] = {XML_TRUE, XML_FALSE};
|
||||
|
||||
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
for (size_t j = 0; j < sizeof(reset_or_not) / sizeof(reset_or_not[0]);
|
||||
j++) {
|
||||
const XML_Bool reset_wanted = reset_or_not[j];
|
||||
const char *const doc = cases[i].doc;
|
||||
const bool usesParameterEntities = cases[i].usesParameterEntities;
|
||||
|
||||
set_subtest("[%i,reset=%i] %s", (int)i, (int)j, doc);
|
||||
|
||||
#ifdef XML_DTD // both GE and DTD
|
||||
const bool rejection_expected = true;
|
||||
#elif XML_GE == 1 // GE but not DTD
|
||||
const bool rejection_expected = ! usesParameterEntities;
|
||||
#else // neither DTD nor GE
|
||||
const bool rejection_expected = false;
|
||||
#endif
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
#ifdef XML_DTD
|
||||
if (usesParameterEntities) {
|
||||
assert_true(
|
||||
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)
|
||||
== 1);
|
||||
}
|
||||
#else
|
||||
UNUSED_P(usesParameterEntities);
|
||||
#endif // XML_DTD
|
||||
|
||||
const enum XML_Status status
|
||||
= _XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal*/ XML_TRUE);
|
||||
|
||||
if (rejection_expected) {
|
||||
assert_true(status == XML_STATUS_ERROR);
|
||||
assert_true(XML_GetErrorCode(parser) == XML_ERROR_RECURSIVE_ENTITY_REF);
|
||||
} else {
|
||||
assert_true(status == XML_STATUS_OK);
|
||||
}
|
||||
|
||||
if (reset_wanted) {
|
||||
// This covers free'ing of (eventually) all three open entity lists by
|
||||
// XML_ParserReset.
|
||||
XML_ParserReset(parser, NULL);
|
||||
}
|
||||
|
||||
// This covers free'ing of (eventually) all three open entity lists by
|
||||
// XML_ParserFree (unless XML_ParserReset has already done that above).
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_recursive_external_parameter_entity_2) {
|
||||
struct TestCase {
|
||||
const char *doc;
|
||||
@@ -1417,7 +1521,9 @@ START_TEST(test_suspend_parser_between_char_data_calls) {
|
||||
|
||||
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
|
||||
g_resumable = XML_TRUE;
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
!= XML_STATUS_SUSPENDED)
|
||||
xml_failure(g_parser);
|
||||
if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
|
||||
@@ -1446,7 +1552,9 @@ START_TEST(test_repeated_stop_parser_between_char_data_calls) {
|
||||
XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
|
||||
g_resumable = XML_TRUE;
|
||||
g_abortable = XML_FALSE;
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
!= XML_STATUS_SUSPENDED)
|
||||
fail("Failed to double-suspend parser");
|
||||
|
||||
@@ -1830,12 +1938,19 @@ END_TEST
|
||||
|
||||
/* Test suspending the parser in cdata handler */
|
||||
START_TEST(test_suspend_parser_between_cdata_calls) {
|
||||
if (g_chunkSize != 0) {
|
||||
// this test does not use SINGLE_BYTES, because of suspension
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text = long_cdata_text;
|
||||
enum XML_Status result;
|
||||
|
||||
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
|
||||
g_resumable = XML_TRUE;
|
||||
result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
result = XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
|
||||
if (result != XML_STATUS_SUSPENDED) {
|
||||
if (result == XML_STATUS_ERROR)
|
||||
xml_failure(g_parser);
|
||||
@@ -2378,6 +2493,11 @@ END_TEST
|
||||
* entity. Exercises some obscure code in XML_ParserReset().
|
||||
*/
|
||||
START_TEST(test_reset_in_entity) {
|
||||
if (g_chunkSize != 0) {
|
||||
// this test does not use SINGLE_BYTES, because of suspension
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text = "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY wombat 'wom'>\n"
|
||||
"<!ENTITY entity 'hi &wom; there'>\n"
|
||||
@@ -2387,7 +2507,9 @@ START_TEST(test_reset_in_entity) {
|
||||
|
||||
g_resumable = XML_TRUE;
|
||||
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(g_parser);
|
||||
XML_GetParsingStatus(g_parser, &status);
|
||||
@@ -3634,7 +3756,9 @@ START_TEST(test_suspend_xdecl) {
|
||||
XML_SetXmlDeclHandler(g_parser, entity_suspending_xdecl_handler);
|
||||
XML_SetUserData(g_parser, g_parser);
|
||||
g_resumable = XML_TRUE;
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
!= XML_STATUS_SUSPENDED)
|
||||
xml_failure(g_parser);
|
||||
if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
|
||||
@@ -3830,13 +3954,20 @@ END_TEST
|
||||
|
||||
/* Test syntax error is caught at parse resumption */
|
||||
START_TEST(test_resume_entity_with_syntax_error) {
|
||||
if (g_chunkSize != 0) {
|
||||
// this test does not use SINGLE_BYTES, because of suspension
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text = "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY foo '<suspend>Hi</wombat>'>\n"
|
||||
"]>\n"
|
||||
"<doc>&foo;</doc>\n";
|
||||
|
||||
XML_SetStartElementHandler(g_parser, start_element_suspender);
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
|
||||
// we won't know exactly how much input we actually managed to give Expat.
|
||||
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
!= XML_STATUS_SUSPENDED)
|
||||
xml_failure(g_parser);
|
||||
if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
|
||||
@@ -3960,7 +4091,7 @@ START_TEST(test_skipped_null_loaded_ext_entity) {
|
||||
= {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
|
||||
"<!ENTITY % pe2 '%pe1;'>\n"
|
||||
"%pe2;\n",
|
||||
external_entity_null_loader};
|
||||
external_entity_null_loader, NULL};
|
||||
|
||||
XML_SetUserData(g_parser, &test_data);
|
||||
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
@@ -3978,7 +4109,7 @@ START_TEST(test_skipped_unloaded_ext_entity) {
|
||||
= {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
|
||||
"<!ENTITY % pe2 '%pe1;'>\n"
|
||||
"%pe2;\n",
|
||||
NULL};
|
||||
NULL, NULL};
|
||||
|
||||
XML_SetUserData(g_parser, &test_data);
|
||||
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
@@ -5278,6 +5409,151 @@ START_TEST(test_pool_integrity_with_unfinished_attr) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Test a possible early return location in internalEntityProcessor */
|
||||
START_TEST(test_entity_ref_no_elements) {
|
||||
const char *const text = "<!DOCTYPE foo [\n"
|
||||
"<!ENTITY e1 \"test\">\n"
|
||||
"]> <foo>&e1;"; // intentionally missing newline
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR);
|
||||
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NO_ELEMENTS);
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Tests if chained entity references lead to unbounded recursion */
|
||||
START_TEST(test_deep_nested_entity) {
|
||||
const size_t N_LINES = 60000;
|
||||
const size_t SIZE_PER_LINE = 50;
|
||||
|
||||
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
|
||||
if (text == NULL) {
|
||||
fail("malloc failed");
|
||||
}
|
||||
|
||||
char *textPtr = text;
|
||||
|
||||
// Create the XML
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE,
|
||||
"<!DOCTYPE foo [\n"
|
||||
" <!ENTITY s0 'deepText'>\n");
|
||||
|
||||
for (size_t i = 1; i < N_LINES; ++i) {
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
|
||||
(long unsigned)i, (long unsigned)(i - 1));
|
||||
}
|
||||
|
||||
snprintf(textPtr, SIZE_PER_LINE, "]> <foo>&s%lu;</foo>\n",
|
||||
(long unsigned)(N_LINES - 1));
|
||||
|
||||
const XML_Char *const expected = XCS("deepText");
|
||||
|
||||
CharData storage;
|
||||
CharData_Init(&storage);
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
XML_SetCharacterDataHandler(parser, accumulate_characters);
|
||||
XML_SetUserData(parser, &storage);
|
||||
|
||||
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(parser);
|
||||
|
||||
CharData_CheckXMLChars(&storage, expected);
|
||||
XML_ParserFree(parser);
|
||||
free(text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Tests if chained entity references in attributes
|
||||
lead to unbounded recursion */
|
||||
START_TEST(test_deep_nested_attribute_entity) {
|
||||
const size_t N_LINES = 60000;
|
||||
const size_t SIZE_PER_LINE = 100;
|
||||
|
||||
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
|
||||
if (text == NULL) {
|
||||
fail("malloc failed");
|
||||
}
|
||||
|
||||
char *textPtr = text;
|
||||
|
||||
// Create the XML
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE,
|
||||
"<!DOCTYPE foo [\n"
|
||||
" <!ENTITY s0 'deepText'>\n");
|
||||
|
||||
for (size_t i = 1; i < N_LINES; ++i) {
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
|
||||
(long unsigned)i, (long unsigned)(i - 1));
|
||||
}
|
||||
|
||||
snprintf(textPtr, SIZE_PER_LINE, "]> <foo name='&s%lu;'>mainText</foo>\n",
|
||||
(long unsigned)(N_LINES - 1));
|
||||
|
||||
AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
|
||||
ElementInfo info[] = {{XCS("foo"), 1, NULL, NULL}, {NULL, 0, NULL, NULL}};
|
||||
info[0].attributes = doc_info;
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
ParserAndElementInfo parserPlusElemenInfo = {parser, info};
|
||||
|
||||
XML_SetStartElementHandler(parser, counting_start_element_handler);
|
||||
XML_SetUserData(parser, &parserPlusElemenInfo);
|
||||
|
||||
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(parser);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
free(text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_deep_nested_entity_delayed_interpretation) {
|
||||
const size_t N_LINES = 70000;
|
||||
const size_t SIZE_PER_LINE = 100;
|
||||
|
||||
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
|
||||
if (text == NULL) {
|
||||
fail("malloc failed");
|
||||
}
|
||||
|
||||
char *textPtr = text;
|
||||
|
||||
// Create the XML
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE,
|
||||
"<!DOCTYPE foo [\n"
|
||||
" <!ENTITY %% s0 'deepText'>\n");
|
||||
|
||||
for (size_t i = 1; i < N_LINES; ++i) {
|
||||
textPtr += snprintf(textPtr, SIZE_PER_LINE,
|
||||
" <!ENTITY %% s%lu '%s%lu;'>\n", (long unsigned)i,
|
||||
(long unsigned)(i - 1));
|
||||
}
|
||||
|
||||
snprintf(textPtr, SIZE_PER_LINE,
|
||||
" <!ENTITY %% define_g \"<!ENTITY g '%s%lu;'>\">\n"
|
||||
" %%define_g;\n"
|
||||
"]>\n"
|
||||
"<foo/>\n",
|
||||
(long unsigned)(N_LINES - 1));
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(parser);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
free(text);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_nested_entity_suspend) {
|
||||
const char *const text = "<!DOCTYPE a [\n"
|
||||
" <!ENTITY e1 '<!--e1-->'>\n"
|
||||
@@ -5308,6 +5584,35 @@ START_TEST(test_nested_entity_suspend) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_nested_entity_suspend_2) {
|
||||
const char *const text = "<!DOCTYPE doc [\n"
|
||||
" <!ENTITY ge1 'head1Ztail1'>\n"
|
||||
" <!ENTITY ge2 'head2&ge1;tail2'>\n"
|
||||
" <!ENTITY ge3 'head3&ge2;tail3'>\n"
|
||||
"]>\n"
|
||||
"<doc>&ge3;</doc>";
|
||||
const XML_Char *const expected = XCS("head3") XCS("head2") XCS("head1")
|
||||
XCS("Z") XCS("tail1") XCS("tail2") XCS("tail3");
|
||||
CharData storage;
|
||||
CharData_Init(&storage);
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
ParserPlusStorage parserPlusStorage = {parser, &storage};
|
||||
|
||||
XML_SetCharacterDataHandler(parser, accumulate_char_data_and_suspend);
|
||||
XML_SetUserData(parser, &parserPlusStorage);
|
||||
|
||||
enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE);
|
||||
while (status == XML_STATUS_SUSPENDED) {
|
||||
status = XML_ResumeParser(parser);
|
||||
}
|
||||
if (status != XML_STATUS_OK)
|
||||
xml_failure(parser);
|
||||
|
||||
CharData_CheckXMLChars(&storage, expected);
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Regression test for quadratic parsing on large tokens */
|
||||
START_TEST(test_big_tokens_scale_linearly) {
|
||||
const struct {
|
||||
@@ -5968,7 +6273,9 @@ make_basic_test_case(Suite *s) {
|
||||
tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
|
||||
tcase_add_test(tc_basic, test_not_standalone_handler_reject);
|
||||
tcase_add_test(tc_basic, test_not_standalone_handler_accept);
|
||||
tcase_add_test(tc_basic, test_entity_start_tag_level_greater_than_one);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
|
||||
tcase_add_test(tc_basic, test_no_indirectly_recursive_entity_refs);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
|
||||
tcase_add_test(tc_basic, test_dtd_attr_handling);
|
||||
@@ -6147,7 +6454,13 @@ make_basic_test_case(Suite *s) {
|
||||
tcase_add_test(tc_basic, test_empty_element_abort);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_basic,
|
||||
test_pool_integrity_with_unfinished_attr);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_entity_ref_no_elements);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_entity);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_attribute_entity);
|
||||
tcase_add_test__if_xml_ge(tc_basic,
|
||||
test_deep_nested_entity_delayed_interpretation);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend_2);
|
||||
tcase_add_test(tc_basic, test_big_tokens_scale_linearly);
|
||||
tcase_add_test(tc_basic, test_set_reparse_deferral);
|
||||
tcase_add_test(tc_basic, test_reparse_deferral_is_inherited);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Copyright (c) 2003-2006 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Licensed under the MIT license:
|
||||
|
||||
@@ -32,10 +32,18 @@
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 1 // fdopen
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <io.h> // _open, _close
|
||||
#else
|
||||
# include <unistd.h> // close
|
||||
#endif
|
||||
|
||||
#include <fcntl.h> // open
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h> // ptrdiff_t
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "expat.h"
|
||||
@@ -52,17 +60,18 @@
|
||||
# define XML_FMT_STR "s"
|
||||
#endif
|
||||
|
||||
static void
|
||||
static int
|
||||
usage(const char *prog, int rc) {
|
||||
fprintf(stderr, "usage: %s [-n] filename bufferSize nr_of_loops\n", prog);
|
||||
exit(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
XML_Parser parser;
|
||||
char *XMLBuf, *XMLBufEnd, *XMLBufPtr;
|
||||
FILE *fd;
|
||||
int fd;
|
||||
FILE *file;
|
||||
struct stat fileAttr;
|
||||
int nrOfLoops, bufferSize, i, isFinal;
|
||||
size_t fileSize;
|
||||
@@ -76,34 +85,48 @@ main(int argc, char *argv[]) {
|
||||
ns = 1;
|
||||
j = 1;
|
||||
} else
|
||||
usage(argv[0], 1);
|
||||
return usage(argv[0], 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != j + 4)
|
||||
usage(argv[0], 1);
|
||||
return usage(argv[0], 1);
|
||||
|
||||
if (stat(argv[j + 1], &fileAttr) != 0) {
|
||||
fprintf(stderr, "could not access file '%s'\n", argv[j + 1]);
|
||||
fd = open(argv[j + 1], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "could not open file '%s'\n", argv[j + 1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
fd = fopen(argv[j + 1], "r");
|
||||
if (! fd) {
|
||||
fprintf(stderr, "could not open file '%s'\n", argv[j + 1]);
|
||||
exit(2);
|
||||
if (fstat(fd, &fileAttr) != 0) {
|
||||
close(fd);
|
||||
fprintf(stderr, "could not fstat file '%s'\n", argv[j + 1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
file = fdopen(fd, "r");
|
||||
if (! file) {
|
||||
close(fd);
|
||||
fprintf(stderr, "could not fdopen file '%s'\n", argv[j + 1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
bufferSize = atoi(argv[j + 2]);
|
||||
nrOfLoops = atoi(argv[j + 3]);
|
||||
if (bufferSize <= 0 || nrOfLoops <= 0) {
|
||||
fclose(file); // NOTE: this closes fd as well
|
||||
fprintf(stderr, "buffer size and nr of loops must be greater than zero.\n");
|
||||
exit(3);
|
||||
return 3;
|
||||
}
|
||||
|
||||
XMLBuf = malloc(fileAttr.st_size);
|
||||
fileSize = fread(XMLBuf, sizeof(char), fileAttr.st_size, fd);
|
||||
fclose(fd);
|
||||
if (XMLBuf == NULL) {
|
||||
fclose(file); // NOTE: this closes fd as well
|
||||
fprintf(stderr, "ouf of memory.\n");
|
||||
return 5;
|
||||
}
|
||||
fileSize = fread(XMLBuf, sizeof(char), fileAttr.st_size, file);
|
||||
fclose(file); // NOTE: this closes fd as well
|
||||
|
||||
if (ns)
|
||||
parser = XML_ParserCreateNS(NULL, '!');
|
||||
@@ -132,7 +155,7 @@ main(int argc, char *argv[]) {
|
||||
XML_GetCurrentColumnNumber(parser));
|
||||
free(XMLBuf);
|
||||
XML_ParserFree(parser);
|
||||
exit(4);
|
||||
return 4;
|
||||
}
|
||||
XMLBufPtr += bufferSize;
|
||||
} while (! isFinal);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
|
||||
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
|
||||
@@ -42,6 +42,8 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h> // for SIZE_MAX
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -202,6 +204,12 @@ _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
|
||||
for (; len > chunksize; len -= chunksize, s += chunksize) {
|
||||
enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE);
|
||||
if (res != XML_STATUS_OK) {
|
||||
if ((res == XML_STATUS_SUSPENDED) && (len > chunksize)) {
|
||||
fail("Use of function _XML_Parse_SINGLE_BYTES with a chunk size "
|
||||
"greater than 0 (from g_chunkSize) does not work well with "
|
||||
"suspension. Please consider use of plain XML_Parse at this "
|
||||
"place in your test, instead.");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -294,3 +302,26 @@ duff_reallocator(void *ptr, size_t size) {
|
||||
g_reallocation_count--;
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
// Portable remake of strndup(3) for C99; does not care about space efficiency
|
||||
char *
|
||||
portable_strndup(const char *s, size_t n) {
|
||||
if ((s == NULL) || (n == SIZE_MAX)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *const buffer = (char *)malloc(n + 1);
|
||||
if (buffer == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
memcpy(buffer, s, n);
|
||||
|
||||
buffer[n] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
|
||||
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
|
||||
@@ -146,6 +146,8 @@ extern void *duff_allocator(size_t size);
|
||||
|
||||
extern void *duff_reallocator(void *ptr, size_t size);
|
||||
|
||||
extern char *portable_strndup(const char *s, size_t n);
|
||||
|
||||
#endif /* XML_COMMON_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1842,6 +1842,15 @@ element_decl_suspender(void *userData, const XML_Char *name,
|
||||
XML_FreeContentModel(g_parser, model);
|
||||
}
|
||||
|
||||
void XMLCALL
|
||||
suspend_after_element_declaration(void *userData, const XML_Char *name,
|
||||
XML_Content *model) {
|
||||
UNUSED_P(name);
|
||||
XML_Parser parser = (XML_Parser)userData;
|
||||
assert_true(XML_StopParser(parser, /*resumable*/ XML_TRUE) == XML_STATUS_OK);
|
||||
XML_FreeContentModel(parser, model);
|
||||
}
|
||||
|
||||
void XMLCALL
|
||||
accumulate_pi_characters(void *userData, const XML_Char *target,
|
||||
const XML_Char *data) {
|
||||
@@ -1882,6 +1891,20 @@ accumulate_entity_decl(void *userData, const XML_Char *entityName,
|
||||
CharData_AppendXMLChars(storage, XCS("\n"), 1);
|
||||
}
|
||||
|
||||
void XMLCALL
|
||||
accumulate_char_data_and_suspend(void *userData, const XML_Char *s, int len) {
|
||||
ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
|
||||
|
||||
CharData_AppendXMLChars(parserPlusStorage->storage, s, len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (s[i] == 'Z') {
|
||||
XML_StopParser(parserPlusStorage->parser, /*resumable=*/XML_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XMLCALL
|
||||
accumulate_start_element(void *userData, const XML_Char *name,
|
||||
const XML_Char **atts) {
|
||||
|
||||
@@ -325,6 +325,7 @@ extern int XMLCALL external_entity_devaluer(XML_Parser parser,
|
||||
typedef struct ext_hdlr_data {
|
||||
const char *parse_text;
|
||||
XML_ExternalEntityRefHandler handler;
|
||||
CharData *storage;
|
||||
} ExtHdlrData;
|
||||
|
||||
extern int XMLCALL external_entity_oneshot_loader(XML_Parser parser,
|
||||
@@ -557,6 +558,10 @@ extern void XMLCALL suspending_comment_handler(void *userData,
|
||||
extern void XMLCALL element_decl_suspender(void *userData, const XML_Char *name,
|
||||
XML_Content *model);
|
||||
|
||||
extern void XMLCALL suspend_after_element_declaration(void *userData,
|
||||
const XML_Char *name,
|
||||
XML_Content *model);
|
||||
|
||||
extern void XMLCALL accumulate_pi_characters(void *userData,
|
||||
const XML_Char *target,
|
||||
const XML_Char *data);
|
||||
@@ -569,6 +574,10 @@ extern void XMLCALL accumulate_entity_decl(
|
||||
const XML_Char *systemId, const XML_Char *publicId,
|
||||
const XML_Char *notationName);
|
||||
|
||||
extern void XMLCALL accumulate_char_data_and_suspend(void *userData,
|
||||
const XML_Char *s,
|
||||
int len);
|
||||
|
||||
extern void XMLCALL accumulate_start_element(void *userData,
|
||||
const XML_Char *name,
|
||||
const XML_Char **atts);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Copyright (c) 2004-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
|
||||
Copyright (c) 2006-2012 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2022 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Licensed under the MIT license:
|
||||
@@ -129,8 +129,10 @@ void _check_set_test_info(char const *function, char const *filename,
|
||||
* Prototypes for the actual implementation.
|
||||
*/
|
||||
|
||||
# if defined(__GNUC__)
|
||||
# if defined(__has_attribute)
|
||||
# if __has_attribute(noreturn)
|
||||
__attribute__((noreturn))
|
||||
# endif
|
||||
# endif
|
||||
void
|
||||
_fail(const char *file, int line, const char *msg);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
|
||||
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
|
||||
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
|
||||
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
|
||||
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
|
||||
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
|
||||
@@ -59,6 +59,9 @@
|
||||
#include "handlers.h"
|
||||
#include "misc_tests.h"
|
||||
|
||||
void XMLCALL accumulate_characters_ext_handler(void *userData,
|
||||
const XML_Char *s, int len);
|
||||
|
||||
/* Test that a failure to allocate the parser structure fails gracefully */
|
||||
START_TEST(test_misc_alloc_create_parser) {
|
||||
XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
|
||||
@@ -208,7 +211,7 @@ START_TEST(test_misc_version) {
|
||||
if (! versions_equal(&read_version, &parsed_version))
|
||||
fail("Version mismatch");
|
||||
|
||||
if (xcstrcmp(version_text, XCS("expat_2.6.4"))) /* needs bump on releases */
|
||||
if (xcstrcmp(version_text, XCS("expat_2.7.1"))) /* needs bump on releases */
|
||||
fail("XML_*_VERSION in expat.h out of sync?\n");
|
||||
}
|
||||
END_TEST
|
||||
@@ -294,6 +297,7 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
|
||||
parser = XML_ParserCreate(NULL);
|
||||
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
|
||||
mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
|
||||
assert_true(mydata != NULL);
|
||||
mydata->parser = parser;
|
||||
mydata->deep = 0;
|
||||
XML_SetUserData(parser, mydata);
|
||||
@@ -315,6 +319,7 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
|
||||
parser = XML_ParserCreate(NULL);
|
||||
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
|
||||
mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
|
||||
assert_true(mydata != NULL);
|
||||
mydata->parser = parser;
|
||||
mydata->deep = 0;
|
||||
XML_SetUserData(parser, mydata);
|
||||
@@ -328,64 +333,119 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
|
||||
const char *const inputOne = "<!DOCTYPE d [\n"
|
||||
"<!ENTITY % e ']><d/>'>\n"
|
||||
"\n"
|
||||
"%e;";
|
||||
const char *const inputOne
|
||||
= "<!DOCTYPE d [\n"
|
||||
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
|
||||
"%element_d;\n"
|
||||
"<!ENTITY % e ']><d/>'>\n"
|
||||
"\n"
|
||||
"%e;";
|
||||
const char *const inputTwo
|
||||
= "<!DOCTYPE d [\n"
|
||||
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
|
||||
"%element_d;\n"
|
||||
"<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '%e1;'>\n"
|
||||
"\n"
|
||||
"%e2;";
|
||||
const char *const inputThree = "<!DOCTYPE d [\n"
|
||||
"<!ENTITY % e ']><d'>\n"
|
||||
"\n"
|
||||
"%e;/>";
|
||||
const char *const inputIssue317 = "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY % foo ']>\n"
|
||||
"<doc>Hell<oc (#PCDATA)*>'>\n"
|
||||
"%foo;\n"
|
||||
"]>\n"
|
||||
"<doc>Hello, world</dVc>";
|
||||
const char *const inputThree
|
||||
= "<!DOCTYPE d [\n"
|
||||
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
|
||||
"%element_d;\n"
|
||||
"<!ENTITY % e ']><d'>\n"
|
||||
"\n"
|
||||
"%e;/>";
|
||||
const char *const inputIssue317
|
||||
= "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY % element_doc '<!ELEMENT doc (#PCDATA)*>'>\n"
|
||||
"%element_doc;\n"
|
||||
"<!ENTITY % foo ']>\n"
|
||||
"<doc>Hell<oc (#PCDATA)*>'>\n"
|
||||
"%foo;\n"
|
||||
"]>\n"
|
||||
"<doc>Hello, world</dVc>";
|
||||
|
||||
const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
|
||||
const XML_Bool suspendOrNot[] = {XML_FALSE, XML_TRUE};
|
||||
size_t inputIndex = 0;
|
||||
|
||||
for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
|
||||
set_subtest("%s", inputs[inputIndex]);
|
||||
XML_Parser parser;
|
||||
enum XML_Status parseResult;
|
||||
int setParamEntityResult;
|
||||
XML_Size lineNumber;
|
||||
XML_Size columnNumber;
|
||||
const char *const input = inputs[inputIndex];
|
||||
for (size_t suspendOrNotIndex = 0;
|
||||
suspendOrNotIndex < sizeof(suspendOrNot) / sizeof(suspendOrNot[0]);
|
||||
suspendOrNotIndex++) {
|
||||
const char *const input = inputs[inputIndex];
|
||||
const XML_Bool suspend = suspendOrNot[suspendOrNotIndex];
|
||||
if (suspend && (g_chunkSize > 0)) {
|
||||
// We cannot use _XML_Parse_SINGLE_BYTES below due to suspension, and
|
||||
// so chunk sizes >0 would only repeat the very same test
|
||||
// due to use of plain XML_Parse; we are saving upon that runtime:
|
||||
return;
|
||||
}
|
||||
|
||||
parser = XML_ParserCreate(NULL);
|
||||
setParamEntityResult
|
||||
= XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
if (setParamEntityResult != 1)
|
||||
fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
|
||||
set_subtest("[input=%d suspend=%s] %s", (int)inputIndex,
|
||||
suspend ? "true" : "false", input);
|
||||
XML_Parser parser;
|
||||
enum XML_Status parseResult;
|
||||
int setParamEntityResult;
|
||||
XML_Size lineNumber;
|
||||
XML_Size columnNumber;
|
||||
|
||||
parser = XML_ParserCreate(NULL);
|
||||
setParamEntityResult
|
||||
= XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
if (setParamEntityResult != 1)
|
||||
fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
|
||||
|
||||
if (suspend) {
|
||||
XML_SetUserData(parser, parser);
|
||||
XML_SetElementDeclHandler(parser, suspend_after_element_declaration);
|
||||
}
|
||||
|
||||
if (suspend) {
|
||||
// can't use SINGLE_BYTES here, because it'll return early on
|
||||
// suspension, and we won't know exactly how much input we actually
|
||||
// managed to give Expat.
|
||||
parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
|
||||
|
||||
while (parseResult == XML_STATUS_SUSPENDED) {
|
||||
parseResult = XML_ResumeParser(parser);
|
||||
}
|
||||
|
||||
if (parseResult != XML_STATUS_ERROR) {
|
||||
// can't use SINGLE_BYTES here, because it'll return early on
|
||||
// suspension, and we won't know exactly how much input we actually
|
||||
// managed to give Expat.
|
||||
parseResult = XML_Parse(parser, "", 0, 1);
|
||||
}
|
||||
|
||||
while (parseResult == XML_STATUS_SUSPENDED) {
|
||||
parseResult = XML_ResumeParser(parser);
|
||||
}
|
||||
} else {
|
||||
parseResult
|
||||
= _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
|
||||
|
||||
if (parseResult != XML_STATUS_ERROR) {
|
||||
parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
|
||||
if (parseResult != XML_STATUS_ERROR) {
|
||||
parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
|
||||
if (parseResult != XML_STATUS_ERROR) {
|
||||
fail("Parsing was expected to fail but succeeded.");
|
||||
}
|
||||
|
||||
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
|
||||
fail("Error code does not match XML_ERROR_INVALID_TOKEN");
|
||||
|
||||
lineNumber = XML_GetCurrentLineNumber(parser);
|
||||
if (lineNumber != 6)
|
||||
fail("XML_GetCurrentLineNumber does not work as expected.");
|
||||
|
||||
columnNumber = XML_GetCurrentColumnNumber(parser);
|
||||
if (columnNumber != 0)
|
||||
fail("XML_GetCurrentColumnNumber does not work as expected.");
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
|
||||
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
|
||||
fail("Error code does not match XML_ERROR_INVALID_TOKEN");
|
||||
|
||||
lineNumber = XML_GetCurrentLineNumber(parser);
|
||||
if (lineNumber != 4)
|
||||
fail("XML_GetCurrentLineNumber does not work as expected.");
|
||||
|
||||
columnNumber = XML_GetCurrentColumnNumber(parser);
|
||||
if (columnNumber != 0)
|
||||
fail("XML_GetCurrentColumnNumber does not work as expected.");
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
@@ -519,6 +579,105 @@ START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Adaptation of accumulate_characters that takes ExtHdlrData input to work with
|
||||
* test_renter_loop_finite_content below */
|
||||
void XMLCALL
|
||||
accumulate_characters_ext_handler(void *userData, const XML_Char *s, int len) {
|
||||
ExtHdlrData *const test_data = (ExtHdlrData *)userData;
|
||||
CharData_AppendXMLChars(test_data->storage, s, len);
|
||||
}
|
||||
|
||||
/* Test that internalEntityProcessor does not re-enter forever;
|
||||
* based on files tests/xmlconf/xmltest/valid/ext-sa/012.{xml,ent} */
|
||||
START_TEST(test_renter_loop_finite_content) {
|
||||
CharData storage;
|
||||
CharData_Init(&storage);
|
||||
const char *const text = "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY e1 '&e2;'>\n"
|
||||
"<!ENTITY e2 '&e3;'>\n"
|
||||
"<!ENTITY e3 SYSTEM '012.ent'>\n"
|
||||
"<!ENTITY e4 '&e5;'>\n"
|
||||
"<!ENTITY e5 '(e5)'>\n"
|
||||
"<!ELEMENT doc (#PCDATA)>\n"
|
||||
"]>\n"
|
||||
"<doc>&e1;</doc>\n";
|
||||
ExtHdlrData test_data = {"&e4;\n", external_entity_null_loader, &storage};
|
||||
const XML_Char *const expected = XCS("(e5)\n");
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(parser != NULL);
|
||||
XML_SetUserData(parser, &test_data);
|
||||
XML_SetExternalEntityRefHandler(parser, external_entity_oneshot_loader);
|
||||
XML_SetCharacterDataHandler(parser, accumulate_characters_ext_handler);
|
||||
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(parser);
|
||||
|
||||
CharData_CheckXMLChars(&storage, expected);
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
// Inspired by function XML_OriginalString of Perl's XML::Parser
|
||||
static char *
|
||||
dup_original_string(XML_Parser parser) {
|
||||
const int byte_count = XML_GetCurrentByteCount(parser);
|
||||
|
||||
assert_true(byte_count >= 0);
|
||||
|
||||
int offset = -1;
|
||||
int size = -1;
|
||||
|
||||
const char *const context = XML_GetInputContext(parser, &offset, &size);
|
||||
|
||||
#if XML_CONTEXT_BYTES > 0
|
||||
assert_true(context != NULL);
|
||||
assert_true(offset >= 0);
|
||||
assert_true(size >= 0);
|
||||
return portable_strndup(context + offset, byte_count);
|
||||
#else
|
||||
assert_true(context == NULL);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
on_characters_issue_980(void *userData, const XML_Char *s, int len) {
|
||||
(void)s;
|
||||
(void)len;
|
||||
XML_Parser parser = (XML_Parser)userData;
|
||||
|
||||
char *const original_string = dup_original_string(parser);
|
||||
|
||||
#if XML_CONTEXT_BYTES > 0
|
||||
assert_true(original_string != NULL);
|
||||
assert_true(strcmp(original_string, "&draft.day;") == 0);
|
||||
free(original_string);
|
||||
#else
|
||||
assert_true(original_string == NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
START_TEST(test_misc_expected_event_ptr_issue_980) {
|
||||
// NOTE: This is a tiny subset of sample "REC-xml-19980210.xml"
|
||||
// from Perl's XML::Parser
|
||||
const char *const doc = "<!DOCTYPE day [\n"
|
||||
" <!ENTITY draft.day '10'>\n"
|
||||
"]>\n"
|
||||
"<day>&draft.day;</day>\n";
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(parser, parser);
|
||||
XML_SetCharacterDataHandler(parser, on_characters_issue_980);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
make_miscellaneous_test_case(Suite *s) {
|
||||
TCase *tc_misc = tcase_create("miscellaneous tests");
|
||||
@@ -545,4 +704,6 @@ make_miscellaneous_test_case(Suite *s) {
|
||||
tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
|
||||
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
|
||||
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
|
||||
tcase_add_test__if_xml_ge(tc_misc, test_renter_loop_finite_content);
|
||||
tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980);
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
|
||||
#
|
||||
# This script can be used to exercise Expat against the
|
||||
# w3c.org xml test suite, available from
|
||||
# http://www.w3.org/XML/Test/xmlts20020606.zip.
|
||||
# w3c.org xml test suite, available from:
|
||||
# https://www.w3.org/XML/Test/xmlts20020606.zip
|
||||
#
|
||||
# To run this script, first set XMLWF below so that xmlwf can be
|
||||
# found, then set the output directory with OUTPUT.
|
||||
@@ -30,6 +30,7 @@
|
||||
# Copyright (c) 2002 Karl Waclawek <[email protected]>
|
||||
# Copyright (c) 2008-2019 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2017 Rhodri James <[email protected]>
|
||||
# Copyright (c) 2025 Hanno Böck <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
|
||||
Copyright (c) 2017 Franek Korta <fkorta@gmail.com>
|
||||
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
|
||||
Copyright (c) 2025 Hanno Böck <hanno@gentoo.org>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -55,7 +56,7 @@
|
||||
# define EXPAT_read_count_t int
|
||||
# define EXPAT_read_req_t unsigned int
|
||||
#else /* POSIX */
|
||||
/* http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
|
||||
/* https://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
|
||||
# define EXPAT_read read
|
||||
# define EXPAT_read_count_t ssize_t
|
||||
# define EXPAT_read_req_t size_t
|
||||
|
||||
@@ -20,7 +20,7 @@ the actual statements in the files are controlling.
|
||||
libarchive/mtree.5
|
||||
|
||||
* The following source files are in the public domain:
|
||||
libarchive/archive_getdate.c
|
||||
libarchive/archive_parse_date.c
|
||||
|
||||
* The following source files are triple-licensed with the ability to choose
|
||||
from CC0 1.0 Universal, OpenSSL or Apache 2.0 licenses:
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
Jun 01, 2026: libarchive 3.8.1 released
|
||||
|
||||
May 20, 2025: libarchive 3.8.0 released
|
||||
|
||||
Mar 30, 2025: libarchive 3.7.9 released
|
||||
|
||||
Mar 20, 2025: libarchive 3.7.8 released
|
||||
|
||||
Oct 13, 2024: libarchive 3.7.7 released
|
||||
|
||||
Sep 23, 2024: libarchive 3.7.6 released
|
||||
|
||||
@@ -85,13 +85,14 @@ Currently, the library automatically detects and reads the following formats:
|
||||
* PWB binary cpio
|
||||
* ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions)
|
||||
* ZIP archives (with uncompressed or "deflate" compressed entries, including support for encrypted Zip archives)
|
||||
* ZIPX archives (with support for bzip2, ppmd8, lzma and xz compressed entries)
|
||||
* ZIPX archives (with support for bzip2, zstd, ppmd8, lzma and xz compressed entries)
|
||||
* GNU and BSD 'ar' archives
|
||||
* 'mtree' format
|
||||
* 7-Zip archives (including archives that use zstandard compression)
|
||||
* Microsoft CAB format
|
||||
* LHA and LZH archives
|
||||
* RAR and RAR 5.0 archives (with some limitations due to RAR's proprietary status)
|
||||
* WARC archives
|
||||
* XAR archives
|
||||
|
||||
The library also detects and handles any of the following before evaluating the archive:
|
||||
@@ -120,15 +121,18 @@ The library can create archives in any of the following formats:
|
||||
* PWB binary cpio
|
||||
* shar archives
|
||||
* ZIP archives (with uncompressed or "deflate" compressed entries)
|
||||
* ZIPX archives (with bzip2, zstd, lzma or xz compressed entries)
|
||||
* GNU and BSD 'ar' archives
|
||||
* 'mtree' format
|
||||
* ISO9660 format
|
||||
* 7-Zip archives
|
||||
* 7-Zip archives (including archives that use zstandard compression)
|
||||
* WARC archives
|
||||
* XAR archives
|
||||
|
||||
When creating archives, the result can be filtered with any of the following:
|
||||
|
||||
* uuencode
|
||||
* base64
|
||||
* gzip compression
|
||||
* bzip2 compression
|
||||
* compress/LZW compression
|
||||
@@ -241,4 +245,3 @@ questions we are asked about libarchive:
|
||||
appropriate. It has many advantages over other tar formats
|
||||
(including the legacy GNU tar format) and is widely supported by
|
||||
current tar implementations.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
# Uncommenting these adds a full minute to the CI time
|
||||
#brew update > /dev/null
|
||||
#brew upgrade > /dev/null
|
||||
|
||||
# This does an upgrade if the package is already installed
|
||||
brew install \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
pkg-config \
|
||||
cmake \
|
||||
xz \
|
||||
lz4 \
|
||||
zstd \
|
||||
libxml2 \
|
||||
openssl
|
||||
@@ -1206,7 +1206,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
|
||||
else
|
||||
strcpy(date, "invalid mtime");
|
||||
|
||||
fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
|
||||
fprintf(out, "%s%3u %-8s %-8s %8s %12s %s",
|
||||
archive_entry_strmode(entry),
|
||||
archive_entry_nlink(entry),
|
||||
uname, gname, size, date,
|
||||
|
||||
@@ -189,10 +189,10 @@ DEFINE_TEST(test_format_newc)
|
||||
gid = from_hex(e + 30, 8); /* gid */
|
||||
assertEqualMem(e + 38, "00000003", 8); /* nlink */
|
||||
t = from_hex(e + 46, 8); /* mtime */
|
||||
failure("t=%#08jx now=%#08jx=%jd", (intmax_t)t, (intmax_t)now,
|
||||
failure("t=%#08jx now=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now,
|
||||
(intmax_t)now);
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
failure("t=%#08jx now - 2=%#08jx=%jd", (intmax_t)t, (intmax_t)now - 2,
|
||||
failure("t=%#08jx now - 2=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now - 2,
|
||||
(intmax_t)now - 2);
|
||||
assert(t >= now - 2); /* File was created w/in last 2 secs. */
|
||||
failure("newc format stores body only with last appearance of a link\n"
|
||||
@@ -219,7 +219,7 @@ DEFINE_TEST(test_format_newc)
|
||||
assert(is_hex(e, 110));
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
assert(is_hex(e + 6, 8)); /* ino */
|
||||
#if defined(_WIN32) && !defined(CYGWIN)
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Mode: Group members bits and others bits do not work. */
|
||||
assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);
|
||||
#else
|
||||
@@ -230,7 +230,7 @@ DEFINE_TEST(test_format_newc)
|
||||
assertEqualMem(e + 38, "00000001", 8); /* nlink */
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=%#08jx this entry created"
|
||||
" at t2=%#08jx", (intmax_t)t, (intmax_t)t2);
|
||||
" at t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualMem(e + 54, "00000005", 8); /* File size */
|
||||
fs = (uint64_t)from_hex(e + 54, 8);
|
||||
@@ -266,7 +266,7 @@ DEFINE_TEST(test_format_newc)
|
||||
#endif
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=%#08jx this entry created at"
|
||||
"t2=%#08jx", (intmax_t)t, (intmax_t)t2);
|
||||
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualMem(e + 54, "00000000", 8); /* File size */
|
||||
fs = (uint64_t)from_hex(e + 54, 8);
|
||||
@@ -300,7 +300,7 @@ DEFINE_TEST(test_format_newc)
|
||||
assertEqualMem(e + 38, "00000003", 8); /* nlink */
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=%#08jx this entry created at"
|
||||
"t2=%#08jx", (intmax_t)t, (intmax_t)t2);
|
||||
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualInt(10, from_hex(e + 54, 8)); /* File size */
|
||||
fs = (uint64_t)from_hex(e + 54, 8);
|
||||
|
||||
@@ -52,7 +52,7 @@ test_create(void)
|
||||
* #ifdef this section out. Most of the test below is
|
||||
* still valid. */
|
||||
memset(×, 0, sizeof(times));
|
||||
#if defined(_WIN32) && !defined(CYGWIN)
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
times.actime = 86400;
|
||||
times.modtime = 86400;
|
||||
#else
|
||||
|
||||
@@ -18,7 +18,7 @@ is_octal(const char *p, size_t l)
|
||||
return (1);
|
||||
}
|
||||
|
||||
static long long int
|
||||
static unsigned long long int
|
||||
from_octal(const char *p, size_t l)
|
||||
{
|
||||
long long int r = 0;
|
||||
@@ -117,7 +117,7 @@ DEFINE_TEST(test_option_c)
|
||||
gid = (int)from_octal(e + 30, 6);
|
||||
assertEqualMem(e + 36, "000001", 6); /* nlink */
|
||||
failure("file entries should not have rdev set (dev field was 0%o)",
|
||||
dev);
|
||||
(unsigned int)dev);
|
||||
assertEqualMem(e + 42, "000000", 6); /* rdev */
|
||||
t = from_octal(e + 48, 11); /* mtime */
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
@@ -133,7 +133,7 @@ DEFINE_TEST(test_option_c)
|
||||
assert(is_octal(e, 76)); /* Entire header is octal digits. */
|
||||
assertEqualMem(e + 0, "070707", 6); /* Magic */
|
||||
assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
|
||||
assert(ino != from_octal(e + 12, 6)); /* ino */
|
||||
assert(ino != (int)from_octal(e + 12, 6)); /* ino */
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
/* On Windows, symbolic link and group members bits and
|
||||
* others bits do not work. */
|
||||
@@ -163,7 +163,7 @@ DEFINE_TEST(test_option_c)
|
||||
assertEqualInt(dev, from_octal(e + 6, 6));
|
||||
/* Ino must be different from first entry. */
|
||||
assert(is_octal(e + 12, 6)); /* ino */
|
||||
assert(ino != from_octal(e + 12, 6));
|
||||
assert(ino != (int)from_octal(e + 12, 6));
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Group members bits and others bits do not work. */
|
||||
assertEqualMem(e + 18, "040777", 6); /* Mode */
|
||||
|
||||
@@ -34,12 +34,15 @@
|
||||
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
|
||||
*/
|
||||
/* Note: Compiler will complain if this does not match archive_entry.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3007007
|
||||
#define ARCHIVE_VERSION_NUMBER 3008001
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
#include <stdio.h> /* For FILE * */
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* time_t is slated to be removed from public includes in 4.0 */
|
||||
#include <time.h> /* For time_t */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note: archive.h is for use outside of libarchive; the configuration
|
||||
@@ -63,12 +66,15 @@
|
||||
#define __LA_INT64_T_DEFINED
|
||||
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
|
||||
typedef __int64 la_int64_t;
|
||||
typedef unsigned __int64 la_uint64_t;
|
||||
# else
|
||||
# include <unistd.h> /* ssize_t */
|
||||
# if defined(_SCO_DS) || defined(__osf__)
|
||||
typedef long long la_int64_t;
|
||||
typedef unsigned long long la_uint64_t;
|
||||
# else
|
||||
typedef int64_t la_int64_t;
|
||||
typedef uint64_t la_uint64_t;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -94,6 +100,22 @@ typedef ssize_t la_ssize_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for time_t */
|
||||
#define __LA_TIME_T time_t
|
||||
#else
|
||||
/* Use 64-bits integer types for time_t */
|
||||
#define __LA_TIME_T la_int64_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for dev_t */
|
||||
#define __LA_DEV_T dev_t
|
||||
#else
|
||||
/* Use 64-bits integer types for dev_t */
|
||||
#define __LA_DEV_T la_int64_t
|
||||
#endif
|
||||
|
||||
/* Large file support for Android */
|
||||
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
|
||||
#include "android_lf.h"
|
||||
@@ -132,7 +154,7 @@ typedef ssize_t la_ssize_t;
|
||||
#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define __LA_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
# define __LA_DEPRECATED
|
||||
@@ -155,7 +177,7 @@ __LA_DECL int archive_version_number(void);
|
||||
/*
|
||||
* Textual name/version of the library, useful for version displays.
|
||||
*/
|
||||
#define ARCHIVE_VERSION_ONLY_STRING "3.7.7"
|
||||
#define ARCHIVE_VERSION_ONLY_STRING "3.8.1"
|
||||
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
|
||||
__LA_DECL const char * archive_version_string(void);
|
||||
|
||||
@@ -178,6 +200,23 @@ __LA_DECL const char * archive_liblzma_version(void);
|
||||
__LA_DECL const char * archive_bzlib_version(void);
|
||||
__LA_DECL const char * archive_liblz4_version(void);
|
||||
__LA_DECL const char * archive_libzstd_version(void);
|
||||
__LA_DECL const char * archive_liblzo2_version(void);
|
||||
__LA_DECL const char * archive_libexpat_version(void);
|
||||
__LA_DECL const char * archive_libbsdxml_version(void);
|
||||
__LA_DECL const char * archive_libxml2_version(void);
|
||||
__LA_DECL const char * archive_mbedtls_version(void);
|
||||
__LA_DECL const char * archive_nettle_version(void);
|
||||
__LA_DECL const char * archive_openssl_version(void);
|
||||
__LA_DECL const char * archive_libmd_version(void);
|
||||
__LA_DECL const char * archive_commoncrypto_version(void);
|
||||
__LA_DECL const char * archive_cng_version(void);
|
||||
__LA_DECL const char * archive_wincrypt_version(void);
|
||||
__LA_DECL const char * archive_librichacl_version(void);
|
||||
__LA_DECL const char * archive_libacl_version(void);
|
||||
__LA_DECL const char * archive_libattr_version(void);
|
||||
__LA_DECL const char * archive_libiconv_version(void);
|
||||
__LA_DECL const char * archive_libpcre_version(void);
|
||||
__LA_DECL const char * archive_libpcre2_version(void);
|
||||
|
||||
/* Declare our basic types. */
|
||||
struct archive;
|
||||
@@ -449,6 +488,8 @@ __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 *);
|
||||
/* archive_read_support_format_gnutar() is an alias for historical reasons
|
||||
* of archive_read_support_format_tar(). */
|
||||
__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 *);
|
||||
@@ -828,6 +869,10 @@ __LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const ch
|
||||
__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_zip_set_compression_lzma(struct archive *);
|
||||
__LA_DECL int archive_write_zip_set_compression_xz(struct archive *);
|
||||
__LA_DECL int archive_write_zip_set_compression_bzip2(struct archive *);
|
||||
__LA_DECL int archive_write_zip_set_compression_zstd(struct archive *);
|
||||
/* Deprecated; use archive_write_open2 instead */
|
||||
__LA_DECL int archive_write_open(struct archive *, void *,
|
||||
archive_open_callback *, archive_write_callback *,
|
||||
@@ -1083,6 +1128,10 @@ __LA_DECL int archive_compression(struct archive *)
|
||||
__LA_DEPRECATED;
|
||||
#endif
|
||||
|
||||
/* Parses a date string relative to the current time.
|
||||
* NOTE: This is not intended for general date parsing, and the resulting timestamp should only be used for libarchive. */
|
||||
__LA_DECL time_t archive_parse_date(time_t now, const char *datestr);
|
||||
|
||||
__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 *);
|
||||
@@ -1201,8 +1250,10 @@ __LA_DECL int archive_match_include_gname_w(struct archive *,
|
||||
const wchar_t *);
|
||||
|
||||
/* Utility functions */
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Convenience function to sort a NULL terminated list of strings */
|
||||
__LA_DECL int archive_utility_string_sort(char **);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1185,8 +1185,13 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
|
||||
/* 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].end == NULL) {
|
||||
/* This should never happen */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (field[0].start != NULL && *(field[0].start) == L'#') {
|
||||
if (*(field[0].start) == L'#') {
|
||||
/* Comment, skip entry */
|
||||
continue;
|
||||
}
|
||||
@@ -1676,7 +1681,12 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
for (n = fields; n < numfields; ++n)
|
||||
field[n].start = field[n].end = NULL;
|
||||
|
||||
if (field[0].start != NULL && *(field[0].start) == '#') {
|
||||
if (field[0].start == NULL || field[0].end == NULL) {
|
||||
/* This should never happen */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (*(field[0].start) == '#') {
|
||||
/* Comment, skip entry */
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -80,4 +80,4 @@ int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,
|
||||
int archive_acl_from_text_nl(struct archive_acl *, const char * /* text */,
|
||||
size_t /* size of text */, int /* type */, struct archive_string_conv *);
|
||||
|
||||
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_ACL_PRIVATE_H_INCLUDED */
|
||||
@@ -71,7 +71,7 @@ get_argument(struct archive_string *as, const char *p)
|
||||
archive_string_empty(as);
|
||||
|
||||
/* Skip beginning space characters. */
|
||||
while (*s != '\0' && *s == ' ')
|
||||
while (*s == ' ')
|
||||
s++;
|
||||
/* Copy non-space characters. */
|
||||
while (*s != '\0' && *s != ' ') {
|
||||
|
||||
@@ -64,6 +64,7 @@ typedef struct {
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#include <bcrypt.h>
|
||||
#define ARCHIVE_CRYPTOR_USE_CNG 1
|
||||
|
||||
/* Common in other bcrypt implementations, but missing from VS2008. */
|
||||
#ifndef BCRYPT_SUCCESS
|
||||
@@ -86,6 +87,7 @@ typedef struct {
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/pkcs5.h>
|
||||
#define ARCHIVE_CRYPTOR_USE_MBED 1
|
||||
|
||||
#define AES_MAX_KEY_SIZE 32
|
||||
#define AES_BLOCK_SIZE 16
|
||||
@@ -105,6 +107,7 @@ typedef struct {
|
||||
#endif
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/version.h>
|
||||
#define ARCHIVE_CRYPTOR_USE_NETTLE 1
|
||||
|
||||
typedef struct {
|
||||
#if NETTLE_VERSION_MAJOR < 3
|
||||
@@ -125,6 +128,7 @@ typedef struct {
|
||||
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
#include "archive_openssl_evp_private.h"
|
||||
#define ARCHIVE_CRYPTOR_USE_OPENSSL 1
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES_MAX_KEY_SIZE 32
|
||||
|
||||
@@ -140,6 +144,10 @@ typedef struct {
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
|
||||
#define ARCHIVE_CRYPTOR_USE_WINCRYPT 1
|
||||
#endif
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES_MAX_KEY_SIZE 32
|
||||
typedef int archive_crypto_ctx;
|
||||
|
||||
@@ -196,6 +196,13 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
|
||||
|
||||
// These functions are available in macOS 10.4 and later, but deprecated from 10.15 onwards.
|
||||
// We need to continue supporting this feature regardless, so suppress the warnings.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
static int
|
||||
__archive_md5init(archive_md5_ctx *ctx)
|
||||
{
|
||||
@@ -218,13 +225,46 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
|
||||
|
||||
static int
|
||||
__archive_md5init(archive_md5_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 16, ctx));
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
|
||||
|
||||
static int
|
||||
__archive_md5init(archive_md5_ctx *ctx)
|
||||
{
|
||||
mbedtls_md5_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_md5_starts(ctx) == 0)
|
||||
#else
|
||||
if (mbedtls_md5_starts_ret(ctx) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -234,7 +274,11 @@ static int
|
||||
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_md5_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_md5_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -243,7 +287,11 @@ __archive_md5update(archive_md5_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_md5_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_md5_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_md5_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -311,31 +359,6 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
|
||||
|
||||
static int
|
||||
__archive_md5init(archive_md5_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 16, ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
@@ -420,7 +443,11 @@ static int
|
||||
__archive_ripemd160init(archive_rmd160_ctx *ctx)
|
||||
{
|
||||
mbedtls_ripemd160_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_ripemd160_starts(ctx) == 0)
|
||||
#else
|
||||
if (mbedtls_ripemd160_starts_ret(ctx) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -430,7 +457,11 @@ static int
|
||||
__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_ripemd160_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -439,7 +470,11 @@ __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_ripemd160_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_ripemd160_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -605,13 +640,42 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha1init(archive_sha1_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 20, ctx));
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
|
||||
|
||||
static int
|
||||
__archive_sha1init(archive_sha1_ctx *ctx)
|
||||
{
|
||||
mbedtls_sha1_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha1_starts(ctx) == 0)
|
||||
#else
|
||||
if (mbedtls_sha1_starts_ret(ctx) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -621,7 +685,11 @@ static int
|
||||
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha1_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -630,7 +698,11 @@ __archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha1_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_sha1_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_sha1_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -698,31 +770,6 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha1init(archive_sha1_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 20, ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
@@ -873,13 +920,42 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha256init(archive_sha256_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 32, ctx));
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
|
||||
|
||||
static int
|
||||
__archive_sha256init(archive_sha256_ctx *ctx)
|
||||
{
|
||||
mbedtls_sha256_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha256_starts(ctx, 0) == 0)
|
||||
#else
|
||||
if (mbedtls_sha256_starts_ret(ctx, 0) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -889,7 +965,11 @@ static int
|
||||
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha256_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -898,7 +978,11 @@ __archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha256_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_sha256_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_sha256_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -962,31 +1046,6 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha256init(archive_sha256_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 32, ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
@@ -1113,13 +1172,42 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha384init(archive_sha384_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 48, ctx));
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
|
||||
|
||||
static int
|
||||
__archive_sha384init(archive_sha384_ctx *ctx)
|
||||
{
|
||||
mbedtls_sha512_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_starts(ctx, 1) == 0)
|
||||
#else
|
||||
if (mbedtls_sha512_starts_ret(ctx, 1) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1129,7 +1217,11 @@ static int
|
||||
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1138,7 +1230,11 @@ __archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_sha512_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -1202,31 +1298,6 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha384init(archive_sha384_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 48, ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
@@ -1377,13 +1448,42 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha512init(archive_sha512_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 64, ctx));
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
|
||||
|
||||
static int
|
||||
__archive_sha512init(archive_sha512_ctx *ctx)
|
||||
{
|
||||
mbedtls_sha512_init(ctx);
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_starts(ctx, 0) == 0)
|
||||
#else
|
||||
if (mbedtls_sha512_starts_ret(ctx, 0) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1393,7 +1493,11 @@ static int
|
||||
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
|
||||
#else
|
||||
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
else
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1402,7 +1506,11 @@ __archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
|
||||
static int
|
||||
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
{
|
||||
#if MBEDTLS_VERSION_NUMBER > 0x03000000
|
||||
if (mbedtls_sha512_finish(ctx, md) == 0) {
|
||||
#else
|
||||
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
|
||||
#endif
|
||||
mbedtls_sha512_free(ctx);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
@@ -1466,31 +1574,6 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
|
||||
|
||||
static int
|
||||
__archive_sha512init(archive_sha512_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
|
||||
size_t insize)
|
||||
{
|
||||
return (win_crypto_Update(ctx, indata, insize));
|
||||
}
|
||||
|
||||
static int
|
||||
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
{
|
||||
return (win_crypto_Final(md, 64, ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
@@ -1525,11 +1608,12 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
* 1. libc
|
||||
* 2. libc2
|
||||
* 3. libc3
|
||||
* 4. libSystem
|
||||
* 5. Nettle
|
||||
* 6. OpenSSL
|
||||
* 7. libmd
|
||||
* 8. Windows API
|
||||
* 4. libmd
|
||||
* 5. libSystem
|
||||
* 6. Windows API
|
||||
* 7. mbedTLS
|
||||
* 8. Nettle
|
||||
* 9. OpenSSL
|
||||
*/
|
||||
const struct archive_digest __archive_digest =
|
||||
{
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
|
||||
defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#define ARCHIVE_CRYPTO_CommonCrypto 1
|
||||
#endif
|
||||
|
||||
/* mbed TLS crypto headers */
|
||||
@@ -167,6 +168,7 @@
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
/* don't use bcrypt when XP needs to be supported */
|
||||
#include <bcrypt.h>
|
||||
#define ARCHIVE_CRYPTO_CNG 1
|
||||
typedef struct {
|
||||
int valid;
|
||||
BCRYPT_ALG_HANDLE hAlg;
|
||||
@@ -175,6 +177,7 @@ typedef struct {
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#define ARCHIVE_CRYPTO_WINCRYPT 1
|
||||
typedef struct {
|
||||
int valid;
|
||||
HCRYPTPROV cryptProv;
|
||||
@@ -190,14 +193,16 @@ typedef MD5_CTX archive_md5_ctx;
|
||||
typedef MD5_CTX archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
|
||||
typedef CC_MD5_CTX archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
|
||||
typedef Digest_CTX archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_md5_context archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct md5_ctx archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_md5_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
|
||||
typedef Digest_CTX archive_md5_ctx;
|
||||
#else
|
||||
typedef unsigned char archive_md5_ctx;
|
||||
#endif
|
||||
@@ -207,8 +212,10 @@ typedef RMD160_CTX archive_rmd160_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
|
||||
typedef RIPEMD160_CTX archive_rmd160_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_ripemd160_context archive_rmd160_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct ripemd160_ctx archive_rmd160_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_rmd160_ctx;
|
||||
@@ -222,14 +229,16 @@ typedef SHA1_CTX archive_sha1_ctx;
|
||||
typedef SHA1_CTX archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
|
||||
typedef CC_SHA1_CTX archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
|
||||
typedef Digest_CTX archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_sha1_context archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct sha1_ctx archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_sha1_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
|
||||
typedef Digest_CTX archive_sha1_ctx;
|
||||
#else
|
||||
typedef unsigned char archive_sha1_ctx;
|
||||
#endif
|
||||
@@ -244,14 +253,16 @@ typedef SHA2_CTX archive_sha256_ctx;
|
||||
typedef SHA256_CTX archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
|
||||
typedef CC_SHA256_CTX archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
|
||||
typedef Digest_CTX archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_sha256_context archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct sha256_ctx archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_sha256_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
|
||||
typedef Digest_CTX archive_sha256_ctx;
|
||||
#else
|
||||
typedef unsigned char archive_sha256_ctx;
|
||||
#endif
|
||||
@@ -264,14 +275,16 @@ typedef SHA384_CTX archive_sha384_ctx;
|
||||
typedef SHA2_CTX archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
|
||||
typedef CC_SHA512_CTX archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
|
||||
typedef Digest_CTX archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_sha512_context archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct sha384_ctx archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_sha384_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
|
||||
typedef Digest_CTX archive_sha384_ctx;
|
||||
#else
|
||||
typedef unsigned char archive_sha384_ctx;
|
||||
#endif
|
||||
@@ -286,14 +299,16 @@ typedef SHA2_CTX archive_sha512_ctx;
|
||||
typedef SHA512_CTX archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
|
||||
typedef CC_SHA512_CTX archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
|
||||
typedef Digest_CTX archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
|
||||
#define ARCHIVE_CRYPTO_MBED 1
|
||||
typedef mbedtls_sha512_context archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
|
||||
#define ARCHIVE_CRYPTO_NETTLE 1
|
||||
typedef struct sha512_ctx archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
|
||||
typedef EVP_MD_CTX *archive_sha512_ctx;
|
||||
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
|
||||
typedef Digest_CTX archive_sha512_ctx;
|
||||
#else
|
||||
typedef unsigned char archive_sha512_ctx;
|
||||
#endif
|
||||
|
||||
@@ -262,7 +262,7 @@ translate_acl(struct archive_read_disk *a,
|
||||
}
|
||||
for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
|
||||
r = acl_get_flag_np(acl_flagset,
|
||||
acl_nfs4_flag_map[i].p_perm);
|
||||
(acl_flag_t)acl_nfs4_flag_map[i].p_perm);
|
||||
if (r == -1) {
|
||||
archive_set_error(&a->archive, errno,
|
||||
"Failed to check flag in a NFSv4 "
|
||||
@@ -517,7 +517,7 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
|
||||
if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
|
||||
if (acl_add_flag_np(acl_flagset,
|
||||
acl_nfs4_flag_map[i].p_perm) != 0) {
|
||||
(acl_flag_t)acl_nfs4_flag_map[i].p_perm) != 0) {
|
||||
archive_set_error(a, errno,
|
||||
"Failed to add flag to "
|
||||
"NFSv4 ACL flagset");
|
||||
|
||||
@@ -275,7 +275,7 @@ archive_entry_new2(struct archive *a)
|
||||
* Functions for reading fields from an archive_entry.
|
||||
*/
|
||||
|
||||
time_t
|
||||
__LA_TIME_T
|
||||
archive_entry_atime(struct archive_entry *entry)
|
||||
{
|
||||
return (entry->ae_stat.aest_atime);
|
||||
@@ -293,7 +293,7 @@ archive_entry_atime_is_set(struct archive_entry *entry)
|
||||
return (entry->ae_set & AE_SET_ATIME);
|
||||
}
|
||||
|
||||
time_t
|
||||
__LA_TIME_T
|
||||
archive_entry_birthtime(struct archive_entry *entry)
|
||||
{
|
||||
return (entry->ae_stat.aest_birthtime);
|
||||
@@ -311,7 +311,7 @@ archive_entry_birthtime_is_set(struct archive_entry *entry)
|
||||
return (entry->ae_set & AE_SET_BIRTHTIME);
|
||||
}
|
||||
|
||||
time_t
|
||||
__LA_TIME_T
|
||||
archive_entry_ctime(struct archive_entry *entry)
|
||||
{
|
||||
return (entry->ae_stat.aest_ctime);
|
||||
@@ -329,7 +329,7 @@ archive_entry_ctime_nsec(struct archive_entry *entry)
|
||||
return (entry->ae_stat.aest_ctime_nsec);
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_dev(struct archive_entry *entry)
|
||||
{
|
||||
if (entry->ae_stat.aest_dev_is_broken_down)
|
||||
@@ -345,7 +345,7 @@ archive_entry_dev_is_set(struct archive_entry *entry)
|
||||
return (entry->ae_set & AE_SET_DEV);
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_devmajor(struct archive_entry *entry)
|
||||
{
|
||||
if (entry->ae_stat.aest_dev_is_broken_down)
|
||||
@@ -354,7 +354,7 @@ archive_entry_devmajor(struct archive_entry *entry)
|
||||
return major(entry->ae_stat.aest_dev);
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_devminor(struct archive_entry *entry)
|
||||
{
|
||||
if (entry->ae_stat.aest_dev_is_broken_down)
|
||||
@@ -568,7 +568,7 @@ archive_entry_mode(struct archive_entry *entry)
|
||||
return (entry->acl.mode);
|
||||
}
|
||||
|
||||
time_t
|
||||
__LA_TIME_T
|
||||
archive_entry_mtime(struct archive_entry *entry)
|
||||
{
|
||||
return (entry->ae_stat.aest_mtime);
|
||||
@@ -667,7 +667,7 @@ archive_entry_rdev_is_set(struct archive_entry *entry)
|
||||
return (entry->ae_set & AE_SET_RDEV);
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_rdev(struct archive_entry *entry)
|
||||
{
|
||||
if (archive_entry_rdev_is_set(entry)) {
|
||||
@@ -681,7 +681,7 @@ archive_entry_rdev(struct archive_entry *entry)
|
||||
}
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_rdevmajor(struct archive_entry *entry)
|
||||
{
|
||||
if (archive_entry_rdev_is_set(entry)) {
|
||||
@@ -694,7 +694,7 @@ archive_entry_rdevmajor(struct archive_entry *entry)
|
||||
}
|
||||
}
|
||||
|
||||
dev_t
|
||||
__LA_DEV_T
|
||||
archive_entry_rdevminor(struct archive_entry *entry)
|
||||
{
|
||||
if (archive_entry_rdev_is_set(entry)) {
|
||||
@@ -984,7 +984,9 @@ void
|
||||
archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
|
||||
{
|
||||
if (ino < 0) {
|
||||
ino = 0;
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set &= ~AE_SET_INO;
|
||||
return;
|
||||
}
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set |= AE_SET_INO;
|
||||
@@ -995,7 +997,9 @@ void
|
||||
archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
|
||||
{
|
||||
if (ino < 0) {
|
||||
ino = 0;
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set &= ~AE_SET_INO;
|
||||
return;
|
||||
}
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set |= AE_SET_INO;
|
||||
@@ -1088,7 +1092,7 @@ _archive_entry_copy_hardlink_l(struct archive_entry *entry,
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
|
||||
archive_entry_set_atime(struct archive_entry *entry, __LA_TIME_T t, long ns)
|
||||
{
|
||||
FIX_NS(t, ns);
|
||||
entry->stat_valid = 0;
|
||||
@@ -1105,7 +1109,7 @@ archive_entry_unset_atime(struct archive_entry *entry)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
|
||||
archive_entry_set_birthtime(struct archive_entry *entry, __LA_TIME_T t, long ns)
|
||||
{
|
||||
FIX_NS(t, ns);
|
||||
entry->stat_valid = 0;
|
||||
@@ -1122,7 +1126,7 @@ archive_entry_unset_birthtime(struct archive_entry *entry)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
|
||||
archive_entry_set_ctime(struct archive_entry *entry, __LA_TIME_T t, long ns)
|
||||
{
|
||||
FIX_NS(t, ns);
|
||||
entry->stat_valid = 0;
|
||||
@@ -1139,7 +1143,7 @@ archive_entry_unset_ctime(struct archive_entry *entry)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_dev(struct archive_entry *entry, dev_t d)
|
||||
archive_entry_set_dev(struct archive_entry *entry, __LA_DEV_T d)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set |= AE_SET_DEV;
|
||||
@@ -1148,7 +1152,7 @@ archive_entry_set_dev(struct archive_entry *entry, dev_t d)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
|
||||
archive_entry_set_devmajor(struct archive_entry *entry, __LA_DEV_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set |= AE_SET_DEV;
|
||||
@@ -1157,7 +1161,7 @@ archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
|
||||
archive_entry_set_devminor(struct archive_entry *entry, __LA_DEV_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_set |= AE_SET_DEV;
|
||||
@@ -1243,7 +1247,7 @@ archive_entry_set_mode(struct archive_entry *entry, mode_t m)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
|
||||
archive_entry_set_mtime(struct archive_entry *entry, __LA_TIME_T t, long ns)
|
||||
{
|
||||
FIX_NS(t, ns);
|
||||
entry->stat_valid = 0;
|
||||
@@ -1319,7 +1323,7 @@ archive_entry_set_perm(struct archive_entry *entry, mode_t p)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
|
||||
archive_entry_set_rdev(struct archive_entry *entry, __LA_DEV_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_stat.aest_rdev = m;
|
||||
@@ -1330,7 +1334,7 @@ archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
|
||||
archive_entry_set_rdevmajor(struct archive_entry *entry, __LA_DEV_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_stat.aest_rdev_is_broken_down = 1;
|
||||
@@ -1340,7 +1344,7 @@ archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
|
||||
archive_entry_set_rdevminor(struct archive_entry *entry, __LA_DEV_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->ae_stat.aest_rdev_is_broken_down = 1;
|
||||
@@ -1603,21 +1607,27 @@ archive_entry_set_digest(struct archive_entry *entry, int type,
|
||||
switch (type) {
|
||||
case ARCHIVE_ENTRY_DIGEST_MD5:
|
||||
copy_digest(entry, md5, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_MD5;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_DIGEST_RMD160:
|
||||
copy_digest(entry, rmd160, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_RMD160;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_DIGEST_SHA1:
|
||||
copy_digest(entry, sha1, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_SHA1;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_DIGEST_SHA256:
|
||||
copy_digest(entry, sha256, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_SHA256;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_DIGEST_SHA384:
|
||||
copy_digest(entry, sha384, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_SHA384;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_DIGEST_SHA512:
|
||||
copy_digest(entry, sha512, digest);
|
||||
entry->mset_digest |= AE_MSET_DIGEST_SHA512;
|
||||
break;
|
||||
default:
|
||||
return ARCHIVE_WARN;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define ARCHIVE_ENTRY_H_INCLUDED
|
||||
|
||||
/* Note: Compiler will complain if this does not match archive.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3007007
|
||||
#define ARCHIVE_VERSION_NUMBER 3008001
|
||||
|
||||
/*
|
||||
* Note: archive_entry.h is for use outside of libarchive; the
|
||||
@@ -40,8 +40,11 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
#include <stdint.h>
|
||||
#include <stdint.h> /* for C99 int64_t, etc. */
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* time_t is slated to be removed from public includes in 4.0 */
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
@@ -55,12 +58,15 @@
|
||||
#define __LA_INT64_T_DEFINED
|
||||
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
|
||||
typedef __int64 la_int64_t;
|
||||
typedef unsigned __int64 la_uint64_t;
|
||||
# else
|
||||
#include <unistd.h>
|
||||
# if defined(_SCO_DS) || defined(__osf__)
|
||||
typedef long long la_int64_t;
|
||||
typedef unsigned long long la_uint64_t;
|
||||
# else
|
||||
typedef int64_t la_int64_t;
|
||||
typedef uint64_t la_uint64_t;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -96,6 +102,30 @@ typedef ssize_t la_ssize_t;
|
||||
# define __LA_MODE_T mode_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for time_t */
|
||||
#define __LA_TIME_T time_t
|
||||
#else
|
||||
/* Use 64-bits integer types for time_t */
|
||||
#define __LA_TIME_T la_int64_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Use the platform types for dev_t */
|
||||
#define __LA_DEV_T dev_t
|
||||
#else
|
||||
/* Use 64-bits integer types for dev_t */
|
||||
#define __LA_DEV_T la_int64_t
|
||||
#endif
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Libarchive 3.x used signed int64 for inode numbers */
|
||||
#define __LA_INO_T la_int64_t
|
||||
#else
|
||||
/* Switch to unsigned for libarchive 4.0 */
|
||||
#define __LA_INO_T la_uint64_t
|
||||
#endif
|
||||
|
||||
/* Large file support for Android */
|
||||
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
|
||||
#include "android_lf.h"
|
||||
@@ -127,7 +157,8 @@ typedef ssize_t la_ssize_t;
|
||||
# define __LA_DECL
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3 || \
|
||||
(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define __LA_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
# define __LA_DEPRECATED
|
||||
@@ -235,19 +266,19 @@ __LA_DECL struct archive_entry *archive_entry_new2(struct archive *);
|
||||
* 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 __LA_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 __LA_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 __LA_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 __LA_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_DEV_T archive_entry_devmajor(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_devminor(struct archive_entry *);
|
||||
__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_filetype_is_set(struct archive_entry *);
|
||||
__LA_DECL void archive_entry_fflags(struct archive_entry *,
|
||||
@@ -264,8 +295,8 @@ __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 int archive_entry_hardlink_is_set(struct archive_entry *);
|
||||
__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *);
|
||||
__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *);
|
||||
__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *);
|
||||
__LA_DECL __LA_INO_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 *);
|
||||
@@ -278,9 +309,9 @@ __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 int archive_entry_perm_is_set(struct archive_entry *);
|
||||
__LA_DECL int archive_entry_rdev_is_set(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 __LA_DEV_T archive_entry_rdev(struct archive_entry *);
|
||||
__LA_DECL __LA_DEV_T archive_entry_rdevmajor(struct archive_entry *);
|
||||
__LA_DECL __LA_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 *);
|
||||
@@ -309,18 +340,18 @@ __LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
|
||||
* always copied.
|
||||
*/
|
||||
|
||||
__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
|
||||
__LA_DECL void archive_entry_set_atime(struct archive_entry *, __LA_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_set_birthtime(struct archive_entry *, __LA_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_set_ctime(struct archive_entry *, __LA_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_dev(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_devminor(struct archive_entry *, __LA_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 */);
|
||||
@@ -343,15 +374,15 @@ __LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const cha
|
||||
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
|
||||
__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
|
||||
__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t);
|
||||
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, la_int64_t);
|
||||
__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INO_T);
|
||||
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INO_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_set_mtime(struct archive_entry *, __LA_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 *);
|
||||
@@ -360,9 +391,9 @@ __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_rdev(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, __LA_DEV_T);
|
||||
__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, __LA_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 *);
|
||||
@@ -418,6 +449,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
|
||||
#define ARCHIVE_ENTRY_DIGEST_SHA512 0x00000006
|
||||
|
||||
__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
|
||||
__LA_DECL int archive_entry_set_digest(struct archive_entry *, int, const unsigned char *);
|
||||
|
||||
/*
|
||||
* ACL routines. This used to simply store and return text-format ACL
|
||||
|
||||
@@ -280,6 +280,10 @@ find_entry(struct archive_entry_linkresolver *res,
|
||||
dev_t dev;
|
||||
int64_t ino;
|
||||
|
||||
if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Free a held entry. */
|
||||
if (res->spare != NULL) {
|
||||
archive_entry_free(res->spare->canonical);
|
||||
@@ -369,6 +373,10 @@ insert_entry(struct archive_entry_linkresolver *res,
|
||||
struct links_entry *le;
|
||||
size_t hash, bucket;
|
||||
|
||||
if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Add this entry to the links cache. */
|
||||
le = calloc(1, sizeof(struct links_entry));
|
||||
if (le == NULL)
|
||||
|
||||
@@ -87,4 +87,4 @@ int _archive_entry_copy_symlink_l(struct archive_entry *,
|
||||
int _archive_entry_copy_uname_l(struct archive_entry *,
|
||||
const char *, size_t, struct archive_string_conv *);
|
||||
|
||||
#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
|
||||
@@ -174,6 +174,13 @@ struct archive_entry {
|
||||
size_t mac_metadata_size;
|
||||
|
||||
/* Digest support. */
|
||||
#define AE_MSET_DIGEST_MD5 1
|
||||
#define AE_MSET_DIGEST_RMD160 2
|
||||
#define AE_MSET_DIGEST_SHA1 4
|
||||
#define AE_MSET_DIGEST_SHA256 8
|
||||
#define AE_MSET_DIGEST_SHA384 16
|
||||
#define AE_MSET_DIGEST_SHA512 32
|
||||
uint_least32_t mset_digest;
|
||||
struct ae_digest digest;
|
||||
|
||||
/* ACL support. */
|
||||
@@ -195,8 +202,4 @@ struct archive_entry {
|
||||
int ae_symlink_type;
|
||||
};
|
||||
|
||||
int
|
||||
archive_entry_set_digest(struct archive_entry *entry, int type,
|
||||
const unsigned char *digest);
|
||||
|
||||
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
|
||||
@@ -116,4 +116,4 @@ struct archive_hmac {
|
||||
};
|
||||
|
||||
extern const struct archive_hmac __archive_hmac;
|
||||
#endif /* ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
|
||||
@@ -35,14 +35,17 @@
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#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"
|
||||
#include "archive_time_private.h"
|
||||
|
||||
struct match {
|
||||
struct match *next;
|
||||
@@ -53,8 +56,7 @@ struct match {
|
||||
struct match_list {
|
||||
struct match *first;
|
||||
struct match **last;
|
||||
int count;
|
||||
int unmatched_count;
|
||||
size_t unmatched_count;
|
||||
struct match *unmatched_next;
|
||||
int unmatched_eof;
|
||||
};
|
||||
@@ -73,7 +75,6 @@ struct match_file {
|
||||
struct entry_list {
|
||||
struct match_file *first;
|
||||
struct match_file **last;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct id_array {
|
||||
@@ -144,12 +145,15 @@ 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 *);
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
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 *);
|
||||
#else
|
||||
static int cmp_key_wcs(const struct archive_rb_node *, const void *);
|
||||
static int cmp_node_wcs(const struct archive_rb_node *,
|
||||
const struct archive_rb_node *);
|
||||
#endif
|
||||
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 *);
|
||||
@@ -187,14 +191,14 @@ 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
|
||||
#define get_date archive_parse_date
|
||||
|
||||
static const struct archive_rb_tree_ops rb_ops_mbs = {
|
||||
static const struct archive_rb_tree_ops rb_ops = {
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
cmp_node_mbs, cmp_key_mbs
|
||||
};
|
||||
|
||||
static const struct archive_rb_tree_ops rb_ops_wcs = {
|
||||
#else
|
||||
cmp_node_wcs, cmp_key_wcs
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -228,7 +232,7 @@ archive_match_new(void)
|
||||
a->recursive_include = 1;
|
||||
match_list_init(&(a->inclusions));
|
||||
match_list_init(&(a->exclusions));
|
||||
__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
|
||||
__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops);
|
||||
entry_list_init(&(a->exclusion_entry_list));
|
||||
match_list_init(&(a->inclusion_unames));
|
||||
match_list_init(&(a->inclusion_gnames));
|
||||
@@ -507,7 +511,9 @@ archive_match_path_unmatched_inclusions(struct archive *_a)
|
||||
ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
|
||||
a = (struct archive_match *)_a;
|
||||
|
||||
return (a->inclusions.unmatched_count);
|
||||
if (a->inclusions.unmatched_count > (size_t)INT_MAX)
|
||||
return INT_MAX;
|
||||
return (int)(a->inclusions.unmatched_count);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -650,7 +656,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (*b == 0x0d || *b == 0x0a) {
|
||||
if (*b == 0x0d || *b == 0x0a) {
|
||||
found_separator = 1;
|
||||
break;
|
||||
}
|
||||
@@ -735,7 +741,7 @@ path_excluded(struct archive_match *a, int mbs, const void *pathname)
|
||||
}
|
||||
}
|
||||
|
||||
/* Exclusions take priority */
|
||||
/* Exclusions take priority. */
|
||||
for (match = a->exclusions.first; match != NULL;
|
||||
match = match->next){
|
||||
r = match_path_exclusion(a, match, mbs, pathname);
|
||||
@@ -834,7 +840,6 @@ match_list_init(struct match_list *list)
|
||||
{
|
||||
list->first = NULL;
|
||||
list->last = &(list->first);
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -855,7 +860,6 @@ match_list_add(struct match_list *list, struct match *m)
|
||||
{
|
||||
*list->last = m;
|
||||
list->last = &(m->next);
|
||||
list->count++;
|
||||
list->unmatched_count++;
|
||||
}
|
||||
|
||||
@@ -1145,36 +1149,15 @@ set_timefilter_date_w(struct archive_match *a, int timetype,
|
||||
}
|
||||
|
||||
#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)
|
||||
const FILETIME* ftLastWriteTime, const FILETIME* ftCreationTime)
|
||||
{
|
||||
ULARGE_INTEGER utc;
|
||||
time_t ctime_sec, mtime_sec;
|
||||
long ctime_ns, mtime_ns;
|
||||
uint32_t 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;
|
||||
}
|
||||
ntfs_to_unix(FILETIME_to_ntfs(ftLastWriteTime), &mtime_sec, &mtime_ns);
|
||||
ntfs_to_unix(FILETIME_to_ntfs(ftCreationTime), &ctime_sec, &ctime_ns);
|
||||
return set_timefilter(a, timetype,
|
||||
mtime_sec, mtime_ns, ctime_sec, ctime_ns);
|
||||
}
|
||||
@@ -1199,9 +1182,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
FindClose(h);
|
||||
return set_timefilter_find_data(a, timetype,
|
||||
d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
|
||||
d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
|
||||
return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1223,9 +1204,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
FindClose(h);
|
||||
return set_timefilter_find_data(a, timetype,
|
||||
d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
|
||||
d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
|
||||
return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime);
|
||||
}
|
||||
|
||||
#else /* _WIN32 && !__CYGWIN__ */
|
||||
@@ -1300,6 +1279,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
|
||||
/*
|
||||
* Call back functions for archive_rb.
|
||||
*/
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
static int
|
||||
cmp_node_mbs(const struct archive_rb_node *n1,
|
||||
const struct archive_rb_node *n2)
|
||||
@@ -1316,7 +1296,7 @@ cmp_node_mbs(const struct archive_rb_node *n1,
|
||||
return (-1);
|
||||
return (strcmp(p1, p2));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmp_key_mbs(const struct archive_rb_node *n, const void *key)
|
||||
{
|
||||
@@ -1328,7 +1308,7 @@ cmp_key_mbs(const struct archive_rb_node *n, const void *key)
|
||||
return (-1);
|
||||
return (strcmp(p, (const char *)key));
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
cmp_node_wcs(const struct archive_rb_node *n1,
|
||||
const struct archive_rb_node *n2)
|
||||
@@ -1345,7 +1325,7 @@ cmp_node_wcs(const struct archive_rb_node *n1,
|
||||
return (-1);
|
||||
return (wcscmp(p1, p2));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmp_key_wcs(const struct archive_rb_node *n, const void *key)
|
||||
{
|
||||
@@ -1357,13 +1337,13 @@ cmp_key_wcs(const struct archive_rb_node *n, const void *key)
|
||||
return (-1);
|
||||
return (wcscmp(p, (const wchar_t *)key));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
entry_list_init(struct entry_list *list)
|
||||
{
|
||||
list->first = NULL;
|
||||
list->last = &(list->first);
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1384,7 +1364,6 @@ entry_list_add(struct entry_list *list, struct match_file *file)
|
||||
{
|
||||
*list->last = file;
|
||||
list->last = &(file->next);
|
||||
list->count++;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1407,9 +1386,7 @@ add_entry(struct archive_match *a, int flag,
|
||||
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);
|
||||
@@ -1417,7 +1394,6 @@ add_entry(struct archive_match *a, int flag,
|
||||
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);
|
||||
@@ -1542,16 +1518,13 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
|
||||
}
|
||||
|
||||
/* If there is no exclusion list, include the file. */
|
||||
if (a->exclusion_entry_list.count == 0)
|
||||
if (a->exclusion_entry_list.first == NULL)
|
||||
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);
|
||||
@@ -1707,7 +1680,7 @@ archive_match_owner_excluded(struct archive *_a,
|
||||
static int
|
||||
add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
|
||||
{
|
||||
unsigned i;
|
||||
size_t i;
|
||||
|
||||
if (ids->count + 1 >= ids->size) {
|
||||
void *p;
|
||||
@@ -1744,10 +1717,10 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
|
||||
static int
|
||||
match_owner_id(struct id_array *ids, int64_t id)
|
||||
{
|
||||
unsigned b, m, t;
|
||||
size_t b, m, t;
|
||||
|
||||
t = 0;
|
||||
b = (unsigned)ids->count;
|
||||
b = ids->count;
|
||||
while (t < b) {
|
||||
m = (t + b)>>1;
|
||||
if (ids->ids[m] == id)
|
||||
@@ -1842,7 +1815,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (a->inclusion_unames.count) {
|
||||
if (a->inclusion_unames.first != NULL) {
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
r = match_owner_name_wcs(a, &(a->inclusion_unames),
|
||||
archive_entry_uname_w(entry));
|
||||
@@ -1856,7 +1829,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
|
||||
return (r);
|
||||
}
|
||||
|
||||
if (a->inclusion_gnames.count) {
|
||||
if (a->inclusion_gnames.first != NULL) {
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
r = match_owner_name_wcs(a, &(a->inclusion_gnames),
|
||||
archive_entry_gname_w(entry));
|
||||
@@ -1871,4 +1844,3 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ parse_option(const char **str,
|
||||
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)
|
||||
unsigned int magic, const char *fn, option_handler use_option)
|
||||
{
|
||||
const char *mp, *op, *vp;
|
||||
int r;
|
||||
@@ -97,7 +97,7 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
|
||||
|
||||
int
|
||||
_archive_set_options(struct archive *a, const char *options,
|
||||
int magic, const char *fn, option_handler use_option)
|
||||
unsigned int magic, const char *fn, option_handler use_option)
|
||||
{
|
||||
int allok = 1, anyok = 0, ignore_mod_err = 0, r;
|
||||
char *data;
|
||||
|
||||
@@ -35,11 +35,11 @@ typedef int (*option_handler)(struct archive *a,
|
||||
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);
|
||||
unsigned 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);
|
||||
unsigned int magic, const char *fn, option_handler use_option);
|
||||
|
||||
int
|
||||
_archive_set_either_option(struct archive *a,
|
||||
|
||||
@@ -46,4 +46,4 @@ pack_t pack_native;
|
||||
(((y) << 12) & 0xfff00000) | \
|
||||
(((y) << 0) & 0x000000ff)))
|
||||
|
||||
#endif /* ARCHIVE_PACK_DEV_H */
|
||||
#endif /* !ARCHIVE_PACK_DEV_H */
|
||||
+56
-9
@@ -35,8 +35,7 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define __LIBARCHIVE_BUILD 1
|
||||
#include "archive_getdate.h"
|
||||
#include "archive.h"
|
||||
|
||||
/* Basic time units. */
|
||||
#define EPOCH 1970
|
||||
@@ -820,6 +819,23 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
|
||||
Timezone, DSTmaybe));
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses and consumes an unsigned number.
|
||||
* Returns 1 if any number is parsed. Otherwise, *value is unchanged.
|
||||
*/
|
||||
static char
|
||||
consume_unsigned_number(const char **in, time_t *value)
|
||||
{
|
||||
char c;
|
||||
if (isdigit((unsigned char)(c = **in))) {
|
||||
for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
|
||||
*value = 10 * *value + c - '0';
|
||||
(*in)--;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokenizer.
|
||||
*/
|
||||
@@ -861,7 +877,8 @@ nexttoken(const char **in, time_t *value)
|
||||
&& i < sizeof(buff)-1) {
|
||||
if (*src != '.') {
|
||||
if (isupper((unsigned char)*src))
|
||||
buff[i++] = tolower((unsigned char)*src);
|
||||
buff[i++] = (char)tolower(
|
||||
(unsigned char)*src);
|
||||
else
|
||||
buff[i++] = *src;
|
||||
}
|
||||
@@ -895,10 +912,7 @@ nexttoken(const char **in, time_t *value)
|
||||
* 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)--;
|
||||
if (consume_unsigned_number(in, value)) {
|
||||
return (tUNUMBER);
|
||||
}
|
||||
|
||||
@@ -914,7 +928,7 @@ 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 = (
|
||||
long days = (
|
||||
/* difference in day of year */
|
||||
a->tm_yday - b->tm_yday
|
||||
/* + intervening leap days */
|
||||
@@ -929,6 +943,32 @@ difftm (struct tm *a, struct tm *b)
|
||||
+ (a->tm_sec - b->tm_sec));
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a Unix epoch timestamp (seconds).
|
||||
* This supports a subset of what GNU tar accepts from black box testing,
|
||||
* but covers common use cases.
|
||||
*/
|
||||
static time_t
|
||||
parse_unix_epoch(const char *p)
|
||||
{
|
||||
time_t epoch;
|
||||
|
||||
/* may begin with + */
|
||||
if (*p == '+') {
|
||||
p++;
|
||||
}
|
||||
|
||||
/* followed by some number */
|
||||
if (!consume_unsigned_number(&p, &epoch))
|
||||
return (time_t)-1;
|
||||
|
||||
/* ...and nothing else */
|
||||
if (*p != '\0')
|
||||
return (time_t)-1;
|
||||
|
||||
return epoch;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* The public function.
|
||||
@@ -936,7 +976,7 @@ difftm (struct tm *a, struct tm *b)
|
||||
* TODO: tokens[] array should be dynamically sized.
|
||||
*/
|
||||
time_t
|
||||
__archive_get_date(time_t now, const char *p)
|
||||
archive_parse_date(time_t now, const char *p)
|
||||
{
|
||||
struct token tokens[256];
|
||||
struct gdstate _gds;
|
||||
@@ -948,6 +988,13 @@ __archive_get_date(time_t now, const char *p)
|
||||
time_t tod;
|
||||
long tzone;
|
||||
|
||||
/*
|
||||
* @-prefixed Unix epoch timestamps (seconds)
|
||||
* Skip the complex tokenizer - We do not want to accept strings like "@tenth"
|
||||
*/
|
||||
if (*p == '@')
|
||||
return parse_unix_epoch(p + 1);
|
||||
|
||||
/* Clear out the parsed token array. */
|
||||
memset(tokens, 0, sizeof(tokens));
|
||||
/* Initialize the parser state. */
|
||||
@@ -61,6 +61,11 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* For cygwin, to avoid missing LONG, ULONG, PUCHAR, ... definitions */
|
||||
#ifdef __CYGWIN__
|
||||
#include <windef.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
|
||||
|
||||
@@ -50,4 +50,4 @@
|
||||
#define ARCHIVE_ACL_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_PLATFORM_ACL_H_INCLUDED */
|
||||
@@ -42,4 +42,4 @@
|
||||
#define ARCHIVE_XATTR_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#endif /* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
|
||||
@@ -287,9 +287,14 @@ static void *AllocUnits(CPpmd7 *p, unsigned indx)
|
||||
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); }
|
||||
#define MyMem12Cpy(dest, src, num) do { \
|
||||
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); \
|
||||
} while (0)
|
||||
|
||||
static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
|
||||
{
|
||||
|
||||
@@ -242,9 +242,14 @@ static void *AllocUnits(CPpmd8 *p, unsigned indx)
|
||||
return AllocUnitsRare(p, indx);
|
||||
}
|
||||
|
||||
#define MyMem12Cpy(dest, src, num) \
|
||||
{ UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \
|
||||
do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); }
|
||||
#define MyMem12Cpy(dest, src, num) do { \
|
||||
UInt32 *d = (UInt32 *)dest; \
|
||||
const UInt32 *z = (const UInt32 *)src; \
|
||||
UInt32 n = num; \
|
||||
do { \
|
||||
d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; \
|
||||
} while (--n); \
|
||||
} while (0)
|
||||
|
||||
static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
|
||||
{
|
||||
@@ -341,7 +346,9 @@ static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
|
||||
(p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
|
||||
#define RESET_TEXT(offs) do { \
|
||||
p->Text = p->Base + p->AlignOffset + (offs); \
|
||||
} while (0)
|
||||
|
||||
static void RestartModel(CPpmd8 *p)
|
||||
{
|
||||
|
||||
@@ -109,8 +109,12 @@ typedef struct
|
||||
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++); }
|
||||
#define Ppmd_See_Update(p) do { \
|
||||
if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) { \
|
||||
(p)->Summ <<= 1; \
|
||||
(p)->Count = (Byte)(3 << (p)->Shift++); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -144,8 +148,12 @@ typedef
|
||||
#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; }}
|
||||
#define PPMD_SetAllBitsIn256Bytes(p) do { \
|
||||
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; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@@ -33,4 +33,4 @@
|
||||
/* Random number generator. */
|
||||
int archive_random(void *buf, size_t nbytes);
|
||||
|
||||
#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
|
||||
#endif /* !ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
|
||||
@@ -110,4 +110,4 @@ struct archive_rb_node *
|
||||
__archive_rb_tree_iterate(struct archive_rb_tree *,
|
||||
struct archive_rb_node *, const unsigned int);
|
||||
|
||||
#endif /* ARCHIVE_RB_H_*/
|
||||
#endif /* !ARCHIVE_RB_H_INCLUDED */
|
||||
@@ -176,15 +176,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
|
||||
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;
|
||||
|
||||
@@ -96,6 +96,10 @@ archive_read_append_filter(struct archive *_a, int code)
|
||||
strcpy(str, "lzip");
|
||||
r1 = archive_read_support_filter_lzip(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZOP:
|
||||
strcpy(str, "lzop");
|
||||
r1 = archive_read_support_filter_lzop(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LRZIP:
|
||||
strcpy(str, "lrzip");
|
||||
r1 = archive_read_support_filter_lrzip(_a);
|
||||
|
||||
@@ -888,7 +888,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
|
||||
count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
|
||||
fm = (struct fiemap *)buff;
|
||||
fm->fm_start = 0;
|
||||
fm->fm_length = ~0ULL;;
|
||||
fm->fm_length = ~0ULL;
|
||||
fm->fm_flags = FIEMAP_FLAG_SYNC;
|
||||
fm->fm_extent_count = count;
|
||||
do_fiemap = 1;
|
||||
|
||||
@@ -276,7 +276,7 @@ tree_dir_next_posix(struct tree *t);
|
||||
#endif
|
||||
|
||||
/* Initiate/terminate a tree traversal. */
|
||||
static struct tree *tree_open(const char *, int, int);
|
||||
static struct tree *tree_open(const char *, char, int);
|
||||
static struct tree *tree_reopen(struct tree *, const char *, int);
|
||||
static void tree_close(struct tree *);
|
||||
static void tree_free(struct tree *);
|
||||
@@ -514,7 +514,7 @@ _archive_read_close(struct archive *_a)
|
||||
|
||||
static void
|
||||
setup_symlink_mode(struct archive_read_disk *a, char symlink_mode,
|
||||
int follow_symlinks)
|
||||
char follow_symlinks)
|
||||
{
|
||||
a->symlink_mode = symlink_mode;
|
||||
a->follow_symlinks = follow_symlinks;
|
||||
@@ -778,7 +778,8 @@ _archive_read_data_block(struct archive *_a, const void **buff,
|
||||
*/
|
||||
if (t->current_sparse->offset > t->entry_total) {
|
||||
if (lseek(t->entry_fd,
|
||||
(off_t)t->current_sparse->offset, SEEK_SET) < 0) {
|
||||
(off_t)t->current_sparse->offset, SEEK_SET) !=
|
||||
t->current_sparse->offset) {
|
||||
archive_set_error(&a->archive, errno, "Seek error");
|
||||
r = ARCHIVE_FATAL;
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
@@ -2180,7 +2181,7 @@ tree_append(struct tree *t, const char *name, size_t name_length)
|
||||
* Open a directory tree for traversal.
|
||||
*/
|
||||
static struct tree *
|
||||
tree_open(const char *path, int symlink_mode, int restore_time)
|
||||
tree_open(const char *path, char symlink_mode, int restore_time)
|
||||
{
|
||||
struct tree *t;
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ struct archive_read_disk {
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* we're following symlinks for the current item, governed by the above
|
||||
* symlink_mode. 'L' sets this true, 'P' sets it false, 'H' changes it
|
||||
* as we traverse.
|
||||
*/
|
||||
char follow_symlinks; /* Either 'L' or 'P'. */
|
||||
char follow_symlinks; /* Either 0 or 1. */
|
||||
|
||||
/* Directory traversals. */
|
||||
struct tree *tree;
|
||||
|
||||
@@ -37,8 +37,10 @@
|
||||
.Nm archive_read_support_format_lha ,
|
||||
.Nm archive_read_support_format_mtree ,
|
||||
.Nm archive_read_support_format_rar ,
|
||||
.Nm archive_read_support_format_rar5 ,
|
||||
.Nm archive_read_support_format_raw ,
|
||||
.Nm archive_read_support_format_tar ,
|
||||
.Nm archive_read_support_format_warc ,
|
||||
.Nm archive_read_support_format_xar ,
|
||||
.Nm archive_read_support_format_zip
|
||||
.Nd functions for reading streaming archives
|
||||
@@ -70,10 +72,14 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_rar "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_rar5 "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_raw "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_tar "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_warc "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_xar "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_read_support_format_zip "struct archive *"
|
||||
@@ -89,8 +95,10 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Fn archive_read_support_format_lha ,
|
||||
.Fn archive_read_support_format_mtree ,
|
||||
.Fn archive_read_support_format_rar ,
|
||||
.Fn archive_read_support_format_rar5 ,
|
||||
.Fn archive_read_support_format_raw ,
|
||||
.Fn archive_read_support_format_tar ,
|
||||
.Fn archive_read_support_format_warc ,
|
||||
.Fn archive_read_support_format_xar ,
|
||||
.Fn archive_read_support_format_zip
|
||||
.Xc
|
||||
@@ -100,6 +108,13 @@ For example,
|
||||
.Fn archive_read_support_format_tar
|
||||
enables support for a variety of standard tar formats, old-style tar,
|
||||
ustar, pax interchange format, and many common variants.
|
||||
.Fn archive_read_support_format_zip
|
||||
enables support for both the streaming and the seeking zip readers,
|
||||
which can separately be enabled by respectively
|
||||
.Fn archive_read_support_format_zip_streamable
|
||||
and
|
||||
.Fn archive_read_support_format_zip_seekable
|
||||
.
|
||||
.It Fn archive_read_support_format_all
|
||||
Enables support for all available formats except the
|
||||
.Dq raw
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
struct read_fd_data {
|
||||
int fd;
|
||||
size_t block_size;
|
||||
int64_t size;
|
||||
char use_lseek;
|
||||
void *buffer;
|
||||
};
|
||||
@@ -95,6 +96,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
|
||||
mine->use_lseek = 1;
|
||||
mine->size = st.st_size;
|
||||
}
|
||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||
setmode(mine->fd, O_BINARY);
|
||||
@@ -131,7 +133,7 @@ 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;
|
||||
off_t skip = (off_t)request;
|
||||
int64_t old_offset, new_offset;
|
||||
int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */
|
||||
|
||||
@@ -140,20 +142,25 @@ file_skip(struct archive *a, void *client_data, int64_t request)
|
||||
|
||||
/* Reduce a request that would overflow the 'skip' variable. */
|
||||
if (sizeof(request) > sizeof(skip)) {
|
||||
int64_t max_skip =
|
||||
const int64_t max_skip =
|
||||
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
|
||||
if (request > max_skip)
|
||||
skip = max_skip;
|
||||
skip = (off_t)max_skip;
|
||||
}
|
||||
|
||||
/* Reduce request to the next smallest multiple of block_size */
|
||||
request = (request / mine->block_size) * mine->block_size;
|
||||
if (request == 0)
|
||||
/* Reduce 'skip' to the next smallest multiple of block_size */
|
||||
skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size);
|
||||
if (skip == 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 ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
|
||||
if (old_offset >= mine->size ||
|
||||
skip > mine->size - old_offset) {
|
||||
/* Do not seek past end of file. */
|
||||
errno = ESPIPE;
|
||||
} else if ((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;
|
||||
@@ -178,11 +185,24 @@ 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;
|
||||
off_t seek = (off_t)request;
|
||||
int64_t r;
|
||||
int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Reduce a request that would overflow the 'seek' variable. */
|
||||
if (sizeof(request) > sizeof(seek)) {
|
||||
const int64_t max_seek =
|
||||
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
|
||||
const int64_t min_seek = ~max_seek;
|
||||
if (request > max_seek)
|
||||
seek = (off_t)max_seek;
|
||||
else if (request < min_seek)
|
||||
seek = (off_t)min_seek;
|
||||
}
|
||||
|
||||
r = lseek(mine->fd, seek, whence);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -52,13 +52,15 @@
|
||||
struct read_FILE_data {
|
||||
FILE *f;
|
||||
size_t block_size;
|
||||
int64_t 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);
|
||||
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, int);
|
||||
static int64_t FILE_skip(struct archive *, void *, int64_t);
|
||||
|
||||
int
|
||||
archive_read_open_FILE(struct archive *a, FILE *f)
|
||||
@@ -69,7 +71,7 @@ archive_read_open_FILE(struct archive *a, FILE *f)
|
||||
void *b;
|
||||
|
||||
archive_clear_error(a);
|
||||
mine = malloc(sizeof(*mine));
|
||||
mine = calloc(1, sizeof(*mine));
|
||||
b = malloc(block_size);
|
||||
if (mine == NULL || b == NULL) {
|
||||
archive_set_error(a, ENOMEM, "No memory");
|
||||
@@ -90,22 +92,23 @@ archive_read_open_FILE(struct archive *a, FILE *f)
|
||||
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;
|
||||
mine->size = st.st_size;
|
||||
}
|
||||
|
||||
#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_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)
|
||||
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;
|
||||
@@ -119,16 +122,17 @@ file_read(struct archive *a, void *client_data, const void **buff)
|
||||
}
|
||||
|
||||
static int64_t
|
||||
file_skip(struct archive *a, void *client_data, int64_t request)
|
||||
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
|
||||
#if HAVE__FSEEKI64
|
||||
int64_t skip = request;
|
||||
#elif HAVE_FSEEKO
|
||||
off_t skip = (off_t)request;
|
||||
#else
|
||||
long skip = (long)request;
|
||||
#endif
|
||||
int64_t old_offset, new_offset = -1;
|
||||
int skip_bits = sizeof(skip) * 8 - 1;
|
||||
|
||||
(void)a; /* UNUSED */
|
||||
@@ -144,7 +148,7 @@ file_skip(struct archive *a, void *client_data, int64_t request)
|
||||
|
||||
/* If request is too big for a long or an off_t, reduce it. */
|
||||
if (sizeof(request) > sizeof(skip)) {
|
||||
int64_t max_skip =
|
||||
const int64_t max_skip =
|
||||
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
|
||||
if (request > max_skip)
|
||||
skip = max_skip;
|
||||
@@ -152,23 +156,92 @@ file_skip(struct archive *a, void *client_data, int64_t request)
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/* fileno() isn't safe on all platforms ... see above. */
|
||||
if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
|
||||
old_offset = lseek(fileno(mine->f), 0, SEEK_CUR);
|
||||
#elif HAVE__FSEEKI64
|
||||
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
|
||||
old_offset = _ftelli64(mine->f);
|
||||
#elif HAVE_FSEEKO
|
||||
if (fseeko(mine->f, skip, SEEK_CUR) != 0)
|
||||
old_offset = ftello(mine->f);
|
||||
#else
|
||||
if (fseek(mine->f, skip, SEEK_CUR) != 0)
|
||||
old_offset = ftell(mine->f);
|
||||
#endif
|
||||
{
|
||||
mine->can_skip = 0;
|
||||
return (0);
|
||||
if (old_offset >= 0) {
|
||||
if (old_offset < mine->size &&
|
||||
skip <= mine->size - old_offset) {
|
||||
#ifdef __ANDROID__
|
||||
new_offset = lseek(fileno(mine->f), skip, SEEK_CUR);
|
||||
#elif HAVE__FSEEKI64
|
||||
if (_fseeki64(mine->f, skip, SEEK_CUR) == 0)
|
||||
new_offset = _ftelli64(mine->f);
|
||||
#elif HAVE_FSEEKO
|
||||
if (fseeko(mine->f, skip, SEEK_CUR) == 0)
|
||||
new_offset = ftello(mine->f);
|
||||
#else
|
||||
if (fseek(mine->f, skip, SEEK_CUR) == 0)
|
||||
new_offset = ftell(mine->f);
|
||||
#endif
|
||||
if (new_offset >= 0)
|
||||
return (new_offset - old_offset);
|
||||
}
|
||||
}
|
||||
return (request);
|
||||
|
||||
mine->can_skip = 0;
|
||||
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;
|
||||
#if HAVE__FSEEKI64
|
||||
int64_t seek = request;
|
||||
#elif HAVE_FSEEKO
|
||||
off_t seek = (off_t)request;
|
||||
#else
|
||||
long seek = (long)request;
|
||||
#endif
|
||||
int seek_bits = sizeof(seek) * 8 - 1;
|
||||
(void)a; /* UNUSED */
|
||||
|
||||
/* Reduce a request that would overflow the 'seek' variable. */
|
||||
if (sizeof(request) > sizeof(seek)) {
|
||||
const int64_t max_seek =
|
||||
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
|
||||
const int64_t min_seek = ~max_seek;
|
||||
if (request > max_seek)
|
||||
seek = max_seek;
|
||||
else if (request < min_seek)
|
||||
seek = min_seek;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/* Newer Android versions have fseeko...to meditate. */
|
||||
int64_t ret = lseek(fileno(mine->f), seek, whence);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
#elif HAVE__FSEEKI64
|
||||
if (_fseeki64(mine->f, seek, whence) == 0) {
|
||||
return _ftelli64(mine->f);
|
||||
}
|
||||
#elif HAVE_FSEEKO
|
||||
if (fseeko(mine->f, seek, whence) == 0) {
|
||||
return ftello(mine->f);
|
||||
}
|
||||
#else
|
||||
if (fseek(mine->f, seek, whence) == 0) {
|
||||
return ftell(mine->f);
|
||||
}
|
||||
#endif
|
||||
/* If we arrive here, the input is corrupted or truncated so fail. */
|
||||
archive_set_error(a, errno, "Error seeking in FILE* pointer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
file_close(struct archive *a, void *client_data)
|
||||
FILE_close(struct archive *a, void *client_data)
|
||||
{
|
||||
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ struct read_file_data {
|
||||
size_t block_size;
|
||||
void *buffer;
|
||||
mode_t st_mode; /* Mode bits for opened file. */
|
||||
int64_t size;
|
||||
char use_lseek;
|
||||
enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type;
|
||||
union {
|
||||
@@ -303,7 +304,7 @@ file_open(struct archive *a, void *client_data)
|
||||
}
|
||||
if (fd < 0) {
|
||||
archive_set_error(a, errno,
|
||||
"Failed to open '%S'", wfilename);
|
||||
"Failed to open '%ls'", wfilename);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
#else
|
||||
@@ -315,7 +316,7 @@ file_open(struct archive *a, void *client_data)
|
||||
if (fstat(fd, &st) != 0) {
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
if (mine->filename_type == FNT_WCS)
|
||||
archive_set_error(a, errno, "Can't stat '%S'",
|
||||
archive_set_error(a, errno, "Can't stat '%ls'",
|
||||
wfilename);
|
||||
else
|
||||
#endif
|
||||
@@ -400,8 +401,10 @@ file_open(struct archive *a, void *client_data)
|
||||
mine->st_mode = st.st_mode;
|
||||
|
||||
/* Disk-like inputs can use lseek(). */
|
||||
if (is_disk_like)
|
||||
if (is_disk_like) {
|
||||
mine->use_lseek = 1;
|
||||
mine->size = st.st_size;
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
fail:
|
||||
@@ -447,7 +450,7 @@ file_read(struct archive *a, void *client_data, const void **buff)
|
||||
"Error reading '%s'", mine->filename.m);
|
||||
else
|
||||
archive_set_error(a, errno,
|
||||
"Error reading '%S'", mine->filename.w);
|
||||
"Error reading '%ls'", mine->filename.w);
|
||||
}
|
||||
return (bytes_read);
|
||||
}
|
||||
@@ -479,21 +482,30 @@ 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;
|
||||
int64_t old_offset, new_offset, skip = request;
|
||||
#else
|
||||
off_t old_offset, new_offset;
|
||||
off_t old_offset, new_offset, skip = (off_t)request;
|
||||
#endif
|
||||
int skip_bits = sizeof(skip) * 8 - 1;
|
||||
|
||||
/* 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);
|
||||
/* Reduce a request that would overflow the 'skip' variable. */
|
||||
if (sizeof(request) > sizeof(skip)) {
|
||||
const int64_t max_skip =
|
||||
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
|
||||
if (request > max_skip)
|
||||
skip = max_skip;
|
||||
}
|
||||
|
||||
if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
|
||||
if (old_offset >= mine->size ||
|
||||
skip > mine->size - old_offset) {
|
||||
/* Do not seek past end of file. */
|
||||
errno = ESPIPE;
|
||||
} else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
|
||||
return (new_offset - old_offset);
|
||||
}
|
||||
|
||||
/* If lseek() fails, don't bother trying again. */
|
||||
mine->use_lseek = 0;
|
||||
@@ -509,7 +521,7 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
|
||||
archive_set_error(a, errno, "Error seeking in '%s'",
|
||||
mine->filename.m);
|
||||
else
|
||||
archive_set_error(a, errno, "Error seeking in '%S'",
|
||||
archive_set_error(a, errno, "Error seeking in '%ls'",
|
||||
mine->filename.w);
|
||||
return (-1);
|
||||
}
|
||||
@@ -540,11 +552,24 @@ 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;
|
||||
off_t seek = (off_t)request;
|
||||
int64_t r;
|
||||
int seek_bits = sizeof(seek) * 8 - 1;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Reduce a request that would overflow the 'seek' variable. */
|
||||
if (sizeof(request) > sizeof(seek)) {
|
||||
const int64_t max_seek =
|
||||
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
|
||||
const int64_t min_seek = ~max_seek;
|
||||
if (request > max_seek)
|
||||
seek = (off_t)max_seek;
|
||||
else if (request < min_seek)
|
||||
seek = (off_t)min_seek;
|
||||
}
|
||||
|
||||
r = lseek(mine->fd, seek, whence);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
@@ -555,7 +580,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
|
||||
archive_set_error(a, errno, "Error seeking in '%s'",
|
||||
mine->filename.m);
|
||||
else
|
||||
archive_set_error(a, errno, "Error seeking in '%S'",
|
||||
archive_set_error(a, errno, "Error seeking in '%ls'",
|
||||
mine->filename.w);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -37,46 +37,32 @@ archive_read_support_filter_by_code(struct archive *a, int filter_code)
|
||||
switch (filter_code) {
|
||||
case ARCHIVE_FILTER_NONE:
|
||||
return archive_read_support_filter_none(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_GZIP:
|
||||
return archive_read_support_filter_gzip(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_BZIP2:
|
||||
return archive_read_support_filter_bzip2(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_COMPRESS:
|
||||
return archive_read_support_filter_compress(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZMA:
|
||||
return archive_read_support_filter_lzma(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_XZ:
|
||||
return archive_read_support_filter_xz(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_UU:
|
||||
return archive_read_support_filter_uu(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_RPM:
|
||||
return archive_read_support_filter_rpm(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZIP:
|
||||
return archive_read_support_filter_lzip(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LRZIP:
|
||||
return archive_read_support_filter_lrzip(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZOP:
|
||||
return archive_read_support_filter_lzop(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_GRZIP:
|
||||
return archive_read_support_filter_grzip(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZ4:
|
||||
return archive_read_support_filter_lz4(a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_ZSTD:
|
||||
return archive_read_support_filter_zstd(a);
|
||||
break;
|
||||
}
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -328,6 +328,7 @@ next_code(struct archive_read_filter *self)
|
||||
static int debug_buff[1024];
|
||||
static unsigned debug_index;
|
||||
|
||||
again:
|
||||
code = newcode = getbits(self, state->bits);
|
||||
if (code < 0)
|
||||
return (code);
|
||||
@@ -360,7 +361,7 @@ next_code(struct archive_read_filter *self)
|
||||
state->section_end_code = (1 << state->bits) - 1;
|
||||
state->free_ent = 257;
|
||||
state->oldcode = -1;
|
||||
return (next_code(self));
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (code > state->free_ent
|
||||
|
||||
@@ -323,7 +323,6 @@ lz4_filter_read(struct archive_read_filter *self, const void **p)
|
||||
archive_set_error(&self->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Program error.");
|
||||
return (ARCHIVE_FATAL);
|
||||
break;
|
||||
}
|
||||
|
||||
while (state->stage == SELECT_STREAM) {
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -50,6 +53,7 @@
|
||||
#include "archive_ppmd7_private.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
#include "archive_time_private.h"
|
||||
#include "archive_endian.h"
|
||||
|
||||
#ifndef HAVE_ZLIB_H
|
||||
@@ -59,7 +63,26 @@
|
||||
#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"
|
||||
#define SFX_MIN_ADDR 0x27000
|
||||
#define SFX_MAX_ADDR 0x60000
|
||||
#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
|
||||
|
||||
/*
|
||||
* PE format
|
||||
*/
|
||||
#define PE_DOS_HDR_LEN 0x40
|
||||
#define PE_DOS_HDR_ELFANEW_OFFSET 0x3c
|
||||
#define PE_COFF_HDR_LEN 0x18
|
||||
#define PE_COFF_HDR_SEC_CNT_OFFSET 0x6
|
||||
#define PE_COFF_HDR_OPT_SZ_OFFSET 0x14
|
||||
#define PE_SEC_HDR_LEN 0x28
|
||||
#define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14
|
||||
#define PE_SEC_HDR_RAW_SZ_OFFSET 0x10
|
||||
|
||||
/*
|
||||
* ELF format
|
||||
*/
|
||||
#define ELF_HDR_MIN_LEN 0x34
|
||||
#define ELF_HDR_EI_CLASS_OFFSET 0x04
|
||||
#define ELF_HDR_EI_DATA_OFFSET 0x05
|
||||
|
||||
/*
|
||||
* Codec ID
|
||||
@@ -83,6 +106,7 @@
|
||||
#define _7Z_ARM 0x03030501
|
||||
#define _7Z_ARMTHUMB 0x03030701
|
||||
#define _7Z_ARM64 0xa
|
||||
#define _7Z_RISCV 0xb
|
||||
#define _7Z_SPARC 0x03030805
|
||||
|
||||
#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */
|
||||
@@ -144,7 +168,6 @@ struct _7z_digests {
|
||||
uint32_t *digests;
|
||||
};
|
||||
|
||||
|
||||
struct _7z_folder {
|
||||
uint64_t numCoders;
|
||||
struct _7z_coder {
|
||||
@@ -224,13 +247,13 @@ struct _7zip_entry {
|
||||
#define CRC32_IS_SET (1<<3)
|
||||
#define HAS_STREAM (1<<4)
|
||||
|
||||
time_t mtime;
|
||||
time_t atime;
|
||||
time_t ctime;
|
||||
long mtime_ns;
|
||||
long atime_ns;
|
||||
long ctime_ns;
|
||||
uint32_t mode;
|
||||
int64_t mtime;
|
||||
int64_t atime;
|
||||
int64_t ctime;
|
||||
uint32_t mtime_ns;
|
||||
uint32_t atime_ns;
|
||||
uint32_t ctime_ns;
|
||||
__LA_MODE_T mode;
|
||||
uint32_t attr;
|
||||
};
|
||||
|
||||
@@ -388,7 +411,6 @@ static int decode_encoded_header_info(struct archive_read *,
|
||||
static int decompress(struct archive_read *, struct _7zip *,
|
||||
void *, size_t *, const void *, size_t *);
|
||||
static ssize_t extract_pack_stream(struct archive_read *, size_t);
|
||||
static void fileTimeToUtc(uint64_t, time_t *, long *);
|
||||
static uint64_t folder_uncompressed_size(struct _7z_folder *);
|
||||
static void free_CodersInfo(struct _7z_coders_info *);
|
||||
static void free_Digest(struct _7z_digests *);
|
||||
@@ -424,7 +446,9 @@ static ssize_t read_stream(struct archive_read *, const void **, size_t,
|
||||
size_t);
|
||||
static int seek_pack(struct archive_read *);
|
||||
static int64_t skip_stream(struct archive_read *, size_t);
|
||||
static int skip_sfx(struct archive_read *, ssize_t);
|
||||
static int skip_sfx(struct archive_read *, const ssize_t);
|
||||
static ssize_t find_pe_overlay(struct archive_read *);
|
||||
static ssize_t find_elf_data_sec(struct archive_read *);
|
||||
static int slurp_central_directory(struct archive_read *, struct _7zip *,
|
||||
struct _7z_header_info *);
|
||||
static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
|
||||
@@ -435,6 +459,8 @@ static void arm_Init(struct _7zip *);
|
||||
static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
|
||||
|
||||
int
|
||||
@@ -522,15 +548,17 @@ archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
|
||||
* It may a 7-Zip SFX archive file. If first two bytes are
|
||||
* 'M' and 'Z' available on Windows or first four bytes are
|
||||
* "\x7F\x45LF" available on posix like system, seek the 7-Zip
|
||||
* signature. Although we will perform a seek when reading
|
||||
* a header, what we do not use __archive_read_seek() here is
|
||||
* due to a bidding performance.
|
||||
* signature. While find_pe_overlay can be performed without
|
||||
* performing a seek, find_elf_data_sec requires one,
|
||||
* thus a performance difference between the two is expected.
|
||||
*/
|
||||
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
|
||||
ssize_t offset = SFX_MIN_ADDR;
|
||||
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
|
||||
find_elf_data_sec(a);
|
||||
ssize_t offset = min_addr;
|
||||
ssize_t window = 4096;
|
||||
ssize_t bytes_avail;
|
||||
while (offset + window <= (SFX_MAX_ADDR)) {
|
||||
while (offset + window <= (min_addr + SFX_MAX_OFFSET)) {
|
||||
const char *buff = __archive_read_ahead(a,
|
||||
offset + window, &bytes_avail);
|
||||
if (buff == NULL) {
|
||||
@@ -580,21 +608,14 @@ check_7zip_header_in_sfx(const char *p)
|
||||
}
|
||||
|
||||
static int
|
||||
skip_sfx(struct archive_read *a, ssize_t bytes_avail)
|
||||
skip_sfx(struct archive_read *a, const ssize_t min_addr)
|
||||
{
|
||||
const void *h;
|
||||
const char *p, *q;
|
||||
size_t skip, offset;
|
||||
ssize_t bytes, window;
|
||||
|
||||
/*
|
||||
* If bytes_avail > SFX_MIN_ADDR we do not have to call
|
||||
* __archive_read_seek() at this time since we have
|
||||
* already had enough data.
|
||||
*/
|
||||
if (bytes_avail > SFX_MIN_ADDR)
|
||||
__archive_read_consume(a, SFX_MIN_ADDR);
|
||||
else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)
|
||||
if (__archive_read_seek(a, min_addr, SEEK_SET) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
offset = 0;
|
||||
@@ -627,7 +648,7 @@ skip_sfx(struct archive_read *a, ssize_t bytes_avail)
|
||||
(struct _7zip *)a->format->data;
|
||||
skip = p - (const char *)h;
|
||||
__archive_read_consume(a, skip);
|
||||
zip->seek_base = SFX_MIN_ADDR + offset + skip;
|
||||
zip->seek_base = min_addr + offset + skip;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
p += step;
|
||||
@@ -644,6 +665,207 @@ fatal:
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
find_pe_overlay(struct archive_read *a)
|
||||
{
|
||||
const char *h;
|
||||
ssize_t bytes, max_offset, offset, sec_end;
|
||||
ssize_t opt_hdr_sz, sec_cnt;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Read Dos header to find e_lfanew
|
||||
*/
|
||||
h = __archive_read_ahead(a, PE_DOS_HDR_LEN, &bytes);
|
||||
if (h == NULL || h[0] != 'M' || h[1] != 'Z') {
|
||||
break;
|
||||
}
|
||||
offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET);
|
||||
|
||||
/*
|
||||
* Read COFF header to find opt header size and sec cnt
|
||||
*/
|
||||
if (bytes < offset + PE_COFF_HDR_LEN) {
|
||||
h = __archive_read_ahead(a, offset + PE_COFF_HDR_LEN,
|
||||
&bytes);
|
||||
if (h == NULL || h[offset] != 'P' ||
|
||||
h[offset + 1] != 'E') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sec_cnt = archive_le16dec(
|
||||
h + offset + PE_COFF_HDR_SEC_CNT_OFFSET);
|
||||
opt_hdr_sz = archive_le16dec(
|
||||
h + offset + PE_COFF_HDR_OPT_SZ_OFFSET);
|
||||
|
||||
/*
|
||||
* Skip optional header
|
||||
*/
|
||||
if (opt_hdr_sz != 0) {
|
||||
offset += PE_COFF_HDR_LEN + opt_hdr_sz;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse sec table to find max raw offset (i.e., overlay)
|
||||
*/
|
||||
if (bytes < offset + sec_cnt * PE_SEC_HDR_LEN) {
|
||||
h = __archive_read_ahead(a,
|
||||
offset + sec_cnt * PE_SEC_HDR_LEN, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
max_offset = offset;
|
||||
while (sec_cnt > 0) {
|
||||
sec_end = archive_le32dec(
|
||||
h + offset + PE_SEC_HDR_RAW_SZ_OFFSET) +
|
||||
archive_le32dec(
|
||||
h + offset + PE_SEC_HDR_RAW_ADDR_OFFSET);
|
||||
if (sec_end > max_offset) {
|
||||
max_offset = sec_end;
|
||||
}
|
||||
offset += PE_SEC_HDR_LEN;
|
||||
sec_cnt--;
|
||||
}
|
||||
return (max_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* If encounter any weirdness, revert to old brute-force style search
|
||||
*/
|
||||
return (SFX_MIN_ADDR);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
find_elf_data_sec(struct archive_read *a)
|
||||
{
|
||||
const char *h;
|
||||
char big_endian, format_64;
|
||||
ssize_t bytes, min_addr = SFX_MIN_ADDR;
|
||||
uint64_t e_shoff, strtab_offset, strtab_size;
|
||||
uint16_t e_shentsize, e_shnum, e_shstrndx;
|
||||
uint16_t (*dec16)(const void *);
|
||||
uint32_t (*dec32)(const void *);
|
||||
uint64_t (*dec64)(const void *);
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Read Elf header to find bitness & endianness
|
||||
*/
|
||||
h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, &bytes);
|
||||
if (h == NULL || memcmp(h, "\x7F\x45LF", 4) != 0) {
|
||||
break;
|
||||
}
|
||||
format_64 = h[ELF_HDR_EI_CLASS_OFFSET] == 0x2;
|
||||
big_endian = h[ELF_HDR_EI_DATA_OFFSET] == 0x2;
|
||||
if (big_endian) {
|
||||
dec16 = &archive_be16dec;
|
||||
dec32 = &archive_be32dec;
|
||||
dec64 = &archive_be64dec;
|
||||
} else {
|
||||
dec16 = &archive_le16dec;
|
||||
dec32 = &archive_le32dec;
|
||||
dec64 = &archive_le64dec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read section header table info
|
||||
*/
|
||||
if (format_64) {
|
||||
e_shoff = (*dec64)(h + 0x28);
|
||||
e_shentsize = (*dec16)(h + 0x3A);
|
||||
e_shnum = (*dec16)(h + 0x3C);
|
||||
e_shstrndx = (*dec16)(h + 0x3E);
|
||||
if (e_shnum < e_shstrndx || e_shentsize < 0x28)
|
||||
break;
|
||||
|
||||
} else {
|
||||
e_shoff = (*dec32)(h + 0x20);
|
||||
e_shentsize = (*dec16)(h + 0x2E);
|
||||
e_shnum = (*dec16)(h + 0x30);
|
||||
e_shstrndx = (*dec16)(h + 0x32);
|
||||
if (e_shnum < e_shstrndx || e_shentsize < 0x18)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reading the section table to find strtab section
|
||||
*/
|
||||
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
|
||||
break;
|
||||
}
|
||||
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
}
|
||||
if (format_64) {
|
||||
strtab_offset = (*dec64)(
|
||||
h + e_shstrndx * e_shentsize + 0x18);
|
||||
strtab_size = (*dec64)(
|
||||
h + e_shstrndx * e_shentsize + 0x20);
|
||||
} else {
|
||||
strtab_offset = (*dec32)(
|
||||
h + e_shstrndx * e_shentsize + 0x10);
|
||||
strtab_size = (*dec32)(
|
||||
h + e_shstrndx * e_shentsize + 0x14);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the STRTAB section to find the .data offset
|
||||
*/
|
||||
if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) {
|
||||
break;
|
||||
}
|
||||
h = __archive_read_ahead(a, strtab_size, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
}
|
||||
ssize_t data_sym_offset = -1;
|
||||
for (size_t offset = 0; offset < strtab_size - 6; offset++) {
|
||||
if (memcmp(h + offset, ".data\00", 6) == 0) {
|
||||
data_sym_offset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data_sym_offset == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the section with the .data name
|
||||
*/
|
||||
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
|
||||
break;
|
||||
}
|
||||
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
}
|
||||
ssize_t sec_tbl_offset = 0, name_offset;
|
||||
while (e_shnum > 0) {
|
||||
name_offset = (*dec32)(h + sec_tbl_offset);
|
||||
if (name_offset == data_sym_offset) {
|
||||
if (format_64) {
|
||||
min_addr = (*dec64)(
|
||||
h + sec_tbl_offset + 0x18);
|
||||
} else {
|
||||
min_addr = (*dec32)(
|
||||
h + sec_tbl_offset + 0x10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sec_tbl_offset += e_shentsize;
|
||||
e_shnum--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
__archive_read_seek(a, 0, SEEK_SET);
|
||||
return (min_addr);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
@@ -770,7 +992,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
/* allocate for ",rdonly,hidden,system" */
|
||||
fflags_text = malloc(22 * sizeof(*fflags_text));
|
||||
if (fflags_text != NULL) {
|
||||
ptr = fflags_text;
|
||||
ptr = fflags_text;
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) {
|
||||
strcpy(ptr, ",rdonly");
|
||||
ptr = ptr + 7;
|
||||
@@ -1109,7 +1331,9 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
if (coder2->codec != _7Z_X86 &&
|
||||
coder2->codec != _7Z_X86_BCJ2 &&
|
||||
coder2->codec != _7Z_ARM &&
|
||||
coder2->codec != _7Z_ARM64) {
|
||||
coder2->codec != _7Z_ARM64 &&
|
||||
coder2->codec != _7Z_POWERPC &&
|
||||
coder2->codec != _7Z_SPARC) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported filter %lx for %lx",
|
||||
@@ -1223,6 +1447,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
filters[fi].id = LZMA_FILTER_ARM64;
|
||||
fi++;
|
||||
break;
|
||||
#endif
|
||||
#ifdef LZMA_FILTER_RISCV
|
||||
case _7Z_RISCV:
|
||||
filters[fi].id = LZMA_FILTER_RISCV;
|
||||
fi++;
|
||||
break;
|
||||
#endif
|
||||
case _7Z_SPARC:
|
||||
filters[fi].id = LZMA_FILTER_SPARC;
|
||||
@@ -1396,6 +1626,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
case _7Z_ARM:
|
||||
case _7Z_ARMTHUMB:
|
||||
case _7Z_ARM64:
|
||||
case _7Z_RISCV:
|
||||
case _7Z_SPARC:
|
||||
case _7Z_DELTA:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -1708,6 +1939,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
*outbytes = arm_Convert(zip, buff, *outbytes);
|
||||
} else if (zip->codec2 == _7Z_ARM64) {
|
||||
*outbytes = arm64_Convert(zip, buff, *outbytes);
|
||||
} else if (zip->codec2 == _7Z_SPARC) {
|
||||
*outbytes = sparc_Convert(zip, buff, *outbytes);
|
||||
} else if (zip->codec2 == _7Z_POWERPC) {
|
||||
*outbytes = powerpc_Convert(zip, buff, *outbytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2841,23 +3076,6 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
|
||||
static void
|
||||
fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
|
||||
{
|
||||
|
||||
if (fileTime >= EPOC_TIME) {
|
||||
fileTime -= EPOC_TIME;
|
||||
/* milli seconds base */
|
||||
*timep = (time_t)(fileTime / 10000000);
|
||||
/* nano seconds base */
|
||||
*ns = (long)(fileTime % 10000000) * 100;
|
||||
} else {
|
||||
*timep = 0;
|
||||
*ns = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
|
||||
{
|
||||
@@ -2900,19 +3118,19 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
|
||||
goto failed;
|
||||
switch (type) {
|
||||
case kCTime:
|
||||
fileTimeToUtc(archive_le64dec(p),
|
||||
ntfs_to_unix(archive_le64dec(p),
|
||||
&(entries[i].ctime),
|
||||
&(entries[i].ctime_ns));
|
||||
entries[i].flg |= CTIME_IS_SET;
|
||||
break;
|
||||
case kATime:
|
||||
fileTimeToUtc(archive_le64dec(p),
|
||||
ntfs_to_unix(archive_le64dec(p),
|
||||
&(entries[i].atime),
|
||||
&(entries[i].atime_ns));
|
||||
entries[i].flg |= ATIME_IS_SET;
|
||||
break;
|
||||
case kMTime:
|
||||
fileTimeToUtc(archive_le64dec(p),
|
||||
ntfs_to_unix(archive_le64dec(p),
|
||||
&(entries[i].mtime),
|
||||
&(entries[i].mtime_ns));
|
||||
entries[i].flg |= MTIME_IS_SET;
|
||||
@@ -3007,7 +3225,9 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
|
||||
|
||||
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
|
||||
/* This is an executable ? Must be self-extracting... */
|
||||
r = skip_sfx(a, bytes_avail);
|
||||
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
|
||||
find_elf_data_sec(a);
|
||||
r = skip_sfx(a, min_addr);
|
||||
if (r < ARCHIVE_WARN)
|
||||
return (r);
|
||||
if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
|
||||
@@ -4007,6 +4227,121 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
{
|
||||
// This function was adapted from
|
||||
// static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
// in https://git.tukaani.org/xz-embedded.git
|
||||
|
||||
/*
|
||||
* Branch/Call/Jump (BCJ) filter decoders
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <https://7-zip.org/>
|
||||
*
|
||||
* Copyright (C) The XZ Embedded authors and contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this
|
||||
* software for any purpose with or without fee is hereby granted.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
size &= ~(size_t)3;
|
||||
|
||||
for (i = 0; i < size; i += 4) {
|
||||
instr = (uint32_t)(buf[i] << 24)
|
||||
| ((uint32_t)buf[i+1] << 16)
|
||||
| ((uint32_t)buf[i+2] << 8)
|
||||
| (uint32_t)buf[i+3];
|
||||
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
|
||||
instr <<= 2;
|
||||
instr -= zip->bcj_ip + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
|
||||
| 0x40000000 | (instr & 0x3FFFFF);
|
||||
|
||||
buf[i] = (uint8_t)(instr >> 24);
|
||||
buf[i+1] = (uint8_t)(instr >> 16);
|
||||
buf[i+2] = (uint8_t)(instr >> 8);
|
||||
buf[i+3] = (uint8_t)instr;
|
||||
}
|
||||
}
|
||||
|
||||
zip->bcj_ip += (uint32_t)i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
powerpc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
{
|
||||
// This function was adapted from
|
||||
// static size_t powerpc_code(void *simple, uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size)
|
||||
// in https://git.tukaani.org/xz.git
|
||||
|
||||
/*
|
||||
* Filter for PowerPC (big endian) binaries
|
||||
*
|
||||
* Authors: Igor Pavlov
|
||||
* Lasse Collin
|
||||
*
|
||||
* Copyright (C) The XZ Utils authors and contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this
|
||||
* software for any purpose with or without fee is hereby granted.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
size &= ~(size_t)3;
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < size; i += 4) {
|
||||
// PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
|
||||
if ((buf[i] >> 2) == 0x12
|
||||
&& ((buf[i + 3] & 3) == 1)) {
|
||||
|
||||
const uint32_t src
|
||||
= (((uint32_t)(buf[i + 0]) & 3) << 24)
|
||||
| ((uint32_t)(buf[i + 1]) << 16)
|
||||
| ((uint32_t)(buf[i + 2]) << 8)
|
||||
| ((uint32_t)(buf[i + 3]) & ~UINT32_C(3));
|
||||
|
||||
uint32_t dest = src - (zip->bcj_ip + (uint32_t)(i));
|
||||
|
||||
buf[i + 0] = 0x48 | ((dest >> 24) & 0x03);
|
||||
buf[i + 1] = (dest >> 16);
|
||||
buf[i + 2] = (dest >> 8);
|
||||
buf[i + 3] &= 0x03;
|
||||
buf[i + 3] |= dest;
|
||||
}
|
||||
}
|
||||
|
||||
zip->bcj_ip += (uint32_t)i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Brought from LZMA SDK.
|
||||
*
|
||||
@@ -4029,8 +4364,17 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
|
||||
#define RC_READ_BYTE (*buffer++)
|
||||
#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
|
||||
#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
|
||||
{ int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
|
||||
#define RC_INIT2 do { \
|
||||
zip->bcj2_code = 0; \
|
||||
zip->bcj2_range = 0xFFFFFFFF; \
|
||||
{ \
|
||||
int ii; \
|
||||
for (ii = 0; ii < 5; ii++) { \
|
||||
RC_TEST; \
|
||||
zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
|
||||
|
||||
@@ -4177,4 +4521,3 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
|
||||
|
||||
return ((ssize_t)outPos);
|
||||
}
|
||||
|
||||
@@ -41,49 +41,34 @@ archive_read_support_format_by_code(struct archive *a, int format_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_EMPTY:
|
||||
return archive_read_support_format_empty(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_RAR_V5:
|
||||
return archive_read_support_format_rar5(a);
|
||||
break;
|
||||
case ARCHIVE_FORMAT_RAW:
|
||||
return archive_read_support_format_raw(a);
|
||||
break;
|
||||
case ARCHIVE_FORMAT_TAR:
|
||||
return archive_read_support_format_tar(a);
|
||||
break;
|
||||
case ARCHIVE_FORMAT_WARC:
|
||||
return archive_read_support_format_warc(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;
|
||||
}
|
||||
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Invalid format code specified");
|
||||
|
||||
@@ -363,7 +363,12 @@ archive_read_support_format_cab(struct archive *_a)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_string_init(&cab->ws);
|
||||
archive_wstring_ensure(&cab->ws, 256);
|
||||
if (archive_wstring_ensure(&cab->ws, 256) == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory");
|
||||
free(cab);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
r = __archive_read_register_format(a,
|
||||
cab,
|
||||
|
||||
@@ -189,6 +189,7 @@ struct cpio {
|
||||
};
|
||||
|
||||
static int64_t atol16(const char *, unsigned);
|
||||
static uint64_t atol16u(const char *, unsigned);
|
||||
static int64_t atol8(const char *, unsigned);
|
||||
static int archive_read_format_cpio_bid(struct archive_read *, int);
|
||||
static int archive_read_format_cpio_options(struct archive_read *,
|
||||
@@ -835,6 +836,7 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
|
||||
struct archive_entry *entry, size_t *namelength, size_t *name_pad)
|
||||
{
|
||||
int64_t t;
|
||||
uint64_t u;
|
||||
const void *h;
|
||||
const char *header;
|
||||
|
||||
@@ -851,12 +853,12 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
|
||||
|
||||
archive_entry_set_dev(entry,
|
||||
(dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
|
||||
t = atol16(header + afiol_ino_offset, afiol_ino_size);
|
||||
if (t < 0) {
|
||||
archive_set_error(&a->archive, 0, "Nonsensical ino value");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_entry_set_ino(entry, t);
|
||||
u = atol16u(header + afiol_ino_offset, afiol_ino_size);
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
archive_entry_set_ino(entry, (int64_t)(u & INT64_MAX));
|
||||
#else
|
||||
archive_entry_set_ino(entry, u);
|
||||
#endif
|
||||
archive_entry_set_mode(entry,
|
||||
(mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
|
||||
archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
|
||||
@@ -1030,6 +1032,12 @@ atol8(const char *p, unsigned char_cnt)
|
||||
|
||||
static int64_t
|
||||
atol16(const char *p, unsigned char_cnt)
|
||||
{
|
||||
return ((int64_t)atol16u(p, char_cnt));
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
atol16u(const char *p, unsigned char_cnt)
|
||||
{
|
||||
uint64_t l;
|
||||
int digit;
|
||||
@@ -1048,7 +1056,7 @@ atol16(const char *p, unsigned char_cnt)
|
||||
l <<= 4;
|
||||
l |= digit;
|
||||
}
|
||||
return ((int64_t)l);
|
||||
return (l);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -1429,7 +1429,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
* information first, then store all file bodies. */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring out-of-order file @%jx (%s) %jd < %jd",
|
||||
(intmax_t)file->number,
|
||||
(uintmax_t)file->number,
|
||||
iso9660->pathname.s,
|
||||
(intmax_t)file->offset,
|
||||
(intmax_t)iso9660->current_position);
|
||||
@@ -2273,7 +2273,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
|
||||
if (version == 1) {
|
||||
if (data_length >= 8)
|
||||
file->mode
|
||||
= toi(data, 4);
|
||||
= (__LA_MODE_T)toi(data, 4);
|
||||
if (data_length >= 16)
|
||||
file->nlinks
|
||||
= toi(data + 8, 4);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
#include "archive_time_private.h"
|
||||
#include "archive_endian.h"
|
||||
|
||||
|
||||
@@ -162,12 +163,12 @@ struct lha {
|
||||
#define ATIME_IS_SET 2
|
||||
#define UNIX_MODE_IS_SET 4
|
||||
#define CRC_IS_SET 8
|
||||
time_t birthtime;
|
||||
long birthtime_tv_nsec;
|
||||
time_t mtime;
|
||||
long mtime_tv_nsec;
|
||||
time_t atime;
|
||||
long atime_tv_nsec;
|
||||
int64_t birthtime;
|
||||
uint32_t birthtime_tv_nsec;
|
||||
int64_t mtime;
|
||||
uint32_t mtime_tv_nsec;
|
||||
int64_t atime;
|
||||
uint32_t atime_tv_nsec;
|
||||
mode_t mode;
|
||||
int64_t uid;
|
||||
int64_t gid;
|
||||
@@ -230,8 +231,6 @@ static int lha_read_file_extended_header(struct archive_read *,
|
||||
struct lha *, uint16_t *, int, uint64_t, size_t *);
|
||||
static size_t lha_check_header_format(const void *);
|
||||
static int lha_skip_sfx(struct archive_read *);
|
||||
static time_t lha_dos_time(const unsigned char *);
|
||||
static time_t lha_win_time(uint64_t, long *);
|
||||
static unsigned char lha_calcsum(unsigned char, const void *,
|
||||
int, size_t);
|
||||
static int lha_parse_linkname(struct archive_wstring *,
|
||||
@@ -819,7 +818,7 @@ lha_read_file_header_0(struct archive_read *a, struct lha *lha)
|
||||
headersum = p[H0_HEADER_SUM_OFFSET];
|
||||
lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
|
||||
lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
|
||||
lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);
|
||||
lha->mtime = dos_to_unix(archive_le32dec(p + H0_DOS_TIME_OFFSET));
|
||||
namelen = p[H0_NAME_LEN_OFFSET];
|
||||
extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
|
||||
if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
|
||||
@@ -919,7 +918,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
|
||||
/* Note: An extended header size is included in a compsize. */
|
||||
lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
|
||||
lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
|
||||
lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);
|
||||
lha->mtime = dos_to_unix(archive_le32dec(p + H1_DOS_TIME_OFFSET));
|
||||
namelen = p[H1_NAME_LEN_OFFSET];
|
||||
/* Calculate a padding size. The result will be normally 0 only(?) */
|
||||
padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
|
||||
@@ -1090,7 +1089,7 @@ lha_read_file_header_3(struct archive_read *a, struct lha *lha)
|
||||
|
||||
if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)
|
||||
goto invalid;
|
||||
lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
|
||||
lha->header_size = archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
|
||||
lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);
|
||||
lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);
|
||||
lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);
|
||||
@@ -1326,16 +1325,16 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
|
||||
break;
|
||||
case EXT_TIMESTAMP:
|
||||
if (datasize == (sizeof(uint64_t) * 3)) {
|
||||
lha->birthtime = lha_win_time(
|
||||
archive_le64dec(extdheader),
|
||||
ntfs_to_unix(archive_le64dec(extdheader),
|
||||
&lha->birthtime,
|
||||
&lha->birthtime_tv_nsec);
|
||||
extdheader += sizeof(uint64_t);
|
||||
lha->mtime = lha_win_time(
|
||||
archive_le64dec(extdheader),
|
||||
ntfs_to_unix(archive_le64dec(extdheader),
|
||||
&lha->mtime,
|
||||
&lha->mtime_tv_nsec);
|
||||
extdheader += sizeof(uint64_t);
|
||||
lha->atime = lha_win_time(
|
||||
archive_le64dec(extdheader),
|
||||
ntfs_to_unix(archive_le64dec(extdheader),
|
||||
&lha->atime,
|
||||
&lha->atime_tv_nsec);
|
||||
lha->setflag |= BIRTHTIME_IS_SET |
|
||||
ATIME_IS_SET;
|
||||
@@ -1716,45 +1715,6 @@ lha_parse_linkname(struct archive_wstring *linkname,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Convert an MSDOS-style date/time into Unix-style time. */
|
||||
static time_t
|
||||
lha_dos_time(const unsigned char *p)
|
||||
{
|
||||
int msTime, msDate;
|
||||
struct tm ts;
|
||||
|
||||
msTime = archive_le16dec(p);
|
||||
msDate = archive_le16dec(p+2);
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
|
||||
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
|
||||
ts.tm_mday = msDate & 0x1f; /* Day of month. */
|
||||
ts.tm_hour = (msTime >> 11) & 0x1f;
|
||||
ts.tm_min = (msTime >> 5) & 0x3f;
|
||||
ts.tm_sec = (msTime << 1) & 0x3e;
|
||||
ts.tm_isdst = -1;
|
||||
return (mktime(&ts));
|
||||
}
|
||||
|
||||
/* Convert an MS-Windows-style date/time into Unix-style time. */
|
||||
static time_t
|
||||
lha_win_time(uint64_t wintime, long *ns)
|
||||
{
|
||||
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
|
||||
|
||||
if (wintime >= EPOC_TIME) {
|
||||
wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */
|
||||
if (ns != NULL)
|
||||
*ns = (long)(wintime % 10000000) * 100;
|
||||
return (wintime / 10000000);
|
||||
} else {
|
||||
if (ns != NULL)
|
||||
*ns = 0;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
|
||||
{
|
||||
@@ -2917,4 +2877,3 @@ lzh_decode_huffman(struct huffman *hf, unsigned rbits)
|
||||
/* This bit pattern needs to be found out at a huffman tree. */
|
||||
return (lzh_decode_huffman_tree(hf, rbits, c));
|
||||
}
|
||||
|
||||
@@ -335,8 +335,8 @@ struct rar
|
||||
int found_first_header;
|
||||
char has_endarc_header;
|
||||
struct data_block_offsets *dbo;
|
||||
unsigned int cursor;
|
||||
unsigned int nodes;
|
||||
size_t cursor;
|
||||
size_t nodes;
|
||||
char filename_must_match;
|
||||
|
||||
/* LZSS members */
|
||||
@@ -451,7 +451,7 @@ static int read_filter(struct archive_read *, int64_t *);
|
||||
static int rar_decode_byte(struct archive_read*, uint8_t *);
|
||||
static int execute_filter(struct archive_read*, struct rar_filter *,
|
||||
struct rar_virtual_machine *, size_t);
|
||||
static int copy_from_lzss_window(struct archive_read *, void *, int64_t, int);
|
||||
static int copy_from_lzss_window(struct archive_read *, uint8_t *, int64_t, int);
|
||||
static inline void vm_write_32(struct rar_virtual_machine*, size_t, uint32_t);
|
||||
static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);
|
||||
|
||||
@@ -475,7 +475,7 @@ static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);
|
||||
((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))
|
||||
/* Notify how many bits we consumed. */
|
||||
#define rar_br_consume(br, n) ((br)->cache_avail -= (n))
|
||||
#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)
|
||||
#define rar_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~7)
|
||||
|
||||
static const uint32_t cache_masks[] = {
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000007,
|
||||
@@ -741,11 +741,11 @@ archive_read_support_format_rar(struct archive *_a)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Until enough data has been read, we cannot tell about
|
||||
* any encrypted entries yet.
|
||||
*/
|
||||
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
/*
|
||||
* Until enough data has been read, we cannot tell about
|
||||
* any encrypted entries yet.
|
||||
*/
|
||||
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
|
||||
r = __archive_read_register_format(a,
|
||||
rar,
|
||||
@@ -768,21 +768,21 @@ archive_read_support_format_rar(struct archive *_a)
|
||||
static int
|
||||
archive_read_support_format_rar_capabilities(struct archive_read * a)
|
||||
{
|
||||
(void)a; /* UNUSED */
|
||||
return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
|
||||
| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
|
||||
(void)a; /* UNUSED */
|
||||
return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
|
||||
| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)
|
||||
{
|
||||
if (_a && _a->format) {
|
||||
struct rar * rar = (struct rar *)_a->format->data;
|
||||
if (rar) {
|
||||
return rar->has_encrypted_entries;
|
||||
}
|
||||
}
|
||||
return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
if (_a && _a->format) {
|
||||
struct rar * rar = (struct rar *)_a->format->data;
|
||||
if (rar) {
|
||||
return rar->has_encrypted_entries;
|
||||
}
|
||||
}
|
||||
return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
}
|
||||
|
||||
|
||||
@@ -793,7 +793,7 @@ archive_read_format_rar_bid(struct archive_read *a, int best_bid)
|
||||
|
||||
/* If there's already a bid > 30, we'll never win. */
|
||||
if (best_bid > 30)
|
||||
return (-1);
|
||||
return (-1);
|
||||
|
||||
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
|
||||
return (-1);
|
||||
@@ -865,7 +865,7 @@ skip_sfx(struct archive_read *a)
|
||||
}
|
||||
skip = p - (const char *)h;
|
||||
__archive_read_consume(a, skip);
|
||||
total += skip;
|
||||
total += skip;
|
||||
}
|
||||
fatal:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
@@ -910,7 +910,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
const void *h;
|
||||
const char *p;
|
||||
struct rar *rar;
|
||||
size_t skip;
|
||||
int64_t skip;
|
||||
char head_type;
|
||||
int ret;
|
||||
unsigned flags;
|
||||
@@ -930,7 +930,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
* as well.
|
||||
*/
|
||||
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar->has_encrypted_entries = 0;
|
||||
rar->has_encrypted_entries = 0;
|
||||
}
|
||||
|
||||
/* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
|
||||
@@ -953,8 +953,11 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
{
|
||||
unsigned long crc32_val;
|
||||
|
||||
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
|
||||
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read next header.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
|
||||
head_type = p[2];
|
||||
@@ -972,7 +975,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
case MAIN_HEAD:
|
||||
rar->main_flags = archive_le16dec(p + 3);
|
||||
skip = archive_le16dec(p + 5);
|
||||
if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
|
||||
if ((size_t)skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid header size");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -984,7 +987,8 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),
|
||||
sizeof(rar->reserved2));
|
||||
if (rar->main_flags & MHD_ENCRYPTVER) {
|
||||
if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {
|
||||
if ((size_t)skip <
|
||||
7 + sizeof(rar->reserved1) + sizeof(rar->reserved2) + 1) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid header size");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1053,28 +1057,30 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
/* Skim the entire header and compute the CRC. */
|
||||
crc32_val = 0;
|
||||
while (skip > 0) {
|
||||
size_t to_read = skip;
|
||||
if (to_read > 32 * 1024)
|
||||
to_read = 32 * 1024;
|
||||
if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned int)to_read);
|
||||
__archive_read_consume(a, to_read);
|
||||
skip -= to_read;
|
||||
unsigned to_read;
|
||||
if (skip > 32 * 1024)
|
||||
to_read = 32 * 1024;
|
||||
else
|
||||
to_read = (unsigned)skip;
|
||||
if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
|
||||
__archive_read_consume(a, to_read);
|
||||
skip -= to_read;
|
||||
}
|
||||
if ((crc32_val & 0xffff) != crc32_expected) {
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Header CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Header CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
#endif
|
||||
}
|
||||
if (head_type == ENDARC_HEAD)
|
||||
return (ARCHIVE_EOF);
|
||||
return (ARCHIVE_EOF);
|
||||
break;
|
||||
|
||||
case NEWSUB_HEAD:
|
||||
@@ -1083,7 +1089,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
break;
|
||||
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -1098,7 +1104,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
|
||||
int ret;
|
||||
|
||||
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar->has_encrypted_entries = 0;
|
||||
rar->has_encrypted_entries = 0;
|
||||
}
|
||||
|
||||
if (rar->bytes_unconsumed > 0) {
|
||||
@@ -1186,7 +1192,7 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
|
||||
int whence)
|
||||
{
|
||||
int64_t client_offset, ret;
|
||||
unsigned int i;
|
||||
size_t i;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
|
||||
if (rar->compression_method == COMPRESS_METHOD_STORE)
|
||||
@@ -1433,7 +1439,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
}
|
||||
|
||||
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read full header content.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* File Header CRC check. */
|
||||
crc32_computed = crc32(crc32_computed, h, (unsigned)(header_size - 7));
|
||||
@@ -1460,8 +1470,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
|
||||
if (rar->file_flags & FHD_PASSWORD)
|
||||
{
|
||||
archive_entry_set_is_data_encrypted(entry, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
archive_entry_set_is_data_encrypted(entry, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"RAR encryption support unavailable.");
|
||||
/* Since it is only the data part itself that is encrypted we can at least
|
||||
@@ -1506,10 +1516,23 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
*/
|
||||
if (head_type == NEWSUB_HEAD) {
|
||||
size_t distance = p - (const char *)h;
|
||||
if (rar->packed_size > INT64_MAX - header_size) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Extended header size too large.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
header_size += rar->packed_size;
|
||||
if ((uintmax_t)header_size > SIZE_MAX) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to read extended header data.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* Make sure we have the extended data. */
|
||||
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read extended header data.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
endp = p + header_size - 7;
|
||||
p += distance;
|
||||
@@ -1670,6 +1693,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
!memcmp(rar->filename, rar->filename_save, filename_size + 1))
|
||||
{
|
||||
__archive_read_consume(a, header_size - 7);
|
||||
rar->br.avail_in = 0;
|
||||
rar->br.next_in = NULL;
|
||||
rar->cursor++;
|
||||
if (rar->cursor >= rar->nodes)
|
||||
{
|
||||
@@ -1689,6 +1714,12 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
}
|
||||
if (rar->dbo[rar->cursor].start_offset < 0)
|
||||
{
|
||||
if (rar->packed_size > INT64_MAX - a->filter->position)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to store offsets.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo[rar->cursor].start_offset = a->filter->position;
|
||||
rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +
|
||||
rar->packed_size;
|
||||
@@ -1745,6 +1776,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
}
|
||||
|
||||
__archive_read_consume(a, header_size - 7);
|
||||
if (rar->packed_size > INT64_MAX - a->filter->position) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to store offsets.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo[0].start_offset = a->filter->position;
|
||||
rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;
|
||||
|
||||
@@ -1753,7 +1789,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
case OS_MSDOS:
|
||||
case OS_OS2:
|
||||
case OS_WIN32:
|
||||
rar->mode = archive_le32dec(file_header.file_attr);
|
||||
rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr);
|
||||
if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)
|
||||
rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
else
|
||||
@@ -1764,7 +1800,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
case OS_UNIX:
|
||||
case OS_MAC_OS:
|
||||
case OS_BEOS:
|
||||
rar->mode = archive_le32dec(file_header.file_attr);
|
||||
rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1780,6 +1816,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
rar->offset_outgoing = 0;
|
||||
rar->br.cache_avail = 0;
|
||||
rar->br.avail_in = 0;
|
||||
rar->br.next_in = NULL;
|
||||
rar->crc_calculated = 0;
|
||||
rar->entry_eof = 0;
|
||||
rar->valid = 1;
|
||||
@@ -1941,8 +1978,18 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
|
||||
int ret = (ARCHIVE_OK);
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
|
||||
if ((uintmax_t)rar->packed_size > SIZE_MAX)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to read link.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read link.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
|
||||
if (archive_entry_copy_symlink_l(entry,
|
||||
@@ -2224,7 +2271,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
|
||||
ret = expand(a, &end);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
return (ret);
|
||||
|
||||
rar->bytes_uncopied = end - start;
|
||||
rar->filters.lastend = end;
|
||||
@@ -2276,7 +2323,7 @@ parse_codes(struct archive_read *a)
|
||||
free_codes(a);
|
||||
|
||||
/* Skip to the next byte */
|
||||
rar_br_consume_unalined_bits(br);
|
||||
rar_br_consume_unaligned_bits(br);
|
||||
|
||||
/* PPMd block flag */
|
||||
if (!rar_br_read_ahead(a, br, 1))
|
||||
@@ -2332,9 +2379,9 @@ parse_codes(struct archive_read *a)
|
||||
__archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
|
||||
|
||||
if (rar->dictionary_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid zero dictionary size");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
|
||||
@@ -2803,7 +2850,7 @@ make_table(struct archive_read *a, struct huffman_code *code)
|
||||
else
|
||||
code->tablesize = code->maxlength;
|
||||
|
||||
code->table = calloc(1U << code->tablesize, sizeof(*code->table));
|
||||
code->table = calloc(((size_t)1U) << code->tablesize, sizeof(*code->table));
|
||||
|
||||
return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
|
||||
}
|
||||
@@ -2929,11 +2976,11 @@ expand(struct archive_read *a, int64_t *end)
|
||||
}
|
||||
|
||||
if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
goto bad_data;
|
||||
|
||||
if (symbol < 256)
|
||||
{
|
||||
lzss_emit_literal(rar, symbol);
|
||||
lzss_emit_literal(rar, (uint8_t)symbol);
|
||||
continue;
|
||||
}
|
||||
else if (symbol == 256)
|
||||
@@ -2956,14 +3003,14 @@ expand(struct archive_read *a, int64_t *end)
|
||||
else
|
||||
{
|
||||
if (parse_codes(a) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
goto bad_data;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(symbol==257)
|
||||
{
|
||||
if (!read_filter(a, end))
|
||||
return (ARCHIVE_FATAL);
|
||||
goto bad_data;
|
||||
continue;
|
||||
}
|
||||
else if(symbol==258)
|
||||
@@ -3048,7 +3095,7 @@ expand(struct archive_read *a, int64_t *end)
|
||||
{
|
||||
if ((lowoffsetsymbol =
|
||||
read_next_symbol(a, &rar->lowoffsetcode)) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
goto bad_data;
|
||||
if(lowoffsetsymbol == 16)
|
||||
{
|
||||
rar->numlowoffsetrepeats = 15;
|
||||
@@ -3096,7 +3143,7 @@ bad_data:
|
||||
}
|
||||
|
||||
static int
|
||||
copy_from_lzss_window(struct archive_read *a, void *buffer,
|
||||
copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,
|
||||
int64_t startpos, int length)
|
||||
{
|
||||
int windowoffs, firstpart;
|
||||
@@ -3111,7 +3158,7 @@ copy_from_lzss_window(struct archive_read *a, void *buffer,
|
||||
}
|
||||
if (firstpart < length) {
|
||||
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
|
||||
memcpy(buffer, &rar->lzss.window[0], length - firstpart);
|
||||
memcpy(buffer + firstpart, &rar->lzss.window[0], length - firstpart);
|
||||
} else {
|
||||
memcpy(buffer, &rar->lzss.window[windowoffs], length);
|
||||
}
|
||||
@@ -3180,8 +3227,12 @@ static const void *
|
||||
rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
const void *h = __archive_read_ahead(a, min, avail);
|
||||
const void *h;
|
||||
int ret;
|
||||
|
||||
again:
|
||||
h = __archive_read_ahead(a, min, avail);
|
||||
|
||||
if (avail)
|
||||
{
|
||||
if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested)
|
||||
@@ -3203,7 +3254,7 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
|
||||
rar->filename_must_match = 0;
|
||||
if (ret != (ARCHIVE_OK))
|
||||
return NULL;
|
||||
return rar_read_ahead(a, min, avail);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
@@ -3266,6 +3317,9 @@ parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint
|
||||
else
|
||||
blocklength = prog ? prog->oldfilterlength : 0;
|
||||
|
||||
if (blocklength > rar->dictionary_size)
|
||||
return 0;
|
||||
|
||||
registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;
|
||||
registers[4] = blocklength;
|
||||
registers[5] = prog ? prog->usagecount : 0;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_ppmd7_private.h"
|
||||
#include "archive_entry_private.h"
|
||||
#include "archive_time_private.h"
|
||||
|
||||
#ifdef HAVE_BLAKE2_H
|
||||
#include <blake2.h>
|
||||
@@ -100,10 +101,12 @@ struct file_header {
|
||||
uint8_t dir : 1; /* Is this file entry a directory? */
|
||||
|
||||
/* Optional time fields. */
|
||||
uint64_t e_mtime;
|
||||
uint64_t e_ctime;
|
||||
uint64_t e_atime;
|
||||
uint32_t e_unix_ns;
|
||||
int64_t e_mtime;
|
||||
int64_t e_ctime;
|
||||
int64_t e_atime;
|
||||
uint32_t e_mtime_ns;
|
||||
uint32_t e_ctime_ns;
|
||||
uint32_t e_atime_ns;
|
||||
|
||||
/* Optional hash fields. */
|
||||
uint32_t stored_crc32;
|
||||
@@ -691,7 +694,8 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
default:
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported filter type: 0x%x", flt->type);
|
||||
"Unsupported filter type: 0x%x",
|
||||
(unsigned int)flt->type);
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -1100,22 +1104,22 @@ static int read_consume_bits(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int read_u32(struct archive_read* a, uint32_t* pvalue) {
|
||||
static char read_u32(struct archive_read* a, uint32_t* pvalue) {
|
||||
const uint8_t* p;
|
||||
if(!read_ahead(a, 4, &p))
|
||||
return 0;
|
||||
|
||||
*pvalue = archive_le32dec(p);
|
||||
return ARCHIVE_OK == consume(a, 4) ? 1 : 0;
|
||||
return ARCHIVE_OK == consume(a, 4);
|
||||
}
|
||||
|
||||
static int read_u64(struct archive_read* a, uint64_t* pvalue) {
|
||||
static char read_u64(struct archive_read* a, uint64_t* pvalue) {
|
||||
const uint8_t* p;
|
||||
if(!read_ahead(a, 8, &p))
|
||||
return 0;
|
||||
|
||||
*pvalue = archive_le64dec(p);
|
||||
return ARCHIVE_OK == consume(a, 8) ? 1 : 0;
|
||||
return ARCHIVE_OK == consume(a, 8);
|
||||
}
|
||||
|
||||
static int bid_standard(struct archive_read* a) {
|
||||
@@ -1293,21 +1297,15 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
|
||||
*extra_data_size -= hash_size;
|
||||
} else {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported hash type (0x%x)", (int) hash_type);
|
||||
"Unsupported hash type (0x%jx)", (uintmax_t)hash_type);
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static uint64_t time_win_to_unix(uint64_t win_time) {
|
||||
const size_t ns_in_sec = 10000000;
|
||||
const uint64_t sec_to_unix = 11644473600LL;
|
||||
return win_time / ns_in_sec - sec_to_unix;
|
||||
}
|
||||
|
||||
static int parse_htime_item(struct archive_read* a, char unix_time,
|
||||
uint64_t* where, int64_t* extra_data_size)
|
||||
int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)
|
||||
{
|
||||
if(unix_time) {
|
||||
uint32_t time_val;
|
||||
@@ -1315,13 +1313,13 @@ static int parse_htime_item(struct archive_read* a, char unix_time,
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
*where = (uint64_t) time_val;
|
||||
*sec = (int64_t) time_val;
|
||||
} else {
|
||||
uint64_t windows_time;
|
||||
if(!read_u64(a, &windows_time))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*where = time_win_to_unix(windows_time);
|
||||
ntfs_to_unix(windows_time, sec, nsec);
|
||||
*extra_data_size -= 8;
|
||||
}
|
||||
|
||||
@@ -1385,7 +1383,7 @@ static int parse_file_extra_version(struct archive_read* a,
|
||||
static int parse_file_extra_htime(struct archive_read* a,
|
||||
struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
|
||||
{
|
||||
char unix_time = 0;
|
||||
char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;
|
||||
size_t flags = 0;
|
||||
size_t value_len;
|
||||
|
||||
@@ -1406,32 +1404,62 @@ static int parse_file_extra_htime(struct archive_read* a,
|
||||
}
|
||||
|
||||
unix_time = flags & IS_UNIX;
|
||||
has_unix_ns = unix_time && (flags & HAS_UNIX_NS);
|
||||
has_mtime = flags & HAS_MTIME;
|
||||
has_atime = flags & HAS_ATIME;
|
||||
has_ctime = flags & HAS_CTIME;
|
||||
rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;
|
||||
|
||||
if(flags & HAS_MTIME) {
|
||||
if(has_mtime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_mtime,
|
||||
extra_data_size);
|
||||
archive_entry_set_mtime(e, rar->file.e_mtime, 0);
|
||||
&rar->file.e_mtime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(flags & HAS_CTIME) {
|
||||
if(has_ctime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_ctime,
|
||||
extra_data_size);
|
||||
archive_entry_set_ctime(e, rar->file.e_ctime, 0);
|
||||
&rar->file.e_ctime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(flags & HAS_ATIME) {
|
||||
if(has_atime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_atime,
|
||||
extra_data_size);
|
||||
archive_entry_set_atime(e, rar->file.e_atime, 0);
|
||||
&rar->file.e_atime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(flags & HAS_UNIX_NS) {
|
||||
if(!read_u32(a, &rar->file.e_unix_ns))
|
||||
if(has_mtime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_mtime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
}
|
||||
|
||||
if(has_ctime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_ctime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
}
|
||||
|
||||
if(has_atime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_atime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
}
|
||||
|
||||
/* The seconds and nanoseconds are either together, or separated in two
|
||||
* fields so we parse them, then set the archive_entry's times. */
|
||||
if(has_mtime) {
|
||||
archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);
|
||||
}
|
||||
|
||||
if(has_ctime) {
|
||||
archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);
|
||||
}
|
||||
|
||||
if(has_atime) {
|
||||
archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
@@ -1896,7 +1924,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
} else {
|
||||
/* Unknown host OS */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported Host OS: 0x%x", (int) host_os);
|
||||
"Unsupported Host OS: 0x%jx",
|
||||
(uintmax_t)host_os);
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
@@ -2104,8 +2133,8 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
default:
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported extra type (0x%x)",
|
||||
(int) extra_field_id);
|
||||
"Unsupported extra type (0x%jx)",
|
||||
(uintmax_t)extra_field_id);
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -3093,7 +3122,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
* can be stored in the output buffer directly.
|
||||
*
|
||||
* - Code 256 defines a new filter, which is later used to
|
||||
* ransform the data block accordingly to the filter type.
|
||||
* transform the data block accordingly to the filter type.
|
||||
* The data block needs to be fully uncompressed first.
|
||||
*
|
||||
* - Code bigger than 257 and smaller than 262 define
|
||||
@@ -3983,7 +4012,7 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Compression method not supported: 0x%x",
|
||||
rar->cstate.method);
|
||||
(unsigned int)rar->cstate.method);
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,11 @@ struct tar {
|
||||
int64_t entry_offset;
|
||||
int64_t entry_padding;
|
||||
int64_t entry_bytes_unconsumed;
|
||||
int64_t realsize;
|
||||
int64_t disk_size;
|
||||
int64_t GNU_sparse_realsize;
|
||||
int64_t GNU_sparse_size;
|
||||
int64_t SCHILY_sparse_realsize;
|
||||
int64_t pax_size;
|
||||
struct sparse_block *sparse_list;
|
||||
struct sparse_block *sparse_last;
|
||||
int64_t sparse_offset;
|
||||
@@ -138,6 +142,7 @@ struct tar {
|
||||
int sparse_gnu_minor;
|
||||
char sparse_gnu_attributes_seen;
|
||||
char filetype;
|
||||
char size_fields; /* Bits defined below */
|
||||
|
||||
struct archive_string localname;
|
||||
struct archive_string_conv *opt_sconv;
|
||||
@@ -148,9 +153,15 @@ struct tar {
|
||||
int compat_2x;
|
||||
int process_mac_extensions;
|
||||
int read_concatenated_archives;
|
||||
int realsize_override;
|
||||
};
|
||||
|
||||
/* Track which size fields were present in the headers */
|
||||
#define TAR_SIZE_PAX_SIZE 1
|
||||
#define TAR_SIZE_GNU_SPARSE_REALSIZE 2
|
||||
#define TAR_SIZE_GNU_SPARSE_SIZE 4
|
||||
#define TAR_SIZE_SCHILY_SPARSE_REALSIZE 8
|
||||
|
||||
|
||||
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 *,
|
||||
@@ -158,36 +169,36 @@ static int gnu_add_sparse_entry(struct archive_read *, struct tar *,
|
||||
|
||||
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 *);
|
||||
const struct archive_entry_header_gnutar *header, int64_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 *, size_t);
|
||||
static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *,
|
||||
size_t *);
|
||||
static int64_t gnu_sparse_10_read(struct archive_read *, struct tar *,
|
||||
int64_t *);
|
||||
static int header_Solaris_ACL(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *, size_t *);
|
||||
struct archive_entry *, const void *, int64_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_extension(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *, size_t *);
|
||||
struct archive_entry *, const void *, int64_t *);
|
||||
static int header_pax_global(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *h, size_t *);
|
||||
struct archive_entry *, const void *h, int64_t *);
|
||||
static int header_gnu_longlink(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *h, size_t *);
|
||||
struct archive_entry *, const void *h, int64_t *);
|
||||
static int header_gnu_longname(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *h, size_t *);
|
||||
struct archive_entry *, const void *h, int64_t *);
|
||||
static int is_mac_metadata_entry(struct archive_entry *entry);
|
||||
static int read_mac_metadata_blob(struct archive_read *,
|
||||
struct archive_entry *, size_t *);
|
||||
struct archive_entry *, int64_t *);
|
||||
static int header_volume(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const void *h, size_t *);
|
||||
struct archive_entry *, const void *h, int64_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 *);
|
||||
struct archive_entry *, const void *h, int64_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 *);
|
||||
@@ -200,7 +211,7 @@ static int archive_read_format_tar_read_header(struct archive_read *,
|
||||
static int checksum(struct archive_read *, const void *);
|
||||
static int pax_attribute(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const char *key, size_t key_length,
|
||||
size_t value_length, size_t *unconsumed);
|
||||
size_t value_length, int64_t *unconsumed);
|
||||
static int pax_attribute_LIBARCHIVE_xattr(struct archive_entry *,
|
||||
const char *, size_t, const char *, size_t);
|
||||
static int pax_attribute_SCHILY_acl(struct archive_read *, struct tar *,
|
||||
@@ -209,20 +220,20 @@ static int pax_attribute_SUN_holesdata(struct archive_read *, struct tar *,
|
||||
struct archive_entry *, const char *, size_t);
|
||||
static void pax_time(const char *, size_t, int64_t *sec, long *nanos);
|
||||
static ssize_t readline(struct archive_read *, struct tar *, const char **,
|
||||
ssize_t limit, size_t *);
|
||||
ssize_t limit, int64_t *);
|
||||
static int read_body_to_string(struct archive_read *, struct tar *,
|
||||
struct archive_string *, const void *h, size_t *);
|
||||
struct archive_string *, const void *h, int64_t *);
|
||||
static int read_bytes_to_string(struct archive_read *,
|
||||
struct archive_string *, size_t, size_t *);
|
||||
struct archive_string *, size_t, int64_t *);
|
||||
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 *);
|
||||
struct archive_entry *, int64_t *);
|
||||
static int tohex(int c);
|
||||
static char *url_decode(const char *, size_t);
|
||||
static void tar_flush_unconsumed(struct archive_read *, size_t *);
|
||||
static void tar_flush_unconsumed(struct archive_read *, int64_t *);
|
||||
|
||||
/* Sanity limits: These numbers should be low enough to
|
||||
* prevent a maliciously-crafted archive from forcing us to
|
||||
@@ -467,7 +478,7 @@ archive_read_format_tar_options(struct archive_read *a,
|
||||
* anything outstanding since we're going to do read_aheads
|
||||
*/
|
||||
static void
|
||||
tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed)
|
||||
tar_flush_unconsumed(struct archive_read *a, int64_t *unconsumed)
|
||||
{
|
||||
if (*unconsumed) {
|
||||
/*
|
||||
@@ -515,7 +526,8 @@ archive_read_format_tar_read_header(struct archive_read *a,
|
||||
const char *p;
|
||||
const wchar_t *wp;
|
||||
int r;
|
||||
size_t l, unconsumed = 0;
|
||||
size_t l;
|
||||
int64_t unconsumed = 0;
|
||||
|
||||
/* Assign default device/inode values. */
|
||||
archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
|
||||
@@ -529,8 +541,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
|
||||
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;
|
||||
tar->size_fields = 0; /* We don't have any size info yet */
|
||||
|
||||
/* Setup default string conversion. */
|
||||
tar->sconv = tar->opt_sconv;
|
||||
@@ -617,12 +628,15 @@ archive_read_format_tar_read_data(struct archive_read *a,
|
||||
/* 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)
|
||||
int64_t request = tar->entry_bytes_remaining +
|
||||
tar->entry_padding;
|
||||
|
||||
if (__archive_read_consume(a, request) != request)
|
||||
return (ARCHIVE_FATAL);
|
||||
tar->entry_padding = 0;
|
||||
*buff = NULL;
|
||||
*size = 0;
|
||||
*offset = tar->realsize;
|
||||
*offset = tar->disk_size;
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
|
||||
@@ -655,29 +669,15 @@ archive_read_format_tar_read_data(struct archive_read *a,
|
||||
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;
|
||||
request = tar->entry_bytes_remaining + tar->entry_padding +
|
||||
tar->entry_bytes_unconsumed;
|
||||
|
||||
bytes_skipped = __archive_read_consume(a, request);
|
||||
if (bytes_skipped < 0)
|
||||
if (__archive_read_consume(a, request) != request)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
tar->entry_bytes_remaining = 0;
|
||||
@@ -690,13 +690,29 @@ archive_read_format_tar_skip(struct archive_read *a)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function resets the accumulated state while reading
|
||||
* a header.
|
||||
*/
|
||||
static void
|
||||
tar_reset_header_state(struct tar *tar)
|
||||
{
|
||||
tar->pax_hdrcharset_utf8 = 1;
|
||||
tar->sparse_gnu_attributes_seen = 0;
|
||||
archive_string_empty(&(tar->entry_gname));
|
||||
archive_string_empty(&(tar->entry_pathname));
|
||||
archive_string_empty(&(tar->entry_pathname_override));
|
||||
archive_string_empty(&(tar->entry_uname));
|
||||
archive_string_empty(&tar->entry_linkpath);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads and 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)
|
||||
struct archive_entry *entry, int64_t *unconsumed)
|
||||
{
|
||||
ssize_t bytes;
|
||||
int err = ARCHIVE_OK, err2;
|
||||
@@ -715,13 +731,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
static const int32_t seen_x_header = 32; /* Also X */
|
||||
static const int32_t seen_mac_metadata = 512;
|
||||
|
||||
tar->pax_hdrcharset_utf8 = 1;
|
||||
tar->sparse_gnu_attributes_seen = 0;
|
||||
archive_string_empty(&(tar->entry_gname));
|
||||
archive_string_empty(&(tar->entry_pathname));
|
||||
archive_string_empty(&(tar->entry_pathname_override));
|
||||
archive_string_empty(&(tar->entry_uname));
|
||||
archive_string_empty(&tar->entry_linkpath);
|
||||
tar_reset_header_state(tar);
|
||||
|
||||
/* Ensure format is set. */
|
||||
if (a->archive.archive_format_name == NULL) {
|
||||
@@ -750,7 +760,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
* if there's no regular header, then this is
|
||||
* a premature EOF. */
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Damaged tar archive");
|
||||
"Damaged tar archive (end-of-archive within a sequence of headers)");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else {
|
||||
return (ARCHIVE_EOF);
|
||||
@@ -760,7 +770,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated tar archive"
|
||||
" detected while reading next heaader");
|
||||
" detected while reading next header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
*unconsumed += 512;
|
||||
@@ -787,7 +797,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
/* This is NOT a null block, so it must be a valid header. */
|
||||
if (!checksum(a, h)) {
|
||||
tar_flush_unconsumed(a, unconsumed);
|
||||
archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Damaged tar archive (bad header checksum)");
|
||||
/* If we've read some critical information (pax headers, etc)
|
||||
* and _then_ see a bad header, we can't really recover. */
|
||||
if (eof_fatal) {
|
||||
@@ -804,6 +815,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
switch(header->typeflag[0]) {
|
||||
case 'A': /* Solaris tar ACL */
|
||||
if (seen_headers & seen_A_header) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Redundant 'A' header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
seen_headers |= seen_A_header;
|
||||
@@ -813,6 +826,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
break;
|
||||
case 'g': /* POSIX-standard 'g' header. */
|
||||
if (seen_headers & seen_g_header) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Redundant 'g' header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
seen_headers |= seen_g_header;
|
||||
@@ -822,27 +837,41 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
break;
|
||||
case 'K': /* Long link name (GNU tar, others) */
|
||||
if (seen_headers & seen_K_header) {
|
||||
return (ARCHIVE_FATAL);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Damaged archive: Redundant 'K' headers may cause linknames to be incorrect");
|
||||
err = err_combine(err, ARCHIVE_WARN);
|
||||
}
|
||||
seen_headers |= seen_K_header;
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
|
||||
a->archive.archive_format_name = "GNU tar format";
|
||||
err2 = header_gnu_longlink(a, tar, entry, h, unconsumed);
|
||||
break;
|
||||
case 'L': /* Long filename (GNU tar, others) */
|
||||
if (seen_headers & seen_L_header) {
|
||||
return (ARCHIVE_FATAL);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Damaged archive: Redundant 'L' headers may cause filenames to be incorrect");
|
||||
err = err_combine(err, ARCHIVE_WARN);
|
||||
}
|
||||
seen_headers |= seen_L_header;
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
|
||||
a->archive.archive_format_name = "GNU tar format";
|
||||
err2 = header_gnu_longname(a, tar, entry, h, unconsumed);
|
||||
break;
|
||||
case 'V': /* GNU volume header */
|
||||
if (seen_headers & seen_V_header) {
|
||||
return (ARCHIVE_FATAL);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Redundant 'V' header");
|
||||
err = err_combine(err, ARCHIVE_WARN);
|
||||
}
|
||||
seen_headers |= seen_V_header;
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
|
||||
a->archive.archive_format_name = "GNU tar format";
|
||||
err2 = header_volume(a, tar, entry, h, unconsumed);
|
||||
break;
|
||||
case 'X': /* Used by SUN tar; same as 'x'. */
|
||||
if (seen_headers & seen_x_header) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Redundant 'X'/'x' header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
seen_headers |= seen_x_header;
|
||||
@@ -853,6 +882,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
break;
|
||||
case 'x': /* POSIX-standard 'x' header. */
|
||||
if (seen_headers & seen_x_header) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Redundant 'x' header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
seen_headers |= seen_x_header;
|
||||
@@ -904,6 +935,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
||||
err = err_combine(err, err2);
|
||||
/* Note: Other headers can appear again. */
|
||||
seen_headers = seen_mac_metadata;
|
||||
tar_reset_header_state(tar);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1032,13 +1064,13 @@ archive_block_is_null(const char *p)
|
||||
*/
|
||||
static int
|
||||
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
const struct archive_entry_header_ustar *header;
|
||||
struct archive_string acl_text;
|
||||
size_t size;
|
||||
int err, acl_type;
|
||||
int64_t type;
|
||||
uint64_t type;
|
||||
char *acl, *p;
|
||||
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
@@ -1075,7 +1107,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
p++;
|
||||
}
|
||||
switch ((int)type & ~0777777) {
|
||||
switch (type & ~0777777) {
|
||||
case 01000000:
|
||||
/* POSIX.1e ACL */
|
||||
acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
|
||||
@@ -1086,8 +1118,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Malformed Solaris ACL attribute (unsupported type %o)",
|
||||
(int)type);
|
||||
"Malformed Solaris ACL attribute (unsupported type %llu)",
|
||||
(unsigned long long)type);
|
||||
archive_string_free(&acl_text);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
@@ -1138,14 +1170,16 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
|
||||
*/
|
||||
static int
|
||||
header_gnu_longlink(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
int err;
|
||||
|
||||
struct archive_string linkpath;
|
||||
archive_string_init(&linkpath);
|
||||
err = read_body_to_string(a, tar, &linkpath, h, unconsumed);
|
||||
archive_entry_set_link(entry, linkpath.s);
|
||||
if (err == ARCHIVE_OK) {
|
||||
archive_entry_set_link(entry, linkpath.s);
|
||||
}
|
||||
archive_string_free(&linkpath);
|
||||
return (err);
|
||||
}
|
||||
@@ -1170,7 +1204,7 @@ set_conversion_failed_error(struct archive_read *a,
|
||||
*/
|
||||
static int
|
||||
header_gnu_longname(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
int err;
|
||||
struct archive_string longname;
|
||||
@@ -1191,7 +1225,7 @@ header_gnu_longname(struct archive_read *a, struct tar *tar,
|
||||
*/
|
||||
static int
|
||||
header_volume(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
const struct archive_entry_header_ustar *header;
|
||||
int64_t size, to_consume;
|
||||
@@ -1217,7 +1251,7 @@ header_volume(struct archive_read *a, struct tar *tar,
|
||||
static int
|
||||
read_bytes_to_string(struct archive_read *a,
|
||||
struct archive_string *as, size_t size,
|
||||
size_t *unconsumed) {
|
||||
int64_t *unconsumed) {
|
||||
const void *src;
|
||||
|
||||
/* Fail if we can't make our buffer big enough. */
|
||||
@@ -1250,7 +1284,7 @@ read_bytes_to_string(struct archive_read *a,
|
||||
*/
|
||||
static int
|
||||
read_body_to_string(struct archive_read *a, struct tar *tar,
|
||||
struct archive_string *as, const void *h, size_t *unconsumed)
|
||||
struct archive_string *as, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
int64_t size;
|
||||
const struct archive_entry_header_ustar *header;
|
||||
@@ -1259,18 +1293,21 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
|
||||
(void)tar; /* UNUSED */
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
size = tar_atol(header->size, sizeof(header->size));
|
||||
if (size > entry_limit) {
|
||||
if (size < 0 || size > entry_limit) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Special header has invalid size: %lld",
|
||||
(long long)size);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((size > (int64_t)pathname_limit) || (size < 0)) {
|
||||
if (size > (int64_t)pathname_limit) {
|
||||
archive_string_empty(as);
|
||||
int64_t to_consume = ((size + 511) & ~511);
|
||||
if (to_consume != __archive_read_consume(a, to_consume)) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Special header too large: %d > 1MiB",
|
||||
(int)size);
|
||||
"Special header too large: %lld > 1MiB",
|
||||
(long long)size);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
r = read_bytes_to_string(a, as, size, unconsumed);
|
||||
@@ -1287,6 +1324,11 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
|
||||
* allows header_old_tar and header_ustar
|
||||
* to handle filenames differently, while still putting most of the
|
||||
* common parsing into one place.
|
||||
*
|
||||
* This is called _after_ ustar, GNU tar, Schily, etc, special
|
||||
* fields have already been parsed into the `tar` structure.
|
||||
* So we can make final decisions here about how to reconcile
|
||||
* size, mode, etc, information.
|
||||
*/
|
||||
static int
|
||||
header_common(struct archive_read *a, struct tar *tar,
|
||||
@@ -1308,34 +1350,73 @@ header_common(struct archive_read *a, struct tar *tar,
|
||||
archive_entry_set_perm(entry,
|
||||
(mode_t)tar_atol(header->mode, sizeof(header->mode)));
|
||||
}
|
||||
|
||||
/* Set uid, gid, mtime if not already set */
|
||||
if (!archive_entry_uid_is_set(entry)) {
|
||||
archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
|
||||
}
|
||||
if (!archive_entry_gid_is_set(entry)) {
|
||||
archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
|
||||
}
|
||||
if (!archive_entry_mtime_is_set(entry)) {
|
||||
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
|
||||
}
|
||||
|
||||
tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
|
||||
/* Reconcile the size info. */
|
||||
/* First, how big is the file on disk? */
|
||||
if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_REALSIZE) != 0) {
|
||||
/* GNU sparse format 1.0 uses `GNU.sparse.realsize`
|
||||
* to hold the size of the file on disk. */
|
||||
tar->disk_size = tar->GNU_sparse_realsize;
|
||||
} else if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_SIZE) != 0
|
||||
&& (tar->sparse_gnu_major == 0)) {
|
||||
/* GNU sparse format 0.0 and 0.1 use `GNU.sparse.size`
|
||||
* to hold the size of the file on disk. */
|
||||
tar->disk_size = tar->GNU_sparse_size;
|
||||
} else if ((tar->size_fields & TAR_SIZE_SCHILY_SPARSE_REALSIZE) != 0) {
|
||||
tar->disk_size = tar->SCHILY_sparse_realsize;
|
||||
} else if ((tar->size_fields & TAR_SIZE_PAX_SIZE) != 0) {
|
||||
tar->disk_size = tar->pax_size;
|
||||
} else {
|
||||
/* There wasn't a suitable pax header, so use the ustar info */
|
||||
tar->disk_size = tar_atol(header->size, sizeof(header->size));
|
||||
}
|
||||
|
||||
if (tar->disk_size < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Tar entry has negative file size");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if (tar->disk_size > entry_limit) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Tar entry size overflow");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else {
|
||||
archive_entry_set_size(entry, tar->disk_size);
|
||||
}
|
||||
|
||||
/* Second, how big is the data in the archive? */
|
||||
if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_SIZE) != 0
|
||||
&& (tar->sparse_gnu_major == 1)) {
|
||||
/* GNU sparse format 1.0 uses `GNU.sparse.size`
|
||||
* to hold the size of the data in the archive. */
|
||||
tar->entry_bytes_remaining = tar->GNU_sparse_size;
|
||||
} else if ((tar->size_fields & TAR_SIZE_PAX_SIZE) != 0) {
|
||||
tar->entry_bytes_remaining = tar->pax_size;
|
||||
} else {
|
||||
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");
|
||||
"Tar entry has negative size");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (tar->entry_bytes_remaining > entry_limit) {
|
||||
} else if (tar->entry_bytes_remaining > entry_limit) {
|
||||
tar->entry_bytes_remaining = 0;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Tar entry size overflow");
|
||||
"Tar entry size overflow");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (!tar->realsize_override) {
|
||||
tar->realsize = tar->entry_bytes_remaining;
|
||||
}
|
||||
archive_entry_set_size(entry, tar->realsize);
|
||||
|
||||
if (!archive_entry_mtime_is_set(entry)) {
|
||||
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
|
||||
}
|
||||
|
||||
/* Handle the tar type flag appropriately. */
|
||||
tar->filetype = header->typeflag[0];
|
||||
@@ -1597,7 +1678,7 @@ is_mac_metadata_entry(struct archive_entry *entry) {
|
||||
*/
|
||||
static int
|
||||
read_mac_metadata_blob(struct archive_read *a,
|
||||
struct archive_entry *entry, size_t *unconsumed)
|
||||
struct archive_entry *entry, int64_t *unconsumed)
|
||||
{
|
||||
int64_t size;
|
||||
size_t msize;
|
||||
@@ -1654,7 +1735,7 @@ read_mac_metadata_blob(struct archive_read *a,
|
||||
*/
|
||||
static int
|
||||
header_pax_global(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
const struct archive_entry_header_ustar *header;
|
||||
int64_t size, to_consume;
|
||||
@@ -1665,7 +1746,10 @@ header_pax_global(struct archive_read *a, struct tar *tar,
|
||||
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
size = tar_atol(header->size, sizeof(header->size));
|
||||
if (size > entry_limit) {
|
||||
if (size < 0 || size > entry_limit) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Special header has invalid size: %lld",
|
||||
(long long)size);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
to_consume = ((size + 511) & ~511);
|
||||
@@ -1761,7 +1845,7 @@ header_ustar(struct archive_read *a, struct tar *tar,
|
||||
|
||||
static int
|
||||
header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
/* Sanity checks: The largest `x` body I've ever heard of was
|
||||
* a little over 4MB. So I doubt there has ever been a
|
||||
@@ -1812,8 +1896,8 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Ignoring oversized pax extensions: %d > %d",
|
||||
(int)ext_size, (int)ext_size_limit);
|
||||
"Ignoring oversized pax extensions: %lld > %lld",
|
||||
(long long)ext_size, (long long)ext_size_limit);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
tar_flush_unconsumed(a, unconsumed);
|
||||
@@ -1912,6 +1996,13 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
*unconsumed += p - attr_start;
|
||||
tar_flush_unconsumed(a, unconsumed);
|
||||
|
||||
if (value_length == 0) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Malformed pax attributes");
|
||||
*unconsumed += ext_size + ext_padding;
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
/* pax_attribute will consume value_length - 1 */
|
||||
r = pax_attribute(a, tar, entry, attr_name.s, archive_strlen(&attr_name), value_length - 1, unconsumed);
|
||||
ext_size -= value_length - 1;
|
||||
@@ -2121,8 +2212,9 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
|
||||
if (value_length > acl_limit) {
|
||||
__archive_read_consume(a, value_length);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unreasonably large ACL: %d > %d",
|
||||
(int)value_length, (int)acl_limit);
|
||||
"Unreasonably large ACL: %llu > %llu",
|
||||
(unsigned long long)value_length,
|
||||
(unsigned long long)acl_limit);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
@@ -2154,7 +2246,7 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
|
||||
static int
|
||||
pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, size_t *unconsumed) {
|
||||
pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, int64_t *unconsumed) {
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -2169,12 +2261,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
|
||||
r = read_bytes_to_string(a, &as, value_length, unconsumed);
|
||||
if (r < ARCHIVE_OK) {
|
||||
archive_string_free(&as);
|
||||
*ps = 0;
|
||||
*pn = 0;
|
||||
return (r);
|
||||
}
|
||||
|
||||
pax_time(as.s, archive_strlen(&as), ps, pn);
|
||||
archive_string_free(&as);
|
||||
if (*ps < 0 || *ps == INT64_MAX) {
|
||||
if (*ps == INT64_MIN) {
|
||||
*ps = 0;
|
||||
*pn = 0;
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
@@ -2183,7 +2279,7 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
|
||||
static int
|
||||
pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *result) {
|
||||
struct archive_string as;
|
||||
size_t unconsumed = 0;
|
||||
int64_t unconsumed = 0;
|
||||
int r;
|
||||
|
||||
if (value_length > 64) {
|
||||
@@ -2197,6 +2293,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *
|
||||
tar_flush_unconsumed(a, &unconsumed);
|
||||
if (r < ARCHIVE_OK) {
|
||||
archive_string_free(&as);
|
||||
*result = 0;
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -2223,7 +2320,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *
|
||||
*/
|
||||
static int
|
||||
pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
|
||||
const char *key, size_t key_length, size_t value_length, size_t *unconsumed)
|
||||
const char *key, size_t key_length, size_t value_length, int64_t *unconsumed)
|
||||
{
|
||||
int64_t t;
|
||||
long n;
|
||||
@@ -2289,10 +2386,13 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
else if (key_length == 4 && memcmp(key, "size", 4) == 0) {
|
||||
/* GNU.sparse.size */
|
||||
/* This is either the size of stored entry OR the size of data on disk,
|
||||
* depending on which GNU sparse format version is in use.
|
||||
* Since pax attributes can be in any order, we may not actually
|
||||
* know at this point how to interpret this. */
|
||||
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
|
||||
tar->realsize = t;
|
||||
archive_entry_set_size(entry, tar->realsize);
|
||||
tar->realsize_override = 1;
|
||||
tar->GNU_sparse_size = t;
|
||||
tar->size_fields |= TAR_SIZE_GNU_SPARSE_SIZE;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
@@ -2304,8 +2404,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
tar->sparse_gnu_minor = 1;
|
||||
if (value_length > sparse_map_limit) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unreasonably large sparse map: %d > %d",
|
||||
(int)value_length, (int)sparse_map_limit);
|
||||
"Unreasonably large sparse map: %llu > %llu",
|
||||
(unsigned long long)value_length,
|
||||
(unsigned long long)sparse_map_limit);
|
||||
err = ARCHIVE_FAILED;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
@@ -2360,11 +2461,10 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
return (err);
|
||||
}
|
||||
else if (key_length == 8 && memcmp(key, "realsize", 8) == 0) {
|
||||
/* GNU.sparse.realsize */
|
||||
/* GNU.sparse.realsize = size of file on disk */
|
||||
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
|
||||
tar->realsize = t;
|
||||
archive_entry_set_size(entry, tar->realsize);
|
||||
tar->realsize_override = 1;
|
||||
tar->GNU_sparse_realsize = t;
|
||||
tar->size_fields |= TAR_SIZE_GNU_SPARSE_REALSIZE;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
@@ -2413,8 +2513,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
} else {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"symlink type is very long"
|
||||
"(longest recognized value is 4 bytes, this is %d)",
|
||||
(int)value_length);
|
||||
"(longest recognized value is 4 bytes, this is %llu)",
|
||||
(unsigned long long)value_length);
|
||||
err = ARCHIVE_WARN;
|
||||
}
|
||||
__archive_read_consume(a, value_length);
|
||||
@@ -2450,8 +2550,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
if (value_length > xattr_limit) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring unreasonably large security.selinux attribute:"
|
||||
" %d > %d",
|
||||
(int)value_length, (int)xattr_limit);
|
||||
" %llu > %llu",
|
||||
(unsigned long long)value_length,
|
||||
(unsigned long long)xattr_limit);
|
||||
/* TODO: Should this be FAILED instead? */
|
||||
err = ARCHIVE_WARN;
|
||||
} else {
|
||||
@@ -2545,12 +2646,12 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
else if (key_length == 8 && memcmp(key, "realsize", 8) == 0) {
|
||||
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
|
||||
tar->realsize = t;
|
||||
tar->realsize_override = 1;
|
||||
archive_entry_set_size(entry, tar->realsize);
|
||||
tar->SCHILY_sparse_realsize = t;
|
||||
tar->size_fields |= TAR_SIZE_SCHILY_SPARSE_REALSIZE;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
/* TODO: Is there a SCHILY.sparse.size similar to GNU.sparse.size ? */
|
||||
else if (key_length > 6 && memcmp(key, "xattr.", 6) == 0) {
|
||||
key_length -= 6;
|
||||
key += 6;
|
||||
@@ -2568,8 +2669,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
} else {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unreasonably large xattr: %d > %d",
|
||||
(int)value_length, (int)xattr_limit);
|
||||
"Unreasonably large xattr: %llu > %llu",
|
||||
(unsigned long long)value_length,
|
||||
(unsigned long long)xattr_limit);
|
||||
err = ARCHIVE_WARN;
|
||||
}
|
||||
__archive_read_consume(a, value_length);
|
||||
@@ -2599,8 +2701,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
} else {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unreasonably large sparse map: %d > %d",
|
||||
(int)value_length, (int)sparse_map_limit);
|
||||
"Unreasonably large sparse map: %llu > %llu",
|
||||
(unsigned long long)value_length,
|
||||
(unsigned long long)sparse_map_limit);
|
||||
err = ARCHIVE_FAILED;
|
||||
}
|
||||
__archive_read_consume(a, value_length);
|
||||
@@ -2669,8 +2772,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
} else {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"hdrcharset attribute is unreasonably large (%d bytes)",
|
||||
(int)value_length);
|
||||
"hdrcharset attribute is unreasonably large (%llu bytes)",
|
||||
(unsigned long long)value_length);
|
||||
err = ARCHIVE_WARN;
|
||||
}
|
||||
__archive_read_consume(a, value_length);
|
||||
@@ -2717,19 +2820,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
if (key_length == 4 && memcmp(key, "size", 4) == 0) {
|
||||
/* "size" is the size of the data in the entry. */
|
||||
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
|
||||
tar->entry_bytes_remaining = t;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
tar->pax_size = t;
|
||||
tar->size_fields |= TAR_SIZE_PAX_SIZE;
|
||||
}
|
||||
else if (t == INT64_MAX) {
|
||||
/* Note: pax_attr_read_number returns INT64_MAX on overflow or < 0 */
|
||||
@@ -2768,7 +2860,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
|
||||
|
||||
/*
|
||||
* parse a decimal time value, which may include a fractional portion
|
||||
* Parse a decimal time value, which may include a fractional portion
|
||||
*
|
||||
* Sets ps to INT64_MIN on error.
|
||||
*/
|
||||
static void
|
||||
pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
@@ -2784,6 +2878,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
|
||||
if (length <= 0) {
|
||||
*ps = 0;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
s = 0;
|
||||
@@ -2797,8 +2892,9 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
digit = *p - '0';
|
||||
if (s > limit ||
|
||||
(s == limit && digit > last_digit_limit)) {
|
||||
s = INT64_MAX;
|
||||
break;
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
s = (s * 10) + digit;
|
||||
++p;
|
||||
@@ -2829,7 +2925,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
*/
|
||||
static int
|
||||
header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, size_t *unconsumed)
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
const struct archive_entry_header_gnutar *header;
|
||||
int64_t t;
|
||||
@@ -2841,11 +2937,6 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
* 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;
|
||||
const char *existing_pathname = archive_entry_pathname(entry);
|
||||
@@ -2894,8 +2985,6 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
archive_entry_set_rdev(entry, 0);
|
||||
}
|
||||
|
||||
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
|
||||
|
||||
/* Grab GNU-specific fields. */
|
||||
if (!archive_entry_atime_is_set(entry)) {
|
||||
t = tar_atol(header->atime, sizeof(header->atime));
|
||||
@@ -2909,10 +2998,10 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
|
||||
if (header->realsize[0] != 0) {
|
||||
tar->realsize
|
||||
/* Treat as a synonym for the pax GNU.sparse.realsize attr */
|
||||
tar->GNU_sparse_realsize
|
||||
= tar_atol(header->realsize, sizeof(header->realsize));
|
||||
archive_entry_set_size(entry, tar->realsize);
|
||||
tar->realsize_override = 1;
|
||||
tar->size_fields |= TAR_SIZE_GNU_SPARSE_REALSIZE;
|
||||
}
|
||||
|
||||
if (header->sparse[0].offset[0] != 0) {
|
||||
@@ -2925,6 +3014,13 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab fields common to all tar variants. */
|
||||
err = header_common(a, tar, entry, h);
|
||||
if (err == ARCHIVE_FATAL)
|
||||
return (err);
|
||||
|
||||
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
@@ -2980,7 +3076,7 @@ gnu_clear_sparse_list(struct tar *tar)
|
||||
|
||||
static int
|
||||
gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
|
||||
const struct archive_entry_header_gnutar *header, size_t *unconsumed)
|
||||
const struct archive_entry_header_gnutar *header, int64_t *unconsumed)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
const void *data;
|
||||
@@ -3104,8 +3200,7 @@ gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p, size
|
||||
* 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.
|
||||
* This variant also introduced the GNU.sparse.major/GNU.sparse.minor attributes.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -3115,7 +3210,7 @@ gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p, size
|
||||
*/
|
||||
static int64_t
|
||||
gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
|
||||
int64_t *remaining, size_t *unconsumed)
|
||||
int64_t *remaining, int64_t *unconsumed)
|
||||
{
|
||||
int64_t l, limit, last_digit_limit;
|
||||
const char *p;
|
||||
@@ -3160,12 +3255,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
|
||||
* 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)
|
||||
static int64_t
|
||||
gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
int entries;
|
||||
int64_t offset, size, to_skip, remaining;
|
||||
int64_t bytes_read, entries, offset, size, to_skip, remaining;
|
||||
|
||||
/* Clear out the existing sparse list. */
|
||||
gnu_clear_sparse_list(tar);
|
||||
@@ -3173,7 +3266,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
|
||||
remaining = tar->entry_bytes_remaining;
|
||||
|
||||
/* Parse entries. */
|
||||
entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
|
||||
entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
|
||||
if (entries < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
/* Parse the individual entries. */
|
||||
@@ -3191,14 +3284,14 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
|
||||
}
|
||||
/* Skip rest of block... */
|
||||
tar_flush_unconsumed(a, unconsumed);
|
||||
bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
|
||||
bytes_read = 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));
|
||||
return (bytes_read + to_skip);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3408,7 +3501,7 @@ tar_atol256(const char *_p, size_t char_cnt)
|
||||
*/
|
||||
static ssize_t
|
||||
readline(struct archive_read *a, struct tar *tar, const char **start,
|
||||
ssize_t limit, size_t *unconsumed)
|
||||
ssize_t limit, int64_t *unconsumed)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
ssize_t total_size = 0;
|
||||
|
||||
@@ -386,7 +386,8 @@ start_over:
|
||||
case LAST_WT:
|
||||
default:
|
||||
/* consume the content and start over */
|
||||
_warc_skip(a);
|
||||
if (_warc_skip(a) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
goto start_over;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
@@ -439,7 +440,9 @@ _warc_skip(struct archive_read *a)
|
||||
{
|
||||
struct warc_s *w = a->format->data;
|
||||
|
||||
__archive_read_consume(a, w->cntlen + 4U/*\r\n\r\n separator*/);
|
||||
if (__archive_read_consume(a, w->cntlen) < 0 ||
|
||||
__archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
w->cntlen = 0U;
|
||||
w->cntoff = 0U;
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#include <bsdxml.h>
|
||||
#elif HAVE_EXPAT_H
|
||||
#include <expat.h>
|
||||
#elif HAVE_XMLLITE_H
|
||||
#include <objidl.h>
|
||||
#include <initguid.h>
|
||||
#include <xmllite.h>
|
||||
#endif
|
||||
#ifdef HAVE_BZLIB_H
|
||||
#include <bzlib.h>
|
||||
@@ -56,12 +60,13 @@
|
||||
#include "archive_read_private.h"
|
||||
|
||||
#if (!defined(HAVE_LIBXML_XMLREADER_H) && \
|
||||
!defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\
|
||||
!defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H) && \
|
||||
!defined(HAVE_XMLLITE_H)) ||\
|
||||
!defined(HAVE_ZLIB_H) || \
|
||||
!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
|
||||
/*
|
||||
* xar needs several external libraries.
|
||||
* o libxml2 or expat --- XML parser
|
||||
* o libxml2, expat or (Windows only) xmllite --- XML parser
|
||||
* o openssl or MD5/SHA1 hash function
|
||||
* o zlib
|
||||
* o bzlib2 (option)
|
||||
@@ -438,6 +443,8 @@ static void expat_start_cb(void *, const XML_Char *, const XML_Char **);
|
||||
static void expat_end_cb(void *, const XML_Char *);
|
||||
static void expat_data_cb(void *, const XML_Char *, int);
|
||||
static int expat_read_toc(struct archive_read *);
|
||||
#elif defined(HAVE_XMLLITE_H)
|
||||
static int xmllite_read_toc(struct archive_read *);
|
||||
#endif
|
||||
|
||||
int
|
||||
@@ -589,6 +596,8 @@ read_toc(struct archive_read *a)
|
||||
r = xml2_read_toc(a);
|
||||
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
|
||||
r = expat_read_toc(a);
|
||||
#elif defined(HAVE_XMLLITE_H)
|
||||
r = xmllite_read_toc(a);
|
||||
#endif
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
@@ -1110,17 +1119,17 @@ atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
|
||||
while (bsize && psize > 1) {
|
||||
unsigned char x;
|
||||
|
||||
if (p[0] >= 'a' && p[0] <= 'z')
|
||||
if (p[0] >= 'a' && p[0] <= 'f')
|
||||
x = (p[0] - 'a' + 0x0a) << 4;
|
||||
else if (p[0] >= 'A' && p[0] <= 'Z')
|
||||
else if (p[0] >= 'A' && p[0] <= 'F')
|
||||
x = (p[0] - 'A' + 0x0a) << 4;
|
||||
else if (p[0] >= '0' && p[0] <= '9')
|
||||
x = (p[0] - '0') << 4;
|
||||
else
|
||||
return (-1);
|
||||
if (p[1] >= 'a' && p[1] <= 'z')
|
||||
if (p[1] >= 'a' && p[1] <= 'f')
|
||||
x |= p[1] - 'a' + 0x0a;
|
||||
else if (p[1] >= 'A' && p[1] <= 'Z')
|
||||
else if (p[1] >= 'A' && p[1] <= 'F')
|
||||
x |= p[1] - 'A' + 0x0a;
|
||||
else if (p[1] >= '0' && p[1] <= '9')
|
||||
x |= p[1] - '0';
|
||||
@@ -1745,15 +1754,6 @@ decompression_cleanup(struct archive_read *a)
|
||||
#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
|
||||
if (xar->lzstream_valid)
|
||||
lzma_end(&(xar->lzstream));
|
||||
#elif defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
|
||||
if (xar->lzstream_valid) {
|
||||
if (lzmadec_end(&(xar->lzstream)) != LZMADEC_OK) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to clean up lzmadec decompressor");
|
||||
r = ARCHIVE_FATAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return (r);
|
||||
}
|
||||
@@ -2070,7 +2070,7 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
|
||||
if (xar->file->link > 0)
|
||||
if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2851,7 +2851,6 @@ xml_data(void *userData, const char *s, size_t len)
|
||||
xar->file->has |= HAS_XATTR;
|
||||
archive_strncpy(&(xar->xattr->fstype), s, len);
|
||||
break;
|
||||
break;
|
||||
case FILE_ACL_DEFAULT:
|
||||
case FILE_ACL_ACCESS:
|
||||
case FILE_ACL_APPLEEXTENDED:
|
||||
@@ -3343,6 +3342,326 @@ expat_read_toc(struct archive_read *a)
|
||||
XML_ParserFree(parser);
|
||||
return (ud.state);
|
||||
}
|
||||
#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */
|
||||
|
||||
#elif defined(HAVE_XMLLITE_H)
|
||||
|
||||
struct ArchiveStreamAdapter {
|
||||
const ISequentialStreamVtbl *lpVtbl; /* see asaStaticVtable */
|
||||
struct archive_read *a;
|
||||
};
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
asaQueryInterface(ISequentialStream *this, REFIID riid, void **ppv)
|
||||
{
|
||||
if (!IsEqualIID(riid, &IID_ISequentialStream)) {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
*ppv = this;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can dispense with reference counting as we tightly manage the lifetime
|
||||
* of an ArchiveStreamAdapter.
|
||||
*/
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
asaAddRef(ISequentialStream *this)
|
||||
{
|
||||
(void)this; /* UNUSED */
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
asaRelease(ISequentialStream *this)
|
||||
{
|
||||
(void)this; /* UNUSED */
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead)
|
||||
{
|
||||
struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;
|
||||
struct archive_read *a;
|
||||
struct xar *xar;
|
||||
const void *d = pv;
|
||||
size_t outbytes = cb;
|
||||
size_t used = 0;
|
||||
int r;
|
||||
|
||||
a = asa->a;
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
*pcbRead = 0;
|
||||
|
||||
if (xar->toc_remaining <= 0)
|
||||
return cb != 0 ? S_FALSE : S_OK;
|
||||
|
||||
r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
|
||||
if (r != ARCHIVE_OK)
|
||||
return E_FAIL;
|
||||
__archive_read_consume(a, used);
|
||||
xar->toc_remaining -= used;
|
||||
xar->offset += used;
|
||||
xar->toc_total += outbytes;
|
||||
PRINT_TOC(pv, outbytes);
|
||||
|
||||
*pcbRead = (ULONG)outbytes;
|
||||
return outbytes < cb ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
asaWrite(ISequentialStream *this, const void *pv, ULONG cb, ULONG *pcbWritten)
|
||||
{
|
||||
(void)this; /* UNUSED */
|
||||
(void)pv; /* UNUSED */
|
||||
(void)cb; /* UNUSED */
|
||||
if (!pcbWritten) return E_INVALIDARG;
|
||||
*pcbWritten = 0;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const ISequentialStreamVtbl asaStaticVtable = {
|
||||
.QueryInterface = asaQueryInterface,
|
||||
.AddRef = asaAddRef,
|
||||
.Release = asaRelease,
|
||||
.Read = asaRead,
|
||||
.Write = asaWrite,
|
||||
};
|
||||
|
||||
static int
|
||||
xmllite_create_stream_adapter(struct archive_read *a,
|
||||
struct ArchiveStreamAdapter **pasa)
|
||||
{
|
||||
struct ArchiveStreamAdapter *asa =
|
||||
calloc(1, sizeof(struct ArchiveStreamAdapter));
|
||||
if (!asa) {
|
||||
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
asa->lpVtbl = &asaStaticVtable;
|
||||
asa->a = a;
|
||||
*pasa = asa;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
typedef HRESULT(STDMETHODCALLTYPE *xmllite_wstr_func)(IXmlReader *, LPCWSTR *,
|
||||
UINT *);
|
||||
|
||||
/*
|
||||
* Returns an narrow-char archive_string in *as after calling
|
||||
* the wide-char COM API callee() on the XmlReader reader.
|
||||
* Sets an appropriate error on the archive if it fails.
|
||||
*/
|
||||
static int
|
||||
xmllite_call_return_as(struct archive_read *a, struct archive_string *as,
|
||||
IXmlReader *reader, xmllite_wstr_func callee)
|
||||
{
|
||||
LPCWSTR wcs;
|
||||
UINT wlen;
|
||||
|
||||
if (FAILED(callee(reader, &wcs, &wlen))) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"Failed to read XML data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
archive_string_init(as);
|
||||
if (archive_string_append_from_wcs(as, wcs, (size_t)wlen) < 0) {
|
||||
archive_string_free(as);
|
||||
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static char *
|
||||
xmllite_call_return_mbs(struct archive_read *a, IXmlReader *reader,
|
||||
xmllite_wstr_func callee)
|
||||
{
|
||||
char *ret;
|
||||
struct archive_string as;
|
||||
|
||||
if (xmllite_call_return_as(a, &as, reader, callee) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = strdup(as.s);
|
||||
archive_string_free(&as);
|
||||
if (ret == NULL) {
|
||||
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
xmllite_xmlattr_setup(struct archive_read *a,
|
||||
struct xmlattr_list *list, IXmlReader *reader)
|
||||
{
|
||||
struct xmlattr *attr;
|
||||
HRESULT hr;
|
||||
|
||||
list->first = NULL;
|
||||
list->last = &(list->first);
|
||||
hr = reader->lpVtbl->MoveToFirstAttribute(reader);
|
||||
/* Contrary to other checks, we're not using SUCCEEDED/FAILED
|
||||
* because MoveToNextAttribute returns *S_FALSE* (success!)
|
||||
* when it runs out of attributes.
|
||||
*/
|
||||
while (hr == S_OK) {
|
||||
/* Attributes implied as being default by the DTD are ignored */
|
||||
if (reader->lpVtbl->IsDefault(reader))
|
||||
continue;
|
||||
|
||||
attr = malloc(sizeof*(attr));
|
||||
if (attr == NULL) {
|
||||
archive_set_error(&(a->archive), ENOMEM,
|
||||
"Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
attr->name = xmllite_call_return_mbs(a, reader,
|
||||
reader->lpVtbl->GetLocalName);
|
||||
if (attr->name == NULL) {
|
||||
free(attr);
|
||||
/* xmllite_call_return_mbs sets an appropriate error */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
attr->value = xmllite_call_return_mbs(a, reader,
|
||||
reader->lpVtbl->GetValue);
|
||||
if (attr->value == NULL) {
|
||||
free(attr->name);
|
||||
free(attr);
|
||||
/* xmllite_call_return_mbs sets an appropriate error */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
attr->next = NULL;
|
||||
*list->last = attr;
|
||||
list->last = &(attr->next);
|
||||
hr = reader->lpVtbl->MoveToNextAttribute(reader);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to parse XML document");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
xmllite_read_toc(struct archive_read *a)
|
||||
{
|
||||
struct ArchiveStreamAdapter *asa = NULL;
|
||||
char *name;
|
||||
struct archive_string as;
|
||||
BOOL empty;
|
||||
XmlNodeType type;
|
||||
struct xmlattr_list list;
|
||||
IXmlReader *reader = NULL;
|
||||
int r = ARCHIVE_OK;
|
||||
|
||||
if ((r = xmllite_create_stream_adapter(a, &asa)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (FAILED(CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL))) {
|
||||
r = ARCHIVE_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (FAILED(reader->lpVtbl->SetInput(reader, (IUnknown *)asa))) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"Failed to prepare XML stream");
|
||||
r = ARCHIVE_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!reader->lpVtbl->IsEOF(reader)) {
|
||||
if (FAILED(reader->lpVtbl->Read(reader, &type))) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"Failed to read XML stream");
|
||||
r = ARCHIVE_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case XmlNodeType_Element:
|
||||
empty = reader->lpVtbl->IsEmptyElement(reader);
|
||||
|
||||
name = xmllite_call_return_mbs(a, reader,
|
||||
reader->lpVtbl->GetLocalName);
|
||||
if (name == NULL) {
|
||||
/* xmllite_call_return_mbs sets an appropriate error */
|
||||
r = ARCHIVE_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = xmllite_xmlattr_setup(a, &list, reader);
|
||||
if (r == ARCHIVE_OK) {
|
||||
r = xml_start(a, name, &list);
|
||||
}
|
||||
xmlattr_cleanup(&list);
|
||||
if (r == ARCHIVE_OK && empty) {
|
||||
xml_end(a, name);
|
||||
}
|
||||
|
||||
free(name);
|
||||
if (r != ARCHIVE_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
case XmlNodeType_EndElement:
|
||||
name = xmllite_call_return_mbs(a, reader,
|
||||
reader->lpVtbl->GetLocalName);
|
||||
if (name == NULL) {
|
||||
/* xmllite_call_return_mbs sets an appropriate error */
|
||||
r = ARCHIVE_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
xml_end(a, name);
|
||||
free(name);
|
||||
break;
|
||||
case XmlNodeType_Text:
|
||||
r = xmllite_call_return_as(a, &as, reader,
|
||||
reader->lpVtbl->GetValue);
|
||||
if (r != ARCHIVE_OK) {
|
||||
/* xmllite_call_return_as sets an appropriate error */
|
||||
goto out;
|
||||
}
|
||||
|
||||
xml_data(a, as.s, (int)archive_strlen(&as));
|
||||
archive_string_free(&as);
|
||||
|
||||
case XmlNodeType_None:
|
||||
case XmlNodeType_Attribute:
|
||||
case XmlNodeType_CDATA:
|
||||
case XmlNodeType_ProcessingInstruction:
|
||||
case XmlNodeType_Comment:
|
||||
case XmlNodeType_DocumentType:
|
||||
case XmlNodeType_Whitespace:
|
||||
case XmlNodeType_XmlDeclaration:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (reader)
|
||||
reader->lpVtbl->Release(reader);
|
||||
|
||||
free(asa);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(XMLLITE) */
|
||||
|
||||
#endif /* Support xar format */
|
||||
@@ -71,6 +71,7 @@
|
||||
#include "archive_private.h"
|
||||
#include "archive_rb.h"
|
||||
#include "archive_read_private.h"
|
||||
#include "archive_time_private.h"
|
||||
#include "archive_ppmd8_private.h"
|
||||
|
||||
#ifndef HAVE_ZLIB_H
|
||||
@@ -465,27 +466,6 @@ compression_name(const int compression)
|
||||
return "??";
|
||||
}
|
||||
|
||||
/* Convert an MSDOS-style date/time into Unix-style time. */
|
||||
static time_t
|
||||
zip_time(const char *p)
|
||||
{
|
||||
int msTime, msDate;
|
||||
struct tm ts;
|
||||
|
||||
msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
|
||||
msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
|
||||
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
|
||||
ts.tm_mday = msDate & 0x1f; /* Day of month. */
|
||||
ts.tm_hour = (msTime >> 11) & 0x1f;
|
||||
ts.tm_min = (msTime >> 5) & 0x3f;
|
||||
ts.tm_sec = (msTime << 1) & 0x3e;
|
||||
ts.tm_isdst = -1;
|
||||
return mktime(&ts);
|
||||
}
|
||||
|
||||
/*
|
||||
* The extra data is stored as a list of
|
||||
* id1+size1+data1 + id2+size2+data2 ...
|
||||
@@ -978,7 +958,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
}
|
||||
zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);
|
||||
zip_entry->compression = (char)archive_le16dec(p + 8);
|
||||
zip_entry->mtime = zip_time(p + 10);
|
||||
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 10));
|
||||
zip_entry->crc32 = archive_le32dec(p + 14);
|
||||
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
zip_entry->decdat = p[11];
|
||||
@@ -2134,15 +2114,15 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
|
||||
|
||||
if(order < 2 || restore_method > 2) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid parameter set in PPMd8 stream (order=%" PRId32 ", "
|
||||
"restore=%" PRId32 ")", order, restore_method);
|
||||
"Invalid parameter set in PPMd8 stream (order=%" PRIu32 ", "
|
||||
"restore=%" PRIu32 ")", order, restore_method);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Allocate the memory needed to properly decompress the file. */
|
||||
if(!__archive_ppmd8_functions.Ppmd8_Alloc(&zip->ppmd8, mem << 20)) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for PPMd8 stream: %" PRId32 " bytes",
|
||||
"Unable to allocate memory for PPMd8 stream: %" PRIu32 " bytes",
|
||||
mem << 20);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -3168,7 +3148,6 @@ archive_read_format_zip_read_data(struct archive_read *a,
|
||||
/* We can't decompress this entry, but we will
|
||||
* be able to skip() it and try the next entry. */
|
||||
return (ARCHIVE_FAILED);
|
||||
break;
|
||||
}
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
@@ -3987,7 +3966,7 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
|
||||
zip->has_encrypted_entries = 1;
|
||||
}
|
||||
zip_entry->compression = (char)archive_le16dec(p + 10);
|
||||
zip_entry->mtime = zip_time(p + 12);
|
||||
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 12));
|
||||
zip_entry->crc32 = archive_le32dec(p + 16);
|
||||
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
zip_entry->decdat = p[13];
|
||||
|
||||
@@ -154,7 +154,6 @@ static int archive_wstring_append_from_mbs_in_codepage(
|
||||
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 *,
|
||||
@@ -199,6 +198,29 @@ static int archive_string_normalize_D(struct archive_string *, const void *,
|
||||
static int archive_string_append_unicode(struct archive_string *,
|
||||
const void *, size_t, struct archive_string_conv *);
|
||||
|
||||
#if defined __LITTLE_ENDIAN__
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#elif defined __BIG_ENDIAN__
|
||||
#define IS_BIG_ENDIAN 1
|
||||
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define IS_BIG_ENDIAN 1
|
||||
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM64))
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#else
|
||||
// Detect endianness at runtime.
|
||||
static int
|
||||
is_big_endian(void)
|
||||
{
|
||||
uint16_t d = 1;
|
||||
|
||||
return (archive_be16dec(&d) == 1);
|
||||
}
|
||||
|
||||
#define IS_BIG_ENDIAN is_big_endian()
|
||||
#endif
|
||||
|
||||
static struct archive_string *
|
||||
archive_string_append(struct archive_string *as, const char *p, size_t s)
|
||||
{
|
||||
@@ -450,7 +472,8 @@ 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;
|
||||
int ret = 0;
|
||||
size_t count;
|
||||
UINT from_cp;
|
||||
|
||||
if (sc != NULL)
|
||||
@@ -472,7 +495,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
|
||||
ws = dest->s + dest->length;
|
||||
mp = (const unsigned char *)s;
|
||||
count = 0;
|
||||
while (count < (int)length && *mp) {
|
||||
while (count < length && *mp) {
|
||||
*ws++ = (wchar_t)*mp++;
|
||||
count++;
|
||||
}
|
||||
@@ -485,7 +508,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
|
||||
struct archive_string u16;
|
||||
int saved_flag = sc->flag;/* save current flag. */
|
||||
|
||||
if (is_big_endian())
|
||||
if (IS_BIG_ENDIAN)
|
||||
sc->flag |= SCONV_TO_UTF16BE;
|
||||
else
|
||||
sc->flag |= SCONV_TO_UTF16LE;
|
||||
@@ -495,16 +518,16 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
|
||||
* UTF-16BE/LE NFD ===> UTF-16 NFC
|
||||
* UTF-16BE/LE NFC ===> UTF-16 NFD
|
||||
*/
|
||||
count = (int)utf16nbytes(s, length);
|
||||
count = utf16nbytes(s, length);
|
||||
} else {
|
||||
/*
|
||||
* UTF-8 NFD ===> UTF-16 NFC
|
||||
* UTF-8 NFC ===> UTF-16 NFD
|
||||
*/
|
||||
count = (int)mbsnbytes(s, length);
|
||||
count = mbsnbytes(s, length);
|
||||
}
|
||||
u16.s = (char *)dest->s;
|
||||
u16.length = dest->length << 1;;
|
||||
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);
|
||||
@@ -516,23 +539,23 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
|
||||
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 = 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()) {
|
||||
if ((sc->flag & SCONV_FROM_UTF16BE) && !IS_BIG_ENDIAN) {
|
||||
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
|
||||
int b;
|
||||
size_t 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()) {
|
||||
} else if ((sc->flag & SCONV_FROM_UTF16LE) && IS_BIG_ENDIAN) {
|
||||
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
|
||||
int b;
|
||||
size_t b;
|
||||
for (b = 0; b < count; b++) {
|
||||
uint16_t val = archive_be16dec(u16+b);
|
||||
archive_le16enc(u16+b, val);
|
||||
@@ -556,21 +579,28 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
|
||||
|
||||
buffsize = dest->length + length + 1;
|
||||
do {
|
||||
int r;
|
||||
|
||||
/* MultiByteToWideChar is limited to int. */
|
||||
if (length > (size_t)INT_MAX ||
|
||||
(dest->buffer_length >> 1) > (size_t)INT_MAX)
|
||||
return (-1);
|
||||
/* Allocate memory for WCS. */
|
||||
if (NULL == archive_wstring_ensure(dest, buffsize))
|
||||
return (-1);
|
||||
/* Convert MBS to WCS. */
|
||||
count = MultiByteToWideChar(from_cp,
|
||||
r = MultiByteToWideChar(from_cp,
|
||||
mbflag, s, (int)length, dest->s + dest->length,
|
||||
(int)(dest->buffer_length >> 1) -1);
|
||||
if (count == 0 &&
|
||||
if (r == 0 &&
|
||||
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
/* Expand the WCS buffer. */
|
||||
buffsize = dest->buffer_length << 1;
|
||||
continue;
|
||||
}
|
||||
if (count == 0 && length != 0)
|
||||
if (r == 0 && length != 0)
|
||||
ret = -1;
|
||||
count = (size_t)r;
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
@@ -679,9 +709,9 @@ 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;
|
||||
int ret = 0;
|
||||
UINT to_cp;
|
||||
int wslen = (int)len;
|
||||
size_t count, wslen = len;
|
||||
|
||||
if (sc != NULL)
|
||||
to_cp = sc->to_cp;
|
||||
@@ -720,13 +750,13 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
|
||||
count = 0;
|
||||
defchar_used = 0;
|
||||
if (sc->flag & SCONV_TO_UTF16BE) {
|
||||
while (count < (int)len && *ws) {
|
||||
while (count < len && *ws) {
|
||||
archive_be16enc(u16+count, *ws);
|
||||
ws++;
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
while (count < (int)len && *ws) {
|
||||
while (count < len && *ws) {
|
||||
archive_le16enc(u16+count, *ws);
|
||||
ws++;
|
||||
count++;
|
||||
@@ -739,15 +769,21 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
|
||||
archive_string_ensure(as, as->length + len * 2 + 1))
|
||||
return (-1);
|
||||
do {
|
||||
int r;
|
||||
|
||||
defchar_used = 0;
|
||||
if (to_cp == CP_UTF8 || sc == NULL)
|
||||
dp = NULL;
|
||||
else
|
||||
dp = &defchar_used;
|
||||
count = WideCharToMultiByte(to_cp, 0, ws, wslen,
|
||||
/* WideCharToMultiByte is limited to int. */
|
||||
if (as->buffer_length - as->length - 1 > (size_t)INT_MAX ||
|
||||
wslen > (size_t)INT_MAX)
|
||||
return (-1);
|
||||
r = WideCharToMultiByte(to_cp, 0, ws, (int)wslen,
|
||||
as->s + as->length,
|
||||
(int)as->buffer_length - (int)as->length - 1, NULL, dp);
|
||||
if (count == 0 &&
|
||||
(int)(as->buffer_length - as->length - 1), NULL, dp);
|
||||
if (r == 0 &&
|
||||
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
/* Expand the MBS buffer and retry. */
|
||||
if (NULL == archive_string_ensure(as,
|
||||
@@ -755,8 +791,9 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
|
||||
return (-1);
|
||||
continue;
|
||||
}
|
||||
if (count == 0)
|
||||
if (r == 0)
|
||||
ret = -1;
|
||||
count = (size_t)r;
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
@@ -2032,7 +2069,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
|
||||
char *outp;
|
||||
size_t avail, bs;
|
||||
int return_value = 0; /* success */
|
||||
int to_size, from_size;
|
||||
size_t to_size, from_size;
|
||||
|
||||
if (sc->flag & SCONV_TO_UTF16)
|
||||
to_size = 2;
|
||||
@@ -2051,7 +2088,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
|
||||
remaining = length;
|
||||
outp = as->s + as->length;
|
||||
avail = as->buffer_length - as->length - to_size;
|
||||
while (remaining >= (size_t)from_size) {
|
||||
while (remaining >= from_size) {
|
||||
size_t result = iconv(cd, &itp, &remaining, &outp, &avail);
|
||||
|
||||
if (result != (size_t)-1)
|
||||
@@ -2174,6 +2211,8 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
|
||||
if (codepage != CP_UTF8)
|
||||
mbflag |= MB_PRECOMPOSED;
|
||||
|
||||
if (n > (size_t)INT_MAX)
|
||||
return (-1); /* Invalid */
|
||||
if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0)
|
||||
return (-1); /* Invalid */
|
||||
return (0); /* Okay */
|
||||
@@ -2327,7 +2366,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
cnt = utf8_count[ch];
|
||||
|
||||
/* Invalid sequence or there are not plenty bytes. */
|
||||
if ((int)n < cnt) {
|
||||
if (n < (size_t)cnt) {
|
||||
cnt = (int)n;
|
||||
for (i = 1; i < cnt; i++) {
|
||||
if ((s[i] & 0xc0) != 0x80) {
|
||||
@@ -2396,7 +2435,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
cnt = 6;
|
||||
else
|
||||
cnt = 1;
|
||||
if ((int)n < cnt)
|
||||
if (n < (size_t)cnt)
|
||||
cnt = (int)n;
|
||||
for (i = 1; i < cnt; i++) {
|
||||
if ((s[i] & 0xc0) != 0x80) {
|
||||
@@ -2612,7 +2651,7 @@ unicode_to_utf16be(char *p, size_t remaining, uint32_t uc)
|
||||
} else {
|
||||
if (remaining < 2)
|
||||
return (0);
|
||||
archive_be16enc(utf16, uc);
|
||||
archive_be16enc(utf16, (uint16_t)uc);
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
@@ -2634,7 +2673,7 @@ unicode_to_utf16le(char *p, size_t remaining, uint32_t uc)
|
||||
} else {
|
||||
if (remaining < 2)
|
||||
return (0);
|
||||
archive_le16enc(utf16, uc);
|
||||
archive_le16enc(utf16, (uint16_t)uc);
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
@@ -3499,10 +3538,9 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
|
||||
{
|
||||
struct archive_string tmp;
|
||||
const char *u16;
|
||||
int ll;
|
||||
BOOL defchar;
|
||||
char *mbs;
|
||||
size_t mbs_size, b;
|
||||
size_t mbs_size, b, ll;
|
||||
int ret = 0;
|
||||
|
||||
bytes &= ~1;
|
||||
@@ -3538,7 +3576,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
|
||||
|
||||
archive_string_init(&tmp);
|
||||
if (be) {
|
||||
if (is_big_endian()) {
|
||||
if (IS_BIG_ENDIAN) {
|
||||
u16 = _p;
|
||||
} else {
|
||||
if (archive_string_ensure(&tmp, bytes+2) == NULL)
|
||||
@@ -3551,7 +3589,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
|
||||
u16 = tmp.s;
|
||||
}
|
||||
} else {
|
||||
if (!is_big_endian()) {
|
||||
if (!IS_BIG_ENDIAN) {
|
||||
u16 = _p;
|
||||
} else {
|
||||
if (archive_string_ensure(&tmp, bytes+2) == NULL)
|
||||
@@ -3566,18 +3604,24 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
|
||||
}
|
||||
|
||||
do {
|
||||
int r;
|
||||
defchar = 0;
|
||||
ll = WideCharToMultiByte(sc->to_cp, 0,
|
||||
/* WideCharToMultiByte is limited to int. */
|
||||
if (bytes > (size_t)INT_MAX || mbs_size > (size_t)INT_MAX)
|
||||
return (-1);
|
||||
r = WideCharToMultiByte(sc->to_cp, 0,
|
||||
(LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,
|
||||
NULL, &defchar);
|
||||
/* Exit loop if we succeeded */
|
||||
if (ll != 0 ||
|
||||
if (r != 0 ||
|
||||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
ll = (size_t)r;
|
||||
break;
|
||||
}
|
||||
/* Else expand buffer and loop to try again. */
|
||||
ll = WideCharToMultiByte(sc->to_cp, 0,
|
||||
r = WideCharToMultiByte(sc->to_cp, 0,
|
||||
(LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);
|
||||
ll = (size_t)r;
|
||||
if (archive_string_ensure(as, ll +1) == NULL)
|
||||
return (-1);
|
||||
mbs = as->s + as->length;
|
||||
@@ -3605,14 +3649,6 @@ win_strncat_from_utf16le(struct archive_string *as, const void *_p,
|
||||
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.
|
||||
@@ -3651,16 +3687,21 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
|
||||
return (0);
|
||||
}
|
||||
do {
|
||||
count = MultiByteToWideChar(sc->from_cp,
|
||||
int r;
|
||||
if (length > (size_t)INT_MAX || (avail >> 1) > (size_t)INT_MAX)
|
||||
return (-1);
|
||||
r = MultiByteToWideChar(sc->from_cp,
|
||||
MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1);
|
||||
/* Exit loop if we succeeded */
|
||||
if (count != 0 ||
|
||||
if (r != 0 ||
|
||||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
count = (size_t)r;
|
||||
break;
|
||||
}
|
||||
/* Expand buffer and try again */
|
||||
count = MultiByteToWideChar(sc->from_cp,
|
||||
r = MultiByteToWideChar(sc->from_cp,
|
||||
MB_PRECOMPOSED, s, (int)length, NULL, 0);
|
||||
count = (size_t)r;
|
||||
if (archive_string_ensure(as16, (count +1) * 2)
|
||||
== NULL)
|
||||
return (-1);
|
||||
@@ -3673,7 +3714,7 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
|
||||
if (count == 0)
|
||||
return (-1);
|
||||
|
||||
if (is_big_endian()) {
|
||||
if (IS_BIG_ENDIAN) {
|
||||
if (!bigendian) {
|
||||
while (count > 0) {
|
||||
uint16_t v = archive_be16dec(u16);
|
||||
@@ -3811,9 +3852,9 @@ best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,
|
||||
ret = -1;
|
||||
}
|
||||
if (bigendian)
|
||||
archive_be16enc(utf16, c);
|
||||
archive_be16enc(utf16, (uint16_t)c);
|
||||
else
|
||||
archive_le16enc(utf16, c);
|
||||
archive_le16enc(utf16, (uint16_t)c);
|
||||
utf16 += 2;
|
||||
}
|
||||
as16->length = utf16 - as16->s;
|
||||
|
||||
@@ -2286,5 +2286,4 @@ static const struct unicode_decomposition_table u_decomposition_table[] = {
|
||||
{ 0x110AB , 0x110A5 , 0x110BA },
|
||||
};
|
||||
|
||||
#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
|
||||
|
||||
#endif /* !ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
|
||||
@@ -116,8 +116,14 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
|
||||
|
||||
long_flag = '\0';
|
||||
switch(*p) {
|
||||
case 'j':
|
||||
case 'l':
|
||||
if (p[1] == 'l') {
|
||||
long_flag = 'L';
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
__LA_FALLTHROUGH;
|
||||
case 'j':
|
||||
case 'z':
|
||||
long_flag = *p;
|
||||
p++;
|
||||
@@ -136,6 +142,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
|
||||
switch(long_flag) {
|
||||
case 'j': s = va_arg(ap, intmax_t); break;
|
||||
case 'l': s = va_arg(ap, long); break;
|
||||
case 'L': s = va_arg(ap, long long); break;
|
||||
case 'z': s = va_arg(ap, ssize_t); break;
|
||||
default: s = va_arg(ap, int); break;
|
||||
}
|
||||
@@ -144,6 +151,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
|
||||
case 's':
|
||||
switch(long_flag) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
pw = va_arg(ap, wchar_t *);
|
||||
if (pw == NULL)
|
||||
pw = L"(null)";
|
||||
@@ -172,6 +180,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
|
||||
switch(long_flag) {
|
||||
case 'j': u = va_arg(ap, uintmax_t); break;
|
||||
case 'l': u = va_arg(ap, unsigned long); break;
|
||||
case 'L': u = va_arg(ap, unsigned long long); break;
|
||||
case 'z': u = va_arg(ap, size_t); break;
|
||||
default: u = va_arg(ap, unsigned int); break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*-
|
||||
* Copyright © 2025 ARJANEN Loïc Jean David
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_time_private.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600)
|
||||
#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000)
|
||||
#define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS)
|
||||
#define DOS_MIN_TIME 0x00210000U
|
||||
#define DOS_MAX_TIME 0xff9fbf7dU
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <winnt.h>
|
||||
/* Windows FILETIME to NTFS time. */
|
||||
uint64_t
|
||||
FILETIME_to_ntfs(const FILETIME* filetime)
|
||||
{
|
||||
ULARGE_INTEGER utc;
|
||||
utc.HighPart = filetime->dwHighDateTime;
|
||||
utc.LowPart = filetime->dwLowDateTime;
|
||||
return utc.QuadPart;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Convert an MSDOS-style date/time into Unix-style time. */
|
||||
int64_t
|
||||
dos_to_unix(uint32_t dos_time)
|
||||
{
|
||||
uint16_t msTime, msDate;
|
||||
struct tm ts;
|
||||
time_t t;
|
||||
|
||||
msTime = (0xFFFF & dos_time);
|
||||
msDate = (dos_time >> 16);
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
|
||||
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
|
||||
ts.tm_mday = msDate & 0x1f; /* Day of month. */
|
||||
ts.tm_hour = (msTime >> 11) & 0x1f;
|
||||
ts.tm_min = (msTime >> 5) & 0x3f;
|
||||
ts.tm_sec = (msTime << 1) & 0x3e;
|
||||
ts.tm_isdst = -1;
|
||||
t = mktime(&ts);
|
||||
return (int64_t)(t == (time_t)-1 ? INT32_MAX : t);
|
||||
}
|
||||
|
||||
/* Convert into MSDOS-style date/time. */
|
||||
uint32_t
|
||||
unix_to_dos(int64_t unix_time)
|
||||
{
|
||||
struct tm *t;
|
||||
uint32_t dt;
|
||||
time_t ut = unix_time;
|
||||
#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
|
||||
struct tm tmbuf;
|
||||
#endif
|
||||
|
||||
if (sizeof(time_t) < sizeof(int64_t) && (int64_t)ut != unix_time) {
|
||||
ut = (time_t)(unix_time > 0 ? INT32_MAX : INT32_MIN);
|
||||
}
|
||||
|
||||
#if defined(HAVE_LOCALTIME_S)
|
||||
t = localtime_s(&tmbuf, &ut) ? NULL : &tmbuf;
|
||||
#elif defined(HAVE_LOCALTIME_R)
|
||||
t = localtime_r(&ut, &tmbuf);
|
||||
#else
|
||||
t = localtime(&ut);
|
||||
#endif
|
||||
dt = 0;
|
||||
if (t != NULL && t->tm_year >= INT_MIN + 80) {
|
||||
const int year = t->tm_year - 80;
|
||||
|
||||
if (year & ~0x7f) {
|
||||
dt = year > 0 ? DOS_MAX_TIME : DOS_MIN_TIME;
|
||||
}
|
||||
else {
|
||||
dt += (year & 0x7f) << 9;
|
||||
dt += ((t->tm_mon + 1) & 0x0f) << 5;
|
||||
dt += (t->tm_mday & 0x1f);
|
||||
dt <<= 16;
|
||||
dt += (t->tm_hour & 0x1f) << 11;
|
||||
dt += (t->tm_min & 0x3f) << 5;
|
||||
/* Only counting every 2 seconds. */
|
||||
dt += (t->tm_sec & 0x3e) >> 1;
|
||||
}
|
||||
}
|
||||
if (dt > DOS_MAX_TIME) {
|
||||
dt = DOS_MAX_TIME;
|
||||
}
|
||||
else if (dt < DOS_MIN_TIME) {
|
||||
dt = DOS_MIN_TIME;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
/* Convert NTFS time to Unix sec/nsec */
|
||||
void
|
||||
ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
|
||||
{
|
||||
if (ntfs > INT64_MAX) {
|
||||
ntfs -= NTFS_EPOC_TICKS;
|
||||
*secs = ntfs / NTFS_TICKS;
|
||||
*nsecs = 100 * (ntfs % NTFS_TICKS);
|
||||
}
|
||||
else {
|
||||
lldiv_t tdiv;
|
||||
int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS;
|
||||
|
||||
tdiv = lldiv(value, NTFS_TICKS);
|
||||
*secs = tdiv.quot;
|
||||
*nsecs = (uint32_t)(tdiv.rem * 100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert Unix sec/nsec to NTFS time */
|
||||
uint64_t
|
||||
unix_to_ntfs(int64_t secs, uint32_t nsecs)
|
||||
{
|
||||
uint64_t ntfs;
|
||||
|
||||
if (secs < -(int64_t)NTFS_EPOC_TIME)
|
||||
return 0;
|
||||
|
||||
ntfs = secs + NTFS_EPOC_TIME;
|
||||
|
||||
if (ntfs > UINT64_MAX / NTFS_TICKS)
|
||||
return UINT64_MAX;
|
||||
|
||||
ntfs *= NTFS_TICKS;
|
||||
|
||||
if (ntfs > UINT64_MAX - nsecs/100)
|
||||
return UINT64_MAX;
|
||||
|
||||
return ntfs + nsecs/100;
|
||||
}
|
||||
+18
-8
@@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2015 Tim Kientzle
|
||||
* Copyright © 2025 ARJANEN Loïc Jean David
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -22,16 +22,26 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_GETDATE_H_INCLUDED
|
||||
#define ARCHIVE_GETDATE_H_INCLUDED
|
||||
#ifndef ARCHIVE_TIME_PRIVATE_H_INCLUDED
|
||||
#define ARCHIVE_TIME_PRIVATE_H_INCLUDED
|
||||
|
||||
#ifndef __LIBARCHIVE_BUILD
|
||||
#error This header is only to be used internally to libarchive.
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
time_t __archive_get_date(time_t now, const char *);
|
||||
|
||||
/* NTFS time to Unix sec/nsec. */
|
||||
void ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs);
|
||||
/* DOS time to Unix sec. */
|
||||
int64_t dos_to_unix(uint32_t dos);
|
||||
/* Unix sec/nsec to NTFS time. */
|
||||
uint64_t unix_to_ntfs(int64_t secs, uint32_t nsecs);
|
||||
/* Unix sec to DOS time. */
|
||||
uint32_t unix_to_dos(int64_t secs);
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
/* Windows FILETIME to NTFS time. */
|
||||
uint64_t FILETIME_to_ntfs(const FILETIME* filetime);
|
||||
#endif
|
||||
#endif /* ARCHIVE_TIME_PRIVATE_H_INCLUDED */
|
||||
@@ -77,7 +77,9 @@
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
static int archive_utility_string_sort_helper(char **, unsigned int);
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
static int __LA_LIBC_CC archive_utility_string_sort_helper(const void *, const void *);
|
||||
#endif
|
||||
|
||||
/* Generic initialization of 'struct archive' objects. */
|
||||
int
|
||||
@@ -629,74 +631,28 @@ __archive_ensure_cloexec_flag(int fd)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/*
|
||||
* Utility function to sort a group of strings using quicksort.
|
||||
* Utility functions to sort a group of strings using quicksort.
|
||||
*/
|
||||
static int
|
||||
archive_utility_string_sort_helper(char **strings, unsigned int n)
|
||||
__LA_LIBC_CC
|
||||
archive_utility_string_sort_helper(const void *p1, const void *p2)
|
||||
{
|
||||
unsigned int i, lesser_count, greater_count;
|
||||
char **lesser, **greater, **tmp, *pivot;
|
||||
int retval1, retval2;
|
||||
const char * const * const s1 = p1;
|
||||
const char * const * const s2 = p2;
|
||||
|
||||
/* 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 = realloc(lesser, lesser_count * sizeof(*tmp));
|
||||
if (!tmp) {
|
||||
free(greater);
|
||||
free(lesser);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
lesser = tmp;
|
||||
lesser[lesser_count - 1] = strings[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
greater_count++;
|
||||
tmp = realloc(greater, greater_count * sizeof(*tmp));
|
||||
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;
|
||||
return strcmp(*s1, *s2);
|
||||
}
|
||||
|
||||
int
|
||||
archive_utility_string_sort(char **strings)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
while (strings[size] != NULL)
|
||||
size_t size = 0;
|
||||
while (strings[size] != NULL)
|
||||
size++;
|
||||
return archive_utility_string_sort_helper(strings, size);
|
||||
qsort(strings, size, sizeof(char *),
|
||||
archive_utility_string_sort_helper);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
#endif
|
||||
@@ -46,11 +46,125 @@
|
||||
#endif
|
||||
#ifdef HAVE_ZSTD_H
|
||||
#include <zstd.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_LZO_LZOCONF_H
|
||||
#include <lzo/lzoconf.h>
|
||||
#endif
|
||||
#if HAVE_LIBXML_XMLVERSION_H
|
||||
#include <libxml/xmlversion.h>
|
||||
#elif HAVE_BSDXML_H
|
||||
#include <bsdxml.h>
|
||||
#elif HAVE_EXPAT_H
|
||||
#include <expat.h>
|
||||
#endif
|
||||
#if HAVE_MBEDTLS_VERSION_H
|
||||
#include <mbedtls/version.h>
|
||||
#endif
|
||||
#if HAVE_NETTLE_VERSION_H
|
||||
#include <nettle/version.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if HAVE_OPENSSL_OPENSSLV_H
|
||||
#include <openssl/opensslv.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#if HAVE_PCRE_H
|
||||
#include <pcre.h>
|
||||
#endif
|
||||
#if HAVE_PCRE2_H
|
||||
#include <pcre2.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_cryptor_private.h"
|
||||
#include "archive_digest_private.h"
|
||||
|
||||
static void
|
||||
archive_regex_version(struct archive_string* str)
|
||||
{
|
||||
#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H
|
||||
archive_strcat(str, " libpcre/");
|
||||
archive_strcat(str, archive_libpcre_version());
|
||||
#elif HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H
|
||||
archive_strcat(str, " libpcre2/");
|
||||
archive_strcat(str, archive_libpcre2_version());
|
||||
#else
|
||||
(void)str; /* UNUSED */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
archive_xml_version(struct archive_string* str)
|
||||
{
|
||||
#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2
|
||||
archive_strcat(str, " libxml2/");
|
||||
archive_strcat(str, archive_libxml2_version());
|
||||
#elif HAVE_BSDXML_H && HAVE_LIBBSDXML
|
||||
archive_strcat(str, " bsdxml/");
|
||||
archive_strcat(str, archive_libbsdxml_version());
|
||||
#elif HAVE_EXPAT_H && HAVE_LIBEXPAT
|
||||
archive_strcat(str, " expat/");
|
||||
archive_strcat(str, archive_libexpat_version());
|
||||
#else
|
||||
(void)str; /* UNUSED */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
archive_libb2_version(struct archive_string* str)
|
||||
{
|
||||
archive_strcat(str, " libb2/");
|
||||
#if HAVE_BLAKE2_H && HAVE_LIBB2
|
||||
#if defined(LIBB2_PKGCONFIG_VERSION)
|
||||
archive_strcat(str, LIBB2_PKGCONFIG_VERSION);
|
||||
#else
|
||||
archive_strcat(str, "system");
|
||||
#endif
|
||||
#else
|
||||
archive_strcat(str, "bundled");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
archive_crypto_version(struct archive_string* str)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto)
|
||||
archive_strcat(str, " CommonCrypto/");
|
||||
archive_strcat(str, archive_commoncrypto_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_CNG)
|
||||
archive_strcat(str, " cng/");
|
||||
archive_strcat(str, archive_cng_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_MBED)
|
||||
archive_strcat(str, " mbedtls/");
|
||||
archive_strcat(str, archive_mbedtls_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_NETTLE)
|
||||
archive_strcat(str, " nettle/");
|
||||
archive_strcat(str, archive_nettle_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL)
|
||||
archive_strcat(str, " openssl/");
|
||||
archive_strcat(str, archive_openssl_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_LIBMD)
|
||||
archive_strcat(str, " libmd/");
|
||||
archive_strcat(str, archive_libmd_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT)
|
||||
archive_strcat(str, " WinCrypt/");
|
||||
archive_strcat(str, archive_wincrypt_version());
|
||||
#endif
|
||||
// Just in case
|
||||
(void)str; /* UNUSED */
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_version_details(void)
|
||||
@@ -62,12 +176,17 @@ archive_version_details(void)
|
||||
const char *bzlib = archive_bzlib_version();
|
||||
const char *liblz4 = archive_liblz4_version();
|
||||
const char *libzstd = archive_libzstd_version();
|
||||
const char *liblzo = archive_liblzo2_version();
|
||||
const char *libiconv = archive_libiconv_version();
|
||||
const char *libacl = archive_libacl_version();
|
||||
const char *librichacl = archive_librichacl_version();
|
||||
const char *libattr = archive_libacl_version();
|
||||
|
||||
if (!init) {
|
||||
archive_string_init(&str);
|
||||
|
||||
archive_strcat(&str, ARCHIVE_VERSION_STRING);
|
||||
if (zlib != NULL) {
|
||||
if (zlib) {
|
||||
archive_strcat(&str, " zlib/");
|
||||
archive_strcat(&str, zlib);
|
||||
}
|
||||
@@ -91,6 +210,30 @@ archive_version_details(void)
|
||||
archive_strcat(&str, " libzstd/");
|
||||
archive_strcat(&str, libzstd);
|
||||
}
|
||||
if (liblzo) {
|
||||
archive_strcat(&str, " liblzo2/");
|
||||
archive_strcat(&str, liblzo);
|
||||
}
|
||||
archive_xml_version(&str);
|
||||
archive_regex_version(&str);
|
||||
archive_crypto_version(&str);
|
||||
archive_libb2_version(&str);
|
||||
if (librichacl) {
|
||||
archive_strcat(&str, " librichacl/");
|
||||
archive_strcat(&str, librichacl);
|
||||
}
|
||||
if (libacl) {
|
||||
archive_strcat(&str, " libacl/");
|
||||
archive_strcat(&str, libacl);
|
||||
}
|
||||
if (libattr) {
|
||||
archive_strcat(&str, " libattr/");
|
||||
archive_strcat(&str, libattr);
|
||||
}
|
||||
if (libiconv) {
|
||||
archive_strcat(&str, " libiconv/");
|
||||
archive_strcat(&str, libiconv);
|
||||
}
|
||||
}
|
||||
return str.s;
|
||||
}
|
||||
@@ -98,8 +241,8 @@ archive_version_details(void)
|
||||
const char *
|
||||
archive_zlib_version(void)
|
||||
{
|
||||
#ifdef HAVE_ZLIB_H
|
||||
return ZLIB_VERSION;
|
||||
#if HAVE_ZLIB_H && HAVE_LIBZ
|
||||
return zlibVersion();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
@@ -108,8 +251,8 @@ archive_zlib_version(void)
|
||||
const char *
|
||||
archive_liblzma_version(void)
|
||||
{
|
||||
#ifdef HAVE_LZMA_H
|
||||
return LZMA_VERSION_STRING;
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
return lzma_version_string();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
@@ -118,7 +261,7 @@ archive_liblzma_version(void)
|
||||
const char *
|
||||
archive_bzlib_version(void)
|
||||
{
|
||||
#ifdef HAVE_BZLIB_H
|
||||
#if HAVE_BZLIB_H && HAVE_LIBBZ2
|
||||
return BZ2_bzlibVersion();
|
||||
#else
|
||||
return NULL;
|
||||
@@ -128,12 +271,22 @@ archive_bzlib_version(void)
|
||||
const char *
|
||||
archive_liblz4_version(void)
|
||||
{
|
||||
#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
|
||||
#if HAVE_LZ4_H && HAVE_LIBLZ4
|
||||
#if LZ4_VERSION_NUMBER > 10705
|
||||
return LZ4_versionString();
|
||||
#elif LZ4_VERSION_NUMBER > 10300
|
||||
div_t major = div(LZ4_versionNumber(), 10000);
|
||||
div_t minor = div(major.rem, 100);
|
||||
static char lz4_version[9];
|
||||
snprintf(lz4_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem);
|
||||
return lz4_version;
|
||||
#else
|
||||
#define str(s) #s
|
||||
#define NUMBER(x) str(x)
|
||||
return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
|
||||
#undef NUMBER
|
||||
#undef str
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
@@ -143,7 +296,243 @@ const char *
|
||||
archive_libzstd_version(void)
|
||||
{
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
return ZSTD_VERSION_STRING;
|
||||
#if ZSTD_VERSION_NUMBER > 10300
|
||||
return ZSTD_versionString();
|
||||
#else
|
||||
div_t major = div(ZSTD_versionNumber(), 10000);
|
||||
div_t minor = div(major.rem, 100);
|
||||
static char zstd_version[9];
|
||||
snprintf(zstd_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem);
|
||||
return zstd_version;
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_liblzo2_version(void)
|
||||
{
|
||||
#if HAVE_LZO_LZOCONF_H && HAVE_LIBLZO2
|
||||
return LZO_VERSION_STRING;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libbsdxml_version(void)
|
||||
{
|
||||
#if HAVE_BSDXML_H && HAVE_LIBBSDXML
|
||||
return XML_ExpatVersion();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libxml2_version(void)
|
||||
{
|
||||
#if HAVE_LIBXML_XMLREADER_H && HAVE_LIBXML2
|
||||
return LIBXML_DOTTED_VERSION;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libexpat_version(void)
|
||||
{
|
||||
#if HAVE_EXPAT_H && HAVE_LIBEXPAT
|
||||
return XML_ExpatVersion();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_mbedtls_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_MBED) || defined(ARCHIVE_CRYPTO_MBED)
|
||||
static char mbed_version[9];
|
||||
mbedtls_version_get_string(mbed_version);
|
||||
return mbed_version;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_nettle_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_NETTLE) || defined(ARCHIVE_CRYPTO_NETTLE)
|
||||
static char nettle_version[6];
|
||||
snprintf(nettle_version, 6, "%d.%d", nettle_version_major(), nettle_version_minor());
|
||||
return nettle_version;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_openssl_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL) || defined(ARCHIVE_CRYPTO_OPENSSL)
|
||||
#ifdef OPENSSL_VERSION_STR
|
||||
return OPENSSL_VERSION_STR;
|
||||
#else
|
||||
#define OPENSSL_MAJOR (OPENSSL_VERSION_NUMBER >> 28)
|
||||
#define OPENSSL_MINOR ((OPENSSL_VERSION_NUMBER >> 20) & 0xFF)
|
||||
static char openssl_version[6];
|
||||
snprintf(openssl_version, 6, "%ld.%ld", OPENSSL_MAJOR, OPENSSL_MINOR);
|
||||
return openssl_version;
|
||||
#undef OPENSSL_MAJOR
|
||||
#undef OPENSSL_MINOR
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libmd_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_LIBMD) || defined(ARCHIVE_CRYPTO_LIBMD)
|
||||
return "system";
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_commoncrypto_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto) || defined(ARCHIVE_CRYPTO_CommonCrypto)
|
||||
return "system";
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_cng_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_CNG) || defined(ARCHIVE_CRYPTO_CNG)
|
||||
#ifdef BCRYPT_HASH_INTERFACE_MAJORVERSION_2
|
||||
return "2.0";
|
||||
#else
|
||||
return "1.0";
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_wincrypt_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_CRYPTO_WINCRYPT)
|
||||
HCRYPTPROV prov;
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
|
||||
return NULL;
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
|
||||
return NULL;
|
||||
}
|
||||
DWORD version, length = sizeof(version);
|
||||
if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) {
|
||||
return NULL;
|
||||
} else {
|
||||
char major = (version >> 8) & 0xFF;
|
||||
char minor = version & 0xFF;
|
||||
static char wincrypt_version[6];
|
||||
snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor);
|
||||
return wincrypt_version;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_librichacl_version(void)
|
||||
{
|
||||
#if HAVE_LIBRICHACL
|
||||
#if defined(LIBRICHACL_PKGCONFIG_VERSION)
|
||||
return LIBRICHACL_PKGCONFIG_VERSION;
|
||||
#else
|
||||
return "system";
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libacl_version(void)
|
||||
{
|
||||
#if HAVE_LIBACL
|
||||
#if defined(LIBACL_PKGCONFIG_VERSION)
|
||||
return LIBACL_PKGCONFIG_VERSION;
|
||||
#else
|
||||
return "system";
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libattr_version(void)
|
||||
{
|
||||
#if HAVE_LIBATTR
|
||||
#if defined(LIBATTR_PKGCONFIG_VERSION)
|
||||
return LIBATTR_PKGCONFIG_VERSION;
|
||||
#else
|
||||
return "system";
|
||||
#endif
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libiconv_version(void)
|
||||
{
|
||||
#if HAVE_LIBCHARSET && HAVE_ICONV_H
|
||||
char major = _libiconv_version >> 8;
|
||||
char minor = _libiconv_version & 0xFF;
|
||||
static char charset_version[6];
|
||||
snprintf(charset_version, 6, "%hhd.%hhd", major, minor);
|
||||
return charset_version;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libpcre_version(void)
|
||||
{
|
||||
#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H
|
||||
#define str(s) #s
|
||||
#define NUMBER(x) str(x)
|
||||
return NUMBER(PCRE_MAJOR) "." NUMBER(PCRE_MINOR);
|
||||
#undef NUMBER
|
||||
#undef str
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_libpcre2_version(void)
|
||||
{
|
||||
#if HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H
|
||||
#define str(s) #s
|
||||
#define NUMBER(x) str(x)
|
||||
return NUMBER(PCRE2_MAJOR) "." NUMBER(PCRE2_MINOR);
|
||||
#undef NUMBER
|
||||
#undef str
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
@@ -283,7 +283,7 @@ __archive_write_filters_open(struct archive_write *a)
|
||||
}
|
||||
|
||||
/*
|
||||
* Close all filtes
|
||||
* Close all filters
|
||||
*/
|
||||
static int
|
||||
__archive_write_filters_close(struct archive_write *a)
|
||||
|
||||
@@ -166,7 +166,7 @@ archive_filter_b64encode_open(struct archive_write_filter *f)
|
||||
}
|
||||
|
||||
archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
|
||||
state->mode, state->name.s);
|
||||
(unsigned int)state->mode, state->name.s);
|
||||
|
||||
f->data = state;
|
||||
return (0);
|
||||
|
||||
@@ -58,6 +58,7 @@ archive_write_set_compression_gzip(struct archive *a)
|
||||
struct private_data {
|
||||
int compression_level;
|
||||
int timestamp;
|
||||
char *original_filename;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
z_stream stream;
|
||||
int64_t total_in;
|
||||
@@ -113,6 +114,8 @@ archive_write_add_filter_gzip(struct archive *_a)
|
||||
f->free = &archive_compressor_gzip_free;
|
||||
f->code = ARCHIVE_FILTER_GZIP;
|
||||
f->name = "gzip";
|
||||
|
||||
data->original_filename = NULL;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
data->compression_level = Z_DEFAULT_COMPRESSION;
|
||||
return (ARCHIVE_OK);
|
||||
@@ -140,6 +143,7 @@ archive_compressor_gzip_free(struct archive_write_filter *f)
|
||||
#else
|
||||
__archive_write_program_free(data->pdata);
|
||||
#endif
|
||||
free((void*)data->original_filename);
|
||||
free(data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
@@ -165,6 +169,13 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
|
||||
data->timestamp = (value == NULL)?-1:1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "original-filename") == 0) {
|
||||
free((void*)data->original_filename);
|
||||
data->original_filename = NULL;
|
||||
if (value)
|
||||
data->original_filename = strdup(value);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/* Note: The "warn" return is just to inform the options
|
||||
* supervisor that we didn't handle it. It will generate
|
||||
@@ -210,7 +221,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
data->compressed[0] = 0x1f; /* GZip signature bytes */
|
||||
data->compressed[1] = 0x8b;
|
||||
data->compressed[2] = 0x08; /* "Deflate" compression */
|
||||
data->compressed[3] = 0; /* No options */
|
||||
data->compressed[3] = data->original_filename == NULL ? 0 : 0x8;
|
||||
if (data->timestamp >= 0) {
|
||||
time_t t = time(NULL);
|
||||
data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */
|
||||
@@ -229,6 +240,12 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
data->stream.next_out += 10;
|
||||
data->stream.avail_out -= 10;
|
||||
|
||||
if (data->original_filename != NULL) {
|
||||
strcpy((char*)data->compressed + 10, data->original_filename);
|
||||
data->stream.next_out += strlen(data->original_filename) + 1;
|
||||
data->stream.avail_out -= strlen(data->original_filename) + 1;
|
||||
}
|
||||
|
||||
f->write = archive_compressor_gzip_write;
|
||||
|
||||
/* Initialize compression library. */
|
||||
|
||||
@@ -155,7 +155,7 @@ archive_filter_uuencode_open(struct archive_write_filter *f)
|
||||
}
|
||||
|
||||
archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
|
||||
state->mode, state->name.s);
|
||||
(unsigned int)state->mode, state->name.s);
|
||||
|
||||
f->data = state;
|
||||
return (0);
|
||||
|
||||
Loaded 100 of 537 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user