Several archive writers duplicate identical hdrcharset option handling.
Share the validation and conversion logic across the affected cpio, tar,
and zip writers.
This reduces duplication without changing behavior.
Use difftime() instead of changing time_t values by the half-year
range. This avoids signed overflow near the time_t limits without
changing normal output.
Use difftime() instead of subtracting time_t values when choosing the
date format. This avoids signed overflow for far past or future
timestamps without changing normal output.
Store the program filter description in the bidder state instead of the
active filter state.
The active state is freed by archive_read_close(), while the bidder state
remains valid until archive_read_free(). This keeps archive_filter_name()
from returning a dangling pointer.
Check reserved fields by comparing adjacent bytes after confirming the
first byte is zero. This preserves the memcmp fast path and removes
2 KiB from each ISO9660 reader state.
Use memcpy() for path components whose lengths are already known and
write the terminating null byte explicitly.
Cache the inserted component length instead of calculating it multiple
times while constructing the ustar pathname.
Replace the single-use basename helper with strrchr() and preserve the
existing rejection of pathnames ending in a slash.
Cache the member filename length to avoid repeated strlen() calls while
building and writing the archive header.
Continue searching after each replaced backslash instead of restarting
from the beginning of the filename.
This avoids repeatedly scanning the already converted prefix.
Check the allocation used to initialize cur_dirstr before accessing the
buffer.
Release the partially initialized strings, root entry, file registry,
and hardlink registry before returning ARCHIVE_FATAL.
Copy the old GNU tar header before reading sparse extension blocks.
Those reads may replace or free the callback buffer backing the original
header. Use the copy when parsing the common header fields.
Calculate the pathname length directly after validating the path.
The helper only wrapped strlen() and adjusted the length for directory
entries. Removing it keeps the calculation beside the validation and
reuses the existing file type value.
Add a test archive that reuses one read buffer for every 512-byte block.
Reading the sparse extension overwrites the main GNU header. Check that
mode, uid, gid, and mtime still come from the original header.
Format integer values directly at each call site and remove the custom
integer formatter.
This handles the full signed integer range and preserves unsigned byte
counters.
Clear format state and callbacks after running the previous format
destructor so a failed replacement setup cannot leave stale pointers.
Also unregister previous GNU tar state and require ARCHIVE_STATE_NEW
before switching to GNU tar.
Test that unregistering 7-Zip and XAR clears format state and is safe
to repeat.
Also test switching from 7-Zip to GNU tar and selecting GNU tar again.
AppleDouble detection only needs to inspect the final path component for
the "._" prefix.
Check the multibyte pathname first on all platforms and only fall back to
WCS when the multibyte pathname is unavailable. This avoids unnecessary
wide-character pathname conversion for ordinary tar entries when mac-ext
handling is enabled.
Entries without an available pathname now return no match instead of
ARCHIVE_FAILED from the boolean check.
Use a more specific error when resource header generation fails.
The old message said `cannot archive file`, but this path fails when
the generated WARC resource header exceeds the internal limit.
Check generated WARC header creation and writes.
Fail when the generated warcinfo header cannot be built. Treat a
resource header build failure as fatal because output may already exist.
Propagate write errors instead of marking the record as written.
Add memory-writer tests for generated WARC header write failures.
Cover both the warcinfo header and a resource header with warcinfo
disabled. These tests show that header write failures are hidden.
The uu filter can keep a partial encoded line in its internal input
buffer, then reach upstream EOF with no new bytes available. In that
case, d is NULL and avail_in is zero, but the buffered-input path still
passes d to memcpy() before processing the saved bytes.
Skip the append copy when avail_in is zero so the saved input is handled
without passing a null source pointer to memcpy().
Reject resource records when less data was written than Content-Length.
Do not append the WARC end marker after a short entry. Return fatal
because the record body has already been started.
This avoids writing a record whose length does not match its body.
Add a writer test for a resource entry shorter than Content-Length.
The test closes after a short write and checks for a fatal error. It
documents that the end marker must not hide a short body.
Rewrite WARC reader comments to use clearer wording and match the
style used by other libarchive format readers.
Keep the change comment-only while preserving existing behavior.
Cache the CPIO trailer-name check before consuming the pathname
buffer.
The reader kept a pointer returned by __archive_read_ahead() and used
it after __archive_read_consume(), and after possible symlink body
processing. Read-ahead pointers are views into libarchive input buffers
and should not be relied on after the associated bytes are consumed.
Store the TRAILER!!! decision while the pathname buffer is still valid,
then use the saved boolean after the remaining header handling.
Parse Content-Length only up to the located end-of-line instead of
passing a bounded header field to strtol(). Use int64_t for the parsed
entry size, ASCII digit checks, and checked arithmetic while accumulating
the value.
iso9660_options() checks the second byte of the iso-level option value
before checking that the first byte contains a valid ISO level.
For an empty option value such as iso9660:iso-level=,
archive_write_set_options() passes a value pointer to the terminating NUL
byte of the duplicated options string. Reading value[1] then reads one byte
past that heap allocation.
Check value[0] before reading value[1]. This keeps the same accepted values
while rejecting the empty value without reading past the option buffer.
The GNU sparse name builder trims trailing slash and /. components before
building the synthetic ustar entry name. If the sparse pathname is fully
pruned, the effective source length becomes zero and build_ustar_entry_name()
reads one byte before the pathname buffer.
Handle the all-pruned pathname case before calling the ustar name builder.
The synthetic name then preserves the root-directory case.
The -s replacement scanner consumes a backslash and then reads the
escaped byte. If the replacement ends in one literal backslash, the loop
can advance past the terminating NUL and read one byte past the
allocated replacement buffer.
Stop scanning when a backslash is followed by the terminating NUL. The
final literal append then preserves the trailing backslash.
The seekable ZIP reader checks whether __MACOSX/ entries are resource
fork entries by testing the basename prefix.
The existing guard used r - name, which is the basename offset from the
start of the filename, not the basename length. For a short basename such
as "__MACOSX/.", this could read one byte past the filename.
Check the remaining basename length before reading the resource fork prefix.
Consume pending data before EOF and skip handling.
Then skip only the unread body bytes plus the WARC record separator.
This keeps the reader at the correct input position after an entry has
been partially or fully read.
read_children() checked the directory record length byte before ensuring
that the record pointer was still inside the current logical block.
If directory records exactly filled the final block, the next loop
condition could read one byte past the image buffer.
Check the remaining block length before reading the record length byte.
tar_atol_base_n() read the next byte before checking whether any bytes
remained. If a numeric field ended at the caller-provided boundary, this
caused a 1-byte OOB read while preparing the next digit range check.
Read each digit only while bytes remain.
header_pax_extension() passes PAX attribute values without the trailing
newline to pax_attribute(). The SUN.holesdata parser read one byte past
the supplied value when the last numeric field ended at the value
boundary.
Handle length == 0 before checking *e.
Add a test that extracts data from the first WARC resource record, then
moves to the second header.
This checks the bug where already-read entry data was not handled correctly
before skip handling.
Read the fixed metadata prefix of the PKWARE Unix extra field 0x000d.
The fixed portion contains atime, mtime, uid, and gid values. Require
the full 12-byte prefix before reading it, and leave the variable-length
data field unsupported for now.
Add a test for the PKWARE Unix extra field 0x000d.
The fixture stores a regular file with the 12-byte fixed metadata
prefix in both the local header and central directory. The test checks
that the ZIP reader exposes mtime, atime, uid, and gid metadata for
seekable and streaming reads.
WARC records require a known Content-Length. Reject regular file
entries without a valid size instead of treating them as zero.
Avoid casting archive_entry_size() through size_t before storing it in
the uint64_t WARC Content-Length field, since that can truncate large
sizes on 32-bit platforms.
archive_write_pax_header() set hardlink entries to size zero for the
restricted pax format, then immediately set all hardlink entries to size
zero again.
Remove the narrower check because it is fully subsumed by the following
hardlink check.
No functional change intended.
header_common() parsed the tar mode field once when setting the file
type and again when setting permissions. Cache the parsed value and reuse
it for both setters.
archive_entry_set_filetype() and archive_entry_set_perm() already mask
the relevant bits, so passing the full header mode preserves behavior.
The permission-set guard is unchanged.
No functional change intended.
ArchiveProperties entries have a property ID, a size, and payload.
The reader parsed the ID and size, but did not consume the payload.
Payload bytes could then be read as the next property ID, which
misaligned the rest of header parsing.
Skip the payload in chunks so parsing stays aligned with 7-Zip/7zz.
Add a 7z test archive with a non-empty ArchiveProperties payload.
The archive has one empty file and an ArchiveProperties entry with a
1-byte payload. It is accepted by 7-Zip/7zz.
This covers parsing when ArchiveProperties has payload bytes.
Avoid adding the encryption overhead directly to entry sizes when deciding
whether Zip64 is needed or when updating the stored compressed size.
For the Zip64 decision, compare against ZIP_4GB_MAX - additional_size. For
stored encrypted entries, use archive_ckd_add_i64() so the size update and
overflow check happen together.
Avoid allocating and filling metadata bitmaps when the 7z header says
that every file has the corresponding value.
Sparse metadata still uses the existing bitmap path.
Flatten nested allAreDefined checks for attribute and timestamp bools.
Also initialize empty-stream entries as directories by default before
applying the optional EmptyFile bitmap.
No archive behavior change is intended.
Both supported BCJ2 layout branches store the chosen unpack size in
remaining.
main_stream_bytes_remaining is set from remaining immediately after
the branch, so the earlier assignments are redundant.
The SFX scanner missed a valid 7-Zip header when exactly 32 bytes
remained in the lookahead buffer.
The ELF SFX path also missed ".data" when it was at the last valid
position in the section string table. It also allowed e_shstrndx to be
equal to e_shnum, even though that is one past the section table.
Tighten these checks so valid edge cases are handled correctly.
Add PE and ELF SFX fixtures for the SFX scanner boundary cases.
The PE fixture places an empty 7z archive at the final exact
32-byte scan window. The ELF fixture places ".data\0" at the final
valid section string-table position.
Register the fixtures for autotools distcheck.
Several ISO tests used a bz2 suffix even though they read .Z files
and verify ARCHIVE_FILTER_COMPRESS. Rename them to use a compress
suffix so the test names match the filter.
The write option setter checks used several tiny source files with the
same basic shape.
Keep the same DEFINE_TEST cases. Put the write-side option setter
checks in test_archive_write_set_options.c. Remove the extra source
files from the build lists.
The read option setter checks used several tiny source files with the
same basic shape.
Keep the same DEFINE_TEST cases. Put the read-side option setter
checks in test_archive_read_set_options.c. Remove the extra source
files from the build lists.
The close-twice read checks used three tiny source files.
Keep the same DEFINE_TEST cases. Put the fresh-object, fd-backed,
and filename-backed checks in one source file. Remove the two extra
files from the build lists.
Several filename encoding tests were copied from KOI8-R or EUC-JP
cases, but now use CP1251 or CP932/SJIS instead.
Update skip messages, conversion messages, and comments to match the
locales and byte sequences used by the tests.
Also fix a typo in an EUC-JP ZIP filename skip message.
For empty-prefix ustar entries, copy the fixed-width name field
directly into the archive entry instead of first building a temporary
archive_string.
This avoids a temporary buffer allocation and intermediate copy in the
common case. It also fixes a small fatal-error leak by freeing the
temporary prefix/name buffer before returning on pathname conversion
failure.
Validate the accumulated unpack stream count before allocating
per-substream metadata.
Reject folders that declare multiple substreams without kSize metadata,
since the parser needs those sizes to describe the stream layout.
Drop the explicit digest zeroing loop. The arrays are allocated with
calloc(), so the entries are already initialized.
Add a 7z regression test for malformed SubStreamsInfo metadata that
declares more than one unpack stream without the kSize data needed to
describe those streams.
Store the archive as a .7z.uu file, matching the existing malformed
7z tests.
Avoid passing negative suffix offsets to the duplicate identifier
resolver. Clamp them where ISO9660 and Joliet identifiers decide
where the duplicate suffix should be written.
Add a test for ISO9660 entries whose Joliet identifiers collide
after default identifier truncation. The writer should resolve
the duplicate identifiers successfully when the archive is closed.
Reject malformed CPIO entries whose pathname field exceeds 1 MiB before asking the read-ahead layer to satisfy the padded pathname length.
This prevents newc archives with attacker-controlled c_namesize values from forcing large metadata read-ahead and pathname allocation during archive listing. Add a regression test that fails on the unpatched reader and passes once the cap is enforced.
Signed-off-by: datauwu <datauwu@users.noreply.github.com>