Merge pull request #2998 from kientzle/archive-read-sticky-fatal
archive_read: FATAL should be sticky for all API calls
(cherry picked from commit e01eeb274d)
This commit is contained in:
1 parent
2df65d402d
commit
c2edc8d181
22 files changed
+334
-166
No files matched your search
@@ -374,6 +374,38 @@ MACRO (GENERATE_LIST_H _listfile _cmlist _target __list_sources)
|
||||
# Attaching list.h to the target tells CMake to build it before compiling.
|
||||
TARGET_SOURCES(${_target} PRIVATE "${_listfile}")
|
||||
ENDMACRO (GENERATE_LIST_H)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
MACRO(DISCOVER_TESTS _component __list_sources)
|
||||
IF(ENABLE_TEST)
|
||||
SET(_sources ${ARGV})
|
||||
LIST(REMOVE_AT _sources 0)
|
||||
FOREACH(_src ${_sources})
|
||||
IF(_src MATCHES "test_[^/]+\\.c$")
|
||||
FILE(STRINGS "${_src}" _lines REGEX "^DEFINE_TEST\(.*\)")
|
||||
FOREACH(_line ${_lines})
|
||||
STRING(REGEX MATCH "DEFINE_TEST\((.*)\)" _full_match ${_line})
|
||||
# CMake REGEX seems to handle ( and \( rather inconsistently...
|
||||
# So we go through an extra dance to definitively strip the parens
|
||||
STRING(REPLACE "(" "" _test_name_with_paren "${CMAKE_MATCH_1}")
|
||||
STRING(REPLACE ")" "" _test_name "${_test_name_with_paren}")
|
||||
SET(_full_test_name "${_component}_${_test_name}")
|
||||
MESSAGE("Found test ${_full_test_name} command ${_component}_test")
|
||||
ADD_TEST(NAME ${_full_test_name}
|
||||
COMMAND ${_component}_test -vv
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_test_name})
|
||||
SET_TESTS_PROPERTIES(${_full_test_name} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
endforeach()
|
||||
ENDIF(ENABLE_TEST)
|
||||
ENDMACRO(DISCOVER_TESTS __sources)
|
||||
|
||||
#
|
||||
# Generate installation rules for man pages.
|
||||
#
|
||||
|
||||
+3
-1
@@ -18,7 +18,7 @@ BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/
|
||||
#
|
||||
check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs)
|
||||
TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs)
|
||||
TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) $(bsdunzip_TESTS_ENVIRONMENT)
|
||||
TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) $(bsdunzip_TESTS_ENVIRONMENT) _VERBOSITY_LEVEL=2
|
||||
# Always build and test both bsdtar and bsdcpio as part of 'distcheck'
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio
|
||||
# The next line is commented out by default in shipping libarchive releases.
|
||||
@@ -543,7 +543,9 @@ libarchive_test_SOURCES= \
|
||||
libarchive/test/test_read_format_rar_invalid1.c \
|
||||
libarchive/test/test_read_format_rar_overflow.c \
|
||||
libarchive/test/test_read_format_rar5.c \
|
||||
libarchive/test/test_read_format_rar5_bad_filter.c \
|
||||
libarchive/test/test_read_format_rar5_bad_tables.c \
|
||||
libarchive/test/test_read_format_rar5_block_hdr_fail_loop.c \
|
||||
libarchive/test/test_read_format_rar5_loop_bug.c \
|
||||
libarchive/test/test_read_format_raw.c \
|
||||
libarchive/test/test_read_format_tar.c \
|
||||
|
||||
+2
-15
@@ -3,7 +3,7 @@
|
||||
#
|
||||
############################################
|
||||
#
|
||||
# How to build bsdtar_test
|
||||
# How to build bsdcat_test
|
||||
#
|
||||
############################################
|
||||
IF(ENABLE_CAT AND ENABLE_TEST)
|
||||
@@ -55,21 +55,8 @@ IF(ENABLE_CAT AND ENABLE_TEST)
|
||||
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# list.h has a line DEFINE_TEST(testname) for every
|
||||
# test. We can use that to define the tests for cmake by
|
||||
# defining a DEFINE_TEST macro and reading list.h in.
|
||||
MACRO (DEFINE_TEST _testname)
|
||||
ADD_TEST(
|
||||
NAME bsdcat_${_testname}
|
||||
COMMAND bsdcat_test -vv
|
||||
-p $<TARGET_FILE:bsdcat>
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_testname})
|
||||
SET_TESTS_PROPERTIES(bsdcat_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDMACRO (DEFINE_TEST _testname)
|
||||
DISCOVER_TESTS(bsdcat ${bsdcat_test_SOURCES})
|
||||
|
||||
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h OPTIONAL)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cat/test)
|
||||
|
||||
@@ -88,21 +88,8 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
|
||||
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# list.h has a line DEFINE_TEST(testname) for every
|
||||
# test. We can use that to define the tests for cmake by
|
||||
# defining a DEFINE_TEST macro and reading list.h in.
|
||||
MACRO (DEFINE_TEST _testname)
|
||||
ADD_TEST(
|
||||
NAME bsdcpio_${_testname}
|
||||
COMMAND bsdcpio_test -vv
|
||||
-p $<TARGET_FILE:bsdcpio>
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_testname})
|
||||
SET_TESTS_PROPERTIES(bsdcpio_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDMACRO (DEFINE_TEST _testname)
|
||||
DISCOVER_TESTS(bsdcpio ${bsdcpio_test_SOURCES})
|
||||
|
||||
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h OPTIONAL)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cpio/test)
|
||||
|
||||
@@ -934,7 +934,10 @@ archive_read_data_skip(struct archive *_a)
|
||||
if (r == ARCHIVE_EOF)
|
||||
r = ARCHIVE_OK;
|
||||
|
||||
a->archive.state = ARCHIVE_STATE_HEADER;
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
else
|
||||
a->archive.state = ARCHIVE_STATE_HEADER;
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -942,6 +945,8 @@ la_int64_t
|
||||
archive_seek_data(struct archive *_a, int64_t offset, int whence)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
la_int64_t r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
"archive_seek_data_block");
|
||||
|
||||
@@ -949,10 +954,14 @@ archive_seek_data(struct archive *_a, int64_t offset, int whence)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: "
|
||||
"No format_seek_data_block function registered");
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
return (a->format->seek_data)(a, offset, whence);
|
||||
r = (a->format->seek_data)(a, offset, whence);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -968,6 +977,8 @@ _archive_read_data_block(struct archive *_a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
"archive_read_data_block");
|
||||
|
||||
@@ -975,10 +986,14 @@ _archive_read_data_block(struct archive *_a,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: "
|
||||
"No format->read_data function registered");
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
return (a->format->read_data)(a, buff, size, offset);
|
||||
r = (a->format->read_data)(a, buff, size, offset);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -1196,8 +1196,19 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
|
||||
* compressed data much more quickly.
|
||||
*/
|
||||
bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
|
||||
/*
|
||||
* TODO: when archive_read_data() fails on an encrypted entry with
|
||||
* ARCHIVE_FAILED, the implicit skip from the next
|
||||
* archive_read_next_header() lands here. Empirically, skip_stream()
|
||||
* still returns ARCHIVE_FATAL via extract_pack_stream() on its second
|
||||
* call (after setup_decode_folder() returned ARCHIVE_FAILED on the
|
||||
* first), so the FAILED-from-data / FATAL-from-skip asymmetry persists.
|
||||
* Audit extract_pack_stream() / read_stream() to see whether the second
|
||||
* call should also surface ARCHIVE_FAILED so the caller can move on
|
||||
* to entries in subsequent folders.
|
||||
*/
|
||||
if (bytes_skipped < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
return ((int)bytes_skipped);
|
||||
zip->entry_bytes_remaining = 0;
|
||||
|
||||
/* This entry is finished and done. */
|
||||
@@ -3699,7 +3710,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
|
||||
r = setup_decode_folder(a,
|
||||
&(zip->si.ci.folders[zip->folder_index]), 0);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (r);
|
||||
|
||||
zip->folder_index++;
|
||||
}
|
||||
@@ -3794,7 +3805,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"The %s is encrypted, "
|
||||
"but currently not supported", cname);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
|
||||
}
|
||||
case _7Z_X86_BCJ2: {
|
||||
found_bcj2++;
|
||||
@@ -3814,7 +3825,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"The %s is encoded with many filters, "
|
||||
"but currently not supported", cname);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1142,7 +1142,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported compression method for RAR file");
|
||||
ret = ARCHIVE_FATAL;
|
||||
ret = ARCHIVE_FAILED;
|
||||
break;
|
||||
}
|
||||
return (ret);
|
||||
@@ -2026,7 +2026,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"File CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
#endif
|
||||
}
|
||||
rar->entry_eof = 1;
|
||||
@@ -2038,7 +2038,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
*size = bytes_avail;
|
||||
@@ -2058,7 +2058,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
int64_t *offset, size_t looper)
|
||||
{
|
||||
if (looper++ > MAX_COMPRESS_DEPTH)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
struct rar *rar;
|
||||
int64_t start, end;
|
||||
@@ -2069,7 +2069,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
|
||||
do {
|
||||
if (!rar->valid)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
if (rar->filters.bytes_ready > 0)
|
||||
{
|
||||
@@ -2121,7 +2121,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"File CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
#endif
|
||||
}
|
||||
rar->entry_eof = 1;
|
||||
@@ -2155,7 +2155,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
if (rar->filters.lastend == rar->filters.filterstart)
|
||||
{
|
||||
if (!run_filters(a))
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2172,7 +2172,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if(sym != rar->ppmd_escape)
|
||||
{
|
||||
@@ -2186,7 +2186,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
switch(code)
|
||||
@@ -2213,7 +2213,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_offset |= code << (i * 8);
|
||||
}
|
||||
@@ -2222,7 +2222,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_emit_match(rar, lzss_offset + 2, length + 32);
|
||||
rar->bytes_uncopied += length + 32;
|
||||
@@ -2234,7 +2234,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_emit_match(rar, 1, length + 4);
|
||||
rar->bytes_uncopied += length + 4;
|
||||
@@ -2280,7 +2280,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
* what we would do to solve it. */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Internal error extracting RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
}
|
||||
if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
|
||||
@@ -2363,7 +2363,7 @@ parse_codes(struct archive_read *a)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Make sure ppmd7_context is freed before Ppmd7_Construct
|
||||
@@ -2379,7 +2379,7 @@ parse_codes(struct archive_read *a)
|
||||
if (rar->dictionary_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid zero dictionary size");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
|
||||
@@ -2393,7 +2393,7 @@ parse_codes(struct archive_read *a)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to initialize PPMd range decoder");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
__archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
|
||||
rar->ppmd_valid = 1;
|
||||
@@ -2403,13 +2403,13 @@ parse_codes(struct archive_read *a)
|
||||
if (!rar->ppmd_valid) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid PPMd sequence");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to initialize PPMd range decoder");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2459,7 +2459,7 @@ parse_codes(struct archive_read *a)
|
||||
if ((val = read_next_symbol(a, &precode)) < 0) {
|
||||
free(precode.tree);
|
||||
free(precode.table);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (val < 16)
|
||||
{
|
||||
@@ -2474,7 +2474,7 @@ parse_codes(struct archive_read *a)
|
||||
free(precode.table);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Internal error extracting RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if(val == 16) {
|
||||
@@ -2564,7 +2564,7 @@ parse_codes(struct archive_read *a)
|
||||
if (new_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Zero window size is invalid");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
new_window = realloc(rar->lzss.window, new_size);
|
||||
if (new_window == NULL) {
|
||||
@@ -2584,7 +2584,7 @@ truncated_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
rar->valid = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2700,7 +2700,7 @@ create_code(struct archive_read *a, struct huffman_code *code,
|
||||
{
|
||||
if (lengths[j] != i) continue;
|
||||
if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
codebits++;
|
||||
if (--symbolsleft <= 0)
|
||||
break;
|
||||
@@ -2752,7 +2752,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Prefix found");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2811,7 +2811,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Prefix found");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Set leaf value */
|
||||
@@ -2865,13 +2865,13 @@ make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Huffman tree was not created");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (node < 0 || node >= code->numentries)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid location to Huffman tree specified");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
currtablesize = 1 << (maxdepth - depth);
|
||||
@@ -3134,11 +3134,11 @@ truncated_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
rar->valid = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
bad_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3153,12 +3153,12 @@ copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,
|
||||
if (length > lzss_size(&rar->lzss)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (firstpart < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (firstpart < length) {
|
||||
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
|
||||
@@ -3200,7 +3200,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
if (firstpart < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if ((size_t)firstpart < length) {
|
||||
memcpy(&rar->unp_buffer[rar->unp_offset],
|
||||
@@ -3224,7 +3224,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
fatal:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
||||
@@ -700,7 +700,7 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported filter type: 0x%x",
|
||||
(unsigned int)flt->type);
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(ret != ARCHIVE_OK) {
|
||||
@@ -2757,7 +2757,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated data in huffman tables");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
value = (p[i] & nibble_mask) >> nibble_shift;
|
||||
@@ -2803,7 +2803,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Decoding huffman tables failed");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
for(i = 0; i < HUFF_TABLE_SIZE;) {
|
||||
@@ -2814,7 +2814,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Decoding huffman tables failed");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(num < 16) {
|
||||
@@ -2848,7 +2848,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unexpected error when decoding "
|
||||
"huffman tables");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
} else {
|
||||
/* other codes: fill with zeroes `n` times */
|
||||
@@ -2876,7 +2876,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create literal table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_NC;
|
||||
@@ -2885,7 +2885,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create distance table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_DC;
|
||||
@@ -2894,7 +2894,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create lower bits of distances table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_LDC;
|
||||
@@ -2903,7 +2903,7 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create repeating distances table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -2921,7 +2921,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported block header size (was %d, max is 2)",
|
||||
bf_byte_count(hdr));
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
/* This should probably use bit reader interface in order to be more
|
||||
@@ -2965,7 +2965,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
"Block checksum error: got 0x%x, expected 0x%x",
|
||||
hdr->block_cksum, calculated_cksum);
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3046,20 +3046,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
filter_type >>= 13;
|
||||
skip_bits(rar, 3);
|
||||
|
||||
/* Perform some sanity checks on this filter parameters. Note that we
|
||||
* allow only DELTA, E8/E9 and ARM filters here, because rest of
|
||||
* filters are not used in RARv5. */
|
||||
/* Perform some sanity checks on this filter parameters. */
|
||||
|
||||
if(block_length < 4 ||
|
||||
block_length > 0x400000 ||
|
||||
filter_type > FILTER_ARM ||
|
||||
!is_valid_filter_block_start(rar, block_start) ||
|
||||
(rar->cstate.window_size > 0 &&
|
||||
(ssize_t)block_length > rar->cstate.window_size >> 1))
|
||||
{
|
||||
archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid filter encountered");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
/* Allocate a new filter. */
|
||||
@@ -3212,7 +3209,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Failed to decode the code length");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,
|
||||
@@ -3222,7 +3219,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Failed to decode the distance slot");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(dist_slot < 4) {
|
||||
@@ -3267,7 +3264,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
"Failed to decode the "
|
||||
"distance slot");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(dist >= INT_MAX - low_dist - 1) {
|
||||
@@ -3277,7 +3274,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Distance pointer "
|
||||
"overflow");
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
dist += low_dist;
|
||||
@@ -3312,7 +3309,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
rar->cstate.last_len = len;
|
||||
|
||||
if(ARCHIVE_OK != copy_string(a, len, dist))
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
|
||||
continue;
|
||||
} else if(num == 256) {
|
||||
@@ -3328,7 +3325,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
rar->cstate.last_len,
|
||||
rar->cstate.dist_cache[0]))
|
||||
{
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3343,18 +3340,18 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
|
||||
if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,
|
||||
&len_slot)) {
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
len = decode_code_length(a, rar, p, len_slot);
|
||||
if (len == -1) {
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
rar->cstate.last_len = len;
|
||||
|
||||
if(ARCHIVE_OK != copy_string(a, len, dist))
|
||||
return ARCHIVE_FATAL;
|
||||
return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -3516,6 +3513,7 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
if(!rar->vol.push_buf) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for a merge block buffer");
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -3534,14 +3532,19 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
block_size - partial_offset);
|
||||
|
||||
if(cur_block_size == 0) {
|
||||
/* bytes_remaining is 0 at the wrong point in the merge
|
||||
* loop, indicating corrupt volume accounting. */
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Encountered block size == 0 during block merge");
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(!read_ahead(a, cur_block_size, &lp))
|
||||
if(!read_ahead(a, cur_block_size, &lp)) {
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
/* Sanity check; there should never be a situation where this
|
||||
* function reads more data than the block's size. */
|
||||
@@ -3549,6 +3552,7 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Consumed too much data when merging blocks");
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -3558,8 +3562,12 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
memcpy(&rar->vol.push_buf[partial_offset], lp, cur_block_size);
|
||||
|
||||
/* Advance the stream read pointer by this block chunk size. */
|
||||
if(ARCHIVE_OK != consume(a, cur_block_size))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != consume(a, cur_block_size)) {
|
||||
/* Data was copied but stream pointer didn't advance;
|
||||
* stream position is unrecoverable. */
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* Update the pointers. `partial_offset` contains information
|
||||
* about the sum of merged block chunks. */
|
||||
@@ -3580,6 +3588,7 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
ret = advance_multivolume(a);
|
||||
rar->merge_mode--;
|
||||
if(ret != ARCHIVE_OK) {
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -3885,7 +3894,7 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
"Invalid window size declaration in this file");
|
||||
|
||||
/* This should never happen in valid files. */
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(rar->cstate.all_filters_applied == 1) {
|
||||
@@ -3896,7 +3905,7 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
* files). */
|
||||
while(1) {
|
||||
ret = process_block(a);
|
||||
if(ret == ARCHIVE_EOF || ret == ARCHIVE_FATAL)
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
if(rar->cstate.last_write_ptr ==
|
||||
@@ -3922,12 +3931,10 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
ret = apply_filters(a);
|
||||
if(ret == ARCHIVE_RETRY) {
|
||||
return ARCHIVE_OK;
|
||||
} else if(ret == ARCHIVE_FATAL) {
|
||||
return ARCHIVE_FATAL;
|
||||
} else if(ret != ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If apply_filters() will return ARCHIVE_OK, we can continue here. */
|
||||
|
||||
if(cdeque_size(&rar->cstate.filters) > 0) {
|
||||
/* Check if we can write something before hitting first
|
||||
* filter. */
|
||||
@@ -4140,7 +4147,7 @@ static int verify_checksums(struct archive_read* a) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Checksum error: CRC32");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_CODE {
|
||||
@@ -4175,7 +4182,7 @@ static int verify_checksums(struct archive_read* a) {
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Checksum error: BLAKE2");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -4216,7 +4223,7 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
if (rar->headers_are_encrypted || rar->cstate.data_encrypted) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Reading encrypted data is not currently supported");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(rar->file.dir > 0) {
|
||||
|
||||
@@ -177,7 +177,9 @@ IF(ENABLE_TEST)
|
||||
test_read_format_rar_filter.c
|
||||
test_read_format_rar_overflow.c
|
||||
test_read_format_rar5.c
|
||||
test_read_format_rar5_bad_filter.c
|
||||
test_read_format_rar5_bad_tables.c
|
||||
test_read_format_rar5_block_hdr_fail_loop.c
|
||||
test_read_format_rar5_loop_bug.c
|
||||
test_read_format_raw.c
|
||||
test_read_format_tar.c
|
||||
@@ -351,20 +353,8 @@ IF(ENABLE_TEST)
|
||||
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# list.h has a line DEFINE_TEST(testname) for every
|
||||
# test. We can use that to define the tests for cmake by
|
||||
# defining a DEFINE_TEST macro and reading list.h in.
|
||||
MACRO (DEFINE_TEST _testname)
|
||||
ADD_TEST(
|
||||
NAME libarchive_${_testname}
|
||||
COMMAND libarchive_test -vv
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_testname})
|
||||
SET_TESTS_PROPERTIES(libarchive_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDMACRO (DEFINE_TEST _testname)
|
||||
DISCOVER_TESTS(libarchive ${libarchive_test_SOURCES})
|
||||
|
||||
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h OPTIONAL)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/libarchive/test)
|
||||
|
||||
@@ -51,7 +51,7 @@ DEFINE_TEST(test_read_format_7zip_encryption_data)
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
assertEqualInt(1, archive_file_count(a));
|
||||
|
||||
|
||||
@@ -63,12 +63,12 @@ DEFINE_TEST(test_read_format_7zip_encryption_partially)
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
assertEqualInt(2, archive_file_count(a));
|
||||
|
||||
/* End of archive. */
|
||||
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
|
||||
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
|
||||
}
|
||||
|
||||
/* Verify archive format. */
|
||||
|
||||
@@ -1452,7 +1452,7 @@ DEFINE_TEST(test_read_format_rar5_only_crypt_exfld)
|
||||
during data extraction. */
|
||||
|
||||
assertA(archive_read_next_header(a, &ae) == ARCHIVE_OK);
|
||||
assertA(archive_read_data(a, buf, sizeof(buf)) == ARCHIVE_FATAL);
|
||||
assertA(archive_read_data(a, buf, sizeof(buf)) == ARCHIVE_FAILED);
|
||||
|
||||
/* The reader should also provide a valid error message. */
|
||||
assertA(archive_error_string(a) != NULL);
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*-
|
||||
* Copyright (c) 2025 Tim Kientzle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
* Two-entry RAR5 archive. Entry 1 ("bad.txt") is compressed with a filter
|
||||
* of unsupported type 4 (FILTER_AUDIO). Entry 2 ("ok.txt") is stored.
|
||||
*
|
||||
* Tests that an unsupported filter type in do_uncompress_file returns
|
||||
* ARCHIVE_FAILED (not ARCHIVE_FATAL), so the archive is not aborted and
|
||||
* the second entry is still readable.
|
||||
*
|
||||
* RAR5 outer block format: 4-byte LE CRC32 of (vint(hdr_size)+hdr_body),
|
||||
* then vint(hdr_size), then hdr_body, then optional data area.
|
||||
* Integers are vint: 7 bits per byte, LSB first, high bit = more follows.
|
||||
*/
|
||||
DEFINE_TEST(test_read_format_rar5_bad_filter)
|
||||
{
|
||||
static const uint8_t data[] = {
|
||||
/* RAR5 signature */
|
||||
0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00,
|
||||
|
||||
/* Main archive header block (type=1):
|
||||
* CRC32, vint(body_size=3), type=1, block_flags=0,
|
||||
* archive_flags=0 */
|
||||
0xC5, 0x1A, 0x33, 0x32, 0x03, 0x01, 0x00, 0x00,
|
||||
|
||||
/* File header block for "bad.txt" (type=2, HFL_DATA flag set):
|
||||
* CRC32, vint(body_size=17), type=2, HFL_DATA,
|
||||
* packed_size=23, file_flags=0, unpacked_size=4,
|
||||
* file_attr=0, compression_info=512 (method=GOOD,
|
||||
* version=0, window_factor=0), host_os=1,
|
||||
* name_len=7, "bad.txt" */
|
||||
0x88, 0xEC, 0xB0, 0x99, 0x11, 0x02, 0x02, 0x17,
|
||||
0x00, 0x04, 0x00, 0x80, 0x04, 0x01, 0x07, 0x62,
|
||||
0x61, 0x64, 0x2E, 0x74, 0x78, 0x74,
|
||||
|
||||
/* Compressed data block for "bad.txt" (23 bytes):
|
||||
*
|
||||
* Compressed block header (3 bytes):
|
||||
* block_flags=0xC2: is_table_present, is_last_block,
|
||||
* bf_bit_size=2 (block ends when
|
||||
* in_addr==last_byte && bit_addr>=3)
|
||||
* checksum=0x8C, block_size=20 */
|
||||
0xC2, 0x8C, 0x14,
|
||||
|
||||
/* Huffman meta-table (20 nibbles packed in 10 bytes):
|
||||
* nibble[2]=1, nibble[19]=1, all others 0.
|
||||
* Two 1-bit meta-symbols:
|
||||
* code 0 -> sym 2 (store bit-length 2 for next entry)
|
||||
* code 1 -> sym 19 (fill N+11 zeros, N in next 7 bits) */
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01,
|
||||
|
||||
/* Huffman main table + compressed data (MSB-first bitstream):
|
||||
*
|
||||
* Main table (ld[], 430 entries, 42 bits total):
|
||||
* skip 97 zeros (sym19, n=86), ld[97]=2 (sym2, 'a'),
|
||||
* skip 138 zeros, skip 20 zeros,
|
||||
* ld[256]=2 (sym2, filter token), skip 138+35 zeros.
|
||||
* Canonical codes: 00->sym97('a'), 01->sym256(filter).
|
||||
*
|
||||
* Compressed data (33 bits):
|
||||
* 01 filter token (sym 256)
|
||||
* 00,00000000 block_start: count=0->1 byte, value=0
|
||||
* 00,00000100 block_length: count=0->1 byte, value=4
|
||||
* 100 filter_type=4 (FILTER_AUDIO, unsupported;
|
||||
* top 3 bits of a 16-bit read, 3 bits consumed)
|
||||
* 00,00,00,00 four 'a' literals (sym 97, code 00 each) */
|
||||
0xD6, 0x7F, 0xC4, 0xBF, 0xE6, 0x10, 0x00, 0x04,
|
||||
0x80, 0x00,
|
||||
|
||||
/* File header block for "ok.txt" (type=2, HFL_DATA flag set):
|
||||
* CRC32, vint(body_size=15), type=2, HFL_DATA,
|
||||
* packed_size=3, file_flags=0, unpacked_size=3,
|
||||
* file_attr=0, compression_info=0 (STORE),
|
||||
* host_os=1, name_len=6, "ok.txt", data "ok\n" */
|
||||
0xB1, 0xC3, 0x30, 0x14, 0x0F, 0x02, 0x02, 0x03,
|
||||
0x00, 0x03, 0x00, 0x00, 0x01, 0x06, 0x6F, 0x6B,
|
||||
0x2E, 0x74, 0x78, 0x74, 0x6F, 0x6B, 0x0A,
|
||||
|
||||
/* End of archive block (type=5):
|
||||
* CRC32, vint(body_size=2), type=5, block_flags=0 */
|
||||
0x39, 0xF9, 0xB2, 0x81, 0x02, 0x05, 0x00,
|
||||
};
|
||||
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
char buf[256];
|
||||
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_rar5(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_open_memory(a, data, sizeof(data)));
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
assertEqualString("bad.txt", archive_entry_pathname(ae));
|
||||
assertA(archive_read_data(a, buf, sizeof(buf)) < 0);
|
||||
assertA(archive_error_string(a) != NULL &&
|
||||
strstr(archive_error_string(a), "Unsupported filter type") != NULL);
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
assertEqualString("ok.txt", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, 3, archive_read_data(a, buf, sizeof(buf)));
|
||||
assertEqualMem(buf, "ok\n", 3);
|
||||
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
@@ -50,12 +50,8 @@ DEFINE_TEST(test_read_format_rar5_bad_tables)
|
||||
/* The file header is valid; the bad data is in the compressed block. */
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
|
||||
/* Reading must fail because the meta-table is over-subscribed.
|
||||
* TODO: Investigate whether ARCHIVE_FAILED is achievable here
|
||||
* instead of ARCHIVE_FATAL, which would allow the caller to skip
|
||||
* to a subsequent valid entry. That would also require expanding
|
||||
* the reference archive to include a valid entry after the bad one. */
|
||||
assertEqualIntA(a, ARCHIVE_FATAL,
|
||||
/* Reading must fail because the meta-table is over-subscribed. */
|
||||
assertEqualIntA(a, ARCHIVE_FAILED,
|
||||
archive_read_data_block(a, &buf, &size, &offset));
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
* Regression test for infinite loop when parse_block_header() returns
|
||||
* ARCHIVE_FAILED inside do_uncompress_file()'s while(1) loop.
|
||||
*
|
||||
* The loop only exited on ARCHIVE_EOF or ARCHIVE_FATAL. After converting
|
||||
* per-entry block header errors from ARCHIVE_FATAL to ARCHIVE_FAILED, a
|
||||
* malformed block header caused the loop to spin forever.
|
||||
*
|
||||
* Fuzzer-generated reproducer (37 bytes).
|
||||
*/
|
||||
DEFINE_TEST(test_read_format_rar5_block_hdr_fail_loop)
|
||||
{
|
||||
/* RAR5 archive with a malformed compressed block header */
|
||||
static const uint8_t data[] = {
|
||||
0x52,0x61,0x72,0x21,0x1a,0x07,0x01,0x00,
|
||||
0x86,0x7e,0xfa,0xe7,0x03,0x02,0x56,0x20,
|
||||
0x00,0x20,0x15,0xae,0x21,0x00,0x01,0x08,
|
||||
0x00,0x00,0x01,0x00,0x00,0x15,0x00,0xbe,
|
||||
0xc0,0x80,0x00,0xff,0xf4
|
||||
};
|
||||
|
||||
struct archive *a = archive_read_new();
|
||||
assert(a != NULL);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_rar5(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a,
|
||||
data, sizeof(data)));
|
||||
|
||||
struct archive_entry *ae;
|
||||
char buf[4096];
|
||||
while (archive_read_next_header(a, &ae) == ARCHIVE_OK)
|
||||
while (archive_read_data(a, buf, sizeof(buf)) > 0)
|
||||
;
|
||||
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
@@ -47,7 +47,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
|
||||
|
||||
/* We should only ever fail to read the data for "a.txt" and "c.txt" if they are encrypted */
|
||||
/* NOTE: We'll never attempt this when filenames are encrypted, so we only check for solid here */
|
||||
expected_read_data_result = solid ? ARCHIVE_FATAL : expected_file_size;
|
||||
expected_read_data_result = solid ? ARCHIVE_FAILED : expected_file_size;
|
||||
|
||||
extract_reference_file(filename);
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
@@ -96,7 +96,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualInt(1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
/* Read the header for "c.txt" */
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
@@ -120,7 +120,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualInt(1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
/* End of archive. */
|
||||
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
|
||||
|
||||
@@ -50,7 +50,7 @@ DEFINE_TEST(test_read_format_rar_encryption_data)
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
/* Verify encrypted file "bar.txt" */
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
@@ -60,7 +60,7 @@ DEFINE_TEST(test_read_format_rar_encryption_data)
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
assertEqualInt(2, archive_file_count(a));
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ DEFINE_TEST(test_read_format_rar_encryption_partially)
|
||||
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
|
||||
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
|
||||
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
|
||||
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
|
||||
assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
|
||||
|
||||
/* Verify unencrypted file "bar.txt". */
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
|
||||
@@ -37,7 +37,7 @@ DEFINE_TEST(test_read_format_rar_invalid1)
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, 99));
|
||||
assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, 99));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
@@ -41,7 +41,7 @@ DEFINE_TEST(test_read_format_rar_overflow)
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
|
||||
assertEqualInt(48, archive_entry_size(ae));
|
||||
/* The next call should reproduce Issue #2565 */
|
||||
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data_block(a, &buff, &size, &offset));
|
||||
assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data_block(a, &buff, &size, &offset));
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
|
||||
+1
-14
@@ -109,21 +109,8 @@ IF(ENABLE_TAR AND ENABLE_TEST)
|
||||
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# list.h has a line DEFINE_TEST(testname) for every
|
||||
# test. We can use that to define the tests for cmake by
|
||||
# defining a DEFINE_TEST macro and reading list.h in.
|
||||
MACRO (DEFINE_TEST _testname)
|
||||
ADD_TEST(
|
||||
NAME bsdtar_${_testname}
|
||||
COMMAND bsdtar_test -vv
|
||||
-p $<TARGET_FILE:bsdtar>
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_testname})
|
||||
SET_TESTS_PROPERTIES(bsdtar_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDMACRO (DEFINE_TEST _testname)
|
||||
DISCOVER_TESTS(bsdtar ${bsdtar_test_SOURCES})
|
||||
|
||||
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h OPTIONAL)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tar/test)
|
||||
|
||||
@@ -56,21 +56,8 @@ IF(ENABLE_UNZIP AND ENABLE_TEST)
|
||||
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# list.h has a line DEFINE_TEST(testname) for every
|
||||
# test. We can use that to define the tests for cmake by
|
||||
# defining a DEFINE_TEST macro and reading list.h in.
|
||||
MACRO (DEFINE_TEST _testname)
|
||||
ADD_TEST(
|
||||
NAME bsdunzip_${_testname}
|
||||
COMMAND bsdunzip_test -vv
|
||||
-p $<TARGET_FILE:bsdunzip>
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_testname})
|
||||
SET_TESTS_PROPERTIES(bsdunzip_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDMACRO (DEFINE_TEST _testname)
|
||||
DISCOVER_TESTS(bsdunzip ${bsdunzip_test_SOURCES})
|
||||
|
||||
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h OPTIONAL)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/unzip/test)
|
||||
|
||||
Reference in new issue
Block a user