Compare commits

...

304 Commits

Author SHA1 Message Date
Martin Matuška
8d1c9b95f1
Merge pull request #2838 from DHowett/revert-2826-waitpid
Revert "Wait for the process instead of busy wait loop"
2026-01-07 23:38:30 +01:00
Dustin L. Howett
dea03d6e00
Revert "Wait for the process instead of busy wait loop" 2026-01-07 13:42:41 -08:00
Martin Matuška
3cd503b75a
Merge pull request #2781 from AZero13/ints
Remove unneeded int cast
2026-01-05 10:35:59 +01:00
Martin Matuška
86851e3092
Merge pull request #2826 from AZero13/waitpid
Wait for the process instead of busy wait loop
2026-01-05 10:33:33 +01:00
Martin Matuška
02eba33825
Merge pull request #2836 from ngie-eign/add-freebsd-15-cirrus-ci
Expand the test matrix to include 15.x images/ZFS
2026-01-05 10:32:49 +01:00
Enji Cooper
0bb2058bd5 Expand the test matrix to include 15.x images/ZFS
This change adds support for the following test scenarios:

- 15.0-RELEASE - ZFS
- 15.0-STABLE - UFS
- 15.0-STABLE - ZFS

This additional testing aims to catch issues with 15.x, as well as
ensure libarchive use doesn't regress when run on ZFS-based hosts.

Signed-off-by: Enji Cooper <yaneurabeya@gmail.com>
2026-01-04 17:55:34 -08:00
Tim Kientzle
e663efb430
Merge pull request #2835 from jmcarp/build-illumos
Skip unsupported linker options on illumos.
2025-12-31 15:31:55 -08:00
Josh Carp
3ff73fdfce Skip unsupported linker options on illumos.
Building on illumos currently fails with:

```
ld: fatal: unrecognized option '--gc-sections'
```

This happens because `--gc-sections` isn't supported on illumos `ld`.
This patch updates CMakeLists.txt to skip unsupported linker options on
illumos. The flags used on other operating systems are optimizations
that don't affect correctness, so this change is safe.
2025-12-31 22:37:01 +00:00
Tim Kientzle
e91171c9a0
Merge pull request #2825 from AZero13/patch-2
Error check ret before calling copy_seek_stat
2025-12-27 10:52:17 -08:00
Tim Kientzle
7f27446a51
Merge pull request #2824 from AZero13/qosflags
Remove bitmask typo in dwSecurityQosFlags
2025-12-27 10:48:03 -08:00
Tim Kientzle
090fbc3655
Merge pull request #2827 from AZero13/free
Simplify file free
2025-12-27 10:31:27 -08:00
Tim Kientzle
8c2241a7e4
Merge pull request #2829 from AZero13/leak-shar
archive_write_shar_header: free shar->last_dir before replacement
2025-12-27 10:30:22 -08:00
Tim Kientzle
d54b2241b9
Merge pull request #2830 from AZero13/return
return early if archive_write_set_format_shar fails
2025-12-27 10:28:27 -08:00
Tim Kientzle
782cdd88b6
Merge pull request #2831 from AZero13/check-copy-length
Use copy_length as upper-bound, not strlen(p)
2025-12-27 10:27:12 -08:00
Tim Kientzle
d1b87af584
Merge pull request #2834 from AZero13/patch-5
Use #warning, not #warn
2025-12-27 10:21:44 -08:00
AZero13
9a089dc44a archive_write_shar_header: free shar->last_dir before replacement 2025-12-26 18:05:03 -05:00
AZero13
a55b8e8aec
Use #warning, not #warn
#warn is a GNU extension
2025-12-26 15:28:12 -05:00
AZero13
76558692a4 Use copy_length as upper-bound, not strlen(p) 2025-12-26 15:09:10 -05:00
AZero13
4a32d9ff7f return early if archive_write_set_format_shar fails 2025-12-26 15:05:46 -05:00
AZero13
998c0b4080 Simplify file free
free is fine if NULL
2025-12-26 14:45:42 -05:00
AZero13
030a93817c Wait for the process instead of busy wait loop 2025-12-26 13:54:21 -05:00
AZero13
9298dc503a
Error check ret before calling copy_seek_stat 2025-12-26 13:29:14 -05:00
AZero13
e54c735586 Remove bitmask typo in dwSecurityQosFlags
We seemed to have been isolating the wrong flags.
2025-12-26 13:19:56 -05:00
Martin Matuška
b2d68e2f1a
Merge pull request #2813 from AZero13/memcpy
We copy from p, not p + module_len
2025-12-26 10:22:13 +01:00
Martin Matuška
1cd0b9179c
Merge pull request #2796 from vcoxvco/fix_unninit
libarchive/archive_util.c: Uninitialized variable
2025-12-25 10:16:46 +01:00
Martin Matuška
095609e89b
Merge pull request #2816 from AZero13/strdup
Error check strdup for path name
2025-12-25 10:14:23 +01:00
Martin Matuška
5c84afd664
Merge pull request #2814 from AZero13/gname
uname_override checks gname_override when it should check uname_override
2025-12-25 10:04:44 +01:00
Martin Matuška
f366e98107
Merge pull request #2789 from libarchive/dependabot/github_actions/all-actions-50b857948b
CI: Bump the all-actions group across 1 directory with 3 updates
2025-12-25 10:03:34 +01:00
Martin Matuška
c4597a73f3
Merge pull request #2815 from AZero13/=
Use >=, not =>
2025-12-25 10:00:35 +01:00
dependabot[bot]
79fac84eb2
CI: Bump the all-actions group across 1 directory with 3 updates
Bumps the all-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `actions/checkout` from 5.0.0 to 5.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](08c6903cd8...93cb6efe18)

Updates `actions/upload-artifact` from 4.6.2 to 5.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](ea165f8d65...330a01c490)

Updates `github/codeql-action` from 3.30.6 to 4.31.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](64d10c1313...014f16e7ab)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: github/codeql-action
  dependency-version: 4.31.3
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-25 08:53:17 +00:00
Martin Matuška
8042630d4f
Merge pull request #2819 from GabrielBarrantes/work/typos
Improve wording
2025-12-25 09:48:17 +01:00
Martin Matuška
214ee3edc7
Merge pull request #2820 from skypher/oss-fuzz-expansion
Expand OSS-Fuzz integration: 1 → 25 fuzz targets
2025-12-25 09:47:17 +01:00
Leslie P. Polzer
eb6f992ba1 Refactor all fuzzers to use shared fuzz_helpers.h
Complete the refactoring of all 25 fuzzers:
- Remove duplicate Buffer struct definitions from 15 format fuzzers
- Remove duplicate DataConsumer class from 7 API fuzzers
- Update consume_bytes() calls to match new signature
- All fuzzers now use shared helpers from fuzz_helpers.h

This eliminates ~1000 lines of duplicated code.
2025-12-22 04:53:06 +00:00
Leslie P. Polzer
544b07541b Refactor fuzzers: add shared header, remove system() call
- Add fuzz_helpers.h with shared Buffer, reader_callback, DataConsumer
- Replace system("rm -rf") with nftw-based remove_directory_tree()
- Refactor entry, tar, write_disk fuzzers to use shared helpers
- Reduces code duplication and improves maintainability
2025-12-22 04:26:57 +00:00
Leslie P. Polzer
5e88593708 Expand OSS-Fuzz integration: 1 → 25 fuzz targets
Add comprehensive fuzzing coverage for libarchive:

Format-specific fuzzers (13):
- tar, zip, 7zip, rar, rar5, xar, cab, lha, iso9660, cpio, warc, mtree, ar

Security-critical fuzzers (4):
- encryption: encrypted archive handling
- write_disk: extraction path traversal
- read_disk: filesystem traversal, symlinks
- entry: ACL functions (previously 0% coverage)

API fuzzers (7):
- write: archive creation
- linkify: hardlink detection (complexity 775, was 0%)
- match: inclusion/exclusion patterns
- string: encoding conversions (UTF-8, wide chars)
- seek: seekable archive operations
- roundtrip: write-then-read consistency
- filter: compression/decompression

Supporting files:
- 14 dictionaries with format-specific magic bytes
- 9 options files for complex fuzzers
- Updated build script with seed corpora generation

Targets previously uncovered functions:
- archive_entry_linkify (complexity 775)
- ACL functions (complexity 705-713)
- xar_read_header (was 10.11% coverage)

Expected coverage improvement: 74% → 85-95%
2025-12-22 04:08:26 +00:00
Gabriel Barrantes
8f3fcf9ecd Improve wording 2025-12-21 17:30:42 -06:00
Tim Kientzle
6e77f521fa
Merge pull request #2812 from AZero13/w
Fix p == null copy paste error
2025-12-18 07:52:10 -08:00
AZero13
50a67c9223 Error check strdup for path name 2025-12-16 21:50:06 -05:00
AZero13
b39f91e5da Use >=, not => 2025-12-16 21:48:45 -05:00
AZero13
55fbf225c8 uname_override checks gname_override when it should check uname_override 2025-12-16 21:44:31 -05:00
AZero13
e75e5892fd We copy from p, not p + module_len 2025-12-16 21:41:05 -05:00
AZero13
784b778f3b Fix p == null copy paste error 2025-12-16 21:37:16 -05:00
Tim Kientzle
b51e59bcfb
Merge pull request #2807 from KlaraSystems/des/list-tests
Add option to list tests
2025-12-12 17:19:37 -08:00
Martin Matuška
a7f3b56af6
Merge pull request #2809 from mmatuska/fix/2787
tar: fix off-bounds read resulting from #2787 (3150539ed)
2025-12-12 12:04:09 +01:00
Martin Matuska
cfb02de558 tar: fix off-bounds read resulting from #2787 (3150539ed) 2025-12-09 22:40:42 +01:00
Dag-Erling Smørgrav
8295366f94 test_main: Add option to list tests
The test runner already lists available tests if it fails to parse the
command line, but add a -l option to explicitly do this without also
printing an error message and a summary of options.
2025-12-06 14:45:40 +01:00
Tim Kientzle
8c86c46d1b
Merge pull request #2805 from fredldotme/android-recovery
libarchive & contrib: Build as static binary for the Android recovery
2025-12-04 04:17:34 -08:00
Alfred Neumayer
752df6abb7 libarchive & contrib: Build as static binary for the Android recovery
Adds a 'bsdtar-recovery' Android build target for use in Android recoveries
as a static binary, and fixes some build failures on the get-go.

Tested on halium-7.1, halium-9.0 & halium-13.0.

Change-Id: I9b656e7016d4bf21517e2edb18f2a7733edc6982
2025-12-04 06:34:21 +01:00
Martin Matuška
728b43c0c1
Merge pull request #2800 from mmatuska/fix/freebsdci
CI: use gmake in Cirrus FreeBSD build
2025-12-01 13:31:22 +01:00
Martin Matuska
0a594ab77d CI: use gmake in Cirrus FreeBSD build 2025-11-28 22:31:25 +01:00
Martin Matuška
a819cc2829
Merge pull request #2797 from mmatuska/fix/treefuncs
Partially revert "Merge pull request #2679 from AZero13/error"
2025-11-28 00:57:09 +01:00
Tim Kientzle
1b9b42720f
Merge pull request #2799 from AZero13/idk
Prevent unneeded truncation
2025-11-26 21:08:01 -08:00
AZero13
827905c93f Prevent unneeded truncation
There is no reason we need to cast when every data type involved is size_t
2025-11-26 15:35:54 -05:00
Martin Matuska
aac59c1bd5 Partially revert "Merge pull request #2679 from AZero13/error"
This reverts commit d8aaf88c9feab047139df4cae60d845764a2480a, reversing
changes made to ee49ac81068f93754f004368f2cc72c95a8bf056.

tree_reopen() and tree_dup() return NULL only of they
are unable to allocate memory. Otherwise libarchive enters
ARCHIVE_FATAL if trying to walk an enterable but unreadable
directory.

__archive_ensure_cloexec_flag() operates only on fd >= 0
so there is no need to skip it

I have reimplemented the check around fdopendir()

Reported by:	Christian Weisgerber from OpenBSD
2025-11-24 14:16:53 +01:00
vcoxvco
f49372e945 libarchive/archive_util.c:__archive_issetugid: Fix uninitialized variable rgid 2025-11-23 19:27:42 +01:00
Tim Kientzle
8ef2084104
Merge pull request #2791 from KlaraSystems/des/383-fixes
Fix issues encountered while importing 3.8.3 downstream
2025-11-20 22:24:38 -08:00
Tim Kientzle
e17f169356
Merge pull request #2792 from KlaraSystems/des/generate-list
Generate test lists reliably and deterministically
2025-11-20 22:22:32 -08:00
Tim Kientzle
47809f10bf
Merge pull request #2793 from bgilbert/rar
Add missing rar5 test case to dist
2025-11-20 22:19:23 -08:00
Tim Kientzle
81bc00a549
Merge pull request #2787 from ljdarj/aar
Fix bsdtar zero-length pattern issue.
2025-11-20 21:40:17 -08:00
ARJANEN Loïc Jean David
3150539edb Fix bsdtar zero-length pattern issue.
Uses the sed-like way (and Java-like, and .Net-like, and Javascript-like…) to fix this issue of advancing the string to be processed by one if the match is zero-length.

Fixes libarchive/libarchive#2725 and solves libarchive/libarchive#2438.
2025-11-21 00:44:38 +01:00
Benjamin Gilbert
8f7d334646 Add missing rar5 test case to dist
Fixes: aafb078b7c ("Update 'archive_mstring_update_utf8' to attempt UTF8->WCS conversion on Windows if MBS conversion fails (#1978)")
2025-11-19 00:12:36 -08:00
Dag-Erling Smørgrav
12522911fa Fix low-hanging type issues 2025-11-19 01:18:18 +01:00
Dag-Erling Smørgrav
1890755ab2 Fix lseek argument order 2025-11-19 01:16:29 +01:00
Dag-Erling Smørgrav
35aac8a925 Fix the condition for using LIBXML_DOTTED_VERSION 2025-11-19 01:15:48 +01:00
Dag-Erling Smørgrav
fdec8c2f24 Improve test list generation
Update the lists of tests reliably and deterministically when the test sources change.
2025-11-19 01:12:50 +01:00
Dag-Erling Smørgrav
2df76f52c2 Clean up the top-level Makefile
Most of this is just moving headers out from *_SOURCES.
2025-11-19 01:05:41 +01:00
Martin Matuška
ce7b3f1c15
Merge pull request #2771 from mostynb/lz4_with_leading_skippable_frames
Support both lz4 and zstd data with leading skippable frames
2025-11-17 20:30:16 +01:00
Martin Matuška
dbacda991c
Merge pull request #2751 from KlaraSystems/des/zip_magic_numbers
Avoid magic numbers in zip support code
2025-11-17 20:27:46 +01:00
Martin Matuška
2caee6a37e
Merge pull request #2752 from KlaraSystems/des/safe-writes-umask
Set umask before testing safe writes
2025-11-17 20:26:35 +01:00
Martin Matuška
d5bd2dfafe
Merge pull request #2755 from mmatuska/fix/cirrusci
CI: update FreeBSD 14 build environment
2025-11-17 20:24:53 +01:00
Tim Kientzle
e1c3061b12
Merge pull request #2783 from YoshiRulz/docs-fix-typo
Fix typo in archive_entry_stat(3) man page
2025-11-16 16:18:03 -08:00
Tim Kientzle
c2333a511d
Merge pull request #2738 from cmcgee1024/add_clang_module_map
Add a clang module map for libarchive
2025-11-16 16:17:54 -08:00
YoshiRulz
d8fba4df3a
Fix typo in archive_entry_stat(3) man page 2025-11-13 12:46:23 +10:00
Chris McGee
f75b5ddab0
Provide a detailed description of the libarchive module map file 2025-11-12 08:42:03 -05:00
AZero13
02a76f2dc9 Remove unneeded int cast 2025-11-11 11:47:26 -05:00
Tim Kientzle
c5cc510145
Merge pull request #2778 from AZero13/result-0
Set *result to 0 when the tar flush fails.
2025-11-06 20:17:19 -08:00
Tim Kientzle
ab09af7304
Merge pull request #2654 from AZero13/swapping-2
s is a signed int, so make it signed int
2025-11-06 20:15:08 -08:00
Tim Kientzle
e929454ec8
Merge pull request #2779 from AZero13/descriptor
file_open should close if fstat fails
2025-11-06 20:13:10 -08:00
AZero13
3aa9c22ddf file_open should close if fstat fails 2025-11-06 11:14:45 -05:00
AZero13
daf5abf802 Add error handling 2025-11-06 10:46:27 -05:00
Rose
f18a754d02 s is a signed int, so make it signed int 2025-11-06 10:44:16 -05:00
AZero13
3396ba84d7 Set *result to 0 when the tar flush fails.
We should not uninitialize 0 when an error happens. Because t is then checked.
2025-11-06 10:02:41 -05:00
Tim Kientzle
26c769ecdc
Merge pull request #2775 from AZero13/off-by-one
[tar] Bounds check newdir_len
2025-11-04 19:30:01 -08:00
AZero13
45a873e998 Bounds check newdir_len
Honestly, this is of little consequence; if old_len is too big the program will crash anyway. However, an error exists just in case.
2025-11-04 19:02:08 -05:00
Tim Kientzle
fa5f70627c
Merge pull request #2769 from kientzle/kientzle-issue2765
Fix a buffer overrun when reading truncated 7zip headers
2025-11-02 14:17:48 -08:00
Tim Kientzle
c45a07854d
Merge pull request #2772 from moubctez/forget_name_max
Remove name_max leftover
2025-11-02 09:08:31 -08:00
Adam Ciarciński
f80b1ae294
Remove name_max leftover 2025-11-02 09:49:02 +01:00
Mostyn Bramley-Moore
1435c4b20c Skip over LZ4/zstd skippable frames when detecting data format
Since LZ4 and zstd share the same format for skippable frames, we need
to skip over these frames when trying to detect the format of compressed
data. Let's read up to something like 64kb of data when performing this
scanning.

Note that the LZ4 specification advises against starting with a skippable
frame, but doesn't forbid it:
> For the purpose of facilitating identification, it is discouraged to
> start a flow of concatenated frames with a skippable frame. If there
> is a need to start such a flow with some user data encapsulated into
> a skippable frame, it's recommended to start with a zero-byte LZ4
> frame followed by a skippable frame. This will make it easier for
> file type identifiers.

Resolves #2692.
2025-11-01 22:43:38 +01:00
Mostyn Bramley-Moore
989a303793 Test that we can read lz4 data with leading skippable frames
This is expected to fail until a followup commit, because lz4 and zstd
skippable frames are the same format and we don't skip over those when
performing format detection (yet).

Relates to #2692.
2025-11-01 22:23:21 +01:00
Tim Kientzle
f02961f402 Correct the new test expectations 2025-10-31 22:37:33 -07:00
Tim Kientzle
dc6c0c5f35 Fix a buffer overrun when reading truncated 7zip headers
This adjusts the request size for reading data from a 7zip SFX header
to ensure we get enough bytes to cover the following checks.

Resolves #2765
2025-10-31 22:31:45 -07:00
Tim Kientzle
ce614c6524
Merge pull request #2768 from Commandoss/master
Fix for an out-of-bounds buffer overrun when using p[H_LEVEL_OFFSET]
2025-10-31 22:07:19 -07:00
Tim Kientzle
8855146220
Merge pull request #2767 from KlaraSystems/des/posix_spawn
Replace system() with posix_spawn() if available
2025-10-31 07:27:15 -07:00
Tim Kientzle
edbada88c0
Merge pull request #2766 from mostynb/fix_mac_signed_unsigned_comparison
Fix signed-unsigned comparison in add_trivial_nfs4_acl
2025-10-31 07:23:44 -07:00
Илья
212426e751
heap-use-after-free(read) at src/libarchive/archive_read_support_format_lha.c:692:6 2025-10-31 15:23:55 +03:00
Mostyn Bramley-Moore
83c30ee813 Fix signed-unsigned comparison in add_trivial_nfs4_acl
Resolves #2760
2025-10-30 11:29:55 +01:00
Tim Kientzle
d2e861769c
Merge pull request #2753 from KlaraSystems/des/temp-files
Create temporary files in the target directory
2025-10-28 17:13:18 -07:00
Martin Matuska
89cbfe1028 CI: update FreeBSD 14 build environment 2025-10-15 23:41:46 +02:00
Dag-Erling Smørgrav
1c08abc60d Create temporary files in the target directory
Whenever we need to create a temporary file while writing to disk on a
POSIX system, try to create it in the same directory as the final file
instead of the current working directory.  The target directory can
reasonably be expected to be writable (and if it isn't, creating the
file will fail anyway), but the current working directory may not be.

While here, consistently use __archive_mkstemp(), and increase the
template from six to eight random characters.

Fixes:		2e73ea3a7db1 ("Fix max path-length metadata writing (#2243)")
Fixes:		e12c955dca63 ("Unify temporary directory handling")
2025-10-15 09:41:06 +02:00
Dag-Erling Smørgrav
8fff509f1a Replace system() with posix_spawn() if available
Some platforms disallow system() due to its perceived insecurity.
Luckily, we can be just as insecure using the more palatable
posix_spawn() instead!
2025-10-14 19:17:53 +02:00
Dag-Erling Smørgrav
d0f69b355d Add archive_string_dirname()
This function performs the equivalent of POSIX dirname(3) on a
struct archive_string.
2025-10-14 02:08:44 +02:00
Dag-Erling Smørgrav
7976476c9f Set umask before testing safe writes
Fixes:		27588eba5077 ("Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES")
2025-10-13 21:49:29 +02:00
Dag-Erling Smørgrav
51b3e14257 zip: Increase max size of Mac metadata
Raise the maximum size of Mac metadata from 4 MiB to 10 MiB, as that is
the value used by Apple themselves in the version of libarchive included
in Darwin.
2025-10-13 21:39:13 +02:00
Dag-Erling Smørgrav
33ac104169 zip: Avoid magic numbers
Provide preprocessor macros for two recurring magic numbers in the zip
support code: the length of the local file header (30 bytes) and the
maximum allowable size for Mac metadata (4 MiB).
2025-10-13 21:39:00 +02:00
Tim Kientzle
de73860cda
Merge pull request #2737 from kientzle/kientzle-volume-header-overflow
Fix an infinite loop when parsing `V` headers
2025-10-13 10:58:26 -07:00
Tim Kientzle
d207d816d0
Merge pull request #2749 from KlaraSystems/des/tempdir
Unify temporary directory handling
2025-10-13 10:57:18 -07:00
Dag-Erling Smørgrav
12cdd35f31 Drop unused variable.
Fixes:		a335429c5e71 ("Drop support for readdir_r()")
2025-10-13 16:58:44 +02:00
Dag-Erling Smørgrav
e12c955dca Unify temporary directory handling
In archive_util.c, we have a private function named get_tempdir() which
is used by __archive_mktemp() to get the temporary directory if the
caller did not pass one.

In archive_read_disk_entry_from_file.c, we use the same logic with a
slight twist (don't trust the environment if setugid) to create a
temporary file for metadata.

Merge the two by renaming get_tempdir() to __archive_get_tempdir() and
unstaticizing it (with a prototype in archive_private.h).
2025-10-13 16:58:44 +02:00
Martin Matuška
46fe318edd
Merge pull request #2722 from dependabot
CI: Bump the all-actions group across 1 directory with 3 updates
2025-10-11 22:12:11 +02:00
Tim Kientzle
582799ee57
Merge pull request #2746 from pbrisbin/patch-1
Fix invalid quoting in archive_entry_paths.3
2025-10-07 06:09:01 -07:00
dependabot[bot]
b12d1c14d1
CI: Bump the all-actions group across 1 directory with 3 updates
Bumps the all-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [github/codeql-action](https://github.com/github/codeql-action) and [ossf/scorecard-action](https://github.com/ossf/scorecard-action).


Updates `actions/checkout` from 4.2.2 to 5.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

Updates `github/codeql-action` from 3.28.18 to 3.29.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](ff0a06e83c...76621b61de)

Updates `ossf/scorecard-action` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](f49aabe0b5...05b42c6244)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: github/codeql-action
  dependency-version: 3.29.8
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 16:07:23 +00:00
Pat Brisbin
6d8e1a883c
Fix invalid quoting in archive_entry_paths.3 2025-10-06 08:23:26 -04:00
Tim Kientzle
eb54a4d869 Add test case 2025-10-04 10:03:08 -07:00
Tim Kientzle
fda50c79ba
Merge pull request #2740 from dunhor/gnutar_longpath_unicode
Check WCS pathname in header_gnutar before overwriting
2025-10-03 20:43:21 -07:00
Tim Kientzle
372e709c1a
Merge pull request #2729 from KlaraSystems/des/leak-on-fatal
Don't leak memory on fatal error
2025-09-27 10:25:03 -07:00
Tim Kientzle
4ecf62fbd7
Merge pull request #2742 from bradking/parse-date-2038
parse_date: handle dates in 2038 and beyond if time_t is big enough
2025-09-26 19:52:20 -07:00
Tim Kientzle
c34ff01c02
Merge pull request #2741 from e-kwsm/extra-semi
fix: remove extra ';' outside of functions
2025-09-26 19:50:52 -07:00
Brad King
2d987e725f parse_date: handle dates in 2038 and beyond if time_t is big enough 2025-09-26 17:48:56 -04:00
Eisuke Kawashima
7fdf32b6b2
fix: remove extra ';' outside of functions 2025-09-26 19:41:30 +09:00
Duncan Horn
98731ad500 Check WCS pathname in header_gnutar 2025-09-25 16:03:18 -07:00
Tim Kientzle
be31ad37f3
Merge pull request #2739 from DHowett/remove-wincrypt
windows: remove support for WinCrypt
2025-09-24 06:21:23 -07:00
Dustin L. Howett
619e22cae7 WIP: remove WinCrypt support
I am debating whether to remove the checks for bcrypt as well (it is
supported on all versions of Windows currently targeted.)

fixes https://github.com/libarchive/libarchive/issues/2595
2025-09-22 16:05:17 -05:00
Chris McGee
52bf0d7de0
Add a clang module map for libarchive
When compiling libarchive using clang in module mode a special
module.modulemap file describes the structure of the header files
so that they can be imported modularly. Having this file makes
it easier for modular uses of the library out of the box so that
clients don't need to write their own, potentially making errors
in doing so.

Add a module.modulemap in the public header file location so that
clang and related tools can find it easily.
2025-09-22 11:11:02 -04:00
Tim Kientzle
36a530973a Fix an infinite loop when parsing V headers
Our tar header parsing tracks a count of bytes that need to be
consumed from the input.  After each header, we skip this many bytes,
discard them, and reset the count to zero.  The `V` header parsing
added the size of the `V` entry body to this count, but failed to
check whether that size was negative.  A negative size (from
overflowing the 64-bit signed number parsing) would decrement this
count, potentially leading us to consume zero bytes and leading to an
infinite loop parsing the same header over and over.

There are two fixes here:
* Check for a negative size for the `V` body
* Check for errors when skipping the bytes that
  need to be consumed

Thanks to Zhang Tianyi from Wuhan University for finding
and reporting this issue.
2025-09-16 08:25:57 -07:00
Tim Kientzle
39dc43b3e0
Merge pull request #2734 from kientzle/kientzle-ignore-too-long-gzip-filename
Ignore over-long gzip filename
2025-09-13 19:34:03 -07:00
Tim Kientzle
638464b477 Fix the reference to the archive object 2025-09-13 13:07:33 -07:00
Martin Matuška
ab5cb61f49
Merge pull request #2735 from kientzle/kientzle-err.h-conflict
Rename err.h to avoid conflict with system header
2025-09-13 22:01:52 +02:00
Martin Matuška
38debf6be1
Merge pull request #2731 from mmatuska/fix/macosci
CI: add workaround for cmake installed from local/pinned tab on GH/MacOS
2025-09-13 21:36:29 +02:00
Martin Matuška
e1dea559c7
Merge pull request #2732 from mmatuska/fix/safe-dir-over-reg-win
win: add complementary safe writes fix for Windows to 27588eba5 (#2477)
2025-09-13 21:36:13 +02:00
Tim Kientzle
96f76577d3 Rename err.h to avoid conflict with system header
Depending on header search path ordering, we can easily
confuse libarchive_fe/err.h with the system header.
Rename ours to lafe_err.h to avoid the confusion.
Rename libarchive_fe/err.c to match.
2025-09-13 12:30:03 -07:00
Tim Kientzle
e5c2eb783b Only set the filename-present bit if we actually write the filename 2025-09-13 11:17:38 -07:00
Tim Kientzle
a3787a34a8 Fix some nearby formatting 2025-09-12 09:03:01 -07:00
Tim Kientzle
a2933fbefd Ignore overlong gzip original_filename
We reuse the compression buffer to format the gzip header,
but didn't check for an overlong gzip original_filename.
This adds that check.  If the original_filename is
over 32k (or bigger than the buffer in case someone shrinks
the buffer someday), we WARN and ignore the filename.
2025-09-12 09:01:13 -07:00
Martin Matuska
123d92bc3a win: add complementary safe writes fix for Windows to 27588eba5 (#2477) 2025-09-10 10:59:40 +02:00
Martin Matuska
ff3a0c37aa CI: add workaround for cmake installed from local/pinned tab on GH/MacOS 2025-09-10 10:50:46 +02:00
Martin Matuška
589659ed7f
Merge pull request #2670 from benoit-pierre/pr/fix_zip_writing_with_zstd_compression_method
zip: fix writing with ZSTD compression
2025-09-10 10:41:33 +02:00
Martin Matuška
52db141ece
Merge pull request #2477 from jrtc27/safe-dir-over-reg
Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES
2025-09-10 10:40:44 +02:00
Martin Matuška
3b1100f9a9
Merge pull request #2686 from stoeckmann/lseek_win_regression
Fix Windows off_t handling
2025-09-10 10:24:34 +02:00
Martin Matuška
6bd863f612
Merge pull request #2710 from meecash/CVE-2025-25724-check_strftime_result
Fix CVE-2025-25724 by checking the result of the strftime
2025-09-10 10:22:58 +02:00
Dag-Erling Smørgrav
4768f38535 archive_write: Set archive state to fatal if format or filters fail
In archive_write_header(), if the format method or a filter flush method
fails, we set the archive state to fatal, but we did not do this in
archive_write_data() or archive_write_finish_entry().  There is no good
reason for this discrepancy.  Not setting the archive state to fatal
means a subsequent archive_write_free() will invoke archive_write_close()
which may retry the operation and cause archive_write_free() to return
an unexpected ARCHIVE_FATAL.
2025-09-08 23:33:32 +02:00
Dag-Erling Smørgrav
3a072e0bb0 write_add_filter_bzip2: End compression in the freer
If a fatal error occurs, the closer will not be called, so neither will
BZ2_bzCompressEnd(), and we will leak memory.  Fix this by calling it a
second time from the freer.  This is harmless in the non-error case as
it will see that the compression state has already been cleared and
immediately return BZ_PARAM_ERROR, which we simply ignore.
2025-09-08 23:33:32 +02:00
Dag-Erling Smørgrav
06191cd287 archive_write_client: Free state in freer, not in closer
The closer will not be called if a fatal error occurs, so the current
arrangement results in a memory leak.  The downside is that the freer
may be called even if we were not fully constructed, so it needs to
perform additional checks.  On the other hand, knowing that the freer
always gets called and will free the client state simplifies error
handling in the opener.
2025-09-08 23:15:57 +02:00
Tim Kientzle
53135ca48e
Merge pull request #2717 from peakschris/cb_windows
bsdtar: Allow @filename to have CRLF endings
2025-08-22 08:13:40 -07:00
Chris Brown
37ab51c2d3 address review comment 2025-08-22 04:00:44 -04:00
Tim Kientzle
ab4d21e4cb
Merge pull request #2707 from fdegros/close_range_support
Avoid leaking file descriptors into subprocesses
2025-08-20 11:18:45 -07:00
François Degros
f12d80442c Use sysconf(_SC_OPEN_MAX) on systems without close_range or closefrom
Close all the file descriptors in the range [3 ..
sysconf(_SC_OPEN_MAX)-1] before executing a filter program to avoid
leaking file descriptors into subprocesses.

Bug: https://github.com/libarchive/libarchive/issues/2520
2025-08-20 15:47:18 +10:00
Tim Kientzle
892f331450
Merge pull request #2696 from al3xtjames/mkstemp
Fix mkstemp path in setup_mac_metadata
2025-08-16 10:27:11 -06:00
Martin Matuška
bf50fe0538
Merge pull request #2723 from KlaraSystems/des/couldnt-visit
archive_read_disk_posix: Don't pass -1 to a function expecting errno
2025-08-14 23:22:30 +02:00
Martin Matuška
2db13f7422
Merge pull request #2716 from antekone/bug/GH-2714/infinite-loop/1
RAR5 reader: early fail when file declares data for a dir entry
2025-08-14 23:20:55 +02:00
Martin Matuška
93f9e93d73
Merge pull request #2713 from antekone/bug/GH-2711/crash-when-rr/1
RAR5 reader: fix multiple issues in extra field parsing function
2025-08-14 23:20:01 +02:00
Martin Matuška
12ffcef28c
Merge pull request #2700 from mostynb/avoid_libxml2_deprecation_warnings
xar: avoid libxml2 deprecation warnings
2025-08-14 23:17:39 +02:00
Dag-Erling Smørgrav
02ebfb5a48 archive_read_disk_posix: Don't pass -1 to a function expecting errno
This fixes an unhelpful "Couldn't visit directory: Unknown error: -1" message.

Fixes:		3311bb52cbe4 ("Bring the code supporting directory traversals from bsdtar/tree.[ch] into archive_read_disk.c and modify it. Introduce new APIs archive_read_disk_open and archive_read_disk_descend.")
2025-08-14 15:29:34 +02:00
Chris Brown
e099b418e3 revert test verbosity change 2025-08-09 16:43:55 -04:00
Chris Brown
6a008e524e revert ci fix which didn't help 2025-08-09 16:13:26 -04:00
Chris Brown
835fe1133f disable tests on windows; they don't work 2025-08-09 15:51:48 -04:00
Chris Brown
466a2b5c7b fix test 2025-08-09 15:50:45 -04:00
Chris Brown
640c9feced fix mingw windows build issue 2025-08-09 15:32:55 -04:00
Chris Brown
9e7af6f21c increase test verbosity 2025-08-09 15:28:34 -04:00
Chris Brown
652a0c107b enable tests on windows 2025-08-09 15:08:49 -04:00
Chris Brown
980b541632 update autotools 2025-08-08 20:53:33 -04:00
Chris Brown
8b3d3ee99b update test 2025-08-08 20:40:14 -04:00
Chris Brown
fb859e6d3f add test 2025-08-08 20:15:35 -04:00
Chris Brown
da65b39c06 suggested changes by kientzle 2025-08-08 19:41:51 -04:00
Chris Brown
e47c315f51 debug non-printing characters and handle CRLF 2025-08-08 11:56:39 -04:00
Grzegorz Antoniak
cb403667d7 RAR5 reader: early fail when file declares data for a dir entry
RAR5 reader had inconsistent sanity checks for directory entries that
declare data. On one hand such declaration was accepted during the
header parsing process, but at the same time this was disallowed during
the data reading process. Disallow logic was returning the
ARCHIVE_FAILED error code that allowed the client to retry, while in
reality, the error was non-retryable.

This commit adds another sanity check during the header parsing logic
that disallows the directory entries to declare any data. This will make
clients fail early when such entry is detected.

Also, the commit changes the ARCHIVE_FAILED error code to ARCHIVE_FATAL
when trying to read data for the directory entry that declares data.
This makes sure that tools like bsdtar won't attempt to retry unpacking
such data.

Fixes issue #2714.
2025-08-04 19:52:53 +02:00
Grzegorz Antoniak
0ff100c8d3 RAR5 reader: fix multiple issues in extra field parsing function
This commit fixes multiple issues found in the function that parses
extra fields found in the "file"/"service" blocks.

1. In case the file declares just one extra field, which is an
   unsupported field, the function returns ARCHIVE_FATAL.

   The commit fixes this so this case is allowed, and the unsupported
   extra field is skipped. The commit also introduces a test for this
   case.

2. Current parsing method of extra fields can report parsing errors in
   case the file is malformed. The problem is that next iteration of
   parsing, which is meant to process the next extra field (if any),
   overwrites the result of the previous iteration, even if previous
   iteration has reported parsing error. A successful parse can be
   returned in this case, leading to undefined behavior.

   This commit changes the behavior to fail the parsing function early.
   Also a test file is introduced for this case.

3. In case the file declares only the EX_CRYPT extra field, current
   function simply returns ARCHIVE_FATAL, preventing the caller from
   setting the proper error string. This results in libarchive returning
   an ARCHIVE_FATAL without any error messages set. The PR #2096 (commit
   adee36b00) was specifically created to provide error strings in case
   EX_CRYPT attribute was encountered, but current behavior contradicts
   this case.

   The commit changes the behavior so that ARCHIVE_OK is returned by the
   extra field parsing function in only EX_CRYPT is encountered, so that
   the caller header reading function can properly return ARCHIVE_FATAL
   to the caller, at the same time setting a proper error string. A test
   file is also provided for this case.

This PR should fix issue #2711.
2025-08-03 15:28:58 +02:00
Tim Kientzle
3bf1035e67
Merge pull request #2712 from KlaraSystems/des/readdir_r
Drop support for readdir_r()
2025-08-02 16:33:01 -07:00
Dag-Erling Smørgrav
a335429c5e Drop support for readdir_r()
There has never been a good reason to prefer it over readdir(), and it
has now been marked obsolete in POSIX-1.2024.
2025-08-01 17:07:17 +02:00
François Degros
23ee781520 Use POSIX_SPAWN_CLOEXEC_DEFAULT when possible
Use posix_spawn() with POSIX_SPAWN_CLOEXEC_DEFAULT on systems that
define this constant, in order to avoid leaking file descriptors into
subprocesses.

Bug: https://github.com/libarchive/libarchive/issues/2520
2025-07-31 15:56:31 +10:00
François Degros
64bcf69ef8 Use closefrom() or close_range() when possible
To avoid leaking file descriptors into subprocesses.

Fixes: https://github.com/libarchive/libarchive/issues/2520
2025-07-31 15:03:22 +10:00
Marcin Mikula
ecce46744f Fix CVE-2025-25724 by checking the result of the strftime
to avoid use of undefined content of buf, in case when custom
locale makes the result string longer than buf length.

Signed-off-by: Marcin Mikula <marcin@helix.pl>
2025-07-30 10:33:51 +02:00
Tim Kientzle
6062470cbc
Merge pull request #2704 from kientzle/kientzle-harden-append-acl
Guard against invalid type arguments
2025-07-26 12:24:43 -07:00
Tim Kientzle
aa1fc90ae5 Guard against invalid type arguments
Some experiments showed strange things happen if you
provide an invalid type value when appending a new ACL entry.
Guard against that, and while we're here be a little more
paranoid elsewhere against bad types in case there is another
way to get them in.
2025-07-26 11:10:24 -07:00
Benoit Pierre
d1418af239 zip: fix writing with ZSTD compression
When testing the feature with `bsdtar -acf test.zip --options
zip:compression=zstd …` on a tree of ~100MB, the execution would
appear to "hang" while writing a multi-gigabytes ZIP file.
2025-07-21 11:35:27 +02:00
Tim Kientzle
cc97338239
Merge pull request #2699 from mostynb/7z_eopm_reference
7z: add liblzma EOPM reference
2025-07-17 19:18:53 -07:00
Mostyn Bramley-Moore
ed2ada78a6 7z: add liblzma EOPM reference
This is useful for developers trying to understand the 7z read support code.
2025-07-15 22:13:10 +02:00
Mostyn Bramley-Moore
4dfaf2d359 xar: avoid libxml2 deprecation warnings 2025-07-15 13:18:14 +02:00
Tim Kientzle
cb6b9e9a28
Merge pull request #2697 from Kraust/topic/cmake_build_fixes
Allow Compiling Against Static CRT.
2025-07-14 10:05:56 -07:00
Kraust
d2d72ac78a Allow Compiling Against Static CRT. 2025-07-13 22:57:25 -04:00
Alex James
b57d14f9c9
Fix mkstemp path in setup_mac_metadata
setup_mac_metadata currently concates the template after TMPDIR without
adding a path separator, which causes mkstemp to create a temporary file
next to TMPDIR instead of in TMPDIR. Add a path separator to the
template to ensure that the temporary file is created under TMPDIR.

I hit this while rebuilding libarchive in nixpkgs. Lix recently started
using a dedicated build directory (under /nix/var/nix/builds) instead of
using a directory under /tmp [1]. nixpkgs & Lix support (optional)
on macOS sandboxing. The default sandbox profile allows builds to access
paths under the build directory and any path under /tmp. Because the
build directory is no longer under /tmp, some of libarchive's tests
started to fail as they accessed paths next to (but not under) the build
directory:

cpio/test/test_basic.c:65: Contents don't match
   Description: Expected: 2 blocks
, options=
  file="pack.err"
0000_62_73_64_63_70_69_6f_3a_20_43_6f_75_6c_64_20_6e_bsdcpio: Could n
0010_6f_74_20_6f_70_65_6e_20_65_78_74_65_6e_64_65_64_ot open extended
0020_20_61_74_74_72_69_62_75_74_65_20_66_69_6c_65_0a_ attribute file.

Sandbox: bsdcpio(11215) deny(1) file-write-create /nix/var/nix/builds/nix-build-libarchive-3.8.0.drv-7tar.md.5EUrQu

[1]: https://lix.systems/blog/2025-06-24-lix-cves/
2025-07-12 15:44:55 -05:00
Tim Kientzle
267042ebc7
Merge pull request #2694 from stoeckmann/cleanups
Perform various cleanups
2025-07-11 21:06:20 -07:00
Tobias Stoeckmann
a3d261a29a rar: Fix typos in comments
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann
3c646995db archive_read: Fix formatting
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann
7b59a6b693 SECURITY.md: Turn singular into plural
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann
e559754d6d mtree: Fix grammar and typos
Fix grammar and typos in comments and error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:48 +02:00
Tobias Stoeckmann
82e247fe7c archive_string: Use correct data types
If it's already known that we use variables for calculations with
size_t, use size_t for them directly instead of int, even if values
fit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:06:09 +02:00
Tobias Stoeckmann
eff524fa4e Fix formatting in archive_string_sprintf.c
Do not mix tabs and spaces if not needed.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:58:38 +02:00
Tobias Stoeckmann
84e8f3c98e tar: Remove unneeded casts
The variable size is already of type size_t. No need to cast it again
to size_t.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:57:40 +02:00
Tobias Stoeckmann
4035fca93a Define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto to 1
All other define statements set a value. Set one here as well for
maximum compatibility.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:55:12 +02:00
Tobias Stoeckmann
3997a5f28a Do not truncate seek requests
If a seek cannot be fulfilled, fail directly with EOVERFLOW to match
regular lseek behavior.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-29 21:35:44 +02:00
Tobias Stoeckmann
d01dc496d3 Fix Windows off_t handling
The off_t datatype in Windows is 32 bit, which leads to issues when
handling files larger than 2 GB.

Add a wrapper around fstat/stat calls to return a struct which has a
properly sized st_size variable. On systems with an off_t representing
the actual system limits, use the native system calls.

This also fixes mtree's checkfs option with large files on Windows.

Fixes https://github.com/libarchive/libarchive/issues/2685
Fixes 89b8c35ff4b5addc08a85bf5df02b407f8af1f6c

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-29 21:35:39 +02:00
Tim Kientzle
d06700a098
Merge pull request #2691 from kientzle/kientzle-issue2681
Add missing test file
2025-06-29 12:03:51 -07:00
Tim Kientzle
2db02ae6ae Add missing test file 2025-06-28 20:45:14 -07:00
Tim Kientzle
595fb29e4c
Merge pull request #2664 from fedegiova/fix_leak_for_cb_error
Fix a memory leak if write callback error early
2025-06-28 19:15:32 -07:00
Tim Kientzle
609d8122f1
Merge pull request #2658 from stoeckmann/skip_tests
Skip tests if respective support is missing
2025-06-28 19:14:17 -07:00
Tim Kientzle
31cff981e4
Merge pull request #2673 from 004helix/master
archive_cryptor_private.h: check message digest functions are enabled for windows
2025-06-28 19:10:27 -07:00
Tim Kientzle
d8aaf88c9f
Merge pull request #2679 from AZero13/error
Handle possible errors from system calls
2025-06-28 19:09:12 -07:00
Tim Kientzle
ee49ac8106
Merge pull request #2687 from hemant-jadhav-emerson/master
Supress restrict keyword for msc_ver older than 1927
2025-06-28 19:04:30 -07:00
Tim Kientzle
9fe18ba0a6
Merge pull request #2689 from ElvishJerricco/linux-fs-flags
clear_nochange_fflags: Use linux FS flags
2025-06-28 14:23:02 -07:00
Tim Kientzle
cd020d1ccb
Merge pull request #2684 from DHowett/dev/duhowett/shim_open
win32: shim wopen, and make both open/wopen use _s "secure" variant
2025-06-28 14:22:26 -07:00
Tim Kientzle
a474bab7e3
Merge pull request #2688 from stoeckmann/entry_off32
Ignore sizes which do not fit into off_t
2025-06-28 14:11:17 -07:00
Will Fancher
489d0b8e2f clear_nochange_fflags: Use linux FS flags 2025-06-27 19:24:34 -04:00
Tobias Stoeckmann
1e4b84ed30 Ignore sizes which do not fit into off_t
It is possible to handle entries and files with sizes which do not fit
into off_t of the current system (Windows always has 32 bit off_t and
32 bit systems without large file support also have 32 bit off_t).

Set sizes to 0 in such cases. The fstat system call would return -1 and
set errno to EOVERFLOW, but that's not how archive_entry_set_size acts.
It would simply ignore negative values and set the size to 0.

Actual callers of archive_entry_stat from foreign projects seem to not
even check for NULL return values, so let's try to handle such cases as
nice as possible.

Affects mtree's checkfs option as well (Windows only, 32 bit systems
would simply fail in fstat/stat).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-27 17:06:14 +02:00
Dustin Howett
50d44b4202 win32: shim wopen, and make both open/wopen use _s "secure" variant
The new `__la_wopen` wrapper is a copy of `__la_open` that
expects--rather than converts--a wcs parameter.

The `sopen` variants are offered as "more secure" variants of `open` and
`wopen`; I cannot vouch for their security, but some build systems are
strict about the use of "banned insecure APIs".

I've confirmed that `_wsopen_s` and `_open_s` are present in the Windows
Vista SDK.

I did not confirm that they are available in the Windows XP Platform
SDK, in part because in e61afbd463d1 (2016!) Tim says:

> I'd like to completely remove support for WinXP and earlier.
2025-06-26 10:56:33 -07:00
Rose
b1b3709cae Handle possible errors from system calls
dup, open, etc, can fail and we should not assume they do not.
2025-06-20 17:35:54 -04:00
Tim Kientzle
ffde04f272
Merge pull request #2672 from AZero13/ferror
Fix error checking in writing files
2025-06-20 14:33:45 -07:00
Rose
fd4ecc0146 Fix error checking in writing files
For write, 0 may not mean an error at all. We need to instead check for the length not being the same.

With fwrite, because 0 could mean an error, but not always. We must check that we wrote the entire file!

Note that unlike write, fwrite's description according to POSIX does not mention returning a negative type at all. Nor does it say you can retry unlike write.

Finally, with write, we need to check less than 0, not 0, as 0 is a valid return and does not mean an error.
2025-06-20 13:55:57 -04:00
Tim Kientzle
a218a52dbb
Merge pull request #2678 from mostynb/zstd_filter_checksum
Enable Zstandard's checksum feature in the zstd write filter
2025-06-20 09:32:51 -07:00
Mostyn Bramley-Moore
0de62cbda8 Enable Zstandard's checksum feature in the zstd write filter
Note that this is not enabled when writing .zip or .7z archive formats,
because they already use their own checksums.

Implements #2675.
2025-06-20 14:42:40 +02:00
Tim Kientzle
e4978e2edd
Merge pull request #2677 from AZero13/fwrite
Change error message from "fwrite function failed" to "write function failed"
2025-06-19 16:12:26 -07:00
Rose
40a89c7379 Change error message from "fwrite function failed" to "write function failed"
We are checking the return value from write, not fwrite, so this message is wrong.
2025-06-19 14:44:43 -04:00
Tim Kientzle
6a252c84a2
Merge pull request #2676 from danyeaw/fix-pkgconf-path
Fix .pc location when CMAKE_INSTALL_LIBDIR not set
2025-06-19 08:20:43 -07:00
Dan Yeaw
4984c652db Fix .pc location when CMAKE_INSTALL_LIBDIR not set 2025-06-18 21:27:04 -04:00
Hemant
664a20b6c7 Error related to restrict keyword supressed for older vs compiler 2025-06-18 14:05:23 -05:00
Hemant
b7066d4a6b Error related to restrict keyword supressed for older vs compiler 2025-06-18 13:51:00 -05:00
Martin Matuška
6effe2ec6b
Merge pull request #2659 from stoeckmann/chld
Improve filter process handling
2025-06-12 10:59:43 +02:00
Martin Matuška
251f7e839c
Merge pull request #2669 from benoit-pierre/pr/minor_test_related_tweaks
minor test related tweaks
2025-06-12 10:57:17 +02:00
Martin Matuška
47bdf82489
Merge pull request #2663 from stoeckmann/filename_errpath
open_filename: Free memory on error paths
2025-06-12 10:56:32 +02:00
Martin Matuška
c3be70e071
Merge pull request #2665 from stoeckmann/read_data_sparse
archive_read_data: Handle sparse holes at end of file correctly
2025-06-12 10:54:08 +02:00
Martin Matuška
9bdc5b82f7
Merge pull request #2668 from stoeckmann/7z_oob
7zip: Fix out of boundary access
2025-06-12 10:51:45 +02:00
Raman Shyshniou
475423a154 archive_cryptor_private.h: check message digest functions are enabled for windows 2025-06-12 00:22:47 +00:00
Benoit Pierre
864c904442 test_utils: factorize canProg implementations 2025-06-08 00:05:58 +02:00
Benoit Pierre
dcf5475661 test_utils: fix canRunCommand implementation
Do not unconditionally cache the result of the first call (and
reused it for subsequent calls). Thankfully, the function is
only called once.
2025-06-08 00:05:34 +02:00
Tobias Stoeckmann
90c1e32a0d open_filename: Free memory on error paths
If opening a filename fails, make sure that allocated memory which is
not inserted into any remaining structure is freed.

Fixes https://github.com/libarchive/libarchive/issues/1949

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 22:17:56 +02:00
Tobias Stoeckmann
c0691458a0 7zip: Fix out ouf boundary read in ELF detection
Make sure that the string table size is not smaller than 6 (and also
not larger than SIZE_MAX for better 32 bit support).

Such small values would lead to a large loop limit which either leads to
a crash or wrong detection of a ".data" string in possibly uninitialized
memory.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 21:38:43 +02:00
Tobias Stoeckmann
75ef803092 7zip: Increase minimum ELF header length
The 64 bit format requires at least 63 bytes, so increase this limit.
Such small binaries most likely don't contain 7zip data anyway.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 21:36:23 +02:00
Tim Kientzle
0931c12b7e
Merge pull request #2662 from stoeckmann/set_format_strcpy
archive_read_set_format: Remove strcpy calls
2025-06-04 05:58:32 -07:00
Tobias Stoeckmann
b1839a20e5 archive_read: Handle sparse holes at end of file
If a sparse hole is located at the end of an entry, then the tar
parser returns ARCHIVE_EOF while updating the offset where 0 bytes of
data will follow.

If archive_read_data encounters such an ARCHIVE_EOF return value, it
has to recheck if the offsets (data offset and output offset) still
match. If they do not match, it has to keep filling 0 bytes.

This changes assumes that it's okay to call archive_read_data_block
again after an EOF. As far as I understood the parsers so far, this
should be okay, since it's always ARCHIVE_EOF afterwards.

Fixes https://github.com/libarchive/libarchive/issues/1194

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 22:01:15 +02:00
Tobias Stoeckmann
f3949062ed rar: Do not forcefully set offset to unpacked size
If an entry reaches its end of file, the offset is not necessarily
the same as unp_size. This is especially true for links which have
a "0 size body" even though the unpacked size is not 0.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:59:05 +02:00
Tobias Stoeckmann
cdb45d71b2 warc: Ignore separator when reaching end of entry
When _warc_read encounters end of entry, it adds 4 bytes to the last
offset for \r\n\r\n separator, which is never written. Ignore these
bytes since they are not part of the returned entry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:57:42 +02:00
Tobias Stoeckmann
fa85c7eaae xar: End with entry offset, not archive offset
If xar_read_data has no further data, set offset to end of entry,
not to total size of parsed archive so far.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:57:05 +02:00
Federico Giovanardi
aa69d34311 Fix a memory leak if write callback error early 2025-06-03 18:24:35 +02:00
Tobias Stoeckmann
5a60d8cda4 archive_read_set_format: Remove strcpy calls
The string constants can be used directly for comparison, which makes
this code robust against future changes which could lead to names being
longer than str could hold on stack.

Also removes around 100 bytes from compiled library (with gcc 15).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:43:27 +02:00
Tobias Stoeckmann
ac66e0bc42 Skip zlib tests if support is missing
If zlib is not supported, do not run tests to avoid false positives.

Also adjust tests to support latest gzip versions (1.10+) which store
less information for improved reproducibility. The gzip binary is
used as a fallback if zlib is not available.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann
f2c3c790ff Skip lzma test if support is missing
If lzma is not supported, do not run tests to avoid false positives.

Fixes https://github.com/libarchive/libarchive/issues/2647

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann
b7e1c617cb Skip KOI8 conversion test if support is missing
If a unix system has no iconv support, the best effort function will
be unable to convert KOI8 to UTF-8. Skip the test if such support is
missing.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann
c40a3887ab unzip: Pass test if encryption support is missing
If no encryption support exists, the -P option will always fail.
"Skip" the test by making sure that there really is no encryption
support according to libarchive functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann
9836e7e2fe zip: Better detect no encryption support
Some functions might return -1 in case of library error. Use an
own return value if a stub function was used for better error
messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tim Kientzle
a8f93f2480
Merge pull request #2660 from kevans91/ke/fix-fortify
libarchive/test: fix build when memcpy() is a macro
2025-06-03 06:02:09 -07:00
Kyle Evans
b76c4042ae libarchive/test: fix build when memcpy() is a macro
After importing the latest libarchive into FreeBSD, Shawn Webb @
HardenedBSD noted that the test build is broken when FORTIFY_SOURCE=2
while building the base system.  Braced initializer lists are a special
case that need some extra fun parentheses when we're dealing with the
preprocessor.

While it's not a particularly common setup, the extra parentheses don't
really hurt readability all that much so it's worth fixing for wider
compatibility.

Fixes: libarchive/libarchive#2657
2025-06-02 21:46:28 -05:00
Tobias Stoeckmann
36bac92cd2 tools: Enforce default handling of SIGCHLD
Ignoring SIGCHLD gets passed to child processes. Doing that has
influence on waitpid, namely that zombie processes won't be
created. This means that a status can never be read.

We can't enforce this in library, but libarchive's tools can be
protected against this by enforcing default handling.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:29:49 +02:00
Tobias Stoeckmann
2764062e65 Unify reader and writer filter process handling
Use pid_t since waitpid returns a pid_t. Also check for a negative
return value in writer as well to avoid reading the possibly
unitialized status value.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:28:26 +02:00
Tobias Stoeckmann
13700e1fb8 windows: close child process handle only once
Calling CloseHandle multiple times for the same handle can lead to
exceptions while debugging according to documentation.

Mimic the waitpid handling for success cases to behave more like the
Unix version which would "reap the zombie".

Doing this for an unsuccessful call is off, but the loop is never
entered again, so I guess it's okay and worth it to reduce the amount
of Windows specific definitions in source files.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:23:05 +02:00
Tobias Stoeckmann
d7d1d19bb6 windows: Preserve GetExitCodeProcess error
If the waitpid version for Windows fails, preserve the error code and
avoid overwriting it with a possible CloseHandle error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:21:26 +02:00
Tim Kientzle
0f9a06d6ab
Merge pull request #2655 from mmatuska/fix/setclocale
test_utils/test_main.c: satisfy -Wstrict-prototypes
2025-06-01 16:04:49 -07:00
Martin Matuska
1311a438a3 test_utils/test_main.c: satisfy -Wstrict-prototypes 2025-06-01 23:35:05 +02:00
Martin Matuška
70978468e9
Merge pull request #2627 from heirecka/do-not-hard-code-pkg-config
Use PKG_CONFIG instead of hard-coded pkg-config
2025-05-31 21:40:04 +02:00
Martin Matuška
c7b7bd7c0e
Merge pull request #2643 from stoeckmann/tar_pax_sparse
tar: Handle extra bytes after sparse entries
2025-05-31 21:31:14 +02:00
Tim Kientzle
8d074302ac
Merge pull request #2652 from stoeckmann/wstring_ensure
Check archive_wstring_ensure return value
2025-05-31 07:16:07 -07:00
Tobias Stoeckmann
e1ca935c00 Always check archive_wstring_ensure return value
Memory allocation might fail, so check if it was successful.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 11:37:02 +02:00
Tobias Stoeckmann
e1c0f9a660 write disk windows: Release memory on error paths
Free wsp in case of out of memory condition.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 11:31:50 +02:00
Tobias Stoeckmann
20b4a4cb7c iso9660: Check another archive_string_ensure result
Missed one unchecked archive_string_ensure in the previous commit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 09:46:17 +02:00
Tim Kientzle
101230094c
Merge pull request #2651 from stoeckmann/string_ensure_check
Always check archive_string_ensure return value
2025-05-30 19:50:25 -07:00
Tim Kientzle
8540cb7cfb
Merge pull request #2648 from stoeckmann/test_en_us
test_utils: Enforce C locale for all tests
2025-05-30 19:35:44 -07:00
Tim Kientzle
e2eda9e68b
Merge pull request #2650 from stoeckmann/string_sort
archive_utility_string_sort: Use qsort directly
2025-05-30 19:33:34 -07:00
Tobias Stoeckmann
9ac39a0168 Always check archive_string_ensure return value
Memory allocation might fail, so check if it was successful.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 23:42:40 +02:00
Tobias Stoeckmann
0a320b6a37 Remove archive_utility_string_sort with 4.0.0
The archive_utility_string_sort function won't be part of the 4.0.0 API
anymore. No users were found and such a task should be done outside of
the library.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:41:26 +02:00
Tobias Stoeckmann
f90d036057 archive_utility_string_sort: Use qsort directly
The utility function "archive_utility_string_sort" is a custom qsort
implementation. Since qsort is specified in C11 and POSIX.1-2008
which libarchive is based on, use system's qsort directly.

The function is not used directly in libarchive, so this is a good
way to save around 500 bytes in resulting library without breaking
compatibility for any user of this function (none found).

Also allows more than UINT_MAX entries which previously were limited
by data type and (way earlier) due to recursion.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:41:12 +02:00
Tobias Stoeckmann
65d0393f24 test_list_item: Do not modify LC_TIME
Test cases already get a C locale, which is sufficient for this test.
IF LC_TIME was not previously set, the used en_US.UTF-8 would stay
as an environment variable, possibly affecting other test cases.
Since en_US.UTF-8 is not guaranteed to be available, C is a better
choice.

Fixes https://github.com/libarchive/libarchive/issues/2560

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:33:19 +02:00
Tobias Stoeckmann
e70e24a738 test_utils: Reset all locale related entries
Reset current locale settings through setlocale and also all
environment variables which might affect test cases which
spawn children through systemf which in turn would call setlocale
on their own, e.g. bsdtar.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:32:02 +02:00
Tim Kientzle
9b07a143ee
Merge pull request #2634 from stoeckmann/tar_neg_time
tar: Support negative time values with pax
2025-05-29 17:31:28 -07:00
Tim Kientzle
cd5c44c5d0
Merge pull request #2649 from stoeckmann/compress_recursion
compress: Prevent call stack overflow
2025-05-29 16:37:44 -07:00
Tobias Stoeckmann
2ed2db55e8 compress: Prevent call stack overflow
Explicitly use goto to turn a recursive call into an iterative one.
Most compilers do this on their own with default settings, but MSVC
with default settings would create a binary which actually performs
recursive calls.

Fixes call stack overflow in binaries compiled with low optimization.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-29 15:07:02 +02:00
Tim Kientzle
59b09796c3
Merge pull request #2642 from stoeckmann/seek_regress
Fix FILE_skip regression
2025-05-27 20:55:15 -07:00
Tim Kientzle
d261f46ae5
Merge pull request #2644 from stoeckmann/tar_neg_size
tar: Always treat negative sizes as error
2025-05-27 20:52:36 -07:00
Tim Kientzle
dcdd7338d6
Merge pull request #2645 from stoeckmann/tar_formatter
tar: Fix archive_set_error formatters
2025-05-27 20:43:46 -07:00
Tim Kientzle
702f31a01c
Merge pull request #2646 from stoeckmann/sparse32
tar: Handle many sparse comments on 32 bit systems
2025-05-27 20:41:19 -07:00
Tobias Stoeckmann
ebca997192 tar: Handle many sparse comments on 32 bit systems
The sparse 1.0 parser skips lines with comments. The amount of skipped
bytes is stored in a ssize_t variable, although common 32 bit systems
allow files larger than 4 GB.

Gracefully handle files with more than 2 GB bytes full of comments to
prevent integer truncations.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 21:30:19 +02:00
Tobias Stoeckmann
9d07162b08 tar: Fix archive_set_error formatters
Use correct formatters and casts with newly introduced ll
length modifier.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 20:50:53 +02:00
Tobias Stoeckmann
33d3528723 tar: Always treat negative sizes as error
If a pax global header specifies a negative size, it is possible to
reduce variable `unconsumed` by 512 bytes, leading to a re-reading
of the pax global header. Fortunately the loop verifies that only one
global header per entry is allowed, leading to a later ARCHIVE_FATAL.

Avoid any form of negative size handling and fail early.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 20:46:51 +02:00
Tobias Stoeckmann
715f7eac02 tar: Handle extra bytes after sparse entries
Skip all entry bytes after sparse entries were encountered. This matches
GNU tar behavior.

I have adjusted (and fixed) the existing test case for this. The test
case test_read_format_gtar_sparse_skip_entry did not work with GNU tar.

In #2558 it was explained that the pax size always overrides the header
size (correct). Since the pax size in the test case was way larger than
the actual entry bytes in archive, GNU tar choke on the test file.

The libarchive parser did not skip any bytes not already read due to
references by sparse entries, so the huge pax size was not detected.

By adjusting the test case to have a leftover byte (only 3 bytes are
referenced through sparse entry now, leaving one extra byte) with a
correct pax size and an invalid header size (after all it is overridden
by pax size), GNU tar works and libarchive gets off its 512 byte
alignment, not being able to read the next entry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 19:57:05 +02:00
Tobias Stoeckmann
51b4c35bb3 Fix FILE_skip regression
The fseek* family of functions return 0 on success, not the new offset.
This is only true for lseek.

Fixes https://github.com/libarchive/libarchive/issues/2641
Fixes dcbf1e0ededa95849f098d154a25876ed5754bcf

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 17:09:12 +02:00
Tim Kientzle
6389d172ed
Merge pull request #2640 from robUx4/xml-uuid
[cmake] add uuid library when using xmllite
2025-05-26 09:06:47 -07:00
Steve Lhomme
ac96967e36 [cmake] add uuid library when using xmllite
Consecutive to 16fd043f51d911b106f2a7834ad8f08f65051977
IID_ISequentialStream is required by the code.
This GUID is defined in uuid.lib or libuuid.a in mingw-w64. It is required
to link with that library to get the definition of the GUID. Some toolchains
add it by default but not all.
2025-05-26 10:44:49 +02:00
Tim Kientzle
341dd5d1d4
Merge pull request #2637 from stoeckmann/pax_nl
tar: Keep block alignment after pax error
2025-05-25 16:22:59 -07:00
Tim Kientzle
18d456377e
Merge pull request #2639 from stoeckmann/sprintf_ll
Add ll length modifier to archive_string_vsprintf
2025-05-25 16:19:38 -07:00
Tobias Stoeckmann
bc5f0884e3 Add ll length modifier to archive_string_vsprintf
Some error messages already use the ll length modifier, which results
in raw formatter output, i.e. "%lld" instead of a number.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-25 14:27:46 +02:00
Tobias Stoeckmann
101646e34e tar: Keep block alignment after pax error
If a pax attribute has a 0 length value and no newline, the tar reader
gets out of sync with block alignment.

This happens because the pax parser assumes that variable value_length
(which includes the terminating newline) is at least 1. To get the
real value length, 1 is subtracted. This result is subtracted from
extsize, which in this case would lead to `extsize -= -1`, i.e.
the remaining byte count is increased.

Such an unexpected calculation leads to an off-by-one when skipping
to the next block. In supplied test case, bsdtar complains that the
checksum of the next block is wrong. Since the tar parser was not
properly 512 bytes aligned, this is no surprise.

Gracefully handle such a case like GNU tar does and warn the user that
an invalid attribute has been encountered.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-25 12:03:55 +02:00
Tim Kientzle
b6e1f06457
Merge pull request #2636 from zhaofengli/reset-header-state-after-mac-metadata
tar: Reset accumulated header state after reading macOS metadata blob
2025-05-24 17:18:00 -07:00
Zhaofeng Li
0685c77e83 Add test for macOS metadata reading in tar archives
Signed-off-by: Zhaofeng Li <hello@zhaofeng.li>
2025-05-24 16:42:26 -06:00
Zhaofeng Li
5bb36db5e1 tar: Reset accumulated header state after reading macOS metadata blob
AppleDouble extension entries are present as separate files immediately
preceding the corresponding real files. In libarchive, we process the
entire metadata file (headers + data) as if it were a header in the real
file. However, the code forgets to reset the accumulated header state
before parsing the real file's headers. In one code path, this causes
the metadata file's name to be used as the real file's name.

Specifically, this can be triggered with a tar containing two files:

1. A file named `._badname` with pax header containing the `path` attribute
2. A file named `goodname` _with_ a pax header but _without_ the `path` attribute

libarchive will list one file, `._badname` containing the data of `goodname`.

This code is pretty brittle and we really should let the client deal with
it :(

Fixes #2510.

Signed-off-by: Zhaofeng Li <hello@zhaofeng.li>
2025-05-24 14:33:08 -06:00
Tim Kientzle
42c2f84649
Merge pull request #2630 from stoeckmann/wincrypt_casts
Fix archive_wincrypt_version
2025-05-24 10:45:57 -07:00
Tim Kientzle
6dbea2df3b
Merge pull request #2633 from stoeckmann/match_cleanup
archive_match: Simplify and clean up code
2025-05-24 10:37:02 -07:00
Tobias Stoeckmann
a5d9c9a7cd tar: Support negative time values with pax
Pax extended headers may specify negative time values for files older
than the epoch.

Adjust the code to clear values to 0.0 more often and set ps to
INT64_MIN to have a proper error specifier, because the parser does
not allow anything below -INT64_MAX.

Fixes https://github.com/libarchive/libarchive/issues/2562

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 19:28:22 +02:00
Tim Kientzle
cdc185e917
Merge pull request #2632 from stoeckmann/cygwin_definition
Prefer __CYGWIN__ over CYGWIN definition
2025-05-24 10:23:28 -07:00
Tobias Stoeckmann
8b978a0368 archive_match: Fix whitespaces, style
Adjust whitespaces to match file layout and add a full stop to
a comment to match others.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:37:44 +02:00
Tobias Stoeckmann
bef52da622 archive_match: Use correct data type for iterator
Iterating over a size_t with unsigned could lead to an endless loop
while adding uid/gid to a list which already counts 4 billion
entries.

I doubt that this can ever happen, given that the routines become
very slow with insertions, but better be safe than sorry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:35:32 +02:00
Tobias Stoeckmann
8b763d872c archive_match: Allow arbitrarily long match lists
Turn unmatched_count into a size_t to support as many entries as
possible on the machine.

If more than INT_MAX entries are not matched, truncate the result
of archive_match_path_unmatched_inclusions for external callers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:28:08 +02:00
Tobias Stoeckmann
51e66d32c6 archive_match: Remove unneeded count fields
The count fields are merely used to check if a list is empty or not.
A check for first being not NULL is sufficient and is already in
place while iterating over the linked elements (count is not used).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:24:49 +02:00
Tobias Stoeckmann
4223b4c548 archive_match: Set red/black tree operations once
The operations for key and node comparison depend on the platform
libarchive is compiled for. Since these values do not change
during runtime, set them only once during initialisation.

Further simplify the code by declaring only one "rb_ops" with
required functions based on platform.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:10:49 +02:00
Tobias Stoeckmann
612223356e Prefer __CYGWIN__ over CYGWIN definition
The cygwin FAQ states that __CYGWIN__ is defined when building for a
Cygwin environment. Only a few test files check (inconsistently) for
CYGWIN, so adjust them to the recommended __CYGWIN__ definition.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 11:37:26 +02:00
Tim Kientzle
0ed4435209
Merge pull request #2631 from stoeckmann/configure_windows
configure.ac: Improve Windows version detection
2025-05-23 19:58:02 -07:00
Tim Kientzle
992734d6cc
Merge pull request #2509 from tesap/install-lib-dir
Make installation lib dir depend on CMAKE_INSTALL_LIBDIR variable
2025-05-23 19:57:14 -07:00
Tim Kientzle
627ba5bbbf
Merge pull request #2629 from mmatuska/fix/versiontest
tests: accept underscore in arbitrary third-party version strings
2025-05-23 19:39:00 -07:00
Tobias Stoeckmann
2cdf47f332 Set ARCHIVE_CRYPTOR_USE_WINCRYPT for WinCrypt
If WinCrypt is used, actually set ARCHIVE_CRYPTOR_USE_WINCRYPT
for version details output.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:43:26 +02:00
Tobias Stoeckmann
d8ff8dd62c archive_version_details.c: Drop ARCHIVE_DIGEST_*
These definitions are never available and are supposedly a leftover of
a work in progress.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:43:24 +02:00
Tobias Stoeckmann
d6f6fdf979 configure.ac: Improve Windows version detection
Include windows.h for better windows version detection.

Fixes https://github.com/libarchive/libarchive/issues/2628

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:22:41 +02:00
Tobias Stoeckmann
38ac49553d Fix archive_wincrypt_version compilation
Cast address of "version" to BYTE pointer for CryptGetProvParam.
Fix "major" variable assignment for picky compilers like MSVC.

The "length" variable is an in/out variable. It must be set to the size
of available memory within "version". Right now it is undefined behavior
and 0 would crash during runtime.

Fixes https://github.com/libarchive/libarchive/issues/2628

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:05:21 +02:00
Martin Matuska
9eacf09a86 tests: accept underscore in arbitrary third-party version strings
Fixes #2626
2025-05-23 13:20:25 +02:00
Heiko Becker
0ddaa5f71c Use PKG_CONFIG instead of hard-coded pkg-config 2025-05-21 00:44:50 +02:00
Tim Kientzle
2961b132d0
Merge pull request #2624 from mmatuska/feat/390dev
Libarchive 3.9.0dev
2025-05-20 07:55:26 -07:00
Martin Matuska
182726d16a Libarchive 3.9.0dev 2025-05-20 10:29:10 +02:00
Stepan Tsepa
447201758e Make installation lib dir depend on CMAKE_INSTALL_LIBDIR variable 2025-02-14 11:34:56 +03:00
Jessica Clarke
27588eba50 Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES
The outer if checks !S_ISDIR(a->st.st_mode), so we know that the file
being overwritten is not a directory, and thus we can rename(2) over it
if we want to, but whether we can use a temporary regular file is a
property of the file being extracted. Otherwise, when replacing a
regular file with a directory, we end up in this case and create a
temporary regular file for the new directory, but with the permissions
of the directory (which likely includes x), and rename it over the top
at the end. Depending on where the archive_entry came from, it may have
a non-zero size that also isn't ovewritten with 0 (e.g. if it came from
stat(2)) and so the API user may then try to copy data (thus failing if
read(2) of directories isn't permitted, or writing the raw directory
contents if it is), but if the size is zero as is the case for this tar
test then it will end up not writing any data and "successfully"
overwrite the file with an empty file, not a directory.
2025-01-07 20:59:09 +00:00
233 changed files with 12561 additions and 1449 deletions

View File

@ -1,3 +1,4 @@
---
env:
CIRRUS_CLONE_DEPTH: 1
ARCH: amd64
@ -9,22 +10,33 @@ FreeBSD_task:
env:
BS: cmake
matrix:
freebsd_instance:
image_family: freebsd-14-2
freebsd_instance:
image_family: freebsd-13-5
- name: 15.0-STABLE (UFS)
freebsd_instance:
image_family: freebsd-15-0-amd64-ufs-snap
- name: 15.0-RELEASE (UFS)
freebsd_instance:
image_family: freebsd-15-0-amd64-ufs
- name: 15.0-RELEASE (ZFS)
freebsd_instance:
image_family: freebsd-15-0-amd64-zfs
- name: 14.3-RELEASE
freebsd_instance:
image_family: freebsd-14-3
- name: 13.5-RELEASE
freebsd_instance:
image_family: freebsd-13-5
prepare_script:
- ./build/ci/cirrus_ci/ci.sh prepare
configure_script:
- env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a autogen
- env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a configure
- env MAKE=gmake CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a configure
build_script:
- env MAKE_ARGS="-j 2" ./build/ci/build.sh -a build
- env MAKE=gmake MAKE_ARGS="-j 2" ./build/ci/build.sh -a build
test_script:
- env SKIP_TEST_RESTORE_ATIME=1 MAKE_ARGS="-j 2" ./build/ci/build.sh -a test
- env MAKE=gmake SKIP_TEST_RESTORE_ATIME=1 MAKE_ARGS="-j 2" ./build/ci/build.sh -a test
- ./build/ci/cirrus_ci/ci.sh test
install_script:
- env MAKE_ARGS="-j 2" ./build/ci/build.sh -a install
- env MAKE=gmake MAKE_ARGS="-j 2" ./build/ci/build.sh -a install
Windows_Cygwin_task:
windows_container:

View File

@ -12,7 +12,7 @@ jobs:
matrix:
bs: [autotools, cmake]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install dependencies
run: ./build/ci/github_actions/install-macos-dependencies.sh
- name: Autogen
@ -47,7 +47,7 @@ jobs:
run: ./build/ci/build.sh -a artifact
env:
BS: ${{ matrix.bs }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: libarchive-macos-${{ matrix.bs }}-${{ github.sha }}
path: libarchive.tar.xz
@ -59,7 +59,7 @@ jobs:
bs: [autotools, cmake]
crypto: [mbedtls, nettle, openssl]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Update apt cache
run: sudo apt-get update
- name: Install dependencies
@ -93,14 +93,14 @@ jobs:
run: ./build/ci/build.sh -a artifact
env:
BS: ${{ matrix.bs }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: libarchive-ubuntu-${{ matrix.bs }}-${{ matrix.crypto }}-${{ github.sha }}
path: libarchive.tar.xz
Ubuntu-distcheck:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Update package definitions
run: sudo apt-get update
- name: Install dependencies
@ -115,7 +115,7 @@ jobs:
SKIP_OPEN_FD_ERR_TEST: 1
- name: Dist-Artifact
run: ./build/ci/build.sh -a dist-artifact
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: libarchive-${{ github.sha }}
path: libarchive-dist.tar
@ -127,7 +127,7 @@ jobs:
matrix:
be: [mingw-gcc, msvc]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install mingw
if: ${{ matrix.be=='mingw-gcc' }}
run: choco install mingw
@ -163,7 +163,7 @@ jobs:
shell: cmd
env:
BE: ${{ matrix.be }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: libarchive-windows-${{ matrix.be }}-${{ github.sha }}
path: libarchive.zip

View File

@ -21,7 +21,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@ -26,18 +26,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
category: "/language:${{ matrix.language }}"

View File

@ -29,12 +29,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
@ -52,7 +52,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: SARIF file
path: results.sarif
@ -60,6 +60,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
sarif_file: results.sarif

View File

@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.17 FATAL_ERROR)
PROJECT(libarchive C)
#
# Include standard installation directories
include(GNUInstallDirs)
#
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
@ -136,7 +139,12 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
# either of the following two, yet neither is supported as of 3.0.2
# - check_linker_flag - does not exist
# - try_compile - does not support linker flags
IF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
# SunOS linker doesn't support --gc-sections
ELSE()
# Place the functions and data into separate sections, allowing the linker
# to garbage collect the unused ones.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
@ -145,10 +153,7 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
# Printing the discarded section is "too much", so enable on demand.
#SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections")
#SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections")
ELSE()
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
ENDIF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
ENDIF()
ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$" AND NOT MSVC)
IF (CMAKE_C_COMPILER_ID MATCHES "^XL$")
@ -255,6 +260,10 @@ OPTION(ENABLE_TEST "Enable unit and regression tests" ON)
OPTION(ENABLE_COVERAGE "Enable code coverage (GCC only, automatically sets ENABLE_TEST to ON)" FALSE)
OPTION(ENABLE_INSTALL "Enable installing of libraries" ON)
IF(WIN32 AND MSVC)
OPTION(MSVC_USE_STATIC_CRT "Use static CRT" OFF)
ENDIF()
SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
SET(WINDOWS_VERSION "WIN10" CACHE STRING "Set Windows version to use (Windows only)")
@ -771,12 +780,22 @@ IF(ENABLE_CNG)
LA_CHECK_INCLUDE_FILE("bcrypt.h" HAVE_BCRYPT_H)
IF(HAVE_BCRYPT_H)
LIST(APPEND ADDITIONAL_LIBS "bcrypt")
# bcrypt supports these algorithms on all available versions
SET(ARCHIVE_CRYPTO_MD5 1)
SET(ARCHIVE_CRYPTO_MD5_WIN 1)
SET(ARCHIVE_CRYPTO_SHA1 1)
SET(ARCHIVE_CRYPTO_SHA1_WIN 1)
SET(ARCHIVE_CRYPTO_SHA256 1)
SET(ARCHIVE_CRYPTO_SHA256_WIN 1)
SET(ARCHIVE_CRYPTO_SHA384 1)
SET(ARCHIVE_CRYPTO_SHA384_WIN 1)
SET(ARCHIVE_CRYPTO_SHA512 1)
SET(ARCHIVE_CRYPTO_SHA512_WIN 1)
ENDIF(HAVE_BCRYPT_H)
ELSE(ENABLE_CNG)
UNSET(HAVE_BCRYPT_H CACHE)
ENDIF(ENABLE_CNG)
# Following files need windows.h, so we should test it after windows.h test.
LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
#
@ -985,85 +1004,6 @@ main(int argc, char **argv)
ENDFOREACH(ALGORITHM ${ALGORITHMS})
ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
#
# CRYPTO functions on Windows is defined at archive_windows.c, thus we do not
# need the test what the functions can be mapped to archive_{crypto name}_init,
# archive_{crypto name}_update and archive_{crypto name}_final.
# The functions on Windows use CALG_{crypto name} macro to create a crypt object
# and then we need to know what CALG_{crypto name} macros is available to show
# ARCHIVE_CRYPTO_{crypto name}_WIN macros because Windows 2000 and earlier version
# of Windows XP do not support SHA256, SHA384 and SHA512.
#
MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
IF(WIN32 AND NOT CYGWIN)
FOREACH(CRYPTO ${CRYPTO_LIST})
IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
STRING(TOUPPER "${CRYPTO}" crypto)
SET(ALGID "")
IF ("${CRYPTO}" MATCHES "^MD5$")
SET(ALGID "CALG_MD5")
ENDIF ("${CRYPTO}" MATCHES "^MD5$")
IF ("${CRYPTO}" MATCHES "^SHA1$")
SET(ALGID "CALG_SHA1")
ENDIF ("${CRYPTO}" MATCHES "^SHA1$")
IF ("${CRYPTO}" MATCHES "^SHA256$")
SET(ALGID "CALG_SHA_256")
ENDIF ("${CRYPTO}" MATCHES "^SHA256$")
IF ("${CRYPTO}" MATCHES "^SHA384$")
SET(ALGID "CALG_SHA_384")
ENDIF ("${CRYPTO}" MATCHES "^SHA384$")
IF ("${CRYPTO}" MATCHES "^SHA512$")
SET(ALGID "CALG_SHA_512")
ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
CONFDEFS_H)
SET(SOURCE "${CONFDEFS_H}
#define ${crypto}_COMPILE_TEST
#include <windows.h>
#include <wincrypt.h>
int
main(int argc, char **argv)
{
return ${ALGID};
}
")
SET(SOURCE_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_win.c")
FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
${CMAKE_BINARY_DIR}
${SOURCE_FILE}
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
OUTPUT_VARIABLE OUTPUT)
IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
MESSAGE(STATUS
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
MESSAGE(STATUS
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN failed with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${SOURCE}\n")
ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
ENDFOREACH(CRYPTO)
ENDIF(WIN32 AND NOT CYGWIN)
ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
#
# Find iconv
# POSIX defines the second arg as const char **
@ -1078,8 +1018,8 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
#
# During checking iconv proto type, we should use -Werror to avoid the
# success of iconv detection with a warning which success is a miss
# detection. So this needs for all build mode(even it's a release mode).
# success of iconv detection with a warning, which would be a false
# positive. So this is needed for all build modes, even in release mode.
#
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
@ -1257,7 +1197,7 @@ ELSE(LIBXML2_FOUND)
# Check linkage as well; versions of mingw-w64 before v11.0.0
# do not contain an import library for xmllite.
cmake_push_check_state()
SET(CMAKE_REQUIRED_LIBRARIES "xmllite")
SET(CMAKE_REQUIRED_LIBRARIES "xmllite" "uuid")
check_c_source_compiles("
#include <initguid.h>
#include <xmllite.h>
@ -1268,7 +1208,7 @@ ELSE(LIBXML2_FOUND)
cmake_pop_check_state()
IF(HAVE_XMLLITE_H)
SET(XMLLITE_FOUND TRUE)
LIST(APPEND ADDITIONAL_LIBS "xmllite")
LIST(APPEND ADDITIONAL_LIBS "xmllite" "uuid")
ENDIF()
ENDIF()
ENDIF(EXPAT_FOUND)
@ -1472,6 +1412,8 @@ CHECK_FUNCTION_EXISTS_GLIBC(arc4random_buf HAVE_ARC4RANDOM_BUF)
CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
CHECK_FUNCTION_EXISTS_GLIBC(closefrom HAVE_CLOSEFROM)
CHECK_FUNCTION_EXISTS_GLIBC(close_range HAVE_CLOSE_RANGE)
CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
@ -1489,15 +1431,19 @@ CHECK_FUNCTION_EXISTS_GLIBC(ftruncate HAVE_FTRUNCATE)
CHECK_FUNCTION_EXISTS_GLIBC(futimens HAVE_FUTIMENS)
CHECK_FUNCTION_EXISTS_GLIBC(futimes HAVE_FUTIMES)
CHECK_FUNCTION_EXISTS_GLIBC(futimesat HAVE_FUTIMESAT)
CHECK_FUNCTION_EXISTS_GLIBC(getegid HAVE_GETEGID)
CHECK_FUNCTION_EXISTS_GLIBC(geteuid HAVE_GETEUID)
CHECK_FUNCTION_EXISTS_GLIBC(getgrgid_r HAVE_GETGRGID_R)
CHECK_FUNCTION_EXISTS_GLIBC(getgrnam_r HAVE_GETGRNAM_R)
CHECK_FUNCTION_EXISTS_GLIBC(getline HAVE_GETLINE)
CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
CHECK_FUNCTION_EXISTS_GLIBC(getresgid HAVE_GETRESGID)
CHECK_FUNCTION_EXISTS_GLIBC(getresuid HAVE_GETRESUID)
CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
CHECK_FUNCTION_EXISTS_GLIBC(issetugid HAVE_ISSETUGID)
CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
@ -1516,6 +1462,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
CHECK_FUNCTION_EXISTS_GLIBC(posix_spawn HAVE_POSIX_SPAWN)
CHECK_FUNCTION_EXISTS_GLIBC(posix_spawnp HAVE_POSIX_SPAWNP)
CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
CHECK_FUNCTION_EXISTS_GLIBC(readpassphrase HAVE_READPASSPHRASE)
@ -1579,12 +1526,6 @@ CHECK_C_SOURCE_COMPILES(
"#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct statfs s; return sizeof(s);}"
HAVE_STRUCT_STATFS)
# Make sure we have the POSIX version of readdir_r, not the
# older 2-argument version.
CHECK_C_SOURCE_COMPILES(
"#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
HAVE_READDIR_R)
# dirfd can be either a function or a macro.
CHECK_C_SOURCE_COMPILES(
"#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); return dirfd(d);}"
@ -2176,8 +2117,6 @@ CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
# Libmd has to be probed after OpenSSL.
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
# Check visibility annotations
SET(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fvisibility=hidden -Werror")

View File

@ -96,60 +96,73 @@ distclean-local:
include_HEADERS= libarchive/archive.h libarchive/archive_entry.h
libarchive_la_SOURCES= \
libarchive/archive_acl.c \
noinst_HEADERS= \
libarchive/archive_acl_private.h \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
libarchive/archive_cmdline_private.h \
libarchive/archive_crc32.h \
libarchive/archive_cryptor.c \
libarchive/archive_cryptor_private.h \
libarchive/archive_digest.c \
libarchive/archive_digest_private.h \
libarchive/archive_endian.h \
libarchive/archive_entry.c \
libarchive/archive_entry.h \
libarchive/archive_entry_copy_stat.c \
libarchive/archive_entry_link_resolver.c \
libarchive/archive_entry_locale.h \
libarchive/archive_entry_private.h \
libarchive/archive_hmac_private.h \
libarchive/archive_openssl_evp_private.h \
libarchive/archive_openssl_hmac_private.h \
libarchive/archive_options_private.h \
libarchive/archive_pack_dev.h \
libarchive/archive_pathmatch.h \
libarchive/archive_platform.h \
libarchive/archive_platform_acl.h \
libarchive/archive_platform_stat.h \
libarchive/archive_platform_xattr.h \
libarchive/archive_ppmd7_private.h \
libarchive/archive_ppmd8_private.h \
libarchive/archive_ppmd_private.h \
libarchive/archive_private.h \
libarchive/archive_random_private.h \
libarchive/archive_rb.h \
libarchive/archive_read_disk_private.h \
libarchive/archive_read_private.h \
libarchive/archive_string.h \
libarchive/archive_string_composition.h \
libarchive/archive_time_private.h \
libarchive/archive_write_disk_private.h \
libarchive/archive_write_private.h \
libarchive/archive_write_set_format_private.h \
libarchive/archive_xxhash.h \
libarchive/config_freebsd.h \
libarchive/filter_fork.h
libarchive_la_SOURCES= \
libarchive/archive_acl.c \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
libarchive/archive_cryptor.c \
libarchive/archive_digest.c \
libarchive/archive_entry.c \
libarchive/archive_entry_copy_stat.c \
libarchive/archive_entry_link_resolver.c \
libarchive/archive_entry_sparse.c \
libarchive/archive_entry_stat.c \
libarchive/archive_entry_strmode.c \
libarchive/archive_entry_xattr.c \
libarchive/archive_hmac.c \
libarchive/archive_hmac_private.h \
libarchive/archive_match.c \
libarchive/archive_openssl_evp_private.h \
libarchive/archive_openssl_hmac_private.h \
libarchive/archive_options.c \
libarchive/archive_options_private.h \
libarchive/archive_pack_dev.h \
libarchive/archive_pack_dev.c \
libarchive/archive_parse_date.c \
libarchive/archive_pathmatch.c \
libarchive/archive_pathmatch.h \
libarchive/archive_platform.h \
libarchive/archive_platform_acl.h \
libarchive/archive_platform_xattr.h \
libarchive/archive_ppmd_private.h \
libarchive/archive_ppmd7.c \
libarchive/archive_ppmd7_private.h \
libarchive/archive_ppmd8.c \
libarchive/archive_ppmd8_private.h \
libarchive/archive_private.h \
libarchive/archive_random.c \
libarchive/archive_random_private.h \
libarchive/archive_rb.c \
libarchive/archive_rb.h \
libarchive/archive_read.c \
libarchive/archive_read_add_passphrase.c \
libarchive/archive_read_append_filter.c \
libarchive/archive_read_data_into_fd.c \
libarchive/archive_read_disk_entry_from_file.c \
libarchive/archive_read_disk_posix.c \
libarchive/archive_read_disk_private.h \
libarchive/archive_read_disk_set_standard_lookup.c \
libarchive/archive_read_extract.c \
libarchive/archive_read_extract2.c \
@ -157,12 +170,11 @@ libarchive_la_SOURCES= \
libarchive/archive_read_open_file.c \
libarchive/archive_read_open_filename.c \
libarchive/archive_read_open_memory.c \
libarchive/archive_read_private.h \
libarchive/archive_read_set_format.c \
libarchive/archive_read_set_options.c \
libarchive/archive_read_support_filter_all.c \
libarchive/archive_read_support_filter_bzip2.c \
libarchive/archive_read_support_filter_by_code.c \
libarchive/archive_read_support_filter_bzip2.c \
libarchive/archive_read_support_filter_compress.c \
libarchive/archive_read_support_filter_grzip.c \
libarchive/archive_read_support_filter_gzip.c \
@ -193,23 +205,12 @@ libarchive_la_SOURCES= \
libarchive/archive_read_support_format_xar.c \
libarchive/archive_read_support_format_zip.c \
libarchive/archive_string.c \
libarchive/archive_string.h \
libarchive/archive_string_composition.h \
libarchive/archive_string_sprintf.c \
libarchive/archive_time.c \
libarchive/archive_time_private.h \
libarchive/archive_util.c \
libarchive/archive_version_details.c \
libarchive/archive_virtual.c \
libarchive/archive_write.c \
libarchive/archive_write_disk_posix.c \
libarchive/archive_write_disk_private.h \
libarchive/archive_write_disk_set_standard_lookup.c \
libarchive/archive_write_open_fd.c \
libarchive/archive_write_open_file.c \
libarchive/archive_write_open_filename.c \
libarchive/archive_write_open_memory.c \
libarchive/archive_write_private.h \
libarchive/archive_write_add_filter.c \
libarchive/archive_write_add_filter_b64encode.c \
libarchive/archive_write_add_filter_by_name.c \
@ -225,6 +226,12 @@ libarchive_la_SOURCES= \
libarchive/archive_write_add_filter_uuencode.c \
libarchive/archive_write_add_filter_xz.c \
libarchive/archive_write_add_filter_zstd.c \
libarchive/archive_write_disk_posix.c \
libarchive/archive_write_disk_set_standard_lookup.c \
libarchive/archive_write_open_fd.c \
libarchive/archive_write_open_file.c \
libarchive/archive_write_open_filename.c \
libarchive/archive_write_open_memory.c \
libarchive/archive_write_set_format.c \
libarchive/archive_write_set_format_7zip.c \
libarchive/archive_write_set_format_ar.c \
@ -234,59 +241,54 @@ libarchive_la_SOURCES= \
libarchive/archive_write_set_format_cpio_newc.c \
libarchive/archive_write_set_format_cpio_odc.c \
libarchive/archive_write_set_format_filter_by_ext.c \
libarchive/archive_write_set_format_gnutar.c \
libarchive/archive_write_set_format_iso9660.c \
libarchive/archive_write_set_format_mtree.c \
libarchive/archive_write_set_format_pax.c \
libarchive/archive_write_set_format_private.h \
libarchive/archive_write_set_format_raw.c \
libarchive/archive_write_set_format_shar.c \
libarchive/archive_write_set_format_ustar.c \
libarchive/archive_write_set_format_v7tar.c \
libarchive/archive_write_set_format_gnutar.c \
libarchive/archive_write_set_format_warc.c \
libarchive/archive_write_set_format_xar.c \
libarchive/archive_write_set_format_zip.c \
libarchive/archive_write_set_options.c \
libarchive/archive_write_set_passphrase.c \
libarchive/archive_xxhash.h \
libarchive/config_freebsd.h \
libarchive/filter_fork_posix.c \
libarchive/filter_fork.h \
libarchive/xxhash.c
if INC_WINDOWS_FILES
noinst_HEADERS+= \
libarchive/archive_windows.h
libarchive_la_SOURCES+= \
libarchive/archive_entry_copy_bhfi.c \
libarchive/archive_read_disk_windows.c \
libarchive/archive_windows.h \
libarchive/archive_windows.c \
libarchive/archive_write_disk_windows.c \
libarchive/filter_fork_windows.c
endif
if INC_BLAKE2
libarchive_la_SOURCES+= \
noinst_HEADERS+= \
libarchive/archive_blake2.h \
libarchive/archive_blake2_impl.h \
libarchive/archive_blake2_impl.h
libarchive_la_SOURCES+= \
libarchive/archive_blake2s_ref.c \
libarchive/archive_blake2sp_ref.c
endif
if INC_LINUX_ACL
libarchive_la_SOURCES+= libarchive/archive_disk_acl_linux.c
else
endif
if INC_SUNOS_ACL
libarchive_la_SOURCES+= libarchive/archive_disk_acl_sunos.c
else
endif
if INC_DARWIN_ACL
libarchive_la_SOURCES+= libarchive/archive_disk_acl_darwin.c
else
endif
if INC_FREEBSD_ACL
libarchive_la_SOURCES+= libarchive/archive_disk_acl_freebsd.c
endif
endif
endif
endif
# -no-undefined marks that libarchive doesn't rely on symbols
# defined in the application. This is mandatory for cygwin.
@ -350,22 +352,24 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = build/pkgconfig/libarchive.pc
# Sources needed by all test programs
noinst_HEADERS+= \
test_utils/test_common.h \
test_utils/test_utils.h
test_utils_SOURCES= \
test_utils/test_utils.c \
test_utils/test_utils.h \
test_utils/test_main.c \
test_utils/test_common.h
test_utils/test_utils.c
#
#
# libarchive_test program
#
#
noinst_HEADERS+= \
libarchive/test/test.h
libarchive_test_SOURCES= \
$(libarchive_la_SOURCES) \
$(test_utils_SOURCES) \
libarchive/test/read_open_memory.c \
libarchive/test/test.h \
libarchive/test/test_7zip_filename_encoding.c \
libarchive/test/test_acl_nfs4.c \
libarchive/test/test_acl_pax.c \
@ -465,6 +469,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_7zip_encryption_data.c \
libarchive/test/test_read_format_7zip_encryption_partially.c \
libarchive/test/test_read_format_7zip_encryption_header.c \
libarchive/test/test_read_format_7zip_issue2765.c \
libarchive/test/test_read_format_7zip_malformed.c \
libarchive/test/test_read_format_7zip_packinfo_digests.c \
libarchive/test/test_read_format_ar.c \
@ -525,14 +530,17 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_rar5.c \
libarchive/test/test_read_format_raw.c \
libarchive/test/test_read_format_tar.c \
libarchive/test/test_read_format_tar_V_negative_size.c \
libarchive/test/test_read_format_tar_concatenated.c \
libarchive/test/test_read_format_tar_empty_pax.c \
libarchive/test/test_read_format_tar_empty_filename.c \
libarchive/test/test_read_format_tar_empty_with_gnulabel.c \
libarchive/test/test_read_format_tar_filename.c \
libarchive/test/test_read_format_tar_invalid_pax_size.c \
libarchive/test/test_read_format_tar_mac_metadata.c \
libarchive/test/test_read_format_tar_pax_g_large.c \
libarchive/test/test_read_format_tar_pax_large_attr.c \
libarchive/test/test_read_format_tar_pax_negative_time.c \
libarchive/test/test_read_format_tbz.c \
libarchive/test/test_read_format_tgz.c \
libarchive/test/test_read_format_tlz.c \
@ -565,6 +573,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_zip_zip64.c \
libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c \
libarchive/test/test_read_large.c \
libarchive/test/test_read_pax_empty_val_no_nl.c \
libarchive/test/test_read_pax_xattr_rht_security_selinux.c \
libarchive/test/test_read_pax_xattr_schily.c \
libarchive/test/test_read_pax_truncated.c \
@ -667,7 +676,6 @@ libarchive_test_SOURCES= \
libarchive/test/test_write_read_format_zip.c \
libarchive/test/test_xattr_platform.c \
libarchive/test/test_zip_filename_encoding.c
libarchive_test_CPPFLAGS= \
-I$(top_srcdir)/libarchive \
-I$(top_srcdir)/libarchive/test \
@ -680,9 +688,9 @@ libarchive_test_LDADD= $(LTLIBICONV)
# The "list.h" file just lists all of the tests defined in all of the sources.
# Building it automatically provides a sanity-check on libarchive_test_SOURCES
# above.
libarchive/test/list.h: Makefile
libarchive/test/list.h: $(libarchive_test_SOURCES)
$(MKDIR_P) libarchive/test
cat $(top_srcdir)/libarchive/test/test_*.c | grep '^DEFINE_TEST' > libarchive/test/list.h
grep -h '^DEFINE_TEST(' $^ | LC_COLLATE=C sort > $@
libarchive_TESTS_ENVIRONMENT= LIBARCHIVE_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/libarchive/test LRZIP=NOCONFIG
@ -702,6 +710,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_compat_lz4_2.tar.lz4.uu \
libarchive/test/test_compat_lz4_3.tar.lz4.uu \
libarchive/test/test_compat_lz4_B4.tar.lz4.uu \
libarchive/test/test_compat_lz4_skippable_frames_B4.tar.lz4.uu \
libarchive/test/test_compat_lz4_B4BD.tar.lz4.uu \
libarchive/test/test_compat_lz4_B4BDBX.tar.lz4.uu \
libarchive/test/test_compat_lz4_B5.tar.lz4.uu \
@ -808,6 +817,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_7zip_encryption_header.7z.uu \
libarchive/test/test_read_format_7zip_encryption_partially.7z.uu \
libarchive/test/test_read_format_7zip_extract_second.7z.uu \
libarchive/test/test_read_format_7zip_issue2765.7z.uu \
libarchive/test/test_read_format_7zip_lzma1.7z.uu \
libarchive/test/test_read_format_7zip_lzma1_2.7z.uu \
libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu \
@ -918,6 +928,9 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu \
libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu \
libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu \
libarchive/test/test_read_format_rar5_only_crypt_exfld.rar.uu \
libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu \
libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu \
libarchive/test/test_read_format_rar5_encrypted.rar.uu \
libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu \
libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu \
@ -949,6 +962,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_rar5_multiple_files.rar.uu \
libarchive/test/test_read_format_rar5_multiple_files_solid.rar.uu \
libarchive/test/test_read_format_rar5_nonempty_dir_stream.rar.uu \
libarchive/test/test_read_format_rar5_dirdata.rar.uu \
libarchive/test/test_read_format_rar5_owner.rar.uu \
libarchive/test/test_read_format_rar5_readtables_overflow.rar.uu \
libarchive/test/test_read_format_rar5_sfx.exe.uu \
@ -957,6 +971,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_rar5_stored_manyfiles.rar.uu \
libarchive/test/test_read_format_rar5_symlink.rar.uu \
libarchive/test/test_read_format_rar5_truncated_huff.rar.uu \
libarchive/test/test_read_format_rar5_unicode.rar.uu \
libarchive/test/test_read_format_rar5_win32.rar.uu \
libarchive/test/test_read_format_rar5_arm_filter_on_window_boundary.rar.uu \
libarchive/test/test_read_format_rar5_different_winsize_on_merge.rar.uu \
@ -969,14 +984,17 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_raw.data.gz.uu \
libarchive/test/test_read_format_raw.data.Z.uu \
libarchive/test/test_read_format_raw.data.uu \
libarchive/test/test_read_format_tar_V_negative_size.tar.uu \
libarchive/test/test_read_format_tar_concatenated.tar.uu \
libarchive/test/test_read_format_tar_empty_filename.tar.uu \
libarchive/test/test_read_format_tar_empty_with_gnulabel.tar.uu \
libarchive/test/test_read_format_tar_empty_pax.tar.Z.uu \
libarchive/test/test_read_format_tar_filename_koi8r.tar.Z.uu \
libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu \
libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu \
libarchive/test/test_read_format_tar_pax_g_large.tar.uu \
libarchive/test/test_read_format_tar_pax_large_attr.tar.Z.uu \
libarchive/test/test_read_format_tar_pax_negative_time.tar.uu \
libarchive/test/test_read_format_ustar_filename_cp866.tar.Z.uu \
libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \
libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \
@ -1041,6 +1059,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_large_splitted_rar_ac.uu \
libarchive/test/test_read_large_splitted_rar_ad.uu \
libarchive/test/test_read_large_splitted_rar_ae.uu \
libarchive/test/test_read_pax_empty_val_no_nl.tar.uu \
libarchive/test/test_read_pax_xattr_rht_security_selinux.tar.uu \
libarchive/test/test_read_pax_xattr_schily.tar.uu \
libarchive/test/test_read_splitted_rar_aa.uu \
@ -1052,6 +1071,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_splitted_rar_seek_support_ab.uu \
libarchive/test/test_splitted_rar_seek_support_ac.uu \
libarchive/test/test_write_disk_appledouble.cpio.gz.uu \
libarchive/test/test_write_disk_appledouble_zip.zip.uu \
libarchive/test/test_write_disk_hfs_compression.tgz.uu \
libarchive/test/test_write_disk_mac_metadata.tar.gz.uu \
libarchive/test/test_write_disk_no_hfs_compression.tgz.uu \
@ -1061,14 +1081,15 @@ libarchive_test_EXTRA_DIST=\
#
# Common code for libarchive frontends (cpio, tar)
#
libarchive_fe_la_SOURCES= \
libarchive_fe/err.c \
libarchive_fe/err.h \
noinst_HEADERS+= \
libarchive_fe/lafe_err.h \
libarchive_fe/lafe_platform.h \
libarchive_fe/line_reader.c \
libarchive_fe/line_reader.h \
libarchive_fe/passphrase.c \
libarchive_fe/passphrase.h
libarchive_fe_la_SOURCES= \
libarchive_fe/lafe_err.c \
libarchive_fe/line_reader.c \
libarchive_fe/passphrase.c
libarchive_fe_la_CPPFLAGS= -I$(top_srcdir)/libarchive
#
@ -1077,21 +1098,23 @@ libarchive_fe_la_CPPFLAGS= -I$(top_srcdir)/libarchive
#
#
noinst_HEADERS+= \
tar/bsdtar.h \
tar/bsdtar_platform.h
bsdtar_SOURCES= \
tar/bsdtar.c \
tar/bsdtar.h \
tar/bsdtar_platform.h \
tar/cmdline.c \
tar/creation_set.c \
tar/read.c \
tar/subst.c \
tar/util.c \
tar/write.c
tar/bsdtar.c \
tar/cmdline.c \
tar/creation_set.c \
tar/read.c \
tar/subst.c \
tar/util.c \
tar/write.c
if INC_WINDOWS_FILES
noinst_HEADERS+= \
tar/bsdtar_windows.h
bsdtar_SOURCES+= \
tar/bsdtar_windows.h \
tar/bsdtar_windows.c
tar/bsdtar_windows.c
endif
bsdtar_DEPENDENCIES= libarchive.la libarchive_fe.la
@ -1128,12 +1151,15 @@ endif
# bsdtar_test
#
noinst_HEADERS+= \
tar/test/test.h
bsdtar_test_SOURCES= \
$(test_utils_SOURCES) \
tar/test/test.h \
tar/test/test_0.c \
tar/test/test_basic.c \
tar/test/test_copy.c \
tar/test/test_crlf_mtree.c \
tar/test/test_empty_mtree.c \
tar/test/test_extract_tar_Z.c \
tar/test/test_extract_tar_bz2.c \
@ -1210,9 +1236,9 @@ bsdtar_test_CPPFLAGS=\
-I$(top_builddir)/tar/test \
$(PLATFORMCPPFLAGS)
tar/test/list.h: Makefile
tar/test/list.h: $(bsdtar_test_SOURCES)
$(MKDIR_P) tar/test
cat $(top_srcdir)/tar/test/test_*.c | grep '^DEFINE_TEST' > tar/test/list.h
grep -h '^DEFINE_TEST(' $^ | LC_COLLATE=C sort > $@
if BUILD_BSDTAR
bsdtar_test_programs= bsdtar_test
@ -1253,16 +1279,18 @@ bsdtar_test_EXTRA_DIST= \
#
#
noinst_HEADERS+= \
cpio/cpio.h \
cpio/cpio_platform.h
bsdcpio_SOURCES= \
cpio/cmdline.c \
cpio/cpio.c \
cpio/cpio.h \
cpio/cpio_platform.h
cpio/cmdline.c \
cpio/cpio.c
if INC_WINDOWS_FILES
noinst_HEADERS+= \
cpio/cpio_windows.h
bsdcpio_SOURCES+= \
cpio/cpio_windows.h \
cpio/cpio_windows.c
cpio/cpio_windows.c
endif
bsdcpio_DEPENDENCIES = libarchive.la libarchive_fe.la
@ -1301,10 +1329,11 @@ endif
# bsdcpio_test
#
noinst_HEADERS+= \
cpio/test/test.h
bsdcpio_test_SOURCES= \
$(test_utils_SOURCES) \
cpio/cmdline.c \
cpio/test/test.h \
cpio/test/test_0.c \
cpio/test/test_basic.c \
cpio/test/test_cmdline.c \
@ -1363,9 +1392,9 @@ bsdcpio_test_CPPFLAGS= \
$(PLATFORMCPPFLAGS)
bsdcpio_test_LDADD=libarchive_fe.la
cpio/test/list.h: Makefile
cpio/test/list.h: $(bsdcpio_test_SOURCES)
$(MKDIR_P) cpio/test
cat $(top_srcdir)/cpio/test/test_*.c | grep '^DEFINE_TEST' > cpio/test/list.h
grep -h '^DEFINE_TEST(' $^ | LC_COLLATE=C sort > $@
if BUILD_BSDCPIO
bsdcpio_test_programs= bsdcpio_test
@ -1410,13 +1439,15 @@ bsdcpio_test_EXTRA_DIST= \
#
#
noinst_HEADERS+= \
cat/bsdcat.h \
cat/bsdcat_platform.h
bsdcat_SOURCES= \
cat/bsdcat.c \
cat/bsdcat.h \
cat/bsdcat_platform.h \
cat/cmdline.c
cat/bsdcat.c \
cat/cmdline.c
if INC_WINDOWS_FILES
noinst_HEADERS+=
bsdcat_SOURCES+=
endif
@ -1453,9 +1484,10 @@ endif
# bsdcat_test
#
noinst_HEADERS+= \
cat/test/test.h
bsdcat_test_SOURCES= \
$(test_utils_SOURCES) \
cat/test/test.h \
cat/test/test_0.c \
cat/test/test_empty_gz.c \
cat/test/test_empty_lz4.c \
@ -1483,9 +1515,9 @@ bsdcat_test_CPPFLAGS= \
$(PLATFORMCPPFLAGS)
bsdcat_test_LDADD=libarchive_fe.la
cat/test/list.h: Makefile
cat/test/list.h: $(bsdcat_test_SOURCES)
$(MKDIR_P) cat/test
cat $(top_srcdir)/cat/test/test_*.c | grep '^DEFINE_TEST' > cat/test/list.h
grep -h '^DEFINE_TEST(' $^ | LC_COLLATE=C sort > $@
if BUILD_BSDCAT
bsdcat_test_programs= bsdcat_test
@ -1516,16 +1548,18 @@ bsdcat_test_EXTRA_DIST= \
#
#
noinst_HEADERS+= \
unzip/bsdunzip.h \
unzip/bsdunzip_platform.h \
unzip/la_getline.h \
unzip/la_queue.h
bsdunzip_SOURCES= \
unzip/bsdunzip.c \
unzip/bsdunzip.h \
unzip/bsdunzip_platform.h \
unzip/cmdline.c \
unzip/la_getline.c \
unzip/la_getline.h \
unzip/la_queue.h
unzip/bsdunzip.c \
unzip/cmdline.c \
unzip/la_getline.c
if INC_WINDOWS_FILES
noinst_HEADERS+=
bsdunzip_SOURCES+=
endif
@ -1562,9 +1596,10 @@ endif
# bsdunzip_test
#
noinst_HEADERS+= \
unzip/test/test.h
bsdunzip_test_SOURCES= \
$(test_utils_SOURCES) \
unzip/test/test.h \
unzip/test/test_0.c \
unzip/test/test_basic.c \
unzip/test/test_doubledash.c \
@ -1595,9 +1630,9 @@ bsdunzip_test_CPPFLAGS= \
$(PLATFORMCPPFLAGS)
bsdunzip_test_LDADD=libarchive_fe.la
unzip/test/list.h: Makefile
unzip/test/list.h: $(bsdunzip_test_SOURCES)
$(MKDIR_P) unzip/test
cat $(top_srcdir)/unzip/test/test_*.c | grep '^DEFINE_TEST' > unzip/test/list.h
grep -h '^DEFINE_TEST(' $^ | LC_COLLATE=C sort > $@
if BUILD_BSDUNZIP
bsdunzip_test_programs= bsdunzip_test

10
NEWS
View File

@ -1,3 +1,13 @@
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
Sep 13, 2024: libarchive 3.7.5 released
Apr 26, 2024: libarchive 3.7.4 released

View File

@ -191,7 +191,7 @@ questions we are asked about libarchive:
libraries. This also reduces the size of statically-linked
binaries in environments where that matters.
* The library is generally _thread safe_ depending on the platform:
* The library is generally _thread-safe_ depending on the platform:
it does not define any global variables of its own. However, some
platforms do not provide fully thread-safe versions of key C library
functions. On those platforms, libarchive will use the non-thread-safe
@ -214,7 +214,7 @@ questions we are asked about libarchive:
multiple threads. Of course, those modules are completely
optional and you can use the rest of libarchive without them.
* The library is _not_ thread aware, however. It does no locking
* The library is _not_ thread-aware, however. It does no locking
or thread management of any kind. If you create a libarchive
object and need to access it from multiple threads, you will
need to provide your own locking.

View File

@ -16,4 +16,4 @@ Please provide the following information in your report:
- How to reproduce the issue
This project is maintained by volunteers on a reasonable-effort basis. As such, we ask
that you give me 90 days to work on a fix before public exposure.
that you give us 90 days to work on a fix before public exposure.

View File

@ -23,7 +23,7 @@ then
tunefs -N enable /dev/$MD
mount /dev/$MD /tmp_acl_nfsv4
chmod 1777 /tmp_acl_nfsv4
pkg install -y autoconf automake cmake libiconv libtool pkgconf expat libxml2 liblz4 zstd
pkg install -y autoconf automake cmake libiconv libtool pkgconf expat libxml2 liblz4 zstd gmake
elif [ "${UNAME}" = "Darwin" ]
then
set -x -e

View File

@ -5,6 +5,9 @@ set -eux
#brew update > /dev/null
#brew upgrade > /dev/null
# Workaround for cmake in local/pinned tap issue
brew uninstall cmake
# This does an upgrade if the package is already installed
brew install \
autoconf \

View File

@ -29,5 +29,5 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
# And install it, of course ;).
IF(ENABLE_INSTALL)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
DESTINATION "lib/pkgconfig")
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF()

View File

@ -405,6 +405,12 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `chroot' function. */
#cmakedefine HAVE_CHROOT 1
/* Define to 1 if you have the `closefrom' function. */
#cmakedefine HAVE_CLOSEFROM 1
/* Define to 1 if you have the `close_range' function. */
#cmakedefine HAVE_CLOSE_RANGE 1
/* Define to 1 if you have the <copyfile.h> header file. */
#cmakedefine HAVE_COPYFILE_H 1
@ -970,9 +976,6 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H 1
/* Define to 1 if you have the `readdir_r' function. */
#cmakedefine HAVE_READDIR_R 1
/* Define to 1 if you have the `readlink' function. */
#cmakedefine HAVE_READLINK 1

View File

@ -1 +1 @@
3008000
3009000

View File

@ -13,8 +13,8 @@ IF(ENABLE_CAT)
bsdcat.h
bsdcat_platform.h
cmdline.c
../libarchive_fe/err.c
../libarchive_fe/err.h
../libarchive_fe/lafe_err.c
../libarchive_fe/lafe_err.h
../libarchive_fe/lafe_platform.h
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe)

View File

@ -7,6 +7,9 @@
#include "bsdcat_platform.h"
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@ -22,7 +25,7 @@
#include <archive_entry.h>
#include "bsdcat.h"
#include "err.h"
#include "lafe_err.h"
#define BYTES_PER_BLOCK (20*512)
@ -105,6 +108,16 @@ main(int argc, char **argv)
bsdcat = &bsdcat_storage;
memset(bsdcat, 0, sizeof(*bsdcat));
#if defined(HAVE_SIGACTION) && defined(SIGCHLD)
{ /* Do not ignore SIGCHLD. */
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGCHLD, &sa, NULL);
}
#endif
lafe_setprogname(*argv, "bsdcat");
bsdcat->argv = argv;

View File

@ -22,7 +22,7 @@
#endif
#include "bsdcat.h"
#include "err.h"
#include "lafe_err.h"
/*
* Short options for bsdcat. Please keep this sorted.

View File

@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
dnl In particular, this allows the version macro to be used in AC_INIT
dnl These first two version numbers are updated automatically on each release.
m4_define([LIBARCHIVE_VERSION_S],[3.8.0dev])
m4_define([LIBARCHIVE_VERSION_N],[3008000])
m4_define([LIBARCHIVE_VERSION_S],[3.9.0dev])
m4_define([LIBARCHIVE_VERSION_N],[3009000])
dnl bsdtar and bsdcpio versioning tracks libarchive
m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
@ -258,7 +258,8 @@ AM_CONDITIONAL([STATIC_BSDCPIO], [ test "$static_bsdcpio" = yes ])
case $host in
*mingw* | *cygwin* | *msys* )
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
[[#ifdef _WIN32_WINNT
[[#include <windows.h>
#ifdef _WIN32_WINNT
# error _WIN32_WINNT already defined
#endif
]],[[;]])
@ -267,7 +268,8 @@ case $host in
AC_DEFINE([NTDDI_VERSION], 0x05020000, [Define to '0x05020000' for Windows Server 2003 APIs.])
])
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
[[#ifdef WINVER
[[#include <windows.h>
#ifdef WINVER
# error WINVER already defined
#endif
]],[[;]])
@ -375,7 +377,7 @@ AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h])
AC_CHECK_TYPE([suseconds_t])
AC_CHECK_HEADERS([windows.h])
# check windows.h first; the other headers require it.
AC_CHECK_HEADERS([wincrypt.h winioctl.h],[],[],
AC_CHECK_HEADERS([winioctl.h],[],[],
[[#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
@ -436,13 +438,15 @@ if test "x$with_bz2lib" != "xno"; then
esac
fi
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([libb2],
AS_HELP_STRING([--without-libb2], [Don't build support for BLAKE2 through libb2]))
if test "x$with_libb2" != "xno"; then
AC_CHECK_HEADERS([blake2.h])
AC_CHECK_LIB(b2,blake2sp_init)
BLAKE2_PC_VER=`pkg-config --modversion libb2`
BLAKE2_PC_VER=`$PKG_CONFIG --modversion libb2`
if test "x$BLAKE2_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBB2_PKGCONFIG_VERSION], ["$BLAKE2_PC_VER"], [Libb2 version coming from pkg-config.])
fi
@ -817,16 +821,20 @@ AC_FUNC_VPRINTF
# To avoid necessity for including windows.h or special forward declaration
# workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *'
AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *])
AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r])
AC_CHECK_FUNCS([arc4random_buf chflags chown chroot])
AC_CHECK_FUNCS([closefrom close_range ctime_r])
AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fnmatch fork])
AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate])
AC_CHECK_FUNCS([futimens futimes futimesat])
AC_CHECK_FUNCS([geteuid getline getpid getgrgid_r getgrnam_r])
AC_CHECK_FUNCS([getpwnam_r getpwuid_r getvfsbyname gmtime_r])
AC_CHECK_FUNCS([getegid geteuid getline getpid getresgid getresuid])
AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r])
AC_CHECK_FUNCS([getvfsbyname gmtime_r])
AC_CHECK_FUNCS([issetugid])
AC_CHECK_FUNCS([lchflags lchmod lchown link linkat localtime_r lstat lutimes])
AC_CHECK_FUNCS([mbrtowc memmove memset])
AC_CHECK_FUNCS([mkdir mkfifo mknod mkstemp])
AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawnp readlink readlinkat])
AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawn posix_spawnp])
AC_CHECK_FUNCS([readlink readlinkat])
AC_CHECK_FUNCS([readpassphrase])
AC_CHECK_FUNCS([select setenv setlocale sigaction statfs statvfs])
AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strnlen strrchr symlink])
@ -877,14 +885,6 @@ AC_CHECK_TYPES(struct statfs,,,
#include <sys/mount.h>
])
# There are several variants of readdir_r around; we only
# accept the POSIX-compliant version.
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <dirent.h>]],
[[DIR *dir; struct dirent e, *r;
return(readdir_r(dir, &e, &r));]])],
[AC_DEFINE(HAVE_READDIR_R,1,[Define to 1 if you have a POSIX compatible readdir_r])]
)
# dirfd can be either a function or a macro.
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <dirent.h>
@ -925,7 +925,7 @@ if test "x$enable_xattr" != "xno"; then
])
AC_CHECK_DECLS([XATTR_NOFOLLOW], [], [], [#include <sys/xattr.h>
])
ATTR_PC_VER=`pkg-config --modversion libattr`
ATTR_PC_VER=`$PKG_CONFIG --modversion libattr`
if test "x$ATTR_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBATTR_PKGCONFIG_VERSION], ["$ATTR_PC_VER"], [Libattr version coming from pkg-config.])
fi
@ -1024,7 +1024,7 @@ AC_ARG_ENABLE([acl],
if test "x$enable_acl" != "xno"; then
# Libacl
AC_CHECK_LIB([acl], [acl_get_file])
ACL_PC_VER=`pkg-config --modversion libacl`
ACL_PC_VER=`$PKG_CONFIG --modversion libacl`
if test "x$ACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBACL_PKGCONFIG_VERSION], ["$ACL_PC_VER"], [Libacl version coming from pkg-config.])
fi
@ -1038,7 +1038,7 @@ if test "x$enable_acl" != "xno"; then
])
AC_CHECK_LIB([richacl], [richacl_get_file])
RICHACL_PC_VER=`pkg-config --modversion librichacl`
RICHACL_PC_VER=`$PKG_CONFIG --modversion librichacl`
if test "x$RICHACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBRICHACL_PKGCONFIG_VERSION], ["$RICHACL_PC_VER"], [Librichacl version coming from pkg-config.])
fi

View File

@ -26,6 +26,8 @@ LOCAL_PATH := $(subst /contrib/android,,$(call my-dir))
libarchive_target_config := contrib/android/config/android.h
libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_blake2s_ref.c \
libarchive/archive_blake2sp_ref.c \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
libarchive/archive_cryptor.c \
@ -44,6 +46,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_parse_date.c \
libarchive/archive_pathmatch.c \
libarchive/archive_ppmd7.c \
libarchive/archive_ppmd8.c \
libarchive/archive_random.c \
libarchive/archive_rb.c \
libarchive/archive_read.c \
@ -86,6 +89,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_read_support_format_lha.c \
libarchive/archive_read_support_format_mtree.c \
libarchive/archive_read_support_format_rar.c \
libarchive/archive_read_support_format_rar5.c \
libarchive/archive_read_support_format_raw.c \
libarchive/archive_read_support_format_tar.c \
libarchive/archive_read_support_format_warc.c \
@ -93,6 +97,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_read_support_format_zip.c \
libarchive/archive_string.c \
libarchive/archive_string_sprintf.c \
libarchive/archive_time.c \
libarchive/archive_util.c \
libarchive/archive_version_details.c \
libarchive/archive_virtual.c \
@ -123,7 +128,9 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_write_set_format_ar.c \
libarchive/archive_write_set_format_by_name.c \
libarchive/archive_write_set_format_cpio.c \
libarchive/archive_write_set_format_cpio_binary.c \
libarchive/archive_write_set_format_cpio_newc.c \
libarchive/archive_write_set_format_cpio_odc.c \
libarchive/archive_write_set_format_iso9660.c \
libarchive/archive_write_set_format_mtree.c \
libarchive/archive_write_set_format_pax.c \
@ -151,7 +158,7 @@ else
libarchive_host_src_files :=
endif
libarchive_fe_src_files := libarchive_fe/err.c \
libarchive_fe_src_files := libarchive_fe/lafe_err.c \
libarchive_fe/line_reader.c \
libarchive_fe/passphrase.c
@ -305,4 +312,17 @@ LOCAL_SRC_FILES := $(bsdcat_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libarchive $(LOCAL_PATH)/libarchive_fe $(LOCAL_PATH)/contrib/android/include
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := bsdtar-recovery
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_STEM := bsdtar
LOCAL_CFLAGS := -DBSDTAR_VERSION_STRING=ARCHIVE_VERSION_ONLY_STRING -DPLATFORM_CONFIG_H=\"$(libarchive_target_config)\"
LOCAL_STATIC_LIBRARIES := libarchive libarchive_fe libz
LOCAL_SRC_FILES := $(bsdtar_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libarchive $(LOCAL_PATH)/libarchive_fe $(LOCAL_PATH)/contrib/android/include
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif

View File

@ -26,6 +26,8 @@
#ifndef ARCHIVE_PLATFORM_H_ANDROID_INCLUDED
#define ARCHIVE_PLATFORM_H_ANDROID_INCLUDED
#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
#include <android/api-level.h>
#ifdef __ANDROID_API__
#if __ANDROID_API__ > 20
@ -40,6 +42,8 @@
#define HAVE_CHOWN 1
#define HAVE_CHROOT 1
#define HAVE_CLOSEFROM 0
#define HAVE_CLOSE_RANGE 0
#define HAVE_CTIME_R 1
#define HAVE_CTYPE_H 1
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0
@ -53,6 +57,8 @@
#define HAVE_DECL_UINTMAX_MAX 1
#define HAVE_DECL_UINT32_MAX 1
#define HAVE_DECL_UINT64_MAX 1
#define HAVE_DECL_INT32_MAX 1
#define HAVE_DECL_INT32_MIN 1
#define HAVE_DIRENT_H 1
#define HAVE_DIRFD 1
#define HAVE_DLFCN_H 1
@ -135,7 +141,7 @@
#define HAVE_STRING_H 1
#define HAVE_STRRCHR 1
#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
#define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
#define HAVE_STRUCT_STAT_ST_MTIME_NSEC 0
#define HAVE_STRUCT_TM_TM_GMTOFF 1
#define HAVE_SYMLINK 1
#define HAVE_SYS_CDEFS_H 1

View File

@ -28,6 +28,8 @@
#define HAVE_CHOWN 1
#define HAVE_CHROOT 1
#define HAVE_CLOSEFROM 1
#define HAVE_CLOSE_RANGE 1
#define HAVE_CTIME_R 1
#define HAVE_CTYPE_H 1
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0
@ -180,7 +182,7 @@
#define HAVE_WMEMCMP 1
#define HAVE_WMEMCPY 1
#define HAVE_ZLIB_H 1
#define ICONV_CONST
#define ICONV_CONST
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
#define SIZEOF_WCHAR_T 4
#define STDC_HEADERS 1

View File

@ -175,6 +175,12 @@
/* Define to 1 if you have the `chroot' function. */
/* #undef HAVE_CHROOT */
/* Define to 1 if you have the `closefrom' function. */
/* #undef HAVE_CLOSEFROM */
/* Define to 1 if you have the `close_range' function. */
/* #undef HAVE_CLOSE_RANGE */
/* Define to 1 if you have the <copyfile.h> header file. */
/* #undef HAVE_COPYFILE_H */
@ -620,9 +626,6 @@
/* Define to 1 if you have the <pwd.h> header file. */
/* #undef HAVE_PWD_H */
/* Define to 1 if you have a POSIX compatible readdir_r */
#define HAVE_READDIR_R 1
/* Define to 1 if you have the `readlink' function. */
/* #undef HAVE_READLINK */
@ -896,9 +899,6 @@
/* Define to 1 if you have the <wctype.h> header file. */
#define HAVE_WCTYPE_H 1
/* Define to 1 if you have the <wincrypt.h> header file. */
#define HAVE_WINCRYPT_H 1
/* Define to 1 if you have the <windows.h> header file. */
#define HAVE_WINDOWS_H 1

View File

@ -1,4 +1,4 @@
/*
/*
* Macros for file64 functions
*
* Android does not support the macro _FILE_OFFSET_BITS=64
@ -19,7 +19,6 @@
#include <sys/vfs.h>
//dirent.h
#define readdir_r readdir64_r
#define readdir readdir64
#define dirent dirent64
//fcntl.h

View File

@ -0,0 +1,156 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBARCHIVE_FUZZ_HELPERS_H_
#define LIBARCHIVE_FUZZ_HELPERS_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <ftw.h>
#include <unistd.h>
#include "archive.h"
// Default maximum input size for fuzzers
static constexpr size_t kDefaultMaxInputSize = 256 * 1024; // 256KB
// Buffer structure for archive reading callbacks
struct Buffer {
const uint8_t* data;
size_t size;
size_t pos;
};
// Archive read callback function
static la_ssize_t reader_callback(struct archive* a, void* client_data,
const void** buffer) {
(void)a;
Buffer* buf = static_cast<Buffer*>(client_data);
if (buf->pos >= buf->size) {
return 0; // EOF
}
*buffer = buf->data + buf->pos;
size_t remaining = buf->size - buf->pos;
buf->pos = buf->size; // Consume all remaining data
return static_cast<la_ssize_t>(remaining);
}
// Helper class for consuming fuzz data in structured ways
class DataConsumer {
public:
DataConsumer(const uint8_t* data, size_t size)
: data_(data), size_(size), pos_(0) {}
bool empty() const { return pos_ >= size_; }
size_t remaining() const { return size_ - pos_; }
uint8_t consume_byte() {
if (pos_ >= size_) return 0;
return data_[pos_++];
}
uint16_t consume_u16() {
uint16_t val = 0;
if (pos_ + 2 <= size_) {
val = static_cast<uint16_t>(data_[pos_]) |
(static_cast<uint16_t>(data_[pos_ + 1]) << 8);
pos_ += 2;
}
return val;
}
uint32_t consume_u32() {
uint32_t val = 0;
if (pos_ + 4 <= size_) {
val = static_cast<uint32_t>(data_[pos_]) |
(static_cast<uint32_t>(data_[pos_ + 1]) << 8) |
(static_cast<uint32_t>(data_[pos_ + 2]) << 16) |
(static_cast<uint32_t>(data_[pos_ + 3]) << 24);
pos_ += 4;
}
return val;
}
int64_t consume_i64() {
int64_t val = 0;
if (pos_ + 8 <= size_) {
for (int i = 0; i < 8; i++) {
val |= static_cast<int64_t>(data_[pos_ + i]) << (8 * i);
}
pos_ += 8;
}
return val;
}
// Consume a null-terminated string up to max_len characters
// Returns pointer to internal buffer (valid until next consume_string call)
const char* consume_string(size_t max_len) {
if (max_len > sizeof(string_buf_) - 1) {
max_len = sizeof(string_buf_) - 1;
}
size_t avail = size_ - pos_;
size_t len = (avail < max_len) ? avail : max_len;
size_t actual_len = 0;
while (actual_len < len && pos_ < size_) {
char c = static_cast<char>(data_[pos_++]);
if (c == '\0') break;
string_buf_[actual_len++] = c;
}
string_buf_[actual_len] = '\0';
return string_buf_;
}
// Consume raw bytes into a buffer
size_t consume_bytes(void* out, size_t len) {
size_t avail = size_ - pos_;
size_t to_copy = (avail < len) ? avail : len;
if (to_copy > 0) {
memcpy(out, data_ + pos_, to_copy);
pos_ += to_copy;
}
return to_copy;
}
// Get remaining data as a buffer
const uint8_t* remaining_data() const {
return data_ + pos_;
}
private:
const uint8_t* data_;
size_t size_;
size_t pos_;
char string_buf_[512];
};
// Callback for nftw to remove files/directories
static int remove_callback(const char* fpath, const struct stat* sb,
int typeflag, struct FTW* ftwbuf) {
(void)sb;
(void)typeflag;
(void)ftwbuf;
return remove(fpath);
}
// Recursively remove a directory tree (safer than system("rm -rf ..."))
static int remove_directory_tree(const char* path) {
// nftw with FTW_DEPTH processes directory contents before the directory itself
return nftw(path, remove_callback, 64, FTW_DEPTH | FTW_PHYS);
}
#endif // LIBARCHIVE_FUZZ_HELPERS_H_

View File

@ -0,0 +1,63 @@
/*
* 7-Zip format specific fuzzer for libarchive
* Targets 7-Zip parsing and decompression code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable 7-Zip format specifically
archive_read_support_format_7zip(a);
// Enable all filters for 7z internal compression
archive_read_support_filter_all(a);
// Set passphrase for encrypted archives
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
archive_entry_is_data_encrypted(entry);
archive_entry_is_metadata_encrypted(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,47 @@
# 7-Zip format dictionary
# Magic bytes
"7z\xbc\xaf\x27\x1c"
"\x37\x7a\xbc\xaf\x27\x1c"
# Common property IDs
"\x00"
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
"\x06"
"\x07"
"\x08"
"\x09"
"\x0a"
"\x0b"
"\x0c"
"\x0d"
"\x0e"
"\x0f"
"\x10"
"\x11"
"\x17"
"\x19"
"\x21"
"\x23"
"\x24"
"\x25"
# Compression method IDs
"\x00\x00"
"\x00\x03"
"\x00\x04"
"\x00\x06"
"\x01\x01"
"\x03\x01\x01"
"\x04\x01\x08"
"\x04\x02\x02"
"\x21\x01"
"\x30\x01\x01"
# Encryption
"\x06\xf1\x07\x01"
"Password"
"password"

View File

@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60

View File

@ -0,0 +1,54 @@
/*
* AR (Unix archive) format fuzzer for libarchive
* Tests BSD and GNU ar formats
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_ar(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,20 @@
# AR format dictionary
# AR magic
"!<arch>\x0a"
# File header terminator
"\x60\x0a"
# Special entries
"/"
"//"
"/SYM64/"
# Common permissions
"100644 "
"100755 "
# UID/GID fields
"0 "
"1000 "

View File

@ -0,0 +1,51 @@
/*
* CAB (Microsoft Cabinet) format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_cab(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,23 @@
# CAB (Microsoft Cabinet) format dictionary
# CAB signature
"MSCF"
"\x4d\x53\x43\x46"
# Version
"\x03\x01"
# Compression types
"\x00\x00"
"\x01\x00"
"\x02\x00"
"\x03\x00"
# Folder count patterns
"\x01\x00"
"\x02\x00"
# Header flags
"\x00\x00"
"\x01\x00"
"\x04\x00"

View File

@ -0,0 +1,58 @@
/*
* CPIO format fuzzer for libarchive
* Tests all CPIO variants: binary, odc, newc, crc
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_cpio(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_ino(entry);
archive_entry_nlink(entry);
archive_entry_rdev(entry);
archive_entry_hardlink(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,25 @@
# CPIO format dictionary
# Binary magic (little endian)
"\xc7\x71"
# Binary magic (big endian)
"\x71\xc7"
# ASCII odc magic
"070707"
# ASCII newc magic
"070701"
# ASCII crc magic
"070702"
# Common trailer
"TRAILER!!!"
# Common field patterns
"00000000"
"00000001"
"000001ed"
"000003e8"

View File

@ -0,0 +1,101 @@
/*
* Encrypted archive fuzzer for libarchive
* Tests password/passphrase handling across formats
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
// Passphrase callback for testing
static const char *test_passphrases[] = {
"password",
"test",
"123456",
"",
"secret",
NULL
};
static int passphrase_idx = 0;
static const char* passphrase_callback(struct archive *a, void *client_data) {
(void)a;
(void)client_data;
const char *pass = test_passphrases[passphrase_idx];
if (pass != NULL) {
passphrase_idx++;
}
return pass;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
// Reset passphrase index
passphrase_idx = 0;
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable all formats that support encryption
archive_read_support_format_zip(a);
archive_read_support_format_7zip(a);
archive_read_support_format_rar(a);
archive_read_support_format_rar5(a);
archive_read_support_filter_all(a);
// Set up passphrase callback
archive_read_set_passphrase_callback(a, NULL, passphrase_callback);
// Also add some static passphrases
archive_read_add_passphrase(a, "password");
archive_read_add_passphrase(a, "test123");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
int entry_count = 0;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && entry_count < 100) {
archive_entry_pathname(entry);
// Check encryption status
int is_encrypted = archive_entry_is_encrypted(entry);
int is_data_encrypted = archive_entry_is_data_encrypted(entry);
int is_meta_encrypted = archive_entry_is_metadata_encrypted(entry);
(void)is_encrypted;
(void)is_data_encrypted;
(void)is_meta_encrypted;
// Check if archive has encrypted entries
archive_read_has_encrypted_entries(a);
// Try to read data (may fail due to wrong password)
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
entry_count++;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60

View File

@ -0,0 +1,105 @@
/*
* Archive entry fuzzer for libarchive
* Targets archive_entry_* functions including ACL, linkify, and metadata
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) {
return 0;
}
// Set basic entry properties
archive_entry_set_pathname(entry, consumer.consume_string(256));
archive_entry_set_size(entry, consumer.consume_i64());
archive_entry_set_mode(entry, consumer.consume_u32());
archive_entry_set_uid(entry, consumer.consume_u32());
archive_entry_set_gid(entry, consumer.consume_u32());
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
archive_entry_set_atime(entry, consumer.consume_i64(), 0);
archive_entry_set_ctime(entry, consumer.consume_i64(), 0);
archive_entry_set_birthtime(entry, consumer.consume_i64(), 0);
// Set various string fields
archive_entry_set_uname(entry, consumer.consume_string(64));
archive_entry_set_gname(entry, consumer.consume_string(64));
archive_entry_set_symlink(entry, consumer.consume_string(256));
archive_entry_set_hardlink(entry, consumer.consume_string(256));
// Exercise ACL functions (low coverage targets)
int acl_type = consumer.consume_byte() & 0x0F;
int acl_permset = consumer.consume_u32();
int acl_tag = consumer.consume_byte() & 0x0F;
int acl_qual = consumer.consume_u32();
const char *acl_name = consumer.consume_string(64);
archive_entry_acl_add_entry(entry, acl_type, acl_permset, acl_tag, acl_qual, acl_name);
// Add more ACL entries based on remaining data
while (!consumer.empty() && consumer.remaining() > 10) {
acl_type = consumer.consume_byte() & 0x0F;
acl_permset = consumer.consume_u32();
acl_tag = consumer.consume_byte() & 0x0F;
acl_qual = consumer.consume_u32();
acl_name = consumer.consume_string(32);
archive_entry_acl_add_entry(entry, acl_type, acl_permset, acl_tag, acl_qual, acl_name);
}
// Exercise ACL text conversion functions (archive_acl_to_text_* are uncovered)
ssize_t text_len;
char *acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
if (acl_text) {
// Parse the text back
archive_entry_acl_from_text(entry, acl_text, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
free(acl_text);
}
acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
if (acl_text) {
free(acl_text);
}
acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
if (acl_text) {
free(acl_text);
}
// Exercise wide character versions
wchar_t *acl_text_w = archive_entry_acl_to_text_w(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
if (acl_text_w) {
free(acl_text_w);
}
// Get pathname variants
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_pathname_utf8(entry);
// Clone the entry
struct archive_entry *entry2 = archive_entry_clone(entry);
if (entry2) {
archive_entry_free(entry2);
}
// Clear and reuse
archive_entry_clear(entry);
archive_entry_free(entry);
return 0;
}

View File

@ -0,0 +1,65 @@
/*
* Compression filter fuzzer for libarchive
* Tests decompression of gzip, bzip2, xz, lzma, zstd, lz4, etc.
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable raw format (just decompress, no archive format)
archive_read_support_format_raw(a);
// Enable all compression filters
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(8192, 0);
struct archive_entry *entry;
if (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Get filter info
int filter_count = archive_filter_count(a);
for (int i = 0; i < filter_count; i++) {
archive_filter_name(a, i);
archive_filter_code(a, i);
archive_filter_bytes(a, i);
}
// Read all decompressed data
ssize_t total = 0;
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0) {
total += r;
// Limit total decompressed size to prevent zip bombs
if (total > 10 * 1024 * 1024) {
break;
}
}
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,33 @@
# Compression filter dictionary
# GZIP magic
"\x1f\x8b"
"\x1f\x8b\x08"
# BZIP2 magic
"BZh"
"BZ0"
# XZ magic
"\xfd7zXZ\x00"
# LZMA magic
"\x5d\x00\x00"
# ZSTD magic
"\x28\xb5\x2f\xfd"
# LZ4 magic
"\x04\x22\x4d\x18"
# Compress (.Z) magic
"\x1f\x9d"
# LZIP magic
"LZIP"
# LRZIP magic
"LRZI"
# LZO magic
"\x89LZO\x00\x0d\x0a\x1a\x0a"

View File

@ -0,0 +1,10 @@
[libfuzzer]
max_len = 262144
timeout = 30
rss_limit_mb = 2048
[honggfuzz]
timeout = 30
[afl]
timeout = 30

View File

@ -3,20 +3,7 @@
#include <vector>
#include "archive.h"
struct Buffer {
const uint8_t *buf;
size_t len;
};
ssize_t reader_callback(struct archive *a, void *client_data,
const void **block) {
Buffer *buffer = reinterpret_cast<Buffer *>(client_data);
*block = buffer->buf;
ssize_t len = buffer->len;
buffer->len = 0;
return len;
}
#include "fuzz_helpers.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
int ret;
@ -26,7 +13,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
Buffer buffer = {buf, len};
Buffer buffer = {buf, len, 0};
archive_read_open(a, &buffer, NULL, reader_callback, NULL);
std::vector<uint8_t> data_buffer(getpagesize(), 0);

View File

@ -0,0 +1,76 @@
# General libarchive dictionary covering multiple formats
# TAR magic
"ustar"
"ustar\x00"
"ustar \x00"
"\x00\x00"
# ZIP magic
"PK\x03\x04"
"PK\x05\x06"
"PK\x01\x02"
"PK\x07\x08"
# 7z magic
"7z\xbc\xaf\x27\x1c"
# RAR magic
"Rar!\x1a\x07\x00"
"Rar!\x1a\x07\x01\x00"
# XAR magic
"xar!"
# CPIO magic
"\xc7\x71"
"070701"
"070702"
"070707"
# CAB magic
"MSCF"
# LHA magic
"-lh"
"-lz"
# AR magic
"!<arch>\x0a"
# ISO9660 magic
"CD001"
# GZIP magic
"\x1f\x8b"
# BZIP2 magic
"BZ"
"BZh"
# XZ magic
"\xfd7zXZ\x00"
# LZMA magic
"\x5d\x00\x00"
# ZSTD magic
"\x28\xb5\x2f\xfd"
# LZ4 magic
"\x04\x22\x4d\x18"
# Common paths
"/"
"./"
"../"
"./test"
"test.txt"
"test/"
# Common attributes
"\x00\x00\x00\x00"
"\xff\xff\xff\xff"
# Passphrase
"password"

View File

@ -0,0 +1,9 @@
[libfuzzer]
max_len = 524288
timeout = 30
[honggfuzz]
timeout = 30
[afl]
timeout = 30

View File

@ -0,0 +1,58 @@
/*
* ISO9660 format fuzzer for libarchive
* Tests ISO, Joliet, and Rock Ridge extensions
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 1024 * 1024; // 1MB for ISO images
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_iso9660(a);
archive_read_support_filter_all(a);
// Set options to test various ISO extensions
archive_read_set_options(a, "iso9660:joliet,iso9660:rockridge");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_symlink(entry);
archive_entry_hardlink(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,36 @@
# ISO9660 format dictionary
# Volume descriptor type
"\x00"
"\x01"
"\x02"
"\xff"
# Standard identifier
"CD001"
# Volume descriptor version
"\x01"
# Joliet escape sequences
"%/@"
"%/C"
"%/E"
# Rock Ridge signatures
"SP"
"RR"
"CE"
"PX"
"PN"
"SL"
"NM"
"CL"
"PL"
"RE"
"TF"
"SF"
# System use
"ER"
"ES"

View File

@ -0,0 +1,10 @@
[libfuzzer]
max_len = 1048576
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60

View File

@ -0,0 +1,54 @@
/*
* LHA/LZH format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_lha(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,26 @@
# LHA/LZH format dictionary
# Compression methods
"-lh0-"
"-lh1-"
"-lh2-"
"-lh3-"
"-lh4-"
"-lh5-"
"-lh6-"
"-lh7-"
"-lhd-"
"-lzs-"
"-lz4-"
"-lz5-"
# OS type
"\x00"
"\x4d"
"\x55"
# Header levels
"\x00"
"\x01"
"\x02"
"\x03"

View File

@ -0,0 +1,110 @@
/*
* Archive entry link resolver fuzzer for libarchive
* Targets archive_entry_linkify (complexity: 775, zero coverage)
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
// Simple data consumer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
// Create a link resolver
struct archive_entry_linkresolver *resolver = archive_entry_linkresolver_new();
if (resolver == NULL) {
return 0;
}
// Set the format strategy based on input
uint8_t strategy = consumer.consume_byte() % 5;
int format;
switch (strategy) {
case 0: format = ARCHIVE_FORMAT_TAR_GNUTAR; break;
case 1: format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; break;
case 2: format = ARCHIVE_FORMAT_CPIO_POSIX; break;
case 3: format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; break;
default: format = ARCHIVE_FORMAT_TAR_USTAR; break;
}
archive_entry_linkresolver_set_strategy(resolver, format);
// Create multiple entries to test linkify with hardlinks
struct archive_entry *entries[32];
int num_entries = 0;
while (!consumer.empty() && num_entries < 32 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
// Set pathname
archive_entry_set_pathname(entry, consumer.consume_string(64));
// Set inode and device for hardlink detection
archive_entry_set_ino(entry, consumer.consume_i64());
archive_entry_set_dev(entry, consumer.consume_u32());
archive_entry_set_nlink(entry, (consumer.consume_byte() % 5) + 1);
// Set mode (regular file or directory)
uint8_t ftype = consumer.consume_byte() % 2;
mode_t mode = ftype ? (S_IFDIR | 0755) : (S_IFREG | 0644);
archive_entry_set_mode(entry, mode);
archive_entry_set_size(entry, consumer.consume_i64() & 0xFFFF);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
entries[num_entries++] = entry;
}
// Now run all entries through the linkresolver
for (int i = 0; i < num_entries; i++) {
struct archive_entry *entry = entries[i];
struct archive_entry *spare = NULL;
// This is the main function we want to fuzz (zero coverage)
archive_entry_linkify(resolver, &entry, &spare);
// entry and spare may be modified by linkify
// We still need to free the original entries we allocated
if (spare != NULL) {
archive_entry_free(spare);
}
}
// Free remaining entries from the resolver
struct archive_entry *entry = NULL;
struct archive_entry *spare = NULL;
while (1) {
archive_entry_linkify(resolver, &entry, &spare);
if (entry == NULL)
break;
archive_entry_free(entry);
entry = NULL;
if (spare != NULL) {
archive_entry_free(spare);
spare = NULL;
}
}
// Free all our created entries
for (int i = 0; i < num_entries; i++) {
if (entries[i] != NULL) {
archive_entry_free(entries[i]);
}
}
archive_entry_linkresolver_free(resolver);
return 0;
}

View File

@ -0,0 +1,96 @@
/*
* Archive match fuzzer for libarchive
* Tests pattern matching, time matching, and owner matching
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 32 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *match = archive_match_new();
if (match == NULL) {
return 0;
}
// Add various match patterns
while (!consumer.empty() && consumer.remaining() > 5) {
uint8_t match_type = consumer.consume_byte() % 6;
switch (match_type) {
case 0: {
// Pattern exclusion
const char *pattern = consumer.consume_string(64);
archive_match_exclude_pattern(match, pattern);
break;
}
case 1: {
// Pattern inclusion
const char *pattern = consumer.consume_string(64);
archive_match_include_pattern(match, pattern);
break;
}
case 2: {
// Time comparison (newer than)
int64_t sec = consumer.consume_i64();
int64_t nsec = consumer.consume_i64() % 1000000000;
archive_match_include_time(match, ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER,
sec, nsec);
break;
}
case 3: {
// Time comparison (older than)
int64_t sec = consumer.consume_i64();
int64_t nsec = consumer.consume_i64() % 1000000000;
archive_match_include_time(match, ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER,
sec, nsec);
break;
}
case 4: {
// UID inclusion
int64_t uid = consumer.consume_i64() & 0xFFFF;
archive_match_include_uid(match, uid);
break;
}
case 5: {
// GID inclusion
int64_t gid = consumer.consume_i64() & 0xFFFF;
archive_match_include_gid(match, gid);
break;
}
}
}
// Create a test entry and check if it matches
struct archive_entry *entry = archive_entry_new();
if (entry) {
archive_entry_set_pathname(entry, "test/file.txt");
archive_entry_set_mtime(entry, 1234567890, 0);
archive_entry_set_uid(entry, 1000);
archive_entry_set_gid(entry, 1000);
archive_entry_set_mode(entry, 0644 | 0100000); // Regular file
// Test matching
archive_match_path_excluded(match, entry);
archive_match_time_excluded(match, entry);
archive_match_owner_excluded(match, entry);
archive_match_excluded(match, entry);
archive_entry_free(entry);
}
archive_match_free(match);
return 0;
}

View File

@ -0,0 +1,61 @@
/*
* MTREE format fuzzer for libarchive
* Tests mtree manifest parsing
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_mtree(a);
archive_read_support_filter_all(a);
// Enable checkfs option to test more code paths
archive_read_set_options(a, "mtree:checkfs");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_uname(entry);
archive_entry_gname(entry);
archive_entry_symlink(entry);
archive_entry_fflags_text(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,47 @@
# MTREE format dictionary
# Keywords
"/set"
"/unset"
".."
# File types
"type=file"
"type=dir"
"type=link"
"type=block"
"type=char"
"type=fifo"
"type=socket"
# Attributes
"mode="
"uid="
"gid="
"uname="
"gname="
"size="
"time="
"link="
"cksum="
"md5="
"md5digest="
"sha1="
"sha1digest="
"sha256="
"sha256digest="
"sha384="
"sha384digest="
"sha512="
"sha512digest="
"rmd160="
"rmd160digest="
"flags="
"nlink="
"inode="
"device="
"resdevice="
"contents="
"optional"
"ignore"
"nochange"

View File

@ -0,0 +1,61 @@
/*
* RAR5 format specific fuzzer for libarchive
* Targets RAR5 parsing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable RAR5 format specifically
archive_read_support_format_rar5(a);
// Enable common filters
archive_read_support_filter_all(a);
// Set passphrase for encrypted archives
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,37 @@
# RAR5 format dictionary
# Magic bytes (RAR5 signature)
"Rar!\x1a\x07\x01\x00"
"\x52\x61\x72\x21\x1a\x07\x01\x00"
# Common header types
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
# Common flags
"\x00\x00"
"\x01\x00"
"\x02\x00"
"\x04\x00"
# Compression methods
"\x00"
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
# File attributes
"\x20\x00\x00\x00"
"\x10\x00\x00\x00"
# Encryption marker
"\x80"
"password"
"Password"
# End of archive
"\x1d\x77\x56\x51\x03\x05\x04\x00"

View File

@ -0,0 +1,56 @@
/*
* RAR v4 format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_rar(a);
archive_read_support_filter_all(a);
// Add passphrase for encrypted RARs
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,76 @@
/*
* Archive read disk fuzzer for libarchive
* Tests filesystem traversal and entry creation from paths
* Security-critical: path traversal, symlink handling
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 16 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *a = archive_read_disk_new();
if (a == NULL) {
return 0;
}
// Configure disk reader behavior
uint8_t flags = consumer.consume_byte();
if (flags & 0x01) {
archive_read_disk_set_symlink_logical(a);
} else if (flags & 0x02) {
archive_read_disk_set_symlink_physical(a);
} else {
archive_read_disk_set_symlink_hybrid(a);
}
archive_read_disk_set_standard_lookup(a);
// Set behavior flags
int behavior = 0;
if (flags & 0x04) behavior |= ARCHIVE_READDISK_RESTORE_ATIME;
if (flags & 0x08) behavior |= ARCHIVE_READDISK_HONOR_NODUMP;
if (flags & 0x10) behavior |= ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS;
archive_read_disk_set_behavior(a, behavior);
// Create an entry and test entry_from_file with various paths
struct archive_entry *entry = archive_entry_new();
if (entry) {
// Test with /tmp (safe, always exists)
archive_entry_copy_pathname(entry, "/tmp");
archive_read_disk_entry_from_file(a, entry, -1, NULL);
// Get entry info
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
// Test name lookups
archive_read_disk_gname(a, 0);
archive_read_disk_uname(a, 0);
archive_read_disk_gname(a, 1000);
archive_read_disk_uname(a, 1000);
archive_entry_free(entry);
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,110 @@
/*
* Archive roundtrip fuzzer for libarchive
* Writes an archive then reads it back - tests write/read consistency
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len < 10 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
std::vector<uint8_t> archive_data;
archive_data.reserve(len * 2);
// Phase 1: Write an archive
struct archive *writer = archive_write_new();
if (writer == NULL) {
return 0;
}
// Select format
uint8_t format = consumer.consume_byte() % 5;
switch (format) {
case 0: archive_write_set_format_pax_restricted(writer); break;
case 1: archive_write_set_format_ustar(writer); break;
case 2: archive_write_set_format_cpio_newc(writer); break;
case 3: archive_write_set_format_zip(writer); break;
default: archive_write_set_format_gnutar(writer); break;
}
archive_write_add_filter_none(writer);
// Open to memory
size_t used = 0;
archive_data.resize(len * 4);
if (archive_write_open_memory(writer, archive_data.data(), archive_data.size(), &used) != ARCHIVE_OK) {
archive_write_free(writer);
return 0;
}
// Write entries
int entry_count = 0;
while (!consumer.empty() && entry_count < 5 && consumer.remaining() > 10) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
archive_entry_set_pathname(entry, consumer.consume_string(32));
archive_entry_set_mode(entry, S_IFREG | 0644);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
uint8_t data_buf[256];
size_t data_len = consumer.consume_bytes(data_buf, 256);
archive_entry_set_size(entry, data_len);
if (archive_write_header(writer, entry) == ARCHIVE_OK && data_len > 0) {
archive_write_data(writer, data_buf, data_len);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(writer);
archive_write_free(writer);
if (used == 0) {
return 0;
}
// Phase 2: Read the archive back
struct archive *reader = archive_read_new();
if (reader == NULL) {
return 0;
}
archive_read_support_format_all(reader);
archive_read_support_filter_all(reader);
if (archive_read_open_memory(reader, archive_data.data(), used) != ARCHIVE_OK) {
archive_read_free(reader);
return 0;
}
std::vector<uint8_t> read_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(reader, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
ssize_t r;
while ((r = archive_read_data(reader, read_buffer.data(), read_buffer.size())) > 0)
;
}
archive_read_free(reader);
return 0;
}

View File

@ -0,0 +1,3 @@
[libfuzzer]
max_len = 65536
timeout = 30

View File

@ -0,0 +1,125 @@
/*
* Archive seek/read fuzzer for libarchive
* Tests seeking within archives and reading at random positions
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
struct SeekableBuffer {
const uint8_t *buf;
size_t len;
size_t pos;
};
static ssize_t seek_read_callback(struct archive *a, void *client_data,
const void **block) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
if (buffer->pos >= buffer->len) {
*block = NULL;
return 0;
}
*block = buffer->buf + buffer->pos;
size_t avail = buffer->len - buffer->pos;
size_t to_read = (avail > 4096) ? 4096 : avail;
buffer->pos += to_read;
return to_read;
}
static la_int64_t seek_callback(struct archive *a, void *client_data,
la_int64_t offset, int whence) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
la_int64_t new_pos;
switch (whence) {
case SEEK_SET:
new_pos = offset;
break;
case SEEK_CUR:
new_pos = static_cast<la_int64_t>(buffer->pos) + offset;
break;
case SEEK_END:
new_pos = static_cast<la_int64_t>(buffer->len) + offset;
break;
default:
return ARCHIVE_FATAL;
}
if (new_pos < 0) new_pos = 0;
if (new_pos > static_cast<la_int64_t>(buffer->len))
new_pos = static_cast<la_int64_t>(buffer->len);
buffer->pos = static_cast<size_t>(new_pos);
return new_pos;
}
static la_int64_t skip_callback(struct archive *a, void *client_data,
la_int64_t request) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
size_t avail = buffer->len - buffer->pos;
la_int64_t to_skip = (request > static_cast<la_int64_t>(avail))
? static_cast<la_int64_t>(avail)
: request;
buffer->pos += static_cast<size_t>(to_skip);
return to_skip;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable formats that benefit from seeking
archive_read_support_format_zip_seekable(a);
archive_read_support_format_7zip(a);
archive_read_support_format_rar(a);
archive_read_support_format_rar5(a);
archive_read_support_format_iso9660(a);
archive_read_support_filter_all(a);
SeekableBuffer buffer = {buf, len, 0};
archive_read_set_read_callback(a, seek_read_callback);
archive_read_set_seek_callback(a, seek_callback);
archive_read_set_skip_callback(a, skip_callback);
archive_read_set_callback_data(a, &buffer);
if (archive_read_open1(a) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
int entry_count = 0;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && entry_count < 50) {
archive_entry_pathname(entry);
archive_entry_size(entry);
// Read data which may trigger seeks
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
entry_count++;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,3 @@
[libfuzzer]
max_len = 262144
timeout = 30

View File

@ -0,0 +1,144 @@
/*
* Archive string/encoding conversion fuzzer for libarchive
* Tests character encoding conversions which are often vulnerability sources
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 32 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) {
return 0;
}
// Reserve some bytes for control
if (len < 4) {
archive_entry_free(entry);
return 0;
}
uint8_t test_type = buf[0];
const char *str = reinterpret_cast<const char*>(buf + 1);
size_t str_len = len - 1;
// Ensure null termination for string operations
char *safe_str = static_cast<char*>(malloc(str_len + 1));
if (safe_str == NULL) {
archive_entry_free(entry);
return 0;
}
memcpy(safe_str, str, str_len);
safe_str[str_len] = '\0';
// Test various string functions based on type
switch (test_type % 10) {
case 0:
// Pathname conversions
archive_entry_set_pathname(entry, safe_str);
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_pathname_utf8(entry);
break;
case 1:
// Symlink conversions
archive_entry_set_symlink(entry, safe_str);
archive_entry_symlink(entry);
archive_entry_symlink_w(entry);
archive_entry_symlink_utf8(entry);
break;
case 2:
// Hardlink conversions
archive_entry_set_hardlink(entry, safe_str);
archive_entry_hardlink(entry);
archive_entry_hardlink_w(entry);
archive_entry_hardlink_utf8(entry);
break;
case 3:
// Username conversions
archive_entry_set_uname(entry, safe_str);
archive_entry_uname(entry);
archive_entry_uname_w(entry);
archive_entry_uname_utf8(entry);
break;
case 4:
// Group name conversions
archive_entry_set_gname(entry, safe_str);
archive_entry_gname(entry);
archive_entry_gname_w(entry);
archive_entry_gname_utf8(entry);
break;
case 5:
// Copy functions
archive_entry_copy_pathname(entry, safe_str);
archive_entry_copy_symlink(entry, safe_str);
archive_entry_copy_hardlink(entry, safe_str);
break;
case 6:
// UTF-8 specific
archive_entry_update_pathname_utf8(entry, safe_str);
archive_entry_update_symlink_utf8(entry, safe_str);
archive_entry_update_hardlink_utf8(entry, safe_str);
break;
case 7:
// Fflags text
archive_entry_copy_fflags_text(entry, safe_str);
archive_entry_fflags_text(entry);
break;
case 8:
// ACL text parsing
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
break;
case 9: {
// Wide character operations
size_t wlen = str_len;
wchar_t *wstr = static_cast<wchar_t*>(malloc((wlen + 1) * sizeof(wchar_t)));
if (wstr) {
mbstowcs(wstr, safe_str, wlen);
wstr[wlen] = L'\0';
archive_entry_copy_pathname_w(entry, wstr);
archive_entry_pathname_w(entry);
archive_entry_copy_symlink_w(entry, wstr);
archive_entry_symlink_w(entry);
free(wstr);
}
break;
}
}
// Clone and compare
struct archive_entry *entry2 = archive_entry_clone(entry);
if (entry2) {
archive_entry_free(entry2);
}
free(safe_str);
archive_entry_free(entry);
return 0;
}

View File

@ -0,0 +1,86 @@
/*
* TAR format fuzzer for libarchive
* Tests all TAR variants: ustar, pax, gnutar, v7, oldgnu
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_tar(a);
archive_read_support_format_gnutar(a);
archive_read_support_filter_all(a);
// Enable various TAR options
archive_read_set_options(a, "tar:read_concatenated_archives,tar:mac-ext");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise all metadata accessors
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_atime(entry);
archive_entry_ctime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_uname(entry);
archive_entry_gname(entry);
archive_entry_symlink(entry);
archive_entry_hardlink(entry);
archive_entry_rdev(entry);
archive_entry_devmajor(entry);
archive_entry_devminor(entry);
// Test sparse file handling
archive_entry_sparse_reset(entry);
int64_t offset, length;
while (archive_entry_sparse_next(entry, &offset, &length) == ARCHIVE_OK) {
(void)offset;
(void)length;
}
// Test xattr handling
archive_entry_xattr_reset(entry);
const char *name;
const void *value;
size_t size;
while (archive_entry_xattr_next(entry, &name, &value, &size) == ARCHIVE_OK) {
(void)name;
(void)value;
(void)size;
}
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,51 @@
# TAR format dictionary
# USTAR magic
"ustar"
"ustar\x00"
"ustar \x00"
# GNU tar magic
"GNUtar "
"GNUtar\x00"
# Common header field values
"00000000000"
"0000644"
"0000755"
"0000777"
# Type flags
"0"
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"g"
"x"
"L"
"K"
# PAX keywords
"path="
"linkpath="
"uname="
"gname="
"uid="
"gid="
"size="
"mtime="
"atime="
"ctime="
"SCHILY.xattr."
"LIBARCHIVE.xattr."
# Sparse headers
"GNU.sparse.major="
"GNU.sparse.minor="
"GNU.sparse.name="
"GNU.sparse.realsize="
"GNU.sparse.map="

View File

@ -0,0 +1,50 @@
/*
* WARC (Web Archive) format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_warc(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,34 @@
# WARC format dictionary
# Version
"WARC/1.0"
"WARC/1.1"
"WARC/0.17"
"WARC/0.18"
# Record types
"warcinfo"
"response"
"resource"
"request"
"metadata"
"revisit"
"conversion"
"continuation"
# Headers
"WARC-Type:"
"WARC-Record-ID:"
"WARC-Date:"
"WARC-Target-URI:"
"Content-Length:"
"Content-Type:"
"WARC-Block-Digest:"
"WARC-Payload-Digest:"
"WARC-Concurrent-To:"
"WARC-Refers-To:"
# Content types
"application/warc-fields"
"application/http;msgtype=request"
"application/http;msgtype=response"

View File

@ -0,0 +1,125 @@
/*
* Archive write disk fuzzer for libarchive
* Tests extraction to filesystem
* Security-critical: path traversal, permission handling, symlink attacks
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024;
static char g_temp_dir[256] = {0};
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
(void)argc;
(void)argv;
// Create a temporary directory for extraction
snprintf(g_temp_dir, sizeof(g_temp_dir), "/tmp/fuzz_extract_XXXXXX");
if (mkdtemp(g_temp_dir) == NULL) {
g_temp_dir[0] = '\0';
}
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
if (g_temp_dir[0] == '\0') {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *disk = archive_write_disk_new();
if (disk == NULL) {
return 0;
}
// Configure write disk options
uint8_t opt_flags = consumer.consume_byte();
int flags = 0;
if (opt_flags & 0x01) flags |= ARCHIVE_EXTRACT_TIME;
if (opt_flags & 0x02) flags |= ARCHIVE_EXTRACT_PERM;
if (opt_flags & 0x04) flags |= ARCHIVE_EXTRACT_ACL;
if (opt_flags & 0x08) flags |= ARCHIVE_EXTRACT_FFLAGS;
if (opt_flags & 0x10) flags |= ARCHIVE_EXTRACT_OWNER;
if (opt_flags & 0x20) flags |= ARCHIVE_EXTRACT_XATTR;
if (opt_flags & 0x40) flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
if (opt_flags & 0x80) flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
archive_write_disk_set_options(disk, flags);
archive_write_disk_set_standard_lookup(disk);
// Create entries to extract
int entry_count = 0;
while (!consumer.empty() && entry_count < 5 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
// Build a safe path within our temp directory
char safe_path[512];
const char *name = consumer.consume_string(32);
snprintf(safe_path, sizeof(safe_path), "%s/%s", g_temp_dir, name);
// Sanitize path to prevent traversal
char *p = safe_path;
while (*p) {
if (p[0] == '.' && p[1] == '.') {
p[0] = '_';
p[1] = '_';
}
p++;
}
archive_entry_set_pathname(entry, safe_path);
uint8_t ftype = consumer.consume_byte() % 3;
mode_t mode;
switch (ftype) {
case 0: mode = S_IFREG | 0644; break;
case 1: mode = S_IFDIR | 0755; break;
default: mode = S_IFREG | 0644; break;
}
archive_entry_set_mode(entry, mode);
archive_entry_set_uid(entry, 1000);
archive_entry_set_gid(entry, 1000);
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
// Write the entry header
if (archive_write_header(disk, entry) == ARCHIVE_OK) {
if (S_ISREG(mode)) {
uint8_t data_buf[256];
size_t data_len = consumer.consume_bytes(data_buf, 256);
archive_entry_set_size(entry, data_len);
if (data_len > 0) {
archive_write_data(disk, data_buf, data_len);
}
}
archive_write_finish_entry(disk);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(disk);
archive_write_free(disk);
// Clean up extracted files using nftw (safer than system())
remove_directory_tree(g_temp_dir);
// Recreate the temp directory for next iteration
mkdir(g_temp_dir, 0700);
return 0;
}

View File

@ -0,0 +1,3 @@
[libfuzzer]
max_len = 65536
timeout = 30

View File

@ -0,0 +1,132 @@
/*
* Archive write fuzzer for libarchive
* Tests archive creation and writing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
// Simple data consumer
// Memory write callback
static std::vector<uint8_t> *g_output = nullptr;
static ssize_t write_callback(struct archive *a, void *client_data, const void *buffer, size_t length) {
(void)a;
(void)client_data;
if (g_output && length > 0) {
const uint8_t *buf = static_cast<const uint8_t*>(buffer);
g_output->insert(g_output->end(), buf, buf + length);
}
return length;
}
static int close_callback(struct archive *a, void *client_data) {
(void)a;
(void)client_data;
return ARCHIVE_OK;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
std::vector<uint8_t> output;
g_output = &output;
struct archive *a = archive_write_new();
if (a == NULL) {
return 0;
}
// Select format based on input
uint8_t format_choice = consumer.consume_byte() % 8;
switch (format_choice) {
case 0: archive_write_set_format_pax_restricted(a); break;
case 1: archive_write_set_format_gnutar(a); break;
case 2: archive_write_set_format_ustar(a); break;
case 3: archive_write_set_format_cpio_newc(a); break;
case 4: archive_write_set_format_zip(a); break;
case 5: archive_write_set_format_7zip(a); break;
case 6: archive_write_set_format_xar(a); break;
default: archive_write_set_format_pax(a); break;
}
// Select compression based on input
uint8_t filter_choice = consumer.consume_byte() % 6;
switch (filter_choice) {
case 0: archive_write_add_filter_gzip(a); break;
case 1: archive_write_add_filter_bzip2(a); break;
case 2: archive_write_add_filter_xz(a); break;
case 3: archive_write_add_filter_zstd(a); break;
case 4: archive_write_add_filter_none(a); break;
default: archive_write_add_filter_none(a); break;
}
// Open for writing to memory
if (archive_write_open(a, NULL, NULL, write_callback, close_callback) != ARCHIVE_OK) {
archive_write_free(a);
g_output = nullptr;
return 0;
}
// Create entries based on remaining input
int entry_count = 0;
while (!consumer.empty() && entry_count < 10 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
// Set entry properties
archive_entry_set_pathname(entry, consumer.consume_string(64));
uint8_t ftype = consumer.consume_byte() % 4;
mode_t mode;
switch (ftype) {
case 0: mode = S_IFREG | 0644; break;
case 1: mode = S_IFDIR | 0755; break;
case 2: mode = S_IFLNK | 0777; break;
default: mode = S_IFREG | 0644; break;
}
archive_entry_set_mode(entry, mode);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
// For regular files, write some data
if (S_ISREG(mode)) {
uint8_t data_buf[1024];
size_t data_len = consumer.consume_bytes(data_buf, 1024);
archive_entry_set_size(entry, data_len);
if (archive_write_header(a, entry) == ARCHIVE_OK && data_len > 0) {
archive_write_data(a, data_buf, data_len);
}
} else if (S_ISLNK(mode)) {
archive_entry_set_symlink(entry, consumer.consume_string(64));
archive_entry_set_size(entry, 0);
archive_write_header(a, entry);
} else {
archive_entry_set_size(entry, 0);
archive_write_header(a, entry);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(a);
archive_write_free(a);
g_output = nullptr;
return 0;
}

View File

@ -0,0 +1,60 @@
/*
* XAR format specific fuzzer for libarchive
* Targets xar_read_header and XAR parsing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable XAR format specifically
archive_read_support_format_xar(a);
// Enable common filters
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_filetype(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,44 @@
# XAR format dictionary
# Magic bytes
"xar!"
"\x78\x61\x72\x21"
# XML elements commonly in XAR
"<xar>"
"</xar>"
"<toc>"
"</toc>"
"<file>"
"</file>"
"<name>"
"</name>"
"<data>"
"</data>"
"<encoding>"
"</encoding>"
"<archived-checksum>"
"<extracted-checksum>"
"<offset>"
"<length>"
"<size>"
"<mode>"
"<uid>"
"<gid>"
"<user>"
"<group>"
"<type>"
"<mtime>"
"<atime>"
"<ctime>"
# Compression types
"application/octet-stream"
"application/x-gzip"
"application/x-bzip2"
"application/x-lzma"
# Checksum types
"sha1"
"md5"
"sha256"
"sha512"

View File

@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60

View File

@ -0,0 +1,68 @@
/*
* ZIP format fuzzer for libarchive
* Tests ZIP with various compression methods and encryption
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_zip(a);
archive_read_support_filter_all(a);
// Add passphrase for encrypted ZIPs
archive_read_add_passphrase(a, "password");
archive_read_add_passphrase(a, "test");
archive_read_add_passphrase(a, "");
// Enable ZIP options
archive_read_set_options(a, "zip:ignorecrc32");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
archive_entry_is_data_encrypted(entry);
archive_entry_is_metadata_encrypted(entry);
// Check compression name
archive_format_name(a);
archive_filter_name(a, 0);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}

View File

@ -0,0 +1,43 @@
# ZIP format dictionary
# Signatures
"PK\x03\x04"
"PK\x01\x02"
"PK\x05\x06"
"PK\x06\x06"
"PK\x06\x07"
"PK\x07\x08"
# Version needed
"\x14\x00"
"\x0a\x00"
"\x2d\x00"
"\x3f\x00"
# Compression methods
"\x00\x00"
"\x08\x00"
"\x09\x00"
"\x0c\x00"
"\x0e\x00"
"\x5f\x00"
# General purpose flags
"\x00\x00"
"\x01\x00"
"\x08\x00"
"\x09\x00"
# Extra field IDs
"\x01\x00"
"\x07\x00"
"\x09\x00"
"\x0a\x00"
"\x15\x00"
"\x17\x00"
"\x55\x54"
"\x75\x78"
# Encryption
"\x01\x99"
"\x02\x99"

View File

@ -1,16 +1,131 @@
# build the project
#!/bin/bash -eu
# Build the project
./build/autogen.sh
./configure
make -j$(nproc) all
# build seed
cp $SRC/libarchive/contrib/oss-fuzz/corpus.zip\
$OUT/libarchive_fuzzer_seed_corpus.zip
FUZZ_DIR=$SRC/libarchive/contrib/oss-fuzz
TEST_DIR=$SRC/libarchive/libarchive/test
# build fuzzer(s)
$CXX $CXXFLAGS -Ilibarchive \
$SRC/libarchive/contrib/oss-fuzz/libarchive_fuzzer.cc \
-o $OUT/libarchive_fuzzer $LIB_FUZZING_ENGINE \
.libs/libarchive.a -Wl,-Bstatic -lbz2 -llzo2 \
-lxml2 -llzma -lz -lcrypto -llz4 -licuuc \
-licudata -Wl,-Bdynamic
# Common libraries for linking
LIBS=".libs/libarchive.a -Wl,-Bstatic -lbz2 -llzo2 -lxml2 -llzma -lz -lcrypto -llz4 -licuuc -licudata -Wl,-Bdynamic"
# Function to build a fuzzer
build_fuzzer() {
local name=$1
local source=$2
echo "Building fuzzer: $name"
$CXX $CXXFLAGS -Ilibarchive \
"$source" \
-o "$OUT/$name" $LIB_FUZZING_ENGINE $LIBS
}
# Build all format-specific fuzzers
FUZZERS=(
"libarchive_fuzzer"
"libarchive_tar_fuzzer"
"libarchive_zip_fuzzer"
"libarchive_7zip_fuzzer"
"libarchive_rar_fuzzer"
"libarchive_rar5_fuzzer"
"libarchive_xar_fuzzer"
"libarchive_cab_fuzzer"
"libarchive_lha_fuzzer"
"libarchive_iso9660_fuzzer"
"libarchive_cpio_fuzzer"
"libarchive_warc_fuzzer"
"libarchive_mtree_fuzzer"
"libarchive_ar_fuzzer"
"libarchive_filter_fuzzer"
"libarchive_entry_fuzzer"
"libarchive_write_fuzzer"
"libarchive_linkify_fuzzer"
"libarchive_match_fuzzer"
"libarchive_encryption_fuzzer"
"libarchive_read_disk_fuzzer"
"libarchive_write_disk_fuzzer"
"libarchive_seek_fuzzer"
"libarchive_string_fuzzer"
"libarchive_roundtrip_fuzzer"
)
for fuzzer in "${FUZZERS[@]}"; do
if [ -f "$FUZZ_DIR/${fuzzer}.cc" ]; then
build_fuzzer "$fuzzer" "$FUZZ_DIR/${fuzzer}.cc"
fi
done
# Copy dictionaries and options
cp "$FUZZ_DIR"/*.dict "$OUT/" 2>/dev/null || true
cp "$FUZZ_DIR"/*.options "$OUT/" 2>/dev/null || true
# Build seed corpora
echo "Building seed corpora..."
# Main fuzzer corpus (existing)
cp "$FUZZ_DIR/corpus.zip" "$OUT/libarchive_fuzzer_seed_corpus.zip"
# Function to create corpus from test files
create_corpus() {
local name=$1
local pattern=$2
local dir="/tmp/${name}_corpus"
mkdir -p "$dir"
for f in $TEST_DIR/$pattern; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "$dir/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A $dir 2>/dev/null)" ]; then
zip -j "$OUT/${name}_seed_corpus.zip" "$dir"/* 2>/dev/null || true
echo "Created corpus for $name with $(ls $dir | wc -l) files"
fi
rm -rf "$dir"
}
# Create format-specific corpora
create_corpus "libarchive_tar_fuzzer" "test_compat_*tar*.uu"
create_corpus "libarchive_zip_fuzzer" "test_*zip*.uu"
create_corpus "libarchive_7zip_fuzzer" "test_read_format_7zip*.uu"
create_corpus "libarchive_rar_fuzzer" "test_read_format_rar_*.uu"
create_corpus "libarchive_rar5_fuzzer" "test_read_format_rar5*.uu"
create_corpus "libarchive_xar_fuzzer" "test_read_format_xar*.uu"
create_corpus "libarchive_cab_fuzzer" "test_read_format_cab*.uu"
create_corpus "libarchive_lha_fuzzer" "test_read_format_lha*.uu"
create_corpus "libarchive_iso9660_fuzzer" "test_read_format_iso*.uu"
create_corpus "libarchive_cpio_fuzzer" "test_compat_cpio*.uu"
create_corpus "libarchive_warc_fuzzer" "test_read_format_warc*.uu"
create_corpus "libarchive_mtree_fuzzer" "test_read_format_mtree*.uu"
create_corpus "libarchive_ar_fuzzer" "test_read_format_ar*.uu"
# Filter corpus - use compressed test files
mkdir -p /tmp/filter_corpus
for f in $TEST_DIR/*.gz.uu $TEST_DIR/*.bz2.uu $TEST_DIR/*.xz.uu $TEST_DIR/*.lz4.uu $TEST_DIR/*.zst.uu $TEST_DIR/*.Z.uu; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "/tmp/filter_corpus/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A /tmp/filter_corpus 2>/dev/null)" ]; then
zip -j "$OUT/libarchive_filter_fuzzer_seed_corpus.zip" /tmp/filter_corpus/* 2>/dev/null || true
fi
rm -rf /tmp/filter_corpus
# Encryption corpus - encrypted archives
mkdir -p /tmp/encryption_corpus
for f in $TEST_DIR/*encrypt*.uu $TEST_DIR/*password*.uu; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "/tmp/encryption_corpus/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A /tmp/encryption_corpus 2>/dev/null)" ]; then
zip -j "$OUT/libarchive_encryption_fuzzer_seed_corpus.zip" /tmp/encryption_corpus/* 2>/dev/null || true
fi
rm -rf /tmp/encryption_corpus
echo "Build complete! Built ${#FUZZERS[@]} fuzzers."

View File

@ -13,8 +13,8 @@ IF(ENABLE_CPIO)
cpio.c
cpio.h
cpio_platform.h
../libarchive_fe/err.c
../libarchive_fe/err.h
../libarchive_fe/lafe_err.c
../libarchive_fe/lafe_err.h
../libarchive_fe/lafe_platform.h
../libarchive_fe/line_reader.c
../libarchive_fe/line_reader.h

View File

@ -26,7 +26,7 @@
#endif
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
/*
* Short options for cpio. Please keep this sorted.

View File

@ -60,7 +60,7 @@
#endif
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
#include "line_reader.h"
#include "passphrase.h"
@ -124,13 +124,21 @@ main(int argc, char *argv[])
cpio->buff_size = sizeof(buff);
#if defined(HAVE_SIGACTION) && defined(SIGPIPE)
{ /* Ignore SIGPIPE signals. */
#if defined(HAVE_SIGACTION)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
#ifdef SIGPIPE
/* Ignore SIGPIPE signals. */
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
#endif
#ifdef SIGCHLD
/* Do not ignore SIGCHLD. */
sa.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &sa, NULL);
#endif
}
#endif
@ -717,7 +725,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
if (cpio->uid_override >= 0)
archive_entry_set_uid(entry, cpio->uid_override);
if (cpio->gname_override != NULL)
if (cpio->uname_override != NULL)
archive_entry_set_uname(entry, cpio->uname_override);
if (cpio->gid_override >= 0)
archive_entry_set_gid(entry, cpio->gid_override);

View File

@ -24,7 +24,7 @@
#include <sddl.h>
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
#define EPOC_TIME (116444736000000000ULL)

View File

@ -9,7 +9,7 @@
IF(ENABLE_CPIO AND ENABLE_TEST)
SET(bsdcpio_test_SOURCES
../cmdline.c
../../libarchive_fe/err.c
../../libarchive_fe/lafe_err.c
../../test_utils/test_utils.c
../../test_utils/test_main.c
test.h

View File

@ -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

View File

@ -52,7 +52,7 @@ test_create(void)
* #ifdef this section out. Most of the test below is
* still valid. */
memset(&times, 0, sizeof(times));
#if defined(_WIN32) && !defined(CYGWIN)
#if defined(_WIN32) && !defined(__CYGWIN__)
times.actime = 86400;
times.modtime = 86400;
#else

View File

@ -7,7 +7,7 @@
#include "test.h"
#include "../cpio.h"
#include "err.h"
#include "lafe_err.h"
#if !defined(_WIN32)
#define ROOT "root"

View File

@ -52,6 +52,7 @@ SET(libarchive_SOURCES
archive_pathmatch.h
archive_platform.h
archive_platform_acl.h
archive_platform_stat.h
archive_platform_xattr.h
archive_ppmd_private.h
archive_ppmd8.c
@ -248,11 +249,14 @@ IF(BUILD_SHARED_LIBS)
ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .)
TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
SET_TARGET_PROPERTIES(archive PROPERTIES
SET_TARGET_PROPERTIES(archive PROPERTIES
VERSION ${SOVERSION_FULL}
SOVERSION ${SOVERSION}
MACHO_COMPATIBILITY_VERSION ${MACHO_COMPATIBILITY_VERSION}
MACHO_CURRENT_VERSION ${MACHO_CURRENT_VERSION})
IF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT)
SET_PROPERTY(TARGET archive PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
ENDIF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT)
ENDIF(BUILD_SHARED_LIBS)
# archive_static is a static library
@ -261,6 +265,9 @@ TARGET_INCLUDE_DIRECTORIES(archive_static PUBLIC .)
TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS})
SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS
LIBARCHIVE_STATIC)
IF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT)
SET_PROPERTY(TARGET archive_static PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
ENDIF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT)
# On Posix systems, libarchive.so and libarchive.a can co-exist.
IF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS)
SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive)
@ -271,13 +278,13 @@ IF(ENABLE_INSTALL)
IF(BUILD_SHARED_LIBS)
INSTALL(TARGETS archive
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
ENDIF(BUILD_SHARED_LIBS)
INSTALL(TARGETS archive_static
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL_MAN(${libarchive_MANS})
INSTALL(FILES ${include_HEADERS} DESTINATION include)
ENDIF()

View File

@ -34,7 +34,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3008000
#define ARCHIVE_VERSION_NUMBER 3009000
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@ -177,7 +177,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_ONLY_STRING "3.8.0dev"
#define ARCHIVE_VERSION_ONLY_STRING "3.9.0dev"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@ -210,7 +210,9 @@ __LA_DECL const char * archive_openssl_version(void);
__LA_DECL const char * archive_libmd_version(void);
__LA_DECL const char * archive_commoncrypto_version(void);
__LA_DECL const char * archive_cng_version(void);
#if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL const char * archive_wincrypt_version(void);
#endif
__LA_DECL const char * archive_librichacl_version(void);
__LA_DECL const char * archive_libacl_version(void);
__LA_DECL const char * archive_libattr_version(void);
@ -1250,8 +1252,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
}

View File

@ -270,6 +270,19 @@ acl_new_entry(struct archive_acl *acl,
{
struct archive_acl_entry *ap, *aq;
/* Reject an invalid type */
switch (type) {
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
break;
default:
return (NULL);
}
/* Type argument must be a valid NFS4 or POSIX.1e type.
* The type must agree with anything already set and
* the permset must be compatible. */
@ -822,6 +835,9 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
wname = NULL;
id = -1;
break;
default:
**wp = '\0';
break;
}
*wp += wcslen(*wp);
*(*wp)++ = L':';
@ -878,6 +894,7 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
wcscpy(*wp, L"alarm");
break;
default:
*(*wp) = L'\0';
break;
}
*wp += wcslen(*wp);
@ -1057,6 +1074,9 @@ append_entry(char **p, const char *prefix, int type,
name = NULL;
id = -1;
break;
default:
**p = '\0';
break;
}
*p += strlen(*p);
*(*p)++ = ':';
@ -1112,6 +1132,9 @@ append_entry(char **p, const char *prefix, int type,
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
strcpy(*p, "alarm");
break;
default:
*(*p) = '\0';
break;
}
*p += strlen(*p);
}

View File

@ -30,6 +30,7 @@
#endif
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@ -54,8 +55,14 @@ errmsg(const char *m)
while (s > 0) {
written = write(2, m, s);
if (written <= 0)
if (written == 0)
return;
if (written < 0)
{
if (errno == EINTR)
continue;
return;
}
m += written;
s -= written;
}

View File

@ -57,7 +57,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
return 0;
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#ifdef _MSC_VER
#pragma comment(lib, "Bcrypt.lib")
#endif
@ -151,7 +151,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
(void)rounds; /* UNUSED */
(void)derived_key; /* UNUSED */
(void)derived_key_len; /* UNUSED */
return -1; /* UNSUPPORTED */
return CRYPTOR_STUB_FUNCTION; /* UNSUPPORTED */
}
#endif
@ -197,7 +197,7 @@ aes_ctr_release(archive_crypto_ctx *ctx)
return 0;
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
static int
aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
@ -439,14 +439,14 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
(void)ctx; /* UNUSED */
(void)key; /* UNUSED */
(void)key_len; /* UNUSED */
return -1;
return CRYPTOR_STUB_FUNCTION;
}
static int
aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
{
(void)ctx; /* UNUSED */
return -1;
return CRYPTOR_STUB_FUNCTION;
}
static int
@ -469,7 +469,7 @@ aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,
(void)out; /* UNUSED */
(void)out_len; /* UNUSED */
aes_ctr_encrypt_counter(ctx); /* UNUSED */ /* Fix unused function warning */
return -1;
return CRYPTOR_STUB_FUNCTION;
}
#else
@ -490,9 +490,9 @@ aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,
size_t in_len, uint8_t * const out, size_t *out_len)
{
uint8_t *const ebuf = ctx->encr_buf;
unsigned pos = ctx->encr_pos;
unsigned max = (unsigned)((in_len < *out_len)? in_len: *out_len);
unsigned i;
size_t pos = ctx->encr_pos;
size_t max = (in_len < *out_len)? in_len: *out_len;
size_t i;
for (i = 0; i < max; ) {
if (pos == AES_BLOCK_SIZE) {

View File

@ -43,7 +43,7 @@ int __libarchive_cryptor_build_hack(void);
#ifdef __APPLE__
# include <AvailabilityMacros.h>
# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto 1
# endif
#endif
@ -56,13 +56,13 @@ int __libarchive_cryptor_build_hack(void);
typedef struct {
CCCryptorRef ctx;
uint8_t key[AES_MAX_KEY_SIZE];
unsigned key_len;
size_t key_len;
uint8_t nonce[AES_BLOCK_SIZE];
uint8_t encr_buf[AES_BLOCK_SIZE];
unsigned encr_pos;
size_t encr_pos;
} archive_crypto_ctx;
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
#define ARCHIVE_CRYPTOR_USE_CNG 1
@ -168,6 +168,9 @@ typedef int archive_crypto_ctx;
#define archive_encrypto_aes_ctr_release(ctx) \
__archive_cryptor.encrypto_aes_ctr_release(ctx)
/* Stub return value if no encryption support exists. */
#define CRYPTOR_STUB_FUNCTION -2
/* Minimal interface to cryptographic functionality for internal use in
* libarchive */
struct archive_cryptor

View File

@ -44,16 +44,11 @@
/*
* Message digest functions for Windows platform.
*/
#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#if defined(HAVE_BCRYPT_H)
/*
* Initialize a Message digest.
*/
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
static int
win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
{
@ -72,30 +67,6 @@ win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
ctx->valid = 1;
return (ARCHIVE_OK);
}
#else
static int
win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
{
ctx->valid = 0;
if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
prov, CRYPT_VERIFYCONTEXT)) {
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
return (ARCHIVE_FAILED);
if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
prov, CRYPT_NEWKEYSET))
return (ARCHIVE_FAILED);
}
if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
CryptReleaseContext(ctx->cryptProv, 0);
return (ARCHIVE_FAILED);
}
ctx->valid = 1;
return (ARCHIVE_OK);
}
#endif
/*
* Update a Message digest.
@ -107,42 +78,26 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
if (!ctx->valid)
return (ARCHIVE_FAILED);
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
BCryptHashData(ctx->hHash,
(PUCHAR)(uintptr_t)buf,
(ULONG)len, 0);
#else
CryptHashData(ctx->hash,
(unsigned char *)(uintptr_t)buf,
(DWORD)len, 0);
#endif
return (ARCHIVE_OK);
}
static int
win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
{
#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
DWORD siglen = (DWORD)bufsize;
#endif
if (!ctx->valid)
return (ARCHIVE_FAILED);
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0);
BCryptDestroyHash(ctx->hHash);
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
#else
CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
CryptDestroyHash(ctx->hash);
CryptReleaseContext(ctx->cryptProv, 0);
#endif
ctx->valid = 0;
return (ARCHIVE_OK);
}
#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
#endif /* defined(HAVE_BCRYPT_H) */
/* MD5 implementations */
@ -234,11 +189,7 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
#endif
}
static int
@ -645,11 +596,7 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
#endif
}
static int
@ -925,11 +872,7 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
#endif
}
static int
@ -1177,11 +1120,7 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
#endif
}
static int
@ -1453,11 +1392,7 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
#endif
}
static int

View File

@ -165,8 +165,7 @@
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
/* don't use bcrypt when XP needs to be supported */
#if defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
#define ARCHIVE_CRYPTO_CNG 1
typedef struct {
@ -174,15 +173,6 @@ typedef struct {
BCRYPT_ALG_HANDLE hAlg;
BCRYPT_HASH_HANDLE hHash;
} Digest_CTX;
#else
#include <windows.h>
#include <wincrypt.h>
#define ARCHIVE_CRYPTO_WINCRYPT 1
typedef struct {
int valid;
HCRYPTPROV cryptProv;
HCRYPTHASH hash;
} Digest_CTX;
#endif
#endif

View File

@ -124,7 +124,6 @@ static void
add_trivial_nfs4_acl(struct archive_entry *entry)
{
mode_t mode;
int i;
const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
ARCHIVE_ENTRY_ACL_APPEND_DATA;
@ -195,7 +194,7 @@ add_trivial_nfs4_acl(struct archive_entry *entry)
} else if ((mode & 0010) || (mode & 0001))
tacl_entry[1].permset |= eperm;
for (i = 0; i < sizeof(tacl_entry) / sizeof(tacl_entry[0]); i++) {
for (size_t i = 0; i < sizeof(tacl_entry) / sizeof(tacl_entry[0]); i++) {
if (tacl_entry[i].permset != 0) {
archive_entry_acl_add_entry(entry,
tacl_entry[i].type, tacl_entry[i].permset,

View File

@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3008000
#define ARCHIVE_VERSION_NUMBER 3009000
/*
* Note: archive_entry.h is for use outside of libarchive; the

View File

@ -64,7 +64,7 @@ Streaming Archive Library (libarchive, -larchive)
.Ft void
.Fn archive_entry_copy_hardlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_hardlink_w "struct archive_entry *a "const wchar_t *path"
.Fn archive_entry_copy_hardlink_w "struct archive_entry *a" "const wchar_t *path"
.Ft int
.Fn archive_entry_update_hardlink_utf8 "struct archive_entry *a" "const char *path"
.Ft void

View File

@ -207,7 +207,7 @@ for setting is recommended.
The function
.Fn archive_entry_size
returns the file size, if it has been set, and 0 otherwise.
.Fn archive_entry_size
.Fn archive_entry_size_is_set
can be used to query that status.
.Fn archive_entry_set_size
and

View File

@ -38,6 +38,7 @@
const struct stat *
archive_entry_stat(struct archive_entry *entry)
{
int64_t size;
struct stat *st;
if (entry->stat == NULL) {
entry->stat = calloc(1, sizeof(*st));
@ -74,7 +75,10 @@ archive_entry_stat(struct archive_entry *entry)
st->st_ino = (ino_t)archive_entry_ino64(entry);
st->st_nlink = archive_entry_nlink(entry);
st->st_rdev = archive_entry_rdev(entry);
st->st_size = (off_t)archive_entry_size(entry);
size = archive_entry_size(entry);
st->st_size = (off_t)size;
if (st->st_size < 0 || (int64_t)st->st_size != size)
st->st_size = 0;
st->st_mode = archive_entry_mode(entry);
/*

View File

@ -74,7 +74,7 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#ifndef BCRYPT_HASH_REUSABLE_FLAG
# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020

View File

@ -52,7 +52,7 @@ int __libarchive_hmac_build_hack(void);
typedef CCHmacContext archive_hmac_sha1_ctx;
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
typedef struct {

View File

@ -35,6 +35,9 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include "archive.h"
#include "archive_private.h"
@ -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 *);
@ -189,12 +193,12 @@ static int validate_time_flag(struct archive *, int, const char *);
#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++;
}
@ -1275,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)
@ -1291,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)
{
@ -1303,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)
@ -1320,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)
{
@ -1332,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
@ -1359,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
@ -1382,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);
@ -1392,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);
@ -1517,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);
@ -1682,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;
@ -1719,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)
@ -1817,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));
@ -1831,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));

View File

@ -703,9 +703,7 @@ Convert(time_t Month, time_t Day, time_t Year,
Year += 1900;
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
? 29 : 28;
/* Checking for 2038 bogusly assumes that time_t is 32 bits. But
I'm too lazy to try to check for time_t overflow in another way. */
if (Year < EPOCH || Year >= 2038
if (Year < EPOCH || (sizeof(time_t) <= 4 && Year >= 2038)
|| Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month]

View File

@ -183,16 +183,6 @@
#define CAN_RESTORE_METADATA_FD
#endif
/*
* glibc 2.24 deprecates readdir_r
* bionic c deprecates readdir_r too
*/
#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) && (!defined(__ANDROID__))
#define USE_READDIR_R 1
#else
#undef USE_READDIR_R
#endif
/* Set up defaults for internal error codes. */
#ifndef ARCHIVE_ERRNO_FILE_FORMAT
#if HAVE_EFTYPE

Some files were not shown because too many files have changed in this diff Show More