diff --git a/src/rar_extract.c b/src/rar_extract.c index 76986a2..c6a1e4f 100644 --- a/src/rar_extract.c +++ b/src/rar_extract.c @@ -660,6 +660,21 @@ scan_archive(HANDLE hArc, rarx_ctx_t *c) { break; } + /* Multi-volume: a file spanning volumes is presented as several header + segments with the SAME name. Segments after the first carry + RHDF_SPLITBEFORE; they must drive the engine forward (SKIP) but must + not be counted, deduped or size-accumulated again. The first segment + already carries the full file size. */ + if(hdr.Flags & RHDF_SPLITBEFORE) { + rc = RARProcessFile(hArc, RAR_SKIP, NULL, NULL); + if(rc != ERAR_SUCCESS && rc != ERAR_END_ARCHIVE) { + ret = -1; + rar_translate_error(rc, hdr.FileName, c); + break; + } + continue; + } + if(normalize_name(hdr.FileName, name, sizeof(name), &is_dir, &depth, c)) { ret = -1; break; @@ -765,6 +780,18 @@ extract_archive(HANDLE hArc, rarx_ctx_t *c) { } is_dir = (hdr.Flags & RHDF_DIRECTORY) ? 1 : 0; + /* Split continuation segments still need RARProcessFile(EXTRACT) so the + volume chain is driven and the file is completed, but only the first + segment is counted / reported / size-accumulated. */ + if(hdr.Flags & RHDF_SPLITBEFORE) { + rc = RARProcessFile(hArc, RAR_EXTRACT, c->staging, NULL); + if(rc != ERAR_SUCCESS) { + rar_translate_error(rc, hdr.FileName, c); + ret = -1; + break; + } + continue; + } rc = RARProcessFile(hArc, RAR_EXTRACT, c->staging, NULL); if(rc != ERAR_SUCCESS) { rar_translate_error(rc, hdr.FileName, c); diff --git a/tests/test_rar_extract.c b/tests/test_rar_extract.c index e03b369..957249e 100644 --- a/tests/test_rar_extract.c +++ b/tests/test_rar_extract.c @@ -384,7 +384,9 @@ test_real_archives(void) { if(st == ZIPX_OK) { snprintf(checkp, sizeof(checkp), "%s/root.txt", dst); check(exists(checkp), " root.txt present across volumes"); - check(res.entries_done >= 3, " entries_done >= 3"); + snprintf(checkp, sizeof(checkp), "%s/big.bin", dst); + check(exists(checkp), " big.bin (split file) present and whole"); + check(res.entries_done >= 2, " entries_done >= 2"); } else { printf(" message=%s\n", res.message); }