From a5b03cc1c5c7c7af0f289324b799b7103d12f28b Mon Sep 17 00:00:00 2001 From: Andres Mejia Date: Fri, 21 Sep 2012 20:23:25 -0400 Subject: [PATCH] Implement function used to seek within data blocks. This only implements seeking fully for uncompressed RAR files. Seeking is not implemented for compressed RAR files and for the other formats (ZIP, TAR, etc.). --- Makefile.am | 9 + libarchive/archive.h | 3 + libarchive/archive_read.c | 127 +++++++++++- libarchive/archive_read_private.h | 9 + libarchive/archive_read_support_format_7zip.c | 1 + libarchive/archive_read_support_format_ar.c | 1 + libarchive/archive_read_support_format_cab.c | 1 + libarchive/archive_read_support_format_cpio.c | 1 + .../archive_read_support_format_empty.c | 1 + .../archive_read_support_format_iso9660.c | 1 + libarchive/archive_read_support_format_lha.c | 1 + .../archive_read_support_format_mtree.c | 2 +- libarchive/archive_read_support_format_rar.c | 157 +++++++++++++- libarchive/archive_read_support_format_raw.c | 1 + libarchive/archive_read_support_format_tar.c | 1 + libarchive/archive_read_support_format_xar.c | 1 + libarchive/archive_read_support_format_zip.c | 2 + ...ar_multivolume_multiple_files.part1.rar.uu | 163 +++++++++++++++ ...ar_multivolume_multiple_files.part2.rar.uu | 163 +++++++++++++++ ...ar_multivolume_multiple_files.part3.rar.uu | 163 +++++++++++++++ ...ar_multivolume_multiple_files.part4.rar.uu | 163 +++++++++++++++ ...ar_multivolume_multiple_files.part5.rar.uu | 163 +++++++++++++++ ...ar_multivolume_multiple_files.part6.rar.uu | 117 +++++++++++ libarchive/test/test_read_format_rar.c | 193 ++++++++++++++++++ .../test/test_splitted_rar_seek_support_aa.uu | 159 +++++++++++++++ .../test/test_splitted_rar_seek_support_ab.uu | 159 +++++++++++++++ .../test/test_splitted_rar_seek_support_ac.uu | 141 +++++++++++++ 27 files changed, 1895 insertions(+), 8 deletions(-) create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part3.rar.uu create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part4.rar.uu create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu create mode 100644 libarchive/test/test_rar_multivolume_multiple_files.part6.rar.uu create mode 100644 libarchive/test/test_splitted_rar_seek_support_aa.uu create mode 100644 libarchive/test/test_splitted_rar_seek_support_ab.uu create mode 100644 libarchive/test/test_splitted_rar_seek_support_ac.uu diff --git a/Makefile.am b/Makefile.am index 928fc82e3..3e40ab743 100644 --- a/Makefile.am +++ b/Makefile.am @@ -492,6 +492,12 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_fuzz.cab.uu \ libarchive/test/test_fuzz.lzh.uu \ libarchive/test/test_pax_filename_encoding.tar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part3.rar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part4.rar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu \ + libarchive/test/test_rar_multivolume_multiple_files.part6.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part1.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part2.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part3.rar.uu \ @@ -612,6 +618,9 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_splitted_rar_ab.uu \ libarchive/test/test_read_splitted_rar_ac.uu \ libarchive/test/test_read_splitted_rar_ad.uu \ + libarchive/test/test_splitted_rar_seek_support_aa.uu \ + libarchive/test/test_splitted_rar_seek_support_ab.uu \ + libarchive/test/test_splitted_rar_seek_support_ac.uu \ libarchive/test/CMakeLists.txt \ libarchive/test/README diff --git a/libarchive/archive.h b/libarchive/archive.h index 07081a5aa..7b7e75eeb 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -440,6 +440,9 @@ __LA_DECL __LA_INT64_T archive_read_header_position(struct archive *); __LA_DECL __LA_SSIZE_T archive_read_data(struct archive *, void *, size_t); +/* Seek within the body of an entry. Similar to lseek(2). */ +__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int); + /* * A zero-copy version of archive_read_data that also exposes the file offset * of each returned block. Note that the client has no way to specify diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index faadbea41..118c10b64 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -399,6 +399,8 @@ archive_read_set_callback_data2(struct archive *_a, void *client_data, return ARCHIVE_FATAL; } a->client.dataset[iindex].data = client_data; + a->client.dataset[iindex].begin_position = -1; + a->client.dataset[iindex].total_size = -1; return ARCHIVE_OK; } @@ -427,8 +429,14 @@ archive_read_add_callback_data(struct archive *_a, void *client_data, } a->client.dataset = (struct archive_read_data_node *)p; for (i = a->client.nodes - 1; i > iindex && i > 0; i--) + { a->client.dataset[i].data = a->client.dataset[i-1].data; + a->client.dataset[i].begin_position = -1; + a->client.dataset[i].total_size = -1; + } a->client.dataset[iindex].data = client_data; + a->client.dataset[iindex].begin_position = -1; + a->client.dataset[iindex].total_size = -1; return ARCHIVE_OK; } @@ -495,6 +503,9 @@ archive_read_open1(struct archive *_a) filter->code = ARCHIVE_COMPRESSION_NONE; a->filter = filter; + client_switch_proxy(a->filter, 0); + a->client.dataset[0].begin_position = 0; + /* Build out the input pipeline. */ e = choose_filters(a); if (e < ARCHIVE_WARN) { @@ -641,6 +652,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) a->read_data_output_offset = 0; a->read_data_remaining = 0; + a->data_start_node = a->client.cursor; /* EOF always wins; otherwise return the worst error. */ return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1; } @@ -838,6 +850,23 @@ archive_read_data_skip(struct archive *_a) return (r); } +int64_t +archive_seek_data(struct archive *_a, int64_t offset, int whence) +{ + struct archive_read *a = (struct archive_read *)_a; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, + "archive_seek_data_block"); + + if (a->format->seek_data == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: " + "No format_seek_data_block function registered"); + return (ARCHIVE_FATAL); + } + + return (a->format->seek_data)(a, offset, whence); +} + /* * Read the next block of entry data from the archive. * This is a zero-copy interface; the client receives a pointer, @@ -1049,6 +1078,7 @@ __archive_read_register_format(struct archive_read *a, int (*read_header)(struct archive_read *, struct archive_entry *), int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), int (*read_data_skip)(struct archive_read *), + int64_t (*seek_data)(struct archive_read *, int64_t, int), int (*cleanup)(struct archive_read *)) { int i, number_slots; @@ -1068,6 +1098,7 @@ __archive_read_register_format(struct archive_read *a, a->formats[i].read_header = read_header; a->formats[i].read_data = read_data; a->formats[i].read_data_skip = read_data_skip; + a->formats[i].seek_data = seek_data; a->formats[i].cleanup = cleanup; a->formats[i].data = format_data; a->formats[i].name = name; @@ -1463,12 +1494,106 @@ int64_t __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence) { int64_t r; + unsigned int cursor; if (filter->closed || filter->fatal) return (ARCHIVE_FATAL); if (filter->seek == NULL) return (ARCHIVE_FAILED); - r = filter->seek(filter, offset, whence); + + switch (whence) + { + case SEEK_CUR: + /* Adjust the offset and use SEEK_SET instead */ + offset += filter->position; + case SEEK_SET: + cursor = 0; + while (1) + { + if (filter->archive->client.dataset[cursor].begin_position < 0 || + filter->archive->client.dataset[cursor].total_size < 0 || + filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size - 1 > offset || + cursor + 1 >= filter->archive->client.nodes) + break; + r = filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size; + filter->archive->client.dataset[++cursor].begin_position = r; + } + while (1) + { + if ((r = client_switch_proxy(filter, cursor)) != (ARCHIVE_OK)) + return r; + if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) + return r; + filter->archive->client.dataset[cursor].total_size = r; + if (filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size - 1 > offset || + cursor + 1 >= filter->archive->client.nodes) + break; + r = filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size; + filter->archive->client.dataset[++cursor].begin_position = r; + } + offset -= filter->archive->client.dataset[cursor].begin_position; + if (offset < 0) + offset = 0; + else if (offset > filter->archive->client.dataset[cursor].total_size - 1) + offset = filter->archive->client.dataset[cursor].total_size - 1; + if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0) + return r; + break; + + case SEEK_END: + cursor = 0; + while (1) + { + if (filter->archive->client.dataset[cursor].begin_position < 0 || + filter->archive->client.dataset[cursor].total_size < 0 || + cursor + 1 >= filter->archive->client.nodes) + break; + r = filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size; + filter->archive->client.dataset[++cursor].begin_position = r; + } + while (1) + { + if ((r = client_switch_proxy(filter, cursor)) != (ARCHIVE_OK)) + return r; + if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) + return r; + filter->archive->client.dataset[cursor].total_size = r; + r = filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size; + if (cursor + 1 >= filter->archive->client.nodes) + break; + filter->archive->client.dataset[++cursor].begin_position = r; + } + while (1) + { + if (r + offset >= + filter->archive->client.dataset[cursor].begin_position) + break; + offset += filter->archive->client.dataset[cursor].total_size; + if (cursor == 0) + break; + cursor--; + r = filter->archive->client.dataset[cursor].begin_position + + filter->archive->client.dataset[cursor].total_size; + } + offset = (r + offset) - + filter->archive->client.dataset[cursor].begin_position; + if ((r = client_switch_proxy(filter, cursor)) != (ARCHIVE_OK)) + return r; + if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < (ARCHIVE_OK)) + return r; + break; + + default: + return (ARCHIVE_FATAL); + } + r += filter->archive->client.dataset[cursor].begin_position; + if (r >= 0) { /* * Ouch. Clearing the buffer like this hurts, especially diff --git a/libarchive/archive_read_private.h b/libarchive/archive_read_private.h index f1153bfc3..bfaedf14b 100644 --- a/libarchive/archive_read_private.h +++ b/libarchive/archive_read_private.h @@ -123,6 +123,8 @@ struct archive_read_filter { * so should be deferred at least until libarchive 3.0. */ struct archive_read_data_node { + int64_t begin_position; + int64_t total_size; void *data; }; struct archive_read_client { @@ -134,6 +136,7 @@ struct archive_read_client { archive_switch_callback *switcher; unsigned int nodes; unsigned int cursor; + int64_t position; struct archive_read_data_node *dataset; }; @@ -168,6 +171,10 @@ struct archive_read { /* File offset of beginning of most recently-read header. */ int64_t header_position; + /* Nodes and offsets of compressed data block */ + unsigned int data_start_node; + unsigned int data_end_node; + /* * Format detection is mostly the same as compression * detection, with one significant difference: The bidders @@ -185,6 +192,7 @@ struct archive_read { int (*read_header)(struct archive_read *, struct archive_entry *); int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *); int (*read_data_skip)(struct archive_read *); + int64_t (*seek_data)(struct archive_read *, int64_t, int); int (*cleanup)(struct archive_read *); } formats[16]; struct archive_format_descriptor *format; /* Active format. */ @@ -204,6 +212,7 @@ int __archive_read_register_format(struct archive_read *a, int (*read_header)(struct archive_read *, struct archive_entry *), int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), int (*read_data_skip)(struct archive_read *), + int64_t (*seek_data)(struct archive_read *, int64_t, int), int (*cleanup)(struct archive_read *)); int __archive_read_get_bidder(struct archive_read *a, diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index e9576b472..494028e88 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -409,6 +409,7 @@ archive_read_support_format_7zip(struct archive *_a) archive_read_format_7zip_read_header, archive_read_format_7zip_read_data, archive_read_format_7zip_read_data_skip, + NULL, archive_read_format_7zip_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/archive_read_support_format_ar.c b/libarchive/archive_read_support_format_ar.c index 9feb547db..40be18c0c 100644 --- a/libarchive/archive_read_support_format_ar.c +++ b/libarchive/archive_read_support_format_ar.c @@ -121,6 +121,7 @@ archive_read_support_format_ar(struct archive *_a) archive_read_format_ar_read_header, archive_read_format_ar_read_data, archive_read_format_ar_skip, + NULL, archive_read_format_ar_cleanup); if (r != ARCHIVE_OK) { diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c index b6f08b4dd..e383f408a 100644 --- a/libarchive/archive_read_support_format_cab.c +++ b/libarchive/archive_read_support_format_cab.c @@ -382,6 +382,7 @@ archive_read_support_format_cab(struct archive *_a) archive_read_format_cab_read_header, archive_read_format_cab_read_data, archive_read_format_cab_read_data_skip, + NULL, archive_read_format_cab_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c index ff29e1ffd..819f4a4f5 100644 --- a/libarchive/archive_read_support_format_cpio.c +++ b/libarchive/archive_read_support_format_cpio.c @@ -242,6 +242,7 @@ archive_read_support_format_cpio(struct archive *_a) archive_read_format_cpio_read_header, archive_read_format_cpio_read_data, archive_read_format_cpio_skip, + NULL, archive_read_format_cpio_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/archive_read_support_format_empty.c b/libarchive/archive_read_support_format_empty.c index 3dc2196cb..366073820 100644 --- a/libarchive/archive_read_support_format_empty.c +++ b/libarchive/archive_read_support_format_empty.c @@ -53,6 +53,7 @@ archive_read_support_format_empty(struct archive *_a) archive_read_format_empty_read_header, archive_read_format_empty_read_data, NULL, + NULL, NULL); return (r); diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 1ffe75108..7882be21e 100644 --- a/libarchive/archive_read_support_format_iso9660.c +++ b/libarchive/archive_read_support_format_iso9660.c @@ -475,6 +475,7 @@ archive_read_support_format_iso9660(struct archive *_a) archive_read_format_iso9660_read_header, archive_read_format_iso9660_read_data, archive_read_format_iso9660_read_data_skip, + NULL, archive_read_format_iso9660_cleanup); if (r != ARCHIVE_OK) { diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c index a92b072ab..a7c071e1a 100644 --- a/libarchive/archive_read_support_format_lha.c +++ b/libarchive/archive_read_support_format_lha.c @@ -319,6 +319,7 @@ archive_read_support_format_lha(struct archive *_a) archive_read_format_lha_read_header, archive_read_format_lha_read_data, archive_read_format_lha_read_data_skip, + NULL, archive_read_format_lha_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index b8a18eb7b..370a2f46d 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -202,7 +202,7 @@ archive_read_support_format_mtree(struct archive *_a) mtree->fd = -1; r = __archive_read_register_format(a, mtree, "mtree", - mtree_bid, NULL, read_header, read_data, skip, cleanup); + mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup); if (r != ARCHIVE_OK) free(mtree); diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c index 63eea0806..83ea8d85a 100644 --- a/libarchive/archive_read_support_format_rar.c +++ b/libarchive/archive_read_support_format_rar.c @@ -199,6 +199,12 @@ struct lzss int64_t position; }; +struct data_block_offsets +{ + int64_t start_offset; + int64_t end_offset; +}; + struct rar { /* Entries from main RAR header */ @@ -217,6 +223,7 @@ struct rar long mnsec; mode_t mode; char *filename; + char *filename_save; size_t filename_allocated; /* File header optional entries */ @@ -243,6 +250,10 @@ struct rar char entry_eof; unsigned long crc_calculated; int found_first_header; + char has_endarc_header; + struct data_block_offsets *dbo; + unsigned int cursor; + unsigned int nodes; /* LZSS members */ struct huffman_code maincode; @@ -301,6 +312,8 @@ static int archive_read_format_rar_read_header(struct archive_read *, static int archive_read_format_rar_read_data(struct archive_read *, const void **, size_t *, int64_t *); static int archive_read_format_rar_read_data_skip(struct archive_read *a); +static int64_t archive_read_format_rar_seek_data(struct archive_read *, int64_t, + int); static int archive_read_format_rar_cleanup(struct archive_read *); /* Support functions */ @@ -639,6 +652,7 @@ archive_read_support_format_rar(struct archive *_a) archive_read_format_rar_read_header, archive_read_format_rar_read_data, archive_read_format_rar_read_data_skip, + archive_read_format_rar_seek_data, archive_read_format_rar_cleanup); if (r != ARCHIVE_OK) @@ -997,6 +1011,93 @@ archive_read_format_rar_read_data_skip(struct archive_read *a) return (ARCHIVE_OK); } +static int64_t +archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset, + int whence) +{ + int64_t client_offset, ret; + unsigned int i; + struct rar *rar = (struct rar *)(a->format->data); + + if (rar->compression_method & COMPRESS_METHOD_STORE) + { + /* Modify the offset for use with SEEK_SET */ + switch (whence) + { + case SEEK_SET: + break; + + case SEEK_CUR: + offset += rar->offset; + break; + + case SEEK_END: + offset += rar->unp_size - 1; + break; + } + if (offset < 0) + offset = 0; + else if (offset > rar->unp_size - 1) + offset = rar->unp_size - 1; + + /* Find the appropriate offset in the client */ + i = 0; + client_offset = offset; + client_offset += rar->dbo[i].start_offset; + while (rar->main_flags & MHD_VOLUME && + client_offset > rar->dbo[i].end_offset) + { + i++; + if (i >= rar->nodes || client_offset <= rar->dbo[i].end_offset) + { + ret = __archive_read_seek(a, rar->dbo[i-1].end_offset + 1, SEEK_SET); + if (ret < (ARCHIVE_OK)) + return ret; + ret = archive_read_format_rar_read_header(a, a->entry); + if (ret == (ARCHIVE_EOF)) + { + rar->has_endarc_header = 1; + ret = archive_read_format_rar_read_header(a, a->entry); + } + if (ret != (ARCHIVE_OK)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Error during seek of RAR file"); + return (ARCHIVE_FAILED); + } + } + client_offset += rar->dbo[i].start_offset - rar->dbo[i-1].end_offset - 1; + } + + ret = __archive_read_seek(a, client_offset, SEEK_SET); + if (ret < (ARCHIVE_OK)) + return ret; + rar->bytes_remaining = rar->dbo[i].end_offset - ret + 1; + while (i > 0) + { + ret -= rar->dbo[i].start_offset - rar->dbo[i-1].end_offset - 1; + i--; + } + ret -= rar->dbo[i].start_offset; + + /* Always restart reading the file after a seek */ + a->read_data_block = NULL; + a->read_data_offset = 0; + a->read_data_output_offset = 0; + a->read_data_remaining = 0; + rar->bytes_unconsumed = 0; + rar->offset = 0; + + return ret; + } + else + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Seeking of compressed RAR files is unsupported"); + } + return (ARCHIVE_FAILED); +} + static int archive_read_format_rar_cleanup(struct archive_read *a) { @@ -1005,6 +1106,8 @@ archive_read_format_rar_cleanup(struct archive_read *a) rar = (struct rar *)(a->format->data); free_codes(a); free(rar->filename); + free(rar->filename_save); + free(rar->dbo); free(rar->unp_buffer); free(rar->lzss.window); __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc); @@ -1144,12 +1247,6 @@ read_header(struct archive_read *a, struct archive_entry *entry, } rar->bytes_remaining = rar->packed_size; - /* Split file in multivolume RAR. No more need to process header. */ - if (rar->file_flags & FHD_SPLIT_BEFORE) - { - __archive_read_consume(a, header_size - 7); - return ret; - } /* TODO: RARv3 subblocks contain comments. For now the complete block is * consumed at the end. @@ -1297,6 +1394,49 @@ read_header(struct archive_read *a, struct archive_entry *entry, p += filename_size; } + /* Split file in multivolume RAR. No more need to process header. */ + if (rar->filename_save && + !memcmp(rar->filename, rar->filename_save, filename_size + 1)) + { + __archive_read_consume(a, header_size - 7); + rar->cursor++; + if (rar->cursor >= rar->nodes) + { + rar->nodes++; + if ((rar->dbo = + realloc(rar->dbo, sizeof(*rar->dbo) * rar->nodes)) == NULL) + { + archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory."); + return (ARCHIVE_FATAL); + } + rar->dbo[rar->cursor].start_offset = -1; + rar->dbo[rar->cursor].end_offset = -1; + } + if (rar->dbo[rar->cursor].start_offset < 0) + { + rar->dbo[rar->cursor].start_offset = a->filter->position; + rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset + + rar->packed_size - 1; + } + return ret; + } + + rar->filename_save = (char*)realloc(rar->filename_save, + filename_size + 1); + memcpy(rar->filename_save, rar->filename, filename_size + 1); + + /* Set info for seeking */ + free(rar->dbo); + if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL) + { + archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory."); + return (ARCHIVE_FATAL); + } + rar->dbo[0].start_offset = -1; + rar->dbo[0].end_offset = -1; + rar->cursor = 0; + rar->nodes = 1; + if (rar->file_flags & FHD_SALT) { if (p + 8 > endp) { @@ -1317,6 +1457,8 @@ read_header(struct archive_read *a, struct archive_entry *entry, } __archive_read_consume(a, header_size - 7); + rar->dbo[0].start_offset = a->filter->position; + rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size - 1; switch(file_header.host_os) { @@ -2621,7 +2763,10 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) { ret = archive_read_format_rar_read_header(a, a->entry); if (ret == (ARCHIVE_EOF)) + { + rar->has_endarc_header = 1; ret = archive_read_format_rar_read_header(a, a->entry); + } if (ret != (ARCHIVE_OK)) return NULL; return rar_read_ahead(a, min, avail); diff --git a/libarchive/archive_read_support_format_raw.c b/libarchive/archive_read_support_format_raw.c index df2c00c96..e371ce815 100644 --- a/libarchive/archive_read_support_format_raw.c +++ b/libarchive/archive_read_support_format_raw.c @@ -77,6 +77,7 @@ archive_read_support_format_raw(struct archive *_a) archive_read_format_raw_read_header, archive_read_format_raw_read_data, archive_read_format_raw_read_data_skip, + NULL, archive_read_format_raw_cleanup); if (r != ARCHIVE_OK) free(info); diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 4538331f3..708eaf1f1 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -253,6 +253,7 @@ archive_read_support_format_tar(struct archive *_a) archive_read_format_tar_read_header, archive_read_format_tar_read_data, archive_read_format_tar_skip, + NULL, archive_read_format_tar_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/archive_read_support_format_xar.c b/libarchive/archive_read_support_format_xar.c index 733011c26..780e749d7 100644 --- a/libarchive/archive_read_support_format_xar.c +++ b/libarchive/archive_read_support_format_xar.c @@ -467,6 +467,7 @@ archive_read_support_format_xar(struct archive *_a) xar_read_header, xar_read_data, xar_read_data_skip, + NULL, xar_cleanup); if (r != ARCHIVE_OK) free(xar); diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 2055313a4..b55f1213e 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -173,6 +173,7 @@ archive_read_support_format_zip_streamable(struct archive *_a) archive_read_format_zip_streamable_read_header, archive_read_format_zip_read_data, archive_read_format_zip_read_data_skip, + NULL, archive_read_format_zip_cleanup); if (r != ARCHIVE_OK) @@ -206,6 +207,7 @@ archive_read_support_format_zip_seekable(struct archive *_a) archive_read_format_zip_seekable_read_header, archive_read_format_zip_read_data, archive_read_format_zip_read_data_skip, + NULL, archive_read_format_zip_cleanup); if (r != ARCHIVE_OK) diff --git a/libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu b/libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu new file mode 100644 index 000000000..fee150c1a --- /dev/null +++ b/libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu @@ -0,0 +1,163 @@ +begin 644 test_rar_multivolume_multiple_files.part1.rar +M4F%R(1H'`%INR!M87)G:6XM8F]T=&]M.B`P+C`X +M:6X@?0H)"4@Q('L@;6%R9VEN+6)O='1O;3H@,"XP.&EN('T*"0E(,2YW97-T +M97)N('L@9F]N="UF86UI;'DZ("),:6)E2!C;VUP;&5X('!I +M96-E(&]F('-O9G1W87)E('1H870@6EN9R!N97<@<&]R=',@86YD(&9O2!S:6=N:69I8V%N="!C +M:&%N9V4@=&\@;&EB87)C:&EV92P@:6YC;'5D:6YG(&UO&5S +M+`IS:&]U;&0@8F4@86-C;VUP86YI960@8GD@;F5W('1E'!L86EN2!O9B!T:&%T(&-O;7!O;F5N="X@5&AE +M6]U +M(&YE960@=&\@9VEV92!T:&5M('1W;R!P:65C97,@;V8*:6YF;W)M871I;VXZ +M(`H\+U`^"CQ53#X*"3Q,23X\4"!35%E,13TB;6%R9VEN+6)O='1O;3H@,&EN +M(CY4:&4@9G5L;"!P871H('1O('1H92!D:7)E8W1O&5C=71A8FQE('!R;V=R86T@8F5I;F<@ +M=&5S=&5D("AN;W0*"6%P<&QI8V%B;&4@=&\@;&EB87)C:&EV95]T97-T('-I +M;F-E(&QI8F%R8VAI=F4@:7,@8V]M<&EL960@:6YT;R!T:&4*"71E'1E;G-I;VXN(%1H92!T97-T('!R;V=R86US(&QO;VL@:6X@82!F97<* +M3L@=&AE>2!N965D('1H92!F=6QL('!A=&@@=&\@ +M=&AE(&%P<')O<')I871E(&5X96-U=&%B;&4N"D%L=&AO=6=H(&)S9'1A2!I;G1E;F1E +M9"!F;W(*=&5S=&EN9R!B2!T;R!V97)I9GD@=&AA="!T:&4@=&5S=`IP2X@"CPO4#X*/%`^5VAE;B!R=6XL('1H +M92!T97-T('!R;V=R86US(&]U='!U="!A('!R;V=R97-S(&UE&5R8VES:6YG.B!B0HF;F)S<#L@=&5S=%]C;W!Y+F,Z,32YC.C$W,3H@ +M1F%I;&5D(#(V-"!T:6UE2!F;W(@9G5R=&AE +M&5R8VES960N(`H)/"]0/@H)/$Q)/CQ0/D)A&%M +M<&QE+`IM86YY(&]F('1H92!L:6)AFEP/"]45#XL"G=H:6-H('9E&%M<&QE +M(&%B;W9E*0IG96YE2!P2!S:6UP;&EF:65S(&1I86=N +M;W-I;F<*9F%I;'5R97,N(`H\+U`^"CQ(,2!#3$%34STB=V5S=&4`9GL/0!0` +-+CO?G@`````````````` +` +end diff --git a/libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu b/libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu new file mode 100644 index 000000000..012399a5c --- /dev/null +++ b/libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu @@ -0,0 +1,163 @@ +begin 644 test_rar_multivolume_multiple_files.part2.rar +M4F%R(1H'`!EZ2!E87-Y('1O"F%D9"!N97<@=&5S=',N*2`*/"]0/@H\ +M4#Y4:&4@=&5S="!H87)N97-S(&1E=&5R;6EN97,@=VAI8V@@=&5S=',@=&\@ +M&-E<'0@9F]R('-T9&EN+"!S=&1O=70L(&%N9"!S +M=&1E2!D:7)E8W1O2!D +M:7)E8W1O2!A2!I0H)=VAE;B!T:&4@=&5S="!S=&%R=',N(`H)/"]0/@H)/$Q)/CQ0(%-4 +M64Q%/2)M87)G:6XM8F]T=&]M.B`P:6XB/D%N>2!F:6QE2X@5&AE('1E2!D +M96)U9V=E2!D:69F97)E;G0@<&QA +M=&9O2!W'@H*2!F=6YC=&EO;G,@=&AA="!Y;W4@8V%N +M('5S92X@5&AE3PO5%0^+"`\5%0@0TQ!4U,](G=E2!T97-T6]U(&-A;B!R96-O=F5R('1H +M92!R969E2!O9B!C:&%R86-T97)S+B!4:&ES('=A2X@270GF5D +M(&9O6]U('1H:6YK"@EY;W4G=F4@9F]U;F0@82!B=6&EN9R!T:&4@8G5G+B`*"3PO4#X*"3Q,23X\ +M4"!35%E,13TB;6%R9VEN+6)O='1O;3H@,&EN(CY$3R!R=6X@86QL(&]F('1H +M92!T97-T0H)97AE6]U('-E92!A('1E6]U(&AA=F4@<75E2!R96%D(&$@<')E+6)U:6QT"FEN<'5T(&9I;&4@86YD('9E2!T:&4@2!S=')A:6=H=&9O0IA;F0@=&AE;B!O<&5N('1H92!M96UO71E&%C="!D871A(&-O;G1A:6YS('9A;'5E2!V97)I9GEI +M;F<@9FEL97,@;VX@9&ES:RX@5&\@;6%K92!T:&ES(&5A0IA +M=F%I;&%B;&4N(`H\+U`^"CQ(,B!#3$%34STB=V5S=&5R;B(^/$$@3D%-13TB +M1G5Z>E]T97-T97(B/CPO03Y&=7IZ('1E0IU2!D86UA9V5D+B`H4F5M96UB97(@=&AA="!L +M:6)AB!T97-T97(@:6YS=&5A9"!G96YE2UD86UA +M9V5D(&9I;&4L('-A=F5S('1H870@9FEL92!T;R!D:7-K+"!T:&5N(')U;G,@ +M=&AE(&9I;&4*=&AR;W5G:"!L:6)A2!T;R!PB!T97-T97(@:&%S('!R +M;W9E;B!Q=6ET92!U0IL87)G92!E;G1R +M:65S+"!U<"!T;R`Q('1E71E+B!/9B!C;W5R71E"F5N=')Y('1O(&%N('5N8V]M<')EFEP +M,@IC;VUP65R('1H870@:6UP;&5M96YT2!L87)G92!E;G1R:65S('1HF5R;RUC;W!Y+B!7:&5N('EO=2!G:79E(&ET(&$@;&%R9V4* +M8FQO8VL@=&\@=W)I=&4@=&\@86X@96YT2P@:70@=VEL;"!P87-S +M('!O:6YT97)S('-T&-E<'0@:6X@=&AO2!D +M971E8W0@=VAE;B!A(&)L;V-K(&)E:6YG('=R:71T96X@;W5T(&)Y"G1H92!A +M2!B;V1Y +M+"!A;F0@F5S('=H:6-H('1R861E(&]F9@IP;W)T86)I;&ET>2!V +M97)S=7,@'0O:'1M;#L@8VAA"DB/@H)/$U%5$$@3D%-13TB0U)%051%1"(@ +M0T].5$5.5#TB,C`Q,3`V,C8[,C(R,S4Q,#`B/@H)/$U%5$$@3D%-13TB0TA! +M3D=%1"(@0T].5$5.5#TB,C`Q,3`V,C8[,C(R-30U,#`B/@H)/%-464Q%(%19 +M4$4](G1E>'0O8W-S(CX*"3PA+2T*"0E`<&%G92![(&UAR!F;VYT +M+69A;6EL>3H@(D)I='-TR!F +M;VYT+69A;6EL>3H@(D9R965386YS(B!]"@D)4%)%+F-J:R![(&9O;G0M9F%M +M:6QY.B`B0FETR!M87)G:6XM8F]T=&]M.B`P+C`X:6X@?0H)"4@R+F-T;"![(&9O;G0M9F%M +M:6QY.B`B1G)E95-A;G,B('T*"0E45"YC:FL@>R!F;VYT+69A;6EL>3H@(D)I +M='-T"!P:65C92!O9B!S;V9T=V%R92!T +M:&%T(')U;G,@;VX*82!N=6UB97(@;V8@9&EF9F5R96YT('!L871F;W)M2X@"CPO4#X*/%`^06YY('-I9VYI9FEC86YT(&-H86YG92!T;R!L:6)A +M2!N97<@=&5S=',@;W(@8VAA;F=E&ES=&EN +M9R!T97-T0H):&]L9&EN9R!T:&4@)G%U;W0[6]U)VQL(&YE960@=&\@ +M2!T:&4*/%14($-,05-3/2)W97-T97)N(CXM2!S:&]U;&0@8F4@=7-A8FQE(&9O +M2!T:&%T('=I;&P@8F4@=7-E +M9`H)9F]R('-C2!F&5C=71A8FQE(&)E:6YG(&5X97)C:7-E +M9"X@"@D\+U`^"@D\3$D^/%`^0F%S:6,@=F5R2(^/"]!/D)A2!T:&%T(&EL;&5G86P@&-E2!W +M:71H('9A'1?:&5A9&5R*&$L("9A;7`[864I*3L*)FYB5]P871H;F%M92AA92DI.SPO +M4%)%/CQ0/@I4:&4@/%14($-,05-3/2)W97-T97)N(CYA2!D969A=6QT+`IT:&5Y(')E<&]R="!T:&4@9F%I;'5R92!A;F0@2!O9@IS<&5C:69I8R!T97-T2!E87-Y +M('1O"F%D9"!N97<@=&5S=',N*2`*/"]0/@H\4#Y4:&4@=&5S="!H87)N97-S +M(&1E=&5R;6EN97,@=VAI8V@@=&5S=',@=&\@&-E +M<'0@9F]R('-T9&EN+"!S=&1O=70L(&%N9"!S=&1E2!D:7)E8W1P6GL/0!0` +-_]75M@,````````````` +` +end diff --git a/libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu b/libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu new file mode 100644 index 000000000..d5ff36ac6 --- /dev/null +++ b/libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu @@ -0,0 +1,163 @@ +begin 644 test_rar_multivolume_multiple_files.part5.rar +M4F%R(1H'`!EZ2X@*$EF(#Q45"!#3$%34STB=V5S=&5R;B(^+6L\ +M+U14/@H):7,@6]U+B`*"3PO4#X*"3Q, +M23X\4#Y4:&4@8W5R6]U(&-A;B!U6UL:6YK/"]45#XL"@D\5%0@0TQ!4U,](G=E3PO5%0^+`H)/%14($-, +M05-3/2)W97-T97)N(CYA&%M<&QE+"!I9B!Y;W4@;F5E9"!A +M(')E9F5R96YC92!T87(@87)C:&EV92!T;R!U2X@"CPO4#X*/%`^3&]O:R!A="`\5%0@0TQ!4U,](G=E&%M<&QE(&]F('1H:7,@=7-A9V4N(`H\+U`^"CQ0/D$@9F5W(&]F +M('1H92!O;&1E'!E6]U)W9E(&9O=6YD(&$@8G5G+"!W92!R96-O;6UE;F0@=W)I=&EN9R!T +M:&4@=&5S="!F:7)S="P@;6%K92!S=7)E"@ET:&4@=&5S="!F86EL6]U2!O +M;B`\5%0@0TQ!4U,](G=E2!A9&1I;F<@:G5S="!A(&-O=7!L92!O9B!A&ES=&EN9R!T97-T(&EN&%M<&QEQ,``(].```#8Z8%7O-C(4`4 +M,!D`I($``$QI8F%R8VAI=F5!9&1I;F=497-T+FAT;6S`S/-C(4"[3#5!2!S +M=')A:6=H=&9O0IA;F0@=&AE;B!O<&5N('1H92!M96UO71E&%C="!D +M871A(&-O;G1A:6YS('9A;'5E2!V97)I9GEI;F<@9FEL97,@;VX@9&ES +M:RX@5&\@;6%K92!T:&ES(&5A0IA=F%I;&%B;&4N(`H\+U`^ +M"CQ(,B!#3$%34STB=V5S=&5R;B(^/$$@3D%-13TB1G5Z>E]T97-T97(B/CPO +M03Y&=7IZ('1E0IU +M2!D86UA9V5D+B`H4F5M96UB97(@=&AA="!L:6)AB!T97-T97(@:6YS +M=&5A9"!G96YE2UD86UA9V5D(&9I;&4L('-A=F5S +M('1H870@9FEL92!T;R!D:7-K+"!T:&5N(')U;G,@=&AE(&9I;&4*=&AR;W5G +M:"!L:6)A2!T;R!PB!T97-T97(@:&%S('!R;W9E;B!Q=6ET92!U0IL87)G92!E;G1R:65S+"!U<"!T;R`Q('1E +M71E+B!/9B!C;W5R71E"F5N=')Y +M('1O(&%N('5N8V]M<')EFEP,@IC;VUP65R +M('1H870@:6UP;&5M96YT2!L87)G92!E;G1R:65S('1H2!H86YD;&5S(&%L;"!O9B!T:&4@8F]U;F1AF5R;RUC +M;W!Y+B!7:&5N('EO=2!G:79E(&ET(&$@;&%R9V4*8FQO8VL@=&\@=W)I=&4@ +M=&\@86X@96YT2P@:70@=VEL;"!P87-S('!O:6YT97)S('-T&-E<'0@:6X@ +M=&AO2!D971E8W0@=VAE;B!A(&)L +M;V-K(&)E:6YG('=R:71T96X@;W5T(&)Y"G1H92!A2!B;V1Y+"!A;F0@F5S +M('=H:6-H('1R861E(&]F9@IP;W)T86)I;&ET>2!V97)S=7,@PY`%`!.[9:E +)!0`````````` +` +end diff --git a/libarchive/test/test_read_format_rar.c b/libarchive/test/test_read_format_rar.c index bb6a522f1..c3daa09be 100644 --- a/libarchive/test/test_read_format_rar.c +++ b/libarchive/test/test_read_format_rar.c @@ -1154,3 +1154,196 @@ DEFINE_TEST(test_read_format_rar_multivolume_stored_file_skip) assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } + +DEFINE_TEST(test_read_format_rar_multivolume_seek_data) +{ + const char *reffiles[] = + { + "test_rar_multivolume_single_file.part1.rar", + "test_rar_multivolume_single_file.part2.rar", + "test_rar_multivolume_single_file.part3.rar", + NULL + }; + char buff[64]; + int file_size = 20111; + const char file_test_txt1[] = "d. \n

\n

" + "
\n

\n\n"; + const char file_test_txt2[] = "\n<"; + const char file_test_txt3[] = "mplify writing such tests,\ntry to use plat" + "form-independent codin"; + const char file_test_txt4[] = "lString in the example above)\ngenerat" + "e detailed log message"; + const char file_test_txt5[] = "SS=\"western\">make check will usually" + " run\n\tall of the tests."; + struct archive_entry *ae; + struct archive *a; + + extract_reference_files(reffiles); + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_support_filter_all(a)); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_open_filenames(a, reffiles, 10240)); + + /* First header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("LibarchiveAddingTest.html", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(file_size, archive_entry_size(ae)); + assertEqualInt(33188, archive_entry_mode(ae)); + + /* Seek to the end minus 64 bytes */ + assertA(file_size - (int)sizeof(buff) == + archive_seek_data(a, file_size - sizeof(buff), SEEK_SET)); + assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, file_test_txt1, sizeof(file_test_txt1) - 1); + + /* Seek back to the beginning */ + assertA(0 == archive_seek_data(a, 0, SEEK_SET)); + assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, file_test_txt2, sizeof(file_test_txt2) - 1); + + /* Seek to the middle of the combined data block */ + assertA(10054 == archive_seek_data(a, 10054, SEEK_SET)); + assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, file_test_txt3, sizeof(file_test_txt3) - 1); + + /* Seek to 32 bytes before the end of the first data sub-block */ + assertA(6860 == archive_seek_data(a, 6860, SEEK_SET)); + assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, file_test_txt4, sizeof(file_test_txt4) - 1); + + /* Seek to 32 bytes before the end of the second data sub-block */ + assertA(13752 == archive_seek_data(a, 13752, SEEK_SET)); + assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, file_test_txt5, sizeof(file_test_txt5) - 1); + + /* Test EOF */ + assertA(1 == archive_read_next_header(a, &ae)); + assertEqualInt(1, archive_file_count(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_rar_multivolume_seek_multiple_files) +{ + const char *reffiles[] = + { + "test_rar_multivolume_multiple_files.part1.rar", + "test_rar_multivolume_multiple_files.part2.rar", + "test_rar_multivolume_multiple_files.part3.rar", + "test_rar_multivolume_multiple_files.part4.rar", + "test_rar_multivolume_multiple_files.part5.rar", + "test_rar_multivolume_multiple_files.part6.rar", + NULL + }; + char buff[64]; + int file_size = 20111; + const char file_test_txt1[] = "d. \n

\n

" + "
\n

\n\n"; + const char file_test_txt2[] = "\n<"; + const char file_test_txt3[] = "mplify writing such tests,\ntry to use plat" + "form-independent codin"; + const char file_test_txt4[] = "\nfailures. \n

\n

<" + "A NAME=\"Life_cycle_of_a_te"; + const char file_test_txt5[] = "LE=\"margin-bottom: 0in\">DO use runtime te" + "sts for platform\n\tfeatu"; + const char file_test_txt6[] = "rough test suite is essential\nboth for ver" + "ifying new ports and f"; + const char file_test_txt7[] = "m: 0in\">Creates a temporary directory\n\tw" + "hose name matches the na"; + const char file_test_txt8[] = "lt\ninput file and verify the results. Thes" + "e use R!M87)G:6XZ(#`N-SEI;B!]"@D)4"![(&UAR!M87)G:6XM8F]T=&]M.B`P+C`X:6X@?0H)"4@Q+G=ER!F;VYT+69A;6EL>3H@(DQI8F5R871I;VX@4V5R:68B+"!S97)I9B!] +M"@D)2#$N8VIK('L@9F]N="UF86UI;'DZ(")":71S=')E86T@5F5R82!386YS +M(B!]"@D)2#$N8W1L('L@9F]N="UF86UI;'DZ(")&R!F;VYT+69A;6EL>3H@(D)I='-TR!F;VYT+69A;6EL>3H@(D9R965386YS(B!]"@D)5%0N8VIK('L@ +M9F]N="UF86UI;'DZ(")":71S=')E86T@5F5R82!386YS(BP@;6]N;W-P86-E +M('T*"2TM/@H)/"]35%E,13X*/"](14%$/@H\0D]$62!,04Y'/2)E;BU54R(@ +M1$E2/2),5%(B/@H\2#$@0TQ!4U,](G=E2X@"CPO4#X*/%`^06YY('-I9VYI9FEC86YT(&-H +M86YG92!T;R!L:6)A2!N97<@=&5S=',@;W(@8VAA;F=E +M&ES=&EN9R!T97-T0H):&]L9&EN9R!T:&4@ +M)G%U;W0[6]U +M)VQL(&YE960@=&\@2!T:&4*/%14($-,05-3/2)W97-T97)N(CXM +M2!S:&]U;&0@ +M8F4@=7-A8FQE(&9O2!F&5C=71A8FQE(&)E +M:6YG(&5X97)C:7-E9"X@"@D\+U`^"@D\3$D^/%`^0F%S:6,@=F5R2(^/"]!/D)A2!T:&%T(&EL;&5G86P@&-E2!W:71H('9A'1R +M86-T7W)E9F5R96YC95]F:6QE*&YA;64I.PHF;F)S<#L@)FYB'1?:&5A9&5R*&$L("9A;7`[864I*3L* +M)FYB5]P871H +M;F%M92AA92DI.SPO4%)%/CQ0/@I4:&4@/%14($-,05-3/2)W97-T97)N(CYA +M2!D969A=6QT+`IT:&5Y(')E<&]R="!T:&4@9F%I;'5R +M92!A;F0@6-L92!O9@IA('1E0IA;F0@87,@82!L +M86)E;"!T:&%T(&-A;B!B92!U2X@"@D\+U`^"@D\3$D^/%`@4U193$4](FUA2!D:7)E8W1O2!A2!O<&5N(&9I;&4@9&5S8W)I<'1O2!W:6QL(&)E +M(')E;6]V960@9F]R('EO=2X@"@D\+U`^"@D\3$D^/%`^5&AE(&-U2X@"@D\+U`^"@D\3$D^/%`@4U193$4](FUA +MPHC:68@7U]03$%41D]230HF;F)S<#L@ +M)FYB"@I(&9U;F-T:6]N +M2!I;F-O;7!L971E(&QI +M'1&:6QE0V]N=&5N=',\+U14/B`*"3PO4#X*/"]53#X*/$@Q($-, +M05-3/2)W97-T97)N(CX\02!.04U%/2)2969E6]U(&YE960@82!R969E'1R86-T7W)E9F5R96YC95]F:6QE*"9Q=6]T +M.W1E"UE;F-O9&5D(&%R'1R86-T7W)E +M9F5R96YC95]F:6QE*"D\+U14/B!W87,@861D960@86YD(&ES"FYO="!R96-O +M;6UE;F1E9"!F;W(@;F5W(&-O9&4N(`H\+U`^"CQ(,2!#3$%34STB=V5S=&5R +M;B(^/$$@3D%-13TB1&]S7V%N9%]$;VYT6]U6]U2!R=6X* +M"6%L;"!O9B!T:&4@=&5S=',N(`H)/"]0/@H)/$Q)/CQ0(%-464Q%/2)M87)G +M:6XM8F]T=&]M.B`P:6XB/D1/3B=4(')E;'D@;VX@/%14($-,05-3/2)W97-T +997)N(CY(059%7SPO5%0^"@EM86-R;W,@9@`` +` +end diff --git a/libarchive/test/test_splitted_rar_seek_support_ac.uu b/libarchive/test/test_splitted_rar_seek_support_ac.uu new file mode 100644 index 000000000..ee9f78c48 --- /dev/null +++ b/libarchive/test/test_splitted_rar_seek_support_ac.uu @@ -0,0 +1,141 @@ +begin 644 - +M2!A9&1I;F<@:G5S="!A(&-O=7!L92!O9B!A&ES=&EN9R!T97-T(&EN&%M<&QE'1R86-T7W)E9F5R96YC +M95]F:6QE*"D\+U14/@IT;R!D96-O9&4@82!U=65N8V]D960@:6YP=70@9FEL +M92P@=&AE;B!O<&5N('1H870@9FEL92!W:71H(&QI8F%R8VAI=F4*86YD('9E +M2!T:&4@0IF965D(&%R8VAI=F4@96YT2!A9V%I;B!T;R!R96%D('1H +M92!D871A(&)A8VL@86YD('9E2!T:&%T"FET(&ES('1H92!S86UE+B`* +M/"]0/@H\2#(@0TQ!4U,](G=E2!T:&%T('1H92!A2X*5&AE2!T6EN9R!F:6QE2!T +M:6UE2!T;PIA=F]I9"!UGH@=&5S=&5R/"](,CX*/%`^5&AE(&9U>GH@=&5S=&5R(&ES(&]N92!O +M9B!T:&4@9F5W('1E2!A8F]R +M=',@=&AE(&5N=&ER92!PGH@9F%I;'5R92!C +M875S97,@82!CFEP(&]R(&)Z:7`R"F-O;7!R97-S:6]N('=O +M;B=T(&AE;'`[(&%L=&AO=6=H('-M86QL97(L('1H92!O=71P=70@:7,@F5R;R!B>71E0IE9F9E8W1I=F4L(&-O;7!R97-S:6YG(&$@F5N(&5N=')I97,@9&]W;B!T;PIJ=7-T(&$@9F5W +M(&MI;&]B>71E2!T:&%T(&QI8F%R8VAI=F4@8V]R +M0IC87-EF5R;R!B;&]C:W,@8V%N('1A:V4*<75I=&4@82!W:&EL92P@F%T +M:6]N.@I,:6)A29Q=6]T.R!Z97)O+6-O +M<'DN(%=H96X@>6]U(&=I=F4@:70@82!L87)G90IB;&]C:R!T;R!W2!B;V1Y+"!I="!W:6QL('!A2!L87)G92!F:6QE('-I>F5S("AT87(@9FEL97,*2D@86YD(&EN=&5G97(@;W9E2D@:6X@82!T97-T('1H870@