libarchive-clib 3.8.8 → 3.8.9
raw patch · 84 files changed
+10148/−9337 lines, 84 files
Files
- c/archive.h +2/−2
- c/archive_acl.c +14/−1
- c/archive_acl_private.h +2/−0
- c/archive_check_magic.c +1/−0
- c/archive_entry.c +15/−11
- c/archive_entry.h +2/−2
- c/archive_entry_link_resolver.c +3/−3
- c/archive_entry_xattr.c +5/−5
- c/archive_integer.h +20/−0
- c/archive_options.c +6/−6
- c/archive_pathmatch.c +1/−1
- c/archive_private.h +26/−0
- c/archive_read.c +209/−175
- c/archive_read_append_filter.c +27/−27
- c/archive_read_data_into_fd.c +50/−4
- c/archive_read_disk_posix.c +4/−0
- c/archive_read_disk_set_standard_lookup.c +5/−2
- c/archive_read_disk_windows.c +44/−3
- c/archive_read_open_fd.c +4/−1
- c/archive_read_open_file.c +4/−1
- c/archive_read_open_memory.c +4/−1
- c/archive_read_private.h +12/−3
- c/archive_read_support_filter_bzip2.c +58/−62
- c/archive_read_support_filter_compress.c +108/−109
- c/archive_read_support_filter_grzip.c +8/−8
- c/archive_read_support_filter_gzip.c +92/−101
- c/archive_read_support_filter_lrzip.c +8/−8
- c/archive_read_support_filter_lz4.c +167/−168
- c/archive_read_support_filter_lzop.c +108/−108
- c/archive_read_support_filter_program.c +93/−90
- c/archive_read_support_filter_rpm.c +32/−35
- c/archive_read_support_filter_uu.c +123/−127
- c/archive_read_support_filter_xz.c +143/−148
- c/archive_read_support_filter_zstd.c +47/−51
- c/archive_read_support_format_7zip.c +459/−408
- c/archive_read_support_format_all.c +1/−1
- c/archive_read_support_format_ar.c +55/−92
- c/archive_read_support_format_cab.c +497/−347
- c/archive_read_support_format_cpio.c +16/−19
- c/archive_read_support_format_iso9660.c +64/−89
- c/archive_read_support_format_lha.c +14/−19
- c/archive_read_support_format_mtree.c +13/−74
- c/archive_read_support_format_rar.c +53/−55
- c/archive_read_support_format_rar5.c +4451/−4437
- c/archive_read_support_format_raw.c +34/−31
- c/archive_read_support_format_tar.c +58/−86
- c/archive_read_support_format_warc.c +282/−265
- c/archive_read_support_format_xar.c +135/−102
- c/archive_read_support_format_zip.c +185/−102
- c/archive_string.c +4/−1
- c/archive_write.c +68/−45
- c/archive_write_add_filter_b64encode.c +63/−52
- c/archive_write_add_filter_bzip2.c +105/−95
- c/archive_write_add_filter_compress.c +126/−112
- c/archive_write_add_filter_grzip.c +39/−29
- c/archive_write_add_filter_gzip.c +136/−120
- c/archive_write_add_filter_lrzip.c +49/−39
- c/archive_write_add_filter_lz4.c +241/−233
- c/archive_write_add_filter_lzop.c +140/−120
- c/archive_write_add_filter_program.c +41/−36
- c/archive_write_add_filter_uuencode.c +64/−53
- c/archive_write_add_filter_xz.c +134/−142
- c/archive_write_add_filter_zstd.c +141/−127
- c/archive_write_disk_posix.c +28/−20
- c/archive_write_disk_set_standard_lookup.c +5/−2
- c/archive_write_disk_windows.c +117/−29
- c/archive_write_private.h +3/−1
- c/archive_write_set_format_7zip.c +18/−37
- c/archive_write_set_format_ar.c +34/−63
- c/archive_write_set_format_cpio_binary.c +19/−19
- c/archive_write_set_format_cpio_newc.c +10/−14
- c/archive_write_set_format_cpio_odc.c +20/−19
- c/archive_write_set_format_gnutar.c +28/−16
- c/archive_write_set_format_iso9660.c +26/−39
- c/archive_write_set_format_mtree.c +33/−36
- c/archive_write_set_format_pax.c +199/−45
- c/archive_write_set_format_raw.c +3/−5
- c/archive_write_set_format_shar.c +31/−37
- c/archive_write_set_format_ustar.c +7/−13
- c/archive_write_set_format_v7tar.c +7/−13
- c/archive_write_set_format_warc.c +291/−244
- c/archive_write_set_format_xar.c +135/−58
- c/archive_write_set_format_zip.c +18/−32
- libarchive-clib.cabal +1/−1
c/archive.h view
@@ -34,7 +34,7 @@ * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */-#define ARCHIVE_VERSION_NUMBER 3008008+#define ARCHIVE_VERSION_NUMBER 3008009 #include <sys/stat.h> #include <stddef.h> /* for wchar_t */@@ -177,7 +177,7 @@ /* * Textual name/version of the library, useful for version displays. */-#define ARCHIVE_VERSION_ONLY_STRING "3.8.8"+#define ARCHIVE_VERSION_ONLY_STRING "3.8.9" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void);
c/archive_acl.c view
@@ -1516,7 +1516,7 @@ const char *end; } field[6], name; - const char *s, *st;+ const char *s, *st, *text_end; int numfields, fields, n, r, sol, ret; int type, types, tag, permset, id; size_t len;@@ -1539,6 +1539,7 @@ ret = ARCHIVE_OK; types = 0;+ text_end = (text == NULL) ? text : text + length; while (text != NULL && length > 0 && *text != '\0') { /*@@ -1563,6 +1564,18 @@ if (field[0].start == NULL || field[0].end == NULL) { /* This should never happen */ return (ARCHIVE_FATAL);+ }++ if (field[0].start == text_end) {+ /*+ * Empty entry: next_field() consumed the rest of the+ * buffer as separators or whitespace, leaving+ * field[0].start one past the end. 'text' is not+ * guaranteed to be NUL terminated, so the byte after it+ * must not be dereferenced.+ */+ ret = ARCHIVE_WARN;+ continue; } if (*(field[0].start) == '#') {
c/archive_acl_private.h view
@@ -27,7 +27,9 @@ #define ARCHIVE_ACL_PRIVATE_H_INCLUDED #ifndef __LIBARCHIVE_BUILD+#ifndef __LIBARCHIVE_TEST #error This header is only to be used internally to libarchive.+#endif #endif #include "archive_string.h"
c/archive_check_magic.c view
@@ -85,6 +85,7 @@ case ARCHIVE_STATE_NEW: return ("new"); case ARCHIVE_STATE_HEADER: return ("header"); case ARCHIVE_STATE_DATA: return ("data");+ case ARCHIVE_STATE_DATA_RECOVERY: return ("data_recovery"); case ARCHIVE_STATE_EOF: return ("eof"); case ARCHIVE_STATE_CLOSED: return ("closed"); case ARCHIVE_STATE_FATAL: return ("fatal");
c/archive_entry.c view
@@ -1562,17 +1562,21 @@ archive_entry_copy_mac_metadata(struct archive_entry *entry, const void *p, size_t s) {- free(entry->mac_metadata);- if (p == NULL || s == 0) {- entry->mac_metadata = NULL;- entry->mac_metadata_size = 0;- } else {- entry->mac_metadata_size = s;- entry->mac_metadata = malloc(s);- if (entry->mac_metadata == NULL)- abort();- memcpy(entry->mac_metadata, p, s);- }+ void *metadata;++ if (p == NULL || s == 0) {+ free(entry->mac_metadata);+ entry->mac_metadata = NULL;+ entry->mac_metadata_size = 0;+ } else {+ metadata = malloc(s);+ if (metadata == NULL)+ abort();+ memcpy(metadata, p, s);+ free(entry->mac_metadata);+ entry->mac_metadata = metadata;+ entry->mac_metadata_size = s;+ } } /* Digest handling */
c/archive_entry.h view
@@ -28,7 +28,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */-#define ARCHIVE_VERSION_NUMBER 3008008+#define ARCHIVE_VERSION_NUMBER 3008009 /* * Note: archive_entry.h is for use outside of libarchive; the@@ -666,7 +666,7 @@ la_int64_t /* offset */, la_int64_t /* length */); /*- * To retrieve the xattr list, first "reset", then repeatedly ask for the+ * To retrieve the sparse list, first "reset", then repeatedly ask for the * "next" entry. */
c/archive_entry_link_resolver.c view
@@ -41,6 +41,7 @@ #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h" /* * This is mostly a pretty straightforward hash table implementation.@@ -387,7 +388,7 @@ } /* If the links cache is getting too full, enlarge the hash table. */- if (res->number_entries > res->number_buckets * 2)+ if (res->number_entries / 2 > res->number_buckets) grow_hash(res); hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));@@ -413,8 +414,7 @@ size_t i, bucket; /* Try to enlarge the bucket list. */- new_size = res->number_buckets * 2;- if (new_size < res->number_buckets)+ if (archive_ckd_mul_size(&new_size, res->number_buckets, 2)) return; new_buckets = calloc(new_size, sizeof(struct links_entry *));
c/archive_entry_xattr.c view
@@ -96,11 +96,11 @@ if ((xp->name = strdup(name)) == NULL) __archive_errx(1, "Out of memory"); - if ((xp->value = malloc(size)) != NULL) {- memcpy(xp->value, value, size);- xp->size = size;- } else- xp->size = 0;+ if ((xp->value = malloc(size)) == NULL)+ __archive_errx(1, "Out of memory");++ memcpy(xp->value, value, size);+ xp->size = size; xp->next = entry->xattr_head; entry->xattr_head = xp;
c/archive_integer.h view
@@ -49,6 +49,9 @@ #ifdef HAVE_STDINT_H #include <stdint.h> #endif+#ifdef HAVE_TIME_H+#include <time.h>+#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif@@ -243,5 +246,22 @@ return 0; #endif }++#if !defined(TIME_MAX)+#define TIME_MAX (((time_t)0 < (time_t)-1) ? (time_t)~0 : \+ sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MAX : \+ sizeof(time_t) == sizeof(long) ? (time_t)LONG_MAX : \+ sizeof(time_t) == sizeof(int) ? (time_t)INT_MAX : \+ sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MAX : \+ 1 /* I give up */)+#endif+#if !defined(TIME_MIN)+#define TIME_MIN (((time_t)0 < (time_t)-1) ? (time_t)0 : \+ sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MIN : \+ sizeof(time_t) == sizeof(long) ? (time_t)LONG_MIN : \+ sizeof(time_t) == sizeof(int) ? (time_t)INT_MIN : \+ sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MIN : \+ -1 /* I give up */)+#endif #endif
c/archive_options.c view
@@ -33,7 +33,7 @@ static char * parse_option(char **str,- char **mod, char **opt, char **val);+ const char **mod, const char **opt, const char **val); int _archive_set_option(struct archive *a,@@ -102,8 +102,8 @@ unsigned int magic, const char *fn, option_handler use_option) { int allok = 1, anyok = 0, ignore_mod_err = 0, r;- char *data;- char *s, *mod, *opt, *val;+ char *data, *s;+ const char *mod, *opt, *val; archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); @@ -168,10 +168,10 @@ } static char *-parse_option(char **s, char **m, char **o, char **v)+parse_option(char **s, const char **m, const char **o, const char **v) {- char *end, *mod, *opt, *val;- char *p;+ const char *mod, *val;+ char *end, *opt, *p; end = NULL; mod = NULL;
c/archive_pathmatch.c view
@@ -337,7 +337,7 @@ } if (*end == L']') { /* We found [...], try to match it. */- if (!pm_list_w(p + 1, end, *s, flags))+ if (*s == L'\0' || !pm_list_w(p + 1, end, *s, flags)) return (0); p = end; /* Jump to trailing ']' char. */ break;
c/archive_private.h view
@@ -61,12 +61,38 @@ #define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) #define ARCHIVE_MATCH_MAGIC (0xcad11c9U) +/*+ * Having the state be a bitmask makes it easy to check+ * for combinations of allowed states. These should+ * generally only be used in public API entry points,+ * primarily in archive_read.c, archive_write.c, etc.+ * Internal callbacks can rely on the core machinery+ * to only call them when appropriate.+ *+ * Generally checked via `__archive_check_magic()`.+ */++/* Newly created archive object, not yet opened */ #define ARCHIVE_STATE_NEW 1U+/* Archive is ready to read a header. */ #define ARCHIVE_STATE_HEADER 2U+/* A header has been read: client can ask for data+ * or they can ask for the next header and+ * we'll automatically skip the remaining data. */ #define ARCHIVE_STATE_DATA 4U+/* Similar to STATE_DATA but after a FAILED header:+ * the client may not read data, but they may ask+ * for the next header and we'll recover. */+#define ARCHIVE_STATE_DATA_RECOVERY 8U+/* End-of-archive has been reached. Client can only+ * close or free the archive. */ #define ARCHIVE_STATE_EOF 0x10U+/* Archive is closed; client is only allowed to free the archive. */ #define ARCHIVE_STATE_CLOSED 0x20U+/* Archive is in a FATAL error state: a close request+ * is permitted but ignored. */ #define ARCHIVE_STATE_FATAL 0x8000U+/* Any valid (non-fatal) state. */ #define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL) struct archive_vtable {
c/archive_read.c view
@@ -103,7 +103,12 @@ a->archive.state = ARCHIVE_STATE_NEW; a->entry = archive_entry_new2(&a->archive);+ if (a->entry == NULL) {+ free(a);+ return (NULL);+ } a->archive.vtable = &archive_read_vtable;+ a->entry_bytes_declared = -1; a->passphrases.last = &a->passphrases.first; @@ -135,12 +140,16 @@ archive_open_callback *client_opener, archive_read_callback *client_reader, archive_close_callback *client_closer) {+ int r;+ /* Old archive_read_open() is just a thin shell around * archive_read_open1. */ archive_read_set_open_callback(a, client_opener); archive_read_set_read_callback(a, client_reader); archive_read_set_close_callback(a, client_closer);- archive_read_set_callback_data(a, client_data);+ r = archive_read_set_callback_data(a, client_data);+ if (r < 0)+ return (r); return archive_read_open1(a); } @@ -152,9 +161,13 @@ archive_skip_callback *client_skipper, archive_close_callback *client_closer) {+ int r;+ /* Old archive_read_open2() is just a thin shell around * archive_read_open1. */- archive_read_set_callback_data(a, client_data);+ r = archive_read_set_callback_data(a, client_data);+ if (r < 0)+ return (r); archive_read_set_open_callback(a, client_opener); archive_read_set_read_callback(a, client_reader); archive_read_set_skip_callback(a, client_skipper);@@ -163,28 +176,28 @@ } static ssize_t-client_read_proxy(struct archive_read_filter *self, const void **buff)+client_read_proxy(struct archive_read_filter *f, const void **buff) { ssize_t r;- r = (self->archive->client.reader)(&self->archive->archive,- self->data, buff);+ r = (f->archive->client.reader)(&f->archive->archive,+ f->data, buff); return (r); } static int64_t-client_skip_proxy(struct archive_read_filter *self, int64_t request)+client_skip_proxy(struct archive_read_filter *f, int64_t request) { if (request < 0) __archive_errx(1, "Negative skip requested"); if (request == 0) return 0; - if (self->archive->client.skipper != NULL) {+ if (f->archive->client.skipper != NULL) { int64_t total = 0; for (;;) { int64_t get, ask = request;- get = (self->archive->client.skipper)- (&self->archive->archive, self->data, ask);+ get = (f->archive->client.skipper)+ (&f->archive->archive, f->data, ask); total += get; if (get == 0 || get == request) return (total);@@ -192,7 +205,7 @@ return ARCHIVE_FATAL; request -= get; }- } else if (self->archive->client.seeker != NULL+ } else if (f->archive->client.seeker != NULL && request > 64 * 1024) { /* If the client provided a seeker but not a skipper, * we can use the seeker to skip forward.@@ -205,9 +218,9 @@ * to just reading and discarding. That's why we * only do this for skips of over 64k. */- int64_t before = self->position;- int64_t after = (self->archive->client.seeker)- (&self->archive->archive, self->data, request, SEEK_CUR);+ int64_t before = f->position;+ int64_t after = (f->archive->client.seeker)+ (&f->archive->archive, f->data, request, SEEK_CUR); if (after != before + request) return ARCHIVE_FATAL; return after - before;@@ -216,20 +229,20 @@ } static int64_t-client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)+client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence) { /* DO NOT use the skipper here! If we transparently handled * forward seek here by using the skipper, that will break * other libarchive code that assumes a successful forward * seek means it can also seek backwards. */- if (self->archive->client.seeker == NULL) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ if (f->archive->client.seeker == NULL) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Current client reader does not support seeking a device"); return (ARCHIVE_FAILED); }- return (self->archive->client.seeker)(&self->archive->archive,- self->data, offset, whence);+ return (f->archive->client.seeker)(&f->archive->archive,+ f->data, offset, whence); } static int@@ -251,21 +264,21 @@ } static int-client_close_proxy(struct archive_read_filter *self)+client_close_proxy(struct archive_read_filter *f) {- return read_client_close_proxy(self->archive);+ return read_client_close_proxy(f->archive); } static int-client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)+client_switch_proxy(struct archive_read_filter *f, unsigned int iindex) { struct archive_read *a; int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; void *data2; - while (self->upstream != NULL)- self = self->upstream;- a = self->archive;+ while (f->upstream != NULL)+ f = f->upstream;+ a = f->archive; /* Don't do anything if already in the specified data node */ if (a->client.cursor == iindex)@@ -276,19 +289,19 @@ if (a->client.switcher != NULL) { r1 = r2 = (a->client.switcher)- ((struct archive *)a, self->data, data2);- self->data = data2;+ ((struct archive *)a, f->data, data2);+ f->data = data2; } else { /* Attempt to call close and open instead */ if (a->client.closer != NULL) r1 = (a->client.closer)- ((struct archive *)a, self->data);- self->data = data2;+ ((struct archive *)a, f->data);+ f->data = data2; if (a->client.opener != NULL) r2 = (a->client.opener)- ((struct archive *)a, self->data);+ ((struct archive *)a, f->data); } return (r1 < r2) ? r1 : r2; }@@ -469,7 +482,7 @@ archive_read_open1(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a;- struct archive_read_filter *filter, *tmp;+ struct archive_read_filter *f, *tmp; int slot, e = ARCHIVE_OK; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,@@ -493,23 +506,23 @@ } } - filter = calloc(1, sizeof(*filter));- if (filter == NULL)+ f = calloc(1, sizeof(*f));+ if (f == NULL) return (ARCHIVE_FATAL);- filter->bidder = NULL;- filter->upstream = NULL;- filter->archive = a;- filter->data = a->client.dataset[0].data;- filter->vtable = &none_reader_vtable;- filter->name = "none";- filter->code = ARCHIVE_FILTER_NONE;- filter->can_skip = 1;- filter->can_seek = 1;+ f->bidder = NULL;+ f->upstream = NULL;+ f->archive = a;+ f->data = a->client.dataset[0].data;+ f->vtable = &none_reader_vtable;+ f->name = "none";+ f->code = ARCHIVE_FILTER_NONE;+ f->can_skip = 1;+ f->can_seek = 1; a->client.dataset[0].begin_position = 0; if (!a->filter || !a->bypass_filter_bidding) {- a->filter = filter;+ a->filter = f; /* Build out the input pipeline. */ e = choose_filters(a); if (e < ARCHIVE_WARN) {@@ -523,7 +536,7 @@ tmp = a->filter; while (tmp->upstream) tmp = tmp->upstream;- tmp->upstream = filter;+ tmp->upstream = f; } if (!a->format)@@ -558,7 +571,7 @@ { int number_bidders, i, bid, best_bid, number_filters; struct archive_read_filter_bidder *bidder, *best_bidder;- struct archive_read_filter *filter;+ struct archive_read_filter *f; ssize_t avail; int r; @@ -590,13 +603,13 @@ return (ARCHIVE_OK); } - filter = calloc(1, sizeof(*filter));- if (filter == NULL)+ f = calloc(1, sizeof(*f));+ if (f == NULL) return (ARCHIVE_FATAL);- filter->bidder = best_bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;+ f->bidder = best_bidder;+ f->archive = a;+ f->upstream = a->filter;+ a->filter = f; r = (best_bidder->vtable->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_free_filters(a);@@ -626,7 +639,8 @@ int r1 = ARCHIVE_OK, r2; archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA |+ ARCHIVE_STATE_DATA_RECOVERY, "archive_read_next_header"); archive_entry_clear(entry);@@ -635,8 +649,12 @@ /* * If client didn't consume entire data, skip any remainder * (This is especially important for GNU incremental directories.)+ * A header that failed to parse (DATA_RECOVERY) still needs the+ * same treatment: whatever of its body the format reader left+ * unconsumed must be skipped before we can read the next header. */- if (a->archive.state == ARCHIVE_STATE_DATA) {+ if (a->archive.state == ARCHIVE_STATE_DATA ||+ a->archive.state == ARCHIVE_STATE_DATA_RECOVERY) { r1 = archive_read_data_skip(&a->archive); if (r1 == ARCHIVE_EOF) archive_set_error(&a->archive, EIO,@@ -674,8 +692,26 @@ case ARCHIVE_FATAL: a->archive.state = ARCHIVE_STATE_FATAL; break;+ case ARCHIVE_FAILED:+ /*+ * This entry's header could not be parsed, so its metadata+ * cannot be trusted. ARCHIVE_STATE_DATA_RECOVERY still+ * permits skipping past it (the format reader is+ * responsible for ensuring that's actually possible), but+ * blocks archive_read_data() and friends, which all check+ * for ARCHIVE_STATE_DATA specifically and would otherwise+ * return content for an entry we don't actually understand.+ */+ a->archive.state = ARCHIVE_STATE_DATA_RECOVERY;+ break; } + if (r2 == ARCHIVE_OK || r2 == ARCHIVE_WARN)+ a->entry_bytes_declared = archive_entry_size_is_set(entry)+ ? archive_entry_size(entry) : -1;+ else+ a->entry_bytes_declared = -1;+ __archive_reset_read_data(&a->archive); a->data_start_node = a->client.cursor;@@ -764,7 +800,7 @@ /* * Returns 1 if the archive contains at least one encrypted entry.- * If the archive format not support encryption at all+ * If the archive format does not support encryption at all, * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. * If for any other reason (e.g. not enough data read so far) * we cannot say whether there are encrypted entries, then@@ -934,7 +970,8 @@ size_t size; int64_t offset; - archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,+ ARCHIVE_STATE_DATA | ARCHIVE_STATE_DATA_RECOVERY, "archive_read_data_skip"); if (a->format->read_data_skip != NULL)@@ -966,11 +1003,9 @@ "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");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "Cannot seek data with this format");+ return (ARCHIVE_FAILED); } r = (a->format->seek_data)(a, offset, whence);@@ -1347,13 +1382,13 @@ } const void *-__archive_read_filter_ahead(struct archive_read_filter *filter,+__archive_read_filter_ahead(struct archive_read_filter *f, size_t min, ssize_t *avail) { ssize_t bytes_read; size_t tocopy; - if (filter->fatal) {+ if (f->fatal) { if (avail) *avail = ARCHIVE_FATAL; return (NULL);@@ -1370,79 +1405,79 @@ * note that min == 0 is a perfectly well-defined * request. */- if (filter->avail >= min && filter->avail > 0) {+ if (f->avail >= min && f->avail > 0) { if (avail != NULL)- *avail = filter->avail;- return (filter->next);+ *avail = f->avail;+ return (f->next); } /* * We can satisfy directly from client buffer if everything * currently in the copy buffer is still in the client buffer. */- if (filter->client_total >= filter->client_avail + filter->avail- && filter->client_avail + filter->avail >= min) {+ if (f->client_total >= f->client_avail + f->avail+ && f->client_avail + f->avail >= min) { /* "Roll back" to client buffer. */- filter->client_avail += filter->avail;- filter->client_next -= filter->avail;+ f->client_avail += f->avail;+ f->client_next -= f->avail; /* Copy buffer is now empty. */- filter->avail = 0;- filter->next = filter->buffer;+ f->avail = 0;+ f->next = f->buffer; /* Return data from client buffer. */ if (avail != NULL)- *avail = filter->client_avail;- return (filter->client_next);+ *avail = f->client_avail;+ return (f->client_next); } /* Move data forward in copy buffer if necessary. */- if (filter->next > filter->buffer &&- min > filter->buffer_size - (filter->next - filter->buffer)) {- if (filter->avail > 0)- memmove(filter->buffer, filter->next,- filter->avail);- filter->next = filter->buffer;+ if (f->next > f->buffer &&+ min > f->buffer_size - (f->next - f->buffer)) {+ if (f->avail > 0)+ memmove(f->buffer, f->next,+ f->avail);+ f->next = f->buffer; } /* If we've used up the client data, get more. */- if (filter->client_avail <= 0) {- if (filter->end_of_file) {+ if (f->client_avail <= 0) {+ if (f->end_of_file) { if (avail != NULL)- *avail = filter->avail;+ *avail = f->avail; return (NULL); }- bytes_read = (filter->vtable->read)(filter,- &filter->client_buff);+ bytes_read = (f->vtable->read)(f,+ &f->client_buff); if (bytes_read < 0) { /* Read error. */- filter->client_total = filter->client_avail = 0;- filter->client_next =- filter->client_buff = NULL;- filter->fatal = 1;+ f->client_total = f->client_avail = 0;+ f->client_next =+ f->client_buff = NULL;+ f->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); } if (bytes_read == 0) { /* Check for another client object first */- if (filter->archive->client.cursor !=- filter->archive->client.nodes - 1) {- if (client_switch_proxy(filter,- filter->archive->client.cursor + 1)+ if (f->archive->client.cursor !=+ f->archive->client.nodes - 1) {+ if (client_switch_proxy(f,+ f->archive->client.cursor + 1) == ARCHIVE_OK) continue; } /* Premature end-of-file. */- filter->client_total = filter->client_avail = 0;- filter->client_next =- filter->client_buff = NULL;- filter->end_of_file = 1;+ f->client_total = f->client_avail = 0;+ f->client_next =+ f->client_buff = NULL;+ f->end_of_file = 1; /* Return whatever we do have. */ if (avail != NULL)- *avail = filter->avail;+ *avail = f->avail; return (NULL); }- filter->client_total = bytes_read;- filter->client_avail = filter->client_total;- filter->client_next = filter->client_buff;+ f->client_total = bytes_read;+ f->client_avail = f->client_total;+ f->client_next = f->client_buff; } else { /* * We can't satisfy the request from the copy@@ -1452,67 +1487,66 @@ */ /* Ensure the buffer is big enough. */- if (min > filter->buffer_size) {- size_t s, t;+ if (min > f->buffer_size) {+ size_t s; char *p; /* Double the buffer; watch for overflow. */- s = t = filter->buffer_size;+ s = f->buffer_size; if (s == 0) s = min; while (s < min) {- t *= 2;- if (t <= s) { /* Integer overflow! */+ if (archive_ckd_mul_size(&s, s, 2)) {+ /* Integer overflow! */ archive_set_error(- &filter->archive->archive,+ &f->archive->archive, ENOMEM, "Unable to allocate copy" " buffer");- filter->fatal = 1;+ f->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); }- s = t; } /* Now s >= min, so allocate a new buffer. */ p = malloc(s); if (p == NULL) { archive_set_error(- &filter->archive->archive,+ &f->archive->archive, ENOMEM, "Unable to allocate copy buffer");- filter->fatal = 1;+ f->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); } /* Move data into newly-enlarged buffer. */- if (filter->avail > 0)- memmove(p, filter->next, filter->avail);- free(filter->buffer);- filter->next = filter->buffer = p;- filter->buffer_size = s;+ if (f->avail > 0)+ memmove(p, f->next, f->avail);+ free(f->buffer);+ f->next = f->buffer = p;+ f->buffer_size = s; } /* We can add client data to copy buffer. */ /* First estimate: copy to fill rest of buffer. */- tocopy = (filter->buffer + filter->buffer_size)- - (filter->next + filter->avail);+ tocopy = (f->buffer + f->buffer_size)+ - (f->next + f->avail); /* Don't waste time buffering more than we need to. */- if (tocopy + filter->avail > min)- tocopy = min - filter->avail;+ if (tocopy + f->avail > min)+ tocopy = min - f->avail; /* Don't copy more than is available. */- if (tocopy > filter->client_avail)- tocopy = filter->client_avail;+ if (tocopy > f->client_avail)+ tocopy = f->client_avail; - memcpy(filter->next + filter->avail,- filter->client_next, tocopy);+ memcpy(f->next + f->avail,+ f->client_next, tocopy); /* Remove this data from client buffer. */- filter->client_next += tocopy;- filter->client_avail -= tocopy;+ f->client_next += tocopy;+ f->client_avail -= tocopy; /* add it to copy buffer. */- filter->avail += tocopy;+ f->avail += tocopy; } } }@@ -1527,7 +1561,7 @@ } int64_t-__archive_read_filter_consume(struct archive_read_filter * filter,+__archive_read_filter_consume(struct archive_read_filter *f, int64_t request) { int64_t skipped;@@ -1537,13 +1571,13 @@ if (request == 0) return 0; - skipped = advance_file_pointer(filter, request);+ skipped = advance_file_pointer(f, request); if (skipped == request) return (skipped); /* We hit EOF before we satisfied the skip request. */ if (skipped < 0) /* Map error code to 0 for error message below. */ skipped = 0;- archive_set_error(&filter->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Truncated input file (needed %jd bytes, only %jd available)", (intmax_t)request, (intmax_t)skipped);@@ -1557,45 +1591,45 @@ * Returns a negative value if there's an I/O error. */ static int64_t-advance_file_pointer(struct archive_read_filter *filter, int64_t request)+advance_file_pointer(struct archive_read_filter *f, int64_t request) { int64_t bytes_skipped, total_bytes_skipped = 0; ssize_t bytes_read; size_t min; - if (filter->fatal)+ if (f->fatal) return (-1); /* Use up the copy buffer first. */- if (filter->avail > 0) {- min = (size_t)minimum(request, (int64_t)filter->avail);- filter->next += min;- filter->avail -= min;+ if (f->avail > 0) {+ min = (size_t)minimum(request, (int64_t)f->avail);+ f->next += min;+ f->avail -= min; request -= min;- filter->position += min;+ f->position += min; total_bytes_skipped += min; } /* Then use up the client buffer. */- if (filter->client_avail > 0) {- min = (size_t)minimum(request, (int64_t)filter->client_avail);- filter->client_next += min;- filter->client_avail -= min;+ if (f->client_avail > 0) {+ min = (size_t)minimum(request, (int64_t)f->client_avail);+ f->client_next += min;+ f->client_avail -= min; request -= min;- filter->position += min;+ f->position += min; total_bytes_skipped += min; } if (request == 0) return (total_bytes_skipped); /* If there's an optimized skip function, use it. */- if (filter->can_skip != 0) {- bytes_skipped = client_skip_proxy(filter, request);+ if (f->can_skip != 0) {+ bytes_skipped = client_skip_proxy(f, request); if (bytes_skipped < 0) { /* error */- filter->fatal = 1;+ f->fatal = 1; return (bytes_skipped); }- filter->position += bytes_skipped;+ f->position += bytes_skipped; total_bytes_skipped += bytes_skipped; request -= bytes_skipped; if (request == 0)@@ -1604,37 +1638,37 @@ /* Use ordinary reads as necessary to complete the request. */ for (;;) {- bytes_read = (filter->vtable->read)(filter, &filter->client_buff);+ bytes_read = (f->vtable->read)(f, &f->client_buff); if (bytes_read < 0) {- filter->client_buff = NULL;- filter->fatal = 1;+ f->client_buff = NULL;+ f->fatal = 1; return (bytes_read); } if (bytes_read == 0) {- if (filter->archive->client.cursor !=- filter->archive->client.nodes - 1) {- if (client_switch_proxy(filter,- filter->archive->client.cursor + 1)+ if (f->archive->client.cursor !=+ f->archive->client.nodes - 1) {+ if (client_switch_proxy(f,+ f->archive->client.cursor + 1) == ARCHIVE_OK) continue; }- filter->client_buff = NULL;- filter->end_of_file = 1;+ f->client_buff = NULL;+ f->end_of_file = 1; return (total_bytes_skipped); } if (bytes_read >= request) {- filter->client_next =- ((const char *)filter->client_buff) + request;- filter->client_avail = (size_t)(bytes_read - request);- filter->client_total = bytes_read;+ f->client_next =+ ((const char *)f->client_buff) + request;+ f->client_avail = (size_t)(bytes_read - request);+ f->client_total = bytes_read; total_bytes_skipped += request;- filter->position += request;+ f->position += request; return (total_bytes_skipped); } - filter->position += bytes_read;+ f->position += bytes_read; total_bytes_skipped += bytes_read; request -= bytes_read; }@@ -1650,23 +1684,23 @@ } int64_t-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,+__archive_read_filter_seek(struct archive_read_filter *f, int64_t offset, int whence) { struct archive_read_client *client; int64_t r; unsigned int cursor; - if (filter->closed || filter->fatal)+ if (f->closed || f->fatal) return (ARCHIVE_FATAL);- if (filter->can_seek == 0)+ if (f->can_seek == 0) return (ARCHIVE_FAILED); - client = &(filter->archive->client);+ client = &(f->archive->client); switch (whence) { case SEEK_CUR: /* Adjust the offset and use SEEK_SET instead */- offset += filter->position;+ offset += f->position; __LA_FALLTHROUGH; case SEEK_SET: cursor = 0;@@ -1683,10 +1717,10 @@ client->dataset[++cursor].begin_position = r; } while (1) {- r = client_switch_proxy(filter, cursor);+ r = client_switch_proxy(f, cursor); if (r != ARCHIVE_OK) return r;- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)+ if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0) return r; client->dataset[cursor].total_size = r; if (client->dataset[cursor].begin_position +@@ -1701,7 +1735,7 @@ if (offset < 0 || offset > client->dataset[cursor].total_size) return ARCHIVE_FATAL;- if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)+ if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0) return r; break; @@ -1717,10 +1751,10 @@ client->dataset[++cursor].begin_position = r; } while (1) {- r = client_switch_proxy(filter, cursor);+ r = client_switch_proxy(f, cursor); if (r != ARCHIVE_OK) return r;- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)+ if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0) return r; client->dataset[cursor].total_size = r; r = client->dataset[cursor].begin_position +@@ -1741,9 +1775,9 @@ client->dataset[cursor].total_size; } offset = (r + offset) - client->dataset[cursor].begin_position;- if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)+ if ((r = client_switch_proxy(f, cursor)) != ARCHIVE_OK) return r;- r = client_seek_proxy(filter, offset, SEEK_SET);+ r = client_seek_proxy(f, offset, SEEK_SET); if (r < ARCHIVE_OK) return r; break;@@ -1771,10 +1805,10 @@ * size is (r - offset). Can we use that to simplify * the TODO items above? */- filter->avail = filter->client_avail = 0;- filter->next = filter->buffer;- filter->position = r;- filter->end_of_file = 0;+ f->avail = f->client_avail = 0;+ f->next = f->buffer;+ f->position = r;+ f->end_of_file = 0; } return r; }
c/archive_read_append_filter.c view
@@ -38,8 +38,8 @@ { int r1, r2, number_bidders, i; const char *str;- struct archive_read_filter_bidder *bidder;- struct archive_read_filter *filter;+ struct archive_read_filter_bidder *b;+ struct archive_read_filter *f; struct archive_read *a = (struct archive_read *)_a; r2 = (ARCHIVE_OK);@@ -118,30 +118,30 @@ { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - bidder = a->bidders;- for (i = 1; i < number_bidders; i++, bidder++)+ b = a->bidders;+ for (i = 1; i < number_bidders; i++, b++) {- if (!bidder->name || !strcmp(bidder->name, str))+ if (!b->name || !strcmp(b->name, str)) break; }- if (!bidder->name || strcmp(bidder->name, str))+ if (!b->name || strcmp(b->name, str)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: Unable to append filter"); return (ARCHIVE_FATAL); } - filter = calloc(1, sizeof(*filter));- if (filter == NULL)+ f = calloc(1, sizeof(*f));+ if (f == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); }- filter->bidder = bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;- r2 = (bidder->vtable->init)(a->filter);+ f->bidder = b;+ f->archive = a;+ f->upstream = a->filter;+ a->filter = f;+ r2 = (b->vtable->init)(a->filter); if (r2 != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL);@@ -163,8 +163,8 @@ const char *cmd, const void *signature, size_t signature_len) { int r, number_bidders, i;- struct archive_read_filter_bidder *bidder;- struct archive_read_filter *filter;+ struct archive_read_filter_bidder *b;+ struct archive_read_filter *f; struct archive_read *a = (struct archive_read *)_a; if (archive_read_support_filter_program_signature(_a, cmd, signature,@@ -173,36 +173,36 @@ number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - bidder = a->bidders;- for (i = 0; i < number_bidders; i++, bidder++)+ b = a->bidders;+ for (i = 0; i < number_bidders; i++, b++) { /* Program bidder name set to filter name after initialization */- if (bidder->data && !bidder->name)+ if (b->data && !b->name) break; }- if (!bidder->data)+ if (!b->data) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: Unable to append program filter"); return (ARCHIVE_FATAL); } - filter = calloc(1, sizeof(*filter));- if (filter == NULL)+ f = calloc(1, sizeof(*f));+ if (f == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); }- filter->bidder = bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;- r = (bidder->vtable->init)(a->filter);+ f->bidder = b;+ f->archive = a;+ f->upstream = a->filter;+ a->filter = f;+ r = (b->vtable->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); }- bidder->name = a->filter->name;+ b->name = a->filter->name; a->bypass_filter_bidding = 1; return r;
c/archive_read_data_into_fd.c view
@@ -37,6 +37,7 @@ #include "archive.h" #include "archive_private.h"+#include "archive_read_private.h" /* Maximum amount of data to write at one time. */ #define MAX_WRITE (1024 * 1024)@@ -97,12 +98,15 @@ int64_t fd_offset; int64_t target_offset; int64_t actual_offset = 0;+ int64_t declared_size; int can_lseek; char *nulls = NULL; archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_into_fd"); + declared_size = ((struct archive_read *)a)->entry_bytes_declared;+ can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode); if (can_lseek) { fd_offset = lseek(fd, 0, SEEK_CUR);@@ -113,6 +117,24 @@ while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) == ARCHIVE_OK) { const char *p = buff;+ int overran = 0;++ if (declared_size >= 0) {+ /* We know the expected size, let's enforce that we don't overrun. */+ if (target_offset > declared_size) {+ /* We're already beyond the end? Don't write any more. */+ target_offset = declared_size;+ size = 0;+ overran = 1;+ } else if (size > (uint64_t)(declared_size - target_offset)) {+ /* Above is safe because target_offset <= declared_size */+ /* This block is bigger than the expected remainder */+ size = (size_t)(declared_size - target_offset);+ overran = 1;+ }+ /* Else size <= expected remainder of data and we're OK. */+ }+ if (target_offset > actual_offset) { r = pad_to(a, fd, can_lseek, &nulls, target_offset, actual_offset);@@ -134,13 +156,37 @@ p += bytes_written; size -= bytes_written; }+ if (overran) {+ archive_set_error(a, ARCHIVE_ERRNO_MISC,+ "Actual entry size exceeds the declared size "+ "(%jd); truncated output at the declared size",+ (intmax_t)declared_size);+ r = ARCHIVE_FAILED;+ goto cleanup;+ } } if (r == ARCHIVE_EOF && target_offset > actual_offset) {- r2 = pad_to(a, fd, can_lseek, &nulls,- target_offset, actual_offset);- if (r2 != ARCHIVE_OK)- r = r2;+ int trailing_hole_overran =+ declared_size >= 0 && target_offset > declared_size;+ if (trailing_hole_overran)+ target_offset = declared_size;+ if (target_offset > actual_offset) {+ r2 = pad_to(a, fd, can_lseek, &nulls,+ target_offset, actual_offset);+ if (r2 != ARCHIVE_OK)+ r = r2;+ else+ actual_offset = target_offset;+ }+ if (trailing_hole_overran) {+ archive_set_error(a, ARCHIVE_ERRNO_MISC,+ "Actual entry size exceeds the declared size "+ "(%jd); truncated output at the declared size",+ (intmax_t)declared_size);+ r = ARCHIVE_FAILED;+ goto cleanup;+ } } cleanup:
c/archive_read_disk_posix.c view
@@ -453,6 +453,10 @@ a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = &archive_read_disk_vtable; a->entry = archive_entry_new2(&a->archive);+ if (a->entry == NULL) {+ free(a);+ return (NULL);+ } a->lookup_uname = trivial_lookup_uname; a->lookup_gname = trivial_lookup_gname; a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
c/archive_read_disk_set_standard_lookup.c view
@@ -45,6 +45,7 @@ #endif #include "archive.h"+#include "archive_integer.h" #if defined(_WIN32) && !defined(__CYGWIN__) int@@ -209,7 +210,8 @@ * we just double it and try again. Because the buffer * is kept around in the cache object, we shouldn't * have to do this very often. */- nbuff_size = cache->buff_size * 2;+ if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))+ break; nbuff = realloc(cache->buff, nbuff_size); if (nbuff == NULL) break;@@ -276,7 +278,8 @@ /* ERANGE means our buffer was too small, but POSIX * doesn't tell us how big the buffer should be, so * we just double it and try again. */- nbuff_size = cache->buff_size * 2;+ if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))+ break; nbuff = realloc(cache->buff, nbuff_size); if (nbuff == NULL) break;
c/archive_read_disk_windows.c view
@@ -37,10 +37,11 @@ #include <winioctl.h> #include "archive.h"-#include "archive_string.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_disk_private.h"+#include "archive_string.h" #include "archive_time_private.h" #ifndef O_BINARY@@ -151,6 +152,8 @@ size_t dirname_length; int depth;+ /* Whether this tree began as a wildcard search */+ int rootwild; BY_HANDLE_FILE_INFORMATION lst; BY_HANDLE_FILE_INFORMATION st;@@ -555,6 +558,10 @@ a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = &archive_read_disk_vtable; a->entry = archive_entry_new2(&a->archive);+ if (a->entry == NULL) {+ free(a);+ return (NULL);+ } a->lookup_uname = trivial_lookup_uname; a->lookup_gname = trivial_lookup_gname; a->flags = ARCHIVE_READDISK_MAC_COPYFILE;@@ -926,7 +933,27 @@ case 0: return (ARCHIVE_EOF); case TREE_POSTDESCENT:+ if (t->depth == 1 && t->rootwild && t->symlink_mode == 'H') {+ /*+ * We have descended from a directory at depth 0 specified by a+ * wildcard search in 'H'ybrid link mode. All items under this+ * directory should be 'P'hysical.+ */+ t->symlink_mode = 'P';+ a->follow_symlinks = 0;+ }+ break; case TREE_POSTASCENT:+ if (t->depth == 0 && t->rootwild && t->initial_symlink_mode == 'H') {+ /*+ * We have returned to the root of a wildcard search, in 'H'ybrid+ * mode, so restore the symlink mode we overwrote in+ * TREE_POSTDESCENT.+ */+ t->symlink_mode = t->initial_symlink_mode;+ /* Mimics setup done in setup_symlink_mode */+ a->follow_symlinks = 1;+ } break; case TREE_REGULAR: lst = tree_current_lstat(t);@@ -966,7 +993,14 @@ switch(t->symlink_mode) { case 'H': /* 'H': After the first item, rest like 'P'. */- t->symlink_mode = 'P';+ if (!t->rootwild) {+ /*+ * 'H': When we started with a wildcard, entries at the starting+ * depth should be kept in `H` mode; switching into 'P' mode+ * is handled in TREE_POSTDESCENT when we enter depth = 1.+ */+ t->symlink_mode = 'P';+ } /* 'H': First item (from command line) like 'L'. */ /* FALLTHROUGH */ case 'L':@@ -1733,6 +1767,7 @@ t->full_path_dir_length = 0; t->dirname_length = 0; t->depth = 0;+ t->rootwild = 0; t->descend = 0; t->current = NULL; t->d = INVALID_HANDLE_VALUE;@@ -1786,6 +1821,7 @@ t->full_path.length = wcslen(t->full_path.s); t->full_path_dir_length = archive_strlen(&t->full_path); }+ t->rootwild = 1; } tree_push(t, base, t->full_path.s, 0, 0, 0, NULL); archive_wstring_free(&ws);@@ -2505,7 +2541,12 @@ (DWORD)outranges_size, &retbytes, NULL); if (ret == 0 && GetLastError() == ERROR_MORE_DATA) { free(outranges);- outranges_size *= 2;+ if (archive_ckd_mul_size(&outranges_size, outranges_size, 2)) {+ archive_set_error(&a->archive, ENOMEM,+ "Couldn't allocate memory");+ exit_sts = ARCHIVE_FATAL;+ goto exit_setup_sparse;+ } outranges = (FILE_ALLOCATED_RANGE_BUFFER *) malloc(outranges_size); if (outranges == NULL) {
c/archive_read_open_fd.c view
@@ -69,6 +69,7 @@ la_seek_stat_t st; struct read_fd_data *mine; void *b;+ int r; archive_clear_error(a); if (la_seek_fstat(fd, &st) != 0) {@@ -107,7 +108,9 @@ archive_read_set_skip_callback(a, file_skip); archive_read_set_seek_callback(a, file_seek); archive_read_set_close_callback(a, file_close);- archive_read_set_callback_data(a, mine);+ r = archive_read_set_callback_data(a, mine);+ if (r < 0)+ return (r); return (archive_read_open1(a)); }
c/archive_read_open_file.c view
@@ -70,6 +70,7 @@ struct read_FILE_data *mine; size_t block_size = 128 * 1024; void *b;+ int r; archive_clear_error(a); mine = calloc(1, sizeof(*mine));@@ -104,7 +105,9 @@ archive_read_set_skip_callback(a, FILE_skip); archive_read_set_seek_callback(a, FILE_seek); archive_read_set_close_callback(a, FILE_close);- archive_read_set_callback_data(a, mine);+ r = archive_read_set_callback_data(a, mine);+ if (r < 0)+ return (r); return (archive_read_open1(a)); }
c/archive_read_open_memory.c view
@@ -68,6 +68,7 @@ size_t size, size_t read_size) { struct read_memory_data *mine;+ int r; mine = calloc(1, sizeof(*mine)); if (mine == NULL) {@@ -82,7 +83,9 @@ archive_read_set_seek_callback(a, memory_read_seek); archive_read_set_skip_callback(a, memory_read_skip); archive_read_set_close_callback(a, memory_read_close);- archive_read_set_callback_data(a, mine);+ r = archive_read_set_callback_data(a, mine);+ if (r < 0)+ return (r); return (archive_read_open1(a)); }
c/archive_read_private.h view
@@ -76,10 +76,10 @@ struct archive_read_filter_vtable { /* Return next block. */ ssize_t (*read)(struct archive_read_filter *, const void **);- /* Close (just this filter) and free(self). */- int (*close)(struct archive_read_filter *self);+ /* Close (just this filter) and free(filter). */+ int (*close)(struct archive_read_filter *); /* Read any header metadata if available. */- int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);+ int (*read_header)(struct archive_read_filter *, struct archive_entry *); }; /*@@ -179,6 +179,15 @@ /* File offset of beginning of most recently-read header. */ int64_t header_position;++ /*+ * Declared uncompressed size of the entry whose header was most+ * recently read, or -1 if no size was declared. Lets format-+ * agnostic consumers like archive_read_data_into_fd() cap their+ * output at the size an entry actually promised, regardless of+ * whether the format reader enforces that itself.+ */+ int64_t entry_bytes_declared; /* Nodes and offsets of compressed data block */ unsigned int data_start_node;
c/archive_read_support_filter_bzip2.c view
@@ -50,7 +50,7 @@ #include "archive_read_private.h" #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-struct private_data {+struct bzip2 { bz_stream stream; char *out_block; size_t out_block_size;@@ -112,15 +112,15 @@ * from verifying as much as we would like. */ static int-bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)+bzip2_reader_bid(struct archive_read_filter_bidder *b, struct archive_read_filter *f) { const unsigned char *buffer; int bits_checked; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ /* Minimal bzip2 archive is 14 bytes. */- buffer = __archive_read_filter_ahead(filter, 14, NULL);+ buffer = __archive_read_filter_ahead(f, 14, NULL); if (buffer == NULL) return (0); @@ -156,16 +156,16 @@ * in case that's available. */ static int-bzip2_reader_init(struct archive_read_filter *self)+bzip2_reader_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "bzip2 -d");+ r = __archive_read_program(f, "bzip2 -d"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_BZIP2;- self->name = "bzip2";+ f->code = ARCHIVE_FILTER_BZIP2;+ f->name = "bzip2"; return (r); } @@ -182,29 +182,29 @@ * Setup the callbacks. */ static int-bzip2_reader_init(struct archive_read_filter *self)+bzip2_reader_init(struct archive_read_filter *f) { static const size_t out_block_size = 64 * 1024; void *out_block;- struct private_data *state;+ struct bzip2 *bzip2; - self->code = ARCHIVE_FILTER_BZIP2;- self->name = "bzip2";+ f->code = ARCHIVE_FILTER_BZIP2;+ f->name = "bzip2"; - state = calloc(1, sizeof(*state));+ bzip2 = calloc(1, sizeof(*bzip2)); out_block = malloc(out_block_size);- if (state == NULL || out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ if (bzip2 == NULL || out_block == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for bzip2 decompression"); free(out_block);- free(state);+ free(bzip2); return (ARCHIVE_FATAL); } - self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &bzip2_reader_vtable;+ f->data = bzip2;+ bzip2->out_block_size = out_block_size;+ bzip2->out_block = out_block;+ f->vtable = &bzip2_reader_vtable; return (ARCHIVE_OK); }@@ -213,44 +213,42 @@ * Return the next block of decompressed data. */ static ssize_t-bzip2_filter_read(struct archive_read_filter *self, const void **p)+bzip2_filter_read(struct archive_read_filter *f, const void **p) {- struct private_data *state;+ struct bzip2 *bzip2 = f->data; size_t decompressed; const char *read_buf; ssize_t ret; - state = (struct private_data *)self->data;-- if (state->eof) {+ if (bzip2->eof) { *p = NULL; return (0); } /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = (uint32_t)state->out_block_size;+ bzip2->stream.next_out = bzip2->out_block;+ bzip2->stream.avail_out = (uint32_t)bzip2->out_block_size; /* Try to fill the output buffer. */ for (;;) { ssize_t max_in; - if (!state->valid) {- if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {- state->eof = 1;- *p = state->out_block;- decompressed = state->stream.next_out- - state->out_block;+ if (!bzip2->valid) {+ if (bzip2_reader_bid(f->bidder, f->upstream) == 0) {+ bzip2->eof = 1;+ *p = bzip2->out_block;+ decompressed = bzip2->stream.next_out+ - bzip2->out_block; return (decompressed); } /* Initialize compression library. */- ret = BZ2_bzDecompressInit(&(state->stream),+ ret = BZ2_bzDecompressInit(&(bzip2->stream), 0 /* library verbosity */, 0 /* don't use low-mem algorithm */); /* If init fails, try low-memory algorithm instead. */ if (ret == BZ_MEM_ERROR)- ret = BZ2_bzDecompressInit(&(state->stream),+ ret = BZ2_bzDecompressInit(&(bzip2->stream), 0 /* library verbosity */, 1 /* do use low-mem algo */); @@ -269,63 +267,63 @@ detail = "mis-compiled library"; break; }- archive_set_error(&self->archive->archive, err,+ archive_set_error(&f->archive->archive, err, "Internal error initializing decompressor%s%s", detail == NULL ? "" : ": ", detail); return (ARCHIVE_FATAL); }- state->valid = 1;+ bzip2->valid = 1; } /* stream.next_in is really const, but bzlib * doesn't declare it so. <sigh> */ read_buf =- __archive_read_filter_ahead(self->upstream, 1, &ret);+ __archive_read_filter_ahead(f->upstream, 1, &ret); if (read_buf == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated bzip2 input"); return (ARCHIVE_FATAL); }- state->stream.next_in = (char *)(uintptr_t)read_buf;+ bzip2->stream.next_in = (char *)(uintptr_t)read_buf; if (UINT_MAX >= SSIZE_MAX) max_in = SSIZE_MAX; else max_in = UINT_MAX; if (ret > max_in) ret = max_in;- state->stream.avail_in = (uint32_t)ret;+ bzip2->stream.avail_in = (uint32_t)ret; /* Decompress as much as we can in one pass. */- ret = BZ2_bzDecompress(&(state->stream));- __archive_read_filter_consume(self->upstream,- state->stream.next_in - read_buf);+ ret = BZ2_bzDecompress(&(bzip2->stream));+ __archive_read_filter_consume(f->upstream,+ bzip2->stream.next_in - read_buf); switch (ret) { case BZ_STREAM_END: /* Found end of stream. */- switch (BZ2_bzDecompressEnd(&(state->stream))) {+ switch (BZ2_bzDecompressEnd(&(bzip2->stream))) { case BZ_OK: break; default:- archive_set_error(&(self->archive->archive),+ archive_set_error(&(f->archive->archive), ARCHIVE_ERRNO_MISC, "Failed to clean up decompressor"); return (ARCHIVE_FATAL); }- state->valid = 0;+ bzip2->valid = 0; /* FALLTHROUGH */ case BZ_OK: /* Decompressor made some progress. */ /* If we filled our buffer, update stats and return. */- if (state->stream.avail_out == 0) {- *p = state->out_block;- decompressed = state->stream.next_out- - state->out_block;+ if (bzip2->stream.avail_out == 0) {+ *p = bzip2->out_block;+ decompressed = bzip2->stream.next_out+ - bzip2->out_block; return (decompressed); } break; default: /* Return an error. */- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "bzip decompression failed"); return (ARCHIVE_FATAL); }@@ -336,28 +334,26 @@ * Clean up the decompressor. */ static int-bzip2_filter_close(struct archive_read_filter *self)+bzip2_filter_close(struct archive_read_filter *f) {- struct private_data *state;+ struct bzip2 *bzip2 = f->data; int ret = ARCHIVE_OK; - state = (struct private_data *)self->data;-- if (state->valid) {- switch (BZ2_bzDecompressEnd(&state->stream)) {+ if (bzip2->valid) {+ switch (BZ2_bzDecompressEnd(&bzip2->stream)) { case BZ_OK: break; default:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Failed to clean up decompressor"); ret = ARCHIVE_FATAL; }- state->valid = 0;+ bzip2->valid = 0; } - free(state->out_block);- free(state);+ free(bzip2->out_block);+ free(bzip2); return (ret); }
c/archive_read_support_filter_compress.c view
@@ -90,7 +90,7 @@ * names and structure here don't exactly match those used by compress. */ -struct private_data {+struct compress { /* Input variables. */ const unsigned char *next_in; size_t avail_in;@@ -169,16 +169,16 @@ * This logic returns zero if any part of the signature fails. */ static int-compress_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+compress_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *buffer; int bits_checked; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ /* Shortest valid compress file is 3 bytes. */- buffer = __archive_read_filter_ahead(filter, 3, NULL);+ buffer = __archive_read_filter_ahead(f, 3, NULL); if (buffer == NULL) return (0);@@ -207,69 +207,69 @@ * Setup the callbacks. */ static int-compress_bidder_init(struct archive_read_filter *self)+compress_bidder_init(struct archive_read_filter *f) {- struct private_data *state;+ struct compress *compress; static const size_t out_block_size = 64 * 1024; void *out_block; - self->code = ARCHIVE_FILTER_COMPRESS;- self->name = "compress (.Z)";+ f->code = ARCHIVE_FILTER_COMPRESS;+ f->name = "compress (.Z)"; - state = calloc(1, sizeof(*state));+ compress = calloc(1, sizeof(*compress)); out_block = malloc(out_block_size);- if (state == NULL || out_block == NULL) {+ if (compress == NULL || out_block == NULL) { free(out_block);- free(state);- archive_set_error(&self->archive->archive, ENOMEM,+ free(compress);+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for %s decompression",- self->name);+ f->name); return (ARCHIVE_FATAL); } - self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &compress_reader_vtable;+ f->data = compress;+ compress->out_block_size = out_block_size;+ compress->out_block = out_block;+ f->vtable = &compress_reader_vtable; return (ARCHIVE_OK); } static int-compress_filter_init(struct archive_read_filter *self)+compress_filter_init(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;+ struct compress *compress = f->data; int code; - state->initialized = 1;+ compress->initialized = 1; - (void)getbits(self, 8); /* Skip first signature byte. */- (void)getbits(self, 8); /* Skip second signature byte. */+ (void)getbits(f, 8); /* Skip first signature byte. */+ (void)getbits(f, 8); /* Skip second signature byte. */ /* Get compression parameters. */- code = getbits(self, 8);+ code = getbits(f, 8); if (code < 0 || (code & 0x1f) > 16) {- archive_set_error(&self->archive->archive, -1,+ archive_set_error(&f->archive->archive, -1, "Invalid compressed data"); return (ARCHIVE_FATAL); }- state->maxcode_bits = code & 0x1f;- state->maxcode = (1 << state->maxcode_bits);- state->use_reset_code = code & 0x80;+ compress->maxcode_bits = code & 0x1f;+ compress->maxcode = (1 << compress->maxcode_bits);+ compress->use_reset_code = code & 0x80; /* Initialize decompressor. */- state->free_ent = 256;- state->stackp = state->stack;- if (state->use_reset_code)- state->free_ent++;- state->bits = 9;- state->section_end_code = (1<<state->bits) - 1;- state->oldcode = -1;+ compress->free_ent = 256;+ compress->stackp = compress->stack;+ if (compress->use_reset_code)+ compress->free_ent++;+ compress->bits = 9;+ compress->section_end_code = (1<<compress->bits) - 1;+ compress->oldcode = -1; for (code = 255; code >= 0; code--) {- state->prefix[code] = 0;- state->suffix[code] = code;+ compress->prefix[code] = 0;+ compress->suffix[code] = code; }- next_code(self);+ next_code(f); return (ARCHIVE_OK); }@@ -279,32 +279,31 @@ * as necessary. */ static ssize_t-compress_filter_read(struct archive_read_filter *self, const void **pblock)+compress_filter_read(struct archive_read_filter *f, const void **pblock) {- struct private_data *state;+ struct compress *compress = f->data; unsigned char *p, *start, *end; int ret; - state = (struct private_data *)self->data;- if (!state->initialized) {- ret = compress_filter_init(self);+ if (!compress->initialized) {+ ret = compress_filter_init(f); if (ret != ARCHIVE_OK) return (ret); }- if (state->end_of_stream) {+ if (compress->end_of_stream) { *pblock = NULL; return (0); }- p = start = (unsigned char *)state->out_block;- end = start + state->out_block_size;+ p = start = (unsigned char *)compress->out_block;+ end = start + compress->out_block_size; - while (p < end && !state->end_of_stream) {- if (state->stackp > state->stack) {- *p++ = *--state->stackp;+ while (p < end && !compress->end_of_stream) {+ if (compress->stackp > compress->stack) {+ *p++ = *--compress->stackp; } else {- ret = next_code(self);+ ret = next_code(f); if (ret == -1)- state->end_of_stream = ret;+ compress->end_of_stream = ret; else if (ret != ARCHIVE_OK) return (ret); }@@ -318,12 +317,12 @@ * Close and release the filter. */ static int-compress_filter_close(struct archive_read_filter *self)+compress_filter_close(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;+ struct compress *compress = f->data; - free(state->out_block);- free(state);+ free(compress->out_block);+ free(compress); return (ARCHIVE_OK); } @@ -333,18 +332,18 @@ * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise. */ static int-next_code(struct archive_read_filter *self)+next_code(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;+ struct compress *compress = f->data; int code, newcode; again:- code = newcode = getbits(self, state->bits);+ code = newcode = getbits(f, compress->bits); if (code < 0) return (code); /* If it's a reset code, reset the dictionary. */- if ((code == 256) && state->use_reset_code) {+ if ((code == 256) && compress->use_reset_code) { /* * The original 'compress' implementation blocked its * I/O in a manner that resulted in junk bytes being@@ -352,63 +351,63 @@ * this junk. (Yes, the number of *bytes* to skip is * a function of the current *bit* length.) */- int skip_bytes = state->bits -- (state->bytes_in_section % state->bits);- skip_bytes %= state->bits;- state->bits_avail = 0; /* Discard rest of this byte. */+ int skip_bytes = compress->bits -+ (compress->bytes_in_section % compress->bits);+ skip_bytes %= compress->bits;+ compress->bits_avail = 0; /* Discard rest of this byte. */ while (skip_bytes-- > 0) {- code = getbits(self, 8);+ code = getbits(f, 8); if (code < 0) return (code); } /* Now, actually do the reset. */- state->bytes_in_section = 0;- state->bits = 9;- state->section_end_code = (1 << state->bits) - 1;- state->free_ent = 257;- state->oldcode = -1;+ compress->bytes_in_section = 0;+ compress->bits = 9;+ compress->section_end_code = (1 << compress->bits) - 1;+ compress->free_ent = 257;+ compress->oldcode = -1; goto again; } - if (code > state->free_ent- || (code == state->free_ent && state->oldcode < 0)) {+ if (code > compress->free_ent+ || (code == compress->free_ent && compress->oldcode < 0)) { /* An invalid code is a fatal error. */- archive_set_error(&(self->archive->archive), -1,+ archive_set_error(&(f->archive->archive), -1, "Invalid compressed data"); return (ARCHIVE_FATAL); } /* Special case for KwKwK string. */- if (code >= state->free_ent) {- *state->stackp++ = state->finbyte;- code = state->oldcode;+ if (code >= compress->free_ent) {+ *compress->stackp++ = compress->finbyte;+ code = compress->oldcode; } /* Generate output characters in reverse order. */ while (code >= 256) {- *state->stackp++ = state->suffix[code];- code = state->prefix[code];+ *compress->stackp++ = compress->suffix[code];+ code = compress->prefix[code]; }- *state->stackp++ = state->finbyte = code;+ *compress->stackp++ = compress->finbyte = code; /* Generate the new entry. */- code = state->free_ent;- if (code < state->maxcode && state->oldcode >= 0) {- state->prefix[code] = state->oldcode;- state->suffix[code] = state->finbyte;- ++state->free_ent;+ code = compress->free_ent;+ if (code < compress->maxcode && compress->oldcode >= 0) {+ compress->prefix[code] = compress->oldcode;+ compress->suffix[code] = compress->finbyte;+ ++compress->free_ent; }- if (state->free_ent > state->section_end_code) {- state->bits++;- state->bytes_in_section = 0;- if (state->bits == state->maxcode_bits)- state->section_end_code = state->maxcode;+ if (compress->free_ent > compress->section_end_code) {+ compress->bits++;+ compress->bytes_in_section = 0;+ if (compress->bits == compress->maxcode_bits)+ compress->section_end_code = compress->maxcode; else- state->section_end_code = (1 << state->bits) - 1;+ compress->section_end_code = (1 << compress->bits) - 1; } /* Remember previous code. */- state->oldcode = newcode;+ compress->oldcode = newcode; return (ARCHIVE_OK); } @@ -418,9 +417,9 @@ * -1 indicates end of available data. */ static int-getbits(struct archive_read_filter *self, int n)+getbits(struct archive_read_filter *f, int n) {- struct private_data *state = (struct private_data *)self->data;+ struct compress *compress = f->data; int code; ssize_t ret; static const int mask[] = {@@ -428,31 +427,31 @@ 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; - while (state->bits_avail < n) {- if (state->avail_in <= 0) {- if (state->consume_unnotified) {- __archive_read_filter_consume(self->upstream,- state->consume_unnotified);- state->consume_unnotified = 0;+ while (compress->bits_avail < n) {+ if (compress->avail_in <= 0) {+ if (compress->consume_unnotified) {+ __archive_read_filter_consume(f->upstream,+ compress->consume_unnotified);+ compress->consume_unnotified = 0; }- state->next_in- = __archive_read_filter_ahead(self->upstream,+ compress->next_in+ = __archive_read_filter_ahead(f->upstream, 1, &ret); if (ret == 0) return (-1);- if (state->next_in == NULL)+ if (compress->next_in == NULL) return (ARCHIVE_FATAL);- state->consume_unnotified = state->avail_in = ret;+ compress->consume_unnotified = compress->avail_in = ret; }- state->bit_buffer |= *state->next_in++ << state->bits_avail;- state->avail_in--;- state->bits_avail += 8;- state->bytes_in_section++;+ compress->bit_buffer |= *compress->next_in++ << compress->bits_avail;+ compress->avail_in--;+ compress->bits_avail += 8;+ compress->bytes_in_section++; } - code = state->bit_buffer;- state->bit_buffer >>= n;- state->bits_avail -= n;+ code = compress->bit_buffer;+ compress->bit_buffer >>= n;+ compress->bits_avail -= n; return (code & mask[n]); }
c/archive_read_support_filter_grzip.c view
@@ -76,14 +76,14 @@ * Bidder just verifies the header and returns the number of verified bits. */ static int-grzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+grzip_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *p; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), NULL);+ p = __archive_read_filter_ahead(f, sizeof(grzip_magic), NULL); if (p == NULL) return (0); @@ -94,15 +94,15 @@ } static int-grzip_bidder_init(struct archive_read_filter *self)+grzip_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "grzip -d");+ r = __archive_read_program(f, "grzip -d"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_GRZIP;- self->name = "grzip";+ f->code = ARCHIVE_FILTER_GRZIP;+ f->name = "grzip"; return (r); }
c/archive_read_support_filter_gzip.c view
@@ -51,7 +51,7 @@ #include "archive_read_private.h" #ifdef HAVE_ZLIB_H-struct private_data {+struct gzip { z_stream stream; char in_stream; unsigned char *out_block;@@ -120,9 +120,9 @@ #define MAX_FILENAME_LENGTH (1024 * 1024L) #define MAX_COMMENT_LENGTH (1024 * 1024L) static ssize_t-peek_at_header(struct archive_read_filter *filter, int *pbits,+peek_at_header(struct archive_read_filter *f, int *pbits, #ifdef HAVE_ZLIB_H- struct private_data *state+ struct gzip *gzip #else void *state #endif@@ -139,7 +139,7 @@ /* Start by looking at the first ten bytes of the header, which * is all fixed layout. */ len = 10;- p = __archive_read_filter_ahead(filter, len, &avail);+ p = __archive_read_filter_ahead(f, len, &avail); if (p == NULL) return (0); /* We only support deflation- third byte must be 0x08. */@@ -152,8 +152,8 @@ header_flags = p[3]; /* Bytes 4-7 are mod time in little endian. */ #ifdef HAVE_ZLIB_H- if (state)- state->mtime = archive_le32dec(p + 4);+ if (gzip)+ gzip->mtime = archive_le32dec(p + 4); #endif /* Byte 8 is deflate flags. */ /* XXXX TODO: return deflate flags back to consume_header for use@@ -162,7 +162,7 @@ /* Optional extra data: 2 byte length plus variable body. */ if (header_flags & 4) {- p = __archive_read_filter_ahead(filter, len + 2, &avail);+ p = __archive_read_filter_ahead(f, len + 2, &avail); if (p == NULL) return (0); len += archive_le16dec(p + len);@@ -180,7 +180,7 @@ if (avail > MAX_FILENAME_LENGTH) { return (0); }- p = __archive_read_filter_ahead(filter,+ p = __archive_read_filter_ahead(f, len, &avail); } if (p == NULL)@@ -188,10 +188,10 @@ } while (p[len - 1] != 0); #ifdef HAVE_ZLIB_H- if (state) {+ if (gzip) { /* Reset the name in case of repeat header reads. */- free(state->name);- state->name = strdup((const char *)&p[file_start]);+ free(gzip->name);+ gzip->name = strdup((const char *)&p[file_start]); } #endif }@@ -204,7 +204,7 @@ if (avail > MAX_COMMENT_LENGTH) { return (0); }- p = __archive_read_filter_ahead(filter,+ p = __archive_read_filter_ahead(f, len, &avail); } if (p == NULL)@@ -214,7 +214,7 @@ /* Optional header CRC */ if ((header_flags & 2)) {- p = __archive_read_filter_ahead(filter, len + 2, &avail);+ p = __archive_read_filter_ahead(f, len + 2, &avail); if (p == NULL) return (0); #if 0@@ -236,14 +236,14 @@ * Bidder just verifies the header and returns the number of verified bits. */ static int-gzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+gzip_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { int bits_checked; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - if (peek_at_header(filter, &bits_checked, NULL))+ if (peek_at_header(f, &bits_checked, NULL)) return (bits_checked); return (0); }@@ -256,35 +256,33 @@ * in case that's available. */ static int-gzip_bidder_init(struct archive_read_filter *self)+gzip_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "gzip -d");+ r = __archive_read_program(f, "gzip -d"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_GZIP;- self->name = "gzip";+ f->code = ARCHIVE_FILTER_GZIP;+ f->name = "gzip"; return (r); } #else static int-gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)+gzip_read_header(struct archive_read_filter *f, struct archive_entry *entry) {- struct private_data *state;-- state = (struct private_data *)self->data;+ struct gzip *gzip = f->data; /* An mtime of 0 is considered invalid/missing. */- if (state->mtime != 0)- archive_entry_set_mtime(entry, state->mtime, 0);+ if (gzip->mtime != 0)+ archive_entry_set_mtime(entry, gzip->mtime, 0); /* If the name is available, extract it. */- if (state->name)- archive_entry_set_pathname(entry, state->name);+ if (gzip->name)+ archive_entry_set_pathname(entry, gzip->name); return (ARCHIVE_OK); }@@ -302,59 +300,57 @@ * Initialize the filter object. */ static int-gzip_bidder_init(struct archive_read_filter *self)+gzip_bidder_init(struct archive_read_filter *f) {- struct private_data *state;+ struct gzip *gzip; static const size_t out_block_size = 64 * 1024; void *out_block; - self->code = ARCHIVE_FILTER_GZIP;- self->name = "gzip";+ f->code = ARCHIVE_FILTER_GZIP;+ f->name = "gzip"; - state = calloc(1, sizeof(*state));+ gzip = calloc(1, sizeof(*gzip)); out_block = malloc(out_block_size);- if (state == NULL || out_block == NULL) {+ if (gzip == NULL || out_block == NULL) { free(out_block);- free(state);- archive_set_error(&self->archive->archive, ENOMEM,+ free(gzip);+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for gzip decompression"); return (ARCHIVE_FATAL); } - self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &gzip_reader_vtable;+ f->data = gzip;+ gzip->out_block_size = out_block_size;+ gzip->out_block = out_block;+ f->vtable = &gzip_reader_vtable; - state->in_stream = 0; /* We're not actually within a stream yet. */+ gzip->in_stream = 0; /* We're not actually within a stream yet. */ return (ARCHIVE_OK); } static int-consume_header(struct archive_read_filter *self)+consume_header(struct archive_read_filter *f) {- struct private_data *state;+ struct gzip *gzip = f->data; ssize_t avail, max_in; size_t len; int ret; - state = (struct private_data *)self->data;- /* If this is a real header, consume it. */- len = peek_at_header(self->upstream, NULL, state);+ len = peek_at_header(f->upstream, NULL, gzip); if (len == 0) return (ARCHIVE_EOF);- __archive_read_filter_consume(self->upstream, len);+ __archive_read_filter_consume(f->upstream, len); /* Initialize CRC accumulator. */- state->crc = crc32(0L, NULL, 0);+ gzip->crc = crc32(0L, NULL, 0); /* Initialize compression library. */- state->stream.next_in = (unsigned char *)(uintptr_t)- __archive_read_filter_ahead(self->upstream, 1, &avail);+ gzip->stream.next_in = (unsigned char *)(uintptr_t)+ __archive_read_filter_ahead(f->upstream, 1, &avail); if (avail < 0) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Failed to read gzip input"); return (ARCHIVE_FATAL);@@ -365,34 +361,34 @@ max_in = UINT_MAX; if (avail > max_in) avail = max_in;- state->stream.avail_in = (uInt)avail;- ret = inflateInit2(&(state->stream),+ gzip->stream.avail_in = (uInt)avail;+ ret = inflateInit2(&(gzip->stream), -15 /* Don't check for zlib header */); /* Decipher the error code. */ switch (ret) { case Z_OK:- state->in_stream = 1;+ gzip->in_stream = 1; return (ARCHIVE_OK); case Z_STREAM_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing compression library: " "invalid setup parameter"); break; case Z_MEM_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Internal error initializing compression library: " "out of memory"); break; case Z_VERSION_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing compression library: " "invalid library version"); break; default:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing compression library: " " Zlib error %d", ret);@@ -402,59 +398,55 @@ } static int-consume_trailer(struct archive_read_filter *self)+consume_trailer(struct archive_read_filter *f) {- struct private_data *state;+ struct gzip *gzip = f->data; const unsigned char *p; - state = (struct private_data *)self->data;-- state->in_stream = 0;- switch (inflateEnd(&(state->stream))) {+ gzip->in_stream = 0;+ switch (inflateEnd(&(gzip->stream))) { case Z_OK: break; default:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Failed to clean up gzip decompressor"); return (ARCHIVE_FATAL); } /* GZip trailer is a fixed 8 byte structure. */- p = __archive_read_filter_ahead(self->upstream, 8, NULL);+ p = __archive_read_filter_ahead(f->upstream, 8, NULL); if (p == NULL) return (ARCHIVE_FATAL); /* XXX TODO: Verify the length and CRC. */ /* We've verified the trailer, so consume it now. */- __archive_read_filter_consume(self->upstream, 8);+ __archive_read_filter_consume(f->upstream, 8); return (ARCHIVE_OK); } static ssize_t-gzip_filter_read(struct archive_read_filter *self, const void **p)+gzip_filter_read(struct archive_read_filter *f, const void **p) {- struct private_data *state;+ struct gzip *gzip = f->data; size_t decompressed; ssize_t avail_in, max_in; int ret; - state = (struct private_data *)self->data;- /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = (uInt)state->out_block_size;+ gzip->stream.next_out = gzip->out_block;+ gzip->stream.avail_out = (uInt)gzip->out_block_size; /* Try to fill the output buffer. */- while (state->stream.avail_out > 0 && !state->eof) {+ while (gzip->stream.avail_out > 0 && !gzip->eof) { /* If we're not in a stream, read a header * and initialize the decompression library. */- if (!state->in_stream) {- ret = consume_header(self);+ if (!gzip->in_stream) {+ ret = consume_header(f); if (ret == ARCHIVE_EOF) {- state->eof = 1;+ gzip->eof = 1; break; } if (ret < ARCHIVE_OK)@@ -464,10 +456,10 @@ /* Peek at the next available data. */ /* ZLib treats stream.next_in as const but doesn't declare * it so, hence this ugly cast. */- state->stream.next_in = (unsigned char *)(uintptr_t)- __archive_read_filter_ahead(self->upstream, 1, &avail_in);- if (state->stream.next_in == NULL) {- archive_set_error(&self->archive->archive,+ gzip->stream.next_in = (unsigned char *)(uintptr_t)+ __archive_read_filter_ahead(f->upstream, 1, &avail_in);+ if (gzip->stream.next_in == NULL) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated gzip input"); return (ARCHIVE_FATAL);@@ -478,27 +470,27 @@ max_in = UINT_MAX; if (avail_in > max_in) avail_in = max_in;- state->stream.avail_in = (uInt)avail_in;+ gzip->stream.avail_in = (uInt)avail_in; /* Decompress and consume some of that data. */- ret = inflate(&(state->stream), 0);+ ret = inflate(&(gzip->stream), 0); switch (ret) { case Z_OK: /* Decompressor made some progress. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);+ __archive_read_filter_consume(f->upstream,+ avail_in - gzip->stream.avail_in); break; case Z_STREAM_END: /* Found end of stream. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);+ __archive_read_filter_consume(f->upstream,+ avail_in - gzip->stream.avail_in); /* Consume the stream trailer; release the * decompression library. */- ret = consume_trailer(self);+ ret = consume_trailer(f); if (ret < ARCHIVE_OK) return (ret); break; default: /* Return an error. */- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "gzip decompression failed"); return (ARCHIVE_FATAL);@@ -506,11 +498,11 @@ } /* We've read as much as we can. */- decompressed = state->stream.next_out - state->out_block;+ decompressed = gzip->stream.next_out - gzip->out_block; if (decompressed == 0) *p = NULL; else- *p = state->out_block;+ *p = gzip->out_block; return (decompressed); } @@ -518,29 +510,28 @@ * Clean up the decompressor. */ static int-gzip_filter_close(struct archive_read_filter *self)+gzip_filter_close(struct archive_read_filter *f) {- struct private_data *state;+ struct gzip *gzip = f->data; int ret; - state = (struct private_data *)self->data; ret = ARCHIVE_OK; - if (state->in_stream) {- switch (inflateEnd(&(state->stream))) {+ if (gzip->in_stream) {+ switch (inflateEnd(&(gzip->stream))) { case Z_OK: break; default:- archive_set_error(&(self->archive->archive),+ archive_set_error(&(f->archive->archive), ARCHIVE_ERRNO_MISC, "Failed to clean up gzip compressor"); ret = ARCHIVE_FATAL; } } - free(state->name);- free(state->out_block);- free(state);+ free(gzip->name);+ free(gzip->out_block);+ free(gzip); return (ret); }
c/archive_read_support_filter_lrzip.c view
@@ -75,18 +75,18 @@ * Bidder just verifies the header and returns the number of verified bits. */ static int-lrzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+lrzip_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *p; ssize_t len; int i; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ /* Start by looking at the first six bytes of the header, which * is all fixed layout. */ len = 6;- p = __archive_read_filter_ahead(filter, len, NULL);+ p = __archive_read_filter_ahead(f, len, NULL); if (p == NULL) return (0); @@ -105,15 +105,15 @@ } static int-lrzip_bidder_init(struct archive_read_filter *self)+lrzip_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "lrzip -d -q");+ r = __archive_read_program(f, "lrzip -d -q"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LRZIP;- self->name = "lrzip";+ f->code = ARCHIVE_FILTER_LRZIP;+ f->name = "lrzip"; return (r); }
c/archive_read_support_filter_lz4.c view
@@ -57,7 +57,7 @@ #define LZ4_SKIPPABLE_MASK 0xFFFFFFF0 #if defined(HAVE_LIBLZ4)-struct private_data {+struct lz4 { enum { SELECT_STREAM, READ_DEFAULT_STREAM, READ_DEFAULT_BLOCK,@@ -139,8 +139,8 @@ * from verifying as much as we would like. */ static int-lz4_reader_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+lz4_reader_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *buffer; ssize_t avail;@@ -159,7 +159,7 @@ const size_t max_lookahead = 64 * 1024; uint32_t magic_number; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ /* * Zstd and LZ4 skippable frame magic numbers are identical. To@@ -168,7 +168,7 @@ */ /* Minimal lz4 archive is 11 bytes. */- buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size,+ buffer = __archive_read_filter_ahead(f, min_lz4_archive_size, &avail); if (buffer == NULL) return (0);@@ -184,7 +184,7 @@ /* Ensure that we can read another 4 bytes. */ if (offset_in_buffer + 4 > (size_t)avail) {- buffer = __archive_read_filter_ahead(filter,+ buffer = __archive_read_filter_ahead(f, offset_in_buffer + 4, &avail); if (buffer == NULL) return (0);@@ -212,7 +212,7 @@ if (min > max_lookahead) return (0); - buffer = __archive_read_filter_ahead(filter,+ buffer = __archive_read_filter_ahead(f, min, &avail); if (buffer == NULL) return (0); @@ -271,16 +271,16 @@ * in case that's available. */ static int-lz4_reader_init(struct archive_read_filter *self)+lz4_reader_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "lz4 -d -q");+ r = __archive_read_program(f, "lz4 -d -q"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZ4;- self->name = "lz4";+ f->code = ARCHIVE_FILTER_LZ4;+ f->name = "lz4"; return (r); } @@ -297,73 +297,73 @@ * Setup the callbacks. */ static int-lz4_reader_init(struct archive_read_filter *self)+lz4_reader_init(struct archive_read_filter *f) {- struct private_data *state;+ struct lz4 *lz4; - self->code = ARCHIVE_FILTER_LZ4;- self->name = "lz4";+ f->code = ARCHIVE_FILTER_LZ4;+ f->name = "lz4"; - state = calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ lz4 = calloc(1, sizeof(*lz4));+ if (lz4 == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for lz4 decompression"); return (ARCHIVE_FATAL); } - self->data = state;- state->stage = SELECT_STREAM;- self->vtable = &lz4_reader_vtable;+ f->data = lz4;+ lz4->stage = SELECT_STREAM;+ f->vtable = &lz4_reader_vtable; return (ARCHIVE_OK); } static int-lz4_allocate_out_block(struct archive_read_filter *self)+lz4_allocate_out_block(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;- size_t out_block_size = state->flags.block_maximum_size;+ struct lz4 *lz4 = f->data;+ size_t out_block_size = lz4->flags.block_maximum_size; void *out_block; - if (!state->flags.block_independence)+ if (!lz4->flags.block_independence) out_block_size += 64 * 1024;- if (state->out_block_size < out_block_size) {- free(state->out_block);- state->out_block = NULL;+ if (lz4->out_block_size < out_block_size) {+ free(lz4->out_block);+ lz4->out_block = NULL; out_block = malloc(out_block_size); if (out_block == NULL) {- state->out_block_size = 0;- archive_set_error(&self->archive->archive, ENOMEM,+ lz4->out_block_size = 0;+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for lz4 decompression"); return (ARCHIVE_FATAL); }- state->out_block_size = out_block_size;- state->out_block = out_block;+ lz4->out_block_size = out_block_size;+ lz4->out_block = out_block; }- if (!state->flags.block_independence)- memset(state->out_block, 0, 64 * 1024);+ if (!lz4->flags.block_independence)+ memset(lz4->out_block, 0, 64 * 1024); return (ARCHIVE_OK); } static int-lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)+lz4_allocate_out_block_for_legacy(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; size_t out_block_size = LEGACY_BLOCK_SIZE; void *out_block; - if (state->out_block_size < out_block_size) {- free(state->out_block);- state->out_block = NULL;+ if (lz4->out_block_size < out_block_size) {+ free(lz4->out_block);+ lz4->out_block = NULL; out_block = malloc(out_block_size); if (out_block == NULL) {- state->out_block_size = 0;- archive_set_error(&self->archive->archive, ENOMEM,+ lz4->out_block_size = 0;+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for lz4 decompression"); return (ARCHIVE_FATAL); }- state->out_block_size = out_block_size;- state->out_block = out_block;+ lz4->out_block_size = out_block_size;+ lz4->out_block = out_block; } return (ARCHIVE_OK); }@@ -372,96 +372,96 @@ * Return the next block of decompressed data. */ static ssize_t-lz4_filter_read(struct archive_read_filter *self, const void **p)+lz4_filter_read(struct archive_read_filter *f, const void **p) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; ssize_t ret; - if (state->eof) {+ if (lz4->eof) { *p = NULL; return (0); } - __archive_read_filter_consume(self->upstream, state->unconsumed);- state->unconsumed = 0;+ __archive_read_filter_consume(f->upstream, lz4->unconsumed);+ lz4->unconsumed = 0; - switch (state->stage) {+ switch (lz4->stage) { case SELECT_STREAM: break; case READ_DEFAULT_STREAM: case READ_LEGACY_STREAM: /* Reading an lz4 stream already failed. */- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid sequence"); return (ARCHIVE_FATAL); case READ_DEFAULT_BLOCK:- ret = lz4_filter_read_default_stream(self, p);- if (ret != 0 || state->stage != SELECT_STREAM)+ ret = lz4_filter_read_default_stream(f, p);+ if (ret != 0 || lz4->stage != SELECT_STREAM) return ret; break; case READ_LEGACY_BLOCK:- ret = lz4_filter_read_legacy_stream(self, p);- if (ret != 0 || state->stage != SELECT_STREAM)+ ret = lz4_filter_read_legacy_stream(f, p);+ if (ret != 0 || lz4->stage != SELECT_STREAM) return ret; break; default:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Program error"); return (ARCHIVE_FATAL); } - while (state->stage == SELECT_STREAM) {+ while (lz4->stage == SELECT_STREAM) { const char *read_buf; /* Read a magic number. */- read_buf = __archive_read_filter_ahead(self->upstream, 4,+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); if (read_buf == NULL) {- state->eof = 1;+ lz4->eof = 1; *p = NULL; return (0); } uint32_t number = archive_le32dec(read_buf);- __archive_read_filter_consume(self->upstream, 4);+ __archive_read_filter_consume(f->upstream, 4); if (number == LZ4_MAGICNUMBER)- return lz4_filter_read_default_stream(self, p);+ return lz4_filter_read_default_stream(f, p); else if (number == LZ4_LEGACY)- return lz4_filter_read_legacy_stream(self, p);+ return lz4_filter_read_legacy_stream(f, p); else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) { read_buf = __archive_read_filter_ahead(- self->upstream, 4, NULL);+ f->upstream, 4, NULL); if (read_buf == NULL) { archive_set_error(- &self->archive->archive,+ &f->archive->archive, ARCHIVE_ERRNO_MISC, "Malformed lz4 data"); return (ARCHIVE_FATAL); } int64_t skip_bytes = archive_le32dec(read_buf);- if (__archive_read_filter_consume(self->upstream,+ if (__archive_read_filter_consume(f->upstream, 4 + skip_bytes) < 0) { archive_set_error(- &self->archive->archive,+ &f->archive->archive, ARCHIVE_ERRNO_MISC, "Malformed lz4 data"); return (ARCHIVE_FATAL); } } else { /* Ignore following unrecognized data. */- state->eof = 1;+ lz4->eof = 1; *p = NULL; return (0); } }- state->eof = 1;+ lz4->eof = 1; *p = NULL; return (0); } static int-lz4_filter_read_descriptor(struct archive_read_filter *self)+lz4_filter_read_descriptor(struct archive_read_filter *f) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; const char *read_buf; ssize_t bytes_remaining; ssize_t descriptor_bytes;@@ -469,10 +469,10 @@ unsigned int chsum, chsum_verifier; /* Make sure we have 2 bytes for flags. */- read_buf = __archive_read_filter_ahead(self->upstream, 2,+ read_buf = __archive_read_filter_ahead(f->upstream, 2, &bytes_remaining); if (read_buf == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL);@@ -488,11 +488,11 @@ /* A reserved bit must be zero. */ if (flag & 0x02) goto malformed_error;- state->flags.block_independence = (flag & 0x20) != 0;- state->flags.block_checksum = (flag & 0x10)?4:0;- state->flags.stream_size = (flag & 0x08) != 0;- state->flags.stream_checksum = (flag & 0x04) != 0;- state->flags.preset_dictionary = (flag & 0x01) != 0;+ lz4->flags.block_independence = (flag & 0x20) != 0;+ lz4->flags.block_checksum = (flag & 0x10)?4:0;+ lz4->flags.stream_size = (flag & 0x08) != 0;+ lz4->flags.stream_checksum = (flag & 0x04) != 0;+ lz4->flags.preset_dictionary = (flag & 0x01) != 0; /* BD */ bd = (unsigned char)read_buf[1];@@ -502,16 +502,16 @@ /* Get a maximum block size. */ switch (read_buf[1] >> 4) { case 4: /* 64 KB */- state->flags.block_maximum_size = 64 * 1024;+ lz4->flags.block_maximum_size = 64 * 1024; break; case 5: /* 256 KB */- state->flags.block_maximum_size = 256 * 1024;+ lz4->flags.block_maximum_size = 256 * 1024; break; case 6: /* 1 MB */- state->flags.block_maximum_size = 1024 * 1024;+ lz4->flags.block_maximum_size = 1024 * 1024; break; case 7: /* 4 MB */- state->flags.block_maximum_size = 4 * 1024 * 1024;+ lz4->flags.block_maximum_size = 4 * 1024 * 1024; break; default: goto malformed_error;@@ -519,15 +519,15 @@ /* Read the whole descriptor in a stream block. */ descriptor_bytes = 3;- if (state->flags.stream_size)+ if (lz4->flags.stream_size) descriptor_bytes += 8;- if (state->flags.preset_dictionary)+ if (lz4->flags.preset_dictionary) descriptor_bytes += 4; if (bytes_remaining < descriptor_bytes) {- read_buf = __archive_read_filter_ahead(self->upstream,+ read_buf = __archive_read_filter_ahead(f->upstream, descriptor_bytes, &bytes_remaining); if (read_buf == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL);@@ -542,30 +542,30 @@ goto malformed_error; #endif - __archive_read_filter_consume(self->upstream, descriptor_bytes);+ __archive_read_filter_consume(f->upstream, descriptor_bytes); /* Make sure we have a large enough buffer for uncompressed data. */- if (lz4_allocate_out_block(self) != ARCHIVE_OK)+ if (lz4_allocate_out_block(f) != ARCHIVE_OK) return (ARCHIVE_FATAL);- if (state->flags.stream_checksum) {- state->xxh32_state = __archive_xxhash.XXH32_init(0);- if (state->xxh32_state == NULL)+ if (lz4->flags.stream_checksum) {+ lz4->xxh32_state = __archive_xxhash.XXH32_init(0);+ if (lz4->xxh32_state == NULL) return (ARCHIVE_FATAL); } - state->decoded_size = 0;+ lz4->decoded_size = 0; /* Success */ return (ARCHIVE_OK); malformed_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "malformed lz4 data"); return (ARCHIVE_FATAL); } static ssize_t-lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)+lz4_filter_read_data_block(struct archive_read_filter *f, const void **p) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; ssize_t compressed_size; const char *read_buf; int checksum_size;@@ -575,19 +575,19 @@ *p = NULL; /* Make sure we have 4 bytes for a block size. */- read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); if (read_buf == NULL) goto truncated_error; compressed_size = archive_le32dec(read_buf);- if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)+ if ((compressed_size & 0x7fffffff) > lz4->flags.block_maximum_size) goto malformed_error; /* A compressed size == 0 means the end of stream blocks. */ if (compressed_size == 0) {- __archive_read_filter_consume(self->upstream, 4);+ __archive_read_filter_consume(f->upstream, 4); return 0; } - checksum_size = state->flags.block_checksum;+ checksum_size = lz4->flags.block_checksum; /* Check if the block is uncompressed. */ if (compressed_size & 0x80000000U) { compressed_size &= 0x7fffffff;@@ -600,7 +600,7 @@ for its decompression speed, so we read a whole block and allocate a huge buffer used for decoded data. */- read_buf = __archive_read_filter_ahead(self->upstream,+ read_buf = __archive_read_filter_ahead(f->upstream, 4 + compressed_size + checksum_size, NULL); if (read_buf == NULL) goto truncated_error;@@ -621,24 +621,24 @@ /* If the block is uncompressed, there is nothing to do. */ if (uncompressed_size) { /* Prepare a prefix 64k block for next block. */- if (!state->flags.block_independence) {+ if (!lz4->flags.block_independence) { prefix64k = 64 * 1024; if (uncompressed_size < (ssize_t)prefix64k) {- memcpy(state->out_block+ memcpy(lz4->out_block + prefix64k - uncompressed_size, read_buf + 4, uncompressed_size);- memset(state->out_block, 0,+ memset(lz4->out_block, 0, prefix64k - uncompressed_size); } else {- memcpy(state->out_block,+ memcpy(lz4->out_block, read_buf + 4 + uncompressed_size - prefix64k, prefix64k); }- state->decoded_size = 0;+ lz4->decoded_size = 0; }- state->unconsumed = 4 + uncompressed_size + checksum_size;+ lz4->unconsumed = 4 + uncompressed_size + checksum_size; *p = read_buf + 4; return uncompressed_size; }@@ -646,168 +646,168 @@ /* Decompress a block data. */- if (state->flags.block_independence) {+ if (lz4->flags.block_independence) { prefix64k = 0; uncompressed_size = LZ4_decompress_safe(read_buf + 4,- state->out_block, (int)compressed_size,- state->flags.block_maximum_size);+ lz4->out_block, (int)compressed_size,+ lz4->flags.block_maximum_size); } else { prefix64k = 64 * 1024;- if (state->decoded_size) {- if (state->decoded_size < prefix64k) {- memmove(state->out_block- + prefix64k - state->decoded_size,- state->out_block + prefix64k,- state->decoded_size);- memset(state->out_block, 0,- prefix64k - state->decoded_size);+ if (lz4->decoded_size) {+ if (lz4->decoded_size < prefix64k) {+ memmove(lz4->out_block+ + prefix64k - lz4->decoded_size,+ lz4->out_block + prefix64k,+ lz4->decoded_size);+ memset(lz4->out_block, 0,+ prefix64k - lz4->decoded_size); } else {- memmove(state->out_block,- state->out_block + state->decoded_size,+ memmove(lz4->out_block,+ lz4->out_block + lz4->decoded_size, prefix64k); } } #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 uncompressed_size = LZ4_decompress_safe_usingDict( read_buf + 4,- state->out_block + prefix64k, (int)compressed_size,- state->flags.block_maximum_size,- state->out_block,+ lz4->out_block + prefix64k, (int)compressed_size,+ lz4->flags.block_maximum_size,+ lz4->out_block, (int)prefix64k); #else uncompressed_size = LZ4_decompress_safe_withPrefix64k( read_buf + 4,- state->out_block + prefix64k, (int)compressed_size,- state->flags.block_maximum_size);+ lz4->out_block + prefix64k, (int)compressed_size,+ lz4->flags.block_maximum_size); #endif } /* Check if an error occurred in the decompression process. */ if (uncompressed_size < 0) {- archive_set_error(&(self->archive->archive),+ archive_set_error(&(f->archive->archive), ARCHIVE_ERRNO_MISC, "lz4 decompression failed"); return (ARCHIVE_FATAL); } - state->unconsumed = 4 + compressed_size + checksum_size;- *p = state->out_block + prefix64k;- state->decoded_size = uncompressed_size;+ lz4->unconsumed = 4 + compressed_size + checksum_size;+ *p = lz4->out_block + prefix64k;+ lz4->decoded_size = uncompressed_size; return uncompressed_size; malformed_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "malformed lz4 data"); return (ARCHIVE_FATAL); truncated_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL); } static ssize_t-lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)+lz4_filter_read_default_stream(struct archive_read_filter *f, const void **p) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; const char *read_buf; ssize_t ret; - if (state->stage == SELECT_STREAM) {- state->stage = READ_DEFAULT_STREAM;+ if (lz4->stage == SELECT_STREAM) {+ lz4->stage = READ_DEFAULT_STREAM; /* First, read a descriptor. */- if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)+ if((ret = lz4_filter_read_descriptor(f)) != ARCHIVE_OK) return (ret);- state->stage = READ_DEFAULT_BLOCK;+ lz4->stage = READ_DEFAULT_BLOCK; } /* Decompress a block. */- ret = lz4_filter_read_data_block(self, p);+ ret = lz4_filter_read_data_block(f, p); /* If the end of block is detected, change the filter status to read next stream. */ if (ret == 0 && *p == NULL)- state->stage = SELECT_STREAM;+ lz4->stage = SELECT_STREAM; /* Optional processing, checking a stream sum. */- if (state->flags.stream_checksum) {- if (state->stage == SELECT_STREAM) {+ if (lz4->flags.stream_checksum) {+ if (lz4->stage == SELECT_STREAM) { unsigned int checksum; unsigned int checksum_stream;- read_buf = __archive_read_filter_ahead(self->upstream,+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); if (read_buf == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL); } checksum = archive_le32dec(read_buf);- __archive_read_filter_consume(self->upstream, 4);+ __archive_read_filter_consume(f->upstream, 4); checksum_stream = __archive_xxhash.XXH32_digest(- state->xxh32_state);- state->xxh32_state = NULL;+ lz4->xxh32_state);+ lz4->xxh32_state = NULL; if (checksum != checksum_stream) { #ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "lz4 stream checksum error"); return (ARCHIVE_FATAL); #endif } } else if (ret > 0)- __archive_xxhash.XXH32_update(state->xxh32_state,+ __archive_xxhash.XXH32_update(lz4->xxh32_state, *p, (int)ret); } return (ret); } static ssize_t-lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)+lz4_filter_read_legacy_stream(struct archive_read_filter *f, const void **p) {- struct private_data *state = (struct private_data *)self->data;+ struct lz4 *lz4 = f->data; uint32_t compressed; const char *read_buf; ssize_t ret; *p = NULL;- ret = lz4_allocate_out_block_for_legacy(self);+ ret = lz4_allocate_out_block_for_legacy(f); if (ret != ARCHIVE_OK) return ret; /* Make sure we have 4 bytes for a block size. */- read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); if (read_buf == NULL) {- if (state->stage == SELECT_STREAM) {- state->stage = READ_LEGACY_STREAM;- archive_set_error(&self->archive->archive,+ if (lz4->stage == SELECT_STREAM) {+ lz4->stage = READ_LEGACY_STREAM;+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL); }- state->stage = SELECT_STREAM;+ lz4->stage = SELECT_STREAM; return 0; }- state->stage = READ_LEGACY_BLOCK;+ lz4->stage = READ_LEGACY_BLOCK; compressed = archive_le32dec(read_buf); if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {- state->stage = SELECT_STREAM;+ lz4->stage = SELECT_STREAM; return 0; } /* Make sure we have a whole block. */- read_buf = __archive_read_filter_ahead(self->upstream,+ read_buf = __archive_read_filter_ahead(f->upstream, 4 + compressed, NULL); if (read_buf == NULL) {- archive_set_error(&(self->archive->archive),+ archive_set_error(&(f->archive->archive), ARCHIVE_ERRNO_MISC, "truncated lz4 input"); return (ARCHIVE_FATAL); }- ret = LZ4_decompress_safe(read_buf + 4, state->out_block,- compressed, (int)state->out_block_size);+ ret = LZ4_decompress_safe(read_buf + 4, lz4->out_block,+ compressed, (int)lz4->out_block_size); if (ret < 0) {- archive_set_error(&(self->archive->archive),+ archive_set_error(&(f->archive->archive), ARCHIVE_ERRNO_MISC, "lz4 decompression failed"); return (ARCHIVE_FATAL); }- *p = state->out_block;- state->unconsumed = 4 + compressed;+ *p = lz4->out_block;+ lz4->unconsumed = 4 + compressed; return ret; } @@ -815,15 +815,14 @@ * Clean up the decompressor. */ static int-lz4_filter_close(struct archive_read_filter *self)+lz4_filter_close(struct archive_read_filter *f) {- struct private_data *state;+ struct lz4 *lz4 = f->data; int ret = ARCHIVE_OK; - state = (struct private_data *)self->data;- free(state->xxh32_state);- free(state->out_block);- free(state);+ free(lz4->xxh32_state);+ free(lz4->out_block);+ free(lz4); return (ret); }
c/archive_read_support_filter_lzop.c view
@@ -68,7 +68,7 @@ #define LZOP_HEADER_MAGIC_LEN 9 #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-struct read_lzop {+struct lzop { unsigned char *out_block; size_t out_block_size; int flags;@@ -127,14 +127,14 @@ * Bidder just verifies the header and returns the number of verified bits. */ static int-lzop_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+lzop_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *p; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, NULL);+ p = __archive_read_filter_ahead(f, LZOP_HEADER_MAGIC_LEN, NULL); if (p == NULL) return (0); @@ -151,16 +151,16 @@ * in case that's available. */ static int-lzop_bidder_init(struct archive_read_filter *self)+lzop_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "lzop -d");+ r = __archive_read_program(f, "lzop -d"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZOP;- self->name = "lzop";+ f->code = ARCHIVE_FILTER_LZOP;+ f->name = "lzop"; return (r); } #else@@ -175,47 +175,47 @@ * Initialize the filter object. */ static int-lzop_bidder_init(struct archive_read_filter *self)+lzop_bidder_init(struct archive_read_filter *f) {- struct read_lzop *state;+ struct lzop *lzop; - self->code = ARCHIVE_FILTER_LZOP;- self->name = "lzop";+ f->code = ARCHIVE_FILTER_LZOP;+ f->name = "lzop"; - state = calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ lzop = calloc(1, sizeof(*lzop));+ if (lzop == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for lzop decompression"); return (ARCHIVE_FATAL); } - self->data = state;- self->vtable = &lzop_reader_vtable;+ f->data = lzop;+ f->vtable = &lzop_reader_vtable; return (ARCHIVE_OK); } static int-consume_header(struct archive_read_filter *self)+consume_header(struct archive_read_filter *f) {- struct read_lzop *state = (struct read_lzop *)self->data;+ struct lzop *lzop = f->data; const unsigned char *p, *_p; unsigned checksum, flags, len, method, version; /* * Check LZOP magic code. */- p = __archive_read_filter_ahead(self->upstream,+ p = __archive_read_filter_ahead(f->upstream, LZOP_HEADER_MAGIC_LEN, NULL); if (p == NULL) return (ARCHIVE_EOF); if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN)) return (ARCHIVE_EOF);- __archive_read_filter_consume(self->upstream,+ __archive_read_filter_consume(f->upstream, LZOP_HEADER_MAGIC_LEN); - p = __archive_read_filter_ahead(self->upstream, 29, NULL);+ p = __archive_read_filter_ahead(f->upstream, 29, NULL); if (p == NULL) goto truncated; _p = p;@@ -225,7 +225,7 @@ if (version >= 0x940) { unsigned reqversion = archive_be16dec(p); p += 2; if (reqversion < 0x900) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid required version"); return (ARCHIVE_FAILED); }@@ -233,7 +233,7 @@ method = *p++; if (method < 1 || method > 3) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Unsupported method"); return (ARCHIVE_FAILED); }@@ -252,7 +252,7 @@ ;/* NOP */ #endif else if (level > 9) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid level"); return (ARCHIVE_FAILED); }@@ -270,7 +270,7 @@ len = *p++; /* Read filename length */ len += p - _p; /* Make sure we have all bytes we need to calculate checksum. */- p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);+ p = __archive_read_filter_ahead(f->upstream, len + 4, NULL); if (p == NULL) goto truncated; if (flags & CRC32_HEADER)@@ -281,146 +281,146 @@ if (archive_be32dec(p + len) != checksum) goto corrupted; #endif- __archive_read_filter_consume(self->upstream, len + 4);+ __archive_read_filter_consume(f->upstream, len + 4); if (flags & EXTRA_FIELD) { /* Skip extra field */- p = __archive_read_filter_ahead(self->upstream, 4, NULL);+ p = __archive_read_filter_ahead(f->upstream, 4, NULL); if (p == NULL) goto truncated; len = archive_be32dec(p);- __archive_read_filter_consume(self->upstream,+ __archive_read_filter_consume(f->upstream, (int64_t)len + 4 + 4); }- state->flags = flags;- state->in_stream = 1;+ lzop->flags = flags;+ lzop->in_stream = 1; return (ARCHIVE_OK); truncated:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FAILED); corrupted:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); return (ARCHIVE_FAILED); } static int-consume_block_info(struct archive_read_filter *self)+consume_block_info(struct archive_read_filter *f) {- struct read_lzop *state = (struct read_lzop *)self->data;+ struct lzop *lzop = f->data; const unsigned char *p;- unsigned flags = state->flags;+ unsigned flags = lzop->flags; - p = __archive_read_filter_ahead(self->upstream, 4, NULL);+ p = __archive_read_filter_ahead(f->upstream, 4, NULL); if (p == NULL) goto truncated;- state->uncompressed_size = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- if (state->uncompressed_size == 0)+ lzop->uncompressed_size = archive_be32dec(p);+ __archive_read_filter_consume(f->upstream, 4);+ if (lzop->uncompressed_size == 0) return (ARCHIVE_EOF);- if (state->uncompressed_size > MAX_BLOCK_SIZE)+ if (lzop->uncompressed_size > MAX_BLOCK_SIZE) goto corrupted; - p = __archive_read_filter_ahead(self->upstream, 4, NULL);+ p = __archive_read_filter_ahead(f->upstream, 4, NULL); if (p == NULL) goto truncated;- state->compressed_size = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- if (state->compressed_size > state->uncompressed_size)+ lzop->compressed_size = archive_be32dec(p);+ __archive_read_filter_consume(f->upstream, 4);+ if (lzop->compressed_size > lzop->uncompressed_size) goto corrupted; if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {- p = __archive_read_filter_ahead(self->upstream, 4, NULL);+ p = __archive_read_filter_ahead(f->upstream, 4, NULL); if (p == NULL) goto truncated;- state->compressed_cksum = state->uncompressed_cksum =+ lzop->compressed_cksum = lzop->uncompressed_cksum = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);+ __archive_read_filter_consume(f->upstream, 4); } if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&- state->compressed_size < state->uncompressed_size) {- p = __archive_read_filter_ahead(self->upstream, 4, NULL);+ lzop->compressed_size < lzop->uncompressed_size) {+ p = __archive_read_filter_ahead(f->upstream, 4, NULL); if (p == NULL) goto truncated;- state->compressed_cksum = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);+ lzop->compressed_cksum = archive_be32dec(p);+ __archive_read_filter_consume(f->upstream, 4); } return (ARCHIVE_OK); truncated:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FAILED); corrupted:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); return (ARCHIVE_FAILED); } static ssize_t-lzop_filter_read(struct archive_read_filter *self, const void **p)+lzop_filter_read(struct archive_read_filter *f, const void **p) {- struct read_lzop *state = (struct read_lzop *)self->data;+ struct lzop *lzop = f->data; const void *b; lzo_uint out_size; uint32_t cksum; int ret, r; - if (state->unconsumed_bytes) {- __archive_read_filter_consume(self->upstream,- state->unconsumed_bytes);- state->unconsumed_bytes = 0;+ if (lzop->unconsumed_bytes) {+ __archive_read_filter_consume(f->upstream,+ lzop->unconsumed_bytes);+ lzop->unconsumed_bytes = 0; }- if (state->eof)+ if (lzop->eof) return (0); for (;;) {- if (!state->in_stream) {- ret = consume_header(self);+ if (!lzop->in_stream) {+ ret = consume_header(f); if (ret < ARCHIVE_OK) return (ret); if (ret == ARCHIVE_EOF) {- state->eof = 1;+ lzop->eof = 1; return (0); } }- ret = consume_block_info(self);+ ret = consume_block_info(f); if (ret < ARCHIVE_OK) return (ret); if (ret == ARCHIVE_EOF)- state->in_stream = 0;+ lzop->in_stream = 0; else break; } - if (state->out_block == NULL ||- state->out_block_size < state->uncompressed_size) {+ if (lzop->out_block == NULL ||+ lzop->out_block_size < lzop->uncompressed_size) { void *new_block; - new_block = realloc(state->out_block, state->uncompressed_size);+ new_block = realloc(lzop->out_block, lzop->uncompressed_size); if (new_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for lzop decompression"); return (ARCHIVE_FATAL); }- state->out_block = new_block;- state->out_block_size = state->uncompressed_size;+ lzop->out_block = new_block;+ lzop->out_block_size = lzop->uncompressed_size; } - b = __archive_read_filter_ahead(self->upstream,- state->compressed_size, NULL);+ b = __archive_read_filter_ahead(f->upstream,+ lzop->compressed_size, NULL); if (b == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FATAL); }- if (state->flags & CRC32_COMPRESSED)- cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);- else if (state->flags & ADLER32_COMPRESSED)- cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);+ if (lzop->flags & CRC32_COMPRESSED)+ cksum = crc32(crc32(0, NULL, 0), b, lzop->compressed_size);+ else if (lzop->flags & ADLER32_COMPRESSED)+ cksum = adler32(adler32(0, NULL, 0), b, lzop->compressed_size); else- cksum = state->compressed_cksum;- if (cksum != state->compressed_cksum) {- archive_set_error(&self->archive->archive,+ cksum = lzop->compressed_cksum;+ if (cksum != lzop->compressed_cksum) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); }@@ -429,51 +429,51 @@ * If both uncompressed size and compressed size are the same, * we do not decompress this block. */- if (state->uncompressed_size == state->compressed_size) {+ if (lzop->uncompressed_size == lzop->compressed_size) { *p = b;- state->unconsumed_bytes = state->compressed_size;- return ((ssize_t)state->uncompressed_size);+ lzop->unconsumed_bytes = lzop->compressed_size;+ return ((ssize_t)lzop->uncompressed_size); } /* * Drive lzo uncompression. */- out_size = (lzo_uint)state->uncompressed_size;- r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,- state->out_block, &out_size, NULL);+ out_size = (lzo_uint)lzop->uncompressed_size;+ r = lzo1x_decompress_safe(b, (lzo_uint)lzop->compressed_size,+ lzop->out_block, &out_size, NULL); switch (r) { case LZO_E_OK:- if (out_size == state->uncompressed_size)+ if (out_size == lzop->uncompressed_size) break;- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); case LZO_E_OUT_OF_MEMORY:- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "lzop decompression failed: out of memory"); return (ARCHIVE_FATAL); default:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "lzop decompression failed: %d", r); return (ARCHIVE_FATAL); } - if (state->flags & CRC32_UNCOMPRESSED)- cksum = crc32(crc32(0, NULL, 0), state->out_block,- state->uncompressed_size);- else if (state->flags & ADLER32_UNCOMPRESSED)- cksum = adler32(adler32(0, NULL, 0), state->out_block,- state->uncompressed_size);+ if (lzop->flags & CRC32_UNCOMPRESSED)+ cksum = crc32(crc32(0, NULL, 0), lzop->out_block,+ lzop->uncompressed_size);+ else if (lzop->flags & ADLER32_UNCOMPRESSED)+ cksum = adler32(adler32(0, NULL, 0), lzop->out_block,+ lzop->uncompressed_size); else- cksum = state->uncompressed_cksum;- if (cksum != state->uncompressed_cksum) {- archive_set_error(&self->archive->archive,+ cksum = lzop->uncompressed_cksum;+ if (cksum != lzop->uncompressed_cksum) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); } - __archive_read_filter_consume(self->upstream, state->compressed_size);- *p = state->out_block;+ __archive_read_filter_consume(f->upstream, lzop->compressed_size);+ *p = lzop->out_block; return ((ssize_t)out_size); } @@ -481,12 +481,12 @@ * Clean up the decompressor. */ static int-lzop_filter_close(struct archive_read_filter *self)+lzop_filter_close(struct archive_read_filter *f) {- struct read_lzop *state = (struct read_lzop *)self->data;+ struct lzop *lzop = f->data; - free(state->out_block);- free(state);+ free(lzop->out_block);+ free(lzop); return (ARCHIVE_OK); }
c/archive_read_support_filter_program.c view
@@ -87,7 +87,7 @@ * bid twice in the same pipeline. */ struct program_bidder {- char *description;+ struct archive_string description; char *cmd; void *signature; size_t signature_len;@@ -102,7 +102,7 @@ /* * The actual filter needs to track input and output data. */-struct program_filter {+struct program { struct archive_string description; #if defined(_WIN32) && !defined(__CYGWIN__) HANDLE child;@@ -145,6 +145,8 @@ state->cmd = strdup(cmd); if (state->cmd == NULL) goto memerr;+ archive_strcpy(&state->description, "Program: ");+ archive_strcat(&state->description, cmd); if (signature != NULL && signature_len > 0) { state->signature_len = signature_len;@@ -168,9 +170,9 @@ } static void-program_bidder_free(struct archive_read_filter_bidder *self)+program_bidder_free(struct archive_read_filter_bidder *b) {- struct program_bidder *state = (struct program_bidder *)self->data;+ struct program_bidder *state = (struct program_bidder *)b->data; free_state(state); }@@ -180,6 +182,7 @@ { if (state) {+ archive_string_free(&state->description); free(state->cmd); free(state->signature); free(state);@@ -193,15 +196,15 @@ * we're called, then never bid again. */ static int-program_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *upstream)+program_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) {- struct program_bidder *state = self->data;+ struct program_bidder *state = b->data; const char *p; /* If we have a signature, use that to match. */ if (state->signature_len > 0) {- p = __archive_read_filter_ahead(upstream,+ p = __archive_read_filter_ahead(f, state->signature_len, NULL); if (p == NULL) return (0);@@ -226,36 +229,36 @@ * (including error message if the child came to a bad end). */ static int-child_stop(struct archive_read_filter *self, struct program_filter *state)+child_stop(struct archive_read_filter *f, struct program *program) { /* Close our side of the I/O with the child. */- if (state->child_stdin != -1) {- close(state->child_stdin);- state->child_stdin = -1;+ if (program->child_stdin != -1) {+ close(program->child_stdin);+ program->child_stdin = -1; }- if (state->child_stdout != -1) {- close(state->child_stdout);- state->child_stdout = -1;+ if (program->child_stdout != -1) {+ close(program->child_stdout);+ program->child_stdout = -1; } - if (state->child != 0) {+ if (program->child != 0) { /* Reap the child. */ do {- state->waitpid_return- = waitpid(state->child, &state->exit_status, 0);- } while (state->waitpid_return == -1 && errno == EINTR);- state->child = 0;+ program->waitpid_return+ = waitpid(program->child, &program->exit_status, 0);+ } while (program->waitpid_return == -1 && errno == EINTR);+ program->child = 0; } - if (state->waitpid_return < 0) {+ if (program->waitpid_return < 0) { /* waitpid() failed? This is ugly. */- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Error closing child process"); return (ARCHIVE_WARN); } #if !defined(_WIN32) || defined(__CYGWIN__)- if (WIFSIGNALED(state->exit_status)) {+ if (WIFSIGNALED(program->exit_status)) { #ifdef SIGPIPE /* If the child died because we stopped reading before * it was done, that's okay. Some archive formats@@ -263,24 +266,24 @@ /* The alternative to this would be to add a step * before close(child_stdout) above to read from the * child until the child has no more to write. */- if (WTERMSIG(state->exit_status) == SIGPIPE)+ if (WTERMSIG(program->exit_status) == SIGPIPE) return (ARCHIVE_OK); #endif- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Child process exited with signal %d",- WTERMSIG(state->exit_status));+ WTERMSIG(program->exit_status)); return (ARCHIVE_WARN); } #endif /* !_WIN32 || __CYGWIN__ */ - if (WIFEXITED(state->exit_status)) {- if (WEXITSTATUS(state->exit_status) == 0)+ if (WIFEXITED(program->exit_status)) {+ if (WEXITSTATUS(program->exit_status) == 0) return (ARCHIVE_OK); - archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Child process exited with status %d",- WEXITSTATUS(state->exit_status));+ WEXITSTATUS(program->exit_status)); return (ARCHIVE_WARN); } @@ -291,13 +294,13 @@ * Use select() to decide whether the child is ready for read or write. */ static ssize_t-child_read(struct archive_read_filter *self, char *buf, size_t buf_len)+child_read(struct archive_read_filter *f, char *buf, size_t buf_len) {- struct program_filter *state = self->data;+ struct program *program = f->data; ssize_t ret, requested, avail; const char *p; #if defined(_WIN32) && !defined(__CYGWIN__)- HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);+ HANDLE handle = (HANDLE)_get_osfhandle(program->child_stdout); #endif requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;@@ -325,7 +328,7 @@ break; } #endif- ret = read(state->child_stdout, buf, requested);+ ret = read(program->child_stdout, buf, requested); } while (ret == -1 && errno == EINTR); if (ret > 0)@@ -333,44 +336,44 @@ if (ret == 0 || (ret == -1 && errno == EPIPE)) /* Child has closed its output; reap the child * and return the status. */- return (child_stop(self, state));+ return (child_stop(f, program)); if (ret == -1 && errno != EAGAIN) return (-1); - if (state->child_stdin == -1) {+ if (program->child_stdin == -1) { /* Block until child has some I/O ready. */- __archive_check_child(state->child_stdin,- state->child_stdout);+ __archive_check_child(program->child_stdin,+ program->child_stdout); continue; } /* Get some more data from upstream. */- p = __archive_read_filter_ahead(self->upstream, 1, &avail);+ p = __archive_read_filter_ahead(f->upstream, 1, &avail); if (p == NULL) {- close(state->child_stdin);- state->child_stdin = -1;- fcntl(state->child_stdout, F_SETFL, 0);+ close(program->child_stdin);+ program->child_stdin = -1;+ fcntl(program->child_stdout, F_SETFL, 0); if (avail < 0) return (avail); continue; } do {- ret = write(state->child_stdin, p, avail);+ ret = write(program->child_stdin, p, avail); } while (ret == -1 && errno == EINTR); if (ret > 0) { /* Consume whatever we managed to write. */- __archive_read_filter_consume(self->upstream, ret);+ __archive_read_filter_consume(f->upstream, ret); } else if (ret == -1 && errno == EAGAIN) { /* Block until child has some I/O ready. */- __archive_check_child(state->child_stdin,- state->child_stdout);+ __archive_check_child(program->child_stdin,+ program->child_stdout); } else { /* Write failed. */- close(state->child_stdin);- state->child_stdin = -1;- fcntl(state->child_stdout, F_SETFL, 0);+ close(program->child_stdin);+ program->child_stdin = -1;+ fcntl(program->child_stdout, F_SETFL, 0); /* If it was a bad error, we're done; otherwise * it was EPIPE or EOF, and we can still read * from the child. */@@ -387,9 +390,9 @@ }; int-__archive_read_program(struct archive_read_filter *self, const char *cmd)+__archive_read_program(struct archive_read_filter *f, const char *cmd) {- struct program_filter *state;+ struct program *program; static const size_t out_buf_len = 65536; char *out_buf; const char *prefix = "Program: ";@@ -397,70 +400,71 @@ size_t l; l = strlen(prefix) + strlen(cmd) + 1;- state = calloc(1, sizeof(*state));+ program = calloc(1, sizeof(*program)); out_buf = malloc(out_buf_len);- if (state == NULL || out_buf == NULL ||- archive_string_ensure(&state->description, l) == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ if (program == NULL || out_buf == NULL ||+ archive_string_ensure(&program->description, l) == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate input data");- if (state != NULL) {- archive_string_free(&state->description);- free(state);+ if (program != NULL) {+ archive_string_free(&program->description);+ free(program); } free(out_buf); return (ARCHIVE_FATAL); }- archive_strcpy(&state->description, prefix);- archive_strcat(&state->description, cmd);+ archive_strcpy(&program->description, prefix);+ archive_strcat(&program->description, cmd); - self->code = ARCHIVE_FILTER_PROGRAM;- self->name = state->description.s;+ f->code = ARCHIVE_FILTER_PROGRAM;+ f->name = program->description.s; - state->out_buf = out_buf;- state->out_buf_len = out_buf_len;+ program->out_buf = out_buf;+ program->out_buf_len = out_buf_len; - ret = __archive_create_child(cmd, &state->child_stdin,- &state->child_stdout, &state->child);+ ret = __archive_create_child(cmd, &program->child_stdin,+ &program->child_stdout, &program->child); if (ret != ARCHIVE_OK) {- free(state->out_buf);- archive_string_free(&state->description);- free(state);- archive_set_error(&self->archive->archive, EINVAL,+ free(program->out_buf);+ archive_string_free(&program->description);+ free(program);+ archive_set_error(&f->archive->archive, EINVAL, "Can't initialize filter; unable to run program \"%s\"", cmd); return (ARCHIVE_FATAL); } - self->data = state;- self->vtable = &program_reader_vtable;+ f->data = program;+ f->vtable = &program_reader_vtable; /* XXX Check that we can read at least one byte? */ return (ARCHIVE_OK); } static int-program_bidder_init(struct archive_read_filter *self)+program_bidder_init(struct archive_read_filter *f) { struct program_bidder *bidder_state;+ int r; - bidder_state = (struct program_bidder *)self->bidder->data;- return (__archive_read_program(self, bidder_state->cmd));+ bidder_state = (struct program_bidder *)f->bidder->data;+ r = __archive_read_program(f, bidder_state->cmd);+ f->name = bidder_state->description.s;+ return (r); } static ssize_t-program_filter_read(struct archive_read_filter *self, const void **buff)+program_filter_read(struct archive_read_filter *f, const void **buff) {- struct program_filter *state;+ struct program *program = f->data; ssize_t bytes; size_t total; char *p; - state = (struct program_filter *)self->data;- total = 0;- p = state->out_buf;- while (state->child_stdout != -1 && total < state->out_buf_len) {- bytes = child_read(self, p, state->out_buf_len - total);+ p = program->out_buf;+ while (program->child_stdout != -1 && total < program->out_buf_len) {+ bytes = child_read(f, p, program->out_buf_len - total); if (bytes < 0) /* No recovery is possible if we can no longer * read from the child. */@@ -472,23 +476,22 @@ p += bytes; } - *buff = state->out_buf;+ *buff = program->out_buf; return (total); } static int-program_filter_close(struct archive_read_filter *self)+program_filter_close(struct archive_read_filter *f) {- struct program_filter *state;+ struct program *program = f->data; int e; - state = (struct program_filter *)self->data;- e = child_stop(self, state);+ e = child_stop(f, program); /* Release our private data. */- free(state->out_buf);- archive_string_free(&state->description);- free(state);+ free(program->out_buf);+ archive_string_free(&program->description);+ free(program); return (e); }
c/archive_read_support_filter_rpm.c view
@@ -76,38 +76,38 @@ } static int-rpm_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+rpm_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) {- const unsigned char *b;+ const unsigned char *p; int bits_checked; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - b = __archive_read_filter_ahead(filter, 8, NULL);- if (b == NULL)+ p = __archive_read_filter_ahead(f, 8, NULL);+ if (p == NULL) return (0); bits_checked = 0; /* * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB */- if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)+ if (memcmp(p, "\xED\xAB\xEE\xDB", 4) != 0) return (0); bits_checked += 32; /* * Check major version. */- if (b[4] != 3 && b[4] != 4)+ if (p[4] != 3 && p[4] != 4) return (0); bits_checked += 8; /* * Check package type; binary or source. */- if (b[6] != 0)+ if (p[6] != 0) return (0); bits_checked += 8;- if (b[7] != 0 && b[7] != 1)+ if (p[7] != 0 && p[7] != 1) return (0); bits_checked += 8; @@ -121,40 +121,40 @@ }; static int-rpm_bidder_init(struct archive_read_filter *self)+rpm_bidder_init(struct archive_read_filter *f) { struct rpm *rpm; - self->code = ARCHIVE_FILTER_RPM;- self->name = "rpm";+ f->code = ARCHIVE_FILTER_RPM;+ f->name = "rpm"; rpm = calloc(1, sizeof(*rpm)); if (rpm == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for rpm"); return (ARCHIVE_FATAL); } - self->data = rpm;+ f->data = rpm; rpm->data_reached = 0;- self->vtable = &rpm_reader_vtable;+ f->vtable = &rpm_reader_vtable; return (ARCHIVE_OK); } static ssize_t-skip_padding(struct archive_read_filter *self)+skip_padding(struct archive_read_filter *f) { const unsigned char *h; ssize_t avail, count, r; do {- h = __archive_read_filter_ahead(self->upstream, 1, &avail);+ h = __archive_read_filter_ahead(f->upstream, 1, &avail); if (h == NULL) return (ARCHIVE_FATAL); for (count = 0; count < avail && *h++ == '\0'; count++) ;- r = __archive_read_filter_consume(self->upstream, count);+ r = __archive_read_filter_consume(f->upstream, count); if (r < 0) return (r); } while (count == avail);@@ -163,20 +163,20 @@ } static ssize_t-skip_prologue(struct archive_read_filter *self)+skip_prologue(struct archive_read_filter *f) { const unsigned char *h; ssize_t r; int header, seen_header = 0; /* Skip lead size. */- r = __archive_read_filter_consume(self->upstream, RPM_LEAD_SIZE);+ r = __archive_read_filter_consume(f->upstream, RPM_LEAD_SIZE); if (r < 0) return (r); do { /* Read header intro. */- h = __archive_read_filter_ahead(self->upstream,+ h = __archive_read_filter_ahead(f->upstream, RPM_MIN_HEAD_SIZE, NULL); if (h == NULL) return (ARCHIVE_FATAL);@@ -193,13 +193,13 @@ length = RPM_MIN_HEAD_SIZE + section * 16 + bytes; /* Skip header. */- r = __archive_read_filter_consume(self->upstream,+ r = __archive_read_filter_consume(f->upstream, length); if (r < 0) return (r); /* Skip padding. */- r = skip_padding(self);+ r = skip_padding(f); if (r != ARCHIVE_OK) return (r); }@@ -208,7 +208,7 @@ /* At least one header must have been encountered. */ if (!seen_header) { archive_set_error(- &self->archive->archive,+ &f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized rpm header"); return (ARCHIVE_FATAL);@@ -218,33 +218,30 @@ } static ssize_t-rpm_filter_read(struct archive_read_filter *self, const void **buff)+rpm_filter_read(struct archive_read_filter *f, const void **buff) {- struct rpm *rpm;+ struct rpm *rpm = f->data; ssize_t r; - rpm = (struct rpm *)self->data;- if (!rpm->data_reached) {- r = skip_prologue(self);+ r = skip_prologue(f); if (r != ARCHIVE_OK) return (r); rpm->data_reached = 1; } - *buff = __archive_read_filter_ahead(self->upstream, 1, &r);+ *buff = __archive_read_filter_ahead(f->upstream, 1, &r); if (r > 0)- __archive_read_filter_consume(self->upstream, r);+ __archive_read_filter_consume(f->upstream, r); return r; } static int-rpm_filter_close(struct archive_read_filter *self)+rpm_filter_close(struct archive_read_filter *f) {- struct rpm *rpm;+ struct rpm *rpm = f->data; - rpm = (struct rpm *)self->data; free(rpm); return (ARCHIVE_OK);
c/archive_read_support_filter_uu.c view
@@ -43,7 +43,7 @@ /* Maximum lookahead during bid phase */ #define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */ -struct uudecode {+struct uu { int64_t total; unsigned char *in_buff; #define IN_BUFF_SIZE (1024)@@ -63,7 +63,7 @@ }; static int uudecode_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *filter);+ struct archive_read_filter *f); static int uudecode_bidder_init(struct archive_read_filter *); static int uudecode_read_header(struct archive_read_filter *,@@ -207,7 +207,7 @@ } static ssize_t-bid_get_line(struct archive_read_filter *filter,+bid_get_line(struct archive_read_filter *f, const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl, size_t* nbytes_read) {@@ -235,12 +235,12 @@ if (nbytes_req < (size_t)*ravail + 160) nbytes_req <<= 1; - *b = __archive_read_filter_ahead(filter, nbytes_req, avail);+ *b = __archive_read_filter_ahead(f, nbytes_req, avail); if (*b == NULL) { if (*ravail >= *avail) return (0); /* Reading bytes reaches the end of a stream. */- *b = __archive_read_filter_ahead(filter, *avail, avail);+ *b = __archive_read_filter_ahead(f, *avail, avail); quit = 1; } *nbytes_read = *avail;@@ -258,42 +258,42 @@ #define UUDECODE(c) (((c) - 0x20) & 0x3f) static int-uudecode_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+uudecode_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) {- const unsigned char *b;+ const unsigned char *p; ssize_t avail, ravail; ssize_t len, nl; int l; int firstline; size_t nbytes_read; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - b = __archive_read_filter_ahead(filter, 1, &avail);- if (b == NULL)+ p = __archive_read_filter_ahead(f, 1, &avail);+ if (p == NULL) return (0); firstline = 20; ravail = avail; nbytes_read = avail; for (;;) {- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);+ len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read); if (len < 0 || nl == 0) return (0); /* No match found. */- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)+ if (len - nl >= 11 && memcmp(p, "begin ", 6) == 0) l = 6;- else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)+ else if (len -nl >= 18 && memcmp(p, "begin-base64 ", 13) == 0) l = 13; else l = 0; - if (l > 0 && (b[l] < '0' || b[l] > '7' ||- b[l+1] < '0' || b[l+1] > '7' ||- b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))+ if (l > 0 && (p[l] < '0' || p[l] > '7' ||+ p[l+1] < '0' || p[l+1] > '7' ||+ p[l+2] < '0' || p[l+2] > '7' || p[l+3] != ' ')) l = 0; - b += len;+ p += len; avail -= len; if (l) break;@@ -305,51 +305,51 @@ } if (!avail) return (0);- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);+ len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read); if (len < 0 || nl == 0) return (0);/* There are non-ascii characters. */ avail -= len; if (l == 6) { /* "begin " */- if (!uuchar[*b])+ if (!uuchar[*p]) return (0); /* Get a length of decoded bytes. */- l = UUDECODE(*b++); len--;+ l = UUDECODE(*p++); len--; if (l > 45) /* Normally, maximum length is 45(character 'M'). */ return (0); if (l > len - nl) return (0); /* Line too short. */ while (l) {- if (!uuchar[*b++])+ if (!uuchar[*p++]) return (0); --len; --l; } if (len-nl == 1 &&- (uuchar[*b] || /* Check sum. */- (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */- ++b;+ (uuchar[*p] || /* Check sum. */+ (*p >= 'a' && *p <= 'z'))) {/* Padding data(MINIX). */+ ++p; --len; }- b += nl;- if (avail && uuchar[*b])+ p += nl;+ if (avail && uuchar[*p]) return (firstline+30); } else if (l == 13) { /* "begin-base64 " */ while (len-nl > 0) {- if (!base64[*b++])+ if (!base64[*p++]) return (0); --len; }- b += nl;+ p += nl; - if (avail >= 5 && memcmp(b, "====\n", 5) == 0)+ if (avail >= 5 && memcmp(p, "====\n", 5) == 0) return (firstline+40);- if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)+ if (avail >= 6 && memcmp(p, "====\r\n", 6) == 0) return (firstline+40);- if (avail > 0 && base64[*b])+ if (avail > 0 && base64[*p]) return (firstline+30); } @@ -364,46 +364,46 @@ }; static int-uudecode_bidder_init(struct archive_read_filter *self)+uudecode_bidder_init(struct archive_read_filter *f) {- struct uudecode *uudecode;+ struct uu *uu; void *out_buff; void *in_buff; - self->code = ARCHIVE_FILTER_UU;- self->name = "uu";+ f->code = ARCHIVE_FILTER_UU;+ f->name = "uu"; - uudecode = calloc(1, sizeof(*uudecode));+ uu = calloc(1, sizeof(*uu)); out_buff = malloc(OUT_BUFF_SIZE); in_buff = malloc(IN_BUFF_SIZE);- if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ if (uu == NULL || out_buff == NULL || in_buff == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for uudecode");- free(uudecode);+ free(uu); free(out_buff); free(in_buff); return (ARCHIVE_FATAL); } - self->data = uudecode;- uudecode->in_buff = in_buff;- uudecode->in_cnt = 0;- uudecode->in_allocated = IN_BUFF_SIZE;- uudecode->out_buff = out_buff;- uudecode->state = ST_FIND_HEAD;- uudecode->mode_set = 0;- uudecode->name = NULL;- self->vtable = &uudecode_reader_vtable;+ f->data = uu;+ uu->in_buff = in_buff;+ uu->in_cnt = 0;+ uu->in_allocated = IN_BUFF_SIZE;+ uu->out_buff = out_buff;+ uu->state = ST_FIND_HEAD;+ uu->mode_set = 0;+ uu->name = NULL;+ f->vtable = &uudecode_reader_vtable; return (ARCHIVE_OK); } static int-ensure_in_buff_size(struct archive_read_filter *self,- struct uudecode *uudecode, size_t size)+ensure_in_buff_size(struct archive_read_filter *f,+ struct uu *uu, size_t size) { - if (size > uudecode->in_allocated) {+ if (size > uu->in_allocated) { unsigned char *ptr; size_t newsize; @@ -411,7 +411,7 @@ * Calculate a new buffer size for in_buff. * Increase its value until it is enough for our needs. */- newsize = uudecode->in_allocated;+ newsize = uu->in_allocated; do { if (newsize < IN_BUFF_SIZE*32) newsize <<= 1;@@ -421,42 +421,40 @@ /* Allocate the new buffer. */ ptr = malloc(newsize); if (ptr == NULL) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for uudecode"); return (ARCHIVE_FATAL); } /* Move the remaining data in in_buff into the new buffer. */- if (uudecode->in_cnt)- memmove(ptr, uudecode->in_buff, uudecode->in_cnt);+ if (uu->in_cnt)+ memmove(ptr, uu->in_buff, uu->in_cnt); /* Replace in_buff with the new buffer. */- free(uudecode->in_buff);- uudecode->in_buff = ptr;- uudecode->in_allocated = newsize;+ free(uu->in_buff);+ uu->in_buff = ptr;+ uu->in_allocated = newsize; } return (ARCHIVE_OK); } static int-uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry)+uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry) {-- struct uudecode *uudecode;- uudecode = (struct uudecode *)self->data;+ struct uu *uu = f->data; - if (uudecode->mode_set != 0)- archive_entry_set_mode(entry, S_IFREG | uudecode->mode);+ if (uu->mode_set != 0)+ archive_entry_set_mode(entry, S_IFREG | uu->mode); - if (uudecode->name != NULL)- archive_entry_set_pathname(entry, uudecode->name);+ if (uu->name != NULL)+ archive_entry_set_pathname(entry, uu->name); return (ARCHIVE_OK); } static ssize_t-uudecode_filter_read(struct archive_read_filter *self, const void **buff)+uudecode_filter_read(struct archive_read_filter *f, const void **buff) {- struct uudecode *uudecode;+ struct uu *uu = f->data; const unsigned char *b, *d; unsigned char *out; ssize_t avail_in, ravail;@@ -464,10 +462,8 @@ ssize_t total; ssize_t len, llen, nl, namelen; - uudecode = (struct uudecode *)self->data;- read_more:- d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);+ d = __archive_read_filter_ahead(f->upstream, 1, &avail_in); if (d == NULL && avail_in < 0) return (ARCHIVE_FATAL); /* Quiet a code analyzer; make sure avail_in must be zero@@ -476,17 +472,17 @@ avail_in = 0; used = 0; total = 0;- out = uudecode->out_buff;+ out = uu->out_buff; if (avail_in > 2 * UUENCODE_BID_MAX_READ) avail_in = 2 * UUENCODE_BID_MAX_READ; ravail = avail_in;- if (uudecode->state == ST_IGNORE) {+ if (uu->state == ST_IGNORE) { used = avail_in; goto finish; }- if (uudecode->in_cnt) {- if (uudecode->in_cnt > UUENCODE_BID_MAX_READ) {- archive_set_error(&self->archive->archive,+ if (uu->in_cnt) {+ if (uu->in_cnt > UUENCODE_BID_MAX_READ) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid format data"); return (ARCHIVE_FATAL);@@ -495,14 +491,15 @@ * If there is remaining data which is saved by * a previous call, use it first. */- if (ensure_in_buff_size(self, uudecode,- avail_in + uudecode->in_cnt) != ARCHIVE_OK)+ if (ensure_in_buff_size(f, uu,+ avail_in + uu->in_cnt) != ARCHIVE_OK) return (ARCHIVE_FATAL);- memcpy(uudecode->in_buff + uudecode->in_cnt,- d, avail_in);- d = uudecode->in_buff;- avail_in += uudecode->in_cnt;- uudecode->in_cnt = 0;+ if (avail_in > 0)+ memcpy(uu->in_buff + uu->in_cnt,+ d, avail_in);+ d = uu->in_buff;+ avail_in += uu->in_cnt;+ uu->in_cnt = 0; } for (;used < avail_in; d += llen, used += llen) { ssize_t l, body;@@ -511,28 +508,28 @@ len = get_line(b, avail_in - used, &nl); if (len < 0) { /* Non-ascii character is found. */- if (uudecode->state == ST_FIND_HEAD &&- (uudecode->total > 0 || total > 0)) {- uudecode->state = ST_IGNORE;+ if (uu->state == ST_FIND_HEAD &&+ (uu->total > 0 || total > 0)) {+ uu->state = ST_IGNORE; used = avail_in; goto finish; }- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } if (len > UUENCODE_BID_MAX_READ) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid format data"); return (ARCHIVE_FATAL); } llen = len;- if ((nl == 0) && (uudecode->state != ST_UUEND)) {+ if ((nl == 0) && (uu->state != ST_UUEND)) { if (total == 0 && ravail <= 0) { /* There is nothing more to read, fail */- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Missing format data"); return (ARCHIVE_FATAL);@@ -541,28 +538,28 @@ * Save remaining data which does not contain * NL('\n','\r'). */- if (ensure_in_buff_size(self, uudecode, len)+ if (ensure_in_buff_size(f, uu, len) != ARCHIVE_OK) return (ARCHIVE_FATAL);- if (uudecode->in_buff != b)- memmove(uudecode->in_buff, b, len);- uudecode->in_cnt = len;+ if (uu->in_buff != b)+ memmove(uu->in_buff, b, len);+ uu->in_cnt = len; if (total == 0) { /* Do not return 0; it means end-of-file. * We should try to read more bytes. */ __archive_read_filter_consume(- self->upstream, ravail);+ f->upstream, ravail); goto read_more; } used += len; break; }- switch (uudecode->state) {+ switch (uu->state) { default: case ST_FIND_HEAD: /* Do not read more than UUENCODE_BID_MAX_READ bytes */ if (total + len >= UUENCODE_BID_MAX_READ) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid format data"); return (ARCHIVE_FATAL);@@ -578,30 +575,30 @@ b[l+1] >= '0' && b[l+1] <= '7' && b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { if (l == 6)- uudecode->state = ST_READ_UU;+ uu->state = ST_READ_UU; else- uudecode->state = ST_READ_BASE64;- uudecode->mode = (mode_t)(+ uu->state = ST_READ_BASE64;+ uu->mode = (mode_t)( ((int)(b[l] - '0') * 64) + ((int)(b[l+1] - '0') * 8) + (int)(b[l+2] - '0'));- uudecode->mode_set = 1;+ uu->mode_set = 1; namelen = len - nl - 4 - l; if (namelen > 1) {- if (uudecode->name != NULL)- free(uudecode->name);- uudecode->name = malloc(namelen + 1);- if (uudecode->name == NULL) {+ if (uu->name != NULL)+ free(uu->name);+ uu->name = malloc(namelen + 1);+ if (uu->name == NULL) { archive_set_error(- &self->archive->archive,+ &f->archive->archive, ENOMEM, "Can't allocate data for uudecode"); return (ARCHIVE_FATAL); }- strncpy(uudecode->name,+ strncpy(uu->name, (const char *)(b + l + 4), namelen);- uudecode->name[namelen] = '\0';+ uu->name[namelen] = '\0'; } } break;@@ -610,7 +607,7 @@ goto finish; body = len - nl; if (!uuchar[*b] || body <= 0) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL);@@ -619,13 +616,13 @@ l = UUDECODE(*b++); body--; if (l > body) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } if (l == 0) {- uudecode->state = ST_UUEND;+ uu->state = ST_UUEND; break; } while (l > 0) {@@ -654,7 +651,7 @@ } } if (l) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL);@@ -662,9 +659,9 @@ break; case ST_UUEND: if (len - nl == 3 && memcmp(b, "end ", 3) == 0)- uudecode->state = ST_FIND_HEAD;+ uu->state = ST_FIND_HEAD; else {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL);@@ -676,7 +673,7 @@ l = len - nl; if (l >= 3 && b[0] == '=' && b[1] == '=' && b[2] == '=') {- uudecode->state = ST_FIND_HEAD;+ uu->state = ST_FIND_HEAD; break; } while (l > 0) {@@ -709,7 +706,7 @@ } } if (l && *b != '=') {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL);@@ -720,23 +717,22 @@ finish: if (ravail < avail_in) used -= avail_in - ravail;- __archive_read_filter_consume(self->upstream, used);+ __archive_read_filter_consume(f->upstream, used); - *buff = uudecode->out_buff;- uudecode->total += total;+ *buff = uu->out_buff;+ uu->total += total; return (total); } static int-uudecode_filter_close(struct archive_read_filter *self)+uudecode_filter_close(struct archive_read_filter *f) {- struct uudecode *uudecode;+ struct uu *uu = f->data; - uudecode = (struct uudecode *)self->data;- free(uudecode->in_buff);- free(uudecode->out_buff);- free(uudecode->name);- free(uudecode);+ free(uu->in_buff);+ free(uu->out_buff);+ free(uu->name);+ free(uu); return (ARCHIVE_OK); }
c/archive_read_support_filter_xz.c view
@@ -50,7 +50,7 @@ #if HAVE_LZMA_H && HAVE_LIBLZMA -struct private_data {+struct xz { lzma_stream stream; unsigned char *out_block; size_t out_block_size;@@ -197,14 +197,14 @@ * Test whether we can handle this data. */ static int-xz_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+xz_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *buffer; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - buffer = __archive_read_filter_ahead(filter, 6, NULL);+ buffer = __archive_read_filter_ahead(f, 6, NULL); if (buffer == NULL) return (0); @@ -230,17 +230,17 @@ * they have other evidence (file name, command-line option) to go on. */ static int-lzma_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+lzma_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *buffer; uint32_t dicsize; uint64_t uncompressed_size; int bits_checked; - (void)self; /* UNUSED */+ (void)b; /* UNUSED */ - buffer = __archive_read_filter_ahead(filter, 14, NULL);+ buffer = __archive_read_filter_ahead(f, 14, NULL); if (buffer == NULL) return (0); @@ -336,13 +336,13 @@ } static int-lzip_has_member(struct archive_read_filter *filter)+lzip_has_member(struct archive_read_filter *f) { const unsigned char *buffer; int bits_checked; int log2dic; - buffer = __archive_read_filter_ahead(filter, 6, NULL);+ buffer = __archive_read_filter_ahead(f, 6, NULL); if (buffer == NULL) return (0); @@ -369,12 +369,12 @@ } static int-lzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+lzip_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { - (void)self; /* UNUSED */- return (lzip_has_member(filter));+ (void)b; /* UNUSED */+ return (lzip_has_member(f)); } #if HAVE_LZMA_H && HAVE_LIBLZMA@@ -383,34 +383,34 @@ * liblzma 4.999.7 and later support both lzma and xz streams. */ static int-xz_bidder_init(struct archive_read_filter *self)+xz_bidder_init(struct archive_read_filter *f) {- self->code = ARCHIVE_FILTER_XZ;- self->name = "xz";- return (xz_lzma_bidder_init(self));+ f->code = ARCHIVE_FILTER_XZ;+ f->name = "xz";+ return (xz_lzma_bidder_init(f)); } static int-lzma_bidder_init(struct archive_read_filter *self)+lzma_bidder_init(struct archive_read_filter *f) {- self->code = ARCHIVE_FILTER_LZMA;- self->name = "lzma";- return (xz_lzma_bidder_init(self));+ f->code = ARCHIVE_FILTER_LZMA;+ f->name = "lzma";+ return (xz_lzma_bidder_init(f)); } static int-lzip_bidder_init(struct archive_read_filter *self)+lzip_bidder_init(struct archive_read_filter *f) {- self->code = ARCHIVE_FILTER_LZIP;- self->name = "lzip";- return (xz_lzma_bidder_init(self));+ f->code = ARCHIVE_FILTER_LZIP;+ f->name = "lzip";+ return (xz_lzma_bidder_init(f)); } /* * Set an error code and choose an error message */ static void-set_error(struct archive_read_filter *self, int ret)+set_error(struct archive_read_filter *f, int ret) { switch (ret) {@@ -418,36 +418,36 @@ case LZMA_OK: /* Decompressor made some progress. */ break; case LZMA_MEM_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Lzma library error: Cannot allocate memory"); break; case LZMA_MEMLIMIT_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Lzma library error: Out of memory"); break; case LZMA_FORMAT_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: format not recognized"); break; case LZMA_OPTIONS_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: Invalid options"); break; case LZMA_DATA_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: Corrupted input data"); break; case LZMA_BUF_ERROR:- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: No progress is possible"); break; default: /* Return an error. */- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma decompression failed: Unknown error"); break;@@ -464,84 +464,83 @@ * Setup the callbacks. */ static int-xz_lzma_bidder_init(struct archive_read_filter *self)+xz_lzma_bidder_init(struct archive_read_filter *f) { static const size_t out_block_size = 64 * 1024; void *out_block;- struct private_data *state;+ struct xz *xz; int ret; - state = calloc(1, sizeof(*state));+ xz = calloc(1, sizeof(*xz)); out_block = malloc(out_block_size);- if (state == NULL || out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,+ if (xz == NULL || out_block == NULL) {+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for xz decompression"); free(out_block);- free(state);+ free(xz); return (ARCHIVE_FATAL); } - self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &xz_lzma_reader_vtable;+ f->data = xz;+ xz->out_block_size = out_block_size;+ xz->out_block = out_block;+ f->vtable = &xz_lzma_reader_vtable; - state->stream.avail_in = 0;+ xz->stream.avail_in = 0; - state->stream.next_out = state->out_block;- state->stream.avail_out = state->out_block_size;+ xz->stream.next_out = xz->out_block;+ xz->stream.avail_out = xz->out_block_size; - state->crc32 = 0;- if (self->code == ARCHIVE_FILTER_LZIP) {+ xz->crc32 = 0;+ if (f->code == ARCHIVE_FILTER_LZIP) { /* * We have to read a lzip header and use it to initialize * compression library, thus we cannot initialize the * library for lzip here. */- state->in_stream = 0;+ xz->in_stream = 0; return (ARCHIVE_OK); } else- state->in_stream = 1;+ xz->in_stream = 1; /* Initialize compression library. */- if (self->code == ARCHIVE_FILTER_XZ)- ret = lzma_stream_decoder(&(state->stream),+ if (f->code == ARCHIVE_FILTER_XZ)+ ret = lzma_stream_decoder(&(xz->stream), LZMA_MEMLIMIT,/* memlimit */ LZMA_CONCATENATED); else- ret = lzma_alone_decoder(&(state->stream),+ ret = lzma_alone_decoder(&(xz->stream), LZMA_MEMLIMIT);/* memlimit */ if (ret == LZMA_OK) return (ARCHIVE_OK); /* Library setup failed: Choose an error message and clean up. */- set_error(self, ret);+ set_error(f, ret); - free(state->out_block);- free(state);- self->data = NULL;- self->vtable = NULL;+ free(xz->out_block);+ free(xz);+ f->data = NULL;+ f->vtable = NULL; return (ARCHIVE_FATAL); } static int-lzip_init(struct archive_read_filter *self)+lzip_init(struct archive_read_filter *f) {- struct private_data *state;+ struct xz *xz = f->data; const unsigned char *h; lzma_filter filters[2]; unsigned char props[5]; uint32_t dicsize; int log2dic, ret; - state = (struct private_data *)self->data;- h = __archive_read_filter_ahead(self->upstream, 6, NULL);+ h = __archive_read_filter_ahead(f->upstream, 6, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Get a version number. */- state->lzip_ver = h[4];+ xz->lzip_ver = h[4]; /* * Setup lzma property.@@ -558,8 +557,8 @@ archive_le32enc(props+1, dicsize); /* Consume lzip header. */- __archive_read_filter_consume(self->upstream, 6);- state->member_in = 6;+ __archive_read_filter_consume(f->upstream, 6);+ xz->member_in = 6; filters[0].id = LZMA_FILTER_LZMA1; filters[0].options = NULL;@@ -568,74 +567,73 @@ ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props)); if (ret != LZMA_OK) {- set_error(self, ret);+ set_error(f, ret); return (ARCHIVE_FATAL); }- ret = lzma_raw_decoder(&(state->stream), filters);+ ret = lzma_raw_decoder(&(xz->stream), filters); free(filters[0].options); if (ret != LZMA_OK) {- set_error(self, ret);+ set_error(f, ret); return (ARCHIVE_FATAL); } return (ARCHIVE_OK); } static int-lzip_tail(struct archive_read_filter *self)+lzip_tail(struct archive_read_filter *f) {- struct private_data *state;- const unsigned char *f;+ struct xz *xz = f->data;+ const unsigned char *p; ssize_t avail_in; int tail; - state = (struct private_data *)self->data;- if (state->lzip_ver == 0)+ if (xz->lzip_ver == 0) tail = 12; else tail = 20;- f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);- if (f == NULL && avail_in < 0)+ p = __archive_read_filter_ahead(f->upstream, tail, &avail_in);+ if (p == NULL && avail_in < 0) return (ARCHIVE_FATAL);- if (f == NULL || avail_in < tail) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ if (p == NULL || avail_in < tail) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzip: Remaining data is less bytes"); return (ARCHIVE_FAILED); } /* Check the crc32 value of the uncompressed data of the current * member */- if (state->crc32 != archive_le32dec(f)) {+ if (xz->crc32 != archive_le32dec(p)) { #ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzip: CRC32 error"); return (ARCHIVE_FAILED); #endif } /* Check the uncompressed size of the current member */- if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ if ((uint64_t)xz->member_out != archive_le64dec(p + 4)) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzip: Uncompressed size error"); return (ARCHIVE_FAILED); } /* Check the total size of the current member */- if (state->lzip_ver == 1 &&- (uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+ if (xz->lzip_ver == 1 &&+ (uint64_t)xz->member_in + tail != archive_le64dec(p + 12)) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Lzip: Member size error"); return (ARCHIVE_FAILED); }- __archive_read_filter_consume(self->upstream, tail);+ __archive_read_filter_consume(f->upstream, tail); /* If current lzip data consists of multi member, try decompressing * a next member. */- if (lzip_has_member(self->upstream) != 0) {- state->in_stream = 0;- state->crc32 = 0;- state->member_out = 0;- state->member_in = 0;- state->eof = 0;+ if (lzip_has_member(f->upstream) != 0) {+ xz->in_stream = 0;+ xz->crc32 = 0;+ xz->member_out = 0;+ xz->member_in = 0;+ xz->eof = 0; } return (ARCHIVE_OK); }@@ -644,82 +642,80 @@ * Return the next block of decompressed data. */ static ssize_t-xz_filter_read(struct archive_read_filter *self, const void **p)+xz_filter_read(struct archive_read_filter *f, const void **p) {- struct private_data *state;+ struct xz *xz = f->data; size_t decompressed; ssize_t avail_in; int64_t member_in; int ret; - state = (struct private_data *)self->data;- redo: /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = state->out_block_size;- member_in = state->member_in;+ xz->stream.next_out = xz->out_block;+ xz->stream.avail_out = xz->out_block_size;+ member_in = xz->member_in; /* Try to fill the output buffer. */- while (state->stream.avail_out > 0 && !state->eof) {- if (!state->in_stream) {+ while (xz->stream.avail_out > 0 && !xz->eof) {+ if (!xz->in_stream) { /* * Initialize liblzma for lzip */- ret = lzip_init(self);+ ret = lzip_init(f); if (ret != ARCHIVE_OK) return (ret);- state->in_stream = 1;+ xz->in_stream = 1; }- state->stream.next_in =- __archive_read_filter_ahead(self->upstream, 1, &avail_in);- if (state->stream.next_in == NULL && avail_in < 0) {- archive_set_error(&self->archive->archive,+ xz->stream.next_in =+ __archive_read_filter_ahead(f->upstream, 1, &avail_in);+ if (xz->stream.next_in == NULL && avail_in < 0) {+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "truncated input"); return (ARCHIVE_FATAL); }- state->stream.avail_in = avail_in;+ xz->stream.avail_in = avail_in; /* Decompress as much as we can in one pass. */- ret = lzma_code(&(state->stream),- (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);+ ret = lzma_code(&(xz->stream),+ (xz->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN); switch (ret) { case LZMA_STREAM_END: /* Found end of stream. */- state->eof = 1;+ xz->eof = 1; /* FALL THROUGH */ case LZMA_OK: /* Decompressor made some progress. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);- state->member_in +=- avail_in - state->stream.avail_in;+ __archive_read_filter_consume(f->upstream,+ avail_in - xz->stream.avail_in);+ xz->member_in +=+ avail_in - xz->stream.avail_in; break; default:- set_error(self, ret);+ set_error(f, ret); return (ARCHIVE_FATAL); } } - decompressed = state->stream.next_out - state->out_block;- state->member_out += decompressed;+ decompressed = xz->stream.next_out - xz->out_block;+ xz->member_out += decompressed; if (decompressed == 0) {- if (member_in != state->member_in &&- self->code == ARCHIVE_FILTER_LZIP &&- state->eof) {- ret = lzip_tail(self);+ if (member_in != xz->member_in &&+ f->code == ARCHIVE_FILTER_LZIP &&+ xz->eof) {+ ret = lzip_tail(f); if (ret != ARCHIVE_OK) return (ret);- if (!state->eof)+ if (!xz->eof) goto redo; } *p = NULL; } else {- *p = state->out_block;- if (self->code == ARCHIVE_FILTER_LZIP) {- state->crc32 = lzma_crc32(state->out_block,- decompressed, state->crc32);- if (state->eof) {- ret = lzip_tail(self);+ *p = xz->out_block;+ if (f->code == ARCHIVE_FILTER_LZIP) {+ xz->crc32 = lzma_crc32(xz->out_block,+ decompressed, xz->crc32);+ if (xz->eof) {+ ret = lzip_tail(f); if (ret != ARCHIVE_OK) return (ret); }@@ -732,14 +728,13 @@ * Clean up the decompressor. */ static int-xz_filter_close(struct archive_read_filter *self)+xz_filter_close(struct archive_read_filter *f) {- struct private_data *state;+ struct xz *xz = f->data; - state = (struct private_data *)self->data;- lzma_end(&(state->stream));- free(state->out_block);- free(state);+ lzma_end(&(xz->stream));+ free(xz->out_block);+ free(xz); return (ARCHIVE_OK); } @@ -753,44 +748,44 @@ * */ static int-lzma_bidder_init(struct archive_read_filter *self)+lzma_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "lzma -d -qq");+ r = __archive_read_program(f, "lzma -d -qq"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZMA;- self->name = "lzma";+ f->code = ARCHIVE_FILTER_LZMA;+ f->name = "lzma"; return (r); } static int-xz_bidder_init(struct archive_read_filter *self)+xz_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "xz -d -qq");+ r = __archive_read_program(f, "xz -d -qq"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_XZ;- self->name = "xz";+ f->code = ARCHIVE_FILTER_XZ;+ f->name = "xz"; return (r); } static int-lzip_bidder_init(struct archive_read_filter *self)+lzip_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "lzip -d -q");+ r = __archive_read_program(f, "lzip -d -q"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZIP;- self->name = "lzip";+ f->code = ARCHIVE_FILTER_LZIP;+ f->name = "lzip"; return (r); }
c/archive_read_support_filter_zstd.c view
@@ -54,7 +54,7 @@ #if HAVE_ZSTD_H && HAVE_LIBZSTD -struct private_data {+struct zstd { ZSTD_DStream *dstream; unsigned char *out_block; size_t out_block_size;@@ -104,8 +104,8 @@ * Test whether we can handle this data. */ static int-zstd_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)+zstd_bidder_bid(struct archive_read_filter_bidder *b,+ struct archive_read_filter *f) { const unsigned char *buffer; ssize_t avail;@@ -132,9 +132,9 @@ const uint32_t zstd_magic_skippable_start = 0x184D2A50; const uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0; - (void) self; /* UNUSED */+ (void) b; /* UNUSED */ - buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size,+ buffer = __archive_read_filter_ahead(f, min_zstd_frame_size, &avail); if (buffer == NULL) return (0);@@ -151,7 +151,7 @@ /* Ensure that we can read another 4 bytes. */ if (offset_in_buffer + 4 > (size_t)avail) {- buffer = __archive_read_filter_ahead(filter,+ buffer = __archive_read_filter_ahead(f, offset_in_buffer + 4, &avail); if (buffer == NULL) return (0);@@ -178,7 +178,7 @@ if (min > max_lookahead) return (0); - buffer = __archive_read_filter_ahead(filter,+ buffer = __archive_read_filter_ahead(f, min, &avail); if (buffer == NULL) return (0);@@ -206,16 +206,16 @@ * in case that's available. */ static int-zstd_bidder_init(struct archive_read_filter *self)+zstd_bidder_init(struct archive_read_filter *f) { int r; - r = __archive_read_program(self, "zstd -d -qq");+ r = __archive_read_program(f, "zstd -d -qq"); /* Note: We set the format here even if __archive_read_program() * above fails. We do, after all, know what the format is * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_ZSTD;- self->name = "zstd";+ f->code = ARCHIVE_FILTER_ZSTD;+ f->name = "zstd"; return (r); } @@ -231,80 +231,78 @@ * Initialize the filter object */ static int-zstd_bidder_init(struct archive_read_filter *self)+zstd_bidder_init(struct archive_read_filter *f) {- struct private_data *state;+ struct zstd *zstd; size_t out_block_size = ZSTD_DStreamOutSize(); void *out_block; ZSTD_DStream *dstream; - self->code = ARCHIVE_FILTER_ZSTD;- self->name = "zstd";+ f->code = ARCHIVE_FILTER_ZSTD;+ f->name = "zstd"; - state = calloc(1, sizeof(*state));+ zstd = calloc(1, sizeof(*zstd)); out_block = malloc(out_block_size); dstream = ZSTD_createDStream(); - if (state == NULL || out_block == NULL || dstream == NULL) {+ if (zstd == NULL || out_block == NULL || dstream == NULL) { free(out_block);- free(state);+ free(zstd); ZSTD_freeDStream(dstream); /* supports free on NULL */- archive_set_error(&self->archive->archive, ENOMEM,+ archive_set_error(&f->archive->archive, ENOMEM, "Can't allocate data for zstd decompression"); return (ARCHIVE_FATAL); } - self->data = state;+ f->data = zstd; - state->out_block_size = out_block_size;- state->out_block = out_block;- state->dstream = dstream;- self->vtable = &zstd_reader_vtable;+ zstd->out_block_size = out_block_size;+ zstd->out_block = out_block;+ zstd->dstream = dstream;+ f->vtable = &zstd_reader_vtable; - state->eof = 0;- state->in_frame = 0;+ zstd->eof = 0;+ zstd->in_frame = 0; return (ARCHIVE_OK); } static ssize_t-zstd_filter_read(struct archive_read_filter *self, const void **p)+zstd_filter_read(struct archive_read_filter *f, const void **p) {- struct private_data *state;+ struct zstd *zstd = f->data; size_t decompressed; ssize_t avail_in; ZSTD_outBuffer out; ZSTD_inBuffer in; size_t ret; - state = (struct private_data *)self->data;-- out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };+ out = (ZSTD_outBuffer) { zstd->out_block, zstd->out_block_size, 0 }; /* Try to fill the output buffer. */- while (out.pos < out.size && !state->eof) {- if (!state->in_frame) {- ret = ZSTD_initDStream(state->dstream);+ while (out.pos < out.size && !zstd->eof) {+ if (!zstd->in_frame) {+ ret = ZSTD_initDStream(zstd->dstream); if (ZSTD_isError(ret)) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Error initializing zstd decompressor: %s", ZSTD_getErrorName(ret)); return (ARCHIVE_FATAL); } }- in.src = __archive_read_filter_ahead(self->upstream, 1,+ in.src = __archive_read_filter_ahead(f->upstream, 1, &avail_in); if (avail_in < 0) { return avail_in; } if (in.src == NULL && avail_in == 0) {- if (!state->in_frame) {+ if (!zstd->in_frame) { /* end of stream */- state->eof = 1;+ zstd->eof = 1; break; } else {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Truncated zstd input"); return (ARCHIVE_FATAL);@@ -314,10 +312,10 @@ in.pos = 0; {- ret = ZSTD_decompressStream(state->dstream, &out, &in);+ ret = ZSTD_decompressStream(zstd->dstream, &out, &in); if (ZSTD_isError(ret)) {- archive_set_error(&self->archive->archive,+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(ret));@@ -325,10 +323,10 @@ } /* Decompressor made some progress */- __archive_read_filter_consume(self->upstream, in.pos);+ __archive_read_filter_consume(f->upstream, in.pos); /* ret guaranteed to be > 0 if frame isn't done yet */- state->in_frame = (ret != 0);+ zstd->in_frame = (ret != 0); } } @@ -336,7 +334,7 @@ if (decompressed == 0) *p = NULL; else- *p = state->out_block;+ *p = zstd->out_block; return (decompressed); } @@ -344,15 +342,13 @@ * Clean up the decompressor. */ static int-zstd_filter_close(struct archive_read_filter *self)+zstd_filter_close(struct archive_read_filter *f) {- struct private_data *state;-- state = (struct private_data *)self->data;+ struct zstd *zstd = f->data; - ZSTD_freeDStream(state->dstream);- free(state->out_block);- free(state);+ ZSTD_freeDStream(zstd->dstream);+ free(zstd->out_block);+ free(zstd); return (ARCHIVE_OK); }
c/archive_read_support_format_7zip.c view
@@ -53,6 +53,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_ppmd7_private.h" #include "archive_private.h" #include "archive_read_private.h"@@ -72,12 +73,12 @@ /* * PE format */-#define PE_DOS_HDR_LEN 0x40+#define PE_DOS_HDR_LEN 0x40 #define PE_DOS_HDR_ELFANEW_OFFSET 0x3c-#define PE_COFF_HDR_LEN 0x18+#define PE_COFF_HDR_LEN 0x18 #define PE_COFF_HDR_SEC_CNT_OFFSET 0x6 #define PE_COFF_HDR_OPT_SZ_OFFSET 0x14-#define PE_SEC_HDR_LEN 0x28+#define PE_SEC_HDR_LEN 0x28 #define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14 #define PE_SEC_HDR_RAW_SZ_OFFSET 0x10 @@ -98,8 +99,8 @@ #define _7Z_BZ2 0x040202 #define _7Z_PPMD 0x030401 #define _7Z_DELTA 0x03-#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */-#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */+#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */+#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */ #define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */ @@ -173,50 +174,48 @@ }; struct _7z_folder {- uint64_t numCoders;+ size_t numCoders; struct _7z_coder {- uint64_t codec;- uint64_t numInStreams;- uint64_t numOutStreams;- uint64_t propertiesSize;+ int64_t codec;+ size_t numInStreams;+ size_t numOutStreams;+ size_t propertiesSize; unsigned char *properties; } *coders;- uint64_t numBindPairs;+ size_t numBindPairs; struct {- uint64_t inIndex;- uint64_t outIndex;+ size_t inIndex;+ size_t outIndex; } *bindPairs;- uint64_t numPackedStreams;- uint64_t *packedStreams;- uint64_t numInStreams;- uint64_t numOutStreams;- uint64_t *unPackSize;+ size_t numPackedStreams;+ size_t numInStreams;+ size_t numOutStreams;+ int64_t *unPackSize; unsigned char digest_defined; uint32_t digest;- uint64_t numUnpackStreams;- uint32_t packIndex;+ size_t numUnpackStreams;+ size_t packIndex; /* Unoperated bytes. */- uint64_t skipped_bytes;+ int64_t skipped_bytes; }; struct _7z_coders_info {- uint64_t numFolders;+ size_t numFolders; struct _7z_folder *folders;- uint64_t dataStreamIndex; }; struct _7z_pack_info {- uint64_t pos;- uint64_t numPackStreams;- uint64_t *sizes;+ int64_t pos;+ size_t numPackStreams;+ int64_t *sizes; struct _7z_digests digest; /* Calculated from pos and numPackStreams. */- uint64_t *positions;+ int64_t *positions; }; struct _7z_substream_info { size_t unpack_streams;- uint64_t *unpackSizes;+ int64_t *unpackSizes; unsigned char *digestsDefined; uint32_t *digests; };@@ -228,8 +227,6 @@ }; struct _7z_header_info {- uint64_t dataIndex;- unsigned char *emptyStreamBools; unsigned char *emptyFileBools; unsigned char *antiBools;@@ -242,8 +239,8 @@ #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) const wchar_t *wname; #endif- uint32_t folderIndex;- uint32_t ssIndex;+ size_t folderIndex;+ size_t ssIndex; unsigned flg; #define MTIME_IS_SET (1<<0) #define ATIME_IS_SET (1<<1)@@ -267,24 +264,24 @@ int header_is_being_read; int header_is_encoded;- uint64_t header_bytes_remaining;+ int64_t header_bytes_remaining; unsigned long header_crc32; /* Header offset to check that reading points of the file contents * will not exceed the header. */- uint64_t header_offset;+ int64_t header_offset; /* Base offset of the archive file for a seek in case reading SFX. */- uint64_t seek_base;+ int64_t seek_base; /* List of entries */ size_t entries_remaining;- uint64_t numFiles;+ size_t numFiles; struct _7zip_entry *entries; struct _7zip_entry *entry; unsigned char *entry_names; /* entry_bytes_remaining is the number of bytes we expect. */ int64_t entry_offset;- uint64_t entry_bytes_remaining;+ int64_t entry_bytes_remaining; /* Running CRC32 of the decompressed data */ unsigned long entry_crc32;@@ -305,16 +302,16 @@ /* * Decompressing control data. */- unsigned folder_index;- uint64_t folder_outbytes_remaining;- unsigned pack_stream_index;- unsigned pack_stream_remaining;- uint64_t pack_stream_inbytes_remaining;- size_t pack_stream_bytes_unconsumed;+ size_t folder_index;+ int64_t folder_outbytes_remaining;+ size_t pack_stream_index;+ size_t pack_stream_remaining;+ int64_t pack_stream_inbytes_remaining;+ int64_t pack_stream_bytes_unconsumed; /* The codec information of a folder. */- unsigned long codec;- unsigned long codec2;+ int64_t codec;+ int64_t codec2; /* * Decompressor controllers.@@ -364,7 +361,7 @@ uint32_t bcj_ip; /* Decoding BCJ2 data. */- size_t main_stream_bytes_remaining;+ int64_t main_stream_bytes_remaining; unsigned char *sub_stream_buff[3]; size_t sub_stream_size[3]; size_t sub_stream_bytes_remaining[3];@@ -381,13 +378,11 @@ uint8_t bcj2_prevByte; uint32_t bcj2_range; uint32_t bcj2_code;- uint64_t bcj2_outPos;+ size_t bcj2_outPos; /* Filename character-set conversion data. */ struct archive_string_conv *sconv; - char format_name[64];- /* Custom value that is non-zero if this archive contains encrypted entries. */ int has_encrypted_entries; };@@ -395,31 +390,14 @@ /* Maximum entry size. This limitation prevents reading intentional * corrupted 7-zip files on assuming there are not so many entries in * the files. */-#define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000)--/*- * Files without unpack streams must be described by the EmptyStream bitmap,- * which consumes one bit for every file entry in FilesInfo.- */-static int-files_info_numfiles_is_sane(const struct _7zip *zip)-{- uint64_t empty_stream_map_bytes;-- if (zip->numFiles > UMAX_ENTRY)- return (0);- if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))- return (0);-- if (zip->numFiles <= zip->si.ss.unpack_streams)- return (1);+#define UMAX_ENTRY ARCHIVE_LITERAL_LL(100000000) - empty_stream_map_bytes = (zip->numFiles + 7) / 8;- return (empty_stream_map_bytes <= zip->header_bytes_remaining);-}+/* Don't try to read more than 16 MB at a time */+#define MAX_READ 16 * 1024 * 1024 +static size_t align_size(size_t); static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *);-static int archive_read_support_format_7zip_capabilities(struct archive_read *a);+static int archive_read_support_format_7zip_capabilities(struct archive_read *); static int archive_read_format_7zip_bid(struct archive_read *, int); static int archive_read_format_7zip_cleanup(struct archive_read *); static int archive_read_format_7zip_read_data(struct archive_read *,@@ -427,14 +405,15 @@ static int archive_read_format_7zip_read_data_skip(struct archive_read *); static int archive_read_format_7zip_read_header(struct archive_read *, struct archive_entry *);-static int check_7zip_header_in_sfx(const unsigned char *);-static int decode_codec_id(const unsigned char *, size_t, uint64_t *);+static size_t check_7zip_header_in_sfx(const unsigned char *);+static int decode_codec_id(const unsigned char *, size_t, int64_t *); static int decode_encoded_header_info(struct archive_read *, struct _7z_stream_info *); static int decompress(struct archive_read *, struct _7zip *, void *, size_t *, const void *, size_t *); static ssize_t extract_pack_stream(struct archive_read *, size_t);-static uint64_t folder_uncompressed_size(struct _7z_folder *);+static int files_info_numfiles_is_sane(const struct _7zip *);+static int64_t folder_uncompressed_size(struct _7z_folder *); static void free_CodersInfo(struct _7z_coders_info *); static void free_Digest(struct _7z_digests *); static void free_Folder(struct _7z_folder *);@@ -445,10 +424,11 @@ static int free_decompression(struct archive_read *, struct _7zip *); static ssize_t get_uncompressed_data(struct archive_read *, const void **, size_t, size_t);-static const unsigned char * header_bytes(struct archive_read *, size_t);+static const unsigned char *header_bytes(struct archive_read *, size_t); static int init_decompression(struct archive_read *, struct _7zip *, const struct _7z_coder *, const struct _7z_coder *);-static int parse_7zip_uint64(struct archive_read *, uint64_t *);+static int parse_7zip_size(struct archive_read *, size_t *);+static int parse_7zip_int64(struct archive_read *, int64_t *); static int read_Bools(struct archive_read *, unsigned char *, size_t); static int read_CodersInfo(struct archive_read *, struct _7z_coders_info *);@@ -462,13 +442,12 @@ struct _7z_stream_info *); static int read_SubStreamsInfo(struct archive_read *, struct _7z_substream_info *, struct _7z_folder *, size_t);-static int read_Times(struct archive_read *, struct _7z_header_info *,- int);-static void read_consume(struct archive_read *);+static int read_Times(struct archive_read *, int);+static int read_consume(struct archive_read *); static ssize_t read_stream(struct archive_read *, const void **, size_t, size_t); static int seek_pack(struct archive_read *);-static int64_t skip_stream(struct archive_read *, size_t);+static int skip_stream(struct archive_read *, int64_t); static int get_data_offset(struct archive_read *, int64_t *, int); static int get_pe_sfx_offset(struct archive_read *, int64_t *); static int get_elf_sfx_offset(struct archive_read *, int64_t *, int);@@ -481,7 +460,7 @@ static void arm_Init(struct _7zip *); static size_t arm_Convert(struct _7zip *, uint8_t *, size_t); static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);-static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);+static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t); static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t); static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t); static int64_t seek_compat(struct archive_read *, int64_t, int, int);@@ -530,19 +509,18 @@ } static int-archive_read_support_format_7zip_capabilities(struct archive_read * a)+archive_read_support_format_7zip_capabilities(struct archive_read *a) { (void)a; /* UNUSED */ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); } - static int-archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)+archive_read_format_7zip_has_encrypted_entries(struct archive_read *a) {- if (_a && _a->format) {- struct _7zip * zip = (struct _7zip *)_a->format->data;+ if (a && a->format) {+ struct _7zip *zip = a->format->data; if (zip) { return zip->has_encrypted_entries; }@@ -601,8 +579,8 @@ continue; } p = buff + offset;- while (p + 32 < buff + bytes_avail) {- int step = check_7zip_header_in_sfx(p);+ while (buff + bytes_avail - p >= 32) {+ size_t step = check_7zip_header_in_sfx(p); if (step == 0) { *data_offset = p - buff; return (ARCHIVE_OK);@@ -633,7 +611,7 @@ return (48); } -static int+static size_t check_7zip_header_in_sfx(const unsigned char *p) { switch (p[5]) {@@ -798,7 +776,7 @@ e_shentsize = (*dec16)(h + 0x3A); e_shnum = (*dec16)(h + 0x3C); e_shstrndx = (*dec16)(h + 0x3E);- if (e_shnum < e_shstrndx || e_shentsize < 0x28)+ if (e_shnum <= e_shstrndx || e_shentsize < 0x28) break; } else {@@ -806,7 +784,7 @@ e_shentsize = (*dec16)(h + 0x2E); e_shnum = (*dec16)(h + 0x30); e_shstrndx = (*dec16)(h + 0x32);- if (e_shnum < e_shstrndx || e_shentsize < 0x18)+ if (e_shnum <= e_shstrndx || e_shentsize < 0x18) break; } @@ -860,7 +838,7 @@ return (ARCHIVE_FATAL); } size_t data_sym_offset = strtab_size;- for (size_t offset = 0; offset < strtab_size - 6; offset++) {+ for (size_t offset = 0; offset + 6 <= strtab_size; offset++) { if (memcmp(h + offset, ".data\00", 6) == 0) { data_sym_offset = offset; break;@@ -916,11 +894,10 @@ archive_read_format_7zip_read_header(struct archive_read *a, struct archive_entry *entry) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; struct _7zip_entry *zip_entry; int r, ret = ARCHIVE_OK; struct _7z_folder *folder = 0;- uint64_t fidx = 0; /* * It should be sufficient to call archive_read_next_header() for@@ -934,8 +911,7 @@ } a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "7-Zip";+ a->archive.archive_format_name = "7-Zip"; if (zip->entries == NULL) { struct _7z_header_info header;@@ -945,20 +921,20 @@ free_Header(&header); if (r != ARCHIVE_OK) return (r);- zip->entries_remaining = (size_t)zip->numFiles;+ zip->entries_remaining = zip->numFiles; zip->entry = zip->entries; } else { ++zip->entry; } zip_entry = zip->entry; - if (zip->entries_remaining <= 0 || zip_entry == NULL)+ if (zip->entries_remaining == 0 || zip_entry == NULL) return ARCHIVE_EOF; --zip->entries_remaining; zip->entry_offset = 0; zip->end_of_entry = 0;- zip->entry_crc32 = crc32(0, NULL, 0);+ zip->entry_crc32 = 0; /* Setup a string conversion for a filename. */ if (zip->sconv == NULL) {@@ -972,9 +948,11 @@ that is associated to the current 7zip entry. If the folder has a coder with a _7Z_CRYPTO codec then the folder is encrypted. Hence the entry must also be encrypted. */- if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) {+ if (zip_entry->folderIndex < zip->si.ci.numFolders) {+ size_t fidx = 0;+ folder = &(zip->si.ci.folders[zip_entry->folderIndex]);- for (fidx=0; folder && fidx<folder->numCoders; fidx++) {+ for (fidx = 0; fidx < folder->numCoders; fidx++) { switch(folder->coders[fidx].codec) { case _7Z_CRYPTO_MAIN_ZIP: case _7Z_CRYPTO_RAR_29:@@ -987,13 +965,6 @@ } } - /* Now that we've checked for encryption, if there were still no- * encrypted entries found we can say for sure that there are none.- */- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }- if (archive_entry_copy_pathname_l(entry, (const char *)zip_entry->utf16name, zip_entry->name_len, zip->sconv) != 0) {@@ -1021,7 +992,7 @@ if (zip_entry->flg & ATIME_IS_SET) archive_entry_set_atime(entry, zip_entry->atime, zip_entry->atime_ns);- if (zip_entry->ssIndex != (uint32_t)-1) {+ if (zip_entry->ssIndex != (size_t)-1) { zip->entry_bytes_remaining = zip->si.ss.unpackSizes[zip_entry->ssIndex]; archive_entry_set_size(entry, zip->entry_bytes_remaining);@@ -1035,8 +1006,8 @@ if (zip_entry->attr & supported_attrs) { char buf[sizeof(",rdonly,hidden,system")];- char *fflags[3] = { "", "", "" };- char **flag = fflags;+ const char *fflags[3] = { "", "", "" };+ const char **flag = fflags; if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) *flag++ = ",rdonly";@@ -1117,10 +1088,6 @@ archive_entry_set_size(entry, 0); } - /* Set up a more descriptive format name. */- snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");- a->archive.archive_format_name = zip->format_name;- return (ret); } @@ -1128,12 +1095,10 @@ archive_read_format_7zip_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct _7zip *zip;+ struct _7zip *zip = a->format->data; ssize_t bytes; int ret = ARCHIVE_OK; - zip = (struct _7zip *)(a->format->data);- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { zip->has_encrypted_entries = 0; }@@ -1151,8 +1116,8 @@ if (zip->end_of_entry) return (ARCHIVE_EOF); - size_t bytes_to_read = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time- if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {+ size_t bytes_to_read = MAX_READ;+ if ((int64_t)bytes_to_read > zip->entry_bytes_remaining) { bytes_to_read = (size_t)zip->entry_bytes_remaining; } bytes = read_stream(a, buff, bytes_to_read, 0);@@ -1181,7 +1146,7 @@ zip->entry_crc32) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "7-Zip bad CRC: 0x%lx should be 0x%lx",- (unsigned long)zip->entry_crc32,+ zip->entry_crc32, (unsigned long)zip->si.ss.digests[ zip->entry->ssIndex]); ret = ARCHIVE_WARN;@@ -1198,10 +1163,8 @@ static int archive_read_format_7zip_read_data_skip(struct archive_read *a) {- struct _7zip *zip;- int64_t bytes_skipped;-- zip = (struct _7zip *)(a->format->data);+ struct _7zip *zip = a->format->data;+ int r; if (zip->pack_stream_bytes_unconsumed) read_consume(a);@@ -1214,9 +1177,9 @@ * If the length is at the beginning, we can skip the * compressed data much more quickly. */- bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);- if (bytes_skipped < 0)- return ((int)bytes_skipped);+ r = skip_stream(a, zip->entry_bytes_remaining);+ if (r < 0)+ return (r); zip->entry_bytes_remaining = 0; /* This entry is finished and done. */@@ -1227,9 +1190,8 @@ static int archive_read_format_7zip_cleanup(struct archive_read *a) {- struct _7zip *zip;+ struct _7zip *zip = a->format->data; - zip = (struct _7zip *)(a->format->data); free_StreamsInfo(&(zip->si)); free(zip->entries); free(zip->entry_names);@@ -1240,24 +1202,30 @@ free(zip->sub_stream_buff[2]); free(zip->tmp_stream_buff); free(zip);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } -static void+static int read_consume(struct archive_read *a) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; if (zip->pack_stream_bytes_unconsumed) {- __archive_read_consume(a, zip->pack_stream_bytes_unconsumed);+ int64_t r;++ if ((r = __archive_read_consume(a,+ zip->pack_stream_bytes_unconsumed)) < 0)+ return ((int)r);+ zip->stream_offset += zip->pack_stream_bytes_unconsumed; zip->pack_stream_bytes_unconsumed = 0; }++ return (ARCHIVE_OK); } #ifdef HAVE_LZMA_H- /* * Set an error code and choose an error message for liblzma. */@@ -1305,22 +1273,19 @@ break; } }- #endif static int-decode_codec_id(const unsigned char *codecId, size_t id_size, uint64_t *id)+decode_codec_id(const unsigned char *codecId, size_t id_size, int64_t *id) {- unsigned i;- uint64_t v = 0;+ size_t i; + *id = 0; for (i = 0; i < id_size; i++) {- if (v > (uint64_t)INT64_MAX / 256)+ if (archive_ckd_mul_i64(id, *id, 256) ||+ archive_ckd_add_i64(id, *id, codecId[i])) return (-1);- v <<= 8;- v += codecId[i]; }- *id = v; return (0); } @@ -1328,7 +1293,7 @@ ppmd_read(void *p) { struct archive_read *a = ((IByteIn*)p)->a;- struct _7zip *zip = (struct _7zip *)(a->format->data);+ struct _7zip *zip = a->format->data; Byte b; if (zip->ppstream.avail_in == 0) {@@ -1337,7 +1302,7 @@ * and we are on boundary; * last resort to read using __archive_read_ahead. */- const uint8_t* data = __archive_read_ahead(a,+ const uint8_t *data = __archive_read_ahead(a, zip->ppstream.stream_in + 1, NULL); if (data == NULL) { archive_set_error(&a->archive,@@ -1466,7 +1431,7 @@ memset(&delta_opt, 0, sizeof(delta_opt)); delta_opt.type = LZMA_DELTA_TYPE_BYTE; delta_opt.dist =- (uint32_t)coder2->properties[0] + 1;+ coder2->properties[0] + 1; filters[fi].options = &delta_opt; fi++; break;@@ -1506,7 +1471,8 @@ default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unexpected codec ID: %lX", zip->codec2);+ "Unexpected codec ID: %jX",+ (uintmax_t)zip->codec2); return (ARCHIVE_FAILED); } }@@ -1518,7 +1484,7 @@ filters[fi].options = NULL; ff = &filters[fi]; r = lzma_properties_decode(&filters[fi], NULL,- coder1->properties, (size_t)coder1->propertiesSize);+ coder1->properties, coder1->propertiesSize); if (r != LZMA_OK) { set_error(a, r); return (ARCHIVE_FAILED);@@ -1673,7 +1639,7 @@ case _7Z_SPARC: case _7Z_DELTA: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unexpected codec ID: %lX", zip->codec);+ "Unexpected codec ID: %jX", (uintmax_t)zip->codec); return (ARCHIVE_FAILED); case _7Z_CRYPTO_MAIN_ZIP: case _7Z_CRYPTO_RAR_29:@@ -1684,11 +1650,12 @@ zip->has_encrypted_entries = 1; } archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Crypto codec not supported yet (ID: 0x%lX)", zip->codec);+ "Crypto codec not supported yet (ID: 0x%jX)",+ (uintmax_t)zip->codec); return (ARCHIVE_FAILED); default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unknown codec ID: %lX", zip->codec);+ "Unknown codec ID: %jX", (uintmax_t)zip->codec); return (ARCHIVE_FAILED); } @@ -1740,7 +1707,7 @@ bcj2_avail_out = t_avail_out; if (zip->codec2 == _7Z_X86_BCJ2) { /*- * Decord a remaining decompressed main stream for BCJ2.+ * Decode a remaining decompressed main stream for BCJ2. */ if (zip->tmp_stream_bytes_remaining) { ssize_t bytes;@@ -1774,8 +1741,8 @@ switch (zip->codec) { case _7Z_COPY: {- size_t bytes =- (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;+ size_t bytes = (t_avail_in > t_avail_out) ?+ t_avail_out : t_avail_in; memcpy(t_next_out, t_next_in, bytes); t_avail_in -= bytes;@@ -1813,10 +1780,14 @@ #endif #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) case _7Z_BZ2:+ if (t_avail_in > UINT_MAX)+ t_avail_in = UINT_MAX;+ if (t_avail_out > UINT_MAX)+ t_avail_out = UINT_MAX; zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;- zip->bzstream.avail_in = (uint32_t)t_avail_in;+ zip->bzstream.avail_in = (unsigned int)t_avail_in; zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;- zip->bzstream.avail_out = (uint32_t)t_avail_out;+ zip->bzstream.avail_out = (unsigned int)t_avail_out; r = BZ2_bzDecompress(&(zip->bzstream)); switch (r) { case BZ_STREAM_END: /* Found end of stream. */@@ -1846,6 +1817,10 @@ #endif #ifdef HAVE_ZLIB_H case _7Z_DEFLATE:+ if (t_avail_in > UINT_MAX)+ t_avail_in = UINT_MAX;+ if (t_avail_out > UINT_MAX)+ t_avail_out = UINT_MAX; zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in; zip->stream.avail_in = (uInt)t_avail_in; zip->stream.next_out = t_next_out;@@ -1869,12 +1844,17 @@ #if HAVE_ZSTD_H && HAVE_LIBZSTD case _7Z_ZSTD: {- ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos- ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos+ /* src, size, pos */+ ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 };+ /* dst, size, pos */+ ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; - size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);+ size_t const zret = ZSTD_decompressStream(zip->zstd_dstream,+ &output, &input); if (ZSTD_isError(zret)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "Zstd decompression failed: %s",+ ZSTD_getErrorName(zret)); return ARCHIVE_FAILED; } t_avail_in -= input.pos;@@ -1884,7 +1864,7 @@ #endif case _7Z_PPMD: {- uint64_t flush_bytes;+ int64_t flush_bytes; if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 || t_avail_out <= 0) {@@ -1942,7 +1922,7 @@ } *zip->ppstream.next_out++ = (unsigned char)sym; zip->ppstream.avail_out--;- if (flush_bytes)+ if (flush_bytes > 0) flush_bytes--; } while (zip->ppstream.avail_out && (zip->ppstream.avail_in || flush_bytes));@@ -1963,7 +1943,7 @@ *outbytes = o_avail_out - t_avail_out; /*- * Decord BCJ.+ * Decode BCJ. */ if (zip->codec != _7Z_LZMA2) { if (zip->codec2 == _7Z_X86) {@@ -1971,9 +1951,10 @@ zip->odd_bcj_size = *outbytes - l; if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&- o_avail_in && ret != ARCHIVE_EOF) {- memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,- zip->odd_bcj_size);+ o_avail_in && ret != ARCHIVE_EOF) {+ memcpy(zip->odd_bcj,+ ((unsigned char *)buff) + l,+ zip->odd_bcj_size); *outbytes = l; } else zip->odd_bcj_size = 0;@@ -1989,7 +1970,7 @@ } /*- * Decord BCJ2 with a decompressed main stream.+ * Decode BCJ2 with a decompressed main stream. */ if (zip->codec2 == _7Z_X86_BCJ2) { ssize_t bytes;@@ -1997,7 +1978,7 @@ zip->tmp_stream_bytes_avail = zip->tmp_stream_buff_size - t_avail_out; if (zip->tmp_stream_bytes_avail >- zip->main_stream_bytes_remaining)+ (uint64_t)zip->main_stream_bytes_remaining) zip->tmp_stream_bytes_avail = zip->main_stream_bytes_remaining; zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;@@ -2065,8 +2046,21 @@ } static int-parse_7zip_uint64(struct archive_read *a, uint64_t *val)+parse_7zip_size(struct archive_read *a, size_t *val) {+ int64_t v;++ if (parse_7zip_int64(a, &v) < 0 || v > UMAX_ENTRY)+ return (-1);++ *val = (size_t)v;+ return (0);+}++static int+parse_7zip_int64(struct archive_read *a, int64_t *val)+{+ uint64_t v; const unsigned char *p; unsigned char avail, mask; int i;@@ -2075,18 +2069,21 @@ return (-1); avail = *p; mask = 0x80;- *val = 0;+ v = 0; for (i = 0; i < 8; i++) { if (avail & mask) { if ((p = header_bytes(a, 1)) == NULL) return (-1);- *val |= ((uint64_t)*p) << (8 * i);+ v |= ((uint64_t)*p) << (8 * i); mask >>= 1; continue; }- *val += ((uint64_t)(avail & (mask -1))) << (8 * i);+ v += ((uint64_t)(avail & (mask - 1))) << (8 * i); break; }+ if (v > (uint64_t)INT64_MAX)+ return (-1);+ *val = (int64_t)v; return (0); } @@ -2094,7 +2091,8 @@ read_Bools(struct archive_read *a, unsigned char *data, size_t num) { const unsigned char *p;- unsigned i, mask = 0, avail = 0;+ size_t i;+ unsigned mask = 0, avail = 0; for (i = 0; i < num; i++) { if (mask == 0) {@@ -2103,7 +2101,7 @@ avail = *p; mask = 0x80; }- data[i] = (avail & mask)?1:0;+ data[i] = (avail & mask) ? 1 : 0; mask >>= 1; } return (0);@@ -2120,7 +2118,7 @@ read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num) { const unsigned char *p;- unsigned i;+ size_t i; if (num == 0) return (-1);@@ -2167,25 +2165,23 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi) { const unsigned char *p;- unsigned i;+ size_t i; memset(pi, 0, sizeof(*pi)); /* * Read PackPos. */- if (parse_7zip_uint64(a, &(pi->pos)) < 0)+ if (parse_7zip_int64(a, &(pi->pos)) < 0) return (-1); /* * Read NumPackStreams. */- if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)+ if (parse_7zip_size(a, &(pi->numPackStreams)) < 0) return (-1); if (pi->numPackStreams == 0) return (-1);- if (UMAX_ENTRY < pi->numPackStreams)- return (-1); /* * Read PackSizes[num]@@ -2197,13 +2193,13 @@ return (0); if (*p != kSize) return (-1);- pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));- pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));+ pi->sizes = calloc(pi->numPackStreams, sizeof(int64_t));+ pi->positions = calloc(pi->numPackStreams, sizeof(int64_t)); if (pi->sizes == NULL || pi->positions == NULL) return (-1); for (i = 0; i < pi->numPackStreams; i++) {- if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)+ if (parse_7zip_int64(a, &(pi->sizes[i])) < 0) return (-1); } @@ -2215,9 +2211,9 @@ if (*p == kEnd) { /* PackStreamDigests[num] are not present. */ pi->digest.defineds =- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));+ calloc(pi->numPackStreams, sizeof(*pi->digest.defineds)); pi->digest.digests =- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));+ calloc(pi->numPackStreams, sizeof(*pi->digest.digests)); if (pi->digest.defineds == NULL || pi->digest.digests == NULL) return (-1); return (0);@@ -2226,7 +2222,7 @@ if (*p != kCRC) return (-1); - if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)+ if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0) return (-1); /*@@ -2242,40 +2238,39 @@ static void free_Folder(struct _7z_folder *f) {- unsigned i;- if (f->coders) {+ size_t i;+ for (i = 0; i< f->numCoders; i++) { free(f->coders[i].properties); } free(f->coders); } free(f->bindPairs);- free(f->packedStreams); free(f->unPackSize); } static int read_Folder(struct archive_read *a, struct _7z_folder *f) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const unsigned char *p;- uint64_t numInStreamsTotal = 0;- uint64_t numOutStreamsTotal = 0;- unsigned i;+ size_t numInStreamsTotal = 0;+ size_t numOutStreamsTotal = 0;+ size_t i; memset(f, 0, sizeof(*f)); /* * Read NumCoders. */- if (parse_7zip_uint64(a, &(f->numCoders)) < 0)+ if (parse_7zip_size(a, &(f->numCoders)) < 0) return (-1); if (f->numCoders > 4) /* Too many coders. */ return (-1); - f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));+ f->coders = calloc(f->numCoders, sizeof(*f->coders)); if (f->coders == NULL) return (-1); for (i = 0; i< f->numCoders; i++) {@@ -2293,7 +2288,7 @@ * 7: Must be zero. */ codec_size = *p & 0xf;- simple = (*p & 0x10)?0:1;+ simple = (*p & 0x10) ? 0 : 1; attr = *p & 0x20; if (*p & 0x80) return (-1);/* Not supported. */@@ -2311,37 +2306,34 @@ f->coders[i].numInStreams = 1; f->coders[i].numOutStreams = 1; } else {- if (parse_7zip_uint64(+ if (parse_7zip_size( a, &(f->coders[i].numInStreams)) < 0) return (-1);- if (UMAX_ENTRY < f->coders[i].numInStreams)- return (-1);- if (parse_7zip_uint64(+ if (parse_7zip_size( a, &(f->coders[i].numOutStreams)) < 0) return (-1);- if (UMAX_ENTRY < f->coders[i].numOutStreams)- return (-1); } if (attr) {- if (parse_7zip_uint64(+ if (parse_7zip_size( a, &(f->coders[i].propertiesSize)) < 0) return (-1);- if (UMAX_ENTRY < f->coders[i].propertiesSize)- return (-1); if ((p = header_bytes(- a, (size_t)f->coders[i].propertiesSize)) == NULL)+ a, f->coders[i].propertiesSize)) == NULL) return (-1); f->coders[i].properties =- malloc((size_t)f->coders[i].propertiesSize);+ malloc(f->coders[i].propertiesSize); if (f->coders[i].properties == NULL) return (-1); memcpy(f->coders[i].properties, p,- (size_t)f->coders[i].propertiesSize);+ f->coders[i].propertiesSize); } - numInStreamsTotal += f->coders[i].numInStreams;- numOutStreamsTotal += f->coders[i].numOutStreams;+ if (archive_ckd_add_size(&numInStreamsTotal,+ numInStreamsTotal, f->coders[i].numInStreams) ||+ archive_ckd_add_size(&numOutStreamsTotal,+ numOutStreamsTotal, f->coders[i].numOutStreams))+ return (-1); } if (numOutStreamsTotal == 0 ||@@ -2349,34 +2341,27 @@ return (-1); f->numBindPairs = numOutStreamsTotal - 1;- if (zip->header_bytes_remaining < f->numBindPairs)+ if ((uint64_t)zip->header_bytes_remaining < f->numBindPairs) return (-1); if (f->numBindPairs > 0) { f->bindPairs =- calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));+ calloc(f->numBindPairs, sizeof(*f->bindPairs)); if (f->bindPairs == NULL) return (-1); } else f->bindPairs = NULL; for (i = 0; i < f->numBindPairs; i++) {- if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)- return (-1);- if (UMAX_ENTRY < f->bindPairs[i].inIndex)- return (-1);- if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)+ if (parse_7zip_size(a, &(f->bindPairs[i].inIndex)) < 0) return (-1);- if (UMAX_ENTRY < f->bindPairs[i].outIndex)+ if (parse_7zip_size(a, &(f->bindPairs[i].outIndex)) < 0) return (-1); } f->numPackedStreams = numInStreamsTotal - f->numBindPairs;- f->packedStreams =- calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));- if (f->packedStreams == NULL)- return (-1);+ /* packedStreams are not needed; parse/verify nonetheless */ if (f->numPackedStreams == 1) { for (i = 0; i < numInStreamsTotal; i++) {- unsigned j;+ size_t j; for (j = 0; j < f->numBindPairs; j++) { if (f->bindPairs[j].inIndex == i) break;@@ -2386,12 +2371,10 @@ } if (i == numInStreamsTotal) return (-1);- f->packedStreams[0] = i; } else { for (i = 0; i < f->numPackedStreams; i++) {- if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)- return (-1);- if (UMAX_ENTRY < f->packedStreams[i])+ size_t packedStream;+ if (parse_7zip_size(a, &packedStream) < 0) return (-1); } }@@ -2404,7 +2387,7 @@ static void free_CodersInfo(struct _7z_coders_info *ci) {- unsigned i;+ size_t i; if (ci->folders) { for (i = 0; i < ci->numFolders; i++)@@ -2416,9 +2399,10 @@ static int read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci) {+ struct _7zip *zip = a->format->data; const unsigned char *p; struct _7z_digests digest;- unsigned i;+ size_t dataStreamIndex, i; memset(ci, 0, sizeof(*ci)); memset(&digest, 0, sizeof(digest));@@ -2431,10 +2415,16 @@ /* * Read NumFolders. */- if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)+ if (parse_7zip_size(a, &(ci->numFolders)) < 0) goto failed;- if (UMAX_ENTRY < ci->numFolders)- return (-1);+ /*+ * Each folder is encoded by at least one byte in the coders+ * list that follows, so a folder count larger than the bytes+ * left in the header cannot be honored and is rejected here+ * before it is used to size the folders allocation.+ */+ if (ci->numFolders > (uint64_t)zip->header_bytes_remaining)+ goto failed; /* * Read External.@@ -2444,7 +2434,7 @@ switch (*p) { case 0: ci->folders =- calloc((size_t)ci->numFolders, sizeof(*ci->folders));+ calloc(ci->numFolders, sizeof(*ci->folders)); if (ci->folders == NULL) return (-1); for (i = 0; i < ci->numFolders; i++) {@@ -2453,9 +2443,7 @@ } break; case 1:- if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)- return (-1);- if (UMAX_ENTRY < ci->dataStreamIndex)+ if (parse_7zip_size(a, &dataStreamIndex) < 0) return (-1); if (ci->numFolders > 0) { archive_set_error(&a->archive, -1,@@ -2476,14 +2464,14 @@ for (i = 0; i < ci->numFolders; i++) { struct _7z_folder *folder = &(ci->folders[i]);- unsigned j;+ size_t j; folder->unPackSize =- calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));+ calloc(folder->numOutStreams, sizeof(*folder->unPackSize)); if (folder->unPackSize == NULL) goto failed; for (j = 0; j < folder->numOutStreams; j++) {- if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)+ if (parse_7zip_int64(a, &(folder->unPackSize[j])) < 0) goto failed; } }@@ -2497,7 +2485,7 @@ return (0); if (*p != kCRC) goto failed;- if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)+ if (read_Digests(a, &digest, ci->numFolders) < 0) goto failed; for (i = 0; i < ci->numFolders; i++) { ci->folders[i].digest_defined = digest.defineds[i];@@ -2518,16 +2506,16 @@ return (-1); } -static uint64_t+static int64_t folder_uncompressed_size(struct _7z_folder *f) {- int n = (int)f->numOutStreams;- unsigned pairs = (unsigned)f->numBindPairs;+ size_t n = f->numOutStreams;+ size_t pairs = f->numBindPairs; - while (--n >= 0) {- unsigned i;+ while (n-- > 0) {+ size_t i; for (i = 0; i < pairs; i++) {- if (f->bindPairs[i].outIndex == (uint64_t)n)+ if (f->bindPairs[i].outIndex == n) break; } if (i >= pairs)@@ -2549,11 +2537,11 @@ struct _7z_folder *f, size_t numFolders) { const unsigned char *p;- uint64_t *usizes;+ int64_t *usizes;+ size_t numDigests; size_t unpack_streams;+ size_t i; int type;- unsigned i;- uint32_t numDigests; memset(ss, 0, sizeof(*ss)); @@ -2567,13 +2555,11 @@ if (type == kNumUnPackStream) { unpack_streams = 0; for (i = 0; i < numFolders; i++) {- if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)+ if (parse_7zip_size(a, &(f[i].numUnpackStreams)) < 0) return (-1);- if (f[i].numUnpackStreams >- UMAX_ENTRY - unpack_streams) {+ if (archive_ckd_add_size(&unpack_streams,+ unpack_streams, f[i].numUnpackStreams)) return (-1);- }- unpack_streams += (size_t)f[i].numUnpackStreams; } if ((p = header_bytes(a, 1)) == NULL) return (-1);@@ -2581,6 +2567,9 @@ } else unpack_streams = numFolders; + if (unpack_streams > UMAX_ENTRY)+ return (-1);+ if (type != kSize) { for (i = 0; i < numFolders; i++) { if (f[i].numUnpackStreams > 1)@@ -2603,8 +2592,8 @@ usizes = ss->unpackSizes; for (i = 0; i < numFolders; i++) {- unsigned pack;- uint64_t size, sum;+ int64_t size, sum;+ size_t pack; if (f[i].numUnpackStreams == 0) continue;@@ -2612,11 +2601,10 @@ sum = 0; if (type == kSize) { for (pack = 1; pack < f[i].numUnpackStreams; pack++) {- if (parse_7zip_uint64(a, usizes) < 0)+ if (parse_7zip_int64(a, usizes) < 0) return (-1);- if (*usizes > UINT64_MAX - sum)+ if (archive_ckd_add_i64(&sum, sum, *usizes++)) return (-1);- sum += *usizes++; } } size = folder_uncompressed_size(&f[i]);@@ -2634,14 +2622,18 @@ numDigests = 0; for (i = 0; i < numFolders; i++) { if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)- numDigests += (uint32_t)f[i].numUnpackStreams;+ if (archive_ckd_add_size(&numDigests,+ numDigests, f[i].numUnpackStreams)) {+ errno = ENOMEM;+ return (-1);+ } } if (type == kCRC) { struct _7z_digests tmpDigests; unsigned char *digestsDefined = ss->digestsDefined;- uint32_t * digests = ss->digests;- int di = 0;+ uint32_t *digests = ss->digests;+ size_t di = 0; memset(&tmpDigests, 0, sizeof(tmpDigests)); if (read_Digests(a, &(tmpDigests), numDigests) < 0) {@@ -2653,7 +2645,7 @@ *digestsDefined++ = 1; *digests++ = f[i].digest; } else {- unsigned j;+ size_t j; for (j = 0; j < f[i].numUnpackStreams; j++, di++) {@@ -2689,16 +2681,16 @@ static int read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const unsigned char *p;- unsigned i;+ size_t i; memset(si, 0, sizeof(*si)); if ((p = header_bytes(a, 1)) == NULL) return (-1); if (*p == kPackInfo) {- uint64_t packPos;+ int64_t packPos; if (read_PackInfo(a, &(si->pi)) < 0) return (-1);@@ -2711,9 +2703,9 @@ packPos = si->pi.pos; for (i = 0; i < si->pi.numPackStreams; i++) { si->pi.positions[i] = packPos;- if (packPos > UINT64_MAX - si->pi.sizes[i])+ if (archive_ckd_add_i64(&packPos,+ packPos, si->pi.sizes[i])) return (-1);- packPos += si->pi.sizes[i]; if (packPos > zip->header_offset) return (-1); }@@ -2721,7 +2713,7 @@ return (-1); } if (*p == kUnPackInfo) {- uint32_t packIndex;+ size_t packIndex; struct _7z_folder *f; if (read_CodersInfo(a, &(si->ci)) < 0)@@ -2734,12 +2726,9 @@ f = si->ci.folders; for (i = 0; i < si->ci.numFolders; i++) { f[i].packIndex = packIndex;- if (f[i].numPackedStreams > UINT32_MAX)- return (-1);- if (packIndex > UINT32_MAX - (uint32_t)f[i].numPackedStreams)- return (-1);- packIndex += (uint32_t)f[i].numPackedStreams;- if (packIndex > si->pi.numPackStreams)+ if (archive_ckd_add_size(&packIndex,+ packIndex, f[i].numPackedStreams) ||+ packIndex > si->pi.numPackStreams) return (-1); } if ((p = header_bytes(a, 1)) == NULL)@@ -2748,7 +2737,7 @@ if (*p == kSubStreamsInfo) { if (read_SubStreamsInfo(a, &(si->ss),- si->ci.folders, (size_t)si->ci.numFolders) < 0)+ si->ci.folders, si->ci.numFolders) < 0) return (-1); if ((p = header_bytes(a, 1)) == NULL) return (-1);@@ -2771,18 +2760,38 @@ free(h->attrBools); } +/*+ * Files without unpack streams must be described by the EmptyStream bitmap,+ * which consumes one bit for every file entry in FilesInfo.+ */ static int+files_info_numfiles_is_sane(const struct _7zip *zip)+{+ int64_t empty_stream_map_bytes;++ if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))+ return (0);++ if (zip->numFiles <= zip->si.ss.unpack_streams)+ return (1);++ empty_stream_map_bytes = (zip->numFiles + 7) / 8;+ return (empty_stream_map_bytes <= zip->header_bytes_remaining);+}++static int read_Header(struct archive_read *a, struct _7z_header_info *h, int check_header_id) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const unsigned char *p; struct _7z_folder *folders; struct _7z_stream_info *si = &(zip->si); struct _7zip_entry *entries;- uint32_t folderIndex, indexInFolder;- unsigned i;- int eindex, empty_streams, sindex;+ size_t folderIndex, indexInFolder;+ size_t i;+ size_t eindex, empty_streams, sindex;+ int attr_seen = 0; if (check_header_id) { /*@@ -2801,13 +2810,26 @@ return (-1); if (*p == kArchiveProperties) { for (;;) {- uint64_t size;+ int64_t size; if ((p = header_bytes(a, 1)) == NULL) return (-1);- if (*p == 0)+ if (*p == kEnd) break;- if (parse_7zip_uint64(a, &size) < 0)+ if (parse_7zip_int64(a, &size) < 0) return (-1);+ if (size < 0 || zip->header_bytes_remaining < size)+ return (-1);++ /* Skip the property data to keep header parsing aligned. */+ while (size > 0) {+ int64_t skip = size;++ if (skip > UBUFF_SIZE)+ skip = UBUFF_SIZE;+ if (header_bytes(a, (size_t)skip) == NULL)+ return (-1);+ size -= skip;+ } } if ((p = header_bytes(a, 1)) == NULL) return (-1);@@ -2831,12 +2853,12 @@ if (*p != kFilesInfo) return (-1); - if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)+ if (parse_7zip_size(a, &(zip->numFiles)) < 0) return (-1); if (!files_info_numfiles_is_sane(zip)) return (-1); - zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));+ zip->entries = calloc(zip->numFiles, sizeof(*zip->entries)); if (zip->entries == NULL) return (-1); entries = zip->entries;@@ -2844,7 +2866,7 @@ empty_streams = 0; for (;;) { int type;- uint64_t size;+ int64_t size; size_t ll; if ((p = header_bytes(a, 1)) == NULL)@@ -2853,9 +2875,10 @@ if (type == kEnd) break; - if (parse_7zip_uint64(a, &size) < 0)+ if (parse_7zip_int64(a, &size) < 0) return (-1);- if (zip->header_bytes_remaining < size || size > SIZE_MAX / 4)+ if (zip->header_bytes_remaining < size ||+ size > (int64_t)(SIZE_MAX / 4)) return (-1); ll = (size_t)size; @@ -2863,12 +2886,12 @@ case kEmptyStream: if (h->emptyStreamBools != NULL) return (-1);- h->emptyStreamBools = calloc((size_t)zip->numFiles,+ h->emptyStreamBools = calloc(zip->numFiles, sizeof(*h->emptyStreamBools)); if (h->emptyStreamBools == NULL) return (-1); if (read_Bools(- a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)+ a, h->emptyStreamBools, zip->numFiles) < 0) return (-1); empty_streams = 0; for (i = 0; i < zip->numFiles; i++) {@@ -2911,7 +2934,7 @@ case kCTime: case kATime: case kMTime:- if (read_Times(a, h, type) < 0)+ if (read_Times(a, type) < 0) return (-1); break; case kName:@@ -2981,21 +3004,20 @@ if ((p = header_bytes(a, 2)) == NULL) return (-1); allAreDefined = *p;- if (h->attrBools != NULL)- return (-1);- h->attrBools = calloc((size_t)zip->numFiles,- sizeof(*h->attrBools));- if (h->attrBools == NULL)+ if (attr_seen) return (-1);- if (allAreDefined)- memset(h->attrBools, 1, (size_t)zip->numFiles);- else {+ attr_seen = 1;+ if (!allAreDefined) {+ h->attrBools = calloc(zip->numFiles,+ sizeof(*h->attrBools));+ if (h->attrBools == NULL)+ return (-1); if (read_Bools(a, h->attrBools,- (size_t)zip->numFiles) < 0)+ zip->numFiles) < 0) return (-1); } for (i = 0; i < zip->numFiles; i++) {- if (h->attrBools[i]) {+ if (allAreDefined || h->attrBools[i]) { if ((p = header_bytes(a, 4)) == NULL) return (-1); entries[i].attr = archive_le32dec(p);@@ -3048,7 +3070,7 @@ } if (entries[i].flg & HAS_STREAM) {- if ((size_t)sindex >= si->ss.unpack_streams)+ if (sindex >= si->ss.unpack_streams) return (-1); if (entries[i].mode == 0) entries[i].mode = AE_IFREG | 0666;@@ -3057,14 +3079,10 @@ entries[i].ssIndex = sindex; sindex++; } else {- int dir;- if (h->emptyFileBools == NULL)- dir = 1;- else {- if (h->emptyFileBools[eindex])- dir = 0;- else- dir = 1;+ int dir = 1;++ if (h->emptyFileBools != NULL) {+ dir = !h->emptyFileBools[eindex]; eindex++; } if (entries[i].mode == 0) {@@ -3121,42 +3139,38 @@ } static int-read_Times(struct archive_read *a, struct _7z_header_info *h, int type)+read_Times(struct archive_read *a, int type) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const unsigned char *p; struct _7zip_entry *entries = zip->entries;- unsigned char *timeBools;+ unsigned char *timeBools = NULL; int allAreDefined;- unsigned i;-- timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));- if (timeBools == NULL)- return (-1);+ size_t dataIndex, i; /* Read allAreDefined. */ if ((p = header_bytes(a, 1)) == NULL) goto failed; allAreDefined = *p;- if (allAreDefined)- memset(timeBools, 1, (size_t)zip->numFiles);- else {- if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)++ if (!allAreDefined) {+ timeBools = calloc(zip->numFiles, sizeof(*timeBools));+ if (timeBools == NULL) goto failed;+ if (read_Bools(a, timeBools, zip->numFiles) < 0)+ goto failed; } /* Read external. */ if ((p = header_bytes(a, 1)) == NULL) goto failed; if (*p) {- if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)- goto failed;- if (UMAX_ENTRY < h->dataIndex)+ if (parse_7zip_size(a, &dataIndex) < 0) goto failed; } for (i = 0; i < zip->numFiles; i++) {- if (!timeBools[i])+ if (!allAreDefined && !timeBools[i]) continue; if ((p = header_bytes(a, 8)) == NULL) goto failed;@@ -3192,7 +3206,8 @@ static int decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data;+ int64_t pi_end; errno = 0; if (read_StreamsInfo(a, si) < 0) {@@ -3210,9 +3225,12 @@ return (ARCHIVE_FATAL); } - if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||- (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||- si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {+ if (archive_ckd_add_i64(&pi_end, si->pi.pos, si->pi.sizes[0])) {+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+ return (ARCHIVE_FATAL);+ }++ if (zip->header_offset < pi_end) { archive_set_error(&a->archive, -1, "Malformed Header offset"); return (ARCHIVE_FATAL); }@@ -3223,10 +3241,10 @@ static const unsigned char * header_bytes(struct archive_read *a, size_t rbytes) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const unsigned char *p; - if (zip->header_bytes_remaining < rbytes)+ if ((uint64_t)zip->header_bytes_remaining < rbytes) return (NULL); if (zip->pack_stream_bytes_unconsumed) read_consume(a);@@ -3258,8 +3276,8 @@ struct _7z_header_info *header) { const unsigned char *p;- uint64_t next_header_offset;- uint64_t next_header_size;+ int64_t next_header_offset;+ int64_t next_header_size; uint32_t next_header_crc; ssize_t bytes_avail; int64_t data_offset;@@ -3277,7 +3295,10 @@ return (ARCHIVE_FATAL); } - zip->seek_base = (uint64_t)data_offset + 32;+ if (archive_ckd_add_i64(&zip->seek_base, data_offset, 32)) {+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+ return (ARCHIVE_FATAL);+ } if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) { archive_set_error(&a->archive, -1, "Not 7-Zip archive file");@@ -3294,25 +3315,35 @@ } next_header_offset = archive_le64dec(p + 12);+ if (next_header_offset < 0) {+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+ return (ARCHIVE_FATAL);+ } next_header_size = archive_le64dec(p + 20);+ if (next_header_size < 0) {+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+ return (ARCHIVE_FATAL);+ } next_header_crc = archive_le32dec(p + 28); if (next_header_size == 0)- /* There is no entry in an archive file. */+ /* There is no entry in the archive file. */ return (ARCHIVE_EOF); - if (((int64_t)next_header_offset) < 0) {- archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- } __archive_read_consume(a, 32); if (next_header_offset != 0) {- if (bytes_avail >= (ssize_t)next_header_offset)+ if (bytes_avail >= next_header_offset) __archive_read_consume(a, next_header_offset);- else if (seek_compat(a,- next_header_offset + zip->seek_base, SEEK_SET, 1) < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");- return (ARCHIVE_FATAL);+ else {+ int64_t target;++ if (archive_ckd_add_i64(&target,+ zip->seek_base, next_header_offset) ||+ seek_compat(a, target, SEEK_SET, 1) < 0) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_MISC, "Seek error");+ return (ARCHIVE_FATAL);+ } } } zip->stream_offset = next_header_offset;@@ -3424,10 +3455,10 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size, size_t minimum) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; ssize_t bytes_avail; - if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {+ if (zip->codec == _7Z_COPY && zip->codec2 == -1) { /* Copy mode. */ *buff = __archive_read_ahead(a, minimum, &bytes_avail);@@ -3473,14 +3504,25 @@ return (bytes_avail); } +static size_t+align_size(size_t s)+{+ size_t r;++ if (archive_ckd_add_size(&r, s, 1023))+ return (s);+ r &= ~0x3ff;+ return (r);+}+ static ssize_t extract_pack_stream(struct archive_read *a, size_t minimum) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; ssize_t bytes_avail; int r; - if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {+ if (zip->codec == _7Z_COPY && zip->codec2 == -1) { if (minimum == 0) minimum = 1; if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL@@ -3490,10 +3532,10 @@ "Truncated 7-Zip file body"); return (ARCHIVE_FATAL); }- if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)+ if (bytes_avail > zip->pack_stream_inbytes_remaining) bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining; zip->pack_stream_inbytes_remaining -= bytes_avail;- if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)+ if (bytes_avail > zip->folder_outbytes_remaining) bytes_avail = (ssize_t)zip->folder_outbytes_remaining; zip->folder_outbytes_remaining -= bytes_avail; zip->uncompressed_buffer_bytes_remaining = bytes_avail;@@ -3502,18 +3544,17 @@ /* If the buffer hasn't been allocated, allocate it now. */ if (zip->uncompressed_buffer == NULL) {- zip->uncompressed_buffer_size = UBUFF_SIZE;- if (zip->uncompressed_buffer_size < minimum) {- zip->uncompressed_buffer_size = minimum + 1023;- zip->uncompressed_buffer_size &= ~0x3ff;- }- zip->uncompressed_buffer =- malloc(zip->uncompressed_buffer_size);+ size_t new_size = UBUFF_SIZE;++ if (new_size < minimum)+ new_size = align_size(minimum);+ zip->uncompressed_buffer = malloc(new_size); if (zip->uncompressed_buffer == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory for 7-Zip decompression"); return (ARCHIVE_FATAL); }+ zip->uncompressed_buffer_size = new_size; zip->uncompressed_buffer_bytes_remaining = 0; } else if (zip->uncompressed_buffer_size < minimum || zip->uncompressed_buffer_bytes_remaining < minimum) {@@ -3534,10 +3575,8 @@ * the minimum size. */ void *p;- size_t new_size;+ size_t new_size = align_size(minimum); - new_size = minimum + 1023;- new_size &= ~0x3ff; p = realloc(zip->uncompressed_buffer, new_size); if (p == NULL) { archive_set_error(&a->archive, ENOMEM,@@ -3583,7 +3622,7 @@ bytes_out = zip->uncompressed_buffer_size - zip->uncompressed_buffer_bytes_remaining; bytes_in = bytes_avail;- if (bytes_in > zip->pack_stream_inbytes_remaining)+ if (bytes_in > (uint64_t)zip->pack_stream_inbytes_remaining) bytes_in = (size_t)zip->pack_stream_inbytes_remaining; /* Drive decompression. */ r = decompress(a, zip, buff_out, &bytes_out,@@ -3599,7 +3638,7 @@ return (ARCHIVE_FATAL); } zip->pack_stream_inbytes_remaining -= bytes_in;- if (bytes_out > zip->folder_outbytes_remaining)+ if (bytes_out > (uint64_t)zip->folder_outbytes_remaining) bytes_out = (size_t)zip->folder_outbytes_remaining; zip->folder_outbytes_remaining -= bytes_out; zip->uncompressed_buffer_bytes_remaining += bytes_out;@@ -3637,10 +3676,10 @@ static int seek_pack(struct archive_read *a) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; int64_t pack_offset; - if (zip->pack_stream_remaining <= 0) {+ if (zip->pack_stream_remaining == 0) { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive"); return (ARCHIVE_FATAL);@@ -3649,8 +3688,11 @@ zip->si.pi.sizes[zip->pack_stream_index]; pack_offset = zip->si.pi.positions[zip->pack_stream_index]; if (zip->stream_offset != pack_offset) {- if (0 > seek_compat(a, pack_offset + zip->seek_base,- SEEK_SET, 1)) {+ int64_t target;++ if (archive_ckd_add_i64(&target,+ zip->seek_base, pack_offset) ||+ 0 > seek_compat(a, target, SEEK_SET, 1)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error"); return (ARCHIVE_FATAL); }@@ -3665,8 +3707,8 @@ read_stream(struct archive_read *a, const void **buff, size_t size, size_t minimum) {- struct _7zip *zip = (struct _7zip *)a->format->data;- uint64_t skip_bytes = 0;+ struct _7zip *zip = a->format->data;+ int64_t skip_bytes = 0; ssize_t r; if (zip->uncompressed_buffer_bytes_remaining == 0) {@@ -3737,9 +3779,10 @@ return (r); /*- * Skip the bytes we already has skipped in skip_stream().+ * Skip the bytes we already have skipped in skip_stream(). */ while (1) {+ size_t request; ssize_t skipped; if (zip->uncompressed_buffer_bytes_remaining == 0) {@@ -3763,8 +3806,12 @@ if (!skip_bytes) break; - skipped = get_uncompressed_data(- a, buff, (size_t)skip_bytes, 0);+ if (skip_bytes > MAX_READ)+ request = MAX_READ;+ else+ request = (size_t)skip_bytes;++ skipped = get_uncompressed_data(a, buff, request, 0); if (skipped < 0) return (skipped); skip_bytes -= skipped;@@ -3779,10 +3826,10 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, int header) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const struct _7z_coder *coder1, *coder2; const char *cname = (header)?"archive header":"file content";- unsigned i;+ size_t i; int r, found_bcj2 = 0; /*@@ -3840,8 +3887,8 @@ /* * Initialize a stream reader. */- zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;- zip->pack_stream_index = (unsigned)folder->packIndex;+ zip->pack_stream_remaining = folder->numPackedStreams;+ zip->pack_stream_index = folder->packIndex; zip->folder_outbytes_remaining = folder_uncompressed_size(folder); zip->uncompressed_buffer_bytes_remaining = 0; coder1 = &(folder->coders[0]);@@ -3863,8 +3910,8 @@ const void *buff; ssize_t bytes; unsigned char *b[3] = {NULL, NULL, NULL};- uint64_t sunpack[3] ={-1, -1, -1};- uint64_t remaining;+ int64_t sunpack[3] ={-1, -1, -1};+ int64_t remaining; size_t s[3] = {0, 0, 0}; int idx[3] = {0, 1, 2}; @@ -3917,15 +3964,11 @@ } } coder2 = &(fc[3]);- zip->main_stream_bytes_remaining =- (size_t)folder->unPackSize[2]; remaining = folder->unPackSize[2]; } else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 && zip->pack_stream_remaining == 4 && folder->numInStreams == 5 && folder->numOutStreams == 2) { /* Source type 0 made by 7z */- zip->main_stream_bytes_remaining =- (size_t)folder->unPackSize[0]; remaining = folder->unPackSize[0]; } else { /* We got an unexpected form. */@@ -3934,13 +3977,6 @@ "Unsupported form of BCJ2 streams"); return (ARCHIVE_FATAL); }- if (remaining > SIZE_MAX) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "7-Zip sub-stream size exceeds "- "platform maximum");- return (ARCHIVE_FATAL);- } zip->main_stream_bytes_remaining = remaining; @@ -3948,8 +3984,9 @@ if ((r = seek_pack(a)) < 0) return (r); zip->pack_stream_bytes_unconsumed =- (size_t)zip->pack_stream_inbytes_remaining;- read_consume(a);+ zip->pack_stream_inbytes_remaining;+ if ((r = read_consume(a)) < 0)+ return (r); /* Read following three sub streams. */ for (i = 0; i < 3; i++) {@@ -3960,7 +3997,7 @@ return (r); } - if (sunpack[i] == (uint64_t)-1)+ if (sunpack[i] == -1) zip->folder_outbytes_remaining = zip->pack_stream_inbytes_remaining; else@@ -3974,7 +4011,7 @@ /* Allocate memory for the decoded data of a sub * stream. */- if (zip->folder_outbytes_remaining > SIZE_MAX) {+ if ((uint64_t)zip->folder_outbytes_remaining > SIZE_MAX) { free(b[0]); free(b[1]); free(b[2]); archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -4039,7 +4076,7 @@ * of BCJ2. */ zip->pack_stream_remaining = 1;- zip->pack_stream_index = (unsigned)folder->packIndex;+ zip->pack_stream_index = folder->packIndex; zip->folder_outbytes_remaining = folder_uncompressed_size(folder); zip->uncompressed_buffer_bytes_remaining = 0;@@ -4054,26 +4091,40 @@ return (ARCHIVE_OK); } -static int64_t-skip_stream(struct archive_read *a, size_t skip_bytes)+static int+skip_stream(struct archive_read *a, int64_t skip_bytes) {- struct _7zip *zip = (struct _7zip *)a->format->data;+ struct _7zip *zip = a->format->data; const void *p; int64_t skipped_bytes;- size_t bytes = skip_bytes;+ int64_t bytes = skip_bytes; if (zip->folder_index == 0) {+ int64_t *v;+ /* * Optimization for a list mode. * Avoid unnecessary decoding operations. */- zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes- += skip_bytes;- return (skip_bytes);+ v = &zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes;+ if (archive_ckd_add_i64(v, *v, skip_bytes)) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Too many bytes to skip");+ return (ARCHIVE_FATAL);+ }+ return (ARCHIVE_OK); } while (bytes) {- skipped_bytes = read_stream(a, &p, bytes, 0);+ size_t request;++ if (bytes > MAX_READ)+ request = MAX_READ;+ else+ request = (size_t)bytes;++ skipped_bytes = read_stream(a, &p, request, 0); if (skipped_bytes < 0) return (skipped_bytes); if (skipped_bytes == 0) {@@ -4082,11 +4133,11 @@ "Truncated 7-Zip file body"); return (ARCHIVE_FATAL); }- bytes -= (size_t)skipped_bytes;+ bytes -= skipped_bytes; if (zip->pack_stream_bytes_unconsumed) read_consume(a); }- return (skip_bytes);+ return (ARCHIVE_OK); } /*@@ -4135,7 +4186,7 @@ if (p >= limit) break; prevPosT = bufferPos - prevPosT;- if (prevPosT > 3)+ if (prevPosT == 0 || prevPosT > 3) prevMask = 0; else { prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;@@ -4439,7 +4490,7 @@ const uint8_t *buf0, *buf1, *buf2, *buf3; size_t size0, size1, size2, size3; const uint8_t *buffer, *bufferLim;- unsigned int i, j;+ size_t i, j; size0 = zip->tmp_stream_bytes_remaining; buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;@@ -4538,7 +4589,7 @@ size2 -= 4; } dest = archive_be32dec(v) -- ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);+ (zip->bcj2_outPos + outPos + 4); archive_le32enc(out, dest); zip->bcj2_prevByte = out[3]; @@ -4549,7 +4600,7 @@ * Save odd bytes which we could not add into * the output buffer because of out of space. */- zip->odd_bcj_size = 4 -i;+ zip->odd_bcj_size = 4 - i; for (; i < 4; i++) { j = i - 4 + (unsigned)zip->odd_bcj_size; zip->odd_bcj[j] = out[i];
c/archive_read_support_format_all.c view
@@ -80,7 +80,7 @@ /* Note: We always return ARCHIVE_OK here, even if some of the * above return ARCHIVE_WARN. The intent here is to enable * "as much as possible." Clients who need specific- * compression should enable those individually so they can+ * formats should enable those individually so they can * verify the level of support. */ /* Clear any warning messages set by the above functions. */ archive_clear_error(a);
c/archive_read_support_format_ar.c view
@@ -55,7 +55,7 @@ * but haven't yet marked as consumed. Must be paired with * entry_bytes_remaining usage/modification. */- size_t entry_bytes_unconsumed;+ int64_t entry_bytes_unconsumed; int64_t entry_offset; int64_t entry_padding; char *strtab;@@ -81,18 +81,18 @@ #define AR_fmag_offset 58 #define AR_fmag_size 2 -static int archive_read_format_ar_bid(struct archive_read *a, int);-static int archive_read_format_ar_cleanup(struct archive_read *a);-static int archive_read_format_ar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset);-static int archive_read_format_ar_skip(struct archive_read *a);-static int archive_read_format_ar_read_header(struct archive_read *a,- struct archive_entry *e);-static uint64_t ar_atol8(const char *p, unsigned char_cnt);-static uint64_t ar_atol10(const char *p, unsigned char_cnt);-static int ar_parse_gnu_filename_table(struct archive_read *a);-static int ar_parse_common_header(struct ar *ar, struct archive_entry *,- const char *h);+static int archive_read_format_ar_bid(struct archive_read *, int);+static int archive_read_format_ar_cleanup(struct archive_read *);+static int archive_read_format_ar_read_data(struct archive_read *,+ const void **, size_t *, int64_t *);+static int archive_read_format_ar_skip(struct archive_read *);+static int archive_read_format_ar_read_header(struct archive_read *,+ struct archive_entry *);+static uint64_t ar_atol8(const char *, size_t);+static uint64_t ar_atol10(const char *, size_t);+static int ar_parse_gnu_filename_table(struct archive_read *);+static void ar_parse_common_header(struct ar *, struct archive_entry *,+ const char *); int archive_read_support_format_ar(struct archive *_a)@@ -135,12 +135,12 @@ static int archive_read_format_ar_cleanup(struct archive_read *a) {- struct ar *ar;+ struct ar *ar = a->format->data; - ar = (struct ar *)(a->format->data); free(ar->strtab); free(ar);- (a->format->data) = NULL;+ a->format->data = NULL;+ return (ARCHIVE_OK); } @@ -165,14 +165,12 @@ static int _ar_read_header(struct archive_read *a, struct archive_entry *entry,- struct ar *ar, const char *h, size_t *unconsumed)+ struct ar *ar, const char *h, int64_t *unconsumed) { char filename[AR_name_size + 1]; uint64_t number; /* Used to hold parsed numbers before validation. */- size_t bsd_name_length, entry_size;- char *p, *st;+ char *p; const void *b;- int r; /* Verify the magic signature on the file header. */ if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {@@ -248,14 +246,20 @@ } /*+ * Parse the time, owner, mode, size fields.+ * This must come before any call to _read_ahead.+ */+ ar_parse_common_header(ar, entry, h);++ /* * '//' is the GNU filename table. * Later entries can refer to names in this table. */ if (strcmp(filename, "//") == 0) {- /* This must come before any call to _read_ahead. */- ar_parse_common_header(ar, entry, h);+ char *st;+ size_t entry_size;+ archive_entry_copy_pathname(entry, filename);- archive_entry_set_filetype(entry, AE_IFREG); /* Get the size of the filename table. */ number = ar_atol10(h + AR_size_offset, AR_size_size); if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {@@ -310,22 +314,15 @@ */ if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') { number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);- /*- * If we can't look up the real name, warn and return- * the entry with the wrong name.- */+ /* Fail if we can't look up the real name. */ if (ar->strtab == NULL || number >= ar->strtab_size) { archive_set_error(&a->archive, EINVAL, "Can't find long filename for GNU/SVR4 archive entry");- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- ar_parse_common_header(ar, entry, h); return (ARCHIVE_FATAL); } archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);- /* Parse the time, owner, mode, size fields. */- return (ar_parse_common_header(ar, entry, h));+ return (ARCHIVE_OK); } /*@@ -334,9 +331,7 @@ * the filename to the file contents. */ if (strncmp(filename, "#1/", 3) == 0) {- /* Parse the time, owner, mode, size fields. */- /* This must occur before _read_ahead is called again. */- ar_parse_common_header(ar, entry, h);+ size_t bsd_name_length; /* Parse the size of the name, adjust the file size. */ number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);@@ -347,7 +342,7 @@ */ if (number > SIZE_MAX - 1 || number > 1024 * 1024- || (int64_t)number > ar->entry_bytes_remaining) {+ || number > (uint64_t)ar->entry_bytes_remaining) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Bad input file size"); return (ARCHIVE_FATAL);@@ -386,49 +381,33 @@ } /*- * "/" is the SVR4/GNU archive symbol table.- * "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.- */- if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- r = ar_parse_common_header(ar, entry, h);- /* Force the file type to a regular file. */- archive_entry_set_filetype(entry, AE_IFREG);- return (r);- }-- /*- * "__.SYMDEF" is a BSD archive symbol table.- */- if (strcmp(filename, "__.SYMDEF") == 0) {- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- return (ar_parse_common_header(ar, entry, h));- }-- /* * Otherwise, this is a standard entry. The filename * has already been trimmed as much as possible, based * on our current knowledge of the format.+ *+ * Note for future implementations:+ *+ * - "/" is the SVR4/GNU archive symbol table.+ * - "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.+ * - "__.SYMDEF" is a BSD archive symbol table. */ archive_entry_copy_pathname(entry, filename);- return (ar_parse_common_header(ar, entry, h));+ return (ARCHIVE_OK); } static int archive_read_format_ar_read_header(struct archive_read *a, struct archive_entry *entry) {- struct ar *ar = (struct ar*)(a->format->data);- size_t unconsumed;+ struct ar *ar = a->format->data;+ int64_t unconsumed; const void *header_data; int ret; if (!ar->read_global_header) { /*- * We are now at the beginning of the archive,- * so we need first consume the ar global header.+ * We are at the beginning of the archive now,+ * so we have to consume the ar global header first. */ __archive_read_consume(a, 8); ar->read_global_header = 1;@@ -452,11 +431,11 @@ } -static int+static void ar_parse_common_header(struct ar *ar, struct archive_entry *entry, const char *h) {- uint64_t n;+ int64_t n; /* Copy remaining header */ archive_entry_set_mtime(entry,@@ -468,24 +447,21 @@ archive_entry_set_mode(entry, (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); archive_entry_set_filetype(entry, AE_IFREG);- n = ar_atol10(h + AR_size_offset, AR_size_size);+ n = (int64_t)ar_atol10(h + AR_size_offset, AR_size_size); ar->entry_offset = 0; ar->entry_padding = n % 2; archive_entry_set_size(entry, n); ar->entry_bytes_remaining = n;- return (ARCHIVE_OK); } static int archive_read_format_ar_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct ar *ar = a->format->data; ssize_t bytes_read;- struct ar *ar; - ar = (struct ar *)(a->format->data);- if (ar->entry_bytes_unconsumed) { __archive_read_consume(a, ar->entry_bytes_unconsumed); ar->entry_bytes_unconsumed = 0;@@ -509,17 +485,9 @@ ar->entry_bytes_remaining -= bytes_read; return (ARCHIVE_OK); } else {- int64_t skipped = __archive_read_consume(a, ar->entry_padding);- if (skipped >= 0) {- ar->entry_padding -= skipped;- }- if (ar->entry_padding) {- if (skipped >= 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated ar archive - failed consuming padding");- }+ if (__archive_read_consume(a, ar->entry_padding) < 0) return (ARCHIVE_FATAL);- }+ ar->entry_padding = 0; *buff = NULL; *size = 0; *offset = ar->entry_offset;@@ -530,15 +498,11 @@ static int archive_read_format_ar_skip(struct archive_read *a) {- int64_t bytes_skipped;- struct ar* ar;-- ar = (struct ar *)(a->format->data);+ struct ar *ar = a->format->data; - bytes_skipped = __archive_read_consume(a,- ar->entry_bytes_remaining + ar->entry_padding- + ar->entry_bytes_unconsumed);- if (bytes_skipped < 0)+ if (__archive_read_consume(a,+ ar->entry_bytes_remaining + ar->entry_padding ++ ar->entry_bytes_unconsumed) < 0) return (ARCHIVE_FATAL); ar->entry_bytes_remaining = 0;@@ -551,11 +515,10 @@ static int ar_parse_gnu_filename_table(struct archive_read *a) {- struct ar *ar;+ struct ar *ar = a->format->data; char *p; size_t size; - ar = (struct ar*)(a->format->data); size = ar->strtab_size; for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {@@ -587,7 +550,7 @@ } static uint64_t-ar_atol8(const char *p, unsigned char_cnt)+ar_atol8(const char *p, size_t char_cnt) { uint64_t l; unsigned int digit, base;@@ -611,7 +574,7 @@ } static uint64_t-ar_atol10(const char *p, unsigned char_cnt)+ar_atol10(const char *p, size_t char_cnt) { uint64_t l; unsigned int base, digit;
c/archive_read_support_format_cab.c view
@@ -49,85 +49,186 @@ #include "archive_endian.h" +/*+ * Huffman coding.+ *+ * Array representation of a Huffman tree for codes of up to 16 bit lengths.+ * Lookups are performed through a direct, expanded lookup table.+ *+ * An expanded table has as many elements as needed to cover all possible+ * indices formable with bit patterns of given lookup_bits length.+ *+ * If less codes exist, these span multiple entries for all possible+ * combinations of following bits.+ *+ * Example of a Huffman tree with len_size = 3, lookup_bits = 2:+ *+ * Symbol | Code+ * -------+-----+ * A | 0b0+ * B | 0b10+ * C | 0b11+ *+ * The bit sequences 0b00 and 0b01 are rightfully not covered by a code,+ * since code 0b0 already maps to symbol A. The table will contain two+ * entries for symbol A instead:+ *+ * idx | tbl[idx]+ * -----+---------+ * 0b00 | A+ * 0b01 | A+ * 0b10 | B+ * 0b11 | C+ *+ * By using lookup_bits bits as a lookup, it becomes apparent that 0b00 and+ * 0b01 point to a symbol which actually has the code 0b0. A user of this+ * data structure must check the code bit length of a retrieved symbol after+ * the lookup to properly advance the bit stream:+ *+ * idx | bitlen[idx]+ * ----+------------+ * A | 1+ * B | 2+ * C | 2+ *+ * Thus, a proper code sequence would be:+ *+ * symbol = tbl[read_bits(lookup_bits)]+ * consume_bits(bitlen[symbol])+ */+struct huffman {+ /*+ * Amount of symbols.+ *+ * This implementation keeps track of unused symbols as well,+ * thus symbols start with 0x0000 up to given symbol amount:+ * [0..symbol_count)+ *+ * Used to construct tbl.+ */+ uint16_t symbol_count;+ /*+ * Frequency of code bit lengths.+ *+ * Represents the amount of occurrences of given bit lengths.+ * Index 0 is used for "empty" codes (aka unused symbols),+ * otherwise index represents the bit length+ * (index 1 is bit length 1 and so on).+ *+ * Used to construct tbl.+ */+ uint16_t freq[17];+ /* Map of symbols to their code bit lengths. */+ uint8_t *bitlen;+ /* Amount of bits to use for lookup (<= tbl_bits). */+ uint8_t lookup_bits;+ /*+ * Code bit length used for allocation (<= 16).+ *+ * Used to construct tbl.+ */+ uint8_t tbl_bits;+ /* Direct, expanded lookup table. */+ uint16_t *tbl;+};++/*+ * Bit stream reader.+ */+struct lzx_br {+#define CACHE_TYPE uint64_t+#define CACHE_BITS (8 * sizeof(CACHE_TYPE))+ /* Cache buffer. */+ CACHE_TYPE cache_buffer;+ /* Indicates how many bits avail in cache_buffer. */+ size_t cache_avail;+ uint8_t odd;+ int have_odd;+};++struct lzx_pos_tbl {+ uint32_t base;+ uint8_t footer_bits;+};+ struct lzx_dec { /* Decoding status. */ int state;+#define ST_RD_TRANSLATION 0+#define ST_RD_TRANSLATION_SIZE 1+#define ST_RD_BLOCK_TYPE 2+#define ST_RD_BLOCK_SIZE 3+#define ST_RD_ALIGNMENT 4+#define ST_RD_R0 5+#define ST_RD_R1 6+#define ST_RD_R2 7+#define ST_COPY_UNCOMP1 8+#define ST_COPY_UNCOMP2 9+#define ST_RD_ALIGNED_OFFSET 10+#define ST_RD_VERBATIM 11+#define ST_RD_PRE_MAIN_TREE_256 12+#define ST_MAIN_TREE_256 13+#define ST_RD_PRE_MAIN_TREE_REM 14+#define ST_MAIN_TREE_REM 15+#define ST_RD_PRE_LENGTH_TREE 16+#define ST_LENGTH_TREE 17+#define ST_MAIN 18+#define ST_LENGTH 19+#define ST_OFFSET 20+#define ST_REAL_POS 21+#define ST_COPY 22 /*- * Window to see last decoded data, from 32KBi to 2MBi.+ * Window to see last decoded data, from 32 KiB to 2 MiB. */- int w_size;- int w_mask;+ size_t w_size;+ size_t w_mask; /* Window buffer, which is a loop buffer. */- unsigned char *w_buff;+ uint8_t *w_buff; /* The insert position to the window. */- int w_pos;+ size_t w_pos; /* The position where we can copy decoded code from the window. */- int copy_pos;+ size_t copy_pos; /* The length how many bytes we can copy decoded code from * the window. */- int copy_len;+ size_t copy_len; /* Translation reversal for x86 processor CALL byte sequence(E8). * This is used for LZX only. */- uint32_t translation_size;- char translation;- char block_type;+ int32_t translation_size;+ int translation;+ uint8_t block_type; #define VERBATIM_BLOCK 1 #define ALIGNED_OFFSET_BLOCK 2 #define UNCOMPRESSED_BLOCK 3 size_t block_size; size_t block_bytes_avail; /* Repeated offset. */- int r0, r1, r2;- unsigned char rbytes[4];- int rbytes_avail;- int length_header;- int position_slot;- int offset_bits;+ size_t r0, r1, r2;+ uint8_t rbytes[4];+ size_t rbytes_avail;+ uint8_t length_header;+ uint16_t position_slot;+ uint8_t offset_bits; - struct lzx_pos_tbl {- int base;- int footer_bits;- } *pos_tbl;+ struct lzx_pos_tbl *pos_tbl; /* * Bit stream reader. */- struct lzx_br {-#define CACHE_TYPE uint64_t-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))- /* Cache buffer. */- CACHE_TYPE cache_buffer;- /* Indicates how many bits avail in cache_buffer. */- int cache_avail;- unsigned char odd;- char have_odd;- } br;+ struct lzx_br br; /* * Huffman coding. */- struct huffman {- int len_size;- int freq[17];- unsigned char *bitlen;-- /*- * Use an index table. It's faster than searching a huffman- * coding tree, which is a binary tree. But usage of a large- * index table causes L1 cache read miss many times.- */- int max_bits;- int tbl_bits;- int tree_used;- /* Direct access table. */- uint16_t *tbl;- } at, lt, mt, pt;+ struct huffman at;+ struct huffman lt;+ struct huffman mt;+ struct huffman pt; - int loop;+ uint16_t loop; int error; }; -static const int slots[] = {+static const size_t slots[] = { 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290 }; #define SLOT_BASE 15@@ -135,11 +236,11 @@ struct lzx_stream { const unsigned char *next_in;- int64_t avail_in;- int64_t total_in;+ size_t avail_in;+ size_t total_in; unsigned char *next_out;- int64_t avail_out;- int64_t total_out;+ size_t avail_out;+ size_t total_out; struct lzx_dec *ds; }; @@ -179,6 +280,11 @@ #define CFDATA_cbData 4 #define CFDATA_cbUncomp 6 +/* Limits */+#define MAX_UNCOMPRESS_SIZE 0x8000+#define MAX_FILE_SIZE (UINT16_MAX * MAX_UNCOMPRESS_SIZE)+#define MAX_E8_TRANSLATION (0x8000 * MAX_UNCOMPRESS_SIZE)+ static const char * const compression_name[] = { "NONE", "MSZIP",@@ -240,8 +346,6 @@ }; struct cfheader {- /* Total bytes of all file size in a Cabinet. */- uint32_t total_bytes; uint32_t files_offset; uint16_t folder_count; uint16_t file_count;@@ -249,7 +353,6 @@ #define PREV_CABINET 0x0001 #define NEXT_CABINET 0x0002 #define RESERVE_PRESENT 0x0004- uint16_t setid; uint16_t cabinet; /* Version number. */ unsigned char major;@@ -268,8 +371,6 @@ int64_t entry_offset; int64_t entry_bytes_remaining; int64_t entry_unconsumed;- int64_t entry_compressed_bytes_read;- int64_t entry_uncompressed_bytes_read; struct cffolder *entry_cffolder; struct cffile *entry_cffile; struct cfdata *entry_cfdata;@@ -314,7 +415,7 @@ static int archive_read_format_cab_cleanup(struct archive_read *); static int cab_skip_sfx(struct archive_read *);-static time_t cab_dos_time(const unsigned char *);+static time_t cab_dos_time(const char *); static int cab_read_data(struct archive_read *, const void **, size_t *, int64_t *); static int cab_read_header(struct archive_read *);@@ -335,15 +436,15 @@ static int lzx_read_blocks(struct lzx_stream *, int); static int lzx_decode_blocks(struct lzx_stream *, int); static void lzx_decode_free(struct lzx_stream *);-static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);+static void lzx_translation(struct lzx_stream *, unsigned char *, size_t, int32_t); static void lzx_cleanup_bitstream(struct lzx_stream *); static int lzx_decode(struct lzx_stream *, int); static int lzx_read_pre_tree(struct lzx_stream *);-static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);-static int lzx_huffman_init(struct huffman *, size_t, int);+static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, uint16_t);+static int lzx_huffman_init(struct huffman *, uint16_t, uint8_t); static void lzx_huffman_free(struct huffman *); static int lzx_make_huffman_table(struct huffman *);-static inline int lzx_decode_huffman(struct huffman *, unsigned);+static uint16_t lzx_decode_huffman(struct huffman *, uint16_t); int@@ -465,10 +566,9 @@ archive_read_format_cab_options(struct archive_read *a, const char *key, const char *val) {- struct cab *cab;+ struct cab *cab = a->format->data; int ret = ARCHIVE_FAILED; - cab = (struct cab *)(a->format->data); if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -540,19 +640,21 @@ return (ARCHIVE_FATAL); } -static ssize_t-cab_strnlen(const unsigned char *p, size_t maxlen)+#ifdef HAVE_STRNLEN+#define cab_strnlen(a,b) strnlen(a,b)+#else+static size_t+cab_strnlen(const char *p, size_t maxlen) { size_t i; - for (i = 0; i <= maxlen; i++) {+ for (i = 0; i < maxlen; i++) { if (p[i] == 0) break; }- if (i > maxlen)- return (-1);/* invalid */- return ((ssize_t)i);+ return (i); }+#endif /* Read up to max remaining bytes. */ static const void *@@ -622,11 +724,11 @@ static int cab_read_header(struct archive_read *a) {- const unsigned char *p;- struct cab *cab;+ struct cab *cab = a->format->data;+ const char *p; struct cfheader *hd;- size_t bytes, used;- ssize_t avail, len;+ size_t bytes, len, maxlen, used;+ ssize_t avail; int64_t skip; int err, i; int cur_folder, prev_folder;@@ -639,7 +741,6 @@ if ((p = __archive_read_ahead(a, 42, NULL)) == NULL) return (truncated_error(a)); - cab = (struct cab *)(a->format->data); if (cab->found_header == 0 && p[0] == 'M' && p[1] == 'Z') { /* This is an executable? Must be self-extracting... */@@ -663,7 +764,6 @@ "Couldn't find out CAB header"); return (ARCHIVE_FATAL); }- hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet); hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles); hd->minor = p[CFHEADER_versionMinor]; hd->major = p[CFHEADER_versionMajor];@@ -674,7 +774,6 @@ if (hd->file_count == 0) goto invalid; hd->flags = archive_le16dec(p + CFHEADER_flags);- hd->setid = archive_le16dec(p + CFHEADER_setID); hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet); used = CFHEADER_iCabinet + 2; if (hd->flags & RESERVE_PRESENT) {@@ -693,7 +792,9 @@ if ((p = cab_read_ahead_remaining(a, used + 256, &avail)) == NULL || (size_t)avail <= used) return (truncated_error(a));- if ((len = cab_strnlen(p + used, avail - used - 1)) <= 0) {+ maxlen = avail - used;+ len = cab_strnlen(p + used, maxlen);+ if (len == 0 || len == maxlen) { goto invalid; } used += len + 1;@@ -701,7 +802,9 @@ if ((p = cab_read_ahead_remaining(a, used + 256, &avail)) == NULL || (size_t)avail <= used) return (truncated_error(a));- if ((len = cab_strnlen(p + used, avail - used - 1)) < 0)+ maxlen = avail - used;+ len = cab_strnlen(p + used, maxlen);+ if (len == maxlen) goto invalid; used += len + 1; }@@ -710,14 +813,18 @@ if ((p = cab_read_ahead_remaining(a, used + 256, &avail)) == NULL || (size_t)avail <= used) return (truncated_error(a));- if ((len = cab_strnlen(p + used, avail - used - 1)) <= 0)+ maxlen = avail - used;+ len = cab_strnlen(p + used, maxlen);+ if (len == 0 || len == maxlen) goto invalid; used += len + 1; /* How many bytes are used for szDiskNext. */ if ((p = cab_read_ahead_remaining(a, used + 256, &avail)) == NULL || (size_t)avail <= used) return (truncated_error(a));- if ((len = cab_strnlen(p + used, avail - used - 1)) < 0)+ maxlen = avail - used;+ len = cab_strnlen(p + used, maxlen);+ if (len == maxlen) goto invalid; used += len + 1; }@@ -787,7 +894,8 @@ return (ARCHIVE_FATAL); } if (skip) {- __archive_read_consume(a, skip);+ if (__archive_read_consume(a, skip) < 0)+ return (truncated_error(a)); cab->cab_offset += skip; } /* Allocate memory for CFDATA */@@ -812,7 +920,9 @@ cab->cab_offset += 16; if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL) return (truncated_error(a));- if ((len = cab_strnlen(p, avail-1)) <= 0)+ maxlen = avail;+ len = cab_strnlen(p, maxlen);+ if (len == 0 || len == maxlen) goto invalid; /* Copy a pathname. */@@ -824,10 +934,10 @@ /* * Sanity check if each data is acceptable. */- if (file->uncompressed_size > 0x7FFF8000)+ if (file->uncompressed_size > MAX_FILE_SIZE) goto invalid;/* Too large */ if ((int64_t)file->offset + (int64_t)file->uncompressed_size- > ARCHIVE_LITERAL_LL(0x7FFF8000))+ > (int64_t)MAX_FILE_SIZE) goto invalid;/* Too large */ switch (file->folder) { case iFoldCONTINUED_TO_NEXT:@@ -893,14 +1003,13 @@ archive_read_format_cab_read_header(struct archive_read *a, struct archive_entry *entry) {- struct cab *cab;+ struct cab *cab = a->format->data; struct cfheader *hd; struct cffolder *prev_folder; struct cffile *file; struct archive_string_conv *sconv; int err = ARCHIVE_OK, r;- - cab = (struct cab *)(a->format->data);+ if (cab->found_header == 0) { err = cab_read_header(a); if (err < ARCHIVE_WARN)@@ -918,8 +1027,6 @@ cab->end_of_entry = 0; cab->end_of_entry_cleanup = 0;- cab->entry_compressed_bytes_read = 0;- cab->entry_uncompressed_bytes_read = 0; cab->entry_unconsumed = 0; cab->entry_cffile = file; @@ -1017,7 +1124,7 @@ archive_read_format_cab_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; int r; switch (cab->entry_cffile->folder) {@@ -1117,7 +1224,7 @@ static void cab_checksum_update(struct archive_read *a, size_t bytes) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata = cab->entry_cfdata; const unsigned char *p; size_t sumbytes;@@ -1157,7 +1264,7 @@ static int cab_checksum_finish(struct archive_read *a) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata = cab->entry_cfdata; int l; @@ -1202,7 +1309,7 @@ static int cab_next_cfdata(struct archive_read *a) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata = cab->entry_cfdata; /* There are remaining bytes in current CFDATA, use it first. */@@ -1280,9 +1387,9 @@ * Sanity check if data size is acceptable. */ if (cfdata->compressed_size == 0 ||- cfdata->compressed_size > (0x8000+6144))+ cfdata->compressed_size > (MAX_UNCOMPRESS_SIZE + 6144)) goto invalid;- if (cfdata->uncompressed_size > 0x8000)+ if (cfdata->uncompressed_size > MAX_UNCOMPRESS_SIZE) goto invalid; if (cfdata->uncompressed_size == 0) { switch (cab->entry_cffile->folder) {@@ -1295,10 +1402,10 @@ } } /* If CFDATA is not last in a folder, an uncompressed- * size must be 0x8000(32KBi) */+ * size must be 0x8000 (32 KiB) */ if ((cab->entry_cffolder->cfdata_index < cab->entry_cffolder->cfdata_count) &&- cfdata->uncompressed_size != 0x8000)+ cfdata->uncompressed_size != MAX_UNCOMPRESS_SIZE) goto invalid; /* A compressed data size and an uncompressed data size must@@ -1339,10 +1446,6 @@ } return (ARCHIVE_OK); invalid:- cfdata->compressed_size = 0;- cfdata->compressed_bytes_remaining = 0;- cfdata->uncompressed_size = 0;- cfdata->uncompressed_bytes_remaining = 0; archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA"); return (ARCHIVE_FATAL);@@ -1354,7 +1457,7 @@ static const void * cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; int err; err = cab_next_cfdata(a);@@ -1385,7 +1488,7 @@ static const void * cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata; const void *d; @@ -1417,7 +1520,7 @@ static const void * cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata; const void *d; int r, mszip;@@ -1427,7 +1530,7 @@ cfdata = cab->entry_cfdata; /* If the buffer hasn't been allocated, allocate it now. */ if (cab->uncompressed_buffer == NULL) {- cab->uncompressed_buffer_size = 0x8000;+ cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE; cab->uncompressed_buffer = malloc(cab->uncompressed_buffer_size); if (cab->uncompressed_buffer == NULL) {@@ -1485,14 +1588,6 @@ cab->uncompressed_buffer + cab->stream.total_out; cab->stream.avail_out = cfdata->uncompressed_size - cab->stream.total_out;- if ((size_t)cfdata->uncompressed_size >- cab->uncompressed_buffer_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid CFDATA uncompressed size");- *avail = ARCHIVE_FATAL;- return (NULL);- } d = __archive_read_ahead(a, 1, &bytes_avail); if (bytes_avail <= 0) {@@ -1653,7 +1748,7 @@ static const void * cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata; const void *d; int r;@@ -1662,7 +1757,7 @@ cfdata = cab->entry_cfdata; /* If the buffer hasn't been allocated, allocate it now. */ if (cab->uncompressed_buffer == NULL) {- cab->uncompressed_buffer_size = 0x8000;+ cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE; cab->uncompressed_buffer = malloc(cab->uncompressed_buffer_size); if (cab->uncompressed_buffer == NULL) {@@ -1703,13 +1798,6 @@ cab->uncompressed_buffer + cab->xstrm.total_out; cab->xstrm.avail_out = cfdata->uncompressed_size - cab->xstrm.total_out;- - if ((size_t)cfdata->uncompressed_size > cab->uncompressed_buffer_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid CFDATA uncompressed size");- *avail = ARCHIVE_FATAL;- return (NULL);- } d = __archive_read_ahead(a, 1, &bytes_avail); if (d == NULL) {@@ -1769,7 +1857,7 @@ */ lzx_translation(&cab->xstrm, cab->uncompressed_buffer, cfdata->uncompressed_size,- (cab->entry_cffolder->cfdata_index-1) * 0x8000);+ (cab->entry_cffolder->cfdata_index - 1) * MAX_UNCOMPRESS_SIZE); d = cab->uncompressed_buffer + cfdata->read_offset; *avail = uavail - cfdata->read_offset;@@ -1790,7 +1878,7 @@ static int64_t cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata; int64_t cbytes, rbytes; int err;@@ -1883,7 +1971,7 @@ static int64_t cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfdata *cfdata; int64_t cbytes, rbytes; int err;@@ -1940,7 +2028,7 @@ cab_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; ssize_t bytes_avail; if (cab->entry_bytes_remaining == 0) {@@ -1986,12 +2074,10 @@ static int archive_read_format_cab_read_data_skip(struct archive_read *a) {- struct cab *cab;+ struct cab *cab = a->format->data; int64_t bytes_skipped; int r; - cab = (struct cab *)(a->format->data);- if (cab->end_of_archive) return (ARCHIVE_EOF); @@ -2041,9 +2127,9 @@ static int archive_read_format_cab_cleanup(struct archive_read *a) {- struct cab *cab = (struct cab *)(a->format->data);+ struct cab *cab = a->format->data; struct cfheader *hd = &cab->cfheader;- int i;+ uint16_t i; if (hd->folder_array != NULL) { for (i = 0; i < hd->folder_count; i++)@@ -2063,13 +2149,13 @@ archive_wstring_free(&cab->ws); free(cab->uncompressed_buffer); free(cab);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } /* Convert an MSDOS-style date/time into Unix-style time. */ static time_t-cab_dos_time(const unsigned char *p)+cab_dos_time(const char *p) { int msTime, msDate; struct tm ts;@@ -2105,10 +2191,11 @@ static int lzx_decode_init(struct lzx_stream *strm, int w_bits) {- struct lzx_dec *ds;- int slot, w_size, w_slot;- int base, footer; int base_inc[18];+ struct lzx_dec *ds;+ uint32_t base;+ uint16_t slot, w_size, w_slot;+ uint8_t footer; if (strm->ds == NULL) { strm->ds = calloc(1, sizeof(*strm->ds));@@ -2118,7 +2205,7 @@ ds = strm->ds; ds->error = ARCHIVE_FAILED; - /* Allow bits from 15(32KBi) up to 21(2MBi) */+ /* Allow bits from 15 (32 KiB) up to 21 (2 MiB) */ if (w_bits < SLOT_BASE || w_bits > SLOT_MAX) return (ARCHIVE_FAILED); @@ -2130,7 +2217,7 @@ w_size = ds->w_size; w_slot = slots[w_bits - SLOT_BASE]; ds->w_size = 1U << w_bits;- ds->w_mask = ds->w_size -1;+ ds->w_mask = ds->w_size - 1; if (ds->w_buff == NULL || w_size != ds->w_size) { free(ds->w_buff); ds->w_buff = malloc(ds->w_size);@@ -2152,18 +2239,20 @@ else base += base_inc[footer]; if (footer < 17) {- footer = -2;+ footer = 0; for (n = base; n; n >>= 1) footer++;- if (footer <= 0)+ if (footer <= 2) footer = 0;+ else+ footer -= 2; } ds->pos_tbl[slot].base = base; ds->pos_tbl[slot].footer_bits = footer; } ds->w_pos = 0;- ds->state = 0;+ ds->state = ST_RD_TRANSLATION; ds->br.cache_buffer = 0; ds->br.cache_avail = 0; ds->r0 = ds->r1 = ds->r2 = 1;@@ -2177,7 +2266,7 @@ return (ARCHIVE_FATAL); /* Initialize Main tree. */- if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)+ if (lzx_huffman_init(&(ds->mt), 256 + (w_slot << 3), 16) != ARCHIVE_OK) return (ARCHIVE_FATAL); @@ -2213,29 +2302,36 @@ * E8 Call Translation reversal. */ static void-lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)+lzx_translation(struct lzx_stream *strm, unsigned char *buffer, size_t size,+ int32_t offset) { struct lzx_dec *ds = strm->ds;- unsigned char *b, *end;+ unsigned char *p, *end; - if (!ds->translation || size <= 10)+ if (!ds->translation || offset >= MAX_E8_TRANSLATION || size <= 10) return;- b = p;- end = b + size - 10;- while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {- size_t i = b - (unsigned char *)p;- int32_t cp, displacement, value; - cp = (int32_t)(offset + (uint32_t)i);- value = archive_le32dec(&b[1]);- if (value >= -cp && value < (int32_t)ds->translation_size) {- if (value >= 0)- displacement = value - cp;+ p = buffer;+ end = buffer + size - 10;++ while (p < end && (p = memchr(p, 0xE8, end - p)) != NULL) {+ int32_t address, position;++ address = archive_le32dec(p + 1);+ position = offset + (p - buffer);++ if (address >= -position && address < ds->translation_size) {+ uint32_t relative;++ if (address >= 0)+ relative = address - position; else- displacement = value + ds->translation_size;- archive_le32enc(&b[1], (uint32_t)displacement);+ relative = address + ds->translation_size;++ archive_le32enc(p + 1, relative); }- b += 5;++ p += 5; } } @@ -2257,7 +2353,7 @@ * False : we met that strm->next_in is empty, we have to get following * bytes. */ #define lzx_br_read_ahead_0(strm, br, n) \- (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))+ (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br) == ARCHIVE_OK) /* True : the cache buffer has some bits as much as we need. * False : there are no enough bits in the cache buffer to be used, * we have to get following bytes if we could. */@@ -2286,8 +2382,8 @@ * Shift away used bits in the cache data and fill it up with following bits. * Call this when cache buffer does not have enough bits you need. *- * Returns 1 if the cache buffer is full.- * Returns 0 if the cache buffer is not full; input buffer is empty.+ * Returns ARCHIVE_OK if the cache buffer is full.+ * Returns ARCHIVE_EOF if the cache buffer is not full; input buffer is empty. */ static int lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)@@ -2295,7 +2391,7 @@ /* * x86 processor family can read misaligned data without an access error. */- int n = CACHE_BITS - br->cache_avail;+ ssize_t n = CACHE_BITS - br->cache_avail; for (;;) { switch (n >> 4) {@@ -2313,7 +2409,7 @@ strm->next_in += 8; strm->avail_in -= 8; br->cache_avail += 8 * 8;- return (1);+ return (ARCHIVE_OK); } break; case 3:@@ -2329,13 +2425,13 @@ strm->next_in += 6; strm->avail_in -= 6; br->cache_avail += 6 * 8;- return (1);+ return (ARCHIVE_OK); } break; case 0: /* We have enough compressed data in * the cache buffer.*/- return (1);+ return (ARCHIVE_EOF); default: break; }@@ -2347,7 +2443,7 @@ strm->avail_in--; br->have_odd = 1; }- return (0);+ return (ARCHIVE_EOF); } br->cache_buffer = (br->cache_buffer << 16) |@@ -2362,7 +2458,7 @@ static void lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br) {- int n = CACHE_BITS - br->cache_avail;+ ssize_t n = CACHE_BITS - br->cache_avail; if (br->have_odd && n >= 16 && strm->avail_in > 0) { br->cache_buffer =@@ -2391,35 +2487,11 @@ * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data * is broken or you do not set 'last' flag properly. */-#define ST_RD_TRANSLATION 0-#define ST_RD_TRANSLATION_SIZE 1-#define ST_RD_BLOCK_TYPE 2-#define ST_RD_BLOCK_SIZE 3-#define ST_RD_ALIGNMENT 4-#define ST_RD_R0 5-#define ST_RD_R1 6-#define ST_RD_R2 7-#define ST_COPY_UNCOMP1 8-#define ST_COPY_UNCOMP2 9-#define ST_RD_ALIGNED_OFFSET 10-#define ST_RD_VERBATIM 11-#define ST_RD_PRE_MAIN_TREE_256 12-#define ST_MAIN_TREE_256 13-#define ST_RD_PRE_MAIN_TREE_REM 14-#define ST_MAIN_TREE_REM 15-#define ST_RD_PRE_LENGTH_TREE 16-#define ST_LENGTH_TREE 17-#define ST_MAIN 18-#define ST_LENGTH 19-#define ST_OFFSET 20-#define ST_REAL_POS 21-#define ST_COPY 22- static int lzx_decode(struct lzx_stream *strm, int last) { struct lzx_dec *ds = strm->ds;- int64_t avail_in;+ size_t avail_in; int r; if (ds->error)@@ -2431,7 +2503,8 @@ if (ds->state < ST_MAIN) r = lzx_read_blocks(strm, last); else {- int64_t bytes_written = strm->avail_out;+ size_t bytes_written = strm->avail_out;+ r = lzx_decode_blocks(strm, last); bytes_written -= strm->avail_out; strm->next_out += bytes_written;@@ -2447,7 +2520,8 @@ { struct lzx_dec *ds = strm->ds; struct lzx_br *br = &(ds->br);- int i, r;+ int r;+ uint16_t i; for (;;) { switch (ds->state) {@@ -2463,16 +2537,21 @@ /* FALL THROUGH */ case ST_RD_TRANSLATION_SIZE: if (ds->translation) {+ uint32_t v;+ if (!lzx_br_read_ahead(strm, br, 32)) { ds->state = ST_RD_TRANSLATION_SIZE; if (last) goto failed; return (ARCHIVE_OK); }- ds->translation_size = lzx_br_bits(br, 16);+ v = lzx_br_bits(br, 16); lzx_br_consume(br, 16);- ds->translation_size <<= 16;- ds->translation_size |= lzx_br_bits(br, 16);+ v <<= 16;+ v |= lzx_br_bits(br, 16);+ if (v > MAX_FILE_SIZE)+ goto failed;+ ds->translation_size = (int32_t)v; lzx_br_consume(br, 16); } /* FALL THROUGH */@@ -2579,17 +2658,17 @@ ds->rbytes_avail = 0; if (ds->state == ST_RD_R0) { ds->r0 = archive_le32dec(ds->rbytes);- if (ds->r0 < 0)+ if (ds->r0 > (size_t)INT32_MAX) goto failed; ds->state = ST_RD_R1; } else if (ds->state == ST_RD_R1) { ds->r1 = archive_le32dec(ds->rbytes);- if (ds->r1 < 0)+ if (ds->r1 > (size_t)INT32_MAX) goto failed; ds->state = ST_RD_R2; } else if (ds->state == ST_RD_R2) { ds->r2 = archive_le32dec(ds->rbytes);- if (ds->r2 < 0)+ if (ds->r2 > (size_t)INT32_MAX) goto failed; /* We've gotten all repeated offsets. */ ds->state = ST_COPY_UNCOMP1;@@ -2598,10 +2677,10 @@ /* FALL THROUGH */ case ST_COPY_UNCOMP1: /*- * Copy bytes form next_in to next_out directly.+ * Copy bytes from next_in to next_out directly. */ while (ds->block_bytes_avail) {- int l;+ size_t l; if (strm->avail_out <= 0) /* Output buffer is empty. */@@ -2612,13 +2691,13 @@ goto failed; return (ARCHIVE_OK); }- l = (int)ds->block_bytes_avail;+ l = ds->block_bytes_avail; if (l > ds->w_size - ds->w_pos) l = ds->w_size - ds->w_pos; if (l > strm->avail_out)- l = (int)strm->avail_out;+ l = strm->avail_out; if (l > strm->avail_in)- l = (int)strm->avail_in;+ l = strm->avail_in; memcpy(strm->next_out, strm->next_in, l); memcpy(&(ds->w_buff[ds->w_pos]), strm->next_in, l);@@ -2652,19 +2731,19 @@ /* * Read Aligned offset tree. */- if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {+ if (!lzx_br_read_ahead(strm, br, 3 * ds->at.symbol_count)) { ds->state = ST_RD_ALIGNED_OFFSET; if (last) goto failed; return (ARCHIVE_OK); } memset(ds->at.freq, 0, sizeof(ds->at.freq));- for (i = 0; i < ds->at.len_size; i++) {+ for (i = 0; i < ds->at.symbol_count; i++) { ds->at.bitlen[i] = lzx_br_bits(br, 3); ds->at.freq[ds->at.bitlen[i]]++; lzx_br_consume(br, 3); }- if (!lzx_make_huffman_table(&ds->at))+ if (lzx_make_huffman_table(&ds->at) < 0) goto failed; /* FALL THROUGH */ case ST_RD_VERBATIM:@@ -2674,13 +2753,13 @@ /* * Read Pre-tree for first 256 elements of main tree. */- if (!lzx_read_pre_tree(strm)) {+ if (lzx_read_pre_tree(strm) < 0) { ds->state = ST_RD_PRE_MAIN_TREE_256; if (last) goto failed; return (ARCHIVE_OK); }- if (!lzx_make_huffman_table(&ds->pt))+ if (lzx_make_huffman_table(&ds->pt) < 0) goto failed; ds->loop = 0; /* FALL THROUGH */@@ -2689,27 +2768,26 @@ * Get path lengths of first 256 elements of main tree. */ r = lzx_read_bitlen(strm, &ds->mt, 256);- if (r < 0)- goto failed;- else if (!r) {+ if (r == ARCHIVE_EOF) { ds->state = ST_MAIN_TREE_256; if (last) goto failed; return (ARCHIVE_OK);- }+ } else if (r < 0)+ goto failed; ds->loop = 0; /* FALL THROUGH */ case ST_RD_PRE_MAIN_TREE_REM: /* * Read Pre-tree for remaining elements of main tree. */- if (!lzx_read_pre_tree(strm)) {+ if (lzx_read_pre_tree(strm) < 0) { ds->state = ST_RD_PRE_MAIN_TREE_REM; if (last) goto failed; return (ARCHIVE_OK); }- if (!lzx_make_huffman_table(&ds->pt))+ if (lzx_make_huffman_table(&ds->pt) < 0) goto failed; ds->loop = 256; /* FALL THROUGH */@@ -2717,30 +2795,29 @@ /* * Get path lengths of remaining elements of main tree. */- r = lzx_read_bitlen(strm, &ds->mt, -1);- if (r < 0)- goto failed;- else if (!r) {+ r = lzx_read_bitlen(strm, &ds->mt, 0);+ if (r == ARCHIVE_EOF) { ds->state = ST_MAIN_TREE_REM; if (last) goto failed; return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->mt))+ } else if (r < 0) goto failed;+ if (lzx_make_huffman_table(&ds->mt) < 0)+ goto failed; ds->loop = 0; /* FALL THROUGH */ case ST_RD_PRE_LENGTH_TREE: /* * Read Pre-tree for remaining elements of main tree. */- if (!lzx_read_pre_tree(strm)) {+ if (lzx_read_pre_tree(strm) < 0) { ds->state = ST_RD_PRE_LENGTH_TREE; if (last) goto failed; return (ARCHIVE_OK); }- if (!lzx_make_huffman_table(&ds->pt))+ if (lzx_make_huffman_table(&ds->pt) < 0) goto failed; ds->loop = 0; /* FALL THROUGH */@@ -2748,17 +2825,16 @@ /* * Get path lengths of remaining elements of main tree. */- r = lzx_read_bitlen(strm, &ds->lt, -1);- if (r < 0)- goto failed;- else if (!r) {+ r = lzx_read_bitlen(strm, &ds->lt, 0);+ if (r == ARCHIVE_EOF) { ds->state = ST_LENGTH_TREE; if (last) goto failed; return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->lt))+ } else if (r < 0) goto failed;+ if (lzx_make_huffman_table(&ds->lt) < 0)+ goto failed; ds->state = ST_MAIN; return (100); }@@ -2776,22 +2852,23 @@ const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl; unsigned char *noutp = strm->next_out; unsigned char *endp = noutp + strm->avail_out;- unsigned char *w_buff = ds->w_buff;- unsigned char *at_bitlen = at->bitlen;- unsigned char *lt_bitlen = lt->bitlen;- unsigned char *mt_bitlen = mt->bitlen;+ uint8_t *w_buff = ds->w_buff;+ uint8_t *at_bitlen = at->bitlen;+ uint8_t *lt_bitlen = lt->bitlen;+ uint8_t *mt_bitlen = mt->bitlen; size_t block_bytes_avail = ds->block_bytes_avail;- int at_max_bits = at->max_bits;- int lt_max_bits = lt->max_bits;- int mt_max_bits = mt->max_bits;- int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;- int length_header = ds->length_header;- int offset_bits = ds->offset_bits;- int position_slot = ds->position_slot;- int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;+ uint8_t at_lookup_bits = at->lookup_bits;+ uint8_t lt_lookup_bits = lt->lookup_bits;+ uint8_t mt_lookup_bits = mt->lookup_bits;+ size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;+ size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;+ uint8_t length_header = ds->length_header;+ uint8_t offset_bits = ds->offset_bits;+ uint16_t position_slot = ds->position_slot;+ size_t r0 = ds->r0, r1 = ds->r1, r2 = ds->r2; int state = ds->state;- char block_type = ds->block_type;+ uint16_t c;+ uint8_t block_type = ds->block_type; for (;;) { switch (state) {@@ -2817,26 +2894,26 @@ goto next_data; if (!lzx_br_read_ahead(strm, &bre,- mt_max_bits)) {+ mt_lookup_bits)) { if (!last) goto next_data; /* Remaining bits are less than- * maximum bits(mt.max_bits) but maybe- * it still remains as much as we need,- * so we should try to use it with- * dummy bits. */+ * maximum bits (mt.lookup_bits) but+ * maybe it still remains as much as we+ * need, so we should try to use it+ * with dummy bits. */ c = lzx_decode_huffman(mt, lzx_br_bits_forced(- &bre, mt_max_bits));- lzx_br_consume(&bre, mt_bitlen[c]);- if (!lzx_br_has(&bre, 0))+ &bre, mt_lookup_bits));+ if (!lzx_br_has(&bre, mt_bitlen[c])) goto failed;/* Over read. */+ lzx_br_consume(&bre, mt_bitlen[c]); } else { c = lzx_decode_huffman(mt,- lzx_br_bits(&bre, mt_max_bits));+ lzx_br_bits(&bre, mt_lookup_bits)); lzx_br_consume(&bre, mt_bitlen[c]); }- if ((unsigned int)c > UCHAR_MAX)+ if (c > UCHAR_MAX) break; /* * 'c' is exactly literal code.@@ -2862,26 +2939,26 @@ */ if (length_header == 7) { if (!lzx_br_read_ahead(strm, &bre,- lt_max_bits)) {+ lt_lookup_bits)) { if (!last) { state = ST_LENGTH; goto next_data; } c = lzx_decode_huffman(lt, lzx_br_bits_forced(- &bre, lt_max_bits));- lzx_br_consume(&bre, lt_bitlen[c]);- if (!lzx_br_has(&bre, 0))+ &bre, lt_lookup_bits));+ if (!lzx_br_has(&bre, lt_bitlen[c])) goto failed;/* Over read. */+ lzx_br_consume(&bre, lt_bitlen[c]); } else { c = lzx_decode_huffman(lt,- lzx_br_bits(&bre, lt_max_bits));+ lzx_br_bits(&bre, lt_lookup_bits)); lzx_br_consume(&bre, lt_bitlen[c]); } copy_len = c + 7 + 2; } else copy_len = length_header + 2;- if ((size_t)copy_len > block_bytes_avail)+ if (copy_len > block_bytes_avail) goto failed; /* * Get an offset.@@ -2918,7 +2995,7 @@ */ if (block_type == ALIGNED_OFFSET_BLOCK && offset_bits >= 3) {- int offbits = offset_bits - 3;+ unsigned offbits = offset_bits - 3; if (!lzx_br_read_ahead(strm, &bre, offbits)) { state = ST_OFFSET;@@ -2930,7 +3007,7 @@ /* Get an aligned number. */ if (!lzx_br_read_ahead(strm, &bre,- offbits + at_max_bits)) {+ offbits + at_lookup_bits)) { if (!last) { state = ST_OFFSET; goto next_data;@@ -2938,14 +3015,14 @@ lzx_br_consume(&bre, offbits); c = lzx_decode_huffman(at, lzx_br_bits_forced(&bre,- at_max_bits));- lzx_br_consume(&bre, at_bitlen[c]);- if (!lzx_br_has(&bre, 0))+ at_lookup_bits));+ if (!lzx_br_has(&bre, at_bitlen[c])) goto failed;/* Over read. */+ lzx_br_consume(&bre, at_bitlen[c]); } else { lzx_br_consume(&bre, offbits); c = lzx_decode_huffman(at,- lzx_br_bits(&bre, at_max_bits));+ lzx_br_bits(&bre, at_lookup_bits)); lzx_br_consume(&bre, at_bitlen[c]); } /* Add an aligned number. */@@ -2961,7 +3038,7 @@ copy_pos = lzx_br_bits(&bre, offset_bits); lzx_br_consume(&bre, offset_bits); }- copy_pos += pos_tbl[position_slot].base -2;+ copy_pos += pos_tbl[position_slot].base - 2; /* Update repeated offset LRU queue. */ r2 = r1;@@ -2980,8 +3057,8 @@ * into the output buffer. */ for (;;) {- const unsigned char *s;- int l;+ const uint8_t *s;+ size_t l; l = copy_len; if (copy_pos > w_pos) {@@ -2992,15 +3069,15 @@ l = w_size - w_pos; } if (noutp + l >= endp)- l = (int)(endp - noutp);+ l = endp - noutp; s = w_buff + copy_pos; if (l >= 8 && ((copy_pos + l < w_pos) || (w_pos + l < copy_pos))) { memcpy(w_buff + w_pos, s, l); memcpy(noutp, s, l); } else {- unsigned char *d;- int li;+ uint8_t *d;+ size_t li; d = w_buff + w_pos; for (li = 0; li < l; li++)@@ -3046,122 +3123,124 @@ { struct lzx_dec *ds = strm->ds; struct lzx_br *br = &(ds->br);- int i;+ uint16_t i; if (ds->loop == 0) memset(ds->pt.freq, 0, sizeof(ds->pt.freq));- for (i = ds->loop; i < ds->pt.len_size; i++) {+ for (i = ds->loop; i < ds->pt.symbol_count; i++) { if (!lzx_br_read_ahead(strm, br, 4)) { ds->loop = i;- return (0);+ return (ARCHIVE_EOF); } ds->pt.bitlen[i] = lzx_br_bits(br, 4); ds->pt.freq[ds->pt.bitlen[i]]++; lzx_br_consume(br, 4); } ds->loop = i;- return (1);+ return (ARCHIVE_OK); } /* * Read a bunch of bit-lengths from pre-tree. */ static int-lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)+lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, uint16_t end) { struct lzx_dec *ds = strm->ds; struct lzx_br *br = &(ds->br);- int c, i, j, ret, same;- unsigned rbits;+ int ret;+ uint16_t c, i, j, rbits, same; i = ds->loop; if (i == 0) memset(d->freq, 0, sizeof(d->freq));- ret = 0;- if (end < 0)- end = d->len_size;+ ret = ARCHIVE_EOF;+ if (end == 0)+ end = d->symbol_count; while (i < end) { ds->loop = i;- if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))+ if (!lzx_br_read_ahead(strm, br, (unsigned)ds->pt.lookup_bits)) goto getdata;- rbits = lzx_br_bits(br, ds->pt.max_bits);+ rbits = lzx_br_bits(br, ds->pt.lookup_bits); c = lzx_decode_huffman(&(ds->pt), rbits); switch (c) { case 17:/* several zero lengths, from 4 to 19. */- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 4U)) goto getdata; lzx_br_consume(br, ds->pt.bitlen[c]); same = lzx_br_bits(br, 4) + 4;- if (i + same > end)- return (-1);/* Invalid */+ if (same > end - i)+ return (ARCHIVE_FATAL); lzx_br_consume(br, 4); for (j = 0; j < same; j++) d->bitlen[i++] = 0; break; case 18:/* many zero lengths, from 20 to 51. */- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 5U)) goto getdata; lzx_br_consume(br, ds->pt.bitlen[c]); same = lzx_br_bits(br, 5) + 20;- if (i + same > end)- return (-1);/* Invalid */+ if (same > end - i)+ return (ARCHIVE_FATAL); lzx_br_consume(br, 5); memset(d->bitlen + i, 0, same); i += same; break; case 19:/* a few same lengths. */ if (!lzx_br_read_ahead(strm, br,- ds->pt.bitlen[c]+1+ds->pt.max_bits))+ ds->pt.bitlen[c] + 1U + ds->pt.lookup_bits)) goto getdata; lzx_br_consume(br, ds->pt.bitlen[c]); same = lzx_br_bits(br, 1) + 4;- if (i + same > end)- return (-1);+ if (same > end - i)+ return (ARCHIVE_FATAL); lzx_br_consume(br, 1);- rbits = lzx_br_bits(br, ds->pt.max_bits);+ rbits = lzx_br_bits(br, ds->pt.lookup_bits); c = lzx_decode_huffman(&(ds->pt), rbits); lzx_br_consume(br, ds->pt.bitlen[c]);- c = (d->bitlen[i] - c + 17) % 17;- if (c < 0)- return (-1);/* Invalid */+ if (c > d->bitlen[i] + 17)+ return (ARCHIVE_FATAL);+ c = (d->bitlen[i] + 17 - c) % 17; for (j = 0; j < same; j++) d->bitlen[i++] = c; d->freq[c] += same; break; default: lzx_br_consume(br, ds->pt.bitlen[c]);- c = (d->bitlen[i] - c + 17) % 17;- if (c < 0)- return (-1);/* Invalid */+ if (c > d->bitlen[i] + 17)+ return (ARCHIVE_FATAL);+ c = (d->bitlen[i] + 17 - c) % 17; d->freq[c]++; d->bitlen[i++] = c; break; } }- ret = 1;+ ret = ARCHIVE_OK; getdata: ds->loop = i; return (ret); } static int-lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)+lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits) {+ size_t tbl_size = (size_t)1 << tbl_bits; - if (hf->bitlen == NULL || hf->len_size != (int)len_size) {+ if (hf->bitlen == NULL || hf->symbol_count != symbol_count) { free(hf->bitlen);- hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));+ hf->bitlen = calloc(symbol_count, sizeof(hf->bitlen[0])); if (hf->bitlen == NULL) return (ARCHIVE_FATAL);- hf->len_size = (int)len_size;+ hf->symbol_count = symbol_count; } else- memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));+ memset(hf->bitlen, 0, symbol_count * sizeof(hf->bitlen[0])); if (hf->tbl == NULL) {- hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));+ hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0])); if (hf->tbl == NULL) return (ARCHIVE_FATAL); hf->tbl_bits = tbl_bits;- }+ } else+ memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0])); return (ARCHIVE_OK); } @@ -3173,19 +3252,47 @@ } /*- * Make a huffman coding table.+ * Create a direct, expanded Huffman lookup table based on+ * canonical representation. */ static int lzx_make_huffman_table(struct huffman *hf) {+ uint16_t bitptn[17], weight[17]; uint16_t *tbl;- const unsigned char *bitlen;- int bitptn[17], weight[17];- int i, maxbits = 0, ptn, tbl_size, w;- int len_avail;+ const uint8_t *bitlen;+ uint8_t maxbits = 0;+ uint32_t ptn;+ uint16_t i, symbol_count, w; /* * Initialize bit patterns.+ *+ * Each bitptn element represents the smallest possible+ * code sequence allowed. The weight represents the amount+ * of lookup bit patterns covered by a code of this length.+ *+ * Example of a Huffman tree:+ *+ * idx | freq[idx]+ * ----+----------+ * 1 | 1+ * 2 | 2+ *+ * The result will be:+ *+ * idx | bitptn[idx] | weight[idx]+ * ----+-------------+------------+ * 1 | 0x0000 | 32768+ * 2 | 0x8000 | 16384+ *+ * This means that a code with bit length 1 will take 32768+ * possible combinations starting with 0b0. Since one such code exists+ * (freq[1] = 1), codes with bit length 2 must start with 0b1. Since+ * two codes with bit length 2 exist (freq[2] = 2), no more codes can+ * be added.+ *+ * In this example, maxbits will be 2 (longest code length is 2). */ ptn = 0; for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {@@ -3196,65 +3303,108 @@ maxbits = i; } }- if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)- return (0);/* Invalid */-- hf->max_bits = maxbits;+ /* Verify Kraft's inequality. */+ if (ptn != 0 && ptn != 0x10000)+ return (ARCHIVE_FATAL); /*- * Cut out extra bits which we won't house in the table.- * This preparation reduces the same calculation in the for-loop- * making the table.+ * Shrink codes to smallest size by removing extra bits after+ * the actual code sequences as good as possible.+ *+ * Continuing the example above:+ *+ * idx | bitptn[idx] | weight[idx]+ * ----+-------------+-------------+ * 1 | 0x0000 | 32768+ * 2 | 0x8000 | 16384+ *+ * As can be seen, a total of 65536 entries must be created even+ * though 4 would be sufficient (indices 0b00 to 0b11). Right shift+ * the pattern and divide weight as much as possible:+ *+ * idx | bitptn[idx] | weight[idx]+ * ----+-------------+-------------+ * 1 | 0x0000 | 2+ * 2 | 0x0002 | 1+ *+ * Thus, the direct, expanded lookup table only needs 4 entries. */ if (maxbits < 16) {- int ebits = 16 - maxbits;+ uint8_t ebits = 16 - maxbits; for (i = 1; i <= maxbits; i++) { bitptn[i] >>= ebits; weight[i] >>= ebits; } } + /* Grow table if necessary. */+ if (maxbits > hf->tbl_bits) {+ size_t tbl_size;++ hf->tbl_bits = 16;+ tbl_size = (size_t)1 << hf->tbl_bits;++ free(hf->tbl);+ hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));+ if (hf->tbl == NULL)+ return (ARCHIVE_FATAL);+ }+ hf->lookup_bits = maxbits;+ /*- * Make the table.+ * Construct the direct, expanded lookup table.+ *+ * Store each symbol in table for every possible bit patterns starting+ * with their code.+ *+ * Following the example with len_avail being 4:+ *+ * idx | bitlen[idx]+ * ----+------------+ * 0 | 0+ * 1 | 1+ * 2 | 0+ * 3 | 2+ * 4 | 2+ *+ * The resulting table contains all used symbols (1, 3, 4) for up to+ * max_len bit patterns:+ *+ * idx | tbl[idx]+ * ----------+---------+ * 0 (0b00) | 1+ * 1 (0b01) | 1+ * 2 (0b10) | 3+ * 3 (0b11) | 4 */- tbl_size = 1 << hf->tbl_bits; tbl = hf->tbl; bitlen = hf->bitlen;- len_avail = hf->len_size;- hf->tree_used = 0;- /* Initialize table to invalid values */- for (i = 0; i < tbl_size; i++) {- tbl[i] = (uint16_t)hf->len_size;- }- for (i = 0; i < len_avail; i++) {+ symbol_count = hf->symbol_count;+ for (i = 0; i < symbol_count; i++) { uint16_t *p;- int len, cnt;+ uint16_t cnt;+ uint8_t len; if (bitlen[i] == 0) continue; /* Get a bit pattern */ len = bitlen[i];- if (len > tbl_size)- return (0);+ if (len > maxbits)+ return (ARCHIVE_FATAL); ptn = bitptn[len]; cnt = weight[len]; /* Calculate next bit pattern */- if ((bitptn[len] = ptn + cnt) > tbl_size)- return (0);/* Invalid */+ bitptn[len] = ptn + cnt; /* Update the table */- p = &(tbl[ptn]);- while (--cnt >= 0)- p[cnt] = (uint16_t)i;+ p = tbl + ptn;+ while (cnt-- > 0)+ *p++ = i; }- return (1);+ return (ARCHIVE_OK); } -static inline int-lzx_decode_huffman(struct huffman *hf, unsigned rbits)+static uint16_t+lzx_decode_huffman(struct huffman *hf, uint16_t rbits) {- int c;- c = hf->tbl[rbits];- if (c < hf->len_size)- return (c);- return (0);+ return hf->tbl[rbits]; }
c/archive_read_support_format_cpio.c view
@@ -261,14 +261,12 @@ static int archive_read_format_cpio_bid(struct archive_read *a, int best_bid) {+ struct cpio *cpio = a->format->data; const unsigned char *p;- struct cpio *cpio; int bid; (void)best_bid; /* UNUSED */ - cpio = (struct cpio *)(a->format->data);- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) return (-1); @@ -326,10 +324,9 @@ archive_read_format_cpio_options(struct archive_read *a, const char *key, const char *val) {- struct cpio *cpio;+ struct cpio *cpio = a->format->data; int ret = ARCHIVE_FAILED; - cpio = (struct cpio *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { /* Handle filenames as libarchive 2.x */ cpio->init_default_conversion = (val != NULL)?1:0;@@ -364,14 +361,14 @@ archive_read_format_cpio_read_header(struct archive_read *a, struct archive_entry *entry) {- struct cpio *cpio;+ struct cpio *cpio = a->format->data; const void *h, *hl; struct archive_string_conv *sconv; size_t namelength; size_t name_pad;+ int is_trailer; int r; - cpio = (struct cpio *)(a->format->data); sconv = cpio->opt_sconv; if (sconv == NULL) { if (!cpio->init_default_conversion) {@@ -411,6 +408,9 @@ archive_string_conversion_charset_name(sconv)); r = ARCHIVE_WARN; }+ /* Save this before consuming the name buffer below. */+ is_trailer = (namelength == 11 &&+ memcmp((const char *)h, "TRAILER!!!", 10) == 0); cpio->entry_offset = 0; __archive_read_consume(a, namelength);@@ -451,8 +451,7 @@ * header. XXX */ /* Compare name to "TRAILER!!!" to test for end-of-archive. */- if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",- 10) == 0) {+ if (is_trailer) { /* TODO: Store file location of start of block. */ archive_clear_error(&a->archive); return (ARCHIVE_EOF);@@ -470,11 +469,9 @@ archive_read_format_cpio_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct cpio *cpio = a->format->data; ssize_t bytes_read;- struct cpio *cpio; - cpio = (struct cpio *)(a->format->data);- if (cpio->entry_bytes_unconsumed) { __archive_read_consume(a, cpio->entry_bytes_unconsumed); cpio->entry_bytes_unconsumed = 0;@@ -508,7 +505,7 @@ static int archive_read_format_cpio_skip(struct archive_read *a) {- struct cpio *cpio = (struct cpio *)(a->format->data);+ struct cpio *cpio = a->format->data; int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding + cpio->entry_bytes_unconsumed; @@ -545,7 +542,8 @@ { const void *h; const char *p, *q;- size_t skip, skipped = 0;+ int64_t skip;+ uintmax_t skipped = 0; ssize_t bytes; for (;;) {@@ -577,9 +575,9 @@ if (skipped > 0) { archive_set_error(&a->archive, 0,- "Skipped %d bytes before "+ "Skipped %ju bytes before " "finding valid header",- (int)skipped);+ skipped); return (ARCHIVE_WARN); } return (ARCHIVE_OK);@@ -1000,9 +998,8 @@ static int archive_read_format_cpio_cleanup(struct archive_read *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format->data; - cpio = (struct cpio *)(a->format->data); /* Free inode->name map */ while (cpio->links_head != NULL) { struct links_entry *lp = cpio->links_head->next;@@ -1012,7 +1009,7 @@ cpio->links_head = lp; } free(cpio);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); }
c/archive_read_support_format_iso9660.c view
@@ -47,6 +47,7 @@ #include "archive_endian.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" #include "archive_string.h"@@ -314,8 +315,8 @@ struct heap_queue { struct file_info **files;- int allocated;- int used;+ size_t allocated;+ size_t used; }; struct iso9660 {@@ -337,8 +338,8 @@ uint64_t offset;/* Offset of CE on disk. */ struct file_info *file; } *reqs;- int cnt;- int allocated;+ size_t cnt;+ size_t allocated; } read_ce_req; int64_t previous_number;@@ -379,8 +380,6 @@ size_t utf16be_path_len; unsigned char *utf16be_previous_path; size_t utf16be_previous_path_len;- /* Null buffer used in bidder to improve its performance. */- unsigned char null[2048]; }; static int archive_read_format_iso9660_bid(struct archive_read *, int);@@ -403,12 +402,12 @@ static int isodate17_valid(const unsigned char *); static time_t isodate7(const unsigned char *); static int isodate7_valid(const unsigned char *);-static int isBootRecord(struct iso9660 *, const unsigned char *);+static int isBootRecord(const unsigned char *); static int isVolumePartition(struct iso9660 *, const unsigned char *);-static int isVDSetTerminator(struct iso9660 *, const unsigned char *);+static int isVDSetTerminator(const unsigned char *); static int isJolietSVD(struct iso9660 *, const unsigned char *);-static int isSVD(struct iso9660 *, const unsigned char *);-static int isEVD(struct iso9660 *, const unsigned char *);+static int isSVD(const unsigned char *);+static int isEVD(const unsigned char *); static int isPVD(struct iso9660 *, const unsigned char *); static int isRootDirectoryRecord(const unsigned char *); static int isValid723Integer(const unsigned char *);@@ -503,7 +502,7 @@ static int archive_read_format_iso9660_bid(struct archive_read *a, int best_bid) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; ssize_t bytes_read; const unsigned char *p; int seenTerminator;@@ -513,8 +512,6 @@ if (best_bid > 48) return (-1); - iso9660 = (struct iso9660 *)(a->format->data);- /* * Skip the first 32k (reserved area) and get the first * 8 sectors of the volume descriptor table. Of course,@@ -547,15 +544,15 @@ if (isJolietSVD(iso9660, p)) continue; }- if (isBootRecord(iso9660, p))+ if (isBootRecord(p)) continue;- if (isEVD(iso9660, p))+ if (isEVD(p)) continue;- if (isSVD(iso9660, p))+ if (isSVD(p)) continue; if (isVolumePartition(iso9660, p)) continue;- if (isVDSetTerminator(iso9660, p)) {+ if (isVDSetTerminator(p)) { seenTerminator = 1; break; }@@ -576,9 +573,7 @@ archive_read_format_iso9660_options(struct archive_read *a, const char *key, const char *val) {- struct iso9660 *iso9660;-- iso9660 = (struct iso9660 *)(a->format->data);+ struct iso9660 *iso9660 = a->format->data; if (strcmp(key, "joliet") == 0) { if (val == NULL || strcmp(val, "off") == 0 ||@@ -603,26 +598,23 @@ } static int-isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,-unsigned bytes)+isNull(const unsigned char *h, unsigned offset, unsigned bytes) {-- while (bytes >= sizeof(iso9660->null)) {- if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))- return (0);- offset += sizeof(iso9660->null);- bytes -= sizeof(iso9660->null);- }- if (bytes)- return memcmp(iso9660->null, h + offset, bytes) == 0;- else+ if (bytes == 0) return (1);++ /*+ * If the first byte is zero and every byte equals the following+ * byte, the entire range is zero.+ */+ return (h[offset] == 0 &&+ (bytes == 1 ||+ memcmp(h + offset, h + offset + 1, bytes - 1) == 0)); } static int-isBootRecord(struct iso9660 *iso9660, const unsigned char *h)+isBootRecord(const unsigned char *h) {- (void)iso9660; /* UNUSED */ /* Type of the Volume Descriptor Boot Record must be 0. */ if (h[0] != 0)@@ -662,9 +654,8 @@ } static int-isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)+isVDSetTerminator(const unsigned char *h) {- (void)iso9660; /* UNUSED */ /* Type of the Volume Descriptor Set Terminator must be 255. */ if (h[0] != 255)@@ -675,7 +666,7 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, 7, 2048-7))+ if (!isNull(h, 7, 2048-7)) return (0); return (1);@@ -690,7 +681,7 @@ /* Check if current sector is a kind of Supplementary Volume * Descriptor. */- if (!isSVD(iso9660, h))+ if (!isSVD(h)) return (0); /* FIXME: do more validations according to joliet spec. */@@ -731,25 +722,24 @@ } static int-isSVD(struct iso9660 *iso9660, const unsigned char *h)+isSVD(const unsigned char *h) { const unsigned char *p; ssize_t logical_block_size; int32_t volume_block; int32_t location; - (void)iso9660; /* UNUSED */ /* Type 2 means it's a SVD. */ if (h[SVD_type_offset] != 2) return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))+ if (!isNull(h, SVD_reserved1_offset, SVD_reserved1_size)) return (0);- if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))+ if (!isNull(h, SVD_reserved2_offset, SVD_reserved2_size)) return (0);- if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))+ if (!isNull(h, SVD_reserved3_offset, SVD_reserved3_size)) return (0); /* File structure version must be 1 for ISO9660/ECMA119. */@@ -791,14 +781,13 @@ } static int-isEVD(struct iso9660 *iso9660, const unsigned char *h)+isEVD(const unsigned char *h) { const unsigned char *p; ssize_t logical_block_size; int32_t volume_block; int32_t location; - (void)iso9660; /* UNUSED */ /* Type of the Enhanced Volume Descriptor must be 2. */ if (h[PVD_type_offset] != 2)@@ -813,11 +802,11 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))+ if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size)) return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))+ if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size)) return (0); /* Logical block size must be > 0. */@@ -853,11 +842,11 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))+ if (!isNull(h, PVD_reserved4_offset, PVD_reserved4_size)) return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))+ if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size)) return (0); /* Read Root Directory Record in Volume Descriptor. */@@ -891,7 +880,7 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))+ if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size)) return (0); /* Volume space size must be encoded according to 7.3.3 */@@ -903,7 +892,7 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))+ if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size)) return (0); /* Volume set size must be encoded according to 7.2.3 */@@ -961,7 +950,7 @@ return (0); /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))+ if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size)) return (0); /* XXX TODO: Check other values for sanity; reject more@@ -1034,12 +1023,11 @@ static int read_children(struct archive_read *a, struct file_info *parent) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; const unsigned char *b, *p; struct file_info *multi; size_t step, skip_size; - iso9660 = (struct iso9660 *)(a->format->data); /* flush any remaining bytes from the last round to ensure * we're positioned */ if (iso9660->entry_bytes_unconsumed) {@@ -1086,7 +1074,7 @@ p = b; b += iso9660->logical_block_size; step -= iso9660->logical_block_size;- for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;+ for (; p < b && b - p > DR_name_offset && *p != 0 && *p <= b - p; p += *p) { struct file_info *child; @@ -1247,12 +1235,10 @@ archive_read_format_iso9660_read_header(struct archive_read *a, struct archive_entry *entry) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; struct file_info *file; int r, rd_r = ARCHIVE_OK; - iso9660 = (struct iso9660 *)(a->format->data);- if (!a->archive.archive_format) { a->archive.archive_format = ARCHIVE_FORMAT_ISO9660; a->archive.archive_format_name = "ISO9660";@@ -1499,7 +1485,7 @@ zisofs_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; struct zisofs *zisofs; const unsigned char *p; size_t avail;@@ -1507,7 +1493,6 @@ size_t uncompressed_size; int r; - iso9660 = (struct iso9660 *)(a->format->data); zisofs = &iso9660->entry_zisofs; p = __archive_read_ahead(a, 1, &bytes_read);@@ -1738,11 +1723,9 @@ archive_read_format_iso9660_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct iso9660 *iso9660 = a->format->data; ssize_t bytes_read;- struct iso9660 *iso9660; - iso9660 = (struct iso9660 *)(a->format->data);- if (iso9660->entry_bytes_unconsumed) { __archive_read_consume(a, iso9660->entry_bytes_unconsumed); iso9660->entry_bytes_unconsumed = 0;@@ -1805,10 +1788,9 @@ static int archive_read_format_iso9660_cleanup(struct archive_read *a) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; int r = ARCHIVE_OK; - iso9660 = (struct iso9660 *)(a->format->data); release_files(iso9660); free(iso9660->read_ce_req.reqs); archive_string_free(&iso9660->pathname);@@ -1828,7 +1810,7 @@ free(iso9660->utf16be_path); free(iso9660->utf16be_previous_path); free(iso9660);- (a->format->data) = NULL;+ a->format->data = NULL; return (r); } @@ -1840,7 +1822,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, const unsigned char *isodirrec, size_t reclen) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; struct file_info *file, *filep; size_t name_len; const unsigned char *rr_start, *rr_end;@@ -1850,8 +1832,6 @@ int32_t location; int flags; - iso9660 = (struct iso9660 *)(a->format->data);- if (reclen != 0) dr_len = (size_t)isodirrec[DR_length_offset]; /*@@ -2192,11 +2172,9 @@ parse_rockridge(struct archive_read *a, struct file_info *file, const unsigned char *p, const unsigned char *end) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; int entry_seen = 0; - iso9660 = (struct iso9660 *)(a->format->data);- while (p + 4 <= end /* Enough space for another entry. */ && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */ && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */@@ -2366,13 +2344,11 @@ register_CE(struct archive_read *a, int32_t location, struct file_info *file) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format->data; struct read_ce_queue *heap;- struct read_ce_req *p; uint64_t offset, parent_offset;- int hole, parent;+ size_t hole, parent; - iso9660 = (struct iso9660 *)(a->format->data); offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size; if (((file->mode & AE_IFMT) == AE_IFREG && offset >= file->offset) ||@@ -2389,14 +2365,13 @@ /* Expand our CE list as necessary. */ heap = &(iso9660->read_ce_req); if (heap->cnt >= heap->allocated) {- int new_size;+ struct read_ce_req *p;+ size_t new_size; if (heap->allocated < 16) new_size = 16;- else- new_size = heap->allocated * 2;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+ /* Overflow keeps us from growing the list. */ archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); }@@ -2438,7 +2413,7 @@ next_CE(struct read_ce_queue *heap) { uint64_t a_offset, b_offset, c_offset;- int a, b, c;+ size_t a, b, c; struct read_ce_req tmp; if (heap->cnt < 1)@@ -2765,7 +2740,7 @@ int data_length) { - if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {+ if (data_length == 12 && data[0] == 0x70 && data[1] == 0x7a) { /* paged zlib */ file->pz = 1; file->pz_log2_bs = data[3];@@ -3144,7 +3119,7 @@ struct file_info *file, uint64_t key) { uint64_t file_key, parent_key;- int hole, parent;+ size_t hole, parent; /* Reserve 16 bits for possible key collisions (needed for linked items) */ /* For ISO files with more than 65535 entries, reordering will still occur */@@ -3154,12 +3129,12 @@ /* Expand our pending files list as necessary. */ if (heap->used >= heap->allocated) { struct file_info **new_pending_files;- int new_size = heap->allocated * 2;+ size_t new_size; if (heap->allocated < 1024) new_size = 1024;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+ /* Overflow keeps us from growing the list. */ archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL);@@ -3186,7 +3161,7 @@ */ hole = heap->used++; while (hole > 0) {- parent = (hole - 1)/2;+ parent = (hole - 1) / 2; parent_key = heap->files[parent]->key; if (file_key >= parent_key) { heap->files[hole] = file;@@ -3205,7 +3180,7 @@ heap_get_entry(struct heap_queue *heap) { uint64_t a_key, b_key, c_key;- int a, b, c;+ size_t a, b, c; struct file_info *r, *tmp; if (heap->used < 1)
c/archive_read_support_format_lha.c view
@@ -390,10 +390,9 @@ archive_read_format_lha_options(struct archive_read *a, const char *key, const char *val) {- struct lha *lha;+ struct lha *lha = a->format->data; int ret = ARCHIVE_FAILED; - lha = (struct lha *)(a->format->data); if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -472,9 +471,9 @@ archive_read_format_lha_read_header(struct archive_read *a, struct archive_entry *entry) {+ struct lha *lha = a->format->data; struct archive_wstring linkname; struct archive_wstring pathname;- struct lha *lha; const unsigned char *p; const char *signature; int err;@@ -485,7 +484,6 @@ if (a->archive.archive_format_name == NULL) a->archive.archive_format_name = "lha"; - lha = (struct lha *)(a->format->data); lha->decompress_init = 0; lha->end_of_entry = 0; lha->end_of_entry_cleanup = 0;@@ -900,7 +898,7 @@ { const unsigned char *p; size_t extdsize;- int i, err, err2;+ int err, err2; int namelen, padding; unsigned char headersum, sum_calculated; @@ -925,10 +923,9 @@ if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL) return (truncated_error(a)); - for (i = 0; i < namelen; i++) {- if (p[i + H1_FILE_NAME_OFFSET] == 0xff)- goto invalid;/* Invalid filename. */- }+ if (memchr(p + H1_FILE_NAME_OFFSET, 0xff,+ (size_t)namelen) != NULL)+ goto invalid; /* Invalid filename. */ archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen); lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen); lha->setflag |= CRC_IS_SET;@@ -1097,7 +1094,7 @@ header_crc = lha_crc16(0, p, H3_FIXED_SIZE); __archive_read_consume(a, H3_FIXED_SIZE); - /* Reject rediculously large header */+ /* Reject ridiculously large header */ if (lha->header_size > 65536) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "LHa header size too large");@@ -1452,7 +1449,7 @@ static int lha_end_of_entry(struct archive_read *a) {- struct lha *lha = (struct lha *)(a->format->data);+ struct lha *lha = a->format->data; int r = ARCHIVE_EOF; if (!lha->end_of_entry_cleanup) {@@ -1473,7 +1470,7 @@ archive_read_format_lha_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct lha *lha = (struct lha *)(a->format->data);+ struct lha *lha = a->format->data; int r; if (lha->entry_unconsumed) {@@ -1506,7 +1503,7 @@ lha_read_data_none(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct lha *lha = (struct lha *)(a->format->data);+ struct lha *lha = a->format->data; ssize_t bytes_avail; if (lha->entry_bytes_remaining == 0) {@@ -1553,7 +1550,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct lha *lha = (struct lha *)(a->format->data);+ struct lha *lha = a->format->data; ssize_t bytes_avail; int r; @@ -1643,11 +1640,9 @@ static int archive_read_format_lha_read_data_skip(struct archive_read *a) {- struct lha *lha;+ struct lha *lha = a->format->data; int64_t bytes_skipped; - lha = (struct lha *)(a->format->data);- if (lha->entry_unconsumed) { /* Consume as much as the decompressor actually used. */ __archive_read_consume(a, lha->entry_unconsumed);@@ -1674,7 +1669,7 @@ static int archive_read_format_lha_cleanup(struct archive_read *a) {- struct lha *lha = (struct lha *)(a->format->data);+ struct lha *lha = a->format->data; lzh_decode_free(&(lha->strm)); archive_string_free(&(lha->dirname));@@ -1683,7 +1678,7 @@ archive_string_free(&(lha->gname)); archive_wstring_free(&(lha->ws)); free(lha);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); }
c/archive_read_support_format_mtree.c view
@@ -141,56 +141,6 @@ static size_t mtree_strnlen(const char *, size_t); #endif -/*- * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them- * here. TODO: Move this to configure time, but be careful- * about cross-compile environments.- */-static int64_t-get_time_t_max(void)-{-#if defined(TIME_T_MAX)- return TIME_T_MAX;-#else- /* ISO C allows time_t to be a floating-point type,- but POSIX requires an integer type. The following- should work on any system that follows the POSIX- conventions. */- if (((time_t)0) < ((time_t)-1)) {- /* Time_t is unsigned */- return (~(time_t)0);- } else {- /* Time_t is signed. */- /* Assume it's the same as int64_t or int32_t */- if (sizeof(time_t) == sizeof(int64_t)) {- return (time_t)INT64_MAX;- } else {- return (time_t)INT32_MAX;- }- }-#endif-}--static int64_t-get_time_t_min(void)-{-#if defined(TIME_T_MIN)- return TIME_T_MIN;-#else- if (((time_t)0) < ((time_t)-1)) {- /* Time_t is unsigned */- return (time_t)0;- } else {- /* Time_t is signed. */- if (sizeof(time_t) == sizeof(int64_t)) {- return (time_t)INT64_MIN;- } else {- return (time_t)INT32_MIN;- }- }-#endif-}- #ifdef HAVE_STRNLEN #define mtree_strnlen(a,b) strnlen(a,b) #else@@ -199,12 +149,10 @@ { size_t i; - for (i = 0; i <= maxlen; i++) {+ for (i = 0; i < maxlen; i++) { if (p[i] == 0) break; }- if (i > maxlen)- return (-1);/* invalid */ return (i); } #endif@@ -213,9 +161,8 @@ archive_read_format_mtree_options(struct archive_read *a, const char *key, const char *val) {- struct mtree *mtree;+ struct mtree *mtree = a->format->data; - mtree = (struct mtree *)(a->format->data); if (strcmp(key, "checkfs") == 0) { /* Allows to read information missing from the mtree from the file system */ if (val == NULL || val[0] == 0) {@@ -297,11 +244,9 @@ static int cleanup(struct archive_read *a) {- struct mtree *mtree;+ struct mtree *mtree = a->format->data; struct mtree_entry *p, *q; - mtree = (struct mtree *)(a->format->data);- /* Close any dangling file descriptor before freeing */ if (mtree->fd >= 0) { close(mtree->fd);@@ -322,7 +267,7 @@ free(mtree->buff); free(mtree);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } @@ -387,7 +332,7 @@ */ while (*nl == 0 && len == *avail && !quit) { ssize_t diff = *ravail - *avail;- size_t nbytes_req = (*ravail+1023) & ~1023U;+ size_t nbytes_req = ((size_t)*ravail + 1023) & ~1023U; ssize_t tested; /*@@ -876,7 +821,7 @@ line = next; next = line + strcspn(line, " \t\r\n"); eq = strchr(line, '=');- if (eq > next)+ if (eq == NULL || eq > next) len = next - line; else len = eq - line;@@ -1121,12 +1066,10 @@ static int read_header(struct archive_read *a, struct archive_entry *entry) {- struct mtree *mtree;+ struct mtree *mtree = a->format->data; char *p; int r, use_next; - mtree = (struct mtree *)(a->format->data);- if (mtree->fd >= 0) { close(mtree->fd); mtree->fd = -1;@@ -1781,8 +1724,6 @@ } if (strcmp(key, "time") == 0) { int64_t m;- int64_t my_time_t_max = get_time_t_max();- int64_t my_time_t_min = get_time_t_min(); long ns = 0; *parsed_kws |= MTREE_HAS_MTIME;@@ -1802,10 +1743,10 @@ else ns = (long)v; }- if (m > my_time_t_max)- m = my_time_t_max;- else if (m < my_time_t_min)- m = my_time_t_min;+ if (m > TIME_MAX)+ m = TIME_MAX;+ else if (m < TIME_MIN)+ m = TIME_MIN; archive_entry_set_mtime(entry, (time_t)m, ns); return (ARCHIVE_OK); }@@ -1892,11 +1833,10 @@ read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct mtree *mtree = a->format->data; size_t bytes_to_read; ssize_t bytes_read;- struct mtree *mtree; - mtree = (struct mtree *)(a->format->data); if (mtree->fd < 0) { *buff = NULL; *offset = 0;@@ -1937,9 +1877,8 @@ static int skip(struct archive_read *a) {- struct mtree *mtree;+ struct mtree *mtree = a->format->data; - mtree = (struct mtree *)(a->format->data); if (mtree->fd >= 0) { close(mtree->fd); mtree->fd = -1;
c/archive_read_support_format_rar.c view
@@ -42,6 +42,7 @@ #include "archive_endian.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_ppmd7_private.h" #include "archive_private.h" #include "archive_read_private.h"@@ -201,8 +202,8 @@ struct huffman_code { struct huffman_tree_node *tree;- int numentries;- int numallocatedentries;+ size_t numentries;+ size_t numallocatedentries; int minlength; int maxlength; int tablesize;@@ -227,8 +228,6 @@ { uint8_t *staticdata; uint32_t staticdatalen;- uint8_t *globalbackup;- uint32_t globalbackuplen; uint64_t fingerprint; uint32_t usagecount; uint32_t oldfilterlength;@@ -499,7 +498,7 @@ static int rar_br_fillup(struct archive_read *a, struct rar_br *br) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; int n = CACHE_BITS - br->cache_avail; for (;;) {@@ -594,7 +593,7 @@ static int rar_br_preparation(struct archive_read *a, struct rar_br *br) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; if (rar->bytes_remaining > 0) { br->next_in = rar_read_ahead(a, 1, &(br->avail_in));@@ -709,7 +708,7 @@ ppmd_read(void *p) { struct archive_read *a = ((IByteIn*)p)->a;- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; struct rar_br *br = &(rar->br); Byte b; if (!rar_br_read_ahead(a, br, 8))@@ -777,7 +776,7 @@ archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) { if (_a && _a->format) {- struct rar * rar = (struct rar *)_a->format->data;+ struct rar *rar = _a->format->data; if (rar) { return rar->has_encrypted_entries; }@@ -877,10 +876,9 @@ archive_read_format_rar_options(struct archive_read *a, const char *key, const char *val) {- struct rar *rar;+ struct rar *rar = a->format->data; int ret = ARCHIVE_FAILED; - rar = (struct rar *)(a->format->data); if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -907,9 +905,9 @@ archive_read_format_rar_read_header(struct archive_read *a, struct archive_entry *entry) {+ struct rar *rar = a->format->data; const void *h; const char *p;- struct rar *rar; int64_t skip; char head_type; int ret;@@ -920,8 +918,6 @@ if (a->archive.archive_format_name == NULL) a->archive.archive_format_name = "RAR"; - rar = (struct rar *)(a->format->data);- /* * It should be sufficient to call archive_read_next_header() for * a reader to determine if an entry is encrypted or not. If the@@ -1100,7 +1096,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; int ret; if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {@@ -1151,12 +1147,10 @@ static int archive_read_format_rar_read_data_skip(struct archive_read *a) {- struct rar *rar;+ struct rar *rar = a->format->data; int64_t bytes_skipped; int ret; - rar = (struct rar *)(a->format->data);- if (rar->bytes_unconsumed > 0) { /* Consume as much as the decompressor actually used. */ __archive_read_consume(a, rar->bytes_unconsumed);@@ -1189,9 +1183,9 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset, int whence) {+ struct rar *rar = a->format->data; int64_t client_offset, ret; size_t i;- struct rar *rar = (struct rar *)(a->format->data); if (rar->compression_method == COMPRESS_METHOD_STORE) {@@ -1294,6 +1288,12 @@ "Error during seek of RAR file"); return (ARCHIVE_FAILED); }+ if (rar->cursor == 0)+ {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "Invalid RAR seek cursor state");+ return (ARCHIVE_FAILED);+ } client_offset += rar->dbo[rar->cursor].start_offset - rar->dbo[rar->cursor-1].end_offset; continue;@@ -1342,9 +1342,8 @@ static int archive_read_format_rar_cleanup(struct archive_read *a) {- struct rar *rar;+ struct rar *rar = a->format->data; - rar = (struct rar *)(a->format->data); free_codes(a); clear_filters(&rar->filters); free(rar->filename);@@ -1354,7 +1353,7 @@ free(rar->lzss.window); __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context); free(rar);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } @@ -1362,9 +1361,9 @@ read_header(struct archive_read *a, struct archive_entry *entry, char head_type) {+ struct rar *rar = a->format->data; const void *h; const char *p, *endp;- struct rar *rar; struct rar_header rar_header; struct rar_file_header file_header; int64_t header_size;@@ -1380,8 +1379,6 @@ char *newptr; size_t newsize; - rar = (struct rar *)(a->format->data);- /* Setup a string conversion object for non-rar-unicode filenames. */ sconv = rar->opt_sconv; if (sconv == NULL) {@@ -1668,16 +1665,18 @@ return (ARCHIVE_FATAL); } fn_sconv = rar->sconv_utf8;- while ((strp = strchr(filename, '\\')) != NULL)- *strp = '/';+ strp = filename;+ while ((strp = strchr(strp, '\\')) != NULL)+ *strp++ = '/'; p += filename_size; } } else { fn_sconv = sconv;- while ((strp = strchr(filename, '\\')) != NULL)- *strp = '/';+ strp = filename;+ while ((strp = strchr(strp, '\\')) != NULL)+ *strp++ = '/'; p += filename_size; } @@ -1962,12 +1961,11 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry, struct archive_string_conv *sconv) {+ struct rar *rar = a->format->data; const void *h; const char *p;- struct rar *rar; int ret = (ARCHIVE_OK); - rar = (struct rar *)(a->format->data); if ((uintmax_t)rar->packed_size > SIZE_MAX) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,@@ -2004,10 +2002,9 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct rar *rar;+ struct rar *rar = a->format->data; ssize_t bytes_avail; - rar = (struct rar *)(a->format->data); if (rar->bytes_remaining == 0 && !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER)) {@@ -2052,13 +2049,11 @@ if (looper++ > MAX_COMPRESS_DEPTH) return (ARCHIVE_FAILED); - struct rar *rar;+ struct rar *rar = a->format->data; int64_t start, end; size_t bs; int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i; - rar = (struct rar *)(a->format->data);- do { if (!rar->valid) return (ARCHIVE_FAILED);@@ -2303,11 +2298,11 @@ static int parse_codes(struct archive_read *a) {+ struct rar *rar = a->format->data; int i, j, val, n, r; unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags; unsigned int maxorder; struct huffman_code precode;- struct rar *rar = (struct rar *)(a->format->data); struct rar_br *br = &(rar->br); free_codes(a);@@ -2589,7 +2584,7 @@ static void free_codes(struct archive_read *a) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; free(rar->maincode.tree); free(rar->offsetcode.tree); free(rar->lowoffsetcode.tree);@@ -2608,10 +2603,10 @@ static int read_next_symbol(struct archive_read *a, struct huffman_code *code) {+ struct rar *rar = a->format->data; unsigned char bit; unsigned int bits; int length, value, node;- struct rar *rar; struct rar_br *br; if (!code->table)@@ -2620,7 +2615,6 @@ return -1; } - rar = (struct rar *)(a->format->data); br = &(rar->br); /* Look ahead (peek) at bits */@@ -2825,11 +2819,16 @@ { void *new_tree; if (code->numallocatedentries == code->numentries) {- int new_num_entries = 256;- if (code->numentries > 0) {- new_num_entries = code->numentries * 2;- }- new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));+ size_t size, new_num_entries;++ if (code->numentries == 0)+ new_num_entries = 256;+ else if (archive_ckd_mul_size(&new_num_entries, code->numentries, 2)+ || new_num_entries > INT_MAX)+ return -1;+ if (archive_ckd_mul_size(&size, new_num_entries, sizeof(*code->tree)))+ return -1;+ new_tree = realloc(code->tree, size); if (new_tree == NULL) return (-1); code->tree = (struct huffman_tree_node *)new_tree;@@ -2870,7 +2869,7 @@ "Huffman tree was not created"); return (ARCHIVE_FAILED); }- if (node < 0 || node >= code->numentries)+ if (node < 0 || (size_t)node >= code->numentries) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid location to Huffman tree specified");@@ -2958,9 +2957,9 @@ static const unsigned char shortbits[] = { 2, 2, 3, 4, 5, 6, 6, 6 }; + struct rar *rar = a->format->data; int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol; unsigned char newfile;- struct rar *rar = (struct rar *)(a->format->data); struct rar_br *br = &(rar->br); if (rar->filters.filterstart < *end)@@ -3148,8 +3147,8 @@ copy_from_lzss_window(struct archive_read *a, uint8_t *buffer, int64_t startpos, int length) {+ struct rar *rar = a->format->data; int windowoffs, firstpart;- struct rar *rar = (struct rar *)(a->format->data); windowoffs = lzss_offset_for_position(&rar->lzss, startpos); firstpart = lzss_size(&rar->lzss) - windowoffs;@@ -3176,8 +3175,8 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer, int64_t startpos, size_t length) {+ struct rar *rar = a->format->data; int windowoffs, firstpart;- struct rar *rar = (struct rar *)(a->format->data); if (length > rar->unp_buffer_size) {@@ -3233,7 +3232,7 @@ static const void * rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; const void *h; int ret; @@ -3270,7 +3269,7 @@ static int parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; struct rar_filters *filters = &rar->filters; struct memory_bit_reader br = { 0 };@@ -3438,7 +3437,7 @@ static int run_filters(struct archive_read *a) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; struct rar_filters *filters = &rar->filters; struct rar_filter *filter = filters->stack; struct rar_filter *f;@@ -3606,7 +3605,6 @@ { struct rar_program_code *next = prog->next; free(prog->staticdata);- free(prog->globalbackup); free(prog); prog = next; }@@ -3659,7 +3657,7 @@ static int read_filter(struct archive_read *a, int64_t *end) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; uint8_t flags, val, *code; uint16_t length, i; @@ -3855,7 +3853,7 @@ state.delta[0] = state.lastdelta; predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF; byte = (predbyte - delta) & 0xFF;- prederror = delta << 3;+ prederror = delta * 8; state.error[0] += abs(prederror); state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]); state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);@@ -3912,7 +3910,7 @@ static int rar_decode_byte(struct archive_read *a, uint8_t *byte) {- struct rar *rar = (struct rar *)(a->format->data);+ struct rar *rar = a->format->data; struct rar_br *br = &(rar->br); if (!rar_br_read_ahead(a, br, 8)) return 0;
c/archive_read_support_format_rar5.c view
@@ -44,4443 +44,4457 @@ #include "archive_entry.h" #include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_entry_private.h"-#include "archive_time_private.h"--#ifdef HAVE_BLAKE2_H-#include <blake2.h>-#else-#include "archive_blake2.h"-#endif--/*#define CHECK_CRC_ON_SOLID_SKIP*/-/*#define DONT_FAIL_ON_CRC_ERROR*/-/*#define DEBUG*/--#define rar5_min(a, b) (((a) > (b)) ? (b) : (a))-#define rar5_max(a, b) (((a) > (b)) ? (a) : (b))-#define rar5_countof(X) ((const ssize_t) (sizeof(X) / sizeof(*X)))--#if defined DEBUG-#define DEBUG_CODE if(1)-#define LOG(...) do { printf("rar5: " __VA_ARGS__); puts(""); } while(0)-#else-#define DEBUG_CODE if(0)-#endif--/* Real RAR5 magic number is:- *- * 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00- * "Rar!→•☺·\x00"- *- * Retrieved with `rar5_signature()` by XOR'ing it with 0xA1, because I don't- * want to put this magic sequence in each binary that uses libarchive, so- * applications that scan through the file for this marker won't trigger on- * this "false" one.- *- * The array itself is decrypted in `rar5_init` function. */--static const unsigned char rar5_signature_xor[] = {- 243, 192, 211, 128, 187, 166, 160, 161-};-static const size_t g_unpack_window_size = 0x20000;--/* These could have been static const's, but they aren't, because of- * Visual Studio. */-#define MAX_NAME_IN_CHARS 2048-#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)--struct file_header {- ssize_t bytes_remaining;- ssize_t unpacked_size;- int64_t last_offset; /* Used in sanity checks. */- int64_t last_size; /* Used in sanity checks. */-- uint8_t solid : 1; /* Is this a solid stream? */- uint8_t service : 1; /* Is this file a service data? */- uint8_t eof : 1; /* Did we finish unpacking the file? */- uint8_t dir : 1; /* Is this file entry a directory? */-- /* Optional time fields. */- int64_t e_mtime;- int64_t e_ctime;- int64_t e_atime;- uint32_t e_mtime_ns;- uint32_t e_ctime_ns;- uint32_t e_atime_ns;-- /* Optional hash fields. */- uint32_t stored_crc32;- uint32_t calculated_crc32;- uint8_t blake2sp[32];- blake2sp_state b2state;- char has_blake2;-- /* Optional redir fields */- uint64_t redir_type;- uint64_t redir_flags;-- ssize_t solid_window_size; /* Used in file format check. */-};--enum EXTRA {- EX_CRYPT = 0x01,- EX_HASH = 0x02,- EX_HTIME = 0x03,- EX_VERSION = 0x04,- EX_REDIR = 0x05,- EX_UOWNER = 0x06,- EX_SUBDATA = 0x07-};--#define REDIR_SYMLINK_IS_DIR 1--enum REDIR_TYPE {- REDIR_TYPE_NONE = 0,- REDIR_TYPE_UNIXSYMLINK = 1,- REDIR_TYPE_WINSYMLINK = 2,- REDIR_TYPE_JUNCTION = 3,- REDIR_TYPE_HARDLINK = 4,- REDIR_TYPE_FILECOPY = 5,-};--#define OWNER_USER_NAME 0x01-#define OWNER_GROUP_NAME 0x02-#define OWNER_USER_UID 0x04-#define OWNER_GROUP_GID 0x08-#define OWNER_MAXNAMELEN 256--enum FILTER_TYPE {- FILTER_DELTA = 0, /* Generic pattern. */- FILTER_E8 = 1, /* Intel x86 code. */- FILTER_E8E9 = 2, /* Intel x86 code. */- FILTER_ARM = 3, /* ARM code. */- FILTER_AUDIO = 4, /* Audio filter, not used in RARv5. */- FILTER_RGB = 5, /* Color palette, not used in RARv5. */- FILTER_ITANIUM = 6, /* Intel's Itanium, not used in RARv5. */- FILTER_PPM = 7, /* Predictive pattern matching, not used in- RARv5. */- FILTER_NONE = 8,-};--struct filter_info {- int type;- int channels;- int pos_r;-- int64_t block_start;- ssize_t block_length;- uint16_t width;-};--struct data_ready {- char used;- const uint8_t* buf;- size_t size;- int64_t offset;-};--struct cdeque {- uint16_t beg_pos;- uint16_t end_pos;- uint16_t cap_mask;- uint16_t size;- size_t* arr;-};--struct decode_table {- uint32_t size;- int32_t decode_len[16];- uint32_t decode_pos[16];- uint32_t quick_bits;- uint8_t quick_len[1 << 10];- uint16_t quick_num[1 << 10];- uint16_t decode_num[306];-};--struct comp_state {- /* Flag used to specify if unpacker needs to reinitialize the- uncompression context. */- uint8_t initialized : 1;-- /* Flag used when applying filters. */- uint8_t all_filters_applied : 1;-- /* Flag used to skip file context reinitialization, used when unpacker- is skipping through different multivolume archives. */- uint8_t switch_multivolume : 1;-- /* Flag used to specify if unpacker has processed the whole data block- or just a part of it. */- uint8_t block_parsing_finished : 1;-- /* Flag used to indicate that a previous file using this buffer was- encrypted, meaning no data in the buffer can be trusted */- uint8_t data_encrypted : 1;-- signed int notused : 3;-- int flags; /* Uncompression flags. */- int method; /* Uncompression algorithm method. */- int version; /* Uncompression algorithm version. */- ssize_t window_size; /* Size of window_buf. */- uint8_t* window_buf; /* Circular buffer used during- decompression. */- uint8_t* filtered_buf; /* Buffer used when applying filters. */- const uint8_t* block_buf; /* Buffer used when merging blocks. */- ssize_t window_mask; /* Convenience field; window_size - 1. */- int64_t write_ptr; /* This amount of data has been unpacked- in the window buffer. */- int64_t last_write_ptr; /* This amount of data has been stored in- the output file. */- int64_t last_unstore_ptr; /* Counter of bytes extracted during- unstoring. This is separate from- last_write_ptr because of how SERVICE- base blocks are handled during skipping- in solid multiarchive archives. */- int64_t solid_offset; /* Additional offset inside the window- buffer, used in unpacking solid- archives. */- ssize_t cur_block_size; /* Size of current data block. */- int last_len; /* Flag used in lzss decompression. */-- /* Decode tables used during lzss uncompression. */--#define HUFF_BC 20- struct decode_table bd; /* huffman bit lengths */-#define HUFF_NC 306- struct decode_table ld; /* literals */-#define HUFF_DC 64- struct decode_table dd; /* distances */-#define HUFF_LDC 16- struct decode_table ldd; /* lower bits of distances */-#define HUFF_RC 44- struct decode_table rd; /* repeating distances */-#define HUFF_TABLE_SIZE (HUFF_NC + HUFF_DC + HUFF_RC + HUFF_LDC)-- /* Circular deque for storing filters. */- struct cdeque filters;- int64_t last_block_start; /* Used for sanity checking. */- ssize_t last_block_length; /* Used for sanity checking. */-- /* Distance cache used during lzss uncompression. */- int dist_cache[4];-- /* Data buffer stack. */- struct data_ready dready[2];-};--/* Bit reader state. */-struct bit_reader {- int8_t bit_addr; /* Current bit pointer inside current byte. */- int in_addr; /* Current byte pointer. */-};--/* RARv5 block header structure. Use bf_* functions to get values from- * block_flags_u8 field. I.e. bf_byte_count, etc. */-struct compressed_block_header {- /* block_flags_u8 contain fields encoded in little-endian bitfield:- *- * - table present flag (shr 7, and 1),- * - last block flag (shr 6, and 1),- * - byte_count (shr 3, and 7),- * - bit_size (shr 0, and 7).- */- uint8_t block_flags_u8;- uint8_t block_cksum;-};--/* RARv5 main header structure. */-struct main_header {- /* Does the archive contain solid streams? */- uint8_t solid : 1;-- /* If this a multi-file archive? */- uint8_t volume : 1;- uint8_t endarc : 1;- uint8_t notused : 5;-- unsigned int vol_no;-};--struct generic_header {- uint8_t split_after : 1;- uint8_t split_before : 1;- uint8_t padding : 6;- int size;- int last_header_id;-};--struct multivolume {- unsigned int expected_vol_no;- uint8_t* push_buf;-};--/* Main context structure. */-struct rar5 {- int header_initialized;-- /* Set to 1 if current file is positioned AFTER the magic value- * of the archive file. This is used in header reading functions. */- int skipped_magic;-- /* Set to not zero if we're in skip mode (either by calling- * rar5_data_skip function or when skipping over solid streams).- * Set to 0 when in * extraction mode. This is used during checksum- * calculation functions. */- int skip_mode;-- /* Set to not zero if we're in block merging mode (i.e. when switching- * to another file in multivolume archive, last block from 1st archive- * needs to be merged with 1st block from 2nd archive). This flag- * guards against recursive use of the merging function, which doesn't- * support recursive calls. */- int merge_mode;-- /* An offset to QuickOpen list. This is not supported by this unpacker,- * because we're focusing on streaming interface. QuickOpen is designed- * to make things quicker for non-stream interfaces, so it's not our- * use case. */- uint64_t qlist_offset;-- /* An offset to additional Recovery data. This is not supported by this- * unpacker. Recovery data are additional Reed-Solomon codes that could- * be used to calculate bytes that are missing in archive or are- * corrupted. */- uint64_t rr_offset;-- /* Various context variables grouped to different structures. */- struct generic_header generic;- struct main_header main;- struct comp_state cstate;- struct file_header file;- struct bit_reader bits;- struct multivolume vol;-- /* The header of currently processed RARv5 block. Used in main- * decompression logic loop. */- struct compressed_block_header last_block_hdr;-- /*- * Custom field to denote that this archive contains encrypted entries- */- int has_encrypted_entries;- int headers_are_encrypted;-};--/* Forward function declarations. */--static void rar5_signature(char *buf);-static int verify_global_checksums(struct archive_read* a);-static int rar5_read_data_skip(struct archive_read *a);-static int push_data_ready(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, size_t size, int64_t offset);-static void clear_data_ready_stack(struct rar5* rar);-static void rar5_deinit(struct rar5* rar);--/* CDE_xxx = Circular Double Ended (Queue) return values. */-enum CDE_RETURN_VALUES {- CDE_OK, CDE_ALLOC, CDE_PARAM, CDE_OUT_OF_BOUNDS,-};--/* Clears the contents of this circular deque. */-static void cdeque_clear(struct cdeque* d) {- d->size = 0;- d->beg_pos = 0;- d->end_pos = 0;-}--/* Creates a new circular deque object. Capacity must be power of 2: 8, 16, 32,- * 64, 256, etc. When the user will add another item above current capacity,- * the circular deque will overwrite the oldest entry. */-static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {- if(d == NULL || max_capacity_power_of_2 == 0)- return CDE_PARAM;-- d->cap_mask = max_capacity_power_of_2 - 1;- d->arr = NULL;-- if((max_capacity_power_of_2 & d->cap_mask) != 0)- return CDE_PARAM;-- cdeque_clear(d);- d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);-- return d->arr ? CDE_OK : CDE_ALLOC;-}--/* Return the current size (not capacity) of circular deque `d`. */-static size_t cdeque_size(struct cdeque* d) {- return d->size;-}--/* Returns the first element of current circular deque. Note that this function- * doesn't perform any bounds checking. If you need bounds checking, use- * `cdeque_front()` function instead. */-static void cdeque_front_fast(struct cdeque* d, void** value) {- *value = (void*) d->arr[d->beg_pos];-}--/* Returns the first element of current circular deque. This function- * performs bounds checking. */-static int cdeque_front(struct cdeque* d, void** value) {- if(d->size > 0) {- cdeque_front_fast(d, value);- return CDE_OK;- } else- return CDE_OUT_OF_BOUNDS;-}--/* Pushes a new element into the end of this circular deque object. */-static int cdeque_push_back(struct cdeque* d, void* item) {- if(d == NULL)- return CDE_PARAM;-- if(d->size == d->cap_mask + 1)- return CDE_OUT_OF_BOUNDS;-- d->arr[d->end_pos] = (size_t) item;- d->end_pos = (d->end_pos + 1) & d->cap_mask;- d->size++;-- return CDE_OK;-}--/* Pops a front element of this circular deque object and returns its value.- * This function doesn't perform any bounds checking. */-static void cdeque_pop_front_fast(struct cdeque* d, void** value) {- *value = (void*) d->arr[d->beg_pos];- d->beg_pos = (d->beg_pos + 1) & d->cap_mask;- d->size--;-}--/* Pops a front element of this circular deque object and returns its value.- * This function performs bounds checking. */-static int cdeque_pop_front(struct cdeque* d, void** value) {- if(!d || !value)- return CDE_PARAM;-- if(d->size == 0)- return CDE_OUT_OF_BOUNDS;-- cdeque_pop_front_fast(d, value);- return CDE_OK;-}--/* Convenience function to cast filter_info** to void **. */-static void** cdeque_filter_p(struct filter_info** f) {- return (void**) (size_t) f;-}--/* Convenience function to cast filter_info* to void *. */-static void* cdeque_filter(struct filter_info* f) {- return (void**) (size_t) f;-}--/* Destroys this circular deque object. Deallocates the memory of the- * collection buffer, but doesn't deallocate the memory of any pointer passed- * to this deque as a value. */-static void cdeque_free(struct cdeque* d) {- if(!d)- return;-- if(!d->arr)- return;-- free(d->arr);-- d->arr = NULL;- d->beg_pos = -1;- d->end_pos = -1;- d->cap_mask = 0;-}--static inline-uint8_t bf_bit_size(const struct compressed_block_header* hdr) {- return hdr->block_flags_u8 & 7;-}--static inline-uint8_t bf_byte_count(const struct compressed_block_header* hdr) {- return (hdr->block_flags_u8 >> 3) & 7;-}--static inline-uint8_t bf_is_table_present(const struct compressed_block_header* hdr) {- return (hdr->block_flags_u8 >> 7) & 1;-}--static inline-uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {- return (hdr->block_flags_u8 >> 6) & 1;-}--static inline struct rar5* get_context(struct archive_read* a) {- return (struct rar5*) a->format->data;-}--/* Convenience functions used by filter implementations. */-static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,- int64_t start, int64_t end)-{- if((start & mask) > (end & mask)) {- ssize_t len1 = mask + 1 - (start & mask);- ssize_t len2 = end & mask;-- memcpy(dst, &window[start & mask], len1);- memcpy(dst + len1, window, len2);- } else {- memcpy(dst, &window[start & mask], (size_t) (end - start));- }-}--static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {- uint8_t linear_buf[4];- circular_memcpy(linear_buf, rar->cstate.window_buf,- rar->cstate.window_mask, offset, offset + 4);- return archive_le32dec(linear_buf);-}--static void write_filter_data(struct rar5* rar, uint32_t offset,- uint32_t value)-{- archive_le32enc(&rar->cstate.filtered_buf[offset], value);-}--/* Allocates a new filter descriptor and adds it to the filter array. */-static struct filter_info* add_new_filter(struct rar5* rar) {- struct filter_info* f = calloc(1, sizeof(*f));-- if(!f) {- return NULL;- }-- if (CDE_OK != cdeque_push_back(&rar->cstate.filters, cdeque_filter(f))) {- free(f);- return NULL;- }-- return f;-}--static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {- int i;- ssize_t dest_pos, src_pos = 0;-- for(i = 0; i < flt->channels; i++) {- uint8_t prev_byte = 0;- for(dest_pos = i;- dest_pos < flt->block_length;- dest_pos += flt->channels)- {- uint8_t byte;-- byte = rar->cstate.window_buf[- (rar->cstate.solid_offset + flt->block_start +- src_pos) & rar->cstate.window_mask];-- prev_byte -= byte;- rar->cstate.filtered_buf[dest_pos] = prev_byte;- src_pos++;- }- }-- return ARCHIVE_OK;-}--static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,- int extended)-{- const uint32_t file_size = 0x1000000;- ssize_t i;-- circular_memcpy(rar->cstate.filtered_buf,- rar->cstate.window_buf, rar->cstate.window_mask,- rar->cstate.solid_offset + flt->block_start,- rar->cstate.solid_offset + flt->block_start + flt->block_length);-- for(i = 0; i < flt->block_length - 4;) {- uint8_t b = rar->cstate.window_buf[- (rar->cstate.solid_offset + flt->block_start +- i++) & rar->cstate.window_mask];-- /*- * 0xE8 = x86's call <relative_addr_uint32> (function call)- * 0xE9 = x86's jmp <relative_addr_uint32> (unconditional jump)- */- if(b == 0xE8 || (extended && b == 0xE9)) {-- uint32_t addr;- uint32_t offset = (i + flt->block_start) % file_size;-- addr = read_filter_data(rar,- (uint32_t)(rar->cstate.solid_offset +- flt->block_start + i) & rar->cstate.window_mask);-- if(addr & 0x80000000) {- if(((addr + offset) & 0x80000000) == 0) {- write_filter_data(rar, (uint32_t)i,- addr + file_size);- }- } else {- if((addr - file_size) & 0x80000000) {- uint32_t naddr = addr - offset;- write_filter_data(rar, (uint32_t)i,- naddr);- }- }-- i += 4;- }- }-- return ARCHIVE_OK;-}--static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {- ssize_t i = 0;- uint32_t offset;-- circular_memcpy(rar->cstate.filtered_buf,- rar->cstate.window_buf, rar->cstate.window_mask,- rar->cstate.solid_offset + flt->block_start,- rar->cstate.solid_offset + flt->block_start + flt->block_length);-- for(i = 0; i < flt->block_length - 3; i += 4) {- uint8_t* b = &rar->cstate.window_buf[- (rar->cstate.solid_offset +- flt->block_start + i + 3) & rar->cstate.window_mask];-- if(*b == 0xEB) {- /* 0xEB = ARM's BL (branch + link) instruction. */- offset = read_filter_data(rar,- (rar->cstate.solid_offset + flt->block_start + i) &- (uint32_t)rar->cstate.window_mask) & 0x00ffffff;-- offset -= (uint32_t) ((i + flt->block_start) / 4);- offset = (offset & 0x00ffffff) | 0xeb000000;- write_filter_data(rar, (uint32_t)i, offset);- }- }-- return ARCHIVE_OK;-}--static int run_filter(struct archive_read* a, struct filter_info* flt) {- int ret;- struct rar5* rar = get_context(a);-- clear_data_ready_stack(rar);- free(rar->cstate.filtered_buf);-- rar->cstate.filtered_buf = malloc(flt->block_length);- if(!rar->cstate.filtered_buf) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for filter data");- return ARCHIVE_FATAL;- }-- switch(flt->type) {- case FILTER_DELTA:- ret = run_delta_filter(rar, flt);- break;-- case FILTER_E8:- /* fallthrough */- case FILTER_E8E9:- ret = run_e8e9_filter(rar, flt,- flt->type == FILTER_E8E9);- break;-- case FILTER_ARM:- ret = run_arm_filter(rar, flt);- break;-- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported filter type: 0x%x",- (unsigned int)flt->type);- return ARCHIVE_FAILED;- }-- if(ret != ARCHIVE_OK) {- /* Filter has failed. */- return ret;- }-- if(ARCHIVE_OK != push_data_ready(a, rar, rar->cstate.filtered_buf,- flt->block_length, rar->cstate.last_write_ptr))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Stack overflow when submitting unpacked data");-- return ARCHIVE_FATAL;- }-- rar->cstate.last_write_ptr += flt->block_length;- return ARCHIVE_OK;-}--/* The `push_data` function submits the selected data range to the user.- * Next call of `use_data` will use the pointer, size and offset arguments- * that are specified here. These arguments are pushed to the FIFO stack here,- * and popped from the stack by the `use_data` function. */-static void push_data(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, int64_t idx_begin, int64_t idx_end)-{- const ssize_t wmask = rar->cstate.window_mask;- const ssize_t solid_write_ptr = (rar->cstate.solid_offset +- rar->cstate.last_write_ptr) & wmask;-- idx_begin += rar->cstate.solid_offset;- idx_end += rar->cstate.solid_offset;-- /* Check if our unpacked data is wrapped inside the window circular- * buffer. If it's not wrapped, it can be copied out by using- * a single memcpy, but when it's wrapped, we need to copy the first- * part with one memcpy, and the second part with another memcpy. */-- if((idx_begin & wmask) > (idx_end & wmask)) {- /* The data is wrapped (begin offset sis bigger than end- * offset). */- const ssize_t frag1_size = rar->cstate.window_size -- (idx_begin & wmask);- const ssize_t frag2_size = idx_end & wmask;-- /* Copy the first part of the buffer first. */- push_data_ready(a, rar, buf + solid_write_ptr, frag1_size,- rar->cstate.last_write_ptr);-- /* Copy the second part of the buffer. */- push_data_ready(a, rar, buf, frag2_size,- rar->cstate.last_write_ptr + frag1_size);-- rar->cstate.last_write_ptr += frag1_size + frag2_size;- } else {- /* Data is not wrapped, so we can just use one call to copy the- * data. */- push_data_ready(a, rar,- buf + solid_write_ptr, (idx_end - idx_begin) & wmask,- rar->cstate.last_write_ptr);-- rar->cstate.last_write_ptr += idx_end - idx_begin;- }-}--/* Convenience function that submits the data to the user. It uses the- * unpack window buffer as a source location. */-static void push_window_data(struct archive_read* a, struct rar5* rar,- int64_t idx_begin, int64_t idx_end)-{- push_data(a, rar, rar->cstate.window_buf, idx_begin, idx_end);-}--static int apply_filters(struct archive_read* a) {- struct filter_info* flt;- struct rar5* rar = get_context(a);- int ret;-- rar->cstate.all_filters_applied = 0;-- /* Get the first filter that can be applied to our data. The data- * needs to be fully unpacked before the filter can be run. */- if(CDE_OK == cdeque_front(&rar->cstate.filters,- cdeque_filter_p(&flt))) {- /* Check if our unpacked data fully covers this filter's- * range. */- if(rar->cstate.write_ptr > flt->block_start &&- rar->cstate.write_ptr >= flt->block_start +- flt->block_length) {- /* Check if we have some data pending to be written- * right before the filter's start offset. */- if(rar->cstate.last_write_ptr == flt->block_start) {- /* Run the filter specified by descriptor- * `flt`. */- ret = run_filter(a, flt);- if(ret != ARCHIVE_OK) {- /* Filter failure, return error. */- return ret;- }-- /* Filter descriptor won't be needed anymore- * after it's used, * so remove it from the- * filter list and free its memory. */- (void) cdeque_pop_front(&rar->cstate.filters,- cdeque_filter_p(&flt));-- free(flt);- } else {- /* We can't run filters yet, dump the memory- * right before the filter. */- push_window_data(a, rar,- rar->cstate.last_write_ptr,- flt->block_start);- }-- /* Return 'filter applied or not needed' state to the- * caller. */- return ARCHIVE_RETRY;- }- }-- rar->cstate.all_filters_applied = 1;- return ARCHIVE_OK;-}--static void dist_cache_push(struct rar5* rar, int value) {- int* q = rar->cstate.dist_cache;-- q[3] = q[2];- q[2] = q[1];- q[1] = q[0];- q[0] = value;-}--static int dist_cache_touch(struct rar5* rar, int idx) {- int* q = rar->cstate.dist_cache;- int i, dist = q[idx];-- for(i = idx; i > 0; i--)- q[i] = q[i - 1];-- q[0] = dist;- return dist;-}--static void free_filters(struct rar5* rar) {- struct cdeque* d = &rar->cstate.filters;-- /* Free any remaining filters. All filters should be naturally- * consumed by the unpacking function, so remaining filters after- * unpacking normally mean that unpacking wasn't successful.- * But still of course we shouldn't leak memory in such case. */-- /* cdeque_size() is a fast operation, so we can use it as a loop- * expression. */- while(cdeque_size(d) > 0) {- struct filter_info* f = NULL;-- /* Pop_front will also decrease the collection's size. */- if (CDE_OK == cdeque_pop_front(d, cdeque_filter_p(&f)))- free(f);- }-- cdeque_clear(d);-- /* Also clear out the variables needed for sanity checking. */- rar->cstate.last_block_start = 0;- rar->cstate.last_block_length = 0;-}--static void reset_file_context(struct rar5* rar) {- memset(&rar->file, 0, sizeof(rar->file));- blake2sp_init(&rar->file.b2state, 32);-- if(rar->main.solid) {- rar->cstate.solid_offset += rar->cstate.write_ptr;- } else {- rar->cstate.solid_offset = 0;- }-- rar->cstate.write_ptr = 0;- rar->cstate.last_write_ptr = 0;- rar->cstate.last_unstore_ptr = 0;-- rar->file.redir_type = REDIR_TYPE_NONE;- rar->file.redir_flags = 0;-- free_filters(rar);-}--static inline int get_archive_read(struct archive* a,- struct archive_read** ar)-{- *ar = (struct archive_read*) a;- archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_support_format_rar5");-- return ARCHIVE_OK;-}--static int read_ahead(struct archive_read* a, size_t how_many,- const uint8_t** ptr)-{- if(!ptr)- return 0;-- *ptr = __archive_read_ahead(a, how_many, NULL);- if(*ptr == NULL) {- return 0;- }-- return 1;-}--static int consume(struct archive_read* a, int64_t how_many) {- int ret;-- ret = how_many == __archive_read_consume(a, how_many)- ? ARCHIVE_OK- : ARCHIVE_FATAL;-- return ret;-}--/**- * Read a RAR5 variable sized numeric value. This value will be stored in- * `pvalue`. The `pvalue_len` argument points to a variable that will receive- * the byte count that was consumed in order to decode the `pvalue` value, plus- * one.- *- * pvalue_len is optional and can be NULL.- *- * NOTE: if `pvalue_len` is NOT NULL, the caller needs to manually consume- * the number of bytes that `pvalue_len` value contains. If the `pvalue_len`- * is NULL, this consuming operation is done automatically.- *- * Returns 1 if *pvalue was successfully read.- * Returns 0 if there was an error. In this case, *pvalue contains an- * invalid value.- */--static int read_var(struct archive_read* a, uint64_t* pvalue,- uint64_t* pvalue_len)-{- uint64_t result = 0;- size_t shift, i;- const uint8_t* p;- uint8_t b;-- /* We will read maximum of 8 bytes. We don't have to handle the- * situation to read the RAR5 variable-sized value stored at the end of- * the file, because such situation will never happen. */- if(!read_ahead(a, 8, &p))- return 0;-- for(shift = 0, i = 0; i < 8; i++, shift += 7) {- b = p[i];-- /* Strip the MSB from the input byte and add the resulting- * number to the `result`. */- result += (b & (uint64_t)0x7F) << shift;-- /* MSB set to 1 means we need to continue decoding process.- * MSB set to 0 means we're done.- *- * This conditional checks for the second case. */- if((b & 0x80) == 0) {- if(pvalue) {- *pvalue = result;- }-- /* If the caller has passed the `pvalue_len` pointer,- * store the number of consumed bytes in it and do NOT- * consume those bytes, since the caller has all the- * information it needs to perform */- if(pvalue_len) {- *pvalue_len = 1 + i;- } else {- /* If the caller did not provide the- * `pvalue_len` pointer, it will not have the- * possibility to advance the file pointer,- * because it will not know how many bytes it- * needs to consume. This is why we handle- * such situation here automatically. */- if(ARCHIVE_OK != consume(a, 1 + i)) {- return 0;- }- }-- /* End of decoding process, return success. */- return 1;- }- }-- /* The decoded value takes the maximum number of 8 bytes.- * It's a maximum number of bytes, so end decoding process here- * even if the first bit of last byte is 1. */- if(pvalue) {- *pvalue = result;- }-- if(pvalue_len) {- *pvalue_len = 9;- } else {- if(ARCHIVE_OK != consume(a, 9)) {- return 0;- }- }-- return 1;-}--static int read_var_sized(struct archive_read* a, size_t* pvalue,- size_t* pvalue_len)-{- uint64_t v;- uint64_t v_size = 0;-- const int ret = pvalue_len ? read_var(a, &v, &v_size)- : read_var(a, &v, NULL);-- if(ret == 1 && pvalue) {- *pvalue = (size_t) v;- }-- if(pvalue_len) {- /* Possible data truncation should be safe. */- *pvalue_len = (size_t) v_size;- }-- return ret;-}--static int read_bits_32(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint32_t* value)-{- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Premature end of stream during extraction of data (#1)");- return ARCHIVE_FATAL;- }-- uint32_t bits = archive_be32dec(p + rar->bits.in_addr);- bits <<= rar->bits.bit_addr;- bits |= p[rar->bits.in_addr + 4] >> (8 - rar->bits.bit_addr);- *value = bits;- return ARCHIVE_OK;-}--static int read_bits_16(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint16_t* value)-{- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Premature end of stream during extraction of data (#2)");- return ARCHIVE_FATAL;- }-- uint32_t bits = archive_be24dec(p + (unsigned)rar->bits.in_addr);- bits >>= (8 - rar->bits.bit_addr);- *value = bits & 0xffff;- return ARCHIVE_OK;-}--static void skip_bits(struct rar5* rar, int bits) {- const int new_bits = rar->bits.bit_addr + bits;- rar->bits.in_addr += new_bits >> 3;- rar->bits.bit_addr = new_bits & 7;-}--/* n = up to 16 */-static int read_consume_bits(struct archive_read* a, struct rar5* rar,- const uint8_t* p, int n, int* value)-{- uint16_t v;- int ret, num;-- if(n == 0 || n > 16) {- /* This is a programmer error and should never happen- * in runtime. */- return ARCHIVE_FATAL;- }-- ret = read_bits_16(a, rar, p, &v);- if(ret != ARCHIVE_OK)- return ret;-- num = (int) v;- num >>= 16 - n;-- skip_bits(rar, n);-- if(value)- *value = num;-- return ARCHIVE_OK;-}--static char read_u32(struct archive_read* a, uint32_t* pvalue) {- const uint8_t* p;- if(!read_ahead(a, 4, &p))- return 0;-- *pvalue = archive_le32dec(p);- return ARCHIVE_OK == consume(a, 4);-}--static char read_u64(struct archive_read* a, uint64_t* pvalue) {- const uint8_t* p;- if(!read_ahead(a, 8, &p))- return 0;-- *pvalue = archive_le64dec(p);- return ARCHIVE_OK == consume(a, 8);-}--static int bid_standard(struct archive_read* a) {- const uint8_t* p;- char signature[sizeof(rar5_signature_xor)];-- rar5_signature(signature);-- if(!read_ahead(a, sizeof(rar5_signature_xor), &p))- return -1;-- if(!memcmp(signature, p, sizeof(rar5_signature_xor)))- return 30;-- return -1;-}--static int bid_sfx(struct archive_read *a)-{- const char *p;-- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)- return -1;-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {- /* This is a PE file */- char signature[sizeof(rar5_signature_xor)];- ssize_t offset = 0x10000;- ssize_t window = 4096;- ssize_t bytes_avail;-- rar5_signature(signature);-- while (offset + window <= (1024 * 512)) {- const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);- if (buff == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- return 0;- continue;- }- p = buff + offset;- while (p + 8 < buff + bytes_avail) {- if (memcmp(p, signature, sizeof(signature)) == 0)- return 30;- p += 0x10;- }- offset = p - buff;- }- }-- return 0;-}--static int rar5_bid(struct archive_read* a, int best_bid) {- int my_bid;-- if(best_bid > 30)- return -1;-- my_bid = bid_standard(a);- if(my_bid > -1) {- return my_bid;- }- my_bid = bid_sfx(a);- if (my_bid > -1) {- return my_bid;- }-- return -1;-}--static int rar5_options(struct archive_read *a, const char *key,- const char *val) {- (void) a;- (void) key;- (void) val;-- /* No options supported in this version. Return the ARCHIVE_WARN code- * to signal the options supervisor that the unpacker didn't handle- * setting this option. */-- return ARCHIVE_WARN;-}--static void init_header(struct archive_read* a) {- a->archive.archive_format = ARCHIVE_FORMAT_RAR_V5;- a->archive.archive_format_name = "RAR5";-}--static void init_window_mask(struct rar5* rar) {- if (rar->cstate.window_size)- rar->cstate.window_mask = rar->cstate.window_size - 1;- else- rar->cstate.window_mask = 0;-}--enum HEADER_FLAGS {- HFL_EXTRA_DATA = 0x0001,- HFL_DATA = 0x0002,- HFL_SKIP_IF_UNKNOWN = 0x0004,- HFL_SPLIT_BEFORE = 0x0008,- HFL_SPLIT_AFTER = 0x0010,- HFL_CHILD = 0x0020,- HFL_INHERITED = 0x0040-};--static int process_main_locator_extra_block(struct archive_read* a,- struct rar5* rar)-{- uint64_t locator_flags;-- enum LOCATOR_FLAGS {- QLIST = 0x01, RECOVERY = 0x02,- };-- if(!read_var(a, &locator_flags, NULL)) {- return ARCHIVE_EOF;- }-- if(locator_flags & QLIST) {- if(!read_var(a, &rar->qlist_offset, NULL)) {- return ARCHIVE_EOF;- }-- /* qlist is not used */- }-- if(locator_flags & RECOVERY) {- if(!read_var(a, &rar->rr_offset, NULL)) {- return ARCHIVE_EOF;- }-- /* rr is not used */- }-- return ARCHIVE_OK;-}--static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,- int64_t* extra_data_size)-{- size_t hash_type = 0;- size_t value_len;-- enum HASH_TYPE {- BLAKE2sp = 0x00- };-- if(!read_var_sized(a, &hash_type, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len)) {- return ARCHIVE_EOF;- }-- /* The file uses BLAKE2sp checksum algorithm instead of plain old- * CRC32. */- if(hash_type == BLAKE2sp) {- const uint8_t* p;- const int hash_size = sizeof(rar->file.blake2sp);-- if(!read_ahead(a, hash_size, &p))- return ARCHIVE_EOF;-- rar->file.has_blake2 = 1;- memcpy(&rar->file.blake2sp, p, hash_size);-- if(ARCHIVE_OK != consume(a, hash_size)) {- return ARCHIVE_EOF;- }-- *extra_data_size -= hash_size;- } else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported hash type (0x%jx)", (uintmax_t)hash_type);- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--static int parse_htime_item(struct archive_read* a, char unix_time,- int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)-{- if(unix_time) {- uint32_t time_val;- if(!read_u32(a, &time_val))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- *sec = (int64_t) time_val;- } else {- uint64_t windows_time;- if(!read_u64(a, &windows_time))- return ARCHIVE_EOF;-- ntfs_to_unix(windows_time, sec, nsec);- *extra_data_size -= 8;- }-- return ARCHIVE_OK;-}--static int parse_file_extra_version(struct archive_read* a,- struct archive_entry* e, int64_t* extra_data_size)-{- size_t flags = 0;- size_t version = 0;- size_t value_len = 0;- struct archive_string version_string;- struct archive_string name_utf8_string;- const char* cur_filename;-- /* Flags are ignored. */- if(!read_var_sized(a, &flags, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len))- return ARCHIVE_EOF;-- if(!read_var_sized(a, &version, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len))- return ARCHIVE_EOF;-- /* extra_data_size should be zero here. */-- cur_filename = archive_entry_pathname_utf8(e);- if(cur_filename == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Version entry without file name");- return ARCHIVE_FATAL;- }-- archive_string_init(&version_string);- archive_string_init(&name_utf8_string);-- /* Prepare a ;123 suffix for the filename, where '123' is the version- * value of this file. */- archive_string_sprintf(&version_string, ";%zu", version);-- /* Build the new filename. */- archive_strcat(&name_utf8_string, cur_filename);- archive_strcat(&name_utf8_string, version_string.s);-- /* Apply the new filename into this file's context. */- archive_entry_update_pathname_utf8(e, name_utf8_string.s);-- /* Free buffers. */- archive_string_free(&version_string);- archive_string_free(&name_utf8_string);- return ARCHIVE_OK;-}--static int parse_file_extra_htime(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)-{- char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;- size_t flags = 0;- size_t value_len;-- enum HTIME_FLAGS {- IS_UNIX = 0x01,- HAS_MTIME = 0x02,- HAS_CTIME = 0x04,- HAS_ATIME = 0x08,- HAS_UNIX_NS = 0x10,- };-- if(!read_var_sized(a, &flags, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len)) {- return ARCHIVE_EOF;- }-- unix_time = flags & IS_UNIX;- has_unix_ns = unix_time && (flags & HAS_UNIX_NS);- has_mtime = flags & HAS_MTIME;- has_atime = flags & HAS_ATIME;- has_ctime = flags & HAS_CTIME;- rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;-- if(has_mtime) {- parse_htime_item(a, unix_time, &rar->file.e_mtime,- &rar->file.e_mtime_ns, extra_data_size);- }-- if(has_ctime) {- parse_htime_item(a, unix_time, &rar->file.e_ctime,- &rar->file.e_ctime_ns, extra_data_size);- }-- if(has_atime) {- parse_htime_item(a, unix_time, &rar->file.e_atime,- &rar->file.e_atime_ns, extra_data_size);- }-- if(has_mtime && has_unix_ns) {- if(!read_u32(a, &rar->file.e_mtime_ns))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- }-- if(has_ctime && has_unix_ns) {- if(!read_u32(a, &rar->file.e_ctime_ns))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- }-- if(has_atime && has_unix_ns) {- if(!read_u32(a, &rar->file.e_atime_ns))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- }-- /* The seconds and nanoseconds are either together, or separated in two- * fields so we parse them, then set the archive_entry's times. */- if(has_mtime) {- archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);- }-- if(has_ctime) {- archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);- }-- if(has_atime) {- archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);- }-- return ARCHIVE_OK;-}--static int parse_file_extra_redir(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)-{- uint64_t value_size = 0;- size_t target_size = 0;- char target_utf8_buf[MAX_NAME_IN_BYTES];- const uint8_t* p;-- if(!read_var(a, &rar->file.redir_type, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if(!read_var(a, &rar->file.redir_flags, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if(!read_var_sized(a, &target_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= target_size + 1;-- if(target_size > (MAX_NAME_IN_CHARS - 1)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Link target is too long");- return ARCHIVE_FATAL;- }-- if(target_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "No link target specified");- return ARCHIVE_FATAL;- }-- if(!read_ahead(a, target_size, &p))- return ARCHIVE_EOF;-- memcpy(target_utf8_buf, p, target_size);- target_utf8_buf[target_size] = 0;-- if(ARCHIVE_OK != consume(a, (int64_t)target_size))- return ARCHIVE_EOF;-- switch(rar->file.redir_type) {- case REDIR_TYPE_UNIXSYMLINK:- case REDIR_TYPE_WINSYMLINK:- archive_entry_set_filetype(e, AE_IFLNK);- archive_entry_update_symlink_utf8(e, target_utf8_buf);- if (rar->file.redir_flags & REDIR_SYMLINK_IS_DIR) {- archive_entry_set_symlink_type(e,- AE_SYMLINK_TYPE_DIRECTORY);- } else {- archive_entry_set_symlink_type(e,- AE_SYMLINK_TYPE_FILE);- }- break;-- case REDIR_TYPE_HARDLINK:- archive_entry_set_filetype(e, AE_IFREG);- archive_entry_update_hardlink_utf8(e, target_utf8_buf);- break;-- default:- /* Unknown redir type, skip it. */- break;- }- return ARCHIVE_OK;-}--static int parse_file_extra_owner(struct archive_read* a,- struct archive_entry* e, int64_t* extra_data_size)-{- uint64_t flags = 0;- uint64_t value_size = 0;- uint64_t id = 0;- size_t name_len = 0;- size_t name_size = 0;- char namebuf[OWNER_MAXNAMELEN];- const uint8_t* p;-- if(!read_var(a, &flags, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if ((flags & OWNER_USER_NAME) != 0) {- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= name_size + 1;-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- if (name_size >= OWNER_MAXNAMELEN) {- name_len = OWNER_MAXNAMELEN - 1;- } else {- name_len = name_size;- }-- memcpy(namebuf, p, name_len);- namebuf[name_len] = 0;- if(ARCHIVE_OK != consume(a, (int64_t)name_size))- return ARCHIVE_EOF;-- archive_entry_set_uname(e, namebuf);- }- if ((flags & OWNER_GROUP_NAME) != 0) {- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= name_size + 1;-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- if (name_size >= OWNER_MAXNAMELEN) {- name_len = OWNER_MAXNAMELEN - 1;- } else {- name_len = name_size;- }-- memcpy(namebuf, p, name_len);- namebuf[name_len] = 0;- if(ARCHIVE_OK != consume(a, (int64_t)name_size))- return ARCHIVE_EOF;-- archive_entry_set_gname(e, namebuf);- }- if ((flags & OWNER_USER_UID) != 0) {- if(!read_var(a, &id, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- archive_entry_set_uid(e, (la_int64_t)id);- }- if ((flags & OWNER_GROUP_GID) != 0) {- if(!read_var(a, &id, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- archive_entry_set_gid(e, (la_int64_t)id);- }- return ARCHIVE_OK;-}--static int process_head_file_extra(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, int64_t extra_data_size)-{- uint64_t extra_field_size;- uint64_t extra_field_id = 0;- uint64_t var_size;-- while(extra_data_size > 0) {- /* Make sure we won't fail if the file declares only unsupported- attributes. */- int ret = ARCHIVE_OK;-- if(!read_var(a, &extra_field_size, &var_size))- return ARCHIVE_EOF;-- extra_data_size -= var_size;- if(ARCHIVE_OK != consume(a, var_size)) {- return ARCHIVE_EOF;- }-- if(!read_var(a, &extra_field_id, &var_size))- return ARCHIVE_EOF;-- extra_field_size -= var_size;- extra_data_size -= var_size;- if(ARCHIVE_OK != consume(a, var_size)) {- return ARCHIVE_EOF;- }-- switch(extra_field_id) {- case EX_HASH:- ret = parse_file_extra_hash(a, rar,- &extra_data_size);- break;- case EX_HTIME:- ret = parse_file_extra_htime(a, e, rar,- &extra_data_size);- break;- case EX_REDIR:- ret = parse_file_extra_redir(a, e, rar,- &extra_data_size);- break;- case EX_UOWNER:- ret = parse_file_extra_owner(a, e,- &extra_data_size);- break;- case EX_VERSION:- ret = parse_file_extra_version(a, e,- &extra_data_size);- break;- case EX_CRYPT:- /* Mark the entry as encrypted */- archive_entry_set_is_data_encrypted(e, 1);- rar->has_encrypted_entries = 1;- rar->cstate.data_encrypted = 1;- /* fallthrough */- case EX_SUBDATA:- /* fallthrough */- default:- /* Skip unsupported entry. */- extra_data_size -= extra_field_size;- if (ARCHIVE_OK != consume(a, extra_field_size)) {- return ARCHIVE_EOF;- }-- /* Don't fail on unsupported attribute -- we've handled it- by skipping over it. */- ret = ARCHIVE_OK;- }-- if (ret != ARCHIVE_OK) {- /* Forward any errors signalled by the attribute parsing- functions. */- return ret;- }- }-- if (extra_data_size != 0) {- /* We didn't skip everything, or we skipped too much; either way,- there's an error in this parsing function. */-- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "unsupported structure of file header extra data");- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--static int file_entry_sanity_checks(struct archive_read* a,- size_t block_flags, uint8_t is_dir, uint64_t unpacked_size,- size_t packed_size)-{- if (is_dir) {- const int declares_data_size =- (int) (unpacked_size != 0 || packed_size != 0);-- /* FILE entries for directories still declare HFL_DATA in block flags,- even though attaching data to such blocks doesn't make much sense. */- if (declares_data_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "directory entries cannot have any data");- return ARCHIVE_FATAL;- }- } else {- const int declares_hfl_data = (int) ((block_flags & HFL_DATA) != 0);- if (!declares_hfl_data) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "no data found in file/service block");- return ARCHIVE_FATAL;- }- }-- return ARCHIVE_OK;-}--static int process_head_file(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- int64_t extra_data_size = 0;- size_t data_size = 0;- size_t file_flags = 0;- size_t file_attr = 0;- size_t compression_info = 0;- size_t host_os = 0;- size_t name_size = 0;- uint64_t unpacked_size, window_size;- uint32_t mtime = 0, crc = 0;- int c_method = 0, c_version = 0;- char name_utf8_buf[MAX_NAME_IN_BYTES];- const uint8_t* p;- int sanity_ret;-- enum FILE_FLAGS {- DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,- UNKNOWN_UNPACKED_SIZE = 0x0008,- };-- enum FILE_ATTRS {- ATTR_READONLY = 0x1, ATTR_HIDDEN = 0x2, ATTR_SYSTEM = 0x4,- ATTR_DIRECTORY = 0x10,- };-- enum COMP_INFO_FLAGS {- SOLID = 0x0040,- };-- enum HOST_OS {- HOST_WINDOWS = 0,- HOST_UNIX = 1,- };-- archive_entry_clear(entry);-- /* Do not reset file context if we're switching archives. */- if(!rar->cstate.switch_multivolume) {- reset_file_context(rar);- }-- if(block_flags & HFL_EXTRA_DATA) {- uint64_t edata_size = 0;- if(!read_var(a, &edata_size, NULL))- return ARCHIVE_EOF;-- /* Intentional type cast from unsigned to signed. */- extra_data_size = (int64_t) edata_size;- }-- if(block_flags & HFL_DATA) {- if(!read_var_sized(a, &data_size, NULL))- return ARCHIVE_EOF;-- if(data_size > SSIZE_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "File data size is too large");- return ARCHIVE_FATAL;- }-- rar->file.bytes_remaining = data_size;- } else {- rar->file.bytes_remaining = 0;- }-- if(!read_var_sized(a, &file_flags, NULL))- return ARCHIVE_EOF;-- if(!read_var(a, &unpacked_size, NULL))- return ARCHIVE_EOF;-- if(file_flags & UNKNOWN_UNPACKED_SIZE) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Files with unknown unpacked size are not supported");- return ARCHIVE_FATAL;- }-- rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);-- sanity_ret = file_entry_sanity_checks(a, block_flags, rar->file.dir,- unpacked_size, data_size);-- if (sanity_ret != ARCHIVE_OK) {- return sanity_ret;- }-- if(!read_var_sized(a, &file_attr, NULL))- return ARCHIVE_EOF;-- if(file_flags & UTIME) {- if(!read_u32(a, &mtime))- return ARCHIVE_EOF;- }-- if(file_flags & CRC32) {- if(!read_u32(a, &crc))- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &compression_info, NULL))- return ARCHIVE_EOF;-- c_method = (int) (compression_info >> 7) & 0x7;- c_version = (int) (compression_info & 0x3f);-- /* RAR5 seems to limit the dictionary size to 64MB. */- window_size = (rar->file.dir > 0) ?- 0 :- g_unpack_window_size << ((compression_info >> 10) & 15);- rar->cstate.method = c_method;- rar->cstate.version = c_version + 50;- rar->file.solid = (compression_info & SOLID) > 0;-- /* Archives which declare solid files without initializing the window- * buffer first are invalid, unless previous data was encrypted, in- * which case we may never have had the chance */-- if(rar->file.solid > 0 && rar->cstate.data_encrypted == 0 &&- rar->cstate.window_buf == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Declared solid file, but no window buffer "- "initialized yet");- return ARCHIVE_FATAL;- }-- /* Check if window_size is a sane value. Also, if the file is not- * declared as a directory, disallow window_size == 0. */- if(window_size > (64 * 1024 * 1024) ||- (rar->file.dir == 0 && window_size == 0))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Declared dictionary size is not supported");- return ARCHIVE_FATAL;- }-- if(rar->file.solid > 0) {- /* Re-check if current window size is the same as previous- * window size (for solid files only). */- if(rar->file.solid_window_size > 0 &&- rar->file.solid_window_size != (ssize_t) window_size)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Window size for this solid file doesn't match "- "the window size used in previous solid file");- return ARCHIVE_FATAL;- }- }- else- rar->cstate.data_encrypted = 0; /* Reset for new buffer */-- if(rar->cstate.window_size < (ssize_t) window_size &&- rar->cstate.window_buf)- {- /* The `data_ready` stack contains pointers to the `window_buf` or- * `filtered_buf` buffers. Since we're about to reallocate the first- * buffer, some of those pointers could become invalid. Therefore, we- * need to dispose of all entries from the stack before attempting the- * realloc. */- clear_data_ready_stack(rar);-- /* If window_buf has been allocated before, reallocate it, so- * that its size will match new window_size. */-- uint8_t* new_window_buf =- realloc(rar->cstate.window_buf, (size_t) window_size);-- if(!new_window_buf) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Not enough memory when trying to realloc the window "- "buffer");- return ARCHIVE_FATAL;- }-- rar->cstate.window_buf = new_window_buf;- }-- /* Values up to 64M should fit into ssize_t on every- * architecture. */- rar->cstate.window_size = (ssize_t) window_size;-- if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {- /* Solid files have to have the same window_size across- whole archive. Remember the window_size parameter- for first solid file found. */- rar->file.solid_window_size = rar->cstate.window_size;- }-- init_window_mask(rar);-- rar->file.service = 0;-- if(!read_var_sized(a, &host_os, NULL))- return ARCHIVE_EOF;-- if(host_os == HOST_WINDOWS) {- /* Host OS is Windows */-- __LA_MODE_T mode;-- if(file_attr & ATTR_DIRECTORY) {- if (file_attr & ATTR_READONLY) {- mode = 0555 | AE_IFDIR;- } else {- mode = 0755 | AE_IFDIR;- }- } else {- if (file_attr & ATTR_READONLY) {- mode = 0444 | AE_IFREG;- } else {- mode = 0644 | AE_IFREG;- }- }-- archive_entry_set_mode(entry, mode);-- if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {- char buf[sizeof(",rdonly,hidden,system")];- char *fflags[3] = { "", "", "" };- char **flag = fflags;-- if (file_attr & ATTR_READONLY)- *flag++ = ",rdonly";- if (file_attr & ATTR_HIDDEN)- *flag++ = ",hidden";- if (file_attr & ATTR_SYSTEM)- *flag++ = ",system";-- snprintf(buf, sizeof(buf), "%s%s%s",- fflags[0], fflags[1], fflags[2]);- archive_entry_copy_fflags_text(entry, buf + 1);- }- } else if(host_os == HOST_UNIX) {- /* Host OS is Unix */- archive_entry_set_mode(entry, (__LA_MODE_T) file_attr);- } else {- /* Unknown host OS */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported Host OS: 0x%jx",- (uintmax_t)host_os);-- return ARCHIVE_FATAL;- }-- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;-- if(name_size > (MAX_NAME_IN_CHARS - 1)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Filename is too long");-- return ARCHIVE_FATAL;- }-- if(name_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "No filename specified");-- return ARCHIVE_FATAL;- }-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- memcpy(name_utf8_buf, p, name_size);- name_utf8_buf[name_size] = 0;- if(ARCHIVE_OK != consume(a, name_size)) {- return ARCHIVE_EOF;- }-- archive_entry_update_pathname_utf8(entry, name_utf8_buf);-- if(extra_data_size > 0) {- int ret = process_head_file_extra(a, entry, rar,- extra_data_size);-- /*- * TODO: rewrite or remove useless sanity check- * as extra_data_size is not passed as a pointer- *- if(extra_data_size < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "File extra data size is not zero");- return ARCHIVE_FATAL;- }- */-- if(ret != ARCHIVE_OK)- return ret;- }-- if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {- rar->file.unpacked_size = (ssize_t) unpacked_size;- if(rar->file.redir_type == REDIR_TYPE_NONE)- archive_entry_set_size(entry, unpacked_size);- }-- if(file_flags & UTIME) {- archive_entry_set_mtime(entry, (time_t) mtime, 0);- }-- if(file_flags & CRC32) {- rar->file.stored_crc32 = crc;- }-- if(!rar->cstate.switch_multivolume) {- /* Do not reinitialize unpacking state if we're switching- * archives. */- rar->cstate.block_parsing_finished = 1;- rar->cstate.all_filters_applied = 1;- rar->cstate.initialized = 0;- }-- if(rar->generic.split_before > 0) {- /* If now we're standing on a header that has a 'split before'- * mark, it means we're standing on a 'continuation' file- * header. Signal the caller that if it wants to move to- * another file, it must call rar5_read_header() function- * again. */-- return ARCHIVE_RETRY;- } else {- return ARCHIVE_OK;- }-}--static int process_head_service(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- /* Process this SERVICE block the same way as FILE blocks. */- int ret = process_head_file(a, rar, entry, block_flags);- if(ret != ARCHIVE_OK)- return ret;-- rar->file.service = 1;-- /* But skip the data part automatically. It's no use for the user- * anyway. It contains only service data, not even needed to- * properly unpack the file. */- ret = rar5_read_data_skip(a);- if(ret != ARCHIVE_OK)- return ret;-- /* After skipping, try parsing another block automatically. */- return ARCHIVE_RETRY;-}--static int process_head_main(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- int ret;- uint64_t extra_data_size = 0;- size_t extra_field_size = 0;- size_t extra_field_id = 0;- size_t archive_flags = 0;-- enum MAIN_FLAGS {- VOLUME = 0x0001, /* multi-volume archive */- VOLUME_NUMBER = 0x0002, /* volume number, first vol doesn't- * have it */- SOLID = 0x0004, /* solid archive */- PROTECT = 0x0008, /* contains Recovery info */- LOCK = 0x0010, /* readonly flag, not used */- };-- enum MAIN_EXTRA {- // Just one attribute here.- LOCATOR = 0x01,- };-- (void) entry;-- if(block_flags & HFL_EXTRA_DATA) {- if(!read_var(a, &extra_data_size, NULL))- return ARCHIVE_EOF;- } else {- extra_data_size = 0;- }-- if(!read_var_sized(a, &archive_flags, NULL)) {- return ARCHIVE_EOF;- }-- rar->main.volume = (archive_flags & VOLUME) > 0;- rar->main.solid = (archive_flags & SOLID) > 0;-- if(archive_flags & VOLUME_NUMBER) {- size_t v = 0;- if(!read_var_sized(a, &v, NULL)) {- return ARCHIVE_EOF;- }-- if (v > UINT_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid volume number");- return ARCHIVE_FATAL;- }-- rar->main.vol_no = (unsigned int) v;- } else {- rar->main.vol_no = 0;- }-- if(rar->vol.expected_vol_no > 0 &&- rar->main.vol_no != rar->vol.expected_vol_no)- {- /* Returning EOF instead of FATAL because of strange- * libarchive behavior. When opening multiple files via- * archive_read_open_filenames(), after reading up the whole- * last file, the __archive_read_ahead function wraps up to- * the first archive instead of returning EOF. */- return ARCHIVE_EOF;- }-- if(extra_data_size == 0) {- /* Early return. */- return ARCHIVE_OK;- }-- if(!read_var_sized(a, &extra_field_size, NULL)) {- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &extra_field_id, NULL)) {- return ARCHIVE_EOF;- }-- if(extra_field_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid extra field size");- return ARCHIVE_FATAL;- }-- switch(extra_field_id) {- case LOCATOR:- ret = process_main_locator_extra_block(a, rar);- if(ret != ARCHIVE_OK) {- /* Error while parsing main locator extra- * block. */- return ret;- }-- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported extra type (0x%jx)",- (uintmax_t)extra_field_id);- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--static int skip_unprocessed_bytes(struct archive_read* a) {- struct rar5* rar = get_context(a);- int ret;-- if(rar->file.bytes_remaining) {- /* Use different skipping method in block merging mode than in- * normal mode. If merge mode is active, rar5_read_data_skip- * can't be used, because it could allow recursive use of- * merge_block() * function, and this function doesn't support- * recursive use. */- if(rar->merge_mode) {- /* Discard whole merged block. This is valid in solid- * mode as well, because the code will discard blocks- * only if those blocks are safe to discard (i.e.- * they're not FILE blocks). */- ret = consume(a, rar->file.bytes_remaining);- if(ret != ARCHIVE_OK) {- return ret;- }- rar->file.bytes_remaining = 0;- } else {- /* If we're not in merge mode, use safe skipping code.- * This will ensure we'll handle solid archives- * properly. */- ret = rar5_read_data_skip(a);- if(ret != ARCHIVE_OK) {- return ret;- }- }- }-- return ARCHIVE_OK;-}--static int scan_for_signature(struct archive_read* a);--/* Base block processing function. A 'base block' is a RARv5 header block- * that tells the reader what kind of data is stored inside the block.- *- * From the birds-eye view a RAR file looks file this:- *- * <magic><base_block_1><base_block_2>...<base_block_n>- *- * There are a few types of base blocks. Those types are specified inside- * the 'switch' statement in this function. For example purposes, I'll write- * how a standard RARv5 file could look like here:- *- * <magic><MAIN><FILE><FILE><FILE><SERVICE><ENDARC>- *- * The structure above could describe an archive file with 3 files in it,- * one service "QuickOpen" block (that is ignored by this parser), and an- * end of file base block marker.- *- * If the file is stored in multiple archive files ("multiarchive"), it might- * look like this:- *- * .part01.rar: <magic><MAIN><FILE><ENDARC>- * .part02.rar: <magic><MAIN><FILE><ENDARC>- * .part03.rar: <magic><MAIN><FILE><ENDARC>- *- * This example could describe 3 RAR files that contain ONE archived file.- * Or it could describe 3 RAR files that contain 3 different files. Or 3- * RAR files than contain 2 files. It all depends what metadata is stored in- * the headers of <FILE> blocks.- *- * Each <FILE> block contains info about its size, the name of the file it's- * storing inside, and whether this FILE block is a continuation block of- * previous archive ('split before'), and is this FILE block should be- * continued in another archive ('split after'). By parsing the 'split before'- * and 'split after' flags, we're able to tell if multiple <FILE> base blocks- * are describing one file, or multiple files (with the same filename, for- * example).- *- * One thing to note is that if we're parsing the first <FILE> block, and- * we see 'split after' flag, then we need to jump over to another <FILE>- * block to be able to decompress rest of the data. To do this, we need- * to skip the <ENDARC> block, then switch to another file, then skip the- * <magic> block, <MAIN> block, and then we're standing on the proper- * <FILE> block.- */--/*- * A header that carries no file data (HEAD_MAIN, or an unknown block- * flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the- * sub-parser did not read. Skip them before returning ARCHIVE_RETRY,- * otherwise rar5_read_header() re-parses the same block region O(N)- * times instead of O(1), letting a crafted RAR5 file stall the reader- * (GHSA-9h2c-464f-j3hj).- *- * Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block- * into one contiguous buffer with no compaction until we return, so- * body_start stays valid and (cur - body_start) is the exact number of- * body bytes consumed so far.- */-static void-rar5_skip_remaining_block(struct archive_read* a,- const uint8_t* body_start, size_t raw_hdr_size)-{- const uint8_t* cur;-- if(read_ahead(a, 1, &cur)) {- size_t body_used = (size_t)(cur - body_start);-- if(body_used < raw_hdr_size)- (void)consume(a, raw_hdr_size - body_used);- }-}--static int process_base_block(struct archive_read* a,- struct archive_entry* entry)-{- const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;-- struct rar5* rar = get_context(a);- uint32_t hdr_crc, computed_crc;- size_t raw_hdr_size = 0, hdr_size_len, hdr_size;- size_t header_id = 0;- size_t header_flags = 0;- const uint8_t* p;- const uint8_t* body_start;- int ret;-- enum HEADER_TYPE {- HEAD_MARK = 0x00, HEAD_MAIN = 0x01, HEAD_FILE = 0x02,- HEAD_SERVICE = 0x03, HEAD_CRYPT = 0x04, HEAD_ENDARC = 0x05,- HEAD_UNKNOWN = 0xff,- };-- /* Skip any unprocessed data for this file. */- ret = skip_unprocessed_bytes(a);- if(ret != ARCHIVE_OK)- return ret;-- /* Read the expected CRC32 checksum. */- if(!read_u32(a, &hdr_crc)) {- return ARCHIVE_EOF;- }-- /* Read header size. */- if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {- return ARCHIVE_EOF;- }-- hdr_size = raw_hdr_size + hdr_size_len;-- /* Sanity check, maximum header size for RAR5 is 2MB. */- if(hdr_size > (2 * 1024 * 1024)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Base block header is too large");-- return ARCHIVE_FATAL;- }-- /* Additional sanity checks to weed out invalid files. */- if(raw_hdr_size == 0 || hdr_size_len == 0 ||- hdr_size < SMALLEST_RAR5_BLOCK_SIZE)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Too small block encountered (%zu bytes)",- raw_hdr_size);-- return ARCHIVE_FATAL;- }-- /* Read the whole header data into memory, maximum memory use here is- * 2MB. */- if(!read_ahead(a, hdr_size, &p)) {- return ARCHIVE_EOF;- }-- /* Verify the CRC32 of the header data. */- computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);- if(computed_crc != hdr_crc) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Header CRC error");-- return ARCHIVE_FATAL;-#endif- }-- /* Remember the first byte of the block body so we can later skip- * any bytes the sub-parser leaves unconsumed. */- body_start = p + hdr_size_len;-- /* If the checksum is OK, we proceed with parsing. */- if(ARCHIVE_OK != consume(a, hdr_size_len)) {- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &header_id, NULL))- return ARCHIVE_EOF;-- if(!read_var_sized(a, &header_flags, NULL))- return ARCHIVE_EOF;-- rar->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;- rar->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;- rar->generic.size = (int)hdr_size;- rar->generic.last_header_id = (int)header_id;- rar->main.endarc = 0;-- /* Those are possible header ids in RARv5. */- switch(header_id) {- case HEAD_MAIN:- ret = process_head_main(a, rar, entry, header_flags);-- /* Main header doesn't have any files in it, so it's- * pointless to return to the caller. Retry to next- * header, which should be HEAD_FILE/HEAD_SERVICE. */- if(ret == ARCHIVE_OK) {- rar5_skip_remaining_block(a, body_start,- raw_hdr_size);- return ARCHIVE_RETRY;- }-- return ret;- case HEAD_SERVICE:- ret = process_head_service(a, rar, entry, header_flags);- return ret;- case HEAD_FILE:- ret = process_head_file(a, rar, entry, header_flags);- return ret;- case HEAD_CRYPT:- archive_entry_set_is_metadata_encrypted(entry, 1);- archive_entry_set_is_data_encrypted(entry, 1);- rar->has_encrypted_entries = 1;- rar->headers_are_encrypted = 1;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Encryption is not supported");- return ARCHIVE_FATAL;- case HEAD_ENDARC:- rar->main.endarc = 1;-- /* After encountering an end of file marker, we need- * to take into consideration if this archive is- * continued in another file (i.e. is it part01.rar:- * is there a part02.rar?) */- if(rar->main.volume) {- /* In case there is part02.rar, position the- * read pointer in a proper place, so we can- * resume parsing. */- ret = scan_for_signature(a);- if(ret == ARCHIVE_FATAL) {- return ARCHIVE_EOF;- } else {- if(rar->vol.expected_vol_no ==- UINT_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Header error");- return ARCHIVE_FATAL;- }-- rar->vol.expected_vol_no =- rar->main.vol_no + 1;- return ARCHIVE_OK;- }- } else {- return ARCHIVE_EOF;- }- case HEAD_MARK:- return ARCHIVE_EOF;- default:- if((header_flags & HFL_SKIP_IF_UNKNOWN) == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Header type error");- return ARCHIVE_FATAL;- } else {- /* If the block is marked as 'skip if unknown',- * do as the flag says: skip the block- * instead on failing on it. */- rar5_skip_remaining_block(a, body_start,- raw_hdr_size);- return ARCHIVE_RETRY;- }- }--#if !defined WIN32- // Not reached.- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal unpacker error");- return ARCHIVE_FATAL;-#endif-}--static int skip_base_block(struct archive_read* a) {- int ret;- struct rar5* rar = get_context(a);-- /* Create a new local archive_entry structure that will be operated on- * by header reader; operations on this archive_entry will be discarded.- */- struct archive_entry* entry = archive_entry_new();- ret = process_base_block(a, entry);-- /* Discard operations on this archive_entry structure. */- archive_entry_free(entry);- if(ret == ARCHIVE_FATAL)- return ret;-- if(rar->generic.last_header_id == 2 && rar->generic.split_before > 0)- return ARCHIVE_OK;-- if(ret == ARCHIVE_OK)- return ARCHIVE_RETRY;- else- return ret;-}--static int try_skip_sfx(struct archive_read *a)-{- const char *p;-- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)- return ARCHIVE_EOF;-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)- {- char signature[sizeof(rar5_signature_xor)];- const void *h;- const char *q;- size_t skip, total = 0;- ssize_t bytes, window = 4096;-- rar5_signature(signature);-- while (total + window <= (1024 * 512)) {- h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- goto fatal;- continue;- }- if (bytes < 0x40)- goto fatal;- p = h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the RAR header.- */- while (p + 8 < q) {- if (memcmp(p, signature, sizeof(signature)) == 0) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- return (ARCHIVE_OK);- }- p += 0x10;- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- total += skip;- }- }-- return ARCHIVE_OK;-fatal:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out RAR header");- return (ARCHIVE_FATAL);-}--static int rar5_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct rar5* rar = get_context(a);- int ret;-- /*- * It should be sufficient to call archive_read_next_header() for- * a reader to determine if an entry is encrypted or not.- */- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- rar->has_encrypted_entries = 0;- }-- if(rar->header_initialized == 0) {- init_header(a);- if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)- return ret;- rar->header_initialized = 1;- }-- if(rar->skipped_magic == 0) {- if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {- return ARCHIVE_EOF;- }-- rar->skipped_magic = 1;- }-- do {- ret = process_base_block(a, entry);- } while(ret == ARCHIVE_RETRY ||- (rar->main.endarc > 0 && ret == ARCHIVE_OK));-- return ret;-}--static int init_unpack(struct rar5* rar) {- rar->file.calculated_crc32 = 0;- init_window_mask(rar);-- free(rar->cstate.window_buf);- free(rar->cstate.filtered_buf);-- rar->cstate.window_buf = NULL;- rar->cstate.filtered_buf = NULL;-- if(rar->cstate.window_size > 0) {- rar->cstate.window_buf = calloc(1, rar->cstate.window_size);- if(rar->cstate.window_buf == NULL)- return ARCHIVE_FATAL;- rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);- if(rar->cstate.filtered_buf == NULL)- return ARCHIVE_FATAL;- }-- clear_data_ready_stack(rar);-- rar->cstate.write_ptr = 0;- rar->cstate.last_write_ptr = 0;-- memset(&rar->cstate.bd, 0, sizeof(rar->cstate.bd));- memset(&rar->cstate.ld, 0, sizeof(rar->cstate.ld));- memset(&rar->cstate.dd, 0, sizeof(rar->cstate.dd));- memset(&rar->cstate.ldd, 0, sizeof(rar->cstate.ldd));- memset(&rar->cstate.rd, 0, sizeof(rar->cstate.rd));- return ARCHIVE_OK;-}--static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {- int verify_crc;-- if(rar->skip_mode) {-#if defined CHECK_CRC_ON_SOLID_SKIP- verify_crc = 1;-#else- verify_crc = 0;-#endif- } else- verify_crc = 1;-- if(verify_crc) {- /* Don't update CRC32 if the file doesn't have the- * `stored_crc32` info filled in. */- if(rar->file.stored_crc32 > 0) {- rar->file.calculated_crc32 =- crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);- }-- /* Check if the file uses an optional BLAKE2sp checksum- * algorithm. */- if(rar->file.has_blake2 > 0) {- /* Return value of the `update` function is always 0,- * so we can explicitly ignore it here. */- (void) blake2sp_update(&rar->file.b2state, p, to_read);- }- }-}--static int create_decode_tables(uint8_t* bit_length,- struct decode_table* table, int size)-{- int code, upper_limit = 0, i, lc[16];- uint32_t decode_pos_clone[rar5_countof(table->decode_pos)];- ssize_t cur_len, quick_data_size;-- memset(&lc, 0, sizeof(lc));- memset(table->decode_num, 0, sizeof(table->decode_num));- table->size = size;- table->quick_bits = size == HUFF_NC ? 10 : 7;-- for(i = 0; i < size; i++) {- lc[bit_length[i] & 15]++;- }-- lc[0] = 0;- table->decode_pos[0] = 0;- table->decode_len[0] = 0;-- for(i = 1; i < 16; i++) {- upper_limit += lc[i];-- table->decode_len[i] = upper_limit << (16 - i);- table->decode_pos[i] = table->decode_pos[i - 1] + lc[i - 1];-- upper_limit <<= 1;- }-- /* Verify the code-length distribution is not over-subscribed.- * After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).- * For a valid prefix-free code this must be <= 2^16 = 65536.- * An over-subscribed table (> 65536) cannot produce a valid- * decode table and must be rejected. */- if(upper_limit > 65536) {- return ARCHIVE_FAILED;- }-- memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));-- for(i = 0; i < size; i++) {- uint8_t clen = bit_length[i] & 15;- if(clen > 0) {- int last_pos = decode_pos_clone[clen];- table->decode_num[last_pos] = i;- decode_pos_clone[clen]++;- }- }-- quick_data_size = (int64_t)1 << table->quick_bits;- cur_len = 1;- for(code = 0; code < quick_data_size; code++) {- int bit_field = code << (16 - table->quick_bits);- int dist, pos;-- while(cur_len < rar5_countof(table->decode_len) &&- bit_field >= table->decode_len[cur_len]) {- cur_len++;- }-- table->quick_len[code] = (uint8_t) cur_len;-- dist = bit_field - table->decode_len[cur_len - 1];- dist >>= (16 - cur_len);-- pos = table->decode_pos[cur_len & 15] + dist;- if(cur_len < rar5_countof(table->decode_pos) && pos < size) {- table->quick_num[code] = table->decode_num[pos];- } else {- table->quick_num[code] = 0;- }- }-- return ARCHIVE_OK;-}--static int decode_number(struct archive_read* a, struct decode_table* table,- const uint8_t* p, uint16_t* num)-{- int i, bits, dist, ret;- uint16_t bitfield;- uint32_t pos;- struct rar5* rar = get_context(a);-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {- return ret;- }-- bitfield &= 0xfffe;-- if(bitfield < table->decode_len[table->quick_bits]) {- int code = bitfield >> (16 - table->quick_bits);- skip_bits(rar, table->quick_len[code]);- *num = table->quick_num[code];- return ARCHIVE_OK;- }-- bits = 15;-- for(i = table->quick_bits + 1; i < 15; i++) {- if(bitfield < table->decode_len[i]) {- bits = i;- break;- }- }-- skip_bits(rar, bits);-- dist = bitfield - table->decode_len[bits - 1];- dist >>= (16 - bits);- pos = table->decode_pos[bits] + dist;-- if(pos >= table->size)- pos = 0;-- *num = table->decode_num[pos];- return ARCHIVE_OK;-}--/* Reads and parses Huffman tables from the beginning of the block. */-static int parse_tables(struct archive_read* a, struct rar5* rar,- const uint8_t* p)-{- int ret, value, i, w, idx = 0;- uint8_t bit_length[HUFF_BC],- table[HUFF_TABLE_SIZE],- nibble_mask = 0xF0,- nibble_shift = 4;-- enum { ESCAPE = 15 };-- /* The data for table generation is compressed using a simple RLE-like- * algorithm when storing zeroes, so we need to unpack it first. */- for(w = 0, i = 0; w < HUFF_BC;) {- if(i >= rar->cstate.cur_block_size) {- /* Truncated data, can't continue. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated data in huffman tables");- return ARCHIVE_FAILED;- }-- value = (p[i] & nibble_mask) >> nibble_shift;-- if(nibble_mask == 0x0F)- ++i;-- nibble_mask ^= 0xFF;- nibble_shift ^= 4;-- /* Values smaller than 15 is data, so we write it directly.- * Value 15 is a flag telling us that we need to unpack more- * bytes. */- if(value == ESCAPE) {- value = (p[i] & nibble_mask) >> nibble_shift;- if(nibble_mask == 0x0F)- ++i;- nibble_mask ^= 0xFF;- nibble_shift ^= 4;-- if(value == 0) {- /* We sometimes need to write the actual value- * of 15, so this case handles that. */- bit_length[w++] = ESCAPE;- } else {- int k;-- /* Fill zeroes. */- for(k = 0; (k < value + 2) && (w < HUFF_BC);- k++) {- bit_length[w++] = 0;- }- }- } else {- bit_length[w++] = value;- }- }-- rar->bits.in_addr = i;- rar->bits.bit_addr = nibble_shift ^ 4;-- ret = create_decode_tables(bit_length, &rar->cstate.bd, HUFF_BC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Decoding huffman tables failed");- return ARCHIVE_FAILED;- }-- for(i = 0; i < HUFF_TABLE_SIZE;) {- uint16_t num;-- ret = decode_number(a, &rar->cstate.bd, p, &num);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Decoding huffman tables failed");- return ARCHIVE_FAILED;- }-- if(num < 16) {- /* 0..15: store directly */- table[i] = (uint8_t) num;- i++;- } else if(num < 18) {- /* 16..17: repeat previous code */- uint16_t n;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))- return ret;-- if(num == 16) {- n >>= 13;- n += 3;- skip_bits(rar, 3);- } else {- n >>= 9;- n += 11;- skip_bits(rar, 7);- }-- if(i > 0) {- while(n-- > 0 && i < HUFF_TABLE_SIZE) {- table[i] = table[i - 1];- i++;- }- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unexpected error when decoding "- "huffman tables");- return ARCHIVE_FAILED;- }- } else {- /* other codes: fill with zeroes `n` times */- uint16_t n;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))- return ret;-- if(num == 18) {- n >>= 13;- n += 3;- skip_bits(rar, 3);- } else {- n >>= 9;- n += 11;- skip_bits(rar, 7);- }-- while(n-- > 0 && i < HUFF_TABLE_SIZE)- table[i++] = 0;- }- }-- ret = create_decode_tables(&table[idx], &rar->cstate.ld, HUFF_NC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create literal table");- return ARCHIVE_FAILED;- }-- idx += HUFF_NC;-- ret = create_decode_tables(&table[idx], &rar->cstate.dd, HUFF_DC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create distance table");- return ARCHIVE_FAILED;- }-- idx += HUFF_DC;-- ret = create_decode_tables(&table[idx], &rar->cstate.ldd, HUFF_LDC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create lower bits of distances table");- return ARCHIVE_FAILED;- }-- idx += HUFF_LDC;-- ret = create_decode_tables(&table[idx], &rar->cstate.rd, HUFF_RC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create repeating distances table");- return ARCHIVE_FAILED;- }-- return ARCHIVE_OK;-}--/* Parses the block header, verifies its CRC byte, and saves the header- * fields inside the `hdr` pointer. */-static int parse_block_header(struct archive_read* a, const uint8_t* p,- ssize_t* block_size, struct compressed_block_header* hdr)-{- uint8_t calculated_cksum;- memcpy(hdr, p, sizeof(struct compressed_block_header));-- if(bf_byte_count(hdr) > 2) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported block header size (was %d, max is 2)",- bf_byte_count(hdr));- return ARCHIVE_FAILED;- }-- /* This should probably use bit reader interface in order to be more- * future-proof. */- *block_size = 0;- switch(bf_byte_count(hdr)) {- /* 1-byte block size */- case 0:- *block_size = *(const uint8_t*) &p[2];- break;-- /* 2-byte block size */- case 1:- *block_size = archive_le16dec(&p[2]);- break;-- /* 3-byte block size */- case 2:- *block_size = archive_le32dec(&p[2]);- *block_size &= 0x00FFFFFF;- break;-- /* Other block sizes are not supported. This case is not- * reached, because we have an 'if' guard before the switch- * that makes sure of it. */- default:- return ARCHIVE_FATAL;- }-- /* Verify the block header checksum. 0x5A is a magic value and is- * always * constant. */- calculated_cksum = 0x5A- ^ (uint8_t) hdr->block_flags_u8- ^ (uint8_t) *block_size- ^ (uint8_t) (*block_size >> 8)- ^ (uint8_t) (*block_size >> 16);-- if(calculated_cksum != hdr->block_cksum) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Block checksum error: got 0x%x, expected 0x%x",- hdr->block_cksum, calculated_cksum);-- return ARCHIVE_FAILED;-#endif- }-- return ARCHIVE_OK;-}--/* Convenience function used during filter processing. */-static int parse_filter_data(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint32_t* filter_data)-{- int i, bytes, ret;- uint32_t data = 0;-- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))- return ret;-- bytes++;-- for(i = 0; i < bytes; i++) {- uint16_t byte;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {- return ret;- }-- /* Cast to uint32_t will ensure the shift operation will not- * produce undefined result. */- data += ((uint32_t) byte >> 8) << (i * 8);- skip_bits(rar, 8);- }-- *filter_data = data;- return ARCHIVE_OK;-}--/* Function is used during sanity checking. */-static int is_valid_filter_block_start(struct rar5* rar,- uint32_t start)-{- const int64_t block_start = (ssize_t) start + rar->cstate.write_ptr;- const int64_t last_bs = rar->cstate.last_block_start;- const ssize_t last_bl = rar->cstate.last_block_length;-- if(last_bs == 0 || last_bl == 0) {- /* We didn't have any filters yet, so accept this offset. */- return 1;- }-- if(block_start >= last_bs + last_bl) {- /* Current offset is bigger than last block's end offset, so- * accept current offset. */- return 1;- }-- /* Any other case is not a normal situation and we should fail. */- return 0;-}--/* The function will create a new filter, read its parameters from the input- * stream and add it to the filter collection. */-static int parse_filter(struct archive_read* ar, const uint8_t* p) {- uint32_t block_start, block_length;- uint16_t filter_type;- struct filter_info* filt = NULL;- struct rar5* rar = get_context(ar);- int ret;-- /* Read the parameters from the input stream. */- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))- return ret;-- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))- return ret;-- if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))- return ret;-- filter_type >>= 13;- skip_bits(rar, 3);-- /* Perform some sanity checks on this filter parameters. */-- if(block_length < 4 ||- block_length > 0x400000 ||- !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_FAILED;- }-- /* Allocate a new filter. */- filt = add_new_filter(rar);- if(filt == NULL) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate memory for a filter descriptor");- return ARCHIVE_FATAL;- }-- filt->type = filter_type;- filt->block_start = rar->cstate.write_ptr + block_start;- filt->block_length = block_length;-- rar->cstate.last_block_start = filt->block_start;- rar->cstate.last_block_length = filt->block_length;-- /* Read some more data in case this is a DELTA filter. Other filter- * types don't require any additional data over what was already- * read. */- if(filter_type == FILTER_DELTA) {- int channels;-- if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))- return ret;-- filt->channels = channels + 1;- }-- return ARCHIVE_OK;-}--static int decode_code_length(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint16_t code)-{- int lbits, length = 2;-- if(code < 8) {- lbits = 0;- length += code;- } else {- lbits = code / 4 - 1;- length += (4 | (code & 3)) << lbits;- }-- if(lbits > 0) {- int add;-- if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))- return -1;-- length += add;- }-- return length;-}--static int copy_string(struct archive_read* a, int len, int dist) {- struct rar5* rar = get_context(a);- const ssize_t cmask = rar->cstate.window_mask;- const uint64_t write_ptr = rar->cstate.write_ptr +- rar->cstate.solid_offset;- int i;-- if (rar->cstate.window_buf == NULL)- return ARCHIVE_FATAL;-- /* The unpacker spends most of the time in this function. It would be- * a good idea to introduce some optimizations here.- *- * Just remember that this loop treats buffers that overlap differently- * than buffers that do not overlap. This is why a simple memcpy(3)- * call will not be enough. */-- for(i = 0; i < len; i++) {- const ssize_t write_idx = (write_ptr + i) & cmask;- const ssize_t read_idx = (write_ptr + i - dist) & cmask;- rar->cstate.window_buf[write_idx] =- rar->cstate.window_buf[read_idx];- }-- rar->cstate.write_ptr += len;- return ARCHIVE_OK;-}--static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {- struct rar5* rar = get_context(a);- uint16_t num;- int ret;-- const uint64_t cmask = rar->cstate.window_mask;- const struct compressed_block_header* hdr = &rar->last_block_hdr;- const uint8_t bit_size = 1 + bf_bit_size(hdr);-- while(1) {- if(rar->cstate.write_ptr - rar->cstate.last_write_ptr >- (rar->cstate.window_size >> 1)) {- /* Don't allow growing data by more than half of the- * window size at a time. In such case, break the loop;- * next call to this function will continue processing- * from this moment. */- break;- }-- if(rar->bits.in_addr > rar->cstate.cur_block_size - 1 ||- (rar->bits.in_addr == rar->cstate.cur_block_size - 1 &&- rar->bits.bit_addr >= bit_size))- {- /* If the program counter is here, it means the- * function has finished processing the block. */- rar->cstate.block_parsing_finished = 1;- break;- }-- /* Decode the next literal. */- if(ARCHIVE_OK != decode_number(a, &rar->cstate.ld, p, &num)) {- return ARCHIVE_EOF;- }-- /* Num holds a decompression literal, or 'command code'.- *- * - Values lower than 256 are just bytes. Those codes- * can be stored in the output buffer directly.- *- * - Code 256 defines a new filter, which is later used to- * transform the data block accordingly to the filter type.- * The data block needs to be fully uncompressed first.- *- * - Code bigger than 257 and smaller than 262 define- * a repetition pattern that should be copied from- * an already uncompressed chunk of data.- */-- if(num < 256) {- /* Directly store the byte. */- int64_t write_idx = rar->cstate.solid_offset +- rar->cstate.write_ptr++;-- rar->cstate.window_buf[write_idx & cmask] =- (uint8_t) num;- continue;- } else if(num >= 262) {- uint16_t dist_slot;- int len = decode_code_length(a, rar, p, num - 262),- dbits,- dist = 1;-- if(len == -1) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the code length");-- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,- &dist_slot))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the distance slot");-- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- if(dist_slot < 4) {- dbits = 0;- dist += dist_slot;- } else {- dbits = dist_slot / 2 - 1;-- /* Cast to uint32_t will make sure the shift- * left operation won't produce undefined- * result. Then, the uint32_t type will- * be implicitly casted to int. */- dist += (uint32_t) (2 |- (dist_slot & 1)) << dbits;- }-- if(dbits > 0) {- if(dbits >= 4) {- uint32_t add = 0;- uint16_t low_dist;-- if(dbits > 4) {- if(ARCHIVE_OK != (ret = read_bits_32(- a, rar, p, &add))) {- /* Return EOF if we- * can't read more- * data. */- return ret;- }-- skip_bits(rar, dbits - 4);- add = (add >> (- 36 - dbits)) << 4;- dist += add;- }-- if(ARCHIVE_OK != decode_number(a,- &rar->cstate.ldd, p, &low_dist))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the "- "distance slot");-- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- if(dist >= INT_MAX - low_dist - 1) {- /* This only happens in- * invalid archives. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Distance pointer "- "overflow");- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- dist += low_dist;- } else {- /* dbits is one of [0,1,2,3] */- int add;-- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,- p, dbits, &add))) {- /* Return EOF if we can't read- * more data. */- return ret;- }-- dist += add;- }- }-- if(dist > 0x100) {- len++;-- if(dist > 0x2000) {- len++;-- if(dist > 0x40000) {- len++;- }- }- }-- dist_cache_push(rar, dist);- rar->cstate.last_len = len;-- if(ARCHIVE_OK != copy_string(a, len, dist))- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-- continue;- } else if(num == 256) {- /* Create a filter. */- ret = parse_filter(a, p);- if(ret != ARCHIVE_OK)- return ret;-- continue;- } else if(num == 257) {- if(rar->cstate.last_len != 0) {- if(ARCHIVE_OK != copy_string(a,- rar->cstate.last_len,- rar->cstate.dist_cache[0]))- {- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }- }-- continue;- } else {- /* num < 262 */- const int idx = num - 258;- const int dist = dist_cache_touch(rar, idx);-- uint16_t len_slot;- int len;-- if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,- &len_slot)) {- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- len = decode_code_length(a, rar, p, len_slot);- if (len == -1) {- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;- }-- rar->cstate.last_len = len;-- if(ARCHIVE_OK != copy_string(a, len, dist))- return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-- continue;- }- }-- return ARCHIVE_OK;-}--/* Binary search for the RARv5 signature. */-static int scan_for_signature(struct archive_read* a) {- const uint8_t* p;- const int chunk_size = 512;- ssize_t i;- char signature[sizeof(rar5_signature_xor)];-- /* If we're here, it means we're on an 'unknown territory' data.- * There's no indication what kind of data we're reading here.- * It could be some text comment, any kind of binary data,- * digital sign, dragons, etc.- *- * We want to find a valid RARv5 magic header inside this unknown- * data. */-- /* Is it possible in libarchive to just skip everything until the- * end of the file? If so, it would be a better approach than the- * current implementation of this function. */-- rar5_signature(signature);-- while(1) {- if(!read_ahead(a, chunk_size, &p))- return ARCHIVE_EOF;-- for(i = 0; i < chunk_size - (int)sizeof(rar5_signature_xor);- i++) {- if(memcmp(&p[i], signature,- sizeof(rar5_signature_xor)) == 0) {- /* Consume the number of bytes we've used to- * search for the signature, as well as the- * number of bytes used by the signature- * itself. After this we should be standing- * on a valid base block header. */- (void) consume(a,- i + sizeof(rar5_signature_xor));- return ARCHIVE_OK;- }- }-- consume(a, chunk_size);- }-- return ARCHIVE_FATAL;-}--/* This function will switch the multivolume archive file to another file,- * i.e. from part03 to part 04. */-static int advance_multivolume(struct archive_read* a) {- int lret;- struct rar5* rar = get_context(a);-- /* A small state machine that will skip unnecessary data, needed to- * switch from one multivolume to another. Such skipping is needed if- * we want to be an stream-oriented (instead of file-oriented)- * unpacker.- *- * The state machine starts with `rar->main.endarc` == 0. It also- * assumes that current stream pointer points to some base block- * header.- *- * The `endarc` field is being set when the base block parsing- * function encounters the 'end of archive' marker.- */-- while(1) {- if(rar->main.endarc == 1) {- int looping = 1;-- rar->main.endarc = 0;-- while(looping) {- lret = skip_base_block(a);- switch(lret) {- case ARCHIVE_RETRY:- /* Continue looping. */- break;- case ARCHIVE_OK:- /* Break loop. */- looping = 0;- break;- default:- /* Forward any errors to the- * caller. */- return lret;- }- }-- break;- } else {- /* Skip current base block. In order to properly skip- * it, we really need to simply parse it and discard- * the results. */-- lret = skip_base_block(a);- if(lret == ARCHIVE_FATAL || lret == ARCHIVE_FAILED)- return lret;-- /* The `skip_base_block` function tells us if we- * should continue with skipping, or we should stop- * skipping. We're trying to skip everything up to- * a base FILE block. */-- if(lret != ARCHIVE_RETRY) {- /* If there was an error during skipping, or we- * have just skipped a FILE base block... */-- if(rar->main.endarc == 0) {- return lret;- } else {- continue;- }- }- }- }-- return ARCHIVE_OK;-}--/* Merges the partial block from the first multivolume archive file, and- * partial block from the second multivolume archive file. The result is- * a chunk of memory containing the whole block, and the stream pointer- * is advanced to the next block in the second multivolume archive file. */-static int merge_block(struct archive_read* a, ssize_t block_size,- const uint8_t** p)-{- struct rar5* rar = get_context(a);- ssize_t cur_block_size, partial_offset = 0;- const uint8_t* lp;- int ret;-- if(rar->merge_mode) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Recursive merge is not allowed");-- return ARCHIVE_FATAL;- }-- /* Set a flag that we're in the switching mode. */- rar->cstate.switch_multivolume = 1;-- /* Reallocate the memory which will hold the whole block. */- if(rar->vol.push_buf)- free((void*) rar->vol.push_buf);-- /* Increasing the allocation block by 8 is due to bit reading functions,- * which are using additional 2 or 4 bytes. Allocating the block size- * by exact value would make bit reader perform reads from invalid- * memory block when reading the last byte from the buffer. */- rar->vol.push_buf = malloc(block_size + 8);- 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;- }-- /* Valgrind complains if the extension block for bit reader is not- * initialized, so initialize it. */- memset(&rar->vol.push_buf[block_size], 0, 8);-- /* A single block can span across multiple multivolume archive files,- * so we use a loop here. This loop will consume enough multivolume- * archive files until the whole block is read. */-- while(1) {- /* Get the size of current block chunk in this multivolume- * archive file and read it. */- cur_block_size = rar5_min(rar->file.bytes_remaining,- block_size - partial_offset);-- if(cur_block_size < 1) {- /* bytes_remaining is less than 1 at the wrong point in- * the merge loop, indicating corrupt volume- * accounting. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Encountered invalid block size during block merge");- rar->cstate.switch_multivolume = 0;- return ARCHIVE_FATAL;- }-- 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. */- if(partial_offset + cur_block_size > 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;- }-- /* Merge previous block chunk with current block chunk,- * or create first block chunk if this is our first- * iteration. */- 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)) {- /* 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. */- partial_offset += cur_block_size;- rar->file.bytes_remaining -= cur_block_size;-- /* If `partial_offset` is the same as `block_size`, this means- * we've merged all block chunks and we have a valid full- * block. */- if(partial_offset == block_size) {- break;- }-- /* If we don't have any bytes to read, this means we should- * switch to another multivolume archive file. */- if(rar->file.bytes_remaining == 0) {- rar->merge_mode++;- ret = advance_multivolume(a);- rar->merge_mode--;- if(ret != ARCHIVE_OK) {- rar->cstate.switch_multivolume = 0;- return ret;- }- }- }-- *p = rar->vol.push_buf;-- /* If we're here, we can resume unpacking by processing the block- * pointed to by the `*p` memory pointer. */-- return ARCHIVE_OK;-}--static int process_block(struct archive_read* a) {- const uint8_t* p;- struct rar5* rar = get_context(a);- int ret;-- /* If we don't have any data to be processed, this most probably means- * we need to switch to the next volume. */- if(rar->main.volume && rar->file.bytes_remaining == 0) {- ret = advance_multivolume(a);- if(ret != ARCHIVE_OK)- return ret;- }-- if(rar->cstate.block_parsing_finished) {- ssize_t block_size;- ssize_t to_skip;- ssize_t cur_block_size;-- /* The header size won't be bigger than 6 bytes. */- if(!read_ahead(a, 6, &p)) {- /* Failed to prefetch data block header. */- return ARCHIVE_EOF;- }-- /*- * Read block_size by parsing block header. Validate the header- * by calculating CRC byte stored inside the header. Size of- * the header is not constant (block size can be stored either- * in 1 or 2 bytes), that's why block size is left out from the- * `compressed_block_header` structure and returned by- * `parse_block_header` as the second argument. */-- ret = parse_block_header(a, p, &block_size,- &rar->last_block_hdr);- if(ret != ARCHIVE_OK) {- return ret;- }-- /* Skip block header. Next data is huffman tables,- * if present. */- to_skip = sizeof(struct compressed_block_header) +- bf_byte_count(&rar->last_block_hdr) + 1;-- /* If the block header's to_skip value exceeds the declared- * remaining data, the archive is malformed. */- if(to_skip > rar->file.bytes_remaining) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Block header size exceeds remaining file data");- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != consume(a, to_skip))- return ARCHIVE_EOF;-- rar->file.bytes_remaining -= to_skip;-- /* The block size gives information about the whole block size,- * but the block could be stored in split form when using- * multi-volume archives. In this case, the block size will be- * bigger than the actual data stored in this file. Remaining- * part of the data will be in another file. */-- cur_block_size =- rar5_min(rar->file.bytes_remaining, block_size);-- if(block_size > rar->file.bytes_remaining) {- /* If current blocks' size is bigger than our data- * size, this means we have a multivolume archive.- * In this case, skip all base headers until the end- * of the file, proceed to next "partXXX.rar" volume,- * find its signature, skip all headers up to the first- * FILE base header, and continue from there.- *- * Note that `merge_block` will update the `rar`- * context structure quite extensively. */-- ret = merge_block(a, block_size, &p);- if(ret != ARCHIVE_OK) {- return ret;- }-- cur_block_size = block_size;-- /* Current stream pointer should be now directly- * *after* the block that spanned through multiple- * archive files. `p` pointer should have the data of- * the *whole* block (merged from partial blocks- * stored in multiple archives files). */- } else {- rar->cstate.switch_multivolume = 0;-- /* Read the whole block size into memory. This can take- * up to 8 megabytes of memory in theoretical cases.- * Might be worth to optimize this and use a standard- * chunk of 4kb's. */- if(!read_ahead(a, 4 + cur_block_size, &p)) {- /* Failed to prefetch block data. */- return ARCHIVE_EOF;- }- }-- rar->cstate.block_buf = p;- rar->cstate.cur_block_size = cur_block_size;- rar->cstate.block_parsing_finished = 0;-- rar->bits.in_addr = 0;- rar->bits.bit_addr = 0;-- if(bf_is_table_present(&rar->last_block_hdr)) {- /* Load Huffman tables. */- ret = parse_tables(a, rar, p);- if(ret != ARCHIVE_OK) {- /* Error during decompression of Huffman- * tables. */- return ret;- }- }- } else {- /* Block parsing not finished, reuse previous memory buffer. */- p = rar->cstate.block_buf;- }-- /* Uncompress the block, or a part of it, depending on how many bytes- * will be generated by uncompressing the block.- *- * In case too many bytes will be generated, calling this function- * again will resume the uncompression operation. */- ret = do_uncompress_block(a, p);- if(ret != ARCHIVE_OK) {- return ret;- }-- if(rar->cstate.block_parsing_finished &&- rar->cstate.switch_multivolume == 0 &&- rar->cstate.cur_block_size > 0)- {- /* If we're processing a normal block, consume the whole- * block. We can do this because we've already read the whole- * block to memory. */- if(ARCHIVE_OK != consume(a, rar->cstate.cur_block_size))- return ARCHIVE_FATAL;-- rar->file.bytes_remaining -= rar->cstate.cur_block_size;- } else if(rar->cstate.switch_multivolume) {- /* Don't consume the block if we're doing multivolume- * processing. The volume switching function will consume- * the proper count of bytes instead. */- rar->cstate.switch_multivolume = 0;- }-- return ARCHIVE_OK;-}--/* Pops the `buf`, `size` and `offset` from the "data ready" stack.- *- * Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY- * when there is no data on the stack. */-static int use_data(struct rar5* rar, const void** buf, size_t* size,- int64_t* offset)-{- int i;-- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {- struct data_ready *d = &rar->cstate.dready[i];-- if(d->used) {- if(buf) *buf = d->buf;- if(size) *size = d->size;- if(offset) *offset = d->offset;-- d->used = 0;- return ARCHIVE_OK;- }- }-- return ARCHIVE_RETRY;-}--static void clear_data_ready_stack(struct rar5* rar) {- memset(&rar->cstate.dready, 0, sizeof(rar->cstate.dready));-}--/* Pushes the `buf`, `size` and `offset` arguments to the rar->cstate.dready- * FIFO stack. Those values will be popped from this stack by the `use_data`- * function. */-static int push_data_ready(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, size_t size, int64_t offset)-{- int i;-- /* Don't push if we're in skip mode. This is needed because solid- * streams need full processing even if we're skipping data. After- * fully processing the stream, we need to discard the generated bytes,- * because we're interested only in the side effect: building up the- * internal window circular buffer. This window buffer will be used- * later during unpacking of requested data. */- if(rar->skip_mode)- return ARCHIVE_OK;-- /* Sanity check. */- if(offset != rar->file.last_offset + rar->file.last_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Sanity check error: output stream is not continuous");- return ARCHIVE_FATAL;- }-- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {- struct data_ready* d = &rar->cstate.dready[i];- if(!d->used) {- d->used = 1;- d->buf = buf;- d->size = size;- d->offset = offset;-- /* These fields are used only in sanity checking. */- rar->file.last_offset = offset;- rar->file.last_size = size;-- /* Calculate the checksum of this new block before- * submitting data to libarchive's engine. */- update_crc(rar, d->buf, d->size);-- return ARCHIVE_OK;- }- }-- /* Program counter will reach this code if the `rar->cstate.data_ready`- * stack will be filled up so that no new entries will be allowed. The- * code shouldn't allow such situation to occur. So we treat this case- * as an internal error. */-- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Premature end of data_ready stack");- return ARCHIVE_FATAL;-}--/* This function uncompresses the data that is stored in the <FILE> base- * block.- *- * The FILE base block looks like this:- *- * <header><huffman tables><block_1><block_2>...<block_n>- *- * The <header> is a block header, that is parsed in parse_block_header().- * It's a "compressed_block_header" structure, containing metadata needed- * to know when we should stop looking for more <block_n> blocks.- *- * <huffman tables> contain data needed to set up the huffman tables, needed- * for the actual decompression.- *- * Each <block_n> consists of series of literals:- *- * <literal><literal><literal>...<literal>- *- * Those literals generate the uncompression data. They operate on a circular- * buffer, sometimes writing raw data into it, sometimes referencing- * some previous data inside this buffer, and sometimes declaring a filter- * that will need to be executed on the data stored in the circular buffer.- * It all depends on the literal that is used.- *- * Sometimes blocks produce output data, sometimes they don't. For example, for- * some huge files that use lots of filters, sometimes a block is filled with- * only filter declaration literals. Such blocks won't produce any data in the- * circular buffer.- *- * Sometimes blocks will produce 4 bytes of data, and sometimes 1 megabyte,- * because a literal can reference previously decompressed data. For example,- * there can be a literal that says: 'append a byte 0xFE here', and after- * it another literal can say 'append 1 megabyte of data from circular buffer- * offset 0x12345'. This is how RAR format handles compressing repeated- * patterns.- *- * The RAR compressor creates those literals and the actual efficiency of- * compression depends on what those literals are. The literals can also- * be seen as a kind of a non-turing-complete virtual machine that simply- * tells the decompressor what it should do.- * */--static int do_uncompress_file(struct archive_read* a) {- struct rar5* rar = get_context(a);- int ret;- int64_t max_end_pos;-- if(!rar->cstate.initialized) {- /* Don't perform full context reinitialization if we're- * processing a solid archive. */- if(!rar->main.solid || !rar->cstate.window_buf) {- if((ret = init_unpack(rar)) != ARCHIVE_OK)- return ret;- }-- rar->cstate.initialized = 1;- }-- /* Don't allow extraction if window_size is invalid. */- if(rar->cstate.window_size == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid window size declaration in this file");-- /* This should never happen in valid files. */- return ARCHIVE_FAILED;- }-- if(rar->cstate.all_filters_applied == 1) {- /* We use while(1) here, but standard case allows for just 1- * iteration. The loop will iterate if process_block() didn't- * generate any data at all. This can happen if the block- * contains only filter definitions (this is common in big- * files). */- while(1) {- ret = process_block(a);- if(ret != ARCHIVE_OK)- return ret;-- if(rar->cstate.last_write_ptr ==- rar->cstate.write_ptr) {- /* The block didn't generate any new data,- * so just process a new block if this one- * wasn't the last block in the file. */- if (bf_is_last_block(&rar->last_block_hdr)) {- return ARCHIVE_EOF;- }-- continue;- }-- /* The block has generated some new data, so break- * the loop. */- break;- }- }-- /* Try to run filters. If filters won't be applied, it means that- * insufficient data was generated. */- ret = apply_filters(a);- if(ret == ARCHIVE_RETRY) {- return ARCHIVE_OK;- } else if(ret != ARCHIVE_OK) {- return ret;- }-- if(cdeque_size(&rar->cstate.filters) > 0) {- /* Check if we can write something before hitting first- * filter. */- struct filter_info* flt;-- /* Get the block_start offset from the first filter. */- if(CDE_OK != cdeque_front(&rar->cstate.filters,- cdeque_filter_p(&flt)))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Can't read first filter");- return ARCHIVE_FATAL;- }-- max_end_pos = rar5_min(flt->block_start,- rar->cstate.write_ptr);- } else {- /* There are no filters defined, or all filters were applied.- * This means we can just store the data without any- * postprocessing. */- max_end_pos = rar->cstate.write_ptr;- }-- if(max_end_pos == rar->cstate.last_write_ptr) {- /* We can't write anything yet. The block uncompression- * function did not generate enough data, and no filter can be- * applied. At the same time we don't have any data that can be- * stored without filter postprocessing. This means we need to- * wait for more data to be generated, so we can apply the- * filters.- *- * Signal the caller that we need more data to be able to do- * anything.- */- return ARCHIVE_RETRY;- } else {- /* We can write the data before hitting the first filter.- * So let's do it. The push_window_data() function will- * effectively return the selected data block to the user- * application. */- push_window_data(a, rar, rar->cstate.last_write_ptr,- max_end_pos);- rar->cstate.last_write_ptr = max_end_pos;- }-- return ARCHIVE_OK;-}--static int uncompress_file(struct archive_read* a) {- int ret;-- while(1) {- /* Sometimes the uncompression function will return a- * 'retry' signal. If this will happen, we have to retry- * the function. */- ret = do_uncompress_file(a);- if(ret != ARCHIVE_RETRY)- return ret;- }-}---static int do_unstore_file(struct archive_read* a,- struct rar5* rar, const void** buf, size_t* size, int64_t* offset)-{- size_t to_read;- const uint8_t* p;-- if(rar->file.bytes_remaining == 0 && rar->main.volume > 0 &&- rar->generic.split_after > 0)- {- int ret;-- rar->cstate.switch_multivolume = 1;- ret = advance_multivolume(a);- rar->cstate.switch_multivolume = 0;-- if(ret != ARCHIVE_OK) {- /* Failed to advance to next multivolume archive- * file. */- return ret;- }- }-- to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);- if(to_read == 0) {- return ARCHIVE_EOF;- }-- if(!read_ahead(a, to_read, &p)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "I/O error when unstoring file");- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != consume(a, to_read)) {- return ARCHIVE_EOF;- }-- if(buf) *buf = p;- if(size) *size = to_read;- if(offset) *offset = rar->cstate.last_unstore_ptr;-- rar->file.bytes_remaining -= to_read;- rar->cstate.last_unstore_ptr += to_read;-- update_crc(rar, p, to_read);- return ARCHIVE_OK;-}--static int do_unpack(struct archive_read* a, struct rar5* rar,- const void** buf, size_t* size, int64_t* offset)-{- enum COMPRESSION_METHOD {- STORE = 0, FASTEST = 1, FAST = 2, NORMAL = 3, GOOD = 4,- BEST = 5- };-- if(rar->file.service > 0) {- return do_unstore_file(a, rar, buf, size, offset);- } else {- switch(rar->cstate.method) {- case STORE:- return do_unstore_file(a, rar, buf, size,- offset);- case FASTEST:- /* fallthrough */- case FAST:- /* fallthrough */- case NORMAL:- /* fallthrough */- case GOOD:- /* fallthrough */- case BEST:- /* No data is returned here. But because a sparse-file aware- * caller (like archive_read_data_into_fd) may treat zero-size- * as a sparse file block, we need to update the offset- * accordingly. At this point the decoder doesn't have any- * pending uncompressed data blocks, so the current position in- * the output file should be last_write_ptr. */- if (offset) *offset = rar->cstate.last_write_ptr;- return uncompress_file(a);- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Compression method not supported: 0x%x",- (unsigned int)rar->cstate.method);-- return ARCHIVE_FATAL;- }- }--#if !defined WIN32- /* Not reached. */- return ARCHIVE_OK;-#endif-}--static int verify_checksums(struct archive_read* a) {- int verify_crc;- struct rar5* rar = get_context(a);-- /* Check checksums only when actually unpacking the data. There's no- * need to calculate checksum when we're skipping data in solid archives- * (skipping in solid archives is the same thing as unpacking compressed- * data and discarding the result). */-- if(!rar->skip_mode) {- /* Always check checksums if we're not in skip mode */- verify_crc = 1;- } else {- /* We can override the logic above with a compile-time option- * NO_CRC_ON_SOLID_SKIP. This option is used during debugging,- * and it will check checksums of unpacked data even when- * we're skipping it. */--#if defined CHECK_CRC_ON_SOLID_SKIP- /* Debug case */- verify_crc = 1;-#else- /* Normal case */- verify_crc = 0;-#endif- }-- if(verify_crc) {- /* During unpacking, on each unpacked block we're calling the- * update_crc() function. Since we are here, the unpacking- * process is already over and we can check if calculated- * checksum (CRC32 or BLAKE2sp) is the same as what is stored- * in the archive. */- if(rar->file.stored_crc32 > 0) {- /* Check CRC32 only when the file contains a CRC32- * value for this file. */-- if(rar->file.calculated_crc32 !=- rar->file.stored_crc32) {- /* Checksums do not match; the unpacked file- * is corrupted. */-- DEBUG_CODE {- printf("Checksum error: CRC32 "- "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",- rar->file.calculated_crc32,- rar->file.stored_crc32);- }--#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Checksum error: CRC32");- return ARCHIVE_FAILED;-#endif- } else {- DEBUG_CODE {- printf("Checksum OK: CRC32 "- "(%08" PRIx32 "/%08" PRIx32 ")\n",- rar->file.stored_crc32,- rar->file.calculated_crc32);- }- }- }-- if(rar->file.has_blake2 > 0) {- /* BLAKE2sp is an optional checksum algorithm that is- * added to RARv5 archives when using the `-htb` switch- * during creation of archive.- *- * We now finalize the hash calculation by calling the- * `final` function. This will generate the final hash- * value we can use to compare it with the BLAKE2sp- * checksum that is stored in the archive.- *- * The return value of this `final` function is not- * very helpful, as it guards only against improper use.- * This is why we're explicitly ignoring it. */-- uint8_t b2_buf[32];- (void) blake2sp_final(&rar->file.b2state, b2_buf, 32);-- if(memcmp(&rar->file.blake2sp, b2_buf, 32) != 0) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Checksum error: BLAKE2");-- return ARCHIVE_FAILED;-#endif- }- }- }-- /* Finalization for this file has been successfully completed. */- return ARCHIVE_OK;-}--static int verify_global_checksums(struct archive_read* a) {- return verify_checksums(a);-}--/*- * Decryption function for the magic signature pattern. Check the comment near- * the `rar5_signature_xor` symbol to read the rationale behind this.- */-static void rar5_signature(char *buf) {- size_t i;-- for(i = 0; i < sizeof(rar5_signature_xor); i++) {- buf[i] = rar5_signature_xor[i] ^ 0xA1;- }-}--static int rar5_read_data(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset) {- int ret;- struct rar5* rar = get_context(a);-- if (size)- *size = 0;-- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- rar->has_encrypted_entries = 0;- }-- 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_FAILED;- }-- if(rar->file.dir > 0) {- /* Don't process any data if this file entry was declared- * as a directory. This is needed, because entries marked as- * directory doesn't have any dictionary buffer allocated, so- * it's impossible to perform any decompression. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't decompress an entry marked as a directory");- return ARCHIVE_FATAL;- }-- if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Unpacker has written too many bytes");- return ARCHIVE_FATAL;- }-- ret = use_data(rar, buff, size, offset);- if(ret == ARCHIVE_OK) {- return ret;- }-- if(rar->file.eof == 1) {- return ARCHIVE_EOF;- }-- ret = do_unpack(a, rar, buff, size, offset);- if(ret != ARCHIVE_OK) {- return ret;- }-- if(rar->file.bytes_remaining == 0 &&- rar->cstate.last_write_ptr == rar->file.unpacked_size)- {- /* If all bytes of current file were processed, run- * finalization.- *- * Finalization will check checksum against proper values. If- * some of the checksums will not match, we'll return an error- * value in the last `archive_read_data` call to signal an error- * to the user. */-- rar->file.eof = 1;- return verify_global_checksums(a);- }-- return ARCHIVE_OK;-}--static int rar5_read_data_skip(struct archive_read *a) {- struct rar5* rar = get_context(a);-- if(rar->main.solid && (rar->cstate.data_encrypted == 0)) {- /* In solid archives, instead of skipping the data, we need to- * extract it, and dispose the result. The side effect of this- * operation will be setting up the initial window buffer state- * needed to be able to extract the selected file. Note that- * this is only possible when data withing this solid block is- * not encrypted, in which case we'll skip and fail if the user- * tries to read data. */-- int ret;-- /* Make sure to process all blocks in the compressed stream. */- while(rar->file.bytes_remaining > 0) {- /* Setting the "skip mode" will allow us to skip- * checksum checks during data skipping. Checking the- * checksum of skipped data isn't really necessary and- * it's only slowing things down.- *- * This is incremented instead of setting to 1 because- * this data skipping function can be called- * recursively. */- rar->skip_mode++;-- /* We're disposing 1 block of data, so we use triple- * NULLs in arguments. */- ret = rar5_read_data(a, NULL, NULL, NULL);-- /* Turn off "skip mode". */- rar->skip_mode--;-- if(ret < 0 || ret == ARCHIVE_EOF) {- /* Propagate any potential error conditions- * to the caller. */- return ret;- }- }- } else {- /* In standard archives, we can just jump over the compressed- * stream. Each file in non-solid archives starts from an empty- * window buffer. */-- if(ARCHIVE_OK != consume(a, rar->file.bytes_remaining)) {- return ARCHIVE_FATAL;- }-- rar->file.bytes_remaining = 0;- }-- return ARCHIVE_OK;-}--static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,- int whence)-{- (void) a;- (void) offset;- (void) whence;-- /* We're a streaming unpacker, and we don't support seeking. */-- return ARCHIVE_FATAL;-}--static int rar5_cleanup(struct archive_read *a) {- struct rar5* rar = get_context(a);-- free(rar->cstate.window_buf);- free(rar->cstate.filtered_buf);- clear_data_ready_stack(rar);-- free(rar->vol.push_buf);-- free_filters(rar);- rar5_deinit(rar);-- free(rar);- a->format->data = NULL;-- return ARCHIVE_OK;-}--static int rar5_capabilities(struct archive_read * a) {- (void) a;- return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA- | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}--static int rar5_has_encrypted_entries(struct archive_read *_a) {- if (_a && _a->format) {- struct rar5 *rar = (struct rar5 *)_a->format->data;- if (rar) {- return rar->has_encrypted_entries;- }- }-- return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}--/* Must match deallocations in rar5_deinit */-static int rar5_init(struct rar5* rar) {- memset(rar, 0, sizeof(struct rar5));-- if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))- return ARCHIVE_FATAL;-- /*- * Until enough data has been read, we cannot tell about- * any encrypted entries yet.- */- rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-- return ARCHIVE_OK;-}--/* Must match allocations in rar5_init */-static void rar5_deinit(struct rar5* rar) {- cdeque_free(&rar->cstate.filters);-}--int archive_read_support_format_rar5(struct archive *_a) {- struct archive_read* ar;- int ret;- struct rar5* rar;-- if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))- return ret;-- rar = malloc(sizeof(*rar));- if(rar == NULL) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate rar5 data");- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != rar5_init(rar)) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate rar5 filter buffer");- free(rar);- return ARCHIVE_FATAL;- }-- ret = __archive_read_register_format(ar,- rar,- "rar5",- rar5_bid,- rar5_options,- rar5_read_header,- rar5_read_data,- rar5_read_data_skip,- rar5_seek_data,- rar5_cleanup,- rar5_capabilities,- rar5_has_encrypted_entries);-- if(ret != ARCHIVE_OK) {- rar5_deinit(rar);- free(rar);+#include "archive_integer.h"+#include "archive_ppmd7_private.h"+#include "archive_entry_private.h"+#include "archive_time_private.h"++#ifdef HAVE_BLAKE2_H+#include <blake2.h>+#else+#include "archive_blake2.h"+#endif++/*#define CHECK_CRC_ON_SOLID_SKIP*/+/*#define DONT_FAIL_ON_CRC_ERROR*/+/*#define DEBUG*/++#define rar5_min(a, b) (((a) > (b)) ? (b) : (a))+#define rar5_max(a, b) (((a) > (b)) ? (a) : (b))+#define rar5_countof(X) ((const ssize_t) (sizeof(X) / sizeof(*X)))++#if defined DEBUG+#define DEBUG_CODE if(1)+#define LOG(...) do { printf("rar5: " __VA_ARGS__); puts(""); } while(0)+#else+#define DEBUG_CODE if(0)+#endif++/* Real RAR5 magic number is:+ *+ * 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00+ * "Rar!→•☺·\x00"+ *+ * Retrieved with `rar5_signature()` by XOR'ing it with 0xA1, because I don't+ * want to put this magic sequence in each binary that uses libarchive, so+ * applications that scan through the file for this marker won't trigger on+ * this "false" one.+ *+ * The array itself is decrypted in `rar5_init` function. */++static const unsigned char rar5_signature_xor[] = {+ 243, 192, 211, 128, 187, 166, 160, 161+};+static const size_t g_unpack_window_size = 0x20000;++/* These could have been static const's, but they aren't, because of+ * Visual Studio. */+#define MAX_NAME_IN_CHARS 2048+#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)++struct file_header {+ ssize_t bytes_remaining;+ ssize_t unpacked_size;+ int64_t last_offset; /* Used in sanity checks. */+ int64_t last_size; /* Used in sanity checks. */++ uint8_t solid : 1; /* Is this a solid stream? */+ uint8_t service : 1; /* Is this file a service data? */+ uint8_t eof : 1; /* Did we finish unpacking the file? */+ uint8_t dir : 1; /* Is this file entry a directory? */++ /* Optional time fields. */+ int64_t e_mtime;+ int64_t e_ctime;+ int64_t e_atime;+ uint32_t e_mtime_ns;+ uint32_t e_ctime_ns;+ uint32_t e_atime_ns;++ /* Optional hash fields. */+ uint32_t stored_crc32;+ uint32_t calculated_crc32;+ uint8_t blake2sp[32];+ blake2sp_state b2state;+ char has_blake2;++ /* Optional redir fields */+ uint64_t redir_type;+ uint64_t redir_flags;++ ssize_t solid_window_size; /* Used in file format check. */+};++enum EXTRA {+ EX_CRYPT = 0x01,+ EX_HASH = 0x02,+ EX_HTIME = 0x03,+ EX_VERSION = 0x04,+ EX_REDIR = 0x05,+ EX_UOWNER = 0x06,+ EX_SUBDATA = 0x07+};++#define REDIR_SYMLINK_IS_DIR 1++enum REDIR_TYPE {+ REDIR_TYPE_NONE = 0,+ REDIR_TYPE_UNIXSYMLINK = 1,+ REDIR_TYPE_WINSYMLINK = 2,+ REDIR_TYPE_JUNCTION = 3,+ REDIR_TYPE_HARDLINK = 4,+ REDIR_TYPE_FILECOPY = 5,+};++#define OWNER_USER_NAME 0x01+#define OWNER_GROUP_NAME 0x02+#define OWNER_USER_UID 0x04+#define OWNER_GROUP_GID 0x08+#define OWNER_MAXNAMELEN 256++enum FILTER_TYPE {+ FILTER_DELTA = 0, /* Generic pattern. */+ FILTER_E8 = 1, /* Intel x86 code. */+ FILTER_E8E9 = 2, /* Intel x86 code. */+ FILTER_ARM = 3, /* ARM code. */+ FILTER_AUDIO = 4, /* Audio filter, not used in RARv5. */+ FILTER_RGB = 5, /* Color palette, not used in RARv5. */+ FILTER_ITANIUM = 6, /* Intel's Itanium, not used in RARv5. */+ FILTER_PPM = 7, /* Predictive pattern matching, not used in+ RARv5. */+ FILTER_NONE = 8,+};++struct filter_info {+ int type;+ int channels;++ int64_t block_start;+ ssize_t block_length;+};++struct data_ready {+ char used;+ const uint8_t* buf;+ size_t size;+ int64_t offset;+};++struct cdeque {+ uint16_t beg_pos;+ uint16_t end_pos;+ uint16_t cap_mask;+ uint16_t size;+ size_t* arr;+};++struct decode_table {+ uint32_t size;+ int32_t decode_len[16];+ uint32_t decode_pos[16];+ uint32_t quick_bits;+ uint8_t quick_len[1 << 10];+ uint16_t quick_num[1 << 10];+ uint16_t decode_num[306];+};++struct comp_state {+ /* Flag used to specify if unpacker needs to reinitialize the+ uncompression context. */+ uint8_t initialized : 1;++ /* Flag used when applying filters. */+ uint8_t all_filters_applied : 1;++ /* Flag used to skip file context reinitialization, used when unpacker+ is skipping through different multivolume archives. */+ uint8_t switch_multivolume : 1;++ /* Flag used to specify if unpacker has processed the whole data block+ or just a part of it. */+ uint8_t block_parsing_finished : 1;++ /* Flag used to indicate that a previous file using this buffer was+ encrypted, meaning no data in the buffer can be trusted */+ uint8_t data_encrypted : 1;++ signed int notused : 3;++ int flags; /* Uncompression flags. */+ int method; /* Uncompression algorithm method. */+ int version; /* Uncompression algorithm version. */+ ssize_t window_size; /* Size of window_buf. */+ uint8_t* window_buf; /* Circular buffer used during+ decompression. */+ uint8_t* filtered_buf; /* Buffer used when applying filters. */+ const uint8_t* block_buf; /* Buffer used when merging blocks. */+ ssize_t window_mask; /* Convenience field; window_size - 1. */+ int64_t write_ptr; /* This amount of data has been unpacked+ in the window buffer. */+ int64_t last_write_ptr; /* This amount of data has been stored in+ the output file. */+ int64_t last_unstore_ptr; /* Counter of bytes extracted during+ unstoring. This is separate from+ last_write_ptr because of how SERVICE+ base blocks are handled during skipping+ in solid multiarchive archives. */+ int64_t solid_offset; /* Additional offset inside the window+ buffer, used in unpacking solid+ archives. */+ ssize_t cur_block_size; /* Size of current data block. */+ int last_len; /* Flag used in lzss decompression. */++ /* Decode tables used during lzss uncompression. */++#define HUFF_BC 20+ struct decode_table bd; /* huffman bit lengths */+#define HUFF_NC 306+ struct decode_table ld; /* literals */+#define HUFF_DC 64+ struct decode_table dd; /* distances */+#define HUFF_LDC 16+ struct decode_table ldd; /* lower bits of distances */+#define HUFF_RC 44+ struct decode_table rd; /* repeating distances */+#define HUFF_TABLE_SIZE (HUFF_NC + HUFF_DC + HUFF_RC + HUFF_LDC)++ /* Circular deque for storing filters. */+ struct cdeque filters;+ int64_t last_block_start; /* Used for sanity checking. */+ ssize_t last_block_length; /* Used for sanity checking. */++ /* Distance cache used during lzss uncompression. */+ int dist_cache[4];++ /* Data buffer stack. */+ struct data_ready dready[2];+};++/* Bit reader state. */+struct bit_reader {+ int8_t bit_addr; /* Current bit pointer inside current byte. */+ int in_addr; /* Current byte pointer. */+};++/* RARv5 block header structure. Use bf_* functions to get values from+ * block_flags_u8 field. I.e. bf_byte_count, etc. */+struct compressed_block_header {+ /* block_flags_u8 contain fields encoded in little-endian bitfield:+ *+ * - table present flag (shr 7, and 1),+ * - last block flag (shr 6, and 1),+ * - byte_count (shr 3, and 7),+ * - bit_size (shr 0, and 7).+ */+ uint8_t block_flags_u8;+ uint8_t block_cksum;+};++/* RARv5 main header structure. */+struct main_header {+ /* Does the archive contain solid streams? */+ uint8_t solid : 1;++ /* If this a multi-file archive? */+ uint8_t volume : 1;+ uint8_t endarc : 1;+ uint8_t notused : 5;++ unsigned int vol_no;+};++struct generic_header {+ uint8_t split_after : 1;+ uint8_t split_before : 1;+ uint8_t padding : 6;+ int size;+ int last_header_id;+};++struct multivolume {+ unsigned int expected_vol_no;+ uint8_t* push_buf;+};++/* Main context structure. */+struct rar5 {+ int header_initialized;++ /* Set to 1 if current file is positioned AFTER the magic value+ * of the archive file. This is used in header reading functions. */+ int skipped_magic;++ /* Set to not zero if we're in skip mode (either by calling+ * rar5_data_skip function or when skipping over solid streams).+ * Set to 0 when in * extraction mode. This is used during checksum+ * calculation functions. */+ int skip_mode;++ /* Set to not zero if we're in block merging mode (i.e. when switching+ * to another file in multivolume archive, last block from 1st archive+ * needs to be merged with 1st block from 2nd archive). This flag+ * guards against recursive use of the merging function, which doesn't+ * support recursive calls. */+ int merge_mode;++ /* An offset to QuickOpen list. This is not supported by this unpacker,+ * because we're focusing on streaming interface. QuickOpen is designed+ * to make things quicker for non-stream interfaces, so it's not our+ * use case. */+ uint64_t qlist_offset;++ /* An offset to additional Recovery data. This is not supported by this+ * unpacker. Recovery data are additional Reed-Solomon codes that could+ * be used to calculate bytes that are missing in archive or are+ * corrupted. */+ uint64_t rr_offset;++ /* Various context variables grouped to different structures. */+ struct generic_header generic;+ struct main_header main;+ struct comp_state cstate;+ struct file_header file;+ struct bit_reader bits;+ struct multivolume vol;++ /* The header of currently processed RARv5 block. Used in main+ * decompression logic loop. */+ struct compressed_block_header last_block_hdr;++ /*+ * Custom field to denote that this archive contains encrypted entries+ */+ int has_encrypted_entries;+ int headers_are_encrypted;+};++/* Forward function declarations. */++static void rar5_signature(char *buf);+static int verify_global_checksums(struct archive_read* a);+static int rar5_read_data_skip(struct archive_read *a);+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* buf, size_t size, int64_t offset);+static void clear_data_ready_stack(struct rar5 *rar5);+static void rar5_deinit(struct rar5 *rar5);++/* CDE_xxx = Circular Double Ended (Queue) return values. */+enum CDE_RETURN_VALUES {+ CDE_OK, CDE_ALLOC, CDE_PARAM, CDE_OUT_OF_BOUNDS,+};++/* Clears the contents of this circular deque. */+static void cdeque_clear(struct cdeque* d) {+ d->size = 0;+ d->beg_pos = 0;+ d->end_pos = 0;+}++/* Creates a new circular deque object. Capacity must be power of 2: 8, 16, 32,+ * 64, 256, etc. When the user will add another item above current capacity,+ * the circular deque will overwrite the oldest entry. */+static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {+ if(d == NULL || max_capacity_power_of_2 == 0)+ return CDE_PARAM;++ d->cap_mask = max_capacity_power_of_2 - 1;+ d->arr = NULL;++ if((max_capacity_power_of_2 & d->cap_mask) != 0)+ return CDE_PARAM;++ cdeque_clear(d);+ d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);++ return d->arr ? CDE_OK : CDE_ALLOC;+}++/* Return the current size (not capacity) of circular deque `d`. */+static size_t cdeque_size(struct cdeque* d) {+ return d->size;+}++/* Returns the first element of current circular deque. Note that this function+ * doesn't perform any bounds checking. If you need bounds checking, use+ * `cdeque_front()` function instead. */+static void cdeque_front_fast(struct cdeque* d, void** value) {+ *value = (void*) d->arr[d->beg_pos];+}++/* Returns the first element of current circular deque. This function+ * performs bounds checking. */+static int cdeque_front(struct cdeque* d, void** value) {+ if(d->size > 0) {+ cdeque_front_fast(d, value);+ return CDE_OK;+ } else+ return CDE_OUT_OF_BOUNDS;+}++/* Pushes a new element into the end of this circular deque object. */+static int cdeque_push_back(struct cdeque* d, void* item) {+ if(d == NULL)+ return CDE_PARAM;++ if(d->size == d->cap_mask + 1)+ return CDE_OUT_OF_BOUNDS;++ d->arr[d->end_pos] = (size_t) item;+ d->end_pos = (d->end_pos + 1) & d->cap_mask;+ d->size++;++ return CDE_OK;+}++/* Pops a front element of this circular deque object and returns its value.+ * This function doesn't perform any bounds checking. */+static void cdeque_pop_front_fast(struct cdeque* d, void** value) {+ *value = (void*) d->arr[d->beg_pos];+ d->beg_pos = (d->beg_pos + 1) & d->cap_mask;+ d->size--;+}++/* Pops a front element of this circular deque object and returns its value.+ * This function performs bounds checking. */+static int cdeque_pop_front(struct cdeque* d, void** value) {+ if(!d || !value)+ return CDE_PARAM;++ if(d->size == 0)+ return CDE_OUT_OF_BOUNDS;++ cdeque_pop_front_fast(d, value);+ return CDE_OK;+}++/* Convenience function to cast filter_info** to void **. */+static void** cdeque_filter_p(struct filter_info** f) {+ return (void**) (size_t) f;+}++/* Convenience function to cast filter_info* to void *. */+static void* cdeque_filter(struct filter_info* f) {+ return (void**) (size_t) f;+}++/* Destroys this circular deque object. Deallocates the memory of the+ * collection buffer, but doesn't deallocate the memory of any pointer passed+ * to this deque as a value. */+static void cdeque_free(struct cdeque* d) {+ if(!d)+ return;++ if(!d->arr)+ return;++ free(d->arr);++ d->arr = NULL;+ d->beg_pos = -1;+ d->end_pos = -1;+ d->cap_mask = 0;+}++static inline+uint8_t bf_bit_size(const struct compressed_block_header* hdr) {+ return hdr->block_flags_u8 & 7;+}++static inline+uint8_t bf_byte_count(const struct compressed_block_header* hdr) {+ return (hdr->block_flags_u8 >> 3) & 7;+}++static inline+uint8_t bf_is_table_present(const struct compressed_block_header* hdr) {+ return (hdr->block_flags_u8 >> 7) & 1;+}++static inline+uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {+ return (hdr->block_flags_u8 >> 6) & 1;+}++/* Convenience functions used by filter implementations. */+static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,+ int64_t start, int64_t end)+{+ if((start & mask) > (end & mask)) {+ ssize_t len1 = mask + 1 - (start & mask);+ ssize_t len2 = end & mask;++ memcpy(dst, &window[start & mask], len1);+ memcpy(dst + len1, window, len2);+ } else {+ memcpy(dst, &window[start & mask], (size_t) (end - start));+ }+}++static uint32_t read_filter_data(struct rar5 *rar5, uint32_t offset) {+ uint8_t linear_buf[4];+ circular_memcpy(linear_buf, rar5->cstate.window_buf,+ rar5->cstate.window_mask, offset, offset + 4);+ return archive_le32dec(linear_buf);+}++static void write_filter_data(struct rar5 *rar5, uint32_t offset,+ uint32_t value)+{+ archive_le32enc(&rar5->cstate.filtered_buf[offset], value);+}++/* Allocates a new filter descriptor and adds it to the filter array. */+static struct filter_info* add_new_filter(struct rar5 *rar5) {+ struct filter_info* f = calloc(1, sizeof(*f));++ if(!f) {+ return NULL;+ }++ if (CDE_OK != cdeque_push_back(&rar5->cstate.filters, cdeque_filter(f))) {+ free(f);+ return NULL;+ }++ return f;+}++static int run_delta_filter(struct rar5 *rar5, struct filter_info* flt) {+ int i;+ ssize_t dest_pos, src_pos = 0;++ for(i = 0; i < flt->channels; i++) {+ uint8_t prev_byte = 0;+ for(dest_pos = i;+ dest_pos < flt->block_length;+ dest_pos += flt->channels)+ {+ uint8_t byte;++ byte = rar5->cstate.window_buf[+ (rar5->cstate.solid_offset + flt->block_start ++ src_pos) & rar5->cstate.window_mask];++ prev_byte -= byte;+ rar5->cstate.filtered_buf[dest_pos] = prev_byte;+ src_pos++;+ }+ }++ return ARCHIVE_OK;+}++static int run_e8e9_filter(struct rar5 *rar5, struct filter_info* flt,+ int extended)+{+ const uint32_t file_size = 0x1000000;+ ssize_t i;++ circular_memcpy(rar5->cstate.filtered_buf,+ rar5->cstate.window_buf, rar5->cstate.window_mask,+ rar5->cstate.solid_offset + flt->block_start,+ rar5->cstate.solid_offset + flt->block_start + flt->block_length);++ for(i = 0; i < flt->block_length - 4;) {+ uint8_t b = rar5->cstate.window_buf[+ (rar5->cstate.solid_offset + flt->block_start ++ i++) & rar5->cstate.window_mask];++ /*+ * 0xE8 = x86's call <relative_addr_uint32> (function call)+ * 0xE9 = x86's jmp <relative_addr_uint32> (unconditional jump)+ */+ if(b == 0xE8 || (extended && b == 0xE9)) {++ uint32_t addr;+ uint32_t offset = (i + flt->block_start) % file_size;++ addr = read_filter_data(rar5,+ (uint32_t)(rar5->cstate.solid_offset ++ flt->block_start + i) & rar5->cstate.window_mask);++ if(addr & 0x80000000) {+ if(((addr + offset) & 0x80000000) == 0) {+ write_filter_data(rar5, (uint32_t)i,+ addr + file_size);+ }+ } else {+ if((addr - file_size) & 0x80000000) {+ uint32_t naddr = addr - offset;+ write_filter_data(rar5, (uint32_t)i,+ naddr);+ }+ }++ i += 4;+ }+ }++ return ARCHIVE_OK;+}++static int run_arm_filter(struct rar5 *rar5, struct filter_info* flt) {+ ssize_t i = 0;+ uint32_t offset;++ circular_memcpy(rar5->cstate.filtered_buf,+ rar5->cstate.window_buf, rar5->cstate.window_mask,+ rar5->cstate.solid_offset + flt->block_start,+ rar5->cstate.solid_offset + flt->block_start + flt->block_length);++ for(i = 0; i < flt->block_length - 3; i += 4) {+ uint8_t* b = &rar5->cstate.window_buf[+ (rar5->cstate.solid_offset ++ flt->block_start + i + 3) & rar5->cstate.window_mask];++ if(*b == 0xEB) {+ /* 0xEB = ARM's BL (branch + link) instruction. */+ offset = read_filter_data(rar5,+ (rar5->cstate.solid_offset + flt->block_start + i) &+ (uint32_t)rar5->cstate.window_mask) & 0x00ffffff;++ offset -= (uint32_t) ((i + flt->block_start) / 4);+ offset = (offset & 0x00ffffff) | 0xeb000000;+ write_filter_data(rar5, (uint32_t)i, offset);+ }+ }++ return ARCHIVE_OK;+}++static int run_filter(struct archive_read* a, struct filter_info* flt) {+ struct rar5 *rar5 = a->format->data;+ int ret;++ clear_data_ready_stack(rar5);+ free(rar5->cstate.filtered_buf);++ rar5->cstate.filtered_buf = malloc(flt->block_length);+ if(!rar5->cstate.filtered_buf) {+ archive_set_error(&a->archive, ENOMEM,+ "Can't allocate memory for filter data");+ return ARCHIVE_FATAL;+ }++ switch(flt->type) {+ case FILTER_DELTA:+ ret = run_delta_filter(rar5, flt);+ break;++ case FILTER_E8:+ /* fallthrough */+ case FILTER_E8E9:+ ret = run_e8e9_filter(rar5, flt,+ flt->type == FILTER_E8E9);+ break;++ case FILTER_ARM:+ ret = run_arm_filter(rar5, flt);+ break;++ default:+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Unsupported filter type: 0x%x",+ (unsigned int)flt->type);+ return ARCHIVE_FAILED;+ }++ if(ret != ARCHIVE_OK) {+ /* Filter has failed. */+ return ret;+ }++ if(ARCHIVE_OK != push_data_ready(a, rar5, rar5->cstate.filtered_buf,+ flt->block_length, rar5->cstate.last_write_ptr))+ {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Stack overflow when submitting unpacked data");++ return ARCHIVE_FATAL;+ }++ rar5->cstate.last_write_ptr += flt->block_length;+ return ARCHIVE_OK;+}++/* The `push_data` function submits the selected data range to the user.+ * Next call of `use_data` will use the pointer, size and offset arguments+ * that are specified here. These arguments are pushed to the FIFO stack here,+ * and popped from the stack by the `use_data` function. */+static void push_data(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* buf, int64_t idx_begin, int64_t idx_end)+{+ const ssize_t wmask = rar5->cstate.window_mask;+ const ssize_t solid_write_ptr = (rar5->cstate.solid_offset ++ rar5->cstate.last_write_ptr) & wmask;++ idx_begin += rar5->cstate.solid_offset;+ idx_end += rar5->cstate.solid_offset;++ /* Check if our unpacked data is wrapped inside the window circular+ * buffer. If it's not wrapped, it can be copied out by using+ * a single memcpy, but when it's wrapped, we need to copy the first+ * part with one memcpy, and the second part with another memcpy. */++ if((idx_begin & wmask) > (idx_end & wmask)) {+ /* The data is wrapped (begin offset sis bigger than end+ * offset). */+ const ssize_t frag1_size = rar5->cstate.window_size -+ (idx_begin & wmask);+ const ssize_t frag2_size = idx_end & wmask;++ /* Copy the first part of the buffer first. */+ push_data_ready(a, rar5, buf + solid_write_ptr, frag1_size,+ rar5->cstate.last_write_ptr);++ /* Copy the second part of the buffer. */+ push_data_ready(a, rar5, buf, frag2_size,+ rar5->cstate.last_write_ptr + frag1_size);++ rar5->cstate.last_write_ptr += frag1_size + frag2_size;+ } else {+ /* Data is not wrapped, so we can just use one call to copy the+ * data. */+ push_data_ready(a, rar5,+ buf + solid_write_ptr, (idx_end - idx_begin) & wmask,+ rar5->cstate.last_write_ptr);++ rar5->cstate.last_write_ptr += idx_end - idx_begin;+ }+}++/* Convenience function that submits the data to the user. It uses the+ * unpack window buffer as a source location. */+static void push_window_data(struct archive_read* a, struct rar5 *rar5,+ int64_t idx_begin, int64_t idx_end)+{+ push_data(a, rar5, rar5->cstate.window_buf, idx_begin, idx_end);+}++static int apply_filters(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ struct filter_info* flt;+ int ret;++ rar5->cstate.all_filters_applied = 0;++ /* Get the first filter that can be applied to our data. The data+ * needs to be fully unpacked before the filter can be run. */+ if(CDE_OK == cdeque_front(&rar5->cstate.filters,+ cdeque_filter_p(&flt))) {+ /* Check if our unpacked data fully covers this filter's+ * range. */+ if(rar5->cstate.write_ptr > flt->block_start &&+ rar5->cstate.write_ptr >= flt->block_start ++ flt->block_length) {+ /* Check if we have some data pending to be written+ * right before the filter's start offset. */+ if(rar5->cstate.last_write_ptr == flt->block_start) {+ /* Run the filter specified by descriptor+ * `flt`. */+ ret = run_filter(a, flt);+ if(ret != ARCHIVE_OK) {+ /* Filter failure, return error. */+ return ret;+ }++ /* Filter descriptor won't be needed anymore+ * after it's used, * so remove it from the+ * filter list and free its memory. */+ (void) cdeque_pop_front(&rar5->cstate.filters,+ cdeque_filter_p(&flt));++ free(flt);+ } else {+ /* We can't run filters yet, dump the memory+ * right before the filter. */+ push_window_data(a, rar5,+ rar5->cstate.last_write_ptr,+ flt->block_start);+ }++ /* Return 'filter applied or not needed' state to the+ * caller. */+ return ARCHIVE_RETRY;+ }+ }++ rar5->cstate.all_filters_applied = 1;+ return ARCHIVE_OK;+}++static void dist_cache_push(struct rar5 *rar5, int value) {+ int* q = rar5->cstate.dist_cache;++ q[3] = q[2];+ q[2] = q[1];+ q[1] = q[0];+ q[0] = value;+}++static int dist_cache_touch(struct rar5 *rar5, int idx) {+ int* q = rar5->cstate.dist_cache;+ int i, dist = q[idx];++ for(i = idx; i > 0; i--)+ q[i] = q[i - 1];++ q[0] = dist;+ return dist;+}++static void free_filters(struct rar5 *rar5) {+ struct cdeque* d = &rar5->cstate.filters;++ /* Free any remaining filters. All filters should be naturally+ * consumed by the unpacking function, so remaining filters after+ * unpacking normally mean that unpacking wasn't successful.+ * But still of course we shouldn't leak memory in such case. */++ /* cdeque_size() is a fast operation, so we can use it as a loop+ * expression. */+ while(cdeque_size(d) > 0) {+ struct filter_info* f = NULL;++ /* Pop_front will also decrease the collection's size. */+ if (CDE_OK == cdeque_pop_front(d, cdeque_filter_p(&f)))+ free(f);+ }++ cdeque_clear(d);++ /* Also clear out the variables needed for sanity checking. */+ rar5->cstate.last_block_start = 0;+ rar5->cstate.last_block_length = 0;+}++static void reset_file_context(struct rar5 *rar5) {+ memset(&rar5->file, 0, sizeof(rar5->file));+ blake2sp_init(&rar5->file.b2state, 32);++ if(rar5->main.solid) {+ rar5->cstate.solid_offset += rar5->cstate.write_ptr;+ } else {+ rar5->cstate.solid_offset = 0;+ }++ rar5->cstate.write_ptr = 0;+ rar5->cstate.last_write_ptr = 0;+ rar5->cstate.last_unstore_ptr = 0;++ rar5->file.redir_type = REDIR_TYPE_NONE;+ rar5->file.redir_flags = 0;++ free_filters(rar5);+}++static inline int get_archive_read(struct archive* a,+ struct archive_read** ar)+{+ *ar = (struct archive_read*) a;+ archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,+ "archive_read_support_format_rar5");++ return ARCHIVE_OK;+}++static int read_ahead(struct archive_read* a, size_t how_many,+ const uint8_t** ptr)+{+ if(!ptr)+ return 0;++ *ptr = __archive_read_ahead(a, how_many, NULL);+ if(*ptr == NULL) {+ return 0;+ }++ return 1;+}++static int consume(struct archive_read* a, int64_t how_many) {+ int ret;++ ret = how_many == __archive_read_consume(a, how_many)+ ? ARCHIVE_OK+ : ARCHIVE_FATAL;++ return ret;+}++/**+ * Read a RAR5 variable sized numeric value. This value will be stored in+ * `pvalue`. The `pvalue_len` argument points to a variable that will receive+ * the byte count that was consumed in order to decode the `pvalue` value, plus+ * one.+ *+ * pvalue_len is optional and can be NULL.+ *+ * NOTE: if `pvalue_len` is NOT NULL, the caller needs to manually consume+ * the number of bytes that `pvalue_len` value contains. If the `pvalue_len`+ * is NULL, this consuming operation is done automatically.+ *+ * Returns 1 if *pvalue was successfully read.+ * Returns 0 if there was an error. In this case, *pvalue contains an+ * invalid value.+ */++static int read_var(struct archive_read* a, uint64_t* pvalue,+ uint64_t* pvalue_len)+{+ uint64_t multiplier;+ uint64_t result = 0;+ size_t i;+ const uint8_t* p;++ /* We will read maximum of 10 bytes. We don't have to handle the+ * situation to read the RAR5 variable-sized value stored at the end of+ * the file, because such situation will never happen. */+ if(!read_ahead(a, 10, &p))+ return 0;++ for(multiplier = 1, i = 0; i < 10; i++, multiplier *= 128) {+ uint64_t val;+ uint8_t b;++ b = p[i];++ /* Strip the MSB from the input byte and add the resulting+ * number to the `result`. */+ if(archive_ckd_mul_u64(&val, b & 0x7F, multiplier) ||+ archive_ckd_add_u64(&result, result, val)) {+ /* Integer overflow occurred. */+ return 0;+ }++ /* MSB set to 1 means we need to continue decoding process.+ * MSB set to 0 means we're done.+ *+ * This conditional checks for the second case. */+ if((b & 0x80) == 0) {+ if(pvalue) {+ *pvalue = result;+ }++ /* If the caller has passed the `pvalue_len` pointer,+ * store the number of consumed bytes in it and do NOT+ * consume those bytes, since the caller has all the+ * information it needs to perform */+ if(pvalue_len) {+ *pvalue_len = 1 + i;+ } else {+ /* If the caller did not provide the+ * `pvalue_len` pointer, it will not have the+ * possibility to advance the file pointer,+ * because it will not know how many bytes it+ * needs to consume. This is why we handle+ * such situation here automatically. */+ if(ARCHIVE_OK != consume(a, 1 + i)) {+ return 0;+ }+ }++ /* End of decoding process, return success. */+ return 1;+ }+ }++ /* All continuation bits were set. This is an error. */+ return 0;+}++static int read_var_sized(struct archive_read* a, size_t* pvalue,+ size_t* pvalue_len)+{+ uint64_t v;+ uint64_t v_size = 0;++ const int ret = pvalue_len ? read_var(a, &v, &v_size)+ : read_var(a, &v, NULL);++ if(ret == 1 && pvalue) {+ *pvalue = (size_t) v;+ }++ if(pvalue_len) {+ /* Possible data truncation should be safe. */+ *pvalue_len = (size_t) v_size;+ }++ return ret;+}++static int read_bits_32(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p, uint32_t* value)+{+ if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Premature end of stream during extraction of data (#1)");+ return ARCHIVE_FATAL;+ }++ uint32_t bits = archive_be32dec(p + rar5->bits.in_addr);+ bits <<= rar5->bits.bit_addr;+ bits |= p[rar5->bits.in_addr + 4] >> (8 - rar5->bits.bit_addr);+ *value = bits;+ return ARCHIVE_OK;+}++static int read_bits_16(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p, uint16_t* value)+{+ if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Premature end of stream during extraction of data (#2)");+ return ARCHIVE_FATAL;+ }++ uint32_t bits = archive_be24dec(p + (unsigned)rar5->bits.in_addr);+ bits >>= (8 - rar5->bits.bit_addr);+ *value = bits & 0xffff;+ return ARCHIVE_OK;+}++static void skip_bits(struct rar5 *rar5, int bits) {+ const int new_bits = rar5->bits.bit_addr + bits;+ rar5->bits.in_addr += new_bits >> 3;+ rar5->bits.bit_addr = new_bits & 7;+}++/* n = up to 16 */+static int read_consume_bits(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p, int n, int* value)+{+ uint16_t v;+ int ret, num;++ if(n == 0 || n > 16) {+ /* This is a programmer error and should never happen+ * in runtime. */+ return ARCHIVE_FATAL;+ }++ ret = read_bits_16(a, rar5, p, &v);+ if(ret != ARCHIVE_OK)+ return ret;++ num = (int) v;+ num >>= 16 - n;++ skip_bits(rar5, n);++ if(value)+ *value = num;++ return ARCHIVE_OK;+}++static char read_u32(struct archive_read* a, uint32_t* pvalue) {+ const uint8_t* p;+ if(!read_ahead(a, 4, &p))+ return 0;++ *pvalue = archive_le32dec(p);+ return ARCHIVE_OK == consume(a, 4);+}++static char read_u64(struct archive_read* a, uint64_t* pvalue) {+ const uint8_t* p;+ if(!read_ahead(a, 8, &p))+ return 0;++ *pvalue = archive_le64dec(p);+ return ARCHIVE_OK == consume(a, 8);+}++static int bid_standard(struct archive_read* a) {+ const uint8_t* p;+ char signature[sizeof(rar5_signature_xor)];++ rar5_signature(signature);++ if(!read_ahead(a, sizeof(rar5_signature_xor), &p))+ return -1;++ if(!memcmp(signature, p, sizeof(rar5_signature_xor)))+ return 30;++ return -1;+}++static int bid_sfx(struct archive_read *a)+{+ const char *p;++ if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)+ return -1;++ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {+ /* This is a PE file */+ char signature[sizeof(rar5_signature_xor)];+ ssize_t offset = 0x10000;+ ssize_t window = 4096;+ ssize_t bytes_avail;++ rar5_signature(signature);++ while (offset + window <= (1024 * 512)) {+ const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);+ if (buff == NULL) {+ /* Remaining bytes are less than window. */+ window >>= 1;+ if (window < 0x40)+ return 0;+ continue;+ }+ p = buff + offset;+ while (p + 8 < buff + bytes_avail) {+ if (memcmp(p, signature, sizeof(signature)) == 0)+ return 30;+ p += 0x10;+ }+ offset = p - buff;+ }+ }++ return 0;+}++static int rar5_bid(struct archive_read* a, int best_bid) {+ int my_bid;++ if(best_bid > 30)+ return -1;++ my_bid = bid_standard(a);+ if(my_bid > -1) {+ return my_bid;+ }+ my_bid = bid_sfx(a);+ if (my_bid > -1) {+ return my_bid;+ }++ return -1;+}++static int rar5_options(struct archive_read *a, const char *key,+ const char *val) {+ (void) a;+ (void) key;+ (void) val;++ /* No options supported in this version. Return the ARCHIVE_WARN code+ * to signal the options supervisor that the unpacker didn't handle+ * setting this option. */++ return ARCHIVE_WARN;+}++static void init_header(struct archive_read* a) {+ a->archive.archive_format = ARCHIVE_FORMAT_RAR_V5;+ a->archive.archive_format_name = "RAR5";+}++static void init_window_mask(struct rar5 *rar5) {+ if (rar5->cstate.window_size)+ rar5->cstate.window_mask = rar5->cstate.window_size - 1;+ else+ rar5->cstate.window_mask = 0;+}++enum HEADER_FLAGS {+ HFL_EXTRA_DATA = 0x0001,+ HFL_DATA = 0x0002,+ HFL_SKIP_IF_UNKNOWN = 0x0004,+ HFL_SPLIT_BEFORE = 0x0008,+ HFL_SPLIT_AFTER = 0x0010,+ HFL_CHILD = 0x0020,+ HFL_INHERITED = 0x0040+};++static int process_main_locator_extra_block(struct archive_read* a,+ struct rar5 *rar5)+{+ uint64_t locator_flags;++ enum LOCATOR_FLAGS {+ QLIST = 0x01, RECOVERY = 0x02,+ };++ if(!read_var(a, &locator_flags, NULL)) {+ return ARCHIVE_EOF;+ }++ if(locator_flags & QLIST) {+ if(!read_var(a, &rar5->qlist_offset, NULL)) {+ return ARCHIVE_EOF;+ }++ /* qlist is not used */+ }++ if(locator_flags & RECOVERY) {+ if(!read_var(a, &rar5->rr_offset, NULL)) {+ return ARCHIVE_EOF;+ }++ /* rr is not used */+ }++ return ARCHIVE_OK;+}++static int parse_file_extra_hash(struct archive_read* a, struct rar5 *rar5,+ int64_t* extra_data_size)+{+ size_t hash_type = 0;+ size_t value_len;++ enum HASH_TYPE {+ BLAKE2sp = 0x00+ };++ if(!read_var_sized(a, &hash_type, &value_len))+ return ARCHIVE_EOF;++ *extra_data_size -= value_len;+ if(ARCHIVE_OK != consume(a, value_len)) {+ return ARCHIVE_EOF;+ }++ /* The file uses BLAKE2sp checksum algorithm instead of plain old+ * CRC32. */+ if(hash_type == BLAKE2sp) {+ const uint8_t* p;+ const int hash_size = sizeof(rar5->file.blake2sp);++ if(!read_ahead(a, hash_size, &p))+ return ARCHIVE_EOF;++ rar5->file.has_blake2 = 1;+ memcpy(&rar5->file.blake2sp, p, hash_size);++ if(ARCHIVE_OK != consume(a, hash_size)) {+ return ARCHIVE_EOF;+ }++ *extra_data_size -= hash_size;+ } else {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Unsupported hash type (0x%jx)", (uintmax_t)hash_type);+ return ARCHIVE_FATAL;+ }++ return ARCHIVE_OK;+}++static int parse_htime_item(struct archive_read* a, char unix_time,+ int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)+{+ if(unix_time) {+ uint32_t time_val;+ if(!read_u32(a, &time_val))+ return ARCHIVE_EOF;++ *extra_data_size -= 4;+ *sec = (int64_t) time_val;+ } else {+ uint64_t windows_time;+ if(!read_u64(a, &windows_time))+ return ARCHIVE_EOF;++ ntfs_to_unix(windows_time, sec, nsec);+ *extra_data_size -= 8;+ }++ return ARCHIVE_OK;+}++static int parse_file_extra_version(struct archive_read* a,+ struct archive_entry* e, int64_t* extra_data_size)+{+ size_t flags = 0;+ size_t version = 0;+ size_t value_len = 0;+ struct archive_string version_string;+ struct archive_string name_utf8_string;+ const char* cur_filename;++ /* Flags are ignored. */+ if(!read_var_sized(a, &flags, &value_len))+ return ARCHIVE_EOF;++ *extra_data_size -= value_len;+ if(ARCHIVE_OK != consume(a, value_len))+ return ARCHIVE_EOF;++ if(!read_var_sized(a, &version, &value_len))+ return ARCHIVE_EOF;++ *extra_data_size -= value_len;+ if(ARCHIVE_OK != consume(a, value_len))+ return ARCHIVE_EOF;++ /* extra_data_size should be zero here. */++ cur_filename = archive_entry_pathname_utf8(e);+ if(cur_filename == NULL) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Version entry without file name");+ return ARCHIVE_FATAL;+ }++ archive_string_init(&version_string);+ archive_string_init(&name_utf8_string);++ /* Prepare a ;123 suffix for the filename, where '123' is the version+ * value of this file. */+ archive_string_sprintf(&version_string, ";%zu", version);++ /* Build the new filename. */+ archive_strcat(&name_utf8_string, cur_filename);+ archive_strcat(&name_utf8_string, version_string.s);++ /* Apply the new filename into this file's context. */+ archive_entry_update_pathname_utf8(e, name_utf8_string.s);++ /* Free buffers. */+ archive_string_free(&version_string);+ archive_string_free(&name_utf8_string);+ return ARCHIVE_OK;+}++static int parse_file_extra_htime(struct archive_read* a,+ struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)+{+ char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;+ size_t flags = 0;+ size_t value_len;++ enum HTIME_FLAGS {+ IS_UNIX = 0x01,+ HAS_MTIME = 0x02,+ HAS_CTIME = 0x04,+ HAS_ATIME = 0x08,+ HAS_UNIX_NS = 0x10,+ };++ if(!read_var_sized(a, &flags, &value_len))+ return ARCHIVE_EOF;++ *extra_data_size -= value_len;+ if(ARCHIVE_OK != consume(a, value_len)) {+ return ARCHIVE_EOF;+ }++ unix_time = flags & IS_UNIX;+ has_unix_ns = unix_time && (flags & HAS_UNIX_NS);+ has_mtime = flags & HAS_MTIME;+ has_atime = flags & HAS_ATIME;+ has_ctime = flags & HAS_CTIME;+ rar5->file.e_atime_ns = rar5->file.e_ctime_ns = rar5->file.e_mtime_ns = 0;++ if(has_mtime) {+ parse_htime_item(a, unix_time, &rar5->file.e_mtime,+ &rar5->file.e_mtime_ns, extra_data_size);+ }++ if(has_ctime) {+ parse_htime_item(a, unix_time, &rar5->file.e_ctime,+ &rar5->file.e_ctime_ns, extra_data_size);+ }++ if(has_atime) {+ parse_htime_item(a, unix_time, &rar5->file.e_atime,+ &rar5->file.e_atime_ns, extra_data_size);+ }++ if(has_mtime && has_unix_ns) {+ if(!read_u32(a, &rar5->file.e_mtime_ns))+ return ARCHIVE_EOF;++ *extra_data_size -= 4;+ }++ if(has_ctime && has_unix_ns) {+ if(!read_u32(a, &rar5->file.e_ctime_ns))+ return ARCHIVE_EOF;++ *extra_data_size -= 4;+ }++ if(has_atime && has_unix_ns) {+ if(!read_u32(a, &rar5->file.e_atime_ns))+ return ARCHIVE_EOF;++ *extra_data_size -= 4;+ }++ /* The seconds and nanoseconds are either together, or separated in two+ * fields so we parse them, then set the archive_entry's times. */+ if(has_mtime) {+ archive_entry_set_mtime(e, rar5->file.e_mtime, rar5->file.e_mtime_ns);+ }++ if(has_ctime) {+ archive_entry_set_ctime(e, rar5->file.e_ctime, rar5->file.e_ctime_ns);+ }++ if(has_atime) {+ archive_entry_set_atime(e, rar5->file.e_atime, rar5->file.e_atime_ns);+ }++ return ARCHIVE_OK;+}++static int parse_file_extra_redir(struct archive_read* a,+ struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)+{+ uint64_t value_size = 0;+ size_t target_size = 0;+ char target_utf8_buf[MAX_NAME_IN_BYTES];+ const uint8_t* p;++ if(!read_var(a, &rar5->file.redir_type, &value_size))+ return ARCHIVE_EOF;+ if(ARCHIVE_OK != consume(a, (int64_t)value_size))+ return ARCHIVE_EOF;+ *extra_data_size -= value_size;++ if(!read_var(a, &rar5->file.redir_flags, &value_size))+ return ARCHIVE_EOF;+ if(ARCHIVE_OK != consume(a, (int64_t)value_size))+ return ARCHIVE_EOF;+ *extra_data_size -= value_size;++ if(!read_var_sized(a, &target_size, NULL))+ return ARCHIVE_EOF;+ *extra_data_size -= target_size + 1;++ if(target_size > (MAX_NAME_IN_CHARS - 1)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Link target is too long");+ return ARCHIVE_FATAL;+ }++ if(target_size == 0) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "No link target specified");+ return ARCHIVE_FATAL;+ }++ if(!read_ahead(a, target_size, &p))+ return ARCHIVE_EOF;++ memcpy(target_utf8_buf, p, target_size);+ target_utf8_buf[target_size] = 0;++ if(ARCHIVE_OK != consume(a, (int64_t)target_size))+ return ARCHIVE_EOF;++ switch(rar5->file.redir_type) {+ case REDIR_TYPE_UNIXSYMLINK:+ case REDIR_TYPE_WINSYMLINK:+ archive_entry_set_filetype(e, AE_IFLNK);+ archive_entry_update_symlink_utf8(e, target_utf8_buf);+ if (rar5->file.redir_flags & REDIR_SYMLINK_IS_DIR) {+ archive_entry_set_symlink_type(e,+ AE_SYMLINK_TYPE_DIRECTORY);+ } else {+ archive_entry_set_symlink_type(e,+ AE_SYMLINK_TYPE_FILE);+ }+ break;++ case REDIR_TYPE_HARDLINK:+ archive_entry_set_filetype(e, AE_IFREG);+ archive_entry_update_hardlink_utf8(e, target_utf8_buf);+ break;++ default:+ /* Unknown redir type, skip it. */+ break;+ }+ return ARCHIVE_OK;+}++static int parse_file_extra_owner(struct archive_read* a,+ struct archive_entry* e, int64_t* extra_data_size)+{+ uint64_t flags = 0;+ uint64_t value_size = 0;+ uint64_t id = 0;+ size_t name_len = 0;+ size_t name_size = 0;+ char namebuf[OWNER_MAXNAMELEN];+ const uint8_t* p;++ if(!read_var(a, &flags, &value_size))+ return ARCHIVE_EOF;+ if(ARCHIVE_OK != consume(a, (int64_t)value_size))+ return ARCHIVE_EOF;+ *extra_data_size -= value_size;++ if ((flags & OWNER_USER_NAME) != 0) {+ if(!read_var_sized(a, &name_size, NULL))+ return ARCHIVE_EOF;+ *extra_data_size -= name_size + 1;++ if(!read_ahead(a, name_size, &p))+ return ARCHIVE_EOF;++ if (name_size >= OWNER_MAXNAMELEN) {+ name_len = OWNER_MAXNAMELEN - 1;+ } else {+ name_len = name_size;+ }++ memcpy(namebuf, p, name_len);+ namebuf[name_len] = 0;+ if(ARCHIVE_OK != consume(a, (int64_t)name_size))+ return ARCHIVE_EOF;++ archive_entry_set_uname(e, namebuf);+ }+ if ((flags & OWNER_GROUP_NAME) != 0) {+ if(!read_var_sized(a, &name_size, NULL))+ return ARCHIVE_EOF;+ *extra_data_size -= name_size + 1;++ if(!read_ahead(a, name_size, &p))+ return ARCHIVE_EOF;++ if (name_size >= OWNER_MAXNAMELEN) {+ name_len = OWNER_MAXNAMELEN - 1;+ } else {+ name_len = name_size;+ }++ memcpy(namebuf, p, name_len);+ namebuf[name_len] = 0;+ if(ARCHIVE_OK != consume(a, (int64_t)name_size))+ return ARCHIVE_EOF;++ archive_entry_set_gname(e, namebuf);+ }+ if ((flags & OWNER_USER_UID) != 0) {+ if(!read_var(a, &id, &value_size))+ return ARCHIVE_EOF;+ if(ARCHIVE_OK != consume(a, (int64_t)value_size))+ return ARCHIVE_EOF;+ *extra_data_size -= value_size;++ archive_entry_set_uid(e, (la_int64_t)id);+ }+ if ((flags & OWNER_GROUP_GID) != 0) {+ if(!read_var(a, &id, &value_size))+ return ARCHIVE_EOF;+ if(ARCHIVE_OK != consume(a, (int64_t)value_size))+ return ARCHIVE_EOF;+ *extra_data_size -= value_size;++ archive_entry_set_gid(e, (la_int64_t)id);+ }+ return ARCHIVE_OK;+}++static int process_head_file_extra(struct archive_read* a,+ struct archive_entry* e, struct rar5 *rar5, int64_t extra_data_size)+{+ uint64_t extra_field_size;+ uint64_t extra_field_id = 0;+ uint64_t var_size;++ while(extra_data_size > 0) {+ /* Make sure we won't fail if the file declares only unsupported+ attributes. */+ int ret = ARCHIVE_OK;++ if(!read_var(a, &extra_field_size, &var_size))+ return ARCHIVE_EOF;++ extra_data_size -= var_size;+ if(ARCHIVE_OK != consume(a, var_size)) {+ return ARCHIVE_EOF;+ }++ if(!read_var(a, &extra_field_id, &var_size))+ return ARCHIVE_EOF;++ extra_field_size -= var_size;+ extra_data_size -= var_size;+ if(ARCHIVE_OK != consume(a, var_size)) {+ return ARCHIVE_EOF;+ }++ switch(extra_field_id) {+ case EX_HASH:+ ret = parse_file_extra_hash(a, rar5,+ &extra_data_size);+ break;+ case EX_HTIME:+ ret = parse_file_extra_htime(a, e, rar5,+ &extra_data_size);+ break;+ case EX_REDIR:+ ret = parse_file_extra_redir(a, e, rar5,+ &extra_data_size);+ break;+ case EX_UOWNER:+ ret = parse_file_extra_owner(a, e,+ &extra_data_size);+ break;+ case EX_VERSION:+ ret = parse_file_extra_version(a, e,+ &extra_data_size);+ break;+ case EX_CRYPT:+ /* Mark the entry as encrypted */+ archive_entry_set_is_data_encrypted(e, 1);+ rar5->has_encrypted_entries = 1;+ rar5->cstate.data_encrypted = 1;+ /* fallthrough */+ case EX_SUBDATA:+ /* fallthrough */+ default:+ /* Skip unsupported entry. */+ extra_data_size -= extra_field_size;+ if (ARCHIVE_OK != consume(a, extra_field_size)) {+ return ARCHIVE_EOF;+ }++ /* Don't fail on unsupported attribute -- we've handled it+ by skipping over it. */+ ret = ARCHIVE_OK;+ }++ if (ret != ARCHIVE_OK) {+ /* Forward any errors signalled by the attribute parsing+ functions. */+ return ret;+ }+ }++ if (extra_data_size != 0) {+ /* We didn't skip everything, or we skipped too much; either way,+ there's an error in this parsing function. */++ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "unsupported structure of file header extra data");+ return ARCHIVE_FATAL;+ }++ return ARCHIVE_OK;+}++static int file_entry_sanity_checks(struct archive_read* a,+ size_t block_flags, uint8_t is_dir, uint64_t unpacked_size,+ size_t packed_size)+{+ if (is_dir) {+ const int declares_data_size =+ (int) (unpacked_size != 0 || packed_size != 0);++ /* FILE entries for directories still declare HFL_DATA in block flags,+ even though attaching data to such blocks doesn't make much sense. */+ if (declares_data_size) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "directory entries cannot have any data");+ return ARCHIVE_FATAL;+ }+ } else {+ const int declares_hfl_data = (int) ((block_flags & HFL_DATA) != 0);+ if (!declares_hfl_data) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "no data found in file/service block");+ return ARCHIVE_FATAL;+ }+ }++ return ARCHIVE_OK;+}++static int process_head_file(struct archive_read* a, struct rar5 *rar5,+ struct archive_entry* entry, size_t block_flags)+{+ int64_t extra_data_size = 0;+ size_t data_size = 0;+ size_t file_flags = 0;+ size_t file_attr = 0;+ size_t compression_info = 0;+ size_t host_os = 0;+ size_t name_size = 0;+ uint64_t unpacked_size, window_size;+ uint32_t mtime = 0, crc = 0;+ int c_method = 0, c_version = 0;+ char name_utf8_buf[MAX_NAME_IN_BYTES];+ const uint8_t* p;+ int sanity_ret;++ enum FILE_FLAGS {+ DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,+ UNKNOWN_UNPACKED_SIZE = 0x0008,+ };++ enum FILE_ATTRS {+ ATTR_READONLY = 0x1, ATTR_HIDDEN = 0x2, ATTR_SYSTEM = 0x4,+ ATTR_DIRECTORY = 0x10,+ };++ enum COMP_INFO_FLAGS {+ SOLID = 0x0040,+ };++ enum HOST_OS {+ HOST_WINDOWS = 0,+ HOST_UNIX = 1,+ };++ archive_entry_clear(entry);++ /* Do not reset file context if we're switching archives. */+ if(!rar5->cstate.switch_multivolume) {+ reset_file_context(rar5);+ }++ if(block_flags & HFL_EXTRA_DATA) {+ uint64_t edata_size = 0;+ if(!read_var(a, &edata_size, NULL))+ return ARCHIVE_EOF;++ /* Intentional type cast from unsigned to signed. */+ extra_data_size = (int64_t) edata_size;+ }++ if(block_flags & HFL_DATA) {+ if(!read_var_sized(a, &data_size, NULL))+ return ARCHIVE_EOF;++ if(data_size > SSIZE_MAX) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "File data size is too large");+ return ARCHIVE_FATAL;+ }++ rar5->file.bytes_remaining = data_size;+ } else {+ rar5->file.bytes_remaining = 0;+ }++ if(!read_var_sized(a, &file_flags, NULL))+ return ARCHIVE_EOF;++ if(!read_var(a, &unpacked_size, NULL))+ return ARCHIVE_EOF;++ if(file_flags & UNKNOWN_UNPACKED_SIZE) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Files with unknown unpacked size are not supported");+ return ARCHIVE_FATAL;+ }++ rar5->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);++ sanity_ret = file_entry_sanity_checks(a, block_flags, rar5->file.dir,+ unpacked_size, data_size);++ if (sanity_ret != ARCHIVE_OK) {+ return sanity_ret;+ }++ if(!read_var_sized(a, &file_attr, NULL))+ return ARCHIVE_EOF;++ if(file_flags & UTIME) {+ if(!read_u32(a, &mtime))+ return ARCHIVE_EOF;+ }++ if(file_flags & CRC32) {+ if(!read_u32(a, &crc))+ return ARCHIVE_EOF;+ }++ if(!read_var_sized(a, &compression_info, NULL))+ return ARCHIVE_EOF;++ c_method = (int) (compression_info >> 7) & 0x7;+ c_version = (int) (compression_info & 0x3f);++ /* RAR5 seems to limit the dictionary size to 64MB. */+ window_size = (rar5->file.dir > 0) ?+ 0 :+ g_unpack_window_size << ((compression_info >> 10) & 15);+ rar5->cstate.method = c_method;+ rar5->cstate.version = c_version + 50;+ rar5->file.solid = (compression_info & SOLID) > 0;++ /* Archives which declare solid files without initializing the window+ * buffer first are invalid, unless previous data was encrypted, in+ * which case we may never have had the chance */++ if(rar5->file.solid > 0 && rar5->cstate.data_encrypted == 0 &&+ rar5->cstate.window_buf == NULL) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Declared solid file, but no window buffer "+ "initialized yet");+ return ARCHIVE_FATAL;+ }++ /* Check if window_size is a sane value. Also, if the file is not+ * declared as a directory, disallow window_size == 0. */+ if(window_size > (64 * 1024 * 1024) ||+ (rar5->file.dir == 0 && window_size == 0))+ {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Declared dictionary size is not supported");+ return ARCHIVE_FATAL;+ }++ if(rar5->file.solid > 0) {+ /* Re-check if current window size is the same as previous+ * window size (for solid files only). */+ if(rar5->file.solid_window_size > 0 &&+ rar5->file.solid_window_size != (ssize_t) window_size)+ {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Window size for this solid file doesn't match "+ "the window size used in previous solid file");+ return ARCHIVE_FATAL;+ }+ }+ else+ rar5->cstate.data_encrypted = 0; /* Reset for new buffer */++ if(rar5->cstate.window_size < (ssize_t) window_size &&+ rar5->cstate.window_buf)+ {+ /* The `data_ready` stack contains pointers to the `window_buf` or+ * `filtered_buf` buffers. Since we're about to reallocate the first+ * buffer, some of those pointers could become invalid. Therefore, we+ * need to dispose of all entries from the stack before attempting the+ * realloc. */+ clear_data_ready_stack(rar5);++ /* If window_buf has been allocated before, reallocate it, so+ * that its size will match new window_size. */++ uint8_t* new_window_buf =+ realloc(rar5->cstate.window_buf, (size_t) window_size);++ if(!new_window_buf) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Not enough memory when trying to realloc the window "+ "buffer");+ return ARCHIVE_FATAL;+ }++ rar5->cstate.window_buf = new_window_buf;+ }++ /* Values up to 64M should fit into ssize_t on every+ * architecture. */+ rar5->cstate.window_size = (ssize_t) window_size;++ if(rar5->file.solid > 0 && rar5->file.solid_window_size == 0) {+ /* Solid files have to have the same window_size across+ whole archive. Remember the window_size parameter+ for first solid file found. */+ rar5->file.solid_window_size = rar5->cstate.window_size;+ }++ init_window_mask(rar5);++ rar5->file.service = 0;++ if(!read_var_sized(a, &host_os, NULL))+ return ARCHIVE_EOF;++ if(host_os == HOST_WINDOWS) {+ /* Host OS is Windows */++ __LA_MODE_T mode;++ if(file_attr & ATTR_DIRECTORY) {+ if (file_attr & ATTR_READONLY) {+ mode = 0555 | AE_IFDIR;+ } else {+ mode = 0755 | AE_IFDIR;+ }+ } else {+ if (file_attr & ATTR_READONLY) {+ mode = 0444 | AE_IFREG;+ } else {+ mode = 0644 | AE_IFREG;+ }+ }++ archive_entry_set_mode(entry, mode);++ if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {+ char buf[sizeof(",rdonly,hidden,system")];+ const char *fflags[3] = { "", "", "" };+ const char **flag = fflags;++ if (file_attr & ATTR_READONLY)+ *flag++ = ",rdonly";+ if (file_attr & ATTR_HIDDEN)+ *flag++ = ",hidden";+ if (file_attr & ATTR_SYSTEM)+ *flag++ = ",system";++ snprintf(buf, sizeof(buf), "%s%s%s",+ fflags[0], fflags[1], fflags[2]);+ archive_entry_copy_fflags_text(entry, buf + 1);+ }+ } else if(host_os == HOST_UNIX) {+ /* Host OS is Unix */+ archive_entry_set_mode(entry, (__LA_MODE_T) file_attr);+ } else {+ /* Unknown host OS */+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Unsupported Host OS: 0x%jx",+ (uintmax_t)host_os);++ return ARCHIVE_FATAL;+ }++ if(!read_var_sized(a, &name_size, NULL))+ return ARCHIVE_EOF;++ if(name_size > (MAX_NAME_IN_CHARS - 1)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Filename is too long");++ return ARCHIVE_FATAL;+ }++ if(name_size == 0) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "No filename specified");++ return ARCHIVE_FATAL;+ }++ if(!read_ahead(a, name_size, &p))+ return ARCHIVE_EOF;++ memcpy(name_utf8_buf, p, name_size);+ name_utf8_buf[name_size] = 0;+ if(ARCHIVE_OK != consume(a, name_size)) {+ return ARCHIVE_EOF;+ }++ archive_entry_update_pathname_utf8(entry, name_utf8_buf);++ if(extra_data_size > 0) {+ int ret = process_head_file_extra(a, entry, rar5,+ extra_data_size);++ /*+ * TODO: rewrite or remove useless sanity check+ * as extra_data_size is not passed as a pointer+ *+ if(extra_data_size < 0) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "File extra data size is not zero");+ return ARCHIVE_FATAL;+ }+ */++ if(ret != ARCHIVE_OK)+ return ret;+ }++ if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {+ rar5->file.unpacked_size = (ssize_t) unpacked_size;+ if(rar5->file.redir_type == REDIR_TYPE_NONE)+ archive_entry_set_size(entry, unpacked_size);+ }++ if(file_flags & UTIME) {+ archive_entry_set_mtime(entry, (time_t) mtime, 0);+ }++ if(file_flags & CRC32) {+ rar5->file.stored_crc32 = crc;+ }++ if(!rar5->cstate.switch_multivolume) {+ /* Do not reinitialize unpacking state if we're switching+ * archives. */+ rar5->cstate.block_parsing_finished = 1;+ rar5->cstate.all_filters_applied = 1;+ rar5->cstate.initialized = 0;+ }++ if(rar5->generic.split_before > 0) {+ /* If now we're standing on a header that has a 'split before'+ * mark, it means we're standing on a 'continuation' file+ * header. Signal the caller that if it wants to move to+ * another file, it must call rar5_read_header() function+ * again. */++ return ARCHIVE_RETRY;+ } else {+ return ARCHIVE_OK;+ }+}++static int process_head_service(struct archive_read* a, struct rar5 *rar5,+ struct archive_entry* entry, size_t block_flags)+{+ /* Process this SERVICE block the same way as FILE blocks. */+ int ret = process_head_file(a, rar5, entry, block_flags);+ if(ret != ARCHIVE_OK)+ return ret;++ rar5->file.service = 1;++ /* But skip the data part automatically. It's no use for the user+ * anyway. It contains only service data, not even needed to+ * properly unpack the file. */+ ret = rar5_read_data_skip(a);+ if(ret != ARCHIVE_OK)+ return ret;++ /* After skipping, try parsing another block automatically. */+ return ARCHIVE_RETRY;+}++static int process_head_main(struct archive_read* a, struct rar5 *rar5,+ struct archive_entry* entry, size_t block_flags)+{+ int ret;+ uint64_t extra_data_size = 0;+ size_t extra_field_size = 0;+ size_t extra_field_id = 0;+ size_t archive_flags = 0;++ enum MAIN_FLAGS {+ VOLUME = 0x0001, /* multi-volume archive */+ VOLUME_NUMBER = 0x0002, /* volume number, first vol doesn't+ * have it */+ SOLID = 0x0004, /* solid archive */+ PROTECT = 0x0008, /* contains Recovery info */+ LOCK = 0x0010, /* readonly flag, not used */+ };++ enum MAIN_EXTRA {+ // Just one attribute here.+ LOCATOR = 0x01,+ };++ (void) entry;++ if(block_flags & HFL_EXTRA_DATA) {+ if(!read_var(a, &extra_data_size, NULL))+ return ARCHIVE_EOF;+ } else {+ extra_data_size = 0;+ }++ if(!read_var_sized(a, &archive_flags, NULL)) {+ return ARCHIVE_EOF;+ }++ rar5->main.volume = (archive_flags & VOLUME) > 0;+ rar5->main.solid = (archive_flags & SOLID) > 0;++ if(archive_flags & VOLUME_NUMBER) {+ size_t v = 0;+ if(!read_var_sized(a, &v, NULL)) {+ return ARCHIVE_EOF;+ }++ if (v > UINT_MAX) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Invalid volume number");+ return ARCHIVE_FATAL;+ }++ rar5->main.vol_no = (unsigned int) v;+ } else {+ rar5->main.vol_no = 0;+ }++ if(rar5->vol.expected_vol_no > 0 &&+ rar5->main.vol_no != rar5->vol.expected_vol_no)+ {+ /* Returning EOF instead of FATAL because of strange+ * libarchive behavior. When opening multiple files via+ * archive_read_open_filenames(), after reading up the whole+ * last file, the __archive_read_ahead function wraps up to+ * the first archive instead of returning EOF. */+ return ARCHIVE_EOF;+ }++ if(extra_data_size == 0) {+ /* Early return. */+ return ARCHIVE_OK;+ }++ if(!read_var_sized(a, &extra_field_size, NULL)) {+ return ARCHIVE_EOF;+ }++ if(!read_var_sized(a, &extra_field_id, NULL)) {+ return ARCHIVE_EOF;+ }++ if(extra_field_size == 0) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Invalid extra field size");+ return ARCHIVE_FATAL;+ }++ switch(extra_field_id) {+ case LOCATOR:+ ret = process_main_locator_extra_block(a, rar5);+ if(ret != ARCHIVE_OK) {+ /* Error while parsing main locator extra+ * block. */+ return ret;+ }++ break;+ default:+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Unsupported extra type (0x%jx)",+ (uintmax_t)extra_field_id);+ return ARCHIVE_FATAL;+ }++ return ARCHIVE_OK;+}++static int skip_unprocessed_bytes(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ int ret;++ if(rar5->file.bytes_remaining) {+ /* Use different skipping method in block merging mode than in+ * normal mode. If merge mode is active, rar5_read_data_skip+ * can't be used, because it could allow recursive use of+ * merge_block() * function, and this function doesn't support+ * recursive use. */+ if(rar5->merge_mode) {+ /* Discard whole merged block. This is valid in solid+ * mode as well, because the code will discard blocks+ * only if those blocks are safe to discard (i.e.+ * they're not FILE blocks). */+ ret = consume(a, rar5->file.bytes_remaining);+ if(ret != ARCHIVE_OK) {+ return ret;+ }+ rar5->file.bytes_remaining = 0;+ } else {+ /* If we're not in merge mode, use safe skipping code.+ * This will ensure we'll handle solid archives+ * properly. */+ ret = rar5_read_data_skip(a);+ if(ret != ARCHIVE_OK) {+ return ret;+ }+ }+ }++ return ARCHIVE_OK;+}++static int scan_for_signature(struct archive_read* a);++/* Base block processing function. A 'base block' is a RARv5 header block+ * that tells the reader what kind of data is stored inside the block.+ *+ * From the birds-eye view a RAR file looks file this:+ *+ * <magic><base_block_1><base_block_2>...<base_block_n>+ *+ * There are a few types of base blocks. Those types are specified inside+ * the 'switch' statement in this function. For example purposes, I'll write+ * how a standard RARv5 file could look like here:+ *+ * <magic><MAIN><FILE><FILE><FILE><SERVICE><ENDARC>+ *+ * The structure above could describe an archive file with 3 files in it,+ * one service "QuickOpen" block (that is ignored by this parser), and an+ * end of file base block marker.+ *+ * If the file is stored in multiple archive files ("multiarchive"), it might+ * look like this:+ *+ * .part01.rar: <magic><MAIN><FILE><ENDARC>+ * .part02.rar: <magic><MAIN><FILE><ENDARC>+ * .part03.rar: <magic><MAIN><FILE><ENDARC>+ *+ * This example could describe 3 RAR files that contain ONE archived file.+ * Or it could describe 3 RAR files that contain 3 different files. Or 3+ * RAR files than contain 2 files. It all depends what metadata is stored in+ * the headers of <FILE> blocks.+ *+ * Each <FILE> block contains info about its size, the name of the file it's+ * storing inside, and whether this FILE block is a continuation block of+ * previous archive ('split before'), and is this FILE block should be+ * continued in another archive ('split after'). By parsing the 'split before'+ * and 'split after' flags, we're able to tell if multiple <FILE> base blocks+ * are describing one file, or multiple files (with the same filename, for+ * example).+ *+ * One thing to note is that if we're parsing the first <FILE> block, and+ * we see 'split after' flag, then we need to jump over to another <FILE>+ * block to be able to decompress rest of the data. To do this, we need+ * to skip the <ENDARC> block, then switch to another file, then skip the+ * <magic> block, <MAIN> block, and then we're standing on the proper+ * <FILE> block.+ */++/*+ * A header that carries no file data (HEAD_MAIN, or an unknown block+ * flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the+ * sub-parser did not read. Skip them before returning ARCHIVE_RETRY,+ * otherwise rar5_read_header() re-parses the same block region O(N)+ * times instead of O(1), letting a crafted RAR5 file stall the reader+ * (GHSA-9h2c-464f-j3hj).+ *+ * Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block+ * into one contiguous buffer with no compaction until we return, so+ * body_start stays valid and (cur - body_start) is the exact number of+ * body bytes consumed so far.+ */+static void+rar5_skip_remaining_block(struct archive_read* a,+ const uint8_t* body_start, size_t raw_hdr_size)+{+ const uint8_t* cur;++ if(read_ahead(a, 1, &cur)) {+ size_t body_used = (size_t)(cur - body_start);++ if(body_used < raw_hdr_size)+ (void)consume(a, raw_hdr_size - body_used);+ }+}++static int process_base_block(struct archive_read* a,+ struct archive_entry* entry)+{+ const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;++ struct rar5 *rar5 = a->format->data;+ uint32_t hdr_crc, computed_crc;+ size_t raw_hdr_size = 0, hdr_size_len, hdr_size;+ size_t header_id = 0;+ size_t header_flags = 0;+ const uint8_t* p;+ const uint8_t* body_start;+ int ret;++ enum HEADER_TYPE {+ HEAD_MARK = 0x00, HEAD_MAIN = 0x01, HEAD_FILE = 0x02,+ HEAD_SERVICE = 0x03, HEAD_CRYPT = 0x04, HEAD_ENDARC = 0x05,+ HEAD_UNKNOWN = 0xff,+ };++ /* Skip any unprocessed data for this file. */+ ret = skip_unprocessed_bytes(a);+ if(ret != ARCHIVE_OK)+ return ret;++ /* Read the expected CRC32 checksum. */+ if(!read_u32(a, &hdr_crc)) {+ return ARCHIVE_EOF;+ }++ /* Read header size. */+ if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {+ return ARCHIVE_EOF;+ }++ hdr_size = raw_hdr_size + hdr_size_len;++ /* Sanity check, maximum header size for RAR5 is 2MB. */+ if(hdr_size > (2 * 1024 * 1024)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Base block header is too large");++ return ARCHIVE_FATAL;+ }++ /* Additional sanity checks to weed out invalid files. */+ if(raw_hdr_size == 0 || hdr_size_len == 0 ||+ hdr_size < SMALLEST_RAR5_BLOCK_SIZE)+ {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Too small block encountered (%zu bytes)",+ raw_hdr_size);++ return ARCHIVE_FATAL;+ }++ /* Read the whole header data into memory, maximum memory use here is+ * 2MB. */+ if(!read_ahead(a, hdr_size, &p)) {+ return ARCHIVE_EOF;+ }++ /* Verify the CRC32 of the header data. */+ computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);+ if(computed_crc != hdr_crc) {+#ifndef DONT_FAIL_ON_CRC_ERROR+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Header CRC error");++ return ARCHIVE_FATAL;+#endif+ }++ /* Remember the first byte of the block body so we can later skip+ * any bytes the sub-parser leaves unconsumed. */+ body_start = p + hdr_size_len;++ /* If the checksum is OK, we proceed with parsing. */+ if(ARCHIVE_OK != consume(a, hdr_size_len)) {+ return ARCHIVE_EOF;+ }++ if(!read_var_sized(a, &header_id, NULL))+ return ARCHIVE_EOF;++ if(!read_var_sized(a, &header_flags, NULL))+ return ARCHIVE_EOF;++ rar5->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;+ rar5->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;+ rar5->generic.size = (int)hdr_size;+ rar5->generic.last_header_id = (int)header_id;+ rar5->main.endarc = 0;++ /* Those are possible header ids in RARv5. */+ switch(header_id) {+ case HEAD_MAIN:+ ret = process_head_main(a, rar5, entry, header_flags);++ /* Main header doesn't have any files in it, so it's+ * pointless to return to the caller. Retry to next+ * header, which should be HEAD_FILE/HEAD_SERVICE. */+ if(ret == ARCHIVE_OK) {+ rar5_skip_remaining_block(a, body_start,+ raw_hdr_size);+ return ARCHIVE_RETRY;+ }++ return ret;+ case HEAD_SERVICE:+ ret = process_head_service(a, rar5, entry, header_flags);+ return ret;+ case HEAD_FILE:+ ret = process_head_file(a, rar5, entry, header_flags);+ return ret;+ case HEAD_CRYPT:+ archive_entry_set_is_metadata_encrypted(entry, 1);+ archive_entry_set_is_data_encrypted(entry, 1);+ rar5->has_encrypted_entries = 1;+ rar5->headers_are_encrypted = 1;+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Encryption is not supported");+ return ARCHIVE_FATAL;+ case HEAD_ENDARC:+ rar5->main.endarc = 1;++ /* After encountering an end of file marker, we need+ * to take into consideration if this archive is+ * continued in another file (i.e. is it part01.rar:+ * is there a part02.rar?) */+ if(rar5->main.volume) {+ /* In case there is part02.rar, position the+ * read pointer in a proper place, so we can+ * resume parsing. */+ ret = scan_for_signature(a);+ if(ret == ARCHIVE_FATAL) {+ return ARCHIVE_EOF;+ } else {+ if(rar5->vol.expected_vol_no ==+ UINT_MAX) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Header error");+ return ARCHIVE_FATAL;+ }++ rar5->vol.expected_vol_no =+ rar5->main.vol_no + 1;+ return ARCHIVE_OK;+ }+ } else {+ return ARCHIVE_EOF;+ }+ case HEAD_MARK:+ return ARCHIVE_EOF;+ default:+ if((header_flags & HFL_SKIP_IF_UNKNOWN) == 0) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Header type error");+ return ARCHIVE_FATAL;+ } else {+ /* If the block is marked as 'skip if unknown',+ * do as the flag says: skip the block+ * instead on failing on it. */+ rar5_skip_remaining_block(a, body_start,+ raw_hdr_size);+ return ARCHIVE_RETRY;+ }+ }++#if !defined WIN32+ // Not reached.+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Internal unpacker error");+ return ARCHIVE_FATAL;+#endif+}++static int skip_base_block(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ int ret;++ /* Create a new local archive_entry structure that will be operated on+ * by header reader; operations on this archive_entry will be discarded.+ */+ struct archive_entry* entry = archive_entry_new();+ if (entry == NULL)+ return ARCHIVE_FATAL;++ ret = process_base_block(a, entry);++ /* Discard operations on this archive_entry structure. */+ archive_entry_free(entry);+ if(ret == ARCHIVE_FATAL)+ return ret;++ if(rar5->generic.last_header_id == 2 && rar5->generic.split_before > 0)+ return ARCHIVE_OK;++ if(ret == ARCHIVE_OK)+ return ARCHIVE_RETRY;+ else+ return ret;+}++static int try_skip_sfx(struct archive_read *a)+{+ const char *p;++ if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)+ return ARCHIVE_EOF;++ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)+ {+ char signature[sizeof(rar5_signature_xor)];+ const void *h;+ const char *q;+ size_t skip, total = 0;+ ssize_t bytes, window = 4096;++ rar5_signature(signature);++ while (total + window <= (1024 * 512)) {+ h = __archive_read_ahead(a, window, &bytes);+ if (h == NULL) {+ /* Remaining bytes are less than window. */+ window >>= 1;+ if (window < 0x40)+ goto fatal;+ continue;+ }+ if (bytes < 0x40)+ goto fatal;+ p = h;+ q = p + bytes;++ /*+ * Scan ahead until we find something that looks+ * like the RAR header.+ */+ while (p + 8 < q) {+ if (memcmp(p, signature, sizeof(signature)) == 0) {+ skip = p - (const char *)h;+ __archive_read_consume(a, skip);+ return (ARCHIVE_OK);+ }+ p += 0x10;+ }+ skip = p - (const char *)h;+ __archive_read_consume(a, skip);+ total += skip;+ }+ }++ return ARCHIVE_OK;+fatal:+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Couldn't find out RAR header");+ return (ARCHIVE_FATAL);+}++static int rar5_read_header(struct archive_read *a,+ struct archive_entry *entry)+{+ struct rar5 *rar5 = a->format->data;+ int ret;++ /*+ * It should be sufficient to call archive_read_next_header() for+ * a reader to determine if an entry is encrypted or not.+ */+ if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {+ rar5->has_encrypted_entries = 0;+ }++ if(rar5->header_initialized == 0) {+ init_header(a);+ if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)+ return ret;+ rar5->header_initialized = 1;+ }++ if(rar5->skipped_magic == 0) {+ if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {+ return ARCHIVE_EOF;+ }++ rar5->skipped_magic = 1;+ }++ do {+ ret = process_base_block(a, entry);+ } while(ret == ARCHIVE_RETRY ||+ (rar5->main.endarc > 0 && ret == ARCHIVE_OK));++ return ret;+}++static int init_unpack(struct rar5 *rar5) {+ rar5->file.calculated_crc32 = 0;+ init_window_mask(rar5);++ free(rar5->cstate.window_buf);+ free(rar5->cstate.filtered_buf);++ rar5->cstate.window_buf = NULL;+ rar5->cstate.filtered_buf = NULL;++ if(rar5->cstate.window_size > 0) {+ rar5->cstate.window_buf = calloc(1, rar5->cstate.window_size);+ if(rar5->cstate.window_buf == NULL)+ return ARCHIVE_FATAL;+ rar5->cstate.filtered_buf = calloc(1,+ rar5->cstate.window_size);+ if(rar5->cstate.filtered_buf == NULL)+ return ARCHIVE_FATAL;+ }++ clear_data_ready_stack(rar5);++ rar5->cstate.write_ptr = 0;+ rar5->cstate.last_write_ptr = 0;++ memset(&rar5->cstate.bd, 0, sizeof(rar5->cstate.bd));+ memset(&rar5->cstate.ld, 0, sizeof(rar5->cstate.ld));+ memset(&rar5->cstate.dd, 0, sizeof(rar5->cstate.dd));+ memset(&rar5->cstate.ldd, 0, sizeof(rar5->cstate.ldd));+ memset(&rar5->cstate.rd, 0, sizeof(rar5->cstate.rd));+ return ARCHIVE_OK;+}++static void update_crc(struct rar5 *rar5, const uint8_t* p, size_t to_read) {+ int verify_crc;++ if(rar5->skip_mode) {+#if defined CHECK_CRC_ON_SOLID_SKIP+ verify_crc = 1;+#else+ verify_crc = 0;+#endif+ } else+ verify_crc = 1;++ if(verify_crc) {+ /* Don't update CRC32 if the file doesn't have the+ * `stored_crc32` info filled in. */+ if(rar5->file.stored_crc32 > 0) {+ rar5->file.calculated_crc32 =+ crc32(rar5->file.calculated_crc32, p,+ (unsigned int)to_read);+ }++ /* Check if the file uses an optional BLAKE2sp checksum+ * algorithm. */+ if(rar5->file.has_blake2 > 0) {+ /* Return value of the `update` function is always 0,+ * so we can explicitly ignore it here. */+ (void) blake2sp_update(&rar5->file.b2state, p,+ to_read);+ }+ }+}++static int create_decode_tables(uint8_t* bit_length,+ struct decode_table* table, int size)+{+ int code, upper_limit = 0, i, lc[16];+ uint32_t decode_pos_clone[rar5_countof(table->decode_pos)];+ ssize_t cur_len, quick_data_size;++ memset(&lc, 0, sizeof(lc));+ memset(table->decode_num, 0, sizeof(table->decode_num));+ table->size = size;+ table->quick_bits = size == HUFF_NC ? 10 : 7;++ for(i = 0; i < size; i++) {+ lc[bit_length[i] & 15]++;+ }++ lc[0] = 0;+ table->decode_pos[0] = 0;+ table->decode_len[0] = 0;++ for(i = 1; i < 16; i++) {+ upper_limit += lc[i];++ table->decode_len[i] = upper_limit << (16 - i);+ table->decode_pos[i] = table->decode_pos[i - 1] + lc[i - 1];++ upper_limit <<= 1;+ }++ /* Verify the code-length distribution is not over-subscribed.+ * After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).+ * For a valid prefix-free code this must be <= 2^16 = 65536.+ * An over-subscribed table (> 65536) cannot produce a valid+ * decode table and must be rejected. */+ if(upper_limit > 65536) {+ return ARCHIVE_FAILED;+ }++ memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));++ for(i = 0; i < size; i++) {+ uint8_t clen = bit_length[i] & 15;+ if(clen > 0) {+ int last_pos = decode_pos_clone[clen];+ table->decode_num[last_pos] = i;+ decode_pos_clone[clen]++;+ }+ }++ quick_data_size = (int64_t)1 << table->quick_bits;+ cur_len = 1;+ for(code = 0; code < quick_data_size; code++) {+ int bit_field = code << (16 - table->quick_bits);+ int dist, pos;++ while(cur_len < rar5_countof(table->decode_len) &&+ bit_field >= table->decode_len[cur_len]) {+ cur_len++;+ }++ table->quick_len[code] = (uint8_t) cur_len;++ dist = bit_field - table->decode_len[cur_len - 1];+ dist >>= (16 - cur_len);++ pos = table->decode_pos[cur_len & 15] + dist;+ if(cur_len < rar5_countof(table->decode_pos) && pos < size) {+ table->quick_num[code] = table->decode_num[pos];+ } else {+ table->quick_num[code] = 0;+ }+ }++ return ARCHIVE_OK;+}++static int decode_number(struct archive_read* a, struct decode_table* table,+ const uint8_t* p, uint16_t* num)+{+ struct rar5 *rar5 = a->format->data;+ int i, bits, dist, ret;+ uint16_t bitfield;+ uint32_t pos;++ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &bitfield))) {+ return ret;+ }++ bitfield &= 0xfffe;++ if(bitfield < table->decode_len[table->quick_bits]) {+ int code = bitfield >> (16 - table->quick_bits);+ skip_bits(rar5, table->quick_len[code]);+ *num = table->quick_num[code];+ return ARCHIVE_OK;+ }++ bits = 15;++ for(i = table->quick_bits + 1; i < 15; i++) {+ if(bitfield < table->decode_len[i]) {+ bits = i;+ break;+ }+ }++ skip_bits(rar5, bits);++ dist = bitfield - table->decode_len[bits - 1];+ dist >>= (16 - bits);+ pos = table->decode_pos[bits] + dist;++ if(pos >= table->size)+ pos = 0;++ *num = table->decode_num[pos];+ return ARCHIVE_OK;+}++/* Reads and parses Huffman tables from the beginning of the block. */+static int parse_tables(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p)+{+ int ret, value, i, w, idx = 0;+ uint8_t bit_length[HUFF_BC],+ table[HUFF_TABLE_SIZE],+ nibble_mask = 0xF0,+ nibble_shift = 4;++ enum { ESCAPE = 15 };++ /* The data for table generation is compressed using a simple RLE-like+ * algorithm when storing zeroes, so we need to unpack it first. */+ for(w = 0, i = 0; w < HUFF_BC;) {+ if(i >= rar5->cstate.cur_block_size) {+ /* Truncated data, can't continue. */+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Truncated data in huffman tables");+ return ARCHIVE_FAILED;+ }++ value = (p[i] & nibble_mask) >> nibble_shift;++ if(nibble_mask == 0x0F)+ ++i;++ nibble_mask ^= 0xFF;+ nibble_shift ^= 4;++ /* Values smaller than 15 is data, so we write it directly.+ * Value 15 is a flag telling us that we need to unpack more+ * bytes. */+ if(value == ESCAPE) {+ value = (p[i] & nibble_mask) >> nibble_shift;+ if(nibble_mask == 0x0F)+ ++i;+ nibble_mask ^= 0xFF;+ nibble_shift ^= 4;++ if(value == 0) {+ /* We sometimes need to write the actual value+ * of 15, so this case handles that. */+ bit_length[w++] = ESCAPE;+ } else {+ int k;++ /* Fill zeroes. */+ for(k = 0; (k < value + 2) && (w < HUFF_BC);+ k++) {+ bit_length[w++] = 0;+ }+ }+ } else {+ bit_length[w++] = value;+ }+ }++ rar5->bits.in_addr = i;+ rar5->bits.bit_addr = nibble_shift ^ 4;++ ret = create_decode_tables(bit_length, &rar5->cstate.bd, HUFF_BC);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Decoding huffman tables failed");+ return ARCHIVE_FAILED;+ }++ for(i = 0; i < HUFF_TABLE_SIZE;) {+ uint16_t num;++ ret = decode_number(a, &rar5->cstate.bd, p, &num);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Decoding huffman tables failed");+ return ARCHIVE_FAILED;+ }++ if(num < 16) {+ /* 0..15: store directly */+ table[i] = (uint8_t) num;+ i++;+ } else if(num < 18) {+ /* 16..17: repeat previous code */+ uint16_t n;++ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))+ return ret;++ if(num == 16) {+ n >>= 13;+ n += 3;+ skip_bits(rar5, 3);+ } else {+ n >>= 9;+ n += 11;+ skip_bits(rar5, 7);+ }++ if(i > 0) {+ while(n-- > 0 && i < HUFF_TABLE_SIZE) {+ table[i] = table[i - 1];+ i++;+ }+ } else {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Unexpected error when decoding "+ "huffman tables");+ return ARCHIVE_FAILED;+ }+ } else {+ /* other codes: fill with zeroes `n` times */+ uint16_t n;++ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))+ return ret;++ if(num == 18) {+ n >>= 13;+ n += 3;+ skip_bits(rar5, 3);+ } else {+ n >>= 9;+ n += 11;+ skip_bits(rar5, 7);+ }++ while(n-- > 0 && i < HUFF_TABLE_SIZE)+ table[i++] = 0;+ }+ }++ ret = create_decode_tables(&table[idx], &rar5->cstate.ld, HUFF_NC);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Failed to create literal table");+ return ARCHIVE_FAILED;+ }++ idx += HUFF_NC;++ ret = create_decode_tables(&table[idx], &rar5->cstate.dd, HUFF_DC);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Failed to create distance table");+ return ARCHIVE_FAILED;+ }++ idx += HUFF_DC;++ ret = create_decode_tables(&table[idx], &rar5->cstate.ldd, HUFF_LDC);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Failed to create lower bits of distances table");+ return ARCHIVE_FAILED;+ }++ idx += HUFF_LDC;++ ret = create_decode_tables(&table[idx], &rar5->cstate.rd, HUFF_RC);+ if(ret != ARCHIVE_OK) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Failed to create repeating distances table");+ return ARCHIVE_FAILED;+ }++ return ARCHIVE_OK;+}++/* Parses the block header, verifies its CRC byte, and saves the header+ * fields inside the `hdr` pointer. */+static int parse_block_header(struct archive_read* a, const uint8_t* p,+ ssize_t* block_size, struct compressed_block_header* hdr)+{+ uint8_t calculated_cksum;+ memcpy(hdr, p, sizeof(struct compressed_block_header));++ if(bf_byte_count(hdr) > 2) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Unsupported block header size (was %d, max is 2)",+ bf_byte_count(hdr));+ return ARCHIVE_FAILED;+ }++ /* This should probably use bit reader interface in order to be more+ * future-proof. */+ *block_size = 0;+ switch(bf_byte_count(hdr)) {+ /* 1-byte block size */+ case 0:+ *block_size = *(const uint8_t*) &p[2];+ break;++ /* 2-byte block size */+ case 1:+ *block_size = archive_le16dec(&p[2]);+ break;++ /* 3-byte block size */+ case 2:+ *block_size = archive_le32dec(&p[2]);+ *block_size &= 0x00FFFFFF;+ break;++ /* Other block sizes are not supported. This case is not+ * reached, because we have an 'if' guard before the switch+ * that makes sure of it. */+ default:+ return ARCHIVE_FATAL;+ }++ /* Verify the block header checksum. 0x5A is a magic value and is+ * always * constant. */+ calculated_cksum = 0x5A+ ^ (uint8_t) hdr->block_flags_u8+ ^ (uint8_t) *block_size+ ^ (uint8_t) (*block_size >> 8)+ ^ (uint8_t) (*block_size >> 16);++ if(calculated_cksum != hdr->block_cksum) {+#ifndef DONT_FAIL_ON_CRC_ERROR+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Block checksum error: got 0x%x, expected 0x%x",+ hdr->block_cksum, calculated_cksum);++ return ARCHIVE_FAILED;+#endif+ }++ return ARCHIVE_OK;+}++/* Convenience function used during filter processing. */+static int parse_filter_data(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p, uint32_t* filter_data)+{+ int i, bytes, ret;+ uint32_t data = 0;++ if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5, p, 2, &bytes)))+ return ret;++ bytes++;++ for(i = 0; i < bytes; i++) {+ uint16_t byte;++ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &byte))) {+ return ret;+ }++ /* Cast to uint32_t will ensure the shift operation will not+ * produce undefined result. */+ data += ((uint32_t) byte >> 8) << (i * 8);+ skip_bits(rar5, 8);+ }++ *filter_data = data;+ return ARCHIVE_OK;+}++/* Function is used during sanity checking. */+static int is_valid_filter_block_start(struct rar5 *rar5,+ uint32_t start)+{+ const int64_t block_start = (ssize_t) start + rar5->cstate.write_ptr;+ const int64_t last_bs = rar5->cstate.last_block_start;+ const ssize_t last_bl = rar5->cstate.last_block_length;++ if(last_bs == 0 || last_bl == 0) {+ /* We didn't have any filters yet, so accept this offset. */+ return 1;+ }++ if(block_start >= last_bs + last_bl) {+ /* Current offset is bigger than last block's end offset, so+ * accept current offset. */+ return 1;+ }++ /* Any other case is not a normal situation and we should fail. */+ return 0;+}++/* The function will create a new filter, read its parameters from the input+ * stream and add it to the filter collection. */+static int parse_filter(struct archive_read* ar, const uint8_t* p) {+ struct rar5 *rar5 = ar->format->data;+ uint32_t block_start, block_length;+ uint16_t filter_type;+ struct filter_info* filt = NULL;+ int ret;++ /* Read the parameters from the input stream. */+ if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_start)))+ return ret;++ if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_length)))+ return ret;++ if(ARCHIVE_OK != (ret = read_bits_16(ar, rar5, p, &filter_type)))+ return ret;++ filter_type >>= 13;+ skip_bits(rar5, 3);++ /* Perform some sanity checks on this filter parameters. */++ if(block_length < 4 ||+ block_length > 0x400000 ||+ !is_valid_filter_block_start(rar5, block_start) ||+ (rar5->cstate.window_size > 0 &&+ (ssize_t)block_length > rar5->cstate.window_size >> 1))+ {+ archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Invalid filter encountered");+ return ARCHIVE_FAILED;+ }++ /* Allocate a new filter. */+ filt = add_new_filter(rar5);+ if(filt == NULL) {+ archive_set_error(&ar->archive, ENOMEM,+ "Can't allocate memory for a filter descriptor");+ return ARCHIVE_FATAL;+ }++ filt->type = filter_type;+ filt->block_start = rar5->cstate.write_ptr + block_start;+ filt->block_length = block_length;++ rar5->cstate.last_block_start = filt->block_start;+ rar5->cstate.last_block_length = filt->block_length;++ /* Read some more data in case this is a DELTA filter. Other filter+ * types don't require any additional data over what was already+ * read. */+ if(filter_type == FILTER_DELTA) {+ int channels;++ if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar5, p, 5, &channels)))+ return ret;++ filt->channels = channels + 1;+ }++ return ARCHIVE_OK;+}++static int decode_code_length(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* p, uint16_t code)+{+ int lbits, length = 2;++ if(code < 8) {+ lbits = 0;+ length += code;+ } else {+ lbits = code / 4 - 1;+ length += (4 | (code & 3)) << lbits;+ }++ if(lbits > 0) {+ int add;++ if(ARCHIVE_OK != read_consume_bits(a, rar5, p, lbits, &add))+ return -1;++ length += add;+ }++ return length;+}++static int copy_string(struct archive_read* a, int len, int dist) {+ struct rar5 *rar5 = a->format->data;+ const ssize_t cmask = rar5->cstate.window_mask;+ const uint64_t write_ptr = rar5->cstate.write_ptr ++ rar5->cstate.solid_offset;+ int i;++ if (rar5->cstate.window_buf == NULL)+ return ARCHIVE_FATAL;++ if (rar5->cstate.write_ptr > rar5->file.unpacked_size ||+ len > rar5->file.unpacked_size - rar5->cstate.write_ptr) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Uncompressed data exceeds declared size");+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ /* The unpacker spends most of the time in this function. It would be+ * a good idea to introduce some optimizations here.+ *+ * Just remember that this loop treats buffers that overlap differently+ * than buffers that do not overlap. This is why a simple memcpy(3)+ * call will not be enough. */++ for(i = 0; i < len; i++) {+ const ssize_t write_idx = (write_ptr + i) & cmask;+ const ssize_t read_idx = (write_ptr + i - dist) & cmask;+ rar5->cstate.window_buf[write_idx] =+ rar5->cstate.window_buf[read_idx];+ }++ rar5->cstate.write_ptr += len;+ return ARCHIVE_OK;+}++static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {+ struct rar5 *rar5 = a->format->data;+ uint16_t num;+ int ret;++ const uint64_t cmask = rar5->cstate.window_mask;+ const struct compressed_block_header* hdr = &rar5->last_block_hdr;+ const uint8_t bit_size = 1 + bf_bit_size(hdr);++ while(1) {+ if(rar5->cstate.write_ptr - rar5->cstate.last_write_ptr >+ (rar5->cstate.window_size >> 1)) {+ /* Don't allow growing data by more than half of the+ * window size at a time. In such case, break the loop;+ * next call to this function will continue processing+ * from this moment. */+ break;+ }++ if(rar5->bits.in_addr > rar5->cstate.cur_block_size - 1 ||+ (rar5->bits.in_addr == rar5->cstate.cur_block_size - 1 &&+ rar5->bits.bit_addr >= bit_size))+ {+ /* If the program counter is here, it means the+ * function has finished processing the block. */+ rar5->cstate.block_parsing_finished = 1;+ break;+ }++ /* Decode the next literal. */+ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.ld, p, &num)) {+ return ARCHIVE_EOF;+ }++ /* Num holds a decompression literal, or 'command code'.+ *+ * - Values lower than 256 are just bytes. Those codes+ * can be stored in the output buffer directly.+ *+ * - Code 256 defines a new filter, which is later used to+ * transform the data block accordingly to the filter type.+ * The data block needs to be fully uncompressed first.+ *+ * - Code bigger than 257 and smaller than 262 define+ * a repetition pattern that should be copied from+ * an already uncompressed chunk of data.+ */++ if(num < 256) {+ /* Directly store the byte. */+ int64_t write_idx;++ /* A literal write emits one byte; copy_string() checks len. */+ if(rar5->cstate.write_ptr >= rar5->file.unpacked_size) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Uncompressed data exceeds declared size");+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ write_idx = rar5->cstate.solid_offset ++ rar5->cstate.write_ptr++;++ rar5->cstate.window_buf[write_idx & cmask] =+ (uint8_t) num;+ continue;+ } else if(num >= 262) {+ uint16_t dist_slot;+ int len = decode_code_length(a, rar5, p, num - 262),+ dbits,+ dist = 1;++ if(len == -1) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Failed to decode the code length");++ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.dd, p,+ &dist_slot))+ {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Failed to decode the distance slot");++ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ if(dist_slot < 4) {+ dbits = 0;+ dist += dist_slot;+ } else {+ dbits = dist_slot / 2 - 1;++ /* Cast to uint32_t will make sure the shift+ * left operation won't produce undefined+ * result. Then, the uint32_t type will+ * be implicitly casted to int. */+ dist += (uint32_t) (2 |+ (dist_slot & 1)) << dbits;+ }++ if(dbits > 0) {+ if(dbits >= 4) {+ uint32_t add = 0;+ uint16_t low_dist;++ if(dbits > 4) {+ if(ARCHIVE_OK != (ret = read_bits_32(+ a, rar5, p, &add))) {+ /* Return EOF if we+ * can't read more+ * data. */+ return ret;+ }++ skip_bits(rar5, dbits - 4);+ add = (add >> (+ 36 - dbits)) << 4;+ dist += add;+ }++ if(ARCHIVE_OK != decode_number(a,+ &rar5->cstate.ldd, p, &low_dist))+ {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Failed to decode the "+ "distance slot");++ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ if(dist >= INT_MAX - low_dist - 1) {+ /* This only happens in+ * invalid archives. */+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Distance pointer "+ "overflow");+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ dist += low_dist;+ } else {+ /* dbits is one of [0,1,2,3] */+ int add;++ if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5,+ p, dbits, &add))) {+ /* Return EOF if we can't read+ * more data. */+ return ret;+ }++ dist += add;+ }+ }++ if(dist > 0x100) {+ len++;++ if(dist > 0x2000) {+ len++;++ if(dist > 0x40000) {+ len++;+ }+ }+ }++ dist_cache_push(rar5, dist);+ rar5->cstate.last_len = len;++ ret = copy_string(a, len, dist);+ if(ret != ARCHIVE_OK)+ return ret;++ continue;+ } else if(num == 256) {+ /* Create a filter. */+ ret = parse_filter(a, p);+ if(ret != ARCHIVE_OK)+ return ret;++ continue;+ } else if(num == 257) {+ if(rar5->cstate.last_len != 0) {+ ret = copy_string(a,+ rar5->cstate.last_len,+ rar5->cstate.dist_cache[0]);+ if(ret != ARCHIVE_OK)+ return ret;+ }++ continue;+ } else {+ /* num < 262 */+ const int idx = num - 258;+ const int dist = dist_cache_touch(rar5, idx);++ uint16_t len_slot;+ int len;++ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.rd, p,+ &len_slot)) {+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ len = decode_code_length(a, rar5, p, len_slot);+ if (len == -1) {+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+ }++ rar5->cstate.last_len = len;++ ret = copy_string(a, len, dist);+ if(ret != ARCHIVE_OK)+ return ret;++ continue;+ }+ }++ return ARCHIVE_OK;+}++/* Binary search for the RARv5 signature. */+static int scan_for_signature(struct archive_read* a) {+ const uint8_t* p;+ const int chunk_size = 512;+ ssize_t i;+ char signature[sizeof(rar5_signature_xor)];++ /* If we're here, it means we're on an 'unknown territory' data.+ * There's no indication what kind of data we're reading here.+ * It could be some text comment, any kind of binary data,+ * digital sign, dragons, etc.+ *+ * We want to find a valid RARv5 magic header inside this unknown+ * data. */++ /* Is it possible in libarchive to just skip everything until the+ * end of the file? If so, it would be a better approach than the+ * current implementation of this function. */++ rar5_signature(signature);++ while(1) {+ if(!read_ahead(a, chunk_size, &p))+ return ARCHIVE_EOF;++ for(i = 0; i < chunk_size - (int)sizeof(rar5_signature_xor);+ i++) {+ if(memcmp(&p[i], signature,+ sizeof(rar5_signature_xor)) == 0) {+ /* Consume the number of bytes we've used to+ * search for the signature, as well as the+ * number of bytes used by the signature+ * itself. After this we should be standing+ * on a valid base block header. */+ (void) consume(a,+ i + sizeof(rar5_signature_xor));+ return ARCHIVE_OK;+ }+ }++ consume(a, chunk_size);+ }++ return ARCHIVE_FATAL;+}++/* This function will switch the multivolume archive file to another file,+ * i.e. from part03 to part 04. */+static int advance_multivolume(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ int lret;++ /* A small state machine that will skip unnecessary data, needed to+ * switch from one multivolume to another. Such skipping is needed if+ * we want to be an stream-oriented (instead of file-oriented)+ * unpacker.+ *+ * The state machine starts with `rar5->main.endarc` == 0. It also+ * assumes that current stream pointer points to some base block+ * header.+ *+ * The `endarc` field is being set when the base block parsing+ * function encounters the 'end of archive' marker.+ */++ while(1) {+ if(rar5->main.endarc == 1) {+ int looping = 1;++ rar5->main.endarc = 0;++ while(looping) {+ lret = skip_base_block(a);+ switch(lret) {+ case ARCHIVE_RETRY:+ /* Continue looping. */+ break;+ case ARCHIVE_OK:+ /* Break loop. */+ looping = 0;+ break;+ default:+ /* Forward any errors to the+ * caller. */+ return lret;+ }+ }++ break;+ } else {+ /* Skip current base block. In order to properly skip+ * it, we really need to simply parse it and discard+ * the results. */++ lret = skip_base_block(a);+ if(lret == ARCHIVE_FATAL || lret == ARCHIVE_FAILED)+ return lret;++ /* The `skip_base_block` function tells us if we+ * should continue with skipping, or we should stop+ * skipping. We're trying to skip everything up to+ * a base FILE block. */++ if(lret != ARCHIVE_RETRY) {+ /* If there was an error during skipping, or we+ * have just skipped a FILE base block... */++ if(rar5->main.endarc == 0) {+ return lret;+ } else {+ continue;+ }+ }+ }+ }++ return ARCHIVE_OK;+}++/* Merges the partial block from the first multivolume archive file, and+ * partial block from the second multivolume archive file. The result is+ * a chunk of memory containing the whole block, and the stream pointer+ * is advanced to the next block in the second multivolume archive file. */+static int merge_block(struct archive_read* a, ssize_t block_size,+ const uint8_t** p)+{+ struct rar5 *rar5 = a->format->data;+ ssize_t cur_block_size, partial_offset = 0;+ const uint8_t* lp;+ int ret;++ if(rar5->merge_mode) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Recursive merge is not allowed");++ return ARCHIVE_FATAL;+ }++ /* Set a flag that we're in the switching mode. */+ rar5->cstate.switch_multivolume = 1;++ /* Reallocate the memory which will hold the whole block. */+ if(rar5->vol.push_buf)+ free((void*) rar5->vol.push_buf);++ /* Increasing the allocation block by 8 is due to bit reading functions,+ * which are using additional 2 or 4 bytes. Allocating the block size+ * by exact value would make bit reader perform reads from invalid+ * memory block when reading the last byte from the buffer. */+ rar5->vol.push_buf = malloc(block_size + 8);+ if(!rar5->vol.push_buf) {+ archive_set_error(&a->archive, ENOMEM,+ "Can't allocate memory for a merge block buffer");+ rar5->cstate.switch_multivolume = 0;+ return ARCHIVE_FATAL;+ }++ /* Valgrind complains if the extension block for bit reader is not+ * initialized, so initialize it. */+ memset(&rar5->vol.push_buf[block_size], 0, 8);++ /* A single block can span across multiple multivolume archive files,+ * so we use a loop here. This loop will consume enough multivolume+ * archive files until the whole block is read. */++ while(1) {+ /* Get the size of current block chunk in this multivolume+ * archive file and read it. */+ cur_block_size = rar5_min(rar5->file.bytes_remaining,+ block_size - partial_offset);++ if(cur_block_size < 1) {+ /* bytes_remaining is less than 1 at the wrong point in+ * the merge loop, indicating corrupt volume+ * accounting. */+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Encountered invalid block size during block merge");+ rar5->cstate.switch_multivolume = 0;+ return ARCHIVE_FATAL;+ }++ if(!read_ahead(a, cur_block_size, &lp)) {+ rar5->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. */+ if(partial_offset + cur_block_size > block_size) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Consumed too much data when merging blocks");+ rar5->cstate.switch_multivolume = 0;+ return ARCHIVE_FATAL;+ }++ /* Merge previous block chunk with current block chunk,+ * or create first block chunk if this is our first+ * iteration. */+ memcpy(&rar5->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)) {+ /* Data was copied but stream pointer didn't advance;+ * stream position is unrecoverable. */+ rar5->cstate.switch_multivolume = 0;+ return ARCHIVE_FATAL;+ }++ /* Update the pointers. `partial_offset` contains information+ * about the sum of merged block chunks. */+ partial_offset += cur_block_size;+ rar5->file.bytes_remaining -= cur_block_size;++ /* If `partial_offset` is the same as `block_size`, this means+ * we've merged all block chunks and we have a valid full+ * block. */+ if(partial_offset == block_size) {+ break;+ }++ /* If we don't have any bytes to read, this means we should+ * switch to another multivolume archive file. */+ if(rar5->file.bytes_remaining == 0) {+ rar5->merge_mode++;+ ret = advance_multivolume(a);+ rar5->merge_mode--;+ if(ret != ARCHIVE_OK) {+ rar5->cstate.switch_multivolume = 0;+ return ret;+ }+ }+ }++ *p = rar5->vol.push_buf;++ /* If we're here, we can resume unpacking by processing the block+ * pointed to by the `*p` memory pointer. */++ return ARCHIVE_OK;+}++static int process_block(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ const uint8_t* p;+ int ret;++ /* If we don't have any data to be processed, this most probably means+ * we need to switch to the next volume. */+ if(rar5->main.volume && rar5->file.bytes_remaining == 0) {+ ret = advance_multivolume(a);+ if(ret != ARCHIVE_OK)+ return ret;+ }++ if(rar5->cstate.block_parsing_finished) {+ ssize_t block_size;+ ssize_t to_skip;+ ssize_t cur_block_size;++ /* The header size won't be bigger than 6 bytes. */+ if(!read_ahead(a, 6, &p)) {+ /* Failed to prefetch data block header. */+ return ARCHIVE_EOF;+ }++ /*+ * Read block_size by parsing block header. Validate the header+ * by calculating CRC byte stored inside the header. Size of+ * the header is not constant (block size can be stored either+ * in 1 or 2 bytes), that's why block size is left out from the+ * `compressed_block_header` structure and returned by+ * `parse_block_header` as the second argument. */++ ret = parse_block_header(a, p, &block_size,+ &rar5->last_block_hdr);+ if(ret != ARCHIVE_OK) {+ return ret;+ }++ /* Skip block header. Next data is huffman tables,+ * if present. */+ to_skip = sizeof(struct compressed_block_header) ++ bf_byte_count(&rar5->last_block_hdr) + 1;++ /* If the block header's to_skip value exceeds the declared+ * remaining data, the archive is malformed. */+ if(to_skip > rar5->file.bytes_remaining) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Block header size exceeds remaining file data");+ return ARCHIVE_FATAL;+ }++ if(ARCHIVE_OK != consume(a, to_skip))+ return ARCHIVE_EOF;++ rar5->file.bytes_remaining -= to_skip;++ /* The block size gives information about the whole block size,+ * but the block could be stored in split form when using+ * multi-volume archives. In this case, the block size will be+ * bigger than the actual data stored in this file. Remaining+ * part of the data will be in another file. */++ cur_block_size =+ rar5_min(rar5->file.bytes_remaining, block_size);++ if(block_size > rar5->file.bytes_remaining) {+ /* If current blocks' size is bigger than our data+ * size, this means we have a multivolume archive.+ * In this case, skip all base headers until the end+ * of the file, proceed to next "partXXX.rar" volume,+ * find its signature, skip all headers up to the first+ * FILE base header, and continue from there.+ *+ * Note that `merge_block` will update the `rar`+ * context structure quite extensively. */++ ret = merge_block(a, block_size, &p);+ if(ret != ARCHIVE_OK) {+ return ret;+ }++ cur_block_size = block_size;++ /* Current stream pointer should be now directly+ * *after* the block that spanned through multiple+ * archive files. `p` pointer should have the data of+ * the *whole* block (merged from partial blocks+ * stored in multiple archives files). */+ } else {+ rar5->cstate.switch_multivolume = 0;++ /* Read the whole block size into memory. This can take+ * up to 8 megabytes of memory in theoretical cases.+ * Might be worth to optimize this and use a standard+ * chunk of 4kb's. */+ if(!read_ahead(a, 4 + cur_block_size, &p)) {+ /* Failed to prefetch block data. */+ return ARCHIVE_EOF;+ }+ }++ rar5->cstate.block_buf = p;+ rar5->cstate.cur_block_size = cur_block_size;+ rar5->cstate.block_parsing_finished = 0;++ rar5->bits.in_addr = 0;+ rar5->bits.bit_addr = 0;++ if(bf_is_table_present(&rar5->last_block_hdr)) {+ /* Load Huffman tables. */+ ret = parse_tables(a, rar5, p);+ if(ret != ARCHIVE_OK) {+ /* Error during decompression of Huffman+ * tables. */+ return ret;+ }+ }+ } else {+ /* Block parsing not finished, reuse previous memory buffer. */+ p = rar5->cstate.block_buf;+ }++ /* Uncompress the block, or a part of it, depending on how many bytes+ * will be generated by uncompressing the block.+ *+ * In case too many bytes will be generated, calling this function+ * again will resume the uncompression operation. */+ ret = do_uncompress_block(a, p);+ if(ret != ARCHIVE_OK) {+ return ret;+ }++ if(rar5->cstate.block_parsing_finished &&+ rar5->cstate.switch_multivolume == 0 &&+ rar5->cstate.cur_block_size > 0)+ {+ /* If we're processing a normal block, consume the whole+ * block. We can do this because we've already read the whole+ * block to memory. */+ if(ARCHIVE_OK != consume(a, rar5->cstate.cur_block_size))+ return ARCHIVE_FATAL;++ rar5->file.bytes_remaining -= rar5->cstate.cur_block_size;+ } else if(rar5->cstate.switch_multivolume) {+ /* Don't consume the block if we're doing multivolume+ * processing. The volume switching function will consume+ * the proper count of bytes instead. */+ rar5->cstate.switch_multivolume = 0;+ }++ return ARCHIVE_OK;+}++/* Pops the `buf`, `size` and `offset` from the "data ready" stack.+ *+ * Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY+ * when there is no data on the stack. */+static int use_data(struct rar5 *rar5, const void** buf, size_t* size,+ int64_t* offset)+{+ int i;++ for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {+ struct data_ready *d = &rar5->cstate.dready[i];++ if(d->used) {+ if(buf) *buf = d->buf;+ if(size) *size = d->size;+ if(offset) *offset = d->offset;++ d->used = 0;+ return ARCHIVE_OK;+ }+ }++ return ARCHIVE_RETRY;+}++static void clear_data_ready_stack(struct rar5 *rar5) {+ memset(&rar5->cstate.dready, 0, sizeof(rar5->cstate.dready));+}++/* Pushes the `buf`, `size` and `offset` arguments to the rar5->cstate.dready+ * FIFO stack. Those values will be popped from this stack by the `use_data`+ * function. */+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,+ const uint8_t* buf, size_t size, int64_t offset)+{+ int i;++ /* Don't push if we're in skip mode. This is needed because solid+ * streams need full processing even if we're skipping data. After+ * fully processing the stream, we need to discard the generated bytes,+ * because we're interested only in the side effect: building up the+ * internal window circular buffer. This window buffer will be used+ * later during unpacking of requested data. */+ if(rar5->skip_mode)+ return ARCHIVE_OK;++ /* Sanity check. */+ if(offset != rar5->file.last_offset + rar5->file.last_size) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Sanity check error: output stream is not continuous");+ return ARCHIVE_FATAL;+ }++ for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {+ struct data_ready* d = &rar5->cstate.dready[i];+ if(!d->used) {+ d->used = 1;+ d->buf = buf;+ d->size = size;+ d->offset = offset;++ /* These fields are used only in sanity checking. */+ rar5->file.last_offset = offset;+ rar5->file.last_size = size;++ /* Calculate the checksum of this new block before+ * submitting data to libarchive's engine. */+ update_crc(rar5, d->buf, d->size);++ return ARCHIVE_OK;+ }+ }++ /* Program counter will reach this code if the+ * `rar5->cstate.data_ready` stack will be filled up so that no new+ * entries will be allowed. The code shouldn't allow such situation to+ * occur. So we treat this case as an internal error. */++ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Premature end of data_ready stack");+ return ARCHIVE_FATAL;+}++/* This function uncompresses the data that is stored in the <FILE> base+ * block.+ *+ * The FILE base block looks like this:+ *+ * <header><huffman tables><block_1><block_2>...<block_n>+ *+ * The <header> is a block header, that is parsed in parse_block_header().+ * It's a "compressed_block_header" structure, containing metadata needed+ * to know when we should stop looking for more <block_n> blocks.+ *+ * <huffman tables> contain data needed to set up the huffman tables, needed+ * for the actual decompression.+ *+ * Each <block_n> consists of series of literals:+ *+ * <literal><literal><literal>...<literal>+ *+ * Those literals generate the uncompression data. They operate on a circular+ * buffer, sometimes writing raw data into it, sometimes referencing+ * some previous data inside this buffer, and sometimes declaring a filter+ * that will need to be executed on the data stored in the circular buffer.+ * It all depends on the literal that is used.+ *+ * Sometimes blocks produce output data, sometimes they don't. For example, for+ * some huge files that use lots of filters, sometimes a block is filled with+ * only filter declaration literals. Such blocks won't produce any data in the+ * circular buffer.+ *+ * Sometimes blocks will produce 4 bytes of data, and sometimes 1 megabyte,+ * because a literal can reference previously decompressed data. For example,+ * there can be a literal that says: 'append a byte 0xFE here', and after+ * it another literal can say 'append 1 megabyte of data from circular buffer+ * offset 0x12345'. This is how RAR format handles compressing repeated+ * patterns.+ *+ * The RAR compressor creates those literals and the actual efficiency of+ * compression depends on what those literals are. The literals can also+ * be seen as a kind of a non-turing-complete virtual machine that simply+ * tells the decompressor what it should do.+ * */++static int do_uncompress_file(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ int ret;+ int64_t max_end_pos;++ if(!rar5->cstate.initialized) {+ /* Don't perform full context reinitialization if we're+ * processing a solid archive. */+ if(!rar5->main.solid || !rar5->cstate.window_buf) {+ if((ret = init_unpack(rar5)) != ARCHIVE_OK)+ return ret;+ }++ rar5->cstate.initialized = 1;+ }++ /* Don't allow extraction if window_size is invalid. */+ if(rar5->cstate.window_size == 0) {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Invalid window size declaration in this file");++ /* This should never happen in valid files. */+ return ARCHIVE_FAILED;+ }++ if(rar5->cstate.all_filters_applied == 1) {+ /* We use while(1) here, but standard case allows for just 1+ * iteration. The loop will iterate if process_block() didn't+ * generate any data at all. This can happen if the block+ * contains only filter definitions (this is common in big+ * files). */+ while(1) {+ ret = process_block(a);+ if(ret != ARCHIVE_OK)+ return ret;++ if(rar5->cstate.last_write_ptr ==+ rar5->cstate.write_ptr) {+ /* The block didn't generate any new data,+ * so just process a new block if this one+ * wasn't the last block in the file. */+ if (bf_is_last_block(&rar5->last_block_hdr)) {+ return ARCHIVE_EOF;+ }++ continue;+ }++ /* The block has generated some new data, so break+ * the loop. */+ break;+ }+ }++ /* Try to run filters. If filters won't be applied, it means that+ * insufficient data was generated. */+ ret = apply_filters(a);+ if(ret == ARCHIVE_RETRY) {+ return ARCHIVE_OK;+ } else if(ret != ARCHIVE_OK) {+ return ret;+ }++ if(cdeque_size(&rar5->cstate.filters) > 0) {+ /* Check if we can write something before hitting first+ * filter. */+ struct filter_info* flt;++ /* Get the block_start offset from the first filter. */+ if(CDE_OK != cdeque_front(&rar5->cstate.filters,+ cdeque_filter_p(&flt)))+ {+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_PROGRAMMER,+ "Can't read first filter");+ return ARCHIVE_FATAL;+ }++ max_end_pos = rar5_min(flt->block_start,+ rar5->cstate.write_ptr);+ } else {+ /* There are no filters defined, or all filters were applied.+ * This means we can just store the data without any+ * postprocessing. */+ max_end_pos = rar5->cstate.write_ptr;+ }++ if(max_end_pos == rar5->cstate.last_write_ptr) {+ /* We can't write anything yet. The block uncompression+ * function did not generate enough data, and no filter can be+ * applied. At the same time we don't have any data that can be+ * stored without filter postprocessing. This means we need to+ * wait for more data to be generated, so we can apply the+ * filters.+ *+ * Signal the caller that we need more data to be able to do+ * anything.+ */+ return ARCHIVE_RETRY;+ } else {+ /* We can write the data before hitting the first filter.+ * So let's do it. The push_window_data() function will+ * effectively return the selected data block to the user+ * application. */+ push_window_data(a, rar5, rar5->cstate.last_write_ptr,+ max_end_pos);+ rar5->cstate.last_write_ptr = max_end_pos;+ }++ return ARCHIVE_OK;+}++static int uncompress_file(struct archive_read* a) {+ int ret;++ while(1) {+ /* Sometimes the uncompression function will return a+ * 'retry' signal. If this will happen, we have to retry+ * the function. */+ ret = do_uncompress_file(a);+ if(ret != ARCHIVE_RETRY)+ return ret;+ }+}+++static int do_unstore_file(struct archive_read* a,+ struct rar5 *rar5, const void** buf, size_t* size, int64_t* offset)+{+ size_t to_read;+ const uint8_t* p;++ if(rar5->file.bytes_remaining == 0 && rar5->main.volume > 0 &&+ rar5->generic.split_after > 0)+ {+ int ret;++ rar5->cstate.switch_multivolume = 1;+ ret = advance_multivolume(a);+ rar5->cstate.switch_multivolume = 0;++ if(ret != ARCHIVE_OK) {+ /* Failed to advance to next multivolume archive+ * file. */+ return ret;+ }+ }++ to_read = rar5_min(rar5->file.bytes_remaining, 64 * 1024);+ if(to_read == 0) {+ return ARCHIVE_EOF;+ }++ if(!read_ahead(a, to_read, &p)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "I/O error when unstoring file");+ return ARCHIVE_FATAL;+ }++ if(ARCHIVE_OK != consume(a, to_read)) {+ return ARCHIVE_EOF;+ }++ if(buf) *buf = p;+ if(size) *size = to_read;+ if(offset) *offset = rar5->cstate.last_unstore_ptr;++ rar5->file.bytes_remaining -= to_read;+ rar5->cstate.last_unstore_ptr += to_read;++ update_crc(rar5, p, to_read);+ return ARCHIVE_OK;+}++static int do_unpack(struct archive_read* a, struct rar5 *rar5,+ const void** buf, size_t* size, int64_t* offset)+{+ enum COMPRESSION_METHOD {+ STORE = 0, FASTEST = 1, FAST = 2, NORMAL = 3, GOOD = 4,+ BEST = 5+ };++ if(rar5->file.service > 0) {+ return do_unstore_file(a, rar5, buf, size, offset);+ } else {+ switch(rar5->cstate.method) {+ case STORE:+ return do_unstore_file(a, rar5, buf, size,+ offset);+ case FASTEST:+ /* fallthrough */+ case FAST:+ /* fallthrough */+ case NORMAL:+ /* fallthrough */+ case GOOD:+ /* fallthrough */+ case BEST:+ /* No data is returned here. But because a sparse-file aware+ * caller (like archive_read_data_into_fd) may treat zero-size+ * as a sparse file block, we need to update the offset+ * accordingly. At this point the decoder doesn't have any+ * pending uncompressed data blocks, so the current position in+ * the output file should be last_write_ptr. */+ if (offset) *offset = rar5->cstate.last_write_ptr;+ return uncompress_file(a);+ default:+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Compression method not supported: 0x%x",+ (unsigned int)rar5->cstate.method);++ return ARCHIVE_FATAL;+ }+ }++#if !defined WIN32+ /* Not reached. */+ return ARCHIVE_OK;+#endif+}++static int verify_checksums(struct archive_read* a) {+ struct rar5 *rar5 = a->format->data;+ int verify_crc;++ /* Check checksums only when actually unpacking the data. There's no+ * need to calculate checksum when we're skipping data in solid archives+ * (skipping in solid archives is the same thing as unpacking compressed+ * data and discarding the result). */++ if(!rar5->skip_mode) {+ /* Always check checksums if we're not in skip mode */+ verify_crc = 1;+ } else {+ /* We can override the logic above with a compile-time option+ * NO_CRC_ON_SOLID_SKIP. This option is used during debugging,+ * and it will check checksums of unpacked data even when+ * we're skipping it. */++#if defined CHECK_CRC_ON_SOLID_SKIP+ /* Debug case */+ verify_crc = 1;+#else+ /* Normal case */+ verify_crc = 0;+#endif+ }++ if(verify_crc) {+ /* During unpacking, on each unpacked block we're calling the+ * update_crc() function. Since we are here, the unpacking+ * process is already over and we can check if calculated+ * checksum (CRC32 or BLAKE2sp) is the same as what is stored+ * in the archive. */+ if(rar5->file.stored_crc32 > 0) {+ /* Check CRC32 only when the file contains a CRC32+ * value for this file. */++ if(rar5->file.calculated_crc32 !=+ rar5->file.stored_crc32) {+ /* Checksums do not match; the unpacked file+ * is corrupted. */++ DEBUG_CODE {+ printf("Checksum error: CRC32 "+ "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",+ rar5->file.calculated_crc32,+ rar5->file.stored_crc32);+ }++#ifndef DONT_FAIL_ON_CRC_ERROR+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Checksum error: CRC32");+ return ARCHIVE_FAILED;+#endif+ } else {+ DEBUG_CODE {+ printf("Checksum OK: CRC32 "+ "(%08" PRIx32 "/%08" PRIx32 ")\n",+ rar5->file.stored_crc32,+ rar5->file.calculated_crc32);+ }+ }+ }++ if(rar5->file.has_blake2 > 0) {+ /* BLAKE2sp is an optional checksum algorithm that is+ * added to RARv5 archives when using the `-htb` switch+ * during creation of archive.+ *+ * We now finalize the hash calculation by calling the+ * `final` function. This will generate the final hash+ * value we can use to compare it with the BLAKE2sp+ * checksum that is stored in the archive.+ *+ * The return value of this `final` function is not+ * very helpful, as it guards only against improper use.+ * This is why we're explicitly ignoring it. */++ uint8_t b2_buf[32];+ (void) blake2sp_final(&rar5->file.b2state, b2_buf, 32);++ if(memcmp(&rar5->file.blake2sp, b2_buf, 32) != 0) {+#ifndef DONT_FAIL_ON_CRC_ERROR+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Checksum error: BLAKE2");++ return ARCHIVE_FAILED;+#endif+ }+ }+ }++ /* Finalization for this file has been successfully completed. */+ return ARCHIVE_OK;+}++static int verify_global_checksums(struct archive_read* a) {+ return verify_checksums(a);+}++/*+ * Decryption function for the magic signature pattern. Check the comment near+ * the `rar5_signature_xor` symbol to read the rationale behind this.+ */+static void rar5_signature(char *buf) {+ size_t i;++ for(i = 0; i < sizeof(rar5_signature_xor); i++) {+ buf[i] = rar5_signature_xor[i] ^ 0xA1;+ }+}++static int rar5_read_data(struct archive_read *a, const void **buff,+ size_t *size, int64_t *offset) {+ struct rar5 *rar5 = a->format->data;+ int ret;++ if (size)+ *size = 0;++ if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {+ rar5->has_encrypted_entries = 0;+ }++ if (rar5->headers_are_encrypted || rar5->cstate.data_encrypted) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Reading encrypted data is not currently supported");+ return ARCHIVE_FAILED;+ }++ if(rar5->file.dir > 0) {+ /* Don't process any data if this file entry was declared+ * as a directory. This is needed, because entries marked as+ * directory doesn't have any dictionary buffer allocated, so+ * it's impossible to perform any decompression. */+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Can't decompress an entry marked as a directory");+ return ARCHIVE_FATAL;+ }++ if(!rar5->skip_mode && (rar5->cstate.last_write_ptr > rar5->file.unpacked_size)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+ "Unpacker has written too many bytes");+ return ARCHIVE_FATAL;+ }++ ret = use_data(rar5, buff, size, offset);+ if(ret == ARCHIVE_OK) {+ return ret;+ }++ if(rar5->file.eof == 1) {+ return ARCHIVE_EOF;+ }++ ret = do_unpack(a, rar5, buff, size, offset);+ if(ret != ARCHIVE_OK) {+ return ret;+ }++ if(rar5->file.bytes_remaining == 0 &&+ rar5->cstate.last_write_ptr == rar5->file.unpacked_size)+ {+ /* If all bytes of current file were processed, run+ * finalization.+ *+ * Finalization will check checksum against proper values. If+ * some of the checksums will not match, we'll return an error+ * value in the last `archive_read_data` call to signal an error+ * to the user. */++ rar5->file.eof = 1;+ return verify_global_checksums(a);+ }++ return ARCHIVE_OK;+}++static int rar5_read_data_skip(struct archive_read *a) {+ struct rar5 *rar5 = a->format->data;++ if(rar5->main.solid && (rar5->cstate.data_encrypted == 0)) {+ /* In solid archives, instead of skipping the data, we need to+ * extract it, and dispose the result. The side effect of this+ * operation will be setting up the initial window buffer state+ * needed to be able to extract the selected file. Note that+ * this is only possible when data within this solid block is+ * not encrypted, in which case we'll skip and fail if the user+ * tries to read data. */++ int ret;++ /* Make sure to process all blocks in the compressed stream. */+ while(rar5->file.bytes_remaining > 0) {+ /* Setting the "skip mode" will allow us to skip+ * checksum checks during data skipping. Checking the+ * checksum of skipped data isn't really necessary and+ * it's only slowing things down.+ *+ * This is incremented instead of setting to 1 because+ * this data skipping function can be called+ * recursively. */+ rar5->skip_mode++;++ /* We're disposing 1 block of data, so we use triple+ * NULLs in arguments. */+ ret = rar5_read_data(a, NULL, NULL, NULL);++ /* Turn off "skip mode". */+ rar5->skip_mode--;++ if(ret < 0 || ret == ARCHIVE_EOF) {+ /* Propagate any potential error conditions+ * to the caller. */+ return ret;+ }+ }+ } else {+ /* In standard archives, we can just jump over the compressed+ * stream. Each file in non-solid archives starts from an empty+ * window buffer. */++ if(ARCHIVE_OK != consume(a, rar5->file.bytes_remaining)) {+ return ARCHIVE_FATAL;+ }++ rar5->file.bytes_remaining = 0;+ }++ return ARCHIVE_OK;+}++static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,+ int whence)+{+ (void) offset;+ (void) whence;++ /* We're a streaming unpacker, and we don't support seeking.+ * That's a capability gap, not a fatal error. */+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "Seeking of RAR5 files is unsupported");++ return (ARCHIVE_FAILED);+}++static int rar5_cleanup(struct archive_read *a) {+ struct rar5 *rar5 = a->format->data;++ free(rar5->cstate.window_buf);+ free(rar5->cstate.filtered_buf);+ clear_data_ready_stack(rar5);++ free(rar5->vol.push_buf);++ free_filters(rar5);+ rar5_deinit(rar5);++ free(rar5);+ a->format->data = NULL;++ return ARCHIVE_OK;+}++static int rar5_capabilities(struct archive_read * a) {+ (void) a;+ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA+ | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);+}++static int rar5_has_encrypted_entries(struct archive_read *_a) {+ if (_a && _a->format) {+ struct rar5 *rar5 = _a->format->data;+ if (rar5) {+ return rar5->has_encrypted_entries;+ }+ }++ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;+}++/* Must match deallocations in rar5_deinit */+static int rar5_init(struct rar5 *rar5) {+ memset(rar5, 0, sizeof(struct rar5));++ if(CDE_OK != cdeque_init(&rar5->cstate.filters, 8192))+ return ARCHIVE_FATAL;++ /*+ * Until enough data has been read, we cannot tell about+ * any encrypted entries yet.+ */+ rar5->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;++ return ARCHIVE_OK;+}++/* Must match allocations in rar5_init */+static void rar5_deinit(struct rar5 *rar5) {+ cdeque_free(&rar5->cstate.filters);+}++int archive_read_support_format_rar5(struct archive *_a) {+ struct archive_read* ar;+ int ret;+ struct rar5 *rar5;++ if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))+ return ret;++ rar5 = malloc(sizeof(*rar5));+ if(rar5 == NULL) {+ archive_set_error(&ar->archive, ENOMEM,+ "Can't allocate rar5 data");+ return ARCHIVE_FATAL;+ }++ if(ARCHIVE_OK != rar5_init(rar5)) {+ archive_set_error(&ar->archive, ENOMEM,+ "Can't allocate rar5 filter buffer");+ free(rar5);+ return ARCHIVE_FATAL;+ }++ ret = __archive_read_register_format(ar,+ rar5,+ "rar5",+ rar5_bid,+ rar5_options,+ rar5_read_header,+ rar5_read_data,+ rar5_read_data_skip,+ rar5_seek_data,+ rar5_cleanup,+ rar5_capabilities,+ rar5_has_encrypted_entries);++ if(ret != ARCHIVE_OK) {+ rar5_deinit(rar5);+ free(rar5); } return ARCHIVE_OK;
c/archive_read_support_format_raw.c view
@@ -34,10 +34,11 @@ #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" -struct raw_info {+struct raw { int64_t offset; /* Current position in the file. */ int64_t unconsumed; int end_of_file;@@ -54,22 +55,22 @@ int archive_read_support_format_raw(struct archive *_a) {- struct raw_info *info; struct archive_read *a = (struct archive_read *)_a;+ struct raw *raw; int r; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_raw"); - info = calloc(1, sizeof(*info));- if (info == NULL) {+ raw = calloc(1, sizeof(*raw));+ if (raw == NULL) { archive_set_error(&a->archive, ENOMEM,- "Can't allocate raw_info data");+ "Can't allocate raw data"); return (ARCHIVE_FATAL); } r = __archive_read_register_format(a,- info,+ raw, "raw", archive_read_format_raw_bid, NULL,@@ -81,7 +82,7 @@ NULL, NULL); if (r != ARCHIVE_OK)- free(info);+ free(raw); return (r); } @@ -107,10 +108,9 @@ archive_read_format_raw_read_header(struct archive_read *a, struct archive_entry *entry) {- struct raw_info *info;+ struct raw *raw = a->format->data; - info = (struct raw_info *)(a->format->data);- if (info->end_of_file)+ if (raw->end_of_file) return (ARCHIVE_EOF); a->archive.archive_format = ARCHIVE_FORMAT_RAW;@@ -128,39 +128,43 @@ archive_read_format_raw_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct raw_info *info;+ struct raw *raw = a->format->data; ssize_t avail; - info = (struct raw_info *)(a->format->data);- /* Consume the bytes we read last time. */- if (info->unconsumed) {- __archive_read_consume(a, info->unconsumed);- info->unconsumed = 0;+ if (raw->unconsumed) {+ __archive_read_consume(a, raw->unconsumed);+ raw->unconsumed = 0; } - if (info->end_of_file)+ if (raw->end_of_file) return (ARCHIVE_EOF); /* Get whatever bytes are immediately available. */ *buff = __archive_read_ahead(a, 1, &avail); if (avail > 0) { /* Return the bytes we just read */+ *offset = raw->offset;+ if (archive_ckd_add_i64(&raw->offset, raw->offset, avail)) {+ avail = INT64_MAX - *offset;+ if (avail == 0) {+ *size = 0;+ return (ARCHIVE_FATAL);+ }+ } *size = avail;- *offset = info->offset;- info->offset += *size;- info->unconsumed = avail;+ raw->unconsumed = avail; return (ARCHIVE_OK); } else if (0 == avail) { /* Record and return end-of-file. */- info->end_of_file = 1;+ raw->end_of_file = 1; *size = 0;- *offset = info->offset;+ *offset = raw->offset; return (ARCHIVE_EOF); } else { /* Record and return an error. */ *size = 0;- *offset = info->offset;+ *offset = raw->offset; return ((int)avail); } }@@ -168,24 +172,23 @@ static int archive_read_format_raw_read_data_skip(struct archive_read *a) {- struct raw_info *info = (struct raw_info *)(a->format->data);+ struct raw *raw = a->format->data; /* Consume the bytes we read last time. */- if (info->unconsumed) {- __archive_read_consume(a, info->unconsumed);- info->unconsumed = 0;+ if (raw->unconsumed) {+ __archive_read_consume(a, raw->unconsumed);+ raw->unconsumed = 0; }- info->end_of_file = 1;+ raw->end_of_file = 1; return (ARCHIVE_OK); } static int archive_read_format_raw_cleanup(struct archive_read *a) {- struct raw_info *info;+ struct raw *raw = a->format->data; - info = (struct raw_info *)(a->format->data);- free(info);+ free(raw); a->format->data = NULL; return (ARCHIVE_OK); }
c/archive_read_support_format_tar.c view
@@ -251,36 +251,6 @@ static const size_t acl_limit = 131072; /* Longest textual ACL: 128kiB */ static const int64_t entry_limit = 0xfffffffffffffffLL; /* 2^60 bytes = 1 ExbiByte */ -/*- * There's no standard for TIME_T_MAX. So we compute it- * here. TODO: Move this to configure time, but be careful- * about cross-compile environments.- */-static time_t-get_time_t_max(void)-{-#if defined(TIME_T_MAX)- return TIME_T_MAX;-#else- /* ISO C allows time_t to be a floating-point type,- but POSIX requires an integer type. The following- should work on any system that follows the POSIX- conventions. */- if (((time_t)0) < ((time_t)-1)) {- /* Time_t is unsigned */- return (~(time_t)0);- } else {- /* Time_t is signed. */- /* Assume it's the same as int64_t or int32_t */- if (sizeof(time_t) == sizeof(int64_t)) {- return (time_t)INT64_MAX;- } else {- return (time_t)INT32_MAX;- }- }-#endif-}- int archive_read_support_format_gnutar(struct archive *a) {@@ -330,9 +300,8 @@ static int archive_read_format_tar_cleanup(struct archive_read *a) {- struct tar *tar;+ struct tar *tar = a->format->data; - tar = (struct tar *)(a->format->data); gnu_clear_sparse_list(tar); archive_string_free(&tar->entry_pathname); archive_string_free(&tar->entry_pathname_override);@@ -342,7 +311,7 @@ archive_string_free(&tar->line); archive_string_free(&tar->localname); free(tar);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } @@ -469,10 +438,9 @@ archive_read_format_tar_options(struct archive_read *a, const char *key, const char *val) {- struct tar *tar;+ struct tar *tar = a->format->data; int ret = ARCHIVE_FAILED; - tar = (struct tar *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { /* Handle UTF-8 filenames as libarchive 2.x */ tar->compat_2x = (val != NULL && val[0] != 0);@@ -555,15 +523,13 @@ * probably not worthwhile just to support the relatively * obscure tar->cpio conversion case. */- struct tar *tar;+ struct tar *tar = a->format->data; const char *p; const wchar_t *wp; int r; size_t l; int64_t unconsumed = 0; - tar = (struct tar *)(a->format->data);- /* Assign default device/inode values. */ archive_entry_set_dev(entry, 1 + tar->default_dev); /* Don't use zero. */ archive_entry_set_ino(entry, ++tar->default_inode); /* Don't use zero. */@@ -639,12 +605,10 @@ archive_read_format_tar_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct tar *tar = a->format->data; ssize_t bytes_read;- struct tar *tar; struct sparse_block *p; - tar = (struct tar *)(a->format->data);- for (;;) { /* Remove exhausted entries from sparse list. */ while (tar->sparse_list != NULL &&@@ -703,11 +667,9 @@ static int archive_read_format_tar_skip(struct archive_read *a) {+ struct tar *tar = a->format->data; int64_t request;- struct tar* tar; - tar = (struct tar *)(a->format->data);- request = tar->entry_bytes_remaining + tar->entry_padding + tar->entry_bytes_unconsumed; @@ -1104,21 +1066,19 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, struct archive_entry *entry, const void *h, int64_t *unconsumed) {- const struct archive_entry_header_ustar *header; struct archive_string acl_text; size_t size; int err, acl_type; uint64_t type; char *acl, *p; - header = (const struct archive_entry_header_ustar *)h;- size = (size_t)tar_atol(header->size, sizeof(header->size)); archive_string_init(&acl_text); err = read_body_to_string(a, tar, &acl_text, h, unconsumed); if (err != ARCHIVE_OK) { archive_string_free(&acl_text); return (err); }+ size = archive_strlen(&acl_text); /* TODO: Examine the first characters to see if this * is an AIX ACL descriptor. We'll likely never support@@ -1377,6 +1337,7 @@ const struct archive_entry_header_ustar *header; const char *existing_linkpath; const wchar_t *existing_wcs_linkpath;+ mode_t header_mode; int err = ARCHIVE_OK; header = (const struct archive_entry_header_ustar *)h;@@ -1384,12 +1345,10 @@ /* Parse out the numeric fields (all are octal) */ /* Split mode handling: Set filetype always, perm only if not already set */- archive_entry_set_filetype(entry,- (mode_t)tar_atol(header->mode, sizeof(header->mode)));- if (!archive_entry_perm_is_set(entry)) {- archive_entry_set_perm(entry,- (mode_t)tar_atol(header->mode, sizeof(header->mode)));- }+ header_mode = (mode_t)tar_atol(header->mode, sizeof(header->mode));+ archive_entry_set_filetype(entry, header_mode);+ if (!archive_entry_perm_is_set(entry))+ archive_entry_set_perm(entry, header_mode); /* Set uid, gid, mtime if not already set */ if (!archive_entry_uid_is_set(entry)) {@@ -1402,7 +1361,7 @@ int64_t t64 = tar_atol(header->mtime, sizeof(header->mtime)); time_t t = (time_t)t64; if ((int64_t)t != t64) { /* time_t overflowed */- t = get_time_t_max();+ t = TIME_MAX; } archive_entry_set_mtime(entry, t, 0); }@@ -1679,33 +1638,33 @@ const char *p, *name; const wchar_t *wp, *wname; - wname = wp = archive_entry_pathname_w(entry);- if (wp != NULL) {+ name = p = archive_entry_pathname(entry);+ if (p != NULL) { /* Find the last path element. */- for (; *wp != L'\0'; ++wp) {- if (wp[0] == '/' && wp[1] != L'\0')- wname = wp + 1;+ for (; *p != '\0'; ++p) {+ if (p[0] == '/' && p[1] != '\0')+ name = p + 1; } /* * If last path element starts with "._", then * this is a Mac extension. */- if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')+ if (name[0] == '.' && name[1] == '_' && name[2] != '\0') return 1; } else { /* Find the last path element. */- name = p = archive_entry_pathname(entry);- if (p == NULL)- return (ARCHIVE_FAILED);- for (; *p != '\0'; ++p) {- if (p[0] == '/' && p[1] != '\0')- name = p + 1;+ wname = wp = archive_entry_pathname_w(entry);+ if (wp == NULL)+ return 0;+ for (; *wp != L'\0'; ++wp) {+ if (wp[0] == L'/' && wp[1] != L'\0')+ wname = wp + 1; } /* * If last path element starts with "._", then * this is a Mac extension. */- if (name[0] == '.' && name[1] == '_' && name[2] != '\0')+ if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0') return 1; } /* Not a mac extension */@@ -1787,7 +1746,6 @@ const struct archive_entry_header_ustar *header; int64_t size, to_consume; - (void)a; /* UNUSED */ (void)tar; /* UNUSED */ (void)entry; /* UNUSED */ @@ -1799,6 +1757,11 @@ (long long)size); return (ARCHIVE_FATAL); }+ if (size == 0) {+ archive_set_error(&a->archive, EINVAL,+ "Invalid empty pax global extended header");+ return (ARCHIVE_FATAL);+ } to_consume = ((size + 511) & ~511); *unconsumed += to_consume; return (ARCHIVE_OK);@@ -1945,6 +1908,11 @@ (long long)ext_size); return (ARCHIVE_FATAL); }+ if (ext_size == 0) {+ archive_set_error(&a->archive, EINVAL,+ "Invalid empty pax extended header");+ return (ARCHIVE_FATAL);+ } ext_padding = 0x1ff & (-ext_size); if (ext_size > ext_size_limit) {@@ -3056,6 +3024,7 @@ header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *entry, const void *h, int64_t *unconsumed) {+ struct archive_entry_header_gnutar header_copy; const struct archive_entry_header_gnutar *header; int64_t t; int err = ARCHIVE_OK;@@ -3066,8 +3035,14 @@ * filename is stored as in old-style archives. */ + /*+ * Sparse extension reads can reuse the callback buffer containing h,+ * so preserve the main header until common fields are parsed.+ */+ memcpy(&header_copy, h, sizeof(header_copy));+ header = &header_copy;+ /* Copy filename over (to ensure null termination). */- header = (const struct archive_entry_header_gnutar *)h; const char *existing_pathname = archive_entry_pathname(entry); const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry); if ((existing_pathname == NULL || existing_pathname[0] == '\0')@@ -3146,7 +3121,7 @@ } /* Grab fields common to all tar variants. */- err = header_common(a, tar, entry, h);+ err = header_common(a, tar, entry, header); if (err == ARCHIVE_FATAL) return (err); @@ -3469,13 +3444,10 @@ return (ARCHIVE_FATAL); tar->sparse_last->hole = hole; }- if (length == 0 || *e == '\n') {- if (length == 0 && *e == '\n') {- return (ARCHIVE_OK);- } else {- return (ARCHIVE_WARN);- }- }+ if (length == 0)+ return (ARCHIVE_OK);+ if (*e == '\n')+ return (ARCHIVE_WARN); p = e + 1; length--; hole = hole == 0;@@ -3538,17 +3510,17 @@ } l = 0;- if (char_cnt != 0) {+ while (char_cnt != 0) { digit = *p - '0';- while (digit >= 0 && digit < base && char_cnt != 0) {- if (archive_ckd_mul_i64(&l, l, base) ||- archive_ckd_add_i64(&l, l, sign * digit)) {- /* Truncate on overflow. */- return sign < 0 ? INT64_MIN : INT64_MAX;- }- digit = *++p - '0';- char_cnt--;+ if (digit < 0 || digit >= base)+ break;+ if (archive_ckd_mul_i64(&l, l, base) ||+ archive_ckd_add_i64(&l, l, sign * digit)) {+ /* Truncate on overflow. */+ return sign < 0 ? INT64_MIN : INT64_MAX; }+ p++;+ char_cnt--; } return l; }
c/archive_read_support_format_warc.c view
@@ -25,28 +25,35 @@ #include "archive_platform.h" -/**- * WARC is standardised by ISO TC46/SC4/WG12 and currently available as- * ISO 28500:2009.- * For the purposes of this file we used the final draft from:+/*+ * An overview of WARC format:+ *+ * WARC files are laid out as a sequence of records. Each record has+ * a text header followed by a content block whose size is given by+ * Content-Length. This reader supports WARC/0.12 through WARC/1.0+ * and was written using the final draft that became ISO 28500:2009: * http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf *- * Todo:- * [ ] real-world warcs can contain resources at endpoints ending in /- * e.g. http://bibnum.bnf.fr/warc/- * if you're lucky their response contains a Content-Location: header- * pointing to a unix-compliant filename, in the example above it's- * Content-Location: http://bibnum.bnf.fr/warc/index.html- * however, that's not mandated and github for example doesn't follow- * this convention.- * We need a set of archive options to control what to do with- * entries like these, at the moment care is taken to skip them.+ * This reader exposes resource and response records as regular files+ * when they have a usable WARC-Target-URI. WARC-Date is exposed as+ * ctime, and a Last-Modified record header is exposed as mtime when+ * present. *- **/+ * TODO: Real-world WARCs can contain resources at endpoints ending in+ * a slash, for example http://bibnum.bnf.fr/warc/. Some responses+ * include a Content-Location header that points to a Unix-compatible+ * filename such as http://bibnum.bnf.fr/warc/index.html, but WARC does+ * not require that convention and some sites do not follow it. Until+ * archive options exist to control these entries, this reader skips+ * them instead of creating directory endpoints as files.+ */ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif+#ifdef HAVE_CTYPE_H+#include <ctype.h>+#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif@@ -56,40 +63,35 @@ #ifdef HAVE_STRING_H #include <string.h> #endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_CTYPE_H-#include <ctype.h>-#endif #ifdef HAVE_TIME_H #include <time.h> #endif #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" typedef enum { WT_NONE,- /* warcinfo */+ /* WARC info */ WT_INFO,- /* metadata */+ /* Metadata */ WT_META,- /* resource */+ /* Resource */ WT_RSRC,- /* request, unsupported */+ /* Request, unsupported */ WT_REQ,- /* response, unsupported */+ /* Response */ WT_RSP,- /* revisit, unsupported */+ /* Revisit, unsupported */ WT_RVIS,- /* conversion, unsupported */+ /* Conversion, unsupported */ WT_CONV,- /* continuation, unsupported at the moment */+ /* Continuation, currently unsupported */ WT_CONT,- /* invalid type */+ /* Invalid type */ LAST_WT } warc_type_t; @@ -103,82 +105,92 @@ char *str; } warc_strbuf_t; -struct warc_s {- /* content length ahead */- size_t cntlen;- /* and how much we've processed so far */- size_t cntoff;- /* and how much we need to consume between calls */- size_t unconsumed;+struct warc {+ /* Content length of the current record */+ int64_t cntlen;+ /* Bytes processed from the current record */+ int64_t cntoff;+ /* Bytes to consume before the next read */+ int64_t unconsumed; - /* string pool */+ /* String pool */ warc_strbuf_t pool;- /* previous version */+ /* Previous version */ unsigned int pver;- /* stringified format name */+ /* Stringified format name */ struct archive_string sver; }; -static int _warc_bid(struct archive_read *a, int);-static int _warc_cleanup(struct archive_read *a);-static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);-static int _warc_skip(struct archive_read *a);-static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);+static int archive_read_format_warc_bid(struct archive_read *, int);+static int archive_read_format_warc_cleanup(struct archive_read *);+static int archive_read_format_warc_read_data(struct archive_read *,+ const void **, size_t *, int64_t *);+static int archive_read_format_warc_skip(struct archive_read *);+static int archive_read_format_warc_read_header(struct archive_read *,+ struct archive_entry *); -/* private routines */-static unsigned int _warc_rdver(const char *buf, size_t bsz);-static unsigned int _warc_rdtyp(const char *buf, size_t bsz);-static warc_string_t _warc_rduri(const char *buf, size_t bsz);-static ssize_t _warc_rdlen(const char *buf, size_t bsz);-static time_t _warc_rdrtm(const char *buf, size_t bsz);-static time_t _warc_rdmtm(const char *buf, size_t bsz);-static const char *_warc_find_eoh(const char *buf, size_t bsz);-static const char *_warc_find_eol(const char *buf, size_t bsz);+/* Private routines */+static unsigned int warc_read_version(const char *, size_t);+static unsigned int warc_read_type(const char *, size_t);+static warc_string_t warc_read_uri(const char *, size_t);+static int64_t warc_read_length(const char *, size_t);+static time_t warc_read_date(const char *, size_t);+static time_t warc_read_last_modified(const char *, size_t);+static const char *warc_find_eoh(const char *, size_t);+static const char *warc_find_eol(const char *, size_t); int archive_read_support_format_warc(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a;- struct warc_s *w;+ struct warc *warc; int r; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_warc"); - if ((w = calloc(1, sizeof(*w))) == NULL) {+ if ((warc = calloc(1, sizeof(*warc))) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate warc data"); return (ARCHIVE_FATAL); } - r = __archive_read_register_format(- a, w, "warc",- _warc_bid, NULL, _warc_rdhdr, _warc_read,- _warc_skip, NULL, _warc_cleanup, NULL, NULL);+ r = __archive_read_register_format(a,+ warc,+ "warc",+ archive_read_format_warc_bid,+ NULL,+ archive_read_format_warc_read_header,+ archive_read_format_warc_read_data,+ archive_read_format_warc_skip,+ NULL,+ archive_read_format_warc_cleanup,+ NULL,+ NULL); if (r != ARCHIVE_OK) {- free(w);+ free(warc); return (r); } return (ARCHIVE_OK); } static int-_warc_cleanup(struct archive_read *a)+archive_read_format_warc_cleanup(struct archive_read *a) {- struct warc_s *w = a->format->data;+ struct warc *warc = a->format->data; - if (w->pool.len > 0U) {- free(w->pool.str);+ if (warc->pool.len > 0U) {+ free(warc->pool.str); }- archive_string_free(&w->sver);- free(w);+ archive_string_free(&warc->sver);+ free(warc); a->format->data = NULL; return (ARCHIVE_OK); } static int-_warc_bid(struct archive_read *a, int best_bid)+archive_read_format_warc_bid(struct archive_read *a, int best_bid) { const char *hdr; ssize_t nrd;@@ -186,55 +198,52 @@ (void)best_bid; /* UNUSED */ - /* check first line of file, it should be a record already */- if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {- /* no idea what to do */- return -1;- } else if (nrd < 12) {- /* nah, not for us, our magic cookie is at least 12 bytes */+ /* Check the first line, which should already be a record header. */+ if ((hdr = __archive_read_ahead(a, 12, &nrd)) == NULL) {+ /* Not enough data to identify this format. */ return -1; } - /* otherwise snarf the record's version number */- ver = _warc_rdver(hdr, nrd);+ /* Parse the record version number. */+ ver = warc_read_version(hdr, nrd); if (ver < 1200U || ver > 10000U) {- /* we only support WARC 0.12 to 1.0 */+ /* Only WARC 0.12 through WARC 1.0 are supported. */ return -1; } - /* otherwise be confident */+ /* WARC magic and version checks passed. */ return (64); } static int-_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)+archive_read_format_warc_read_header(struct archive_read *a,+ struct archive_entry *entry) { #define HDR_PROBE_LEN (12U)- struct warc_s *w = a->format->data;+ struct warc *warc = a->format->data; unsigned int ver; const char *buf; ssize_t nrd; const char *eoh; char *tmp;- /* for the file name, saves some strndup()'ing */+ /* Reuse the header buffer while parsing the file name. */ warc_string_t fnam;- /* warc record type, not that we really use it a lot */+ /* WARC record type */ warc_type_t ftyp;- /* content-length+error monad */- ssize_t cntlen;- /* record time is the WARC-Date time we reinterpret it as ctime */+ /* Content length, or a negative error indicator */+ int64_t cntlen;+ /* WARC-Date is exposed as the entry ctime. */ time_t rtime;- /* mtime is the Last-Modified time which will be the entry's mtime */+ /* A Last-Modified record header is exposed as the entry mtime. */ time_t mtime; start_over:- /* just use read_ahead() they keep track of unconsumed- * bits and bobs for us; no need to put an extra shift in- * and reproduce that functionality here */+ /* Use read_ahead(); it already tracks unconsumed bytes, so this+ * reader does not need a separate shift buffer. */ buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd); if (nrd < 0) {- /* no good */+ /* I/O or stream error. */ archive_set_error( &a->archive, ARCHIVE_ERRNO_MISC, "Bad record header");@@ -244,19 +253,17 @@ * must be EOF therefore */ return (ARCHIVE_EOF); }- /* looks good so far, try and find the end of the header now */- eoh = _warc_find_eoh(buf, nrd);+ /* Locate the end of the record header. */+ eoh = warc_find_eoh(buf, nrd); if (eoh == NULL) {- /* still no good, the header end might be beyond the- * probe we've requested, but then again who'd cram- * so much stuff into the header *and* be 28500-compliant */+ /* The header terminator was not found in the probed data. */ archive_set_error( &a->archive, ARCHIVE_ERRNO_MISC, "Bad record header"); return (ARCHIVE_FATAL); }- ver = _warc_rdver(buf, eoh - buf);- /* we currently support WARC 0.12 to 1.0 */+ ver = warc_read_version(buf, eoh - buf);+ /* Only WARC 0.12 through WARC 1.0 are supported. */ if (ver == 0U) { archive_set_error( &a->archive, ARCHIVE_ERRNO_MISC,@@ -269,78 +276,73 @@ ver / 10000, (ver % 10000) / 100); return (ARCHIVE_FATAL); }- cntlen = _warc_rdlen(buf, eoh - buf);+ cntlen = warc_read_length(buf, eoh - buf); if (cntlen < 0) {- /* nightmare! the specs say content-length is mandatory- * so I don't feel overly bad stopping the reader here */+ /* This reader requires Content-Length before processing a record. */ archive_set_error( &a->archive, EINVAL, "Bad content length"); return (ARCHIVE_FATAL); }- rtime = _warc_rdrtm(buf, eoh - buf);+ rtime = warc_read_date(buf, eoh - buf); if (rtime == (time_t)-1) {- /* record time is mandatory as per WARC/1.0,- * so just barf here, fast and loud */+ /* This reader requires WARC-Date before processing a record. */ archive_set_error( &a->archive, EINVAL, "Bad record time"); return (ARCHIVE_FATAL); } - /* let the world know we're a WARC archive */+ /* Report this archive as WARC. */ a->archive.archive_format = ARCHIVE_FORMAT_WARC;- if (ver != w->pver) {- /* stringify this entry's version */- archive_string_sprintf(&w->sver,+ if (ver != warc->pver) {+ /* Format this entry's WARC version. */+ archive_string_sprintf(&warc->sver, "WARC/%u.%u", ver / 10000, (ver % 10000) / 100);- /* remember the version */- w->pver = ver;+ /* Remember the version for later entries. */+ warc->pver = ver; }- /* start off with the type */- ftyp = _warc_rdtyp(buf, eoh - buf);- /* and let future calls know about the content */- w->cntlen = cntlen;- w->cntoff = 0U;- mtime = 0;/* Avoid compiling error on some platform. */+ /* Parse the record type. */+ ftyp = warc_read_type(buf, eoh - buf);+ /* Save content state for subsequent read calls. */+ warc->cntlen = cntlen;+ warc->cntoff = 0;+ mtime = 0;/* Avoid compiler warnings on some platforms. */ switch (ftyp) { case WT_RSRC: case WT_RSP:- /* only try and read the filename in the cases that are- * guaranteed to have one */- fnam = _warc_rduri(buf, eoh - buf);- /* check the last character in the URI to avoid creating- * directory endpoints as files, see Todo above */+ /* Read the filename only for record types that are expected to+ * have a target URI. */+ fnam = warc_read_uri(buf, eoh - buf);+ /* Avoid creating directory endpoints as files. */ if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {- /* break here for now */+ /* Skip this record. */ fnam.len = 0U; fnam.str = NULL; break; }- /* bang to our string pool, so we save a- * malloc()+free() roundtrip */- if (fnam.len + 1U > w->pool.len) {- w->pool.len = ((fnam.len + 64U) / 64U) * 64U;- tmp = realloc(w->pool.str, w->pool.len);+ /* Copy the name into the reusable string pool to avoid a malloc/free+ * roundtrip for each entry. */+ if (fnam.len + 1U > warc->pool.len) {+ warc->pool.len = ((fnam.len + 64U) / 64U) * 64U;+ tmp = realloc(warc->pool.str, warc->pool.len); if (tmp == NULL) { archive_set_error( &a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); }- w->pool.str = tmp;+ warc->pool.str = tmp; }- memcpy(w->pool.str, fnam.str, fnam.len);- w->pool.str[fnam.len] = '\0';- /* let no one else know about the pool, it's a secret, shhh */- fnam.str = w->pool.str;+ memcpy(warc->pool.str, fnam.str, fnam.len);+ warc->pool.str[fnam.len] = '\0';+ /* Hide the pool implementation behind the parsed string. */+ fnam.str = warc->pool.str; - /* snarf mtime or deduce from rtime- * this is a custom header added by our writer, it's quite- * hard to believe anyone else would go through with it- * (apart from being part of some http responses of course) */- if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {+ /* Use a Last-Modified record header when present; otherwise fall back+ * to WARC-Date. */+ if ((mtime = warc_read_last_modified(buf, eoh - buf)) == (time_t)-1) { mtime = rtime; } break;@@ -358,19 +360,19 @@ break; } - /* now eat some of those delicious buffer bits */+ /* Consume the record header. */ __archive_read_consume(a, eoh - buf); switch (ftyp) { case WT_RSRC: case WT_RSP: if (fnam.len > 0U) {- /* populate entry object */+ /* Populate the entry object. */ archive_entry_set_filetype(entry, AE_IFREG); archive_entry_copy_pathname(entry, fnam.str); archive_entry_set_size(entry, cntlen); archive_entry_set_perm(entry, 0644);- /* rtime is the new ctime, mtime stays mtime */+ /* WARC-Date becomes ctime; mtime comes from Last-Modified or WARC-Date. */ archive_entry_set_ctime(entry, rtime, 0L); archive_entry_set_mtime(entry, mtime, 0L); break;@@ -385,8 +387,8 @@ case WT_CONT: case LAST_WT: default:- /* consume the content and start over */- if (_warc_skip(a) < 0)+ /* Skip this record body and look for the next one. */+ if (archive_read_format_warc_skip(a) < 0) return (ARCHIVE_FATAL); goto start_over; }@@ -394,62 +396,69 @@ } static int-_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)+archive_read_format_warc_read_data(struct archive_read *a, const void **buf,+ size_t *bsz, int64_t *off) {- struct warc_s *w = a->format->data;+ struct warc *warc = a->format->data; const char *rab; ssize_t nrd; - if (w->cntoff >= w->cntlen) {- eof:- /* it's our lucky day, no work, we can leave early */+ if (warc->unconsumed) {+ __archive_read_consume(a, warc->unconsumed);+ warc->unconsumed = 0;+ }++ if (warc->cntoff >= warc->cntlen) {+ /* No data is available to return for this entry. */ *buf = NULL; *bsz = 0U;- *off = w->cntoff;- w->unconsumed = 0U;+ *off = warc->cntoff; return (ARCHIVE_EOF); } - if (w->unconsumed) {- __archive_read_consume(a, w->unconsumed);- w->unconsumed = 0U;- }- rab = __archive_read_ahead(a, 1U, &nrd); if (nrd < 0) { *bsz = 0U;- /* big catastrophe */+ /* Propagate the read error. */ return (int)nrd; } else if (nrd == 0) {- goto eof;- } else if ((size_t)nrd > w->cntlen - w->cntoff) {- /* clamp to content-length */- nrd = w->cntlen - w->cntoff;+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+ "Truncated WARC file data");+ return (ARCHIVE_FATAL);+ } else if ((int64_t)nrd > warc->cntlen - warc->cntoff) {+ /* Clamp reads to Content-Length. */+ nrd = warc->cntlen - warc->cntoff; }- *off = w->cntoff;+ *off = warc->cntoff; *bsz = nrd; *buf = rab; - w->cntoff += nrd;- w->unconsumed = (size_t)nrd;+ warc->cntoff += nrd;+ warc->unconsumed = nrd; return (ARCHIVE_OK); } static int-_warc_skip(struct archive_read *a)+archive_read_format_warc_skip(struct archive_read *a) {- struct warc_s *w = a->format->data;+ struct warc *warc = a->format->data; - if (__archive_read_consume(a, w->cntlen) < 0 ||+ if (warc->cntoff > warc->cntlen)+ return (ARCHIVE_FATAL);+ if (warc->unconsumed) {+ __archive_read_consume(a, warc->unconsumed);+ warc->unconsumed = 0;+ }+ if (__archive_read_consume(a, warc->cntlen - warc->cntoff) < 0 || __archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0) return (ARCHIVE_FATAL);- w->cntlen = 0U;- w->cntoff = 0U;+ warc->cntlen = 0;+ warc->cntoff = 0; return (ARCHIVE_OK); } -/* private routines */+/* Private routines */ static void* deconst(const void *c) {@@ -469,44 +478,41 @@ unsigned int nsum; unsigned int eqp; - /* trivial checks first- * a 0-sized needle is defined to be found anywhere in haystack- * then run strchr() to find a candidate in HAYSTACK (i.e. a portion- * that happens to begin with *NEEDLE) */+ /* Handle trivial cases first. A zero-sized needle is defined to be+ * found anywhere in the haystack; otherwise find the first candidate+ * that begins with *NEEDLE. */ if (needlesize == 0UL) { return deconst(hay); } else if ((hay = memchr(hay, *needle, haysize)) == NULL) {- /* trivial */+ /* No candidate match remains. */ return NULL; } - /* First characters of haystack and needle are the same now. Both are- * guaranteed to be at least one character long. Now computes the sum- * of characters values of needle together with the sum of the first- * needle_len characters of haystack. */+ /* The first characters of haystack and needle already match, and both+ * strings are at least one character long. Compute the rolling XOR+ * values for the needle and the first NEEDLESIZE characters of haystack. */ for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U; hp < eoh && np < eon; hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++); /* HP now references the (NEEDLESIZE + 1)-th character. */ if (np < eon) {- /* haystack is smaller than needle, :O */+ /* The haystack is smaller than the needle. */ return NULL; } else if (eqp) {- /* found a match */+ /* Found a match. */ return deconst(hay); } - /* now loop through the rest of haystack,- * updating the sum iteratively */+ /* Loop through the rest of the haystack and update the rolling XOR+ * iteratively. */ for (cand = hay; hp < eoh; hp++) { hsum ^= *cand++; hsum ^= *hp; - /* Since the sum of the characters is already known to be- * equal at that point, it is enough to check just NEEDLESIZE - 1- * characters for equality,- * also CAND is by design < HP, so no need for range checks */+ /* When the rolling XOR values match, it is enough to check+ * NEEDLESIZE - 1 characters for equality. CAND is always before+ * HP by design, so no range check is needed. */ if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) { return deconst(cand); }@@ -519,7 +525,7 @@ { int res = 0; const char *sp;- /* we keep track of the number of digits via rulim */+ /* Track the number of digits with rulim. */ int rulim; for (sp = str, rulim = ulim > 10 ? ulim : 10;@@ -546,11 +552,11 @@ /* Use platform timegm() if available. */ return (timegm(t)); #else- /* Else use direct calculation using POSIX assumptions. */- /* First, fix up tm_yday based on the year/month/day. */+ /* Otherwise, calculate directly using POSIX assumptions. */+ /* First, fix up tm_yday based on the year, month, and day. */ if (mktime(t) == (time_t)-1) return ((time_t)-1);- /* Then we can compute timegm() from first principles. */+ /* Then compute timegm() from first principles. */ return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600@@ -565,48 +571,48 @@ static time_t xstrpisotime(const char *s, char **endptr) {-/** like strptime() but strictly for ISO 8601 Zulu strings */+/* Like strptime(), but only for ISO 8601 Zulu strings. */ struct tm tm; time_t res = (time_t)-1; - /* make sure tm is clean */+ /* Clear the tm structure. */ memset(&tm, 0, sizeof(tm)); - /* as a courtesy to our callers, and since this is a non-standard- * routine, we skip leading whitespace */+ /* This is a non-standard routine, so skip leading whitespace for+ * caller convenience. */ while (*s == ' ' || *s == '\t') ++s; - /* read year */+ /* Read the year. */ if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') { goto out; }- /* read month */+ /* Read the month. */ if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') { goto out; }- /* read day-of-month */+ /* Read the day of the month. */ if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') { goto out; }- /* read hour */+ /* Read the hour. */ if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') { goto out; }- /* read minute */+ /* Read the minute. */ if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') { goto out; }- /* read second */+ /* Read the second. */ if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') { goto out; } - /* massage TM to fulfill some of POSIX' constraints */+ /* Adjust tm fields to satisfy POSIX constraints. */ tm.tm_year -= 1900; tm.tm_mon--; - /* now convert our custom tm struct to a unix stamp using UTC */+ /* Convert the tm structure to a Unix timestamp in UTC. */ res = time_from_tm(&tm); out:@@ -616,8 +622,14 @@ return res; } +static int+warc_isdigit(const char c)+{+ return c >= '0' && c <= '9';+}+ static unsigned int-_warc_rdver(const char *buf, size_t bsz)+warc_read_version(const char *buf, size_t bsz) { static const char magic[] = "WARC/"; const char *c;@@ -625,35 +637,34 @@ unsigned int end = 0U; if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {- /* buffer too small or invalid magic */+ /* Buffer too small or invalid magic. */ return ver; }- /* looks good so far, read the version number for a laugh */+ /* Parse the version number. */ buf += sizeof(magic) - 1U; - if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&- isdigit((unsigned char)buf[2U])) {- /* we support a maximum of 2 digits in the minor version */- if (isdigit((unsigned char)buf[3U]))+ if (warc_isdigit(buf[0]) && buf[1] == '.' && warc_isdigit(buf[2])) {+ /* Support at most two digits in the minor version. */+ if (warc_isdigit(buf[3])) end = 1U;- /* set up major version */+ /* Set up the major version. */ ver = (buf[0U] - '0') * 10000U;- /* set up minor version */+ /* Set up the minor version. */ if (end == 1U) { ver += (buf[2U] - '0') * 1000U; ver += (buf[3U] - '0') * 100U; } else ver += (buf[2U] - '0') * 100U; /*- * WARC below version 0.12 has a space-separated header- * WARC 0.12 and above terminates the version with a CRLF+ * WARC versions before 0.12 use a space-separated header.+ * WARC 0.12 and later terminate the version with CRLF. */ c = buf + 3U + end; if (ver >= 1200U) { if (memcmp(c, "\r\n", 2U) != 0) ver = 0U; } else {- /* ver < 1200U */+ /* Version is below WARC 0.12. */ if (*c != ' ' && *c != '\t') ver = 0U; }@@ -662,22 +673,22 @@ } static unsigned int-_warc_rdtyp(const char *buf, size_t bsz)+warc_read_type(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Type:"; const char *val, *eol; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */+ /* Header field is absent. */ return WT_NONE; } val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+ /* Header field has no end of line. */ return WT_NONE; } - /* overread whitespace */+ /* Skip leading whitespace. */ while (val < eol && (*val == ' ' || *val == '\t')) ++val; @@ -691,55 +702,55 @@ } static warc_string_t-_warc_rduri(const char *buf, size_t bsz)+warc_read_uri(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Target-URI:"; const char *val, *uri, *eol, *p; warc_string_t res = {0U, NULL}; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */+ /* Header field is absent. */ return res; }- /* overread whitespace */+ /* Skip leading whitespace. */ val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+ /* Header field has no end of line. */ return res; } while (val < eol && (*val == ' ' || *val == '\t')) ++val; - /* overread URL designators */+ /* Locate the :// separator. */ if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {- /* not touching that! */+ /* Ignore values without a :// separator. */ return res; } - /* spaces inside uri are not allowed, CRLF should follow */+ /* Spaces inside a URI are not allowed; CRLF should follow. */ for (p = val; p < eol; p++) { if (isspace((unsigned char)*p)) return res; } - /* there must be at least space for ftp */+ /* Require enough room for the shortest supported scheme. */ if (uri < (val + 3U)) return res; - /* move uri to point to after :// */+ /* Move uri past the :// separator. */ uri += 3U; - /* now then, inspect the URI */+ /* Inspect the scheme prefix. */ if (memcmp(val, "file", 4U) == 0) {- /* perfect, nothing left to do here */+ /* Keep file:// paths as-is. */ } else if (memcmp(val, "http", 4U) == 0 || memcmp(val, "ftp", 3U) == 0) {- /* overread domain, and the first / */+ /* Skip the domain and the first slash. */ while (uri < eol && *uri++ != '/'); } else {- /* not sure what to do? best to bugger off */+ /* Unsupported URI scheme. */ return res; } res.str = uri;@@ -747,42 +758,49 @@ return res; } -static ssize_t-_warc_rdlen(const char *buf, size_t bsz)+static int64_t+warc_read_length(const char *buf, size_t bsz) { static const char _key[] = "\r\nContent-Length:";- const char *val, *eol;- char *on = NULL;- long int len;+ const char *val, *eol, *p;+ int64_t len; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */+ /* Header field is absent. */ return -1; } val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */++ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+ /* Malformed field with no end of line. */ return -1; } - /* skip leading whitespace */+ /* Skip leading whitespace. */ while (val < eol && (*val == ' ' || *val == '\t')) val++;- /* there must be at least one digit */- if (!isdigit((unsigned char)*val))- return -1;- errno = 0;- len = strtol(val, &on, 10);- if (errno != 0 || on != eol) {- /* line must end here */++ /* Require at least one digit. */+ if (val >= eol || *val < '0' || *val > '9') return -1;++ len = 0;+ for (p = val; p < eol; p++) {+ int64_t digit;++ if (*p < '0' || *p > '9')+ return -1;+ digit = *p - '0';+ if (archive_ckd_mul_i64(&len, len, 10) ||+ archive_ckd_add_i64(&len, len, digit))+ return -1; } - return (size_t)len;+ return len; } static time_t-_warc_rdrtm(const char *buf, size_t bsz)+warc_read_date(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Date:"; const char *val, *eol;@@ -790,26 +808,26 @@ time_t res; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */+ /* Header field is absent. */ return (time_t)-1; } val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {- /* no end of line */+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {+ /* Header field has no end of line. */ return -1; } - /* xstrpisotime() kindly overreads whitespace for us, so use that */+ /* xstrpisotime() skips leading whitespace. */ res = xstrpisotime(val, &on); if (on != eol) {- /* line must end here */+ /* The field must end here. */ return -1; } return res; } static time_t-_warc_rdmtm(const char *buf, size_t bsz)+warc_read_last_modified(const char *buf, size_t bsz) { static const char _key[] = "\r\nLast-Modified:"; const char *val, *eol;@@ -817,26 +835,26 @@ time_t res; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */+ /* Header field is absent. */ return (time_t)-1; } val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {- /* no end of line */+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {+ /* Header field has no end of line. */ return -1; } - /* xstrpisotime() kindly overreads whitespace for us, so use that */+ /* xstrpisotime() skips leading whitespace. */ res = xstrpisotime(val, &on); if (on != eol) {- /* line must end here */+ /* The field must end here. */ return -1; } return res; } -static const char*-_warc_find_eoh(const char *buf, size_t bsz)+static const char *+warc_find_eoh(const char *buf, size_t bsz) { static const char _marker[] = "\r\n\r\n"; const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);@@ -847,12 +865,11 @@ return hit; } -static const char*-_warc_find_eol(const char *buf, size_t bsz)+static const char *+warc_find_eol(const char *buf, size_t bsz) { static const char _marker[] = "\r\n"; const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U); return hit; }-/* archive_read_support_format_warc.c ends here */
c/archive_read_support_format_xar.c view
@@ -108,10 +108,14 @@ #define CKSUM_NONE 0 #define CKSUM_SHA1 1 #define CKSUM_MD5 2+#define CKSUM_SHA256 3+#define CKSUM_SHA512 4 #define MD5_SIZE 16 #define SHA1_SIZE 20-#define MAX_SUM_SIZE 20+#define SHA256_SIZE 32+#define SHA512_SIZE 64+#define MAX_SUM_SIZE 64 enum enctype { NONE,@@ -135,6 +139,12 @@ #ifdef ARCHIVE_HAS_SHA1 archive_sha1_ctx sha1ctx; #endif+#ifdef ARCHIVE_HAS_SHA256+ archive_sha256_ctx sha256ctx;+#endif+#ifdef ARCHIVE_HAS_SHA512+ archive_sha512_ctx sha512ctx;+#endif }; struct xattr {@@ -214,8 +224,8 @@ struct heap_queue { struct xar_file **files;- int allocated;- int used;+ size_t allocated;+ size_t used; }; enum xmlstatus {@@ -396,7 +406,7 @@ static struct xar_file *heap_get_entry(struct heap_queue *); static int add_link(struct archive_read *, struct xar *, struct xar_file *);-static void checksum_init(struct archive_read *, int, int);+static int checksum_init(struct archive_read *, int, int); static void checksum_update(struct archive_read *, const void *, size_t, const void *, size_t); static int checksum_final(struct archive_read *, const void *,@@ -524,6 +534,8 @@ case CKSUM_NONE: case CKSUM_SHA1: case CKSUM_MD5:+ case CKSUM_SHA256:+ case CKSUM_SHA512: bid += 32; break; default:@@ -536,7 +548,7 @@ static int read_toc(struct archive_read *a) {- struct xar *xar;+ struct xar *xar = a->format->data; struct xar_file *file; const unsigned char *b; uint64_t toc_compressed_size;@@ -545,8 +557,6 @@ ssize_t bytes; int r; - xar = (struct xar *)(a->format->data);- /* * Read xar header. */@@ -674,12 +684,11 @@ static int xar_read_header(struct archive_read *a, struct archive_entry *entry) {- struct xar *xar;+ struct xar *xar = a->format->data; struct xar_file *file; struct xattr *xattr; int r; - xar = (struct xar *)(a->format->data); r = ARCHIVE_OK; if (xar->offset == 0) {@@ -729,6 +738,7 @@ if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Gname");+ file_free(file); return (ARCHIVE_FATAL); } archive_set_error(&a->archive,@@ -744,6 +754,7 @@ if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Uname");+ file_free(file); return (ARCHIVE_FATAL); } archive_set_error(&a->archive,@@ -758,6 +769,7 @@ if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname");+ file_free(file); return (ARCHIVE_FATAL); } archive_set_error(&a->archive,@@ -774,6 +786,7 @@ if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname");+ file_free(file); return (ARCHIVE_FATAL); } archive_set_error(&a->archive,@@ -874,12 +887,10 @@ xar_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct xar *xar;+ struct xar *xar = a->format->data; size_t used = 0; int r; - xar = (struct xar *)(a->format->data);- if (xar->entry_unconsumed) { __archive_read_consume(a, xar->entry_unconsumed); xar->entry_unconsumed = 0;@@ -937,10 +948,9 @@ static int xar_read_data_skip(struct archive_read *a) {- struct xar *xar;+ struct xar *xar = a->format->data; int64_t bytes_skipped; - xar = (struct xar *)(a->format->data); if (xar->end_of_file) return (ARCHIVE_EOF); bytes_skipped = __archive_read_consume(a, xar->entry_remaining +@@ -955,12 +965,11 @@ static int xar_cleanup(struct archive_read *a) {- struct xar *xar;+ struct xar *xar = a->format->data; struct hdlink *hdlink;- int i;+ size_t i; int r; - xar = (struct xar *)(a->format->data); checksum_cleanup(a); r = decompression_cleanup(a); hdlink = xar->hdlink_list;@@ -990,9 +999,8 @@ static int move_reading_point(struct archive_read *a, uint64_t offset) {- struct xar *xar;+ struct xar *xar = a->format->data; - xar = (struct xar *)(a->format->data); if (xar->offset - xar->h_base != offset) { /* Seek forward to the start of file contents. */ int64_t step;@@ -1027,8 +1035,7 @@ if ((r = decompression_init(a, encoding)) != ARCHIVE_OK) return (r); /* Init checksum library. */- checksum_init(a, a_sum_alg, e_sum_alg);- return (ARCHIVE_OK);+ return (checksum_init(a, a_sum_alg, e_sum_alg)); } static int@@ -1077,16 +1084,14 @@ uint64_t l; l = 0;- if (char_cnt > 0) {- int digit;+ while (char_cnt-- > 0) {+ int digit = *p++ - '0'; - digit = *p - '0';- while (digit >= 0 && digit < base && char_cnt-- > 0) {- if (archive_ckd_mul_u64(&l, l, base) ||- archive_ckd_add_u64(&l, l, digit))- return (ARCHIVE_FATAL);- digit = *++p - '0';- }+ if (digit < 0 || digit >= base)+ break;+ if (archive_ckd_mul_u64(&l, l, base) ||+ archive_ckd_add_u64(&l, l, digit))+ return (ARCHIVE_FATAL); } *val = l;@@ -1166,31 +1171,31 @@ p += 4; if (*p++ != '-') return (t);- if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1 || data > 12)+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 12) return (t); tm.tm_mon = (int)data -1; p += 2; if (*p++ != '-') return (t);- if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1 || data > 31)+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 31) return (t); tm.tm_mday = (int)data; p += 2; if (*p++ != 'T') return (t);- if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 23)+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 23) return (t); tm.tm_hour = (int)data; p += 2; if (*p++ != ':') return (t);- if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 59)+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 59) return (t); tm.tm_min = (int)data; p += 2; if (*p++ != ':') return (t);- if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 60)+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 60) return (t); tm.tm_sec = (int)data; #if 0@@ -1209,19 +1214,17 @@ struct heap_queue *heap, struct xar_file *file) { uint64_t file_id, parent_id;- int hole, parent;+ size_t hole, parent; /* Expand our pending files list as necessary. */ if (heap->used >= heap->allocated) { struct xar_file **new_pending_files;- int new_size;+ size_t new_size; if (heap->allocated < 1024) new_size = 1024;- else- new_size = heap->allocated * 2;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+ /* Overflow keeps us from growing the list. */ archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL);@@ -1249,7 +1252,7 @@ */ hole = heap->used++; while (hole > 0) {- parent = (hole - 1)/2;+ parent = (hole - 1) / 2; parent_id = heap->files[parent]->id; if (file_id >= parent_id) { heap->files[hole] = file;@@ -1268,7 +1271,7 @@ heap_get_entry(struct heap_queue *heap) { uint64_t a_id, b_id, c_id;- int a, b, c;+ size_t a, b, c; struct xar_file *r, *tmp; if (heap->used < 1)@@ -1338,7 +1341,7 @@ return (ARCHIVE_OK); } -static void+static int _checksum_init(struct chksumwork *sumwrk, int sum_alg) { sumwrk->alg = sum_alg;@@ -1351,7 +1354,20 @@ case CKSUM_MD5: archive_md5_init(&(sumwrk->md5ctx)); break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_init(&(sumwrk->sha256ctx));+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_init(&(sumwrk->sha512ctx));+ break;+#endif+ default:+ return (ARCHIVE_FATAL); }+ return (ARCHIVE_OK); } static void@@ -1367,6 +1383,16 @@ case CKSUM_MD5: archive_md5_update(&(sumwrk->md5ctx), buff, size); break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_update(&(sumwrk->sha256ctx), buff, size);+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_update(&(sumwrk->sha512ctx), buff, size);+ break;+#endif } } @@ -1391,27 +1417,48 @@ memcmp(val, sum, MD5_SIZE) != 0) r = ARCHIVE_FAILED; break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_final(&(sumwrk->sha256ctx), sum);+ if (len != SHA256_SIZE ||+ memcmp(val, sum, SHA256_SIZE) != 0)+ r = ARCHIVE_FAILED;+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_final(&(sumwrk->sha512ctx), sum);+ if (len != SHA512_SIZE ||+ memcmp(val, sum, SHA512_SIZE) != 0)+ r = ARCHIVE_FAILED;+ break;+#endif+ default:+ r = ARCHIVE_FAILED; } return (r); } -static void+static int checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg) {- struct xar *xar;+ struct xar *xar = a->format->data; - xar = (struct xar *)(a->format->data);- _checksum_init(&(xar->a_sumwrk), a_sum_alg);- _checksum_init(&(xar->e_sumwrk), e_sum_alg);+ if (_checksum_init(&(xar->a_sumwrk), a_sum_alg) != ARCHIVE_OK ||+ _checksum_init(&(xar->e_sumwrk), e_sum_alg) != ARCHIVE_OK) {+ archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,+ "Unsupported checksum");+ return (ARCHIVE_FATAL);+ }+ return (ARCHIVE_OK); } static void checksum_update(struct archive_read *a, const void *abuff, size_t asize, const void *ebuff, size_t esize) {- struct xar *xar;+ struct xar *xar = a->format->data; - xar = (struct xar *)(a->format->data); _checksum_update(&(xar->a_sumwrk), abuff, asize); _checksum_update(&(xar->e_sumwrk), ebuff, esize); }@@ -1420,27 +1467,24 @@ checksum_final(struct archive_read *a, const void *a_sum_val, size_t a_sum_len, const void *e_sum_val, size_t e_sum_len) {- struct xar *xar;- int r;+ struct xar *xar = a->format->data; - xar = (struct xar *)(a->format->data);- r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);- if (r == ARCHIVE_OK)- r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);- if (r != ARCHIVE_OK)+ if (_checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len) != ARCHIVE_OK ||+ _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len) != ARCHIVE_OK) { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Sumcheck error");- return (r);+ "Checksum error");+ return (ARCHIVE_FATAL);+ }+ return (ARCHIVE_OK); } static int decompression_init(struct archive_read *a, enum enctype encoding) {- struct xar *xar;+ struct xar *xar = a->format->data; const char *detail; int r; - xar = (struct xar *)(a->format->data); xar->rd_encoding = encoding; switch (encoding) { case NONE:@@ -1576,12 +1620,11 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes, const void *b, size_t *used) {- struct xar *xar;+ struct xar *xar = a->format->data; void *outbuff; size_t avail_in, avail_out; int r; - xar = (struct xar *)(a->format->data); avail_in = *used; outbuff = (void *)(uintptr_t)*buff; if (outbuff == NULL) {@@ -1704,10 +1747,9 @@ static int decompression_cleanup(struct archive_read *a) {- struct xar *xar;+ struct xar *xar = a->format->data; int r; - xar = (struct xar *)(a->format->data); r = ARCHIVE_OK; if (xar->stream_valid) { if (inflateEnd(&(xar->stream)) != Z_OK) {@@ -1736,9 +1778,7 @@ static void checksum_cleanup(struct archive_read *a) {- struct xar *xar;-- xar = (struct xar *)(a->format->data);+ struct xar *xar = a->format->data; _checksum_final(&(xar->a_sumwrk), NULL, 0); _checksum_final(&(xar->e_sumwrk), NULL, 0);@@ -1791,8 +1831,11 @@ } xar->file = file; file->nlink = 1;- if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)+ if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK) {+ xar->file = file->parent;+ file_free(file); return (ARCHIVE_FATAL);+ } return (ARCHIVE_OK); } @@ -1897,9 +1940,16 @@ const char *v = attr->value; if ((v[0] == 'S' || v[0] == 's') && (v[1] == 'H' || v[1] == 'h') &&- (v[2] == 'A' || v[2] == 'a') &&- v[3] == '1' && v[4] == '\0')- alg = CKSUM_SHA1;+ (v[2] == 'A' || v[2] == 'a')) {+ if (v[3] == '1' && v[4] == '\0')+ alg = CKSUM_SHA1;+ else if (v[3] == '2' && v[4] == '5' &&+ v[5] == '6' && v[6] == '\0')+ alg = CKSUM_SHA256;+ else if (v[3] == '5' && v[4] == '1' &&+ v[5] == '2' && v[6] == '\0')+ alg = CKSUM_SHA512;+ } if ((v[0] == 'M' || v[0] == 'm') && (v[1] == 'D' || v[1] == 'd') && v[2] == '5' && v[3] == '\0')@@ -1957,11 +2007,9 @@ static int xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list) {- struct xar *xar;+ struct xar *xar = a->format->data; struct xmlattr *attr; - xar = (struct xar *)(a->format->data);- #if DEBUG fprintf(stderr, "xml_sta:[%s]\n", name); for (attr = list->first; attr != NULL; attr = attr->next)@@ -2253,11 +2301,8 @@ static void xml_end(void *userData, const char *name) {- struct archive_read *a;- struct xar *xar;-- a = (struct archive_read *)userData;- xar = (struct xar *)(a->format->data);+ struct archive_read *a = (struct archive_read *)userData;+ struct xar *xar = a->format->data; #if DEBUG fprintf(stderr, "xml_end:[%s]\n", name);@@ -2631,7 +2676,7 @@ len = 0; out = buff; b = (const unsigned char *)s;- while (l > 0) {+ while (l > 1) { int n = 0; if (base64[b[0]] < 0 || base64[b[1]] < 0)@@ -2679,14 +2724,11 @@ static int xml_data(void *userData, const char *s, size_t len) {+ struct archive_read *a = (struct archive_read *)userData;+ struct xar *xar = a->format->data; uint64_t val;- struct archive_read *a;- struct xar *xar; int r; - a = (struct archive_read *)userData;- xar = (struct xar *)(a->format->data);- #if DEBUG { char buff[1024];@@ -3166,16 +3208,13 @@ static int xml2_read_cb(void *context, char *buffer, int len) {- struct archive_read *a;- struct xar *xar;+ struct archive_read *a = (struct archive_read *)context;+ struct xar *xar = a->format->data; const void *d; size_t outbytes; size_t used = 0; int r; - a = (struct archive_read *)context;- xar = (struct xar *)(a->format->data);- if (xar->toc_remaining <= 0) return (0); d = buffer;@@ -3204,10 +3243,9 @@ xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) {- struct archive_read *a;+ struct archive_read *a = (struct archive_read *)arg; (void)locator; /* UNUSED */- a = (struct archive_read *)arg; switch (severity) { case XML_PARSER_SEVERITY_VALIDITY_WARNING: case XML_PARSER_SEVERITY_WARNING:@@ -3357,15 +3395,13 @@ static int expat_read_toc(struct archive_read *a) {- struct xar *xar;+ struct xar *xar = a->format->data; XML_Parser parser; struct expat_userData ud; ud.state = ARCHIVE_OK; ud.archive = a; - xar = (struct xar *)(a->format->data);- /* Initialize XML Parser library. */ parser = XML_ParserCreate(NULL); if (parser == NULL) {@@ -3449,15 +3485,12 @@ asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead) { struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;- struct archive_read *a;- struct xar *xar;+ struct archive_read *a = asa->a;+ struct xar *xar = a->format->data; const void *d = pv; size_t outbytes = cb; size_t used = 0; int r;-- a = asa->a;- xar = (struct xar *)(a->format->data); *pcbRead = 0;
c/archive_read_support_format_zip.c view
@@ -152,8 +152,6 @@ struct archive_string format_name; int64_t central_directory_offset; int64_t central_directory_offset_adjusted;- size_t central_directory_entries_total;- size_t central_directory_entries_on_this_disk; int has_encrypted_entries; /* List of entries (seekable Zip only) */@@ -261,6 +259,15 @@ /* Many systems define min or MIN, but not all. */ #define zipmin(a,b) ((a) < (b) ? (a) : (b)) +/* True if this entry has declared a specific uncompressed size. */+static int+zip_entry_size_is_set(const struct zip_entry *zip_entry)+{+ return (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)+ || (zip_entry->uncompressed_size > 0+ && zip_entry->uncompressed_size != 0xffffffff));+}+ #ifdef HAVE_ZLIB_H static int zip_read_data_deflate(struct archive_read *a, const void **buff,@@ -284,7 +291,7 @@ ppmd_read(void* p) { /* Get the handle to current decompression context. */ struct archive_read *a = ((IByteIn*)p)->a;- struct zip *zip = (struct zip*) a->format->data;+ struct zip *zip = a->format->data; /* Fetch next byte. */ const uint8_t* data = __archive_read_ahead(a, 1, NULL);@@ -430,7 +437,7 @@ zipx_read_header_and_decrypt(struct archive_read *a, const void **buf, size_t in_len, size_t *out_len, size_t *consumed) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; const void *raw; ssize_t bytes_avail; size_t to_decrypt;@@ -482,6 +489,13 @@ { *sp = compressed_buff; + /* Safety check to prevent potential OOB reads if something went wrong+ * previously. We should not have a negative bytes_avail count here.+ * If we do, set them to zero so that reading the ZIP will fail later,+ * safely as corrupted instead of crashing. */+ if (bytes_avail < 0)+ bytes_avail = 0;+ if (zip->tctx_valid || zip->cctx_valid) { if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) { size_t buff_remaining =@@ -642,8 +656,8 @@ process_extra(struct archive_read *a, struct archive_entry *entry, const char *p, size_t extra_length, struct zip_entry* zip_entry) {+ struct zip *zip = a->format->data; unsigned offset = 0;- struct zip *zip = (struct zip *)(a->format->data); if (extra_length == 0) { return ARCHIVE_OK;@@ -742,6 +756,22 @@ * on which file starts, but we don't handle * multi-volume Zip files. */ break;+ case 0x000d:+ /* PKWARE Unix Extra Field fixed metadata. */+ if (datasize >= 12) {+ zip_entry->atime = archive_le32dec(p + offset);+ zip_entry->mtime =+ archive_le32dec(p + offset + 4);+ zip_entry->uid =+ archive_le16dec(p + offset + 8);+ zip_entry->gid =+ archive_le16dec(p + offset + 10);+ /*+ * APPNOTE.TXT also defines additional data after+ * this fixed metadata, depending on file type.+ */+ }+ break; #ifdef DEBUG case 0x0017: {@@ -1430,10 +1460,7 @@ "Read error skipping symlink target name"); return ARCHIVE_FATAL; }- } else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)- || (zip_entry->uncompressed_size > 0- && zip_entry->uncompressed_size != 0xffffffff)) {- /* Set the size only if it's meaningful. */+ } else if (zip_entry_size_is_set(zip_entry)) { archive_entry_set_size(entry, zip_entry->uncompressed_size); } zip->entry_bytes_remaining = zip_entry->compressed_size;@@ -1456,7 +1483,7 @@ static int check_authentication_code(struct archive_read *a, const void *_p) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; /* Check authentication code. */ if (zip->hctx_valid) {@@ -1683,6 +1710,26 @@ return; } + /* None of the exact patterns matched. If entry size was unknown+ * (ZIP_LENGTH_AT_END flag), before treating this as+ * corruption, check whether the next ZIP record follows the data+ * immediately: a length-at-end entry whose compression format has+ * its own end-of-stream marker (e.g. PPMd) may be written with no+ * data descriptor at all. In that case the byte counts we measured+ * during decompression are authoritative, so trust them and leave+ * the stream untouched. */+ if (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+ {+ const uint32_t sig = archive_le32dec(p);+ if (sig == 0x04034b50U /* Local file header */+ || sig == 0x02014b50U /* Central directory record */+ || sig == 0x06054b50U) /* End of central directory */ {+ zip->entry->compressed_size = compressed_actual;+ zip->entry->uncompressed_size = uncompressed_actual;+ return;+ }+ }+ /* If none of the above patterns gives us a full exact match, * then there's something definitely amiss. The fallback code * below will parse out some plausible values for error@@ -1760,7 +1807,7 @@ zip_read_data_none(struct archive_read *a, const void **_buff, size_t *size, int64_t *offset) {- struct zip *zip;+ struct zip *zip = a->format->data; const char *buff; ssize_t bytes_avail; ssize_t trailing_extra;@@ -1768,7 +1815,6 @@ (void)offset; /* UNUSED */ - zip = (struct zip *)(a->format->data); trailing_extra = zip->hctx_valid ? AUTH_CODE_SIZE : 0; if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {@@ -1986,7 +2032,13 @@ */ /* Read magic1,magic2,lzma_params from the ZIPX stream. */- if(zip->entry_bytes_remaining < 9) {+ /* When the compressed size is unknown (e.g. ZIP_LENGTH_AT_END read+ * from a non-seekable source), entry_bytes_remaining is 0 or negative+ * here. We can still attempt to read the 9-byte header; if the data+ * is truly truncated, the __archive_read_ahead calls below will catch+ * it. */+ if(zip->entry_bytes_remaining > 0+ && zip->entry_bytes_remaining < 9) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzma data"); return (ARCHIVE_FATAL);@@ -2060,8 +2112,10 @@ /* We've already consumed some bytes, so take this into account. */ __archive_read_consume(a, 9);- zip->entry_bytes_remaining -= 9; zip->entry_compressed_bytes_read += 9;+ if (zip->entry_bytes_remaining > 0) {+ zip->entry_bytes_remaining -= 9;+ } zip->decompress_init = 1; return (ARCHIVE_OK);@@ -2071,12 +2125,12 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip* zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; int ret; lzma_ret lz_ret; const void* compressed_buf; const void* sp;- ssize_t bytes_avail, in_bytes, to_consume = 0;+ ssize_t bytes_avail, to_consume = 0; (void) offset; /* UNUSED */ @@ -2088,19 +2142,21 @@ } compressed_buf = sp = __archive_read_ahead(a, 1, &bytes_avail);+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+ && bytes_avail > zip->entry_bytes_remaining) {+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;+ } if (bytes_avail < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated xz file body"); return (ARCHIVE_FATAL); } - in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);-- zip_read_decrypt(zip, compressed_buf, in_bytes,- &compressed_buf, &in_bytes, &sp);+ zip_read_decrypt(zip, compressed_buf, bytes_avail,+ &compressed_buf, &bytes_avail, &sp); zip->zipx_lzma_stream.next_in = compressed_buf;- zip->zipx_lzma_stream.avail_in = in_bytes;+ zip->zipx_lzma_stream.avail_in = bytes_avail; zip->zipx_lzma_stream.total_in = 0; zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer; zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;@@ -2127,8 +2183,10 @@ lzma_end(&zip->zipx_lzma_stream); zip->zipx_lzma_valid = 0; - if((int64_t) zip->zipx_lzma_stream.total_in !=- zip->entry_bytes_remaining)+ /* This assertion is only possible if the size of the compressed data+ * stream is known -> !ZIP_LENGTH_AT_END */+ if((int64_t) zip->zipx_lzma_stream.total_in != zip->entry_bytes_remaining+ && !(zip->entry->zip_flags & ZIP_LENGTH_AT_END)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -2167,12 +2225,12 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip* zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; int ret; lzma_ret lz_ret; const void* compressed_buf; const void* sp;- ssize_t bytes_avail, in_bytes, to_consume;+ ssize_t bytes_avail, to_consume; (void) offset; /* UNUSED */ @@ -2192,29 +2250,38 @@ * data. */ compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);+ if (zip->entry_bytes_remaining > 0+ && bytes_avail > zip->entry_bytes_remaining) {+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;+ } if (bytes_avail < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzma file body"); return (ARCHIVE_FATAL); } - /* Set decompressor parameters. */- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);-- zip_read_decrypt(zip, compressed_buf, in_bytes,- &compressed_buf, &in_bytes, &sp);+ zip_read_decrypt(zip, compressed_buf, bytes_avail,+ &compressed_buf, &bytes_avail, &sp); zip->zipx_lzma_stream.next_in = compressed_buf;- zip->zipx_lzma_stream.avail_in = in_bytes;+ zip->zipx_lzma_stream.avail_in = bytes_avail; zip->zipx_lzma_stream.total_in = 0; zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;- zip->zipx_lzma_stream.avail_out =- /* These lzma_alone streams lack end of stream marker, so let's- * make sure the unpacker won't try to unpack more than it's- * supposed to. */- (size_t)zipmin((int64_t) zip->uncompressed_buffer_size,- zip->entry->uncompressed_size -- zip->entry_uncompressed_bytes_read);+ /* These lzma_alone streams lack an end of stream marker in some+ * cases, so when the uncompressed size is known we cap avail_out to+ * make sure the unpacker won't try to unpack more than it's supposed+ * to. When the compressed size is unknown (entry_bytes_remaining <= 0,+ * e.g. ZIP_LENGTH_AT_END from a non-seekable source) we must use the+ * full buffer and rely on the LZMA stream end marker to detect the end+ * of the entry. */+ if (zip->entry_bytes_remaining <= 0) {+ zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;+ } else {+ zip->zipx_lzma_stream.avail_out =+ (size_t)zipmin((int64_t) zip->uncompressed_buffer_size,+ zip->entry->uncompressed_size -+ zip->entry_uncompressed_bytes_read);+ } zip->zipx_lzma_stream.total_out = 0; /* Perform the decompression. */@@ -2228,8 +2295,11 @@ /* This case is optional in lzma alone format. It can happen, * but most of the files don't have it. (GitHub #1257) */ case LZMA_STREAM_END:+ /* This assertion is only possible if the size of the+ * compressed data stream is known. */ if((int64_t) zip->zipx_lzma_stream.total_in !=- zip->entry_bytes_remaining)+ zip->entry_bytes_remaining+ && zip->entry_bytes_remaining > 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -2245,7 +2315,13 @@ case LZMA_BUF_ERROR: if (zip->zipx_lzma_stream.avail_out == 0) {- zip->end_of_entry = 1;+ /* The output buffer was filled exactly. When+ * the uncompressed size is known this means we+ * have decompressed all expected bytes. When+ * the size is unknown a full buffer just means+ * we need another iteration. */+ if (zip->entry_bytes_remaining > 0)+ zip->end_of_entry = 1; break; } /* FALL THROUGH */@@ -2259,14 +2335,16 @@ /* Update pointers. */ __archive_read_consume(a, to_consume);- zip->entry_bytes_remaining -= to_consume; zip->entry_compressed_bytes_read += to_consume; zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out; zip_read_decrypt_update(zip, to_consume, sp); - if(zip->entry_bytes_remaining == 0) {- zip->end_of_entry = 1;+ if(zip->entry_bytes_remaining > 0) {+ zip->entry_bytes_remaining -= to_consume;+ if(zip->entry_bytes_remaining == 0) {+ zip->end_of_entry = 1;+ } } if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {@@ -2417,7 +2495,7 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip* zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; int ret; size_t consumed_bytes = 0; @@ -2536,8 +2614,8 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip *zip = (struct zip *)(a->format->data);- ssize_t bytes_avail = 0, in_bytes, to_consume;+ struct zip *zip = a->format->data;+ ssize_t bytes_avail = 0, to_consume; const void *compressed_buff; const void *sp; int r;@@ -2554,30 +2632,26 @@ /* Fetch more compressed bytes. */ compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated bzip2 file body");- return (ARCHIVE_FATAL);+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+ && bytes_avail > zip->entry_bytes_remaining) {+ bytes_avail = (ssize_t)zip->entry_bytes_remaining; }-- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);- if(in_bytes < 1) {+ if(bytes_avail < 1) { /* libbz2 doesn't complain when caller feeds avail_in == 0. * It will actually return success in this case, which is * undesirable. This is why we need to make this check * manually. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated bzip2 file body"); return (ARCHIVE_FATAL); } - zip_read_decrypt(zip, compressed_buff, in_bytes,- &compressed_buff, &in_bytes, &sp);+ zip_read_decrypt(zip, compressed_buff, bytes_avail,+ &compressed_buff, &bytes_avail, &sp); /* Setup buffer boundaries. */ zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;- zip->bzstream.avail_in = (uint32_t)in_bytes;+ zip->bzstream.avail_in = (uint32_t)bytes_avail; zip->bzstream.total_in_hi32 = 0; zip->bzstream.total_in_lo32 = 0; zip->bzstream.next_out = (char*) zip->uncompressed_buffer;@@ -2691,8 +2765,8 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip *zip = (struct zip *)(a->format->data);- ssize_t bytes_avail = 0, in_bytes, to_consume;+ struct zip *zip = a->format->data;+ ssize_t bytes_avail = 0, to_consume; const void *compressed_buff; const void *sp; int r;@@ -2712,14 +2786,11 @@ /* Fetch more compressed bytes */ compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated zstd file body");- return (ARCHIVE_FATAL);+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+ && bytes_avail > zip->entry_bytes_remaining) {+ bytes_avail = (ssize_t)zip->entry_bytes_remaining; }-- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);- if(in_bytes < 1) {+ if(bytes_avail < 1) { /* zstd doesn't complain when caller feeds avail_in == 0. * It will actually return success in this case, which is * undesirable. This is why we need to make this check@@ -2729,12 +2800,12 @@ return (ARCHIVE_FATAL); } - zip_read_decrypt(zip, compressed_buff, in_bytes,- &compressed_buff, &in_bytes, &sp);+ zip_read_decrypt(zip, compressed_buff, bytes_avail,+ &compressed_buff, &bytes_avail, &sp); /* Setup buffer boundaries */ in.src = compressed_buff;- in.size = in_bytes;+ in.size = bytes_avail; in.pos = 0; out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 }; @@ -2746,6 +2817,10 @@ ZSTD_getErrorName(ret)); return (ARCHIVE_FATAL); }+ /* End of stream handling for zips with ZIP_LENGTH_AT_END flag */+ if (ret == 0 && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {+ zip->end_of_entry = 1;+ } /* Check end of the stream. */ if (ret == 0) {@@ -2812,7 +2887,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {- struct zip *zip;+ struct zip *zip = a->format->data; ssize_t bytes_avail, to_consume = 0; const void *compressed_buff; const void *sp;@@ -2820,8 +2895,6 @@ (void)offset; /* UNUSED */ - zip = (struct zip *)(a->format->data);- /* If the buffer hasn't been allocated, allocate it now. */ if (zip->uncompressed_buffer == NULL) { zip->uncompressed_buffer_size = 256 * 1024;@@ -2914,7 +2987,7 @@ static int read_decryption_header(struct archive_read *a) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; const char *p; unsigned int remaining_size; unsigned int ts;@@ -3108,7 +3181,7 @@ static int zip_alloc_decryption_buffer(struct archive_read *a) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; size_t bs = 256 * 1024; if (zip->decrypted_buffer == NULL) {@@ -3127,7 +3200,7 @@ static int init_traditional_PKWARE_decryption(struct archive_read *a) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; const void *p; int retry; int r;@@ -3199,7 +3272,7 @@ static int init_WinZip_AES_decryption(struct archive_read *a) {- struct zip *zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; const void *p; const uint8_t *pv; size_t key_len, salt_len;@@ -3293,8 +3366,8 @@ archive_read_format_zip_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) {+ struct zip *zip = a->format->data; int r;- struct zip *zip = (struct zip *)(a->format->data); if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {@@ -3372,6 +3445,25 @@ } if (r != ARCHIVE_OK) return (r);++ /*+ * FAIL if there are more uncompressed bytes than were+ * initially advertised. The end-of-entry check below also+ * compares these values, but only once decoding reaches its+ * own natural end. Fail the entry so a caller relying on+ * archive_entry_size() as a hard boundary is never misled;+ * later entries in the archive can still be read normally.+ */+ if (*size > 0 && zip_entry_size_is_set(zip->entry) &&+ zip->entry_uncompressed_bytes_read > zip->entry->uncompressed_size) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "ZIP uncompressed data is larger than the declared "+ "entry size (read at least %jd, expected %jd)",+ (intmax_t)zip->entry_uncompressed_bytes_read,+ (intmax_t)zip->entry->uncompressed_size);+ return (ARCHIVE_FAILED);+ }+ if (*size > 0) { zip->computed_crc32 = zip->crc32func(zip->computed_crc32, *buff, (unsigned)*size);@@ -3402,10 +3494,8 @@ (intmax_t)zip->entry->compressed_size); return (ARCHIVE_FAILED); }- /* Size field only stores the lower 32 bits of the actual- * size. */- if ((zip->entry->uncompressed_size & UINT32_MAX)- != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {+ if (zip->entry->uncompressed_size !=+ zip->entry_uncompressed_bytes_read) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "ZIP uncompressed data is wrong size " "(read %jd, expected %jd)",@@ -3421,11 +3511,9 @@ static int archive_read_format_zip_cleanup(struct archive_read *a) {- struct zip *zip;+ struct zip *zip = a->format->data; struct zip_entry *zip_entry, *next_zip_entry; - zip = (struct zip *)(a->format->data);- #ifdef HAVE_ZLIB_H if (zip->stream_valid) inflateEnd(&zip->stream);@@ -3473,7 +3561,7 @@ free(zip->v_data); archive_string_free(&zip->format_name); free(zip);- (a->format->data) = NULL;+ a->format->data = NULL; return (ARCHIVE_OK); } @@ -3481,7 +3569,7 @@ archive_read_format_zip_has_encrypted_entries(struct archive_read *_a) { if (_a && _a->format) {- struct zip * zip = (struct zip *)_a->format->data;+ struct zip *zip = _a->format->data; if (zip) { return zip->has_encrypted_entries; }@@ -3493,10 +3581,9 @@ archive_read_format_zip_options(struct archive_read *a, const char *key, const char *val) {- struct zip *zip;+ struct zip *zip = a->format->data; int ret = ARCHIVE_FAILED; - zip = (struct zip *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { /* Handle filenames as libarchive 2.x */ zip->init_default_conversion = (val != NULL) ? 1 : 0;@@ -3603,14 +3690,12 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a, struct archive_entry *entry) {- struct zip *zip;+ struct zip *zip = a->format->data; a->archive.archive_format = ARCHIVE_FORMAT_ZIP; if (a->archive.archive_format_name == NULL) a->archive.archive_format_name = "ZIP"; - zip = (struct zip *)(a->format->data);- /* * It should be sufficient to call archive_read_next_header() for * a reader to determine if an entry is encrypted or not. If the@@ -3696,10 +3781,9 @@ static int archive_read_format_zip_read_data_skip_streamable(struct archive_read *a) {- struct zip *zip;+ struct zip *zip = a->format->data; int64_t bytes_skipped; - zip = (struct zip *)(a->format->data); bytes_skipped = __archive_read_consume(a, zip->unconsumed); zip->unconsumed = 0; if (bytes_skipped < 0)@@ -3941,7 +4025,7 @@ static int archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) {- struct zip *zip = (struct zip *)a->format->data;+ struct zip *zip = a->format->data; int64_t file_size, current_offset; const char *p; int i, tail;@@ -4147,7 +4231,6 @@ __archive_rb_tree_init(&zip->tree, &rb_ops); __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops); - zip->central_directory_entries_total = 0; while (1) { struct zip_entry *zip_entry; size_t filename_length, extra_length, comment_length;@@ -4176,7 +4259,6 @@ zip_entry->next = zip->zip_entries; zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY; zip->zip_entries = zip_entry;- zip->central_directory_entries_total++; /* version = p[4]; */ zip_entry->system = p[5];@@ -4256,12 +4338,14 @@ r = rsrc_basename(name, filename_length); if (filename_length >= 9 && strncmp("__MACOSX/", name, 9) == 0) {+ const char *name_end;++ name_end = name + filename_length; /* If this file is not a resource fork nor * a directory. We should treat it as a non * resource fork file to expose it. */ if (name[filename_length-1] != '/' &&- (r - name < 3 || r[0] != '.' ||- r[1] != '_')) {+ (name_end - r < 2 || r[0] != '.' || r[1] != '_')) { __archive_rb_tree_insert_node( &zip->tree, &zip_entry->node); /* Expose its parent directories. */@@ -4339,7 +4423,7 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, struct zip_entry *rsrc) {- struct zip *zip = (struct zip *)a->format->data;+ struct zip *zip = a->format->data; unsigned char *metadata, *mp; int64_t offset = archive_filter_bytes(&a->archive, 0); size_t remaining_bytes, metadata_bytes;@@ -4490,7 +4574,7 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a, struct archive_entry *entry) {- struct zip *zip = (struct zip *)a->format->data;+ struct zip *zip = a->format->data; struct zip_entry *rsrc; int64_t offset; int r, ret = ARCHIVE_OK;@@ -4570,8 +4654,7 @@ static int archive_read_format_zip_read_data_skip_seekable(struct archive_read *a) {- struct zip *zip;- zip = (struct zip *)(a->format->data);+ struct zip *zip = a->format->data; zip->unconsumed = 0; return (ARCHIVE_OK);
c/archive_string.c view
@@ -450,6 +450,8 @@ return locale_charset(); #elif HAVE_NL_LANGINFO return nl_langinfo(CODESET);+#elif defined(__BIONIC__)+ return "UTF-8"; #else return ""; #endif@@ -2325,7 +2327,7 @@ remaining = length; itp = (const uint8_t *)_p;- while (*itp && remaining > 0) {+ while (remaining > 0 && *itp) { if (*itp > 127) { // Non-ASCII: Substitute with suitable replacement if (sc->flag & SCONV_TO_UTF8) {@@ -2340,6 +2342,7 @@ archive_strappend_char(as, *itp); } ++itp;+ --remaining; } return (return_value); }
c/archive_write.c view
@@ -69,7 +69,7 @@ static int _archive_write_finish_entry(struct archive *); static ssize_t _archive_write_data(struct archive *, const void *, size_t); -struct archive_none {+struct client { size_t buffer_size; size_t avail; char *buffer;@@ -135,7 +135,7 @@ if (bytes_per_block < 0) { // Do nothing if the bytes_per_block is negative- return 0;+ return ARCHIVE_OK; } a->bytes_per_block = bytes_per_block; return (ARCHIVE_OK);@@ -240,8 +240,10 @@ /* If unset, a fatal error has already occurred, so this filter * didn't open. We cannot write anything. */ return(ARCHIVE_FATAL);+ if (length > (uint64_t)(INT64_MAX - f->bytes_written))+ return(ARCHIVE_FATAL); r = (f->write)(f, buff, length);- f->bytes_written += length;+ f->bytes_written += (int64_t)length; return (r); } @@ -338,7 +340,7 @@ } int-__archive_write_nulls(struct archive_write *a, size_t length)+__archive_write_nulls(struct archive_write *a, uint64_t length) { if (length == 0) return (ARCHIVE_OK);@@ -357,7 +359,7 @@ archive_write_client_open(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state;+ struct client *client; void *buffer; size_t buffer_size; @@ -366,21 +368,21 @@ archive_write_get_bytes_in_last_block(f->archive); buffer_size = f->bytes_per_block; - state = calloc(1, sizeof(*state));+ client = calloc(1, sizeof(*client)); buffer = malloc(buffer_size);- if (state == NULL || buffer == NULL) {- free(state);+ if (client == NULL || buffer == NULL) {+ free(client); free(buffer); archive_set_error(f->archive, ENOMEM, "Can't allocate data for output buffering"); return (ARCHIVE_FATAL); } - state->buffer_size = buffer_size;- state->buffer = buffer;- state->next = state->buffer;- state->avail = state->buffer_size;- f->data = state;+ client->buffer_size = buffer_size;+ client->buffer = buffer;+ client->next = client->buffer;+ client->avail = client->buffer_size;+ f->data = client; if (a->client_opener == NULL) return (ARCHIVE_OK);@@ -392,7 +394,7 @@ const void *_buff, size_t length) { struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state = (struct archive_none *)f->data;+ struct client *client = f->data; const char *buff = (const char *)_buff; ssize_t remaining, to_copy; ssize_t bytes_written;@@ -405,7 +407,7 @@ * particular, this supports "no write delay" operation for * special applications. Just set the block size to zero. */- if (state->buffer_size == 0) {+ if (client->buffer_size == 0) { while (remaining > 0) { bytes_written = (a->client_writer)(&a->archive, a->client_data, buff, remaining);@@ -418,20 +420,20 @@ } /* If the copy buffer isn't empty, try to fill it. */- if (state->avail < state->buffer_size) {+ if (client->avail < client->buffer_size) { /* If buffer is not empty... */ /* ... copy data into buffer ... */- to_copy = ((size_t)remaining > state->avail) ?- state->avail : (size_t)remaining;- memcpy(state->next, buff, to_copy);- state->next += to_copy;- state->avail -= to_copy;+ to_copy = ((size_t)remaining > client->avail) ?+ client->avail : (size_t)remaining;+ memcpy(client->next, buff, to_copy);+ client->next += to_copy;+ client->avail -= to_copy; buff += to_copy; remaining -= to_copy; /* ... if it's full, write it out. */- if (state->avail == 0) {- char *p = state->buffer;- size_t to_write = state->buffer_size;+ if (client->avail == 0) {+ char *p = client->buffer;+ size_t to_write = client->buffer_size; while (to_write > 0) { bytes_written = (a->client_writer)(&a->archive, a->client_data, p, to_write);@@ -445,15 +447,15 @@ p += bytes_written; to_write -= bytes_written; }- state->next = state->buffer;- state->avail = state->buffer_size;+ client->next = client->buffer;+ client->avail = client->buffer_size; } } - while ((size_t)remaining >= state->buffer_size) {+ while ((size_t)remaining >= client->buffer_size) { /* Write out full blocks directly to client. */ bytes_written = (a->client_writer)(&a->archive,- a->client_data, buff, state->buffer_size);+ a->client_data, buff, client->buffer_size); if (bytes_written <= 0) return (ARCHIVE_FATAL); buff += bytes_written;@@ -462,9 +464,9 @@ if (remaining > 0) { /* Copy last bit into copy buffer. */- memcpy(state->next, buff, remaining);- state->next += remaining;- state->avail -= remaining;+ memcpy(client->next, buff, remaining);+ client->next += remaining;+ client->avail -= remaining; } return (ARCHIVE_OK); }@@ -473,7 +475,7 @@ archive_write_client_free(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state = (struct archive_none *)f->data;+ struct client *client = f->data; if (a->client_freer) (*a->client_freer)(&a->archive, a->client_data);@@ -487,9 +489,9 @@ } /* Free state. */- if (state != NULL) {- free(state->buffer);- free(state);+ if (client != NULL) {+ free(client->buffer);+ free(client); f->data = NULL; } @@ -500,7 +502,7 @@ archive_write_client_close(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state = (struct archive_none *)f->data;+ struct client *client = f->data; ssize_t block_length; ssize_t target_block_length; ssize_t bytes_written;@@ -509,8 +511,8 @@ int ret = ARCHIVE_OK; /* If there's pending data, pad and write the last block */- if (state->next != state->buffer) {- block_length = state->buffer_size - state->avail;+ if (client->next != client->buffer) {+ block_length = client->buffer_size - client->avail; /* Tricky calculation to determine size of last block */ if (a->bytes_in_last_block <= 0)@@ -524,11 +526,11 @@ if (target_block_length > a->bytes_per_block) target_block_length = a->bytes_per_block; if (block_length < target_block_length) {- memset(state->next, 0,+ memset(client->next, 0, target_block_length - block_length); block_length = target_block_length; }- p = state->buffer;+ p = client->buffer; to_write = block_length; while (to_write > 0) { bytes_written = (a->client_writer)(&a->archive,@@ -683,6 +685,29 @@ a->filter_last = NULL; } +int+__archive_write_unregister_format(struct archive_write *a)+{+ int r = ARCHIVE_OK;++ if (a->format_free != NULL)+ r = (a->format_free)(a);++ a->format_data = NULL;+ a->format_name = NULL;+ a->format_init = NULL;+ a->format_options = NULL;+ a->format_finish_entry = NULL;+ a->format_write_header = NULL;+ a->format_write_data = NULL;+ a->format_close = NULL;+ a->format_free = NULL;+ a->archive.archive_format = 0;+ a->archive.archive_format_name = NULL;++ return (r);+}+ /* * Destroy the archive structure. *@@ -705,11 +730,9 @@ r = archive_write_close(&a->archive); /* Release format resources. */- if (a->format_free != NULL) {- r1 = (a->format_free)(a);- if (r1 < r)- r = r1;- }+ r1 = __archive_write_unregister_format(a);+ if (r1 < r)+ r = r1; __archive_write_filters_free(_a);
c/archive_write_add_filter_b64encode.c view
@@ -46,7 +46,7 @@ #define LBYTES 57 -struct private_b64encode {+struct b64encode { int mode; struct archive_string name; struct archive_string encoded_buff;@@ -64,6 +64,7 @@ static int archive_filter_b64encode_free(struct archive_write_filter *); static void la_b64_encode(struct archive_string *, const unsigned char *, size_t); static int64_t atol8(const char *, size_t);+static void free_data(struct b64encode *); static const char base64[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',@@ -80,34 +81,38 @@ * Add a compress filter to this write handle. */ int-archive_write_add_filter_b64encode(struct archive *_a)+archive_write_add_filter_b64encode(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_b64encode *state;+ struct archive_write_filter *f;+ struct b64encode *b64encode; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_b64encode"); - state = calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for b64encode filter");- return (ARCHIVE_FATAL);- }- archive_strcpy(&state->name, "-");- state->mode = 0644;+ b64encode = calloc(1, sizeof(*b64encode));+ if (b64encode == NULL)+ goto memerr;+ archive_strcpy(&b64encode->name, "-");+ b64encode->mode = 0644; - f->data = state;+ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr; f->name = "b64encode"; f->code = ARCHIVE_FILTER_UU;- f->open = archive_filter_b64encode_open;+ f->data = b64encode; f->options = archive_filter_b64encode_options;+ f->open = archive_filter_b64encode_open; f->write = archive_filter_b64encode_write; f->close = archive_filter_b64encode_close; f->free = archive_filter_b64encode_free; return (ARCHIVE_OK);+memerr:+ free_data(b64encode);+ archive_set_error(a, ENOMEM,+ "Can't allocate data for b64encode filter");+ return (ARCHIVE_FATAL); } /*@@ -117,7 +122,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_b64encode *state = (struct private_b64encode *)f->data;+ struct b64encode *b64encode = f->data; if (strcmp(key, "mode") == 0) { int64_t val;@@ -133,7 +138,7 @@ "invalid mode option"); return (ARCHIVE_FAILED); }- state->mode = (int)val & 0777;+ b64encode->mode = (int)val & 0777; return (ARCHIVE_OK); } else if (strcmp(key, "name") == 0) { if (value == NULL) {@@ -141,7 +146,7 @@ "name option requires a string"); return (ARCHIVE_FAILED); }- archive_strcpy(&state->name, value);+ archive_strcpy(&b64encode->name, value); return (ARCHIVE_OK); } @@ -157,7 +162,7 @@ static int archive_filter_b64encode_open(struct archive_write_filter *f) {- struct private_b64encode *state = (struct private_b64encode *)f->data;+ struct b64encode *b64encode = f->data; size_t bs = 65536, bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {@@ -170,18 +175,17 @@ bs -= bs % bpb; } - state->bs = bs;- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {+ b64encode->bs = bs;+ if (archive_string_ensure(&b64encode->encoded_buff, bs + 512) == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for b64encode buffer"); return (ARCHIVE_FATAL); } - archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",- (unsigned int)state->mode, state->name.s);+ archive_string_sprintf(&b64encode->encoded_buff, "begin-base64 %o %s\n",+ (unsigned int)b64encode->mode, b64encode->name.s); - f->data = state;- return (0);+ return (ARCHIVE_OK); } static void@@ -225,39 +229,39 @@ archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_b64encode *state = (struct private_b64encode *)f->data;+ struct b64encode *b64encode = f->data; const unsigned char *p = buff; int ret = ARCHIVE_OK; if (length == 0) return (ret); - if (state->hold_len) {- while (state->hold_len < LBYTES && length > 0) {- state->hold[state->hold_len++] = *p++;+ if (b64encode->hold_len) {+ while (b64encode->hold_len < LBYTES && length > 0) {+ b64encode->hold[b64encode->hold_len++] = *p++; length--; }- if (state->hold_len < LBYTES)+ if (b64encode->hold_len < LBYTES) return (ret);- la_b64_encode(&state->encoded_buff, state->hold, LBYTES);- state->hold_len = 0;+ la_b64_encode(&b64encode->encoded_buff, b64encode->hold, LBYTES);+ b64encode->hold_len = 0; } for (; length >= LBYTES; length -= LBYTES, p += LBYTES)- la_b64_encode(&state->encoded_buff, p, LBYTES);+ la_b64_encode(&b64encode->encoded_buff, p, LBYTES); /* Save remaining bytes. */ if (length > 0) {- memcpy(state->hold, p, length);- state->hold_len = length;+ memcpy(b64encode->hold, p, length);+ b64encode->hold_len = length; }- while (archive_strlen(&state->encoded_buff) >= state->bs) {+ while (archive_strlen(&b64encode->encoded_buff) >= b64encode->bs) { ret = __archive_write_filter(f->next_filter,- state->encoded_buff.s, state->bs);- memmove(state->encoded_buff.s,- state->encoded_buff.s + state->bs,- state->encoded_buff.length - state->bs);- state->encoded_buff.length -= state->bs;+ b64encode->encoded_buff.s, b64encode->bs);+ memmove(b64encode->encoded_buff.s,+ b64encode->encoded_buff.s + b64encode->bs,+ b64encode->encoded_buff.length - b64encode->bs);+ b64encode->encoded_buff.length -= b64encode->bs; } return (ret);@@ -270,26 +274,24 @@ static int archive_filter_b64encode_close(struct archive_write_filter *f) {- struct private_b64encode *state = (struct private_b64encode *)f->data;+ struct b64encode *b64encode = f->data; /* Flush remaining bytes. */- if (state->hold_len != 0)- la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);- archive_string_sprintf(&state->encoded_buff, "====\n");+ if (b64encode->hold_len != 0)+ la_b64_encode(&b64encode->encoded_buff, b64encode->hold,+ b64encode->hold_len);+ archive_string_sprintf(&b64encode->encoded_buff, "====\n"); /* Write the last block */ archive_write_set_bytes_in_last_block(f->archive, 1); return __archive_write_filter(f->next_filter,- state->encoded_buff.s, archive_strlen(&state->encoded_buff));+ b64encode->encoded_buff.s, archive_strlen(&b64encode->encoded_buff)); } static int archive_filter_b64encode_free(struct archive_write_filter *f) {- struct private_b64encode *state = (struct private_b64encode *)f->data;-- archive_string_free(&state->name);- archive_string_free(&state->encoded_buff);- free(state);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK); } @@ -316,3 +318,12 @@ return (l); } +static void+free_data(struct b64encode *b64encode)+{+ if (b64encode != NULL) {+ archive_string_free(&b64encode->name);+ archive_string_free(&b64encode->encoded_buff);+ free(b64encode);+ }+}
c/archive_write_add_filter_bzip2.c view
@@ -53,7 +53,7 @@ } #endif -struct private_data {+struct bzip2 { int compression_level; #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) bz_stream stream;@@ -71,50 +71,66 @@ const char *, const char *); static int archive_compressor_bzip2_write(struct archive_write_filter *, const void *, size_t);+static void free_data(struct bzip2 *); /* * Add a bzip2 compression filter to this write handle. */ int-archive_write_add_filter_bzip2(struct archive *_a)+archive_write_add_filter_bzip2(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_data *data;+ struct archive_write_filter *f;+ struct bzip2 *bzip2;+ int r; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_bzip2"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 9; /* default */-- f->data = data;- f->options = &archive_compressor_bzip2_options;- f->close = &archive_compressor_bzip2_close;- f->free = &archive_compressor_bzip2_free;- f->open = &archive_compressor_bzip2_open;- f->code = ARCHIVE_FILTER_BZIP2;- f->name = "bzip2";+ bzip2 = calloc(1, sizeof(*bzip2));+ if (bzip2 == NULL)+ goto memerr; #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- return (ARCHIVE_OK);+ bzip2->compression_level = 9;++ r = ARCHIVE_OK; #else- data->pdata = __archive_write_program_allocate("bzip2");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ bzip2->pdata = __archive_write_program_allocate("bzip2");+ if (bzip2->pdata == NULL)+ goto memerr;+ bzip2->compression_level = 0;++ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external bzip2 program");- return (ARCHIVE_WARN);+ r = ARCHIVE_WARN; #endif++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = "bzip2";+ f->code = ARCHIVE_FILTER_BZIP2;+ f->data = bzip2;+ f->options = archive_compressor_bzip2_options;+ f->open = archive_compressor_bzip2_open;+ f->write = archive_compressor_bzip2_write;+ f->close = archive_compressor_bzip2_close;+ f->free = archive_compressor_bzip2_free;++ return (r);+memerr:+ free_data(bzip2);+ archive_set_error(a, ENOMEM, "Out of memory");+ return (ARCHIVE_FATAL); } +static int+archive_compressor_bzip2_free(struct archive_write_filter *f)+{+ free_data(f->data);+ f->data = NULL;+ return (ARCHIVE_OK);+}+ /* * Set write options. */@@ -122,7 +138,7 @@ archive_compressor_bzip2_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; if (strcmp(key, "compression-level") == 0) { if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -131,12 +147,12 @@ "compression-level invalid"); return (ARCHIVE_FAILED); }- data->compression_level = value[0] - '0';+ bzip2->compression_level = value[0] - '0'; /* Make '0' be a synonym for '1'. */ /* This way, bzip2 compressor supports the same 0..9 * range of levels as gzip. */- if (data->compression_level < 1)- data->compression_level = 1;+ if (bzip2->compression_level < 1)+ bzip2->compression_level = 1; return (ARCHIVE_OK); } @@ -156,7 +172,7 @@ #define SET_NEXT_IN(st,src) \ (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src) static int drive_compressor(struct archive_write_filter *,- struct private_data *, int finishing);+ struct bzip2 *, int finishing); /* * Setup callback.@@ -164,10 +180,10 @@ static int archive_compressor_bzip2_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; int ret; - if (data->compressed == NULL) {+ if (bzip2->compressed == NULL) { size_t bs = 65536, bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of the bytes@@ -178,25 +194,23 @@ else if (bpb != 0) bs -= bs % bpb; }- data->compressed_buffer_size = bs;- data->compressed = malloc(data->compressed_buffer_size);- if (data->compressed == NULL) {+ bzip2->compressed_buffer_size = bs;+ bzip2->compressed = malloc(bzip2->compressed_buffer_size);+ if (bzip2->compressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } } - memset(&data->stream, 0, sizeof(data->stream));- data->stream.next_out = data->compressed;- data->stream.avail_out = (uint32_t)data->compressed_buffer_size;- f->write = archive_compressor_bzip2_write;+ memset(&bzip2->stream, 0, sizeof(bzip2->stream));+ bzip2->stream.next_out = bzip2->compressed;+ bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size; /* Initialize compression library */- ret = BZ2_bzCompressInit(&(data->stream),- data->compression_level, 0, 30);+ ret = BZ2_bzCompressInit(&(bzip2->stream),+ bzip2->compression_level, 0, 30); if (ret == BZ_OK) {- f->data = data; return (ARCHIVE_OK); } @@ -236,12 +250,12 @@ archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; /* Compress input data to output buffer */- SET_NEXT_IN(data, buff);- data->stream.avail_in = (uint32_t)length;- if (drive_compressor(f, data, 0))+ SET_NEXT_IN(bzip2, buff);+ bzip2->stream.avail_in = (uint32_t)length;+ if (drive_compressor(f, bzip2, 0)) return (ARCHIVE_FATAL); return (ARCHIVE_OK); }@@ -253,19 +267,19 @@ static int archive_compressor_bzip2_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; int ret; /* Finish compression cycle. */- ret = drive_compressor(f, data, 1);+ ret = drive_compressor(f, bzip2, 1); if (ret == ARCHIVE_OK) { /* Write the last block */ ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size - data->stream.avail_out);+ bzip2->compressed,+ bzip2->compressed_buffer_size - bzip2->stream.avail_out); } - switch (BZ2_bzCompressEnd(&(data->stream))) {+ switch (BZ2_bzCompressEnd(&(bzip2->stream))) { case BZ_OK: break; default:@@ -276,20 +290,6 @@ return ret; } -static int-archive_compressor_bzip2_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- /* May already have been called, but not necessarily. */- (void)BZ2_bzCompressEnd(&(data->stream));-- free(data->compressed);- free(data);- f->data = NULL;- return (ARCHIVE_OK);-}- /* * Utility function to push input data through compressor, writing * full output blocks as necessary.@@ -299,35 +299,35 @@ */ static int drive_compressor(struct archive_write_filter *f,- struct private_data *data, int finishing)+ struct bzip2 *bzip2, int finishing) { int ret; for (;;) {- if (data->stream.avail_out == 0) {+ if (bzip2->stream.avail_out == 0) { ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size);+ bzip2->compressed,+ bzip2->compressed_buffer_size); if (ret != ARCHIVE_OK) { /* TODO: Handle this write failure */ return (ARCHIVE_FATAL); }- data->stream.next_out = data->compressed;- data->stream.avail_out = (uint32_t)data->compressed_buffer_size;+ bzip2->stream.next_out = bzip2->compressed;+ bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size; } /* If there's nothing to do, we're done. */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && bzip2->stream.avail_in == 0) return (ARCHIVE_OK); - ret = BZ2_bzCompress(&(data->stream),+ ret = BZ2_bzCompress(&(bzip2->stream), finishing ? BZ_FINISH : BZ_RUN); switch (ret) { case BZ_RUN_OK: /* In non-finishing case, did compressor * consume everything? */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && bzip2->stream.avail_in == 0) return (ARCHIVE_OK); break; case BZ_FINISH_OK: /* Finishing: There's more work to do */@@ -347,12 +347,24 @@ } } +static void+free_data(struct bzip2 *bzip2)+{+ if (bzip2 != NULL) {+ /* May already have been called, but not necessarily. */+ (void)BZ2_bzCompressEnd(&(bzip2->stream));++ free(bzip2->compressed);+ free(bzip2);+ }+}+ #else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */ static int archive_compressor_bzip2_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; struct archive_string as; int r; @@ -360,13 +372,12 @@ archive_strcpy(&as, "bzip2"); /* Specify compression level. */- if (data->compression_level > 0) {+ if (bzip2->compression_level > 0) { archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);+ archive_strappend_char(&as, '0' + bzip2->compression_level); }- f->write = archive_compressor_bzip2_write; - r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, bzip2->pdata, as.s); archive_string_free(&as); return (r); }@@ -375,27 +386,26 @@ archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, bzip2->pdata, buff, length); } static int archive_compressor_bzip2_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct bzip2 *bzip2 = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, bzip2->pdata); } -static int-archive_compressor_bzip2_free(struct archive_write_filter *f)+static void+free_data(struct bzip2 *bzip2) {- struct private_data *data = (struct private_data *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);+ if (bzip2 != NULL) {+ __archive_write_program_free(bzip2->pdata);+ free(bzip2);+ } } #endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
c/archive_write_add_filter_compress.c view
@@ -85,7 +85,7 @@ #define FIRST 257 /* First free entry. */ #define CLEAR 256 /* Table clear output code. */ -struct private_data {+struct compress { int64_t in_count, out_count, checkpoint; int code_len; /* Number of bits/code. */@@ -111,6 +111,7 @@ const void *, size_t); static int archive_compressor_compress_close(struct archive_write_filter *); static int archive_compressor_compress_free(struct archive_write_filter *);+static void free_data(struct compress *); #if ARCHIVE_VERSION_NUMBER < 4000000 int@@ -125,17 +126,35 @@ * Add a compress filter to this write handle. */ int-archive_write_add_filter_compress(struct archive *_a)+archive_write_add_filter_compress(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);+ struct archive_write_filter *f;+ struct compress *compress; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");- f->open = &archive_compressor_compress_open;- f->code = ARCHIVE_FILTER_COMPRESS;++ compress = calloc(1, sizeof(*compress));+ if (compress == NULL)+ goto memerr;++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr; f->name = "compress";+ f->code = ARCHIVE_FILTER_COMPRESS;+ f->data = compress;+ f->open = archive_compressor_compress_open;+ f->write = archive_compressor_compress_write;+ f->close = archive_compressor_compress_close;+ f->free = archive_compressor_compress_free;+ return (ARCHIVE_OK);+memerr:+ free_data(compress);+ archive_set_error(a, ENOMEM,+ "Can't allocate data for compression");+ return (ARCHIVE_FATAL); } /*@@ -144,19 +163,9 @@ static int archive_compressor_compress_open(struct archive_write_filter *f) {- struct private_data *state;+ struct compress *compress = f->data; size_t bs = 65536, bpb; - f->code = ARCHIVE_FILTER_COMPRESS;- f->name = "compress";-- state = calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression");- return (ARCHIVE_FATAL);- }- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of the bytes * per block for performance. */@@ -166,41 +175,38 @@ else if (bpb != 0) bs -= bs % bpb; }- state->compressed_buffer_size = bs;- state->compressed = malloc(state->compressed_buffer_size);+ compress->compressed_buffer_size = bs;+ compress->compressed = malloc(compress->compressed_buffer_size); - if (state->compressed == NULL) {+ if (compress->compressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer");- free(state); return (ARCHIVE_FATAL); } - f->write = archive_compressor_compress_write;- f->close = archive_compressor_compress_close;- f->free = archive_compressor_compress_free;-- state->max_maxcode = 0x10000; /* Should NEVER generate this code. */- state->in_count = 0; /* Length of input. */- state->bit_buf = 0;- state->bit_offset = 0;- state->out_count = 3; /* Includes 3-byte header mojo. */- state->compress_ratio = 0;- state->checkpoint = CHECK_GAP;- state->code_len = 9;- state->cur_maxcode = MAXCODE(state->code_len);- state->first_free = FIRST;+ /* Should NEVER generate this code. */+ compress->max_maxcode = 0x10000;+ /* Length of input. */+ compress->in_count = 0;+ compress->bit_buf = 0;+ compress->bit_offset = 0;+ /* Includes 3-byte header mojo. */+ compress->out_count = 3;+ compress->compress_ratio = 0;+ compress->checkpoint = CHECK_GAP;+ compress->code_len = 9;+ compress->cur_maxcode = MAXCODE(compress->code_len);+ compress->first_free = FIRST; - memset(state->hashtab, 0xff, sizeof(state->hashtab));+ memset(compress->hashtab, 0xff, sizeof(compress->hashtab)); /* Prime output buffer with a gzip header. */- state->compressed[0] = 0x1f; /* Compress */- state->compressed[1] = 0x9d;- state->compressed[2] = 0x90; /* Block mode, 16bit max */- state->compressed_offset = 3;+ compress->compressed[0] = 0x1f; /* Compress */+ compress->compressed[1] = 0x9d;+ compress->compressed[2] = 0x90; /* Block mode, 16bit max */+ compress->compressed_offset = 3; - f->data = state;- return (0);+ return (ARCHIVE_OK); } /*-@@ -224,17 +230,17 @@ static int output_byte(struct archive_write_filter *f, unsigned char c) {- struct private_data *state = f->data;+ struct compress *compress = f->data; - state->compressed[state->compressed_offset++] = c;- ++state->out_count;+ compress->compressed[compress->compressed_offset++] = c;+ ++compress->out_count; - if (state->compressed_buffer_size == state->compressed_offset) {+ if (compress->compressed_buffer_size == compress->compressed_offset) { int ret = __archive_write_filter(f->next_filter,- state->compressed, state->compressed_buffer_size);+ compress->compressed, compress->compressed_buffer_size); if (ret != ARCHIVE_OK) return ARCHIVE_FATAL;- state->compressed_offset = 0;+ compress->compressed_offset = 0; } return ARCHIVE_OK;@@ -243,7 +249,7 @@ static int output_code(struct archive_write_filter *f, int ocode) {- struct private_data *state = f->data;+ struct compress *compress = f->data; int bits, ret, clear_flg, bit_offset; clear_flg = ocode == CLEAR;@@ -252,11 +258,11 @@ * Since ocode is always >= 8 bits, only need to mask the first * hunk on the left. */- bit_offset = state->bit_offset % 8;- state->bit_buf |= (ocode << bit_offset) & 0xff;- output_byte(f, state->bit_buf);+ bit_offset = compress->bit_offset % 8;+ compress->bit_buf |= (ocode << bit_offset) & 0xff;+ output_byte(f, compress->bit_buf); - bits = state->code_len - (8 - bit_offset);+ bits = compress->code_len - (8 - bit_offset); ocode >>= 8 - bit_offset; /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ if (bits >= 8) {@@ -265,41 +271,41 @@ bits -= 8; } /* Last bits. */- state->bit_offset += state->code_len;- state->bit_buf = ocode & rmask[bits];- if (state->bit_offset == state->code_len * 8)- state->bit_offset = 0;+ compress->bit_offset += compress->code_len;+ compress->bit_buf = ocode & rmask[bits];+ if (compress->bit_offset == compress->code_len * 8)+ compress->bit_offset = 0; /* * If the next entry is going to be too big for the ocode size, * then increase it, if possible. */- if (clear_flg || state->first_free > state->cur_maxcode) {+ if (clear_flg || compress->first_free > compress->cur_maxcode) { /* * Write the whole buffer, because the input side won't * discover the size increase until after it has read it. */- if (state->bit_offset > 0) {- while (state->bit_offset < state->code_len * 8) {- ret = output_byte(f, state->bit_buf);+ if (compress->bit_offset > 0) {+ while (compress->bit_offset < compress->code_len * 8) {+ ret = output_byte(f, compress->bit_buf); if (ret != ARCHIVE_OK) return ret;- state->bit_offset += 8;- state->bit_buf = 0;+ compress->bit_offset += 8;+ compress->bit_buf = 0; } }- state->bit_buf = 0;- state->bit_offset = 0;+ compress->bit_buf = 0;+ compress->bit_offset = 0; if (clear_flg) {- state->code_len = 9;- state->cur_maxcode = MAXCODE(state->code_len);+ compress->code_len = 9;+ compress->cur_maxcode = MAXCODE(compress->code_len); } else {- state->code_len++;- if (state->code_len == 16)- state->cur_maxcode = state->max_maxcode;+ compress->code_len++;+ if (compress->code_len == 16)+ compress->cur_maxcode = compress->max_maxcode; else- state->cur_maxcode = MAXCODE(state->code_len);+ compress->cur_maxcode = MAXCODE(compress->code_len); } } @@ -309,13 +315,13 @@ static int output_flush(struct archive_write_filter *f) {- struct private_data *state = f->data;+ struct compress *compress = f->data; int ret; /* At EOF, write the rest of the buffer. */- if (state->bit_offset % 8) {- state->code_len = (state->bit_offset % 8 + 7) / 8;- ret = output_byte(f, state->bit_buf);+ if (compress->bit_offset % 8) {+ compress->code_len = (compress->bit_offset % 8 + 7) / 8;+ ret = output_byte(f, compress->bit_buf); if (ret != ARCHIVE_OK) return ret; }@@ -330,7 +336,7 @@ archive_compressor_compress_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *state = (struct private_data *)f->data;+ struct compress *compress = f->data; int i; int ratio; int c, disp, ret;@@ -341,23 +347,24 @@ bp = buff; - if (state->in_count == 0) {- state->cur_code = *bp++;- ++state->in_count;+ if (compress->in_count == 0) {+ compress->cur_code = *bp++;+ ++compress->in_count; --length; } while (length--) { c = *bp++;- state->in_count++;- state->cur_fcode = (c << 16) | state->cur_code;- i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */+ compress->in_count++;+ compress->cur_fcode = (c << 16) | compress->cur_code;+ /* Xor hashing. */+ i = ((c << HSHIFT) ^ compress->cur_code); - if (state->hashtab[i] == state->cur_fcode) {- state->cur_code = state->codetab[i];+ if (compress->hashtab[i] == compress->cur_fcode) {+ compress->cur_code = compress->codetab[i]; continue; }- if (state->hashtab[i] < 0) /* Empty slot. */+ if (compress->hashtab[i] < 0) /* Empty slot. */ goto nomatch; /* Secondary hash (after G. Knott). */ if (i == 0)@@ -368,40 +375,40 @@ if ((i -= disp) < 0) i += HSIZE; - if (state->hashtab[i] == state->cur_fcode) {- state->cur_code = state->codetab[i];+ if (compress->hashtab[i] == compress->cur_fcode) {+ compress->cur_code = compress->codetab[i]; continue; }- if (state->hashtab[i] >= 0)+ if (compress->hashtab[i] >= 0) goto probe; nomatch:- ret = output_code(f, state->cur_code);+ ret = output_code(f, compress->cur_code); if (ret != ARCHIVE_OK) return ret;- state->cur_code = c;- if (state->first_free < state->max_maxcode) {- state->codetab[i] = state->first_free++; /* code -> hashtable */- state->hashtab[i] = state->cur_fcode;+ compress->cur_code = c;+ if (compress->first_free < compress->max_maxcode) {+ compress->codetab[i] = compress->first_free++; /* code -> hashtable */+ compress->hashtab[i] = compress->cur_fcode; continue; }- if (state->in_count < state->checkpoint)+ if (compress->in_count < compress->checkpoint) continue; - state->checkpoint = state->in_count + CHECK_GAP;+ compress->checkpoint = compress->in_count + CHECK_GAP; - if (state->in_count <= 0x007fffff && state->out_count != 0)- ratio = (int)(state->in_count * 256 / state->out_count);- else if ((ratio = (int)(state->out_count / 256)) == 0)+ if (compress->in_count <= 0x007fffff && compress->out_count != 0)+ ratio = (int)(compress->in_count * 256 / compress->out_count);+ else if ((ratio = (int)(compress->out_count / 256)) == 0) ratio = 0x7fffffff; else- ratio = (int)(state->in_count / ratio);+ ratio = (int)(compress->in_count / ratio); - if (ratio > state->compress_ratio)- state->compress_ratio = ratio;+ if (ratio > compress->compress_ratio)+ compress->compress_ratio = ratio; else {- state->compress_ratio = 0;- memset(state->hashtab, 0xff, sizeof(state->hashtab));- state->first_free = FIRST;+ compress->compress_ratio = 0;+ memset(compress->hashtab, 0xff, sizeof(compress->hashtab));+ compress->first_free = FIRST; ret = output_code(f, CLEAR); if (ret != ARCHIVE_OK) return ret;@@ -418,10 +425,10 @@ static int archive_compressor_compress_close(struct archive_write_filter *f) {- struct private_data *state = (struct private_data *)f->data;+ struct compress *compress = f->data; int ret; - ret = output_code(f, state->cur_code);+ ret = output_code(f, compress->cur_code); if (ret != ARCHIVE_OK) return ret; ret = output_flush(f);@@ -430,16 +437,23 @@ /* Write the last block */ ret = __archive_write_filter(f->next_filter,- state->compressed, state->compressed_offset);+ compress->compressed, compress->compressed_offset); return (ret); } static int archive_compressor_compress_free(struct archive_write_filter *f) {- struct private_data *state = (struct private_data *)f->data;-- free(state->compressed);- free(state);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK);+}++static void+free_data(struct compress *compress)+{+ if (compress != NULL) {+ free(compress->compressed);+ free(compress);+ } }
c/archive_write_add_filter_grzip.c view
@@ -35,7 +35,7 @@ #include "archive.h" #include "archive_write_private.h" -struct write_grzip {+struct grzip { struct archive_write_program_data *pdata; }; @@ -46,42 +46,45 @@ const void *, size_t); static int archive_write_grzip_close(struct archive_write_filter *); static int archive_write_grzip_free(struct archive_write_filter *);+static void free_data(struct grzip *); int-archive_write_add_filter_grzip(struct archive *_a)+archive_write_add_filter_grzip(struct archive *a) {- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_grzip *data;+ struct archive_write_filter *f;+ struct grzip *grzip; - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->pdata = __archive_write_program_allocate("grzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }+ grzip = calloc(1, sizeof(*grzip));+ if (grzip == NULL)+ goto memerr;+ grzip->pdata = __archive_write_program_allocate("grzip");+ if (grzip->pdata == NULL)+ goto memerr; + f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr; f->name = "grzip"; f->code = ARCHIVE_FILTER_GRZIP;- f->data = data;- f->open = archive_write_grzip_open;+ f->data = grzip; f->options = archive_write_grzip_options;+ f->open = archive_write_grzip_open; f->write = archive_write_grzip_write; f->close = archive_write_grzip_close; f->free = archive_write_grzip_free; /* Note: This filter always uses an external program, so we * return "warn" to inform of the fact. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external grzip program for grzip compression"); return (ARCHIVE_WARN);+memerr:+ free_data(grzip);+ archive_set_error(a, ENOMEM, "Can't allocate memory");+ return (ARCHIVE_FATAL); } static int@@ -100,34 +103,41 @@ static int archive_write_grzip_open(struct archive_write_filter *f) {- struct write_grzip *data = (struct write_grzip *)f->data;+ struct grzip *grzip = f->data; - return __archive_write_program_open(f, data->pdata, "grzip");+ return __archive_write_program_open(f, grzip->pdata, "grzip"); } static int archive_write_grzip_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct write_grzip *data = (struct write_grzip *)f->data;+ struct grzip *grzip = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, grzip->pdata, buff, length); } static int archive_write_grzip_close(struct archive_write_filter *f) {- struct write_grzip *data = (struct write_grzip *)f->data;+ struct grzip *grzip = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, grzip->pdata); } static int archive_write_grzip_free(struct archive_write_filter *f) {- struct write_grzip *data = (struct write_grzip *)f->data;-- __archive_write_program_free(data->pdata);- free(data);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK);+}++static void+free_data(struct grzip *grzip)+{+ if (grzip != NULL) {+ __archive_write_program_free(grzip->pdata);+ free(grzip);+ } }
c/archive_write_add_filter_gzip.c view
@@ -56,7 +56,7 @@ /* Don't compile this if we don't have zlib. */ -struct private_data {+struct gzip { int compression_level; int timestamp; char *original_filename;@@ -87,65 +87,66 @@ static int archive_compressor_gzip_free(struct archive_write_filter *); #ifdef HAVE_ZLIB_H static int drive_compressor(struct archive_write_filter *,- struct private_data *, int finishing);+ struct gzip *, int finishing); #endif+static void free_data(struct gzip *); /* * Add a gzip compression filter to this write handle. */ int-archive_write_add_filter_gzip(struct archive *_a)+archive_write_add_filter_gzip(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_data *data;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");+ struct archive_write_filter *f;+ struct gzip *gzip;+ int r; - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- f->data = data;- f->open = &archive_compressor_gzip_open;- f->options = &archive_compressor_gzip_options;- f->close = &archive_compressor_gzip_close;- f->free = &archive_compressor_gzip_free;- f->code = ARCHIVE_FILTER_GZIP;- f->name = "gzip";+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,+ ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip"); - data->original_filename = NULL;+ gzip = calloc(1, sizeof(*gzip));+ if (gzip == NULL)+ goto memerr;+ gzip->original_filename = NULL; #ifdef HAVE_ZLIB_H- data->compression_level = Z_DEFAULT_COMPRESSION;- return (ARCHIVE_OK);+ gzip->compression_level = Z_DEFAULT_COMPRESSION;++ r = ARCHIVE_OK; #else- data->pdata = __archive_write_program_allocate("gzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ gzip->pdata = __archive_write_program_allocate("gzip");+ if (gzip->pdata == NULL)+ goto memerr;+ gzip->compression_level = 0;++ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external gzip program");- return (ARCHIVE_WARN);+ r = ARCHIVE_WARN; #endif++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = "gzip";+ f->code = ARCHIVE_FILTER_GZIP;+ f->data = gzip;+ f->options = archive_compressor_gzip_options;+ f->open = archive_compressor_gzip_open;+ f->write = archive_compressor_gzip_write;+ f->close = archive_compressor_gzip_close;+ f->free = archive_compressor_gzip_free;++ return (r);+memerr:+ free_data(gzip);+ archive_set_error(a, ENOMEM, "Out of memory");+ return (ARCHIVE_FATAL); } static int archive_compressor_gzip_free(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;--#ifdef HAVE_ZLIB_H- free(data->compressed);-#else- __archive_write_program_free(data->pdata);-#endif- free((void*)data->original_filename);- free(data);+ free_data(f->data); f->data = NULL; return (ARCHIVE_OK); }@@ -157,7 +158,7 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; if (strcmp(key, "compression-level") == 0) { if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -166,19 +167,19 @@ "compression-level invalid"); return (ARCHIVE_FAILED); }- data->compression_level = value[0] - '0';+ gzip->compression_level = value[0] - '0'; return (ARCHIVE_OK); } if (strcmp(key, "timestamp") == 0) {- data->timestamp = (value == NULL)?-1:1;+ gzip->timestamp = (value == NULL)?-1:1; return (ARCHIVE_OK); } if (strcmp(key, "original-filename") == 0) {- free((void*)data->original_filename);- data->original_filename = NULL;+ free((void*)gzip->original_filename);+ gzip->original_filename = NULL; if (value) {- data->original_filename = strdup(value);- if (data->original_filename == NULL)+ gzip->original_filename = strdup(value);+ if (gzip->original_filename == NULL) return (ARCHIVE_FAILED); } return (ARCHIVE_OK);@@ -197,11 +198,11 @@ static int archive_compressor_gzip_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; int ret = ARCHIVE_OK; int init_success; - if (data->compressed == NULL) {+ if (gzip->compressed == NULL) { size_t bs = 65536, bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of@@ -212,60 +213,60 @@ else if (bpb != 0) bs -= bs % bpb; }- data->compressed_buffer_size = bs;- data->compressed = malloc(data->compressed_buffer_size);- if (data->compressed == NULL) {+ gzip->compressed_buffer_size = bs;+ gzip->compressed = malloc(gzip->compressed_buffer_size);+ if (gzip->compressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } } - data->crc = crc32(0L, NULL, 0);- data->stream.next_out = data->compressed;- data->stream.avail_out = (uInt)data->compressed_buffer_size;+ gzip->crc = crc32(0L, NULL, 0);+ gzip->stream.next_out = gzip->compressed;+ gzip->stream.avail_out = (uInt)gzip->compressed_buffer_size; /* Prime output buffer with a gzip header. */- data->compressed[0] = 0x1f; /* GZip signature bytes */- data->compressed[1] = 0x8b;- data->compressed[2] = 0x08; /* "Deflate" compression */- data->compressed[3] = 0x00; /* Flags */- if (data->timestamp >= 0) {+ gzip->compressed[0] = 0x1f; /* GZip signature bytes */+ gzip->compressed[1] = 0x8b;+ gzip->compressed[2] = 0x08; /* "Deflate" compression */+ gzip->compressed[3] = 0x00; /* Flags */+ if (gzip->timestamp >= 0) { uint32_t t = (uint32_t)time(NULL);- archive_le32enc(data->compressed + 4, t); /* Timestamp */+ archive_le32enc(gzip->compressed + 4, t); /* Timestamp */ } else {- memset(&data->compressed[4], 0, 4);+ memset(&gzip->compressed[4], 0, 4); }- if (data->compression_level == 9) {- data->compressed[8] = 2;- } else if(data->compression_level == 1) {- data->compressed[8] = 4;+ if (gzip->compression_level == 9) {+ gzip->compressed[8] = 2;+ } else if(gzip->compression_level == 1) {+ gzip->compressed[8] = 4; } else {- data->compressed[8] = 0;+ gzip->compressed[8] = 0; }- data->compressed[9] = 3; /* OS=Unix */- data->stream.next_out += 10;- data->stream.avail_out -= 10;+ gzip->compressed[9] = 3; /* OS=Unix */+ gzip->stream.next_out += 10;+ gzip->stream.avail_out -= 10; - if (data->original_filename != NULL) {+ if (gzip->original_filename != NULL) { /* Limit "original filename" to 32k or the * remaining space in the buffer, whichever is smaller. */- size_t ofn_length = strlen(data->original_filename);+ size_t ofn_length = strlen(gzip->original_filename); size_t ofn_max_length = 32768;- size_t ofn_space_available = data->compressed- + data->compressed_buffer_size- - data->stream.next_out+ size_t ofn_space_available = gzip->compressed+ + gzip->compressed_buffer_size+ - gzip->stream.next_out - 1; if (ofn_max_length > ofn_space_available) { ofn_max_length = ofn_space_available; } if (ofn_length < ofn_max_length) {- data->compressed[3] |= 0x8;- strcpy((char*)data->compressed + 10,- data->original_filename);- data->stream.next_out += ofn_length + 1;- data->stream.avail_out -= ofn_length + 1;+ gzip->compressed[3] |= 0x8;+ strcpy((char*)gzip->compressed + 10,+ gzip->original_filename);+ gzip->stream.next_out += ofn_length + 1;+ gzip->stream.avail_out -= ofn_length + 1; } else { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Gzip 'Original Filename' ignored because it is too long");@@ -273,18 +274,15 @@ } } - f->write = archive_compressor_gzip_write;- /* Initialize compression library. */- init_success = deflateInit2(&(data->stream),- data->compression_level,+ init_success = deflateInit2(&(gzip->stream),+ gzip->compression_level, Z_DEFLATED, -15 /* < 0 to suppress zlib header */, 8, Z_DEFAULT_STRATEGY); if (init_success == Z_OK) {- f->data = data; return (ret); } @@ -320,17 +318,17 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; int ret; /* Update statistics */- data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);- data->total_in += length;+ gzip->crc = crc32(gzip->crc, (const Bytef *)buff, (uInt)length);+ gzip->total_in += length; /* Compress input data to output buffer */- SET_NEXT_IN(data, buff);- data->stream.avail_in = (uInt)length;- if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)+ SET_NEXT_IN(gzip, buff);+ gzip->stream.avail_in = (uInt)length;+ if ((ret = drive_compressor(f, gzip, 0)) != ARCHIVE_OK) return (ret); return (ARCHIVE_OK);@@ -342,26 +340,26 @@ static int archive_compressor_gzip_close(struct archive_write_filter *f) {+ struct gzip *gzip = f->data; unsigned char trailer[8];- struct private_data *data = (struct private_data *)f->data; int ret; /* Finish compression cycle */- ret = drive_compressor(f, data, 1);+ ret = drive_compressor(f, gzip, 1); if (ret == ARCHIVE_OK) { /* Write the last compressed data. */ ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size - data->stream.avail_out);+ gzip->compressed,+ gzip->compressed_buffer_size - gzip->stream.avail_out); } if (ret == ARCHIVE_OK) { /* Build and write out 8-byte trailer. */- archive_le32enc(trailer, data->crc);- archive_le32enc(trailer + 4, data->total_in);+ archive_le32enc(trailer, gzip->crc);+ archive_le32enc(trailer + 4, gzip->total_in); ret = __archive_write_filter(f->next_filter, trailer, 8); } - switch (deflateEnd(&(data->stream))) {+ switch (deflateEnd(&(gzip->stream))) { case Z_OK: break; default:@@ -381,34 +379,34 @@ */ static int drive_compressor(struct archive_write_filter *f,- struct private_data *data, int finishing)+ struct gzip *gzip, int finishing) { int ret; for (;;) {- if (data->stream.avail_out == 0) {+ if (gzip->stream.avail_out == 0) { ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size);+ gzip->compressed,+ gzip->compressed_buffer_size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL);- data->stream.next_out = data->compressed;- data->stream.avail_out =- (uInt)data->compressed_buffer_size;+ gzip->stream.next_out = gzip->compressed;+ gzip->stream.avail_out =+ (uInt)gzip->compressed_buffer_size; } /* If there's nothing to do, we're done. */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && gzip->stream.avail_in == 0) return (ARCHIVE_OK); - ret = deflate(&(data->stream),+ ret = deflate(&(gzip->stream), finishing ? Z_FINISH : Z_NO_FLUSH ); switch (ret) { case Z_OK: /* In non-finishing case, check if compressor * consumed everything */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && gzip->stream.avail_in == 0) return (ARCHIVE_OK); /* In finishing case, this return always means * there's more work */@@ -427,12 +425,22 @@ } } +static void+free_data(struct gzip *gzip)+{+ if (gzip != NULL) {+ free(gzip->compressed);+ free(gzip->original_filename);+ free(gzip);+ }+}+ #else /* HAVE_ZLIB_H */ static int archive_compressor_gzip_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; struct archive_string as; int r; @@ -440,19 +448,18 @@ archive_strcpy(&as, "gzip"); /* Specify compression level. */- if (data->compression_level > 0) {+ if (gzip->compression_level > 0) { archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);+ archive_strappend_char(&as, '0' + gzip->compression_level); }- if (data->timestamp < 0)+ if (gzip->timestamp < 0) /* Do not save timestamp. */ archive_strcat(&as, " -n");- else if (data->timestamp > 0)+ else if (gzip->timestamp > 0) /* Save timestamp. */ archive_strcat(&as, " -N"); - f->write = archive_compressor_gzip_write;- r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, gzip->pdata, as.s); archive_string_free(&as); return (r); }@@ -461,17 +468,26 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, gzip->pdata, buff, length); } static int archive_compressor_gzip_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct gzip *gzip = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, gzip->pdata); } +static void+free_data(struct gzip *gzip)+{+ if (gzip != NULL) {+ __archive_write_program_free(gzip->pdata);+ free(gzip->original_filename);+ free(gzip);+ }+} #endif /* HAVE_ZLIB_H */
c/archive_write_add_filter_lrzip.c view
@@ -39,7 +39,7 @@ #include "archive_string.h" #include "archive_write_private.h" -struct write_lrzip {+struct lrzip { struct archive_write_program_data *pdata; int compression_level; enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;@@ -52,49 +52,52 @@ const void *, size_t); static int archive_write_lrzip_close(struct archive_write_filter *); static int archive_write_lrzip_free(struct archive_write_filter *);+static void free_data(struct lrzip *); int-archive_write_add_filter_lrzip(struct archive *_a)+archive_write_add_filter_lrzip(struct archive *a) {- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_lrzip *data;+ struct archive_write_filter *f;+ struct lrzip *lrzip; - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->pdata = __archive_write_program_allocate("lrzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }+ lrzip = calloc(1, sizeof(*lrzip));+ if (lrzip == NULL)+ goto memerr;+ lrzip->pdata = __archive_write_program_allocate("lrzip");+ if (lrzip->pdata == NULL)+ goto memerr; + f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr; f->name = "lrzip"; f->code = ARCHIVE_FILTER_LRZIP;- f->data = data;- f->open = archive_write_lrzip_open;+ f->data = lrzip; f->options = archive_write_lrzip_options;+ f->open = archive_write_lrzip_open; f->write = archive_write_lrzip_write; f->close = archive_write_lrzip_close; f->free = archive_write_lrzip_free; /* Note: This filter always uses an external program, so we * return "warn" to inform of the fact. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external lrzip program for lrzip compression"); return (ARCHIVE_WARN);+memerr:+ free_data(lrzip);+ archive_set_error(a, ENOMEM, "Can't allocate memory");+ return (ARCHIVE_FATAL); } static int archive_write_lrzip_options(struct archive_write_filter *f, const char *key, const char *value) {- struct write_lrzip *data = (struct write_lrzip *)f->data;+ struct lrzip *lrzip = f->data; if (strcmp(key, "compression") == 0) { if (value == NULL) {@@ -103,15 +106,15 @@ return (ARCHIVE_FAILED); } else if (strcmp(value, "bzip2") == 0)- data->compression = bzip2;+ lrzip->compression = bzip2; else if (strcmp(value, "gzip") == 0)- data->compression = gzip;+ lrzip->compression = gzip; else if (strcmp(value, "lzo") == 0)- data->compression = lzo;+ lrzip->compression = lzo; else if (strcmp(value, "none") == 0)- data->compression = none;+ lrzip->compression = none; else if (strcmp(value, "zpaq") == 0)- data->compression = zpaq;+ lrzip->compression = zpaq; else { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "compression invalid");@@ -125,7 +128,7 @@ "compression-level invalid"); return (ARCHIVE_FAILED); }- data->compression_level = value[0] - '0';+ lrzip->compression_level = value[0] - '0'; return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options@@ -137,7 +140,7 @@ static int archive_write_lrzip_open(struct archive_write_filter *f) {- struct write_lrzip *data = (struct write_lrzip *)f->data;+ struct lrzip *lrzip = f->data; struct archive_string as; int r; @@ -145,7 +148,7 @@ archive_strcpy(&as, "lrzip -q"); /* Specify compression type. */- switch (data->compression) {+ switch (lrzip->compression) { case lzma:/* default compression */ break; case bzip2:@@ -166,12 +169,12 @@ } /* Specify compression level. */- if (data->compression_level > 0) {+ if (lrzip->compression_level > 0) { archive_strcat(&as, " -L ");- archive_strappend_char(&as, '0' + data->compression_level);+ archive_strappend_char(&as, '0' + lrzip->compression_level); } - r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, lrzip->pdata, as.s); archive_string_free(&as); return (r); }@@ -180,25 +183,32 @@ archive_write_lrzip_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct write_lrzip *data = (struct write_lrzip *)f->data;+ struct lrzip *lrzip = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, lrzip->pdata, buff, length); } static int archive_write_lrzip_close(struct archive_write_filter *f) {- struct write_lrzip *data = (struct write_lrzip *)f->data;+ struct lrzip *lrzip = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, lrzip->pdata); } static int archive_write_lrzip_free(struct archive_write_filter *f) {- struct write_lrzip *data = (struct write_lrzip *)f->data;-- __archive_write_program_free(data->pdata);- free(data);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK);+}++static void+free_data(struct lrzip *lrzip)+{+ if (lrzip != NULL) {+ __archive_write_program_free(lrzip->pdata);+ free(lrzip);+ } }
c/archive_write_add_filter_lz4.c view
@@ -50,7 +50,7 @@ #define LZ4_MAGICNUMBER 0x184d2204 -struct private_data {+struct lz4 { int compression_level; unsigned header_written:1; unsigned version_number:1;@@ -85,68 +85,83 @@ const char *, const char *); static int archive_filter_lz4_write(struct archive_write_filter *, const void *, size_t);+static void free_data(struct lz4 *); /* * Add an lz4 compression filter to this write handle. */ int-archive_write_add_filter_lz4(struct archive *_a)+archive_write_add_filter_lz4(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_data *data;+ struct archive_write_filter *f;+ struct lz4 *lz4;+ int r; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }-+ lz4 = calloc(1, sizeof(*lz4));+ if (lz4 == NULL)+ goto memerr; /* * Setup default settings. */- data->compression_level = 1;- data->version_number = 0x01;- data->block_independence = 1;- data->block_checksum = 0;- data->stream_size = 0;- data->stream_checksum = 1;- data->preset_dictionary = 0;- data->block_maximum_size = 7;-- /*- * Setup a filter setting.- */- f->data = data;- f->options = &archive_filter_lz4_options;- f->close = &archive_filter_lz4_close;- f->free = &archive_filter_lz4_free;- f->open = &archive_filter_lz4_open;- f->code = ARCHIVE_FILTER_LZ4;- f->name = "lz4";+ lz4->version_number = 0x01;+ lz4->block_independence = 1;+ lz4->block_checksum = 0;+ lz4->stream_size = 0;+ lz4->stream_checksum = 1;+ lz4->preset_dictionary = 0;+ lz4->block_maximum_size = 7; #if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2- return (ARCHIVE_OK);+ lz4->compression_level = 1;++ r = ARCHIVE_OK; #else /* * We don't have lz4 library, and execute external lz4 program * instead. */- data->pdata = __archive_write_program_allocate("lz4");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ lz4->pdata = __archive_write_program_allocate("lz4");+ if (lz4->pdata == NULL)+ goto memerr;+ lz4->compression_level = 0;++ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external lz4 program");- return (ARCHIVE_WARN);+ r = ARCHIVE_WARN; #endif++ /*+ * Setup a filter setting.+ */+ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = "lz4";+ f->code = ARCHIVE_FILTER_LZ4;+ f->data = lz4;+ f->options = archive_filter_lz4_options;+ f->open = archive_filter_lz4_open;+ f->write = archive_filter_lz4_write;+ f->close = archive_filter_lz4_close;+ f->free = archive_filter_lz4_free;++ return (r);+memerr:+ free_data(lz4);+ archive_set_error(a, ENOMEM, "Out of memory");+ return (ARCHIVE_FATAL); } +static int+archive_filter_lz4_free(struct archive_write_filter *f)+{+ free_data(f->data);+ f->data = NULL;+ return (ARCHIVE_OK);+}+ /* * Set write options. */@@ -154,7 +169,7 @@ archive_filter_lz4_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; if (strcmp(key, "compression-level") == 0) { int val;@@ -173,15 +188,15 @@ return (ARCHIVE_FATAL); } #endif- data->compression_level = val;+ lz4->compression_level = val; return (ARCHIVE_OK); } if (strcmp(key, "stream-checksum") == 0) {- data->stream_checksum = value != NULL;+ lz4->stream_checksum = value != NULL; return (ARCHIVE_OK); } if (strcmp(key, "block-checksum") == 0) {- data->block_checksum = value != NULL;+ lz4->block_checksum = value != NULL; return (ARCHIVE_OK); } if (strcmp(key, "block-size") == 0) {@@ -191,11 +206,11 @@ "block-size invalid"); return (ARCHIVE_FAILED); }- data->block_maximum_size = value[0] - '0';+ lz4->block_maximum_size = value[0] - '0'; return (ARCHIVE_OK); } if (strcmp(key, "block-dependence") == 0) {- data->block_independence = value == NULL;+ lz4->block_independence = value == NULL; return (ARCHIVE_OK); } @@ -225,21 +240,21 @@ static int archive_filter_lz4_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; size_t required_size; static const size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024, 4 * 1024 * 1024 }; size_t pre_block_size; - if (data->block_maximum_size < 4)- data->block_size = bkmap[0];+ if (lz4->block_maximum_size < 4)+ lz4->block_size = bkmap[0]; else- data->block_size = bkmap[data->block_maximum_size - 4];+ lz4->block_size = bkmap[lz4->block_maximum_size - 4]; - required_size = 4 + 15 + 4 + data->block_size + 4 + 4;- if (data->out_buffer_size < required_size) {+ required_size = 4 + 15 + 4 + lz4->block_size + 4 + 4;+ if (lz4->out_buffer_size < required_size) { size_t bs = required_size, bpb;- free(data->out_buffer);+ free(lz4->out_buffer); if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of * the bytes per block for performance. */@@ -251,34 +266,32 @@ bs -= bs % bpb; } }- data->out_block_size = bs;+ lz4->out_block_size = bs; bs += required_size;- data->out_buffer = malloc(bs);- data->out = data->out_buffer;- data->out_buffer_size = bs;+ lz4->out_buffer = malloc(bs);+ lz4->out = lz4->out_buffer;+ lz4->out_buffer_size = bs; } - pre_block_size = (data->block_independence)? 0: 64 * 1024;- if (data->in_buffer_size < data->block_size + pre_block_size) {- free(data->in_buffer_allocated);- data->in_buffer_size = data->block_size;- data->in_buffer_allocated =- malloc(data->in_buffer_size + pre_block_size);- data->in_buffer = data->in_buffer_allocated + pre_block_size;- if (!data->block_independence && data->compression_level >= 3)- data->in_buffer = data->in_buffer_allocated;- data->in = data->in_buffer;- data->in_buffer_size = data->block_size;+ pre_block_size = (lz4->block_independence)? 0: 64 * 1024;+ if (lz4->in_buffer_size < lz4->block_size + pre_block_size) {+ free(lz4->in_buffer_allocated);+ lz4->in_buffer_size = lz4->block_size;+ lz4->in_buffer_allocated =+ malloc(lz4->in_buffer_size + pre_block_size);+ lz4->in_buffer = lz4->in_buffer_allocated + pre_block_size;+ if (!lz4->block_independence && lz4->compression_level >= 3)+ lz4->in_buffer = lz4->in_buffer_allocated;+ lz4->in = lz4->in_buffer;+ lz4->in_buffer_size = lz4->block_size; } - if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {+ if (lz4->out_buffer == NULL || lz4->in_buffer_allocated == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } - f->write = archive_filter_lz4_write;- return (ARCHIVE_OK); } @@ -291,18 +304,18 @@ archive_filter_lz4_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; int ret = ARCHIVE_OK; const char *p; size_t remaining; ssize_t size; /* If we haven't written a stream descriptor, we have to do it first. */- if (!data->header_written) {+ if (!lz4->header_written) { ret = lz4_write_stream_descriptor(f); if (ret != ARCHIVE_OK) return (ret);- data->header_written = 1;+ lz4->header_written = 1; } p = (const char *)buff;@@ -313,14 +326,14 @@ size = lz4_write_one_block(f, p, remaining); if (size < ARCHIVE_OK) return (ARCHIVE_FATAL);- l = data->out - data->out_buffer;- if (l >= data->out_block_size) {+ l = lz4->out - lz4->out_buffer;+ if (l >= lz4->out_block_size) { ret = __archive_write_filter(f->next_filter,- data->out_buffer, data->out_block_size);- l -= data->out_block_size;- memcpy(data->out_buffer,- data->out_buffer + data->out_block_size, l);- data->out = data->out_buffer + l;+ lz4->out_buffer, lz4->out_block_size);+ l -= lz4->out_block_size;+ memcpy(lz4->out_buffer,+ lz4->out_buffer + lz4->out_block_size, l);+ lz4->out = lz4->out_buffer + l; if (ret < ARCHIVE_WARN) break; }@@ -337,7 +350,7 @@ static int archive_filter_lz4_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; int ret; /* Finish compression cycle. */@@ -348,77 +361,48 @@ */ /* Write End Of Stream. */- memset(data->out, 0, 4); data->out += 4;+ memset(lz4->out, 0, 4); lz4->out += 4; /* Write Stream checksum if needed. */- if (data->stream_checksum) {+ if (lz4->stream_checksum) { unsigned int checksum; checksum = __archive_xxhash.XXH32_digest(- data->xxh32_state);- data->xxh32_state = NULL;- archive_le32enc(data->out, checksum);- data->out += 4;+ lz4->xxh32_state);+ lz4->xxh32_state = NULL;+ archive_le32enc(lz4->out, checksum);+ lz4->out += 4; } ret = __archive_write_filter(f->next_filter,- data->out_buffer, data->out - data->out_buffer);+ lz4->out_buffer, lz4->out - lz4->out_buffer); } return ret; } static int-archive_filter_lz4_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->lz4_stream != NULL) {-#ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3)-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- LZ4_freeStreamHC(data->lz4_stream);-#else- LZ4_freeHC(data->lz4_stream);-#endif- else-#endif-#if LZ4_VERSION_MINOR >= 3- LZ4_freeStream(data->lz4_stream);-#else- LZ4_free(data->lz4_stream);-#endif- }- free(data->out_buffer);- free(data->in_buffer_allocated);- free(data->xxh32_state);- free(data);- f->data = NULL;- return (ARCHIVE_OK);-}--static int lz4_write_stream_descriptor(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; uint8_t *sd; - sd = (uint8_t *)data->out;+ sd = (uint8_t *)lz4->out; /* Write Magic Number. */ archive_le32enc(&sd[0], LZ4_MAGICNUMBER); /* FLG */- sd[4] = (data->version_number << 6)- | (data->block_independence << 5)- | (data->block_checksum << 4)- | (data->stream_size << 3)- | (data->stream_checksum << 2)- | (data->preset_dictionary << 0);+ sd[4] = (lz4->version_number << 6)+ | (lz4->block_independence << 5)+ | (lz4->block_checksum << 4)+ | (lz4->stream_size << 3)+ | (lz4->stream_checksum << 2)+ | (lz4->preset_dictionary << 0); /* BD */- sd[5] = (data->block_maximum_size << 4);+ sd[5] = (lz4->block_maximum_size << 4); sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;- data->out += 7;- if (data->stream_checksum) {- data->xxh32_state = __archive_xxhash.XXH32_init(0);- if (data->xxh32_state == NULL)+ lz4->out += 7;+ if (lz4->stream_checksum) {+ lz4->xxh32_state = __archive_xxhash.XXH32_init(0);+ if (lz4->xxh32_state == NULL) return (ARCHIVE_FATAL); } else- data->xxh32_state = NULL;+ lz4->xxh32_state = NULL; return (ARCHIVE_OK); } @@ -426,36 +410,36 @@ lz4_write_one_block(struct archive_write_filter *f, const char *p, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; ssize_t r; if (p == NULL) { /* Compress remaining uncompressed data. */- if (data->in_buffer == data->in)+ if (lz4->in_buffer == lz4->in) return 0; else {- size_t l = data->in - data->in_buffer;- r = drive_compressor(f, data->in_buffer, l);+ size_t l = lz4->in - lz4->in_buffer;+ r = drive_compressor(f, lz4->in_buffer, l); if (r == ARCHIVE_OK) r = (ssize_t)l; }- } else if ((data->block_independence || data->compression_level < 3) &&- data->in_buffer == data->in && length >= data->block_size) {- r = drive_compressor(f, p, data->block_size);+ } else if ((lz4->block_independence || lz4->compression_level < 3) &&+ lz4->in_buffer == lz4->in && length >= lz4->block_size) {+ r = drive_compressor(f, p, lz4->block_size); if (r == ARCHIVE_OK)- r = (ssize_t)data->block_size;+ r = (ssize_t)lz4->block_size; } else {- size_t remaining_size = data->in_buffer_size -- (data->in - data->in_buffer);+ size_t remaining_size = lz4->in_buffer_size -+ (lz4->in - lz4->in_buffer); size_t l = (remaining_size > length)? length: remaining_size;- memcpy(data->in, p, l);- data->in += l;+ memcpy(lz4->in, p, l);+ lz4->in += l; if (l == remaining_size) {- r = drive_compressor(f, data->in_buffer,- data->block_size);+ r = drive_compressor(f, lz4->in_buffer,+ lz4->block_size); if (r == ARCHIVE_OK) r = (ssize_t)l;- data->in = data->in_buffer;+ lz4->in = lz4->in_buffer; } else r = (ssize_t)l; }@@ -474,12 +458,12 @@ static int drive_compressor(struct archive_write_filter *f, const char *p, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; - if (data->stream_checksum)- __archive_xxhash.XXH32_update(data->xxh32_state,+ if (lz4->stream_checksum)+ __archive_xxhash.XXH32_update(lz4->xxh32_state, p, (int)length);- if (data->block_independence)+ if (lz4->block_independence) return drive_compressor_independence(f, p, length); else return drive_compressor_dependence(f, p, length);@@ -489,48 +473,48 @@ drive_compressor_independence(struct archive_write_filter *f, const char *p, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; unsigned int outsize; #ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3)+ if (lz4->compression_level >= 3) #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_HC(p, data->out + 4,- (int)length, (int)data->block_size,- data->compression_level);+ outsize = LZ4_compress_HC(p, lz4->out + 4,+ (int)length, (int)lz4->block_size,+ lz4->compression_level); #else- outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,- (int)length, (int)data->block_size,- data->compression_level);+ outsize = LZ4_compressHC2_limitedOutput(p, lz4->out + 4,+ (int)length, (int)lz4->block_size,+ lz4->compression_level); #endif else #endif #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_default(p, data->out + 4,- (int)length, (int)data->block_size);+ outsize = LZ4_compress_default(p, lz4->out + 4,+ (int)length, (int)lz4->block_size); #else- outsize = LZ4_compress_limitedOutput(p, data->out + 4,- (int)length, (int)data->block_size);+ outsize = LZ4_compress_limitedOutput(p, lz4->out + 4,+ (int)length, (int)lz4->block_size); #endif if (outsize) { /* The buffer is compressed. */- archive_le32enc(data->out, outsize);- data->out += 4;+ archive_le32enc(lz4->out, outsize);+ lz4->out += 4; } else { /* The buffer is not compressed. The compressed size was * bigger than its uncompressed size. */- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));- data->out += 4;- memcpy(data->out, p, length);+ archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));+ lz4->out += 4;+ memcpy(lz4->out, p, length); outsize = (uint32_t)length; }- data->out += outsize;- if (data->block_checksum) {+ lz4->out += outsize;+ if (lz4->block_checksum) { unsigned int checksum =- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);- archive_le32enc(data->out, checksum);- data->out += 4;+ __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);+ archive_le32enc(lz4->out, checksum);+ lz4->out += 4; } return (ARCHIVE_OK); }@@ -539,21 +523,21 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; int outsize; #define DICT_SIZE (64 * 1024) #ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3) {- if (data->lz4_stream == NULL) {+ if (lz4->compression_level >= 3) {+ if (lz4->lz4_stream == NULL) { #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- data->lz4_stream = LZ4_createStreamHC();- LZ4_resetStreamHC(data->lz4_stream, data->compression_level);+ lz4->lz4_stream = LZ4_createStreamHC();+ LZ4_resetStreamHC(lz4->lz4_stream, lz4->compression_level); #else- data->lz4_stream =- LZ4_createHC(data->in_buffer_allocated);+ lz4->lz4_stream =+ LZ4_createHC(lz4->in_buffer_allocated); #endif- if (data->lz4_stream == NULL) {+ if (lz4->lz4_stream == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression" " buffer");@@ -561,23 +545,23 @@ } } else- LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+ LZ4_loadDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE); #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 outsize = LZ4_compress_HC_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size);+ lz4->lz4_stream, p, lz4->out + 4, (int)length,+ (int)lz4->block_size); #else outsize = LZ4_compressHC2_limitedOutput_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size, data->compression_level);+ lz4->lz4_stream, p, lz4->out + 4, (int)length,+ (int)lz4->block_size, lz4->compression_level); #endif } else #endif {- if (data->lz4_stream == NULL) {- data->lz4_stream = LZ4_createStream();- if (data->lz4_stream == NULL) {+ if (lz4->lz4_stream == NULL) {+ lz4->lz4_stream = LZ4_createStream();+ if (lz4->lz4_stream == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression" " buffer");@@ -585,64 +569,91 @@ } } else- LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+ LZ4_loadDict(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE); #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 outsize = LZ4_compress_fast_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size, 1);+ lz4->lz4_stream, p, lz4->out + 4, (int)length,+ (int)lz4->block_size, 1); #else outsize = LZ4_compress_limitedOutput_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size);+ lz4->lz4_stream, p, lz4->out + 4, (int)length,+ (int)lz4->block_size); #endif } if (outsize) { /* The buffer is compressed. */- archive_le32enc(data->out, outsize);- data->out += 4;+ archive_le32enc(lz4->out, outsize);+ lz4->out += 4; } else { /* The buffer is not compressed. The compressed size was * bigger than its uncompressed size. */- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));- data->out += 4;- memcpy(data->out, p, length);+ archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));+ lz4->out += 4;+ memcpy(lz4->out, p, length); outsize = (uint32_t)length; }- data->out += outsize;- if (data->block_checksum) {+ lz4->out += outsize;+ if (lz4->block_checksum) { unsigned int checksum =- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);- archive_le32enc(data->out, checksum);- data->out += 4;+ __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);+ archive_le32enc(lz4->out, checksum);+ lz4->out += 4; } - if (length == data->block_size) {+ if (length == lz4->block_size) { #ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3) {+ if (lz4->compression_level >= 3) { #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+ LZ4_saveDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE); #else- LZ4_slideInputBufferHC(data->lz4_stream);+ LZ4_slideInputBufferHC(lz4->lz4_stream); #endif- data->in_buffer = data->in_buffer_allocated + DICT_SIZE;+ lz4->in_buffer = lz4->in_buffer_allocated + DICT_SIZE; } else #endif- LZ4_saveDict(data->lz4_stream,- data->in_buffer_allocated, DICT_SIZE);+ LZ4_saveDict(lz4->lz4_stream,+ lz4->in_buffer_allocated, DICT_SIZE); #undef DICT_SIZE } return (ARCHIVE_OK); } +static void+free_data(struct lz4 *lz4)+{+ if (lz4 != NULL) {+ if (lz4->lz4_stream != NULL) {+#ifdef HAVE_LZ4HC_H+ if (lz4->compression_level >= 3)+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7+ LZ4_freeStreamHC(lz4->lz4_stream);+#else+ LZ4_freeHC(lz4->lz4_stream);+#endif+ else+#endif+#if LZ4_VERSION_MINOR >= 3+ LZ4_freeStream(lz4->lz4_stream);+#else+ LZ4_free(lz4->lz4_stream);+#endif+ }+ free(lz4->out_buffer);+ free(lz4->in_buffer_allocated);+ free(lz4->xxh32_state);+ free(lz4);+ }+}+ #else /* HAVE_LIBLZ4 */ static int archive_filter_lz4_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; struct archive_string as; int r; @@ -650,24 +661,22 @@ archive_strcpy(&as, "lz4 -z -q -q"); /* Specify a compression level. */- if (data->compression_level > 0) {+ if (lz4->compression_level > 0) { archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);+ archive_strappend_char(&as, '0' + lz4->compression_level); } /* Specify a block size. */ archive_strcat(&as, " -B");- archive_strappend_char(&as, '0' + data->block_maximum_size);+ archive_strappend_char(&as, '0' + lz4->block_maximum_size); - if (data->block_checksum)+ if (lz4->block_checksum) archive_strcat(&as, " -BX");- if (data->stream_checksum == 0)+ if (lz4->stream_checksum == 0) archive_strcat(&as, " --no-frame-crc");- if (data->block_independence == 0)+ if (lz4->block_independence == 0) archive_strcat(&as, " -BD"); - f->write = archive_filter_lz4_write;-- r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, lz4->pdata, as.s); archive_string_free(&as); return (r); }@@ -676,27 +685,26 @@ archive_filter_lz4_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, lz4->pdata, buff, length); } static int archive_filter_lz4_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct lz4 *lz4 = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, lz4->pdata); } -static int-archive_filter_lz4_free(struct archive_write_filter *f)+static void+free_data(struct lz4 *lz4) {- struct private_data *data = (struct private_data *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);+ if (lz4 != NULL) {+ __archive_write_program_free(lz4->pdata);+ free(lz4);+ } } #endif /* HAVE_LIBLZ4 */
c/archive_write_add_filter_lzop.c view
@@ -55,7 +55,7 @@ METHOD_LZO1X_1_15 = 2, METHOD_LZO1X_999 = 3 };-struct write_lzop {+struct lzop { int compression_level; #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) unsigned char *uncompressed;@@ -80,6 +80,7 @@ const void *, size_t); static int archive_write_lzop_close(struct archive_write_filter *); static int archive_write_lzop_free(struct archive_write_filter *);+static void free_data(struct lzop *); #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) /* Maximum block size. */@@ -133,73 +134,72 @@ #endif int-archive_write_add_filter_lzop(struct archive *_a)+archive_write_add_filter_lzop(struct archive *a) {- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_lzop *data;+ struct archive_write_filter *f;+ struct lzop *lzop;+ int r; - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- f->name = "lzop";- f->code = ARCHIVE_FILTER_LZOP;- f->data = data;- f->open = archive_write_lzop_open;- f->options = archive_write_lzop_options;- f->write = archive_write_lzop_write;- f->close = archive_write_lzop_close;- f->free = archive_write_lzop_free;+ lzop = calloc(1, sizeof(*lzop));+ if (lzop == NULL)+ goto memerr; #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) if (lzo_init() != LZO_E_OK) {- free(data);- archive_set_error(_a, ARCHIVE_ERRNO_MISC,+ free_data(lzop);+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "lzo_init(type check) failed"); return (ARCHIVE_FATAL); } if (lzo_version() < 0x940) {- free(data);- archive_set_error(_a, ARCHIVE_ERRNO_MISC,+ free_data(lzop);+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "liblzo library is too old(%s < 0.940)", lzo_version_string()); return (ARCHIVE_FATAL); }- data->compression_level = 5;- return (ARCHIVE_OK);+ lzop->compression_level = 5;++ r = ARCHIVE_OK; #else- data->pdata = __archive_write_program_allocate("lzop");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;+ lzop->pdata = __archive_write_program_allocate("lzop");+ if (lzop->pdata == NULL)+ goto memerr;+ lzop->compression_level = 0;+ /* Note: We return "warn" to inform of using an external lzop * program. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external lzop program for lzop compression");- return (ARCHIVE_WARN);+ r = ARCHIVE_WARN; #endif++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = "lzop";+ f->code = ARCHIVE_FILTER_LZOP;+ f->data = lzop;+ f->options = archive_write_lzop_options;+ f->open = archive_write_lzop_open;+ f->write = archive_write_lzop_write;+ f->close = archive_write_lzop_close;+ f->free = archive_write_lzop_free;++ return (r);+memerr:+ free_data(lzop);+ archive_set_error(a, ENOMEM, "Can't allocate memory");+ return (ARCHIVE_FATAL); } static int archive_write_lzop_free(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)- free(data->uncompressed);- free(data->compressed);- free(data->work_buffer);-#else- __archive_write_program_free(data->pdata);-#endif- free(data);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK); } @@ -207,7 +207,7 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key, const char *value) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; if (strcmp(key, "compression-level") == 0) { if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||@@ -216,7 +216,7 @@ "compression-level invalid"); return (ARCHIVE_FAILED); }- data->compression_level = value[0] - '0';+ lzop->compression_level = value[0] - '0'; return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options@@ -229,58 +229,58 @@ static int archive_write_lzop_open(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; - switch (data->compression_level) {+ switch (lzop->compression_level) { case 1:- data->method = METHOD_LZO1X_1_15; data->level = 1; break;+ lzop->method = METHOD_LZO1X_1_15; lzop->level = 1; break; default: case 2: case 3: case 4: case 5: case 6:- data->method = METHOD_LZO1X_1; data->level = 5; break;+ lzop->method = METHOD_LZO1X_1; lzop->level = 5; break; case 7:- data->method = METHOD_LZO1X_999; data->level = 7; break;+ lzop->method = METHOD_LZO1X_999; lzop->level = 7; break; case 8:- data->method = METHOD_LZO1X_999; data->level = 8; break;+ lzop->method = METHOD_LZO1X_999; lzop->level = 8; break; case 9:- data->method = METHOD_LZO1X_999; data->level = 9; break;+ lzop->method = METHOD_LZO1X_999; lzop->level = 9; break; }- switch (data->method) {+ switch (lzop->method) { case METHOD_LZO1X_1:- data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;+ lzop->work_buffer_size = LZO1X_1_MEM_COMPRESS; break; case METHOD_LZO1X_1_15:- data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;+ lzop->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break; case METHOD_LZO1X_999:- data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;+ lzop->work_buffer_size = LZO1X_999_MEM_COMPRESS; break; }- if (data->work_buffer == NULL) {- data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);- if (data->work_buffer == NULL) {+ if (lzop->work_buffer == NULL) {+ lzop->work_buffer = (lzo_voidp)malloc(lzop->work_buffer_size);+ if (lzop->work_buffer == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } }- if (data->compressed == NULL) {- data->compressed_buffer_size = sizeof(header) ++ if (lzop->compressed == NULL) {+ lzop->compressed_buffer_size = sizeof(header) + BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;- data->compressed = (unsigned char *)- malloc(data->compressed_buffer_size);- if (data->compressed == NULL) {+ lzop->compressed = (unsigned char *)+ malloc(lzop->compressed_buffer_size);+ if (lzop->compressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } }- if (data->uncompressed == NULL) {- data->uncompressed_buffer_size = BLOCK_SIZE;- data->uncompressed = (unsigned char *)- malloc(data->uncompressed_buffer_size);- if (data->uncompressed == NULL) {+ if (lzop->uncompressed == NULL) {+ lzop->uncompressed_buffer_size = BLOCK_SIZE;+ lzop->uncompressed = (unsigned char *)+ malloc(lzop->uncompressed_buffer_size);+ if (lzop->uncompressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); }- data->uncompressed_avail_bytes = BLOCK_SIZE;+ lzop->uncompressed_avail_bytes = BLOCK_SIZE; } return (ARCHIVE_OK); }@@ -288,68 +288,68 @@ static int make_header(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; int64_t t; uint32_t checksum; - memcpy(data->compressed, header, sizeof(header));+ memcpy(lzop->compressed, header, sizeof(header)); /* Overwrite library version. */- data->compressed[HEADER_LIBVERSION] = (unsigned char )+ lzop->compressed[HEADER_LIBVERSION] = (unsigned char ) (lzo_version() >> 8) & 0xff;- data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )+ lzop->compressed[HEADER_LIBVERSION + 1] = (unsigned char ) lzo_version() & 0xff; /* Overwrite method and level. */- data->compressed[HEADER_METHOD] = (unsigned char)data->method;- data->compressed[HEADER_LEVEL] = data->level;+ lzop->compressed[HEADER_METHOD] = (unsigned char)lzop->method;+ lzop->compressed[HEADER_LEVEL] = lzop->level; /* Overwrite mtime with current time. */ t = (int64_t)time(NULL);- archive_be32enc(&data->compressed[HEADER_MTIME_LOW],+ archive_be32enc(&lzop->compressed[HEADER_MTIME_LOW], (uint32_t)(t & 0xffffffff));- archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],+ archive_be32enc(&lzop->compressed[HEADER_MTIME_HIGH], (uint32_t)((t >> 32) & 0xffffffff)); /* Overwrite header checksum with calculated value. */- checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,+ checksum = lzo_adler32(1, lzop->compressed + HEADER_VERSION, (lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));- archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);+ archive_be32enc(&lzop->compressed[HEADER_H_CHECKSUM], checksum); return (sizeof(header)); } static int drive_compressor(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; unsigned char *p; const int block_info_bytes = 12; int header_bytes, r; lzo_uint usize, csize; uint32_t checksum; - if (!data->header_written) {+ if (!lzop->header_written) { header_bytes = make_header(f);- data->header_written = 1;+ lzop->header_written = 1; } else header_bytes = 0;- p = data->compressed;+ p = lzop->compressed; usize = (lzo_uint)- (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);+ (lzop->uncompressed_buffer_size - lzop->uncompressed_avail_bytes); csize = 0;- switch (data->method) {+ switch (lzop->method) { default: case METHOD_LZO1X_1:- r = lzo1x_1_compress(data->uncompressed, usize,+ r = lzo1x_1_compress(lzop->uncompressed, usize, p + header_bytes + block_info_bytes, &csize,- data->work_buffer);+ lzop->work_buffer); break; case METHOD_LZO1X_1_15:- r = lzo1x_1_15_compress(data->uncompressed, usize,+ r = lzo1x_1_15_compress(lzop->uncompressed, usize, p + header_bytes + block_info_bytes, &csize,- data->work_buffer);+ lzop->work_buffer); break; case METHOD_LZO1X_999:- r = lzo1x_999_compress_level(data->uncompressed, usize,+ r = lzo1x_999_compress_level(lzop->uncompressed, usize, p + header_bytes + block_info_bytes, &csize,- data->work_buffer, NULL, 0, 0, data->level);+ lzop->work_buffer, NULL, 0, 0, lzop->level); break; } if (r != LZO_E_OK) {@@ -361,13 +361,13 @@ /* Store uncompressed size. */ archive_be32enc(p + header_bytes, (uint32_t)usize); /* Store the checksum of the uncompressed data. */- checksum = lzo_adler32(1, data->uncompressed, usize);+ checksum = lzo_adler32(1, lzop->uncompressed, usize); archive_be32enc(p + header_bytes + 8, checksum); if (csize < usize) { /* Store compressed size. */ archive_be32enc(p + header_bytes + 4, (uint32_t)csize);- r = __archive_write_filter(f->next_filter, data->compressed,+ r = __archive_write_filter(f->next_filter, lzop->compressed, header_bytes + block_info_bytes + csize); } else { /*@@ -375,11 +375,11 @@ */ /* Store uncompressed size as compressed size. */ archive_be32enc(p + header_bytes + 4, (uint32_t)usize);- r = __archive_write_filter(f->next_filter, data->compressed,+ r = __archive_write_filter(f->next_filter, lzop->compressed, header_bytes + block_info_bytes); if (r != ARCHIVE_OK) return (ARCHIVE_FATAL);- r = __archive_write_filter(f->next_filter, data->uncompressed,+ r = __archive_write_filter(f->next_filter, lzop->uncompressed, usize); } @@ -392,30 +392,30 @@ archive_write_lzop_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; const char *p = buff; int r; do {- if (data->uncompressed_avail_bytes > length) {- memcpy(data->uncompressed- + data->uncompressed_buffer_size- - data->uncompressed_avail_bytes,+ if (lzop->uncompressed_avail_bytes > length) {+ memcpy(lzop->uncompressed+ + lzop->uncompressed_buffer_size+ - lzop->uncompressed_avail_bytes, p, length);- data->uncompressed_avail_bytes -= length;+ lzop->uncompressed_avail_bytes -= length; return (ARCHIVE_OK); } - memcpy(data->uncompressed + data->uncompressed_buffer_size- - data->uncompressed_avail_bytes,- p, data->uncompressed_avail_bytes);- length -= data->uncompressed_avail_bytes;- p += data->uncompressed_avail_bytes;- data->uncompressed_avail_bytes = 0;+ memcpy(lzop->uncompressed + lzop->uncompressed_buffer_size+ - lzop->uncompressed_avail_bytes,+ p, lzop->uncompressed_avail_bytes);+ length -= lzop->uncompressed_avail_bytes;+ p += lzop->uncompressed_avail_bytes;+ lzop->uncompressed_avail_bytes = 0; r = drive_compressor(f); if (r != ARCHIVE_OK) return (r);- data->uncompressed_avail_bytes = BLOCK_SIZE;+ lzop->uncompressed_avail_bytes = BLOCK_SIZE; } while (length); return (ARCHIVE_OK);@@ -424,11 +424,11 @@ static int archive_write_lzop_close(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; const uint32_t endmark = 0; int r; - if (data->uncompressed_avail_bytes < BLOCK_SIZE) {+ if (lzop->uncompressed_avail_bytes < BLOCK_SIZE) { /* Compress and output remaining data. */ r = drive_compressor(f); if (r != ARCHIVE_OK)@@ -439,24 +439,35 @@ return __archive_write_filter(f->next_filter, &endmark, sizeof(endmark)); } +static void+free_data(struct lzop *lzop)+{+ if (lzop != NULL) {+ free(lzop->uncompressed);+ free(lzop->compressed);+ free(lzop->work_buffer);+ free(lzop);+ }+}+ #else static int archive_write_lzop_open(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; struct archive_string as; int r; archive_string_init(&as); archive_strcpy(&as, "lzop"); /* Specify compression level. */- if (data->compression_level > 0) {+ if (lzop->compression_level > 0) { archive_strappend_char(&as, ' '); archive_strappend_char(&as, '-');- archive_strappend_char(&as, '0' + data->compression_level);+ archive_strappend_char(&as, '0' + lzop->compression_level); } - r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, lzop->pdata, as.s); archive_string_free(&as); return (r); }@@ -465,16 +476,25 @@ archive_write_lzop_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, lzop->pdata, buff, length); } static int archive_write_lzop_close(struct archive_write_filter *f) {- struct write_lzop *data = (struct write_lzop *)f->data;+ struct lzop *lzop = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, lzop->pdata);+}++static void+free_data(struct lzop *lzop)+{+ if (lzop != NULL) {+ __archive_write_program_free(lzop->pdata);+ free(lzop);+ } } #endif
c/archive_write_add_filter_program.c view
@@ -70,7 +70,7 @@ char *program_name; }; -struct private_data {+struct program { struct archive_write_program_data *pdata; struct archive_string description; char *cmd;@@ -81,51 +81,53 @@ const void *, size_t); static int archive_compressor_program_close(struct archive_write_filter *); static int archive_compressor_program_free(struct archive_write_filter *);+static void free_data(struct program *); /* * Add a filter to this write handle that passes all data through an * external program. */ int-archive_write_add_filter_program(struct archive *_a, const char *cmd)+archive_write_add_filter_program(struct archive *a, const char *cmd) {- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_data *data;+ struct archive_write_filter *f;+ struct program *program; static const char prefix[] = "Program: "; - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_program"); - f->data = calloc(1, sizeof(*data));- if (f->data == NULL)+ program = calloc(1, sizeof(*program));+ if (program == NULL) goto memerr;- data = (struct private_data *)f->data;-- data->cmd = strdup(cmd);- if (data->cmd == NULL)+ program->cmd = strdup(cmd);+ if (program->cmd == NULL) goto memerr;-- data->pdata = __archive_write_program_allocate(cmd);- if (data->pdata == NULL)+ program->pdata = __archive_write_program_allocate(cmd);+ if (program->pdata == NULL) goto memerr;- /* Make up a description string. */- if (archive_string_ensure(&data->description,+ if (archive_string_ensure(&program->description, strlen(prefix) + strlen(cmd) + 1) == NULL) goto memerr;- archive_strcpy(&data->description, prefix);- archive_strcat(&data->description, cmd);+ archive_strcpy(&program->description, prefix);+ archive_strcat(&program->description, cmd); - f->name = data->description.s;+ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = program->description.s; f->code = ARCHIVE_FILTER_PROGRAM;+ f->data = program; f->open = archive_compressor_program_open; f->write = archive_compressor_program_write; f->close = archive_compressor_program_close; f->free = archive_compressor_program_free;+ return (ARCHIVE_OK); memerr:- archive_compressor_program_free(f);- archive_set_error(_a, ENOMEM,+ free_data(program);+ archive_set_error(a, ENOMEM, "Can't allocate memory for filter program"); return (ARCHIVE_FATAL); }@@ -133,40 +135,33 @@ static int archive_compressor_program_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct program *program = f->data; - return __archive_write_program_open(f, data->pdata, data->cmd);+ return __archive_write_program_open(f, program->pdata, program->cmd); } static int archive_compressor_program_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct program *program = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, program->pdata, buff, length); } static int archive_compressor_program_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct program *program = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, program->pdata); } static int archive_compressor_program_free(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;-- if (data) {- free(data->cmd);- archive_string_free(&data->description);- __archive_write_program_free(data->pdata);- free(data);- f->data = NULL;- }+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK); } @@ -391,3 +386,13 @@ return ret; } +static void+free_data(struct program *program)+{+ if (program) {+ free(program->cmd);+ archive_string_free(&program->description);+ __archive_write_program_free(program->pdata);+ free(program);+ }+}
c/archive_write_add_filter_uuencode.c view
@@ -46,7 +46,7 @@ #define LBYTES 45 -struct private_uuencode {+struct uuencode { int mode; struct archive_string name; struct archive_string encoded_buff;@@ -64,39 +64,44 @@ static int archive_filter_uuencode_free(struct archive_write_filter *); static void uu_encode(struct archive_string *, const unsigned char *, size_t); static int64_t atol8(const char *, size_t);+static void free_data(struct uuencode *); /* * Add a compress filter to this write handle. */ int-archive_write_add_filter_uuencode(struct archive *_a)+archive_write_add_filter_uuencode(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_uuencode *state;+ struct archive_write_filter *f;+ struct uuencode *uuencode; - archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,+ ARCHIVE_STATE_NEW, "archive_write_add_filter_uuencode"); - state = calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for uuencode filter");- return (ARCHIVE_FATAL);- }- archive_strcpy(&state->name, "-");- state->mode = 0644;+ uuencode = calloc(1, sizeof(*uuencode));+ if (uuencode == NULL)+ goto memerr;+ archive_strcpy(&uuencode->name, "-");+ uuencode->mode = 0644; - f->data = state;+ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr; f->name = "uuencode"; f->code = ARCHIVE_FILTER_UU;- f->open = archive_filter_uuencode_open;+ f->data = uuencode; f->options = archive_filter_uuencode_options;+ f->open = archive_filter_uuencode_open; f->write = archive_filter_uuencode_write; f->close = archive_filter_uuencode_close; f->free = archive_filter_uuencode_free; return (ARCHIVE_OK);+memerr:+ free_data(uuencode);+ archive_set_error(a, ENOMEM,+ "Can't allocate data for uuencode filter");+ return (ARCHIVE_FATAL); } /*@@ -106,7 +111,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_uuencode *state = (struct private_uuencode *)f->data;+ struct uuencode *uuencode = f->data; if (strcmp(key, "mode") == 0) { int64_t val;@@ -122,7 +127,7 @@ "invalid mode option"); return (ARCHIVE_FAILED); }- state->mode = (int)val & 0777;+ uuencode->mode = (int)val & 0777; return (ARCHIVE_OK); } else if (strcmp(key, "name") == 0) { if (value == NULL) {@@ -130,7 +135,7 @@ "name option requires a string"); return (ARCHIVE_FAILED); }- archive_strcpy(&state->name, value);+ archive_strcpy(&uuencode->name, value); return (ARCHIVE_OK); } @@ -146,7 +151,7 @@ static int archive_filter_uuencode_open(struct archive_write_filter *f) {- struct private_uuencode *state = (struct private_uuencode *)f->data;+ struct uuencode *uuencode = f->data; size_t bs = 65536, bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {@@ -159,18 +164,17 @@ bs -= bs % bpb; } - state->bs = bs;- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {+ uuencode->bs = bs;+ if (archive_string_ensure(&uuencode->encoded_buff, bs + 512) == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for uuencode buffer"); return (ARCHIVE_FATAL); } - archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",- (unsigned int)state->mode, state->name.s);+ archive_string_sprintf(&uuencode->encoded_buff, "begin %o %s\n",+ (unsigned int)uuencode->mode, uuencode->name.s); - f->data = state;- return (0);+ return (ARCHIVE_OK); } static void@@ -216,39 +220,39 @@ archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_uuencode *state = (struct private_uuencode *)f->data;+ struct uuencode *uuencode = f->data; const unsigned char *p = buff; int ret = ARCHIVE_OK; if (length == 0) return (ret); - if (state->hold_len) {- while (state->hold_len < LBYTES && length > 0) {- state->hold[state->hold_len++] = *p++;+ if (uuencode->hold_len) {+ while (uuencode->hold_len < LBYTES && length > 0) {+ uuencode->hold[uuencode->hold_len++] = *p++; length--; }- if (state->hold_len < LBYTES)+ if (uuencode->hold_len < LBYTES) return (ret);- uu_encode(&state->encoded_buff, state->hold, LBYTES);- state->hold_len = 0;+ uu_encode(&uuencode->encoded_buff, uuencode->hold, LBYTES);+ uuencode->hold_len = 0; } for (; length >= LBYTES; length -= LBYTES, p += LBYTES)- uu_encode(&state->encoded_buff, p, LBYTES);+ uu_encode(&uuencode->encoded_buff, p, LBYTES); /* Save remaining bytes. */ if (length > 0) {- memcpy(state->hold, p, length);- state->hold_len = length;+ memcpy(uuencode->hold, p, length);+ uuencode->hold_len = length; }- while (archive_strlen(&state->encoded_buff) >= state->bs) {+ while (archive_strlen(&uuencode->encoded_buff) >= uuencode->bs) { ret = __archive_write_filter(f->next_filter,- state->encoded_buff.s, state->bs);- memmove(state->encoded_buff.s,- state->encoded_buff.s + state->bs,- state->encoded_buff.length - state->bs);- state->encoded_buff.length -= state->bs;+ uuencode->encoded_buff.s, uuencode->bs);+ memmove(uuencode->encoded_buff.s,+ uuencode->encoded_buff.s + uuencode->bs,+ uuencode->encoded_buff.length - uuencode->bs);+ uuencode->encoded_buff.length -= uuencode->bs; } return (ret);@@ -261,26 +265,24 @@ static int archive_filter_uuencode_close(struct archive_write_filter *f) {- struct private_uuencode *state = (struct private_uuencode *)f->data;+ struct uuencode *uuencode = f->data; /* Flush remaining bytes. */- if (state->hold_len != 0)- uu_encode(&state->encoded_buff, state->hold, state->hold_len);- archive_string_sprintf(&state->encoded_buff, "`\nend\n");+ if (uuencode->hold_len != 0)+ uu_encode(&uuencode->encoded_buff, uuencode->hold,+ uuencode->hold_len);+ archive_string_sprintf(&uuencode->encoded_buff, "`\nend\n"); /* Write the last block */ archive_write_set_bytes_in_last_block(f->archive, 1); return __archive_write_filter(f->next_filter,- state->encoded_buff.s, archive_strlen(&state->encoded_buff));+ uuencode->encoded_buff.s, archive_strlen(&uuencode->encoded_buff)); } static int archive_filter_uuencode_free(struct archive_write_filter *f) {- struct private_uuencode *state = (struct private_uuencode *)f->data;-- archive_string_free(&state->name);- archive_string_free(&state->encoded_buff);- free(state);+ free_data(f->data);+ f->data = NULL; return (ARCHIVE_OK); } @@ -307,3 +309,12 @@ return (l); } +static void+free_data(struct uuencode *uuencode)+{+ if (uuencode != NULL) {+ archive_string_free(&uuencode->name);+ archive_string_free(&uuencode->encoded_buff);+ free(uuencode);+ }+}
c/archive_write_add_filter_xz.c view
@@ -99,7 +99,7 @@ #else /* Don't compile this if we don't have liblzma. */ -struct private_data {+struct xz { int compression_level; uint32_t threads; lzma_stream stream;@@ -121,7 +121,8 @@ static int archive_compressor_xz_close(struct archive_write_filter *); static int archive_compressor_xz_free(struct archive_write_filter *); static int drive_compressor(struct archive_write_filter *,- struct private_data *, int finishing);+ struct xz *, int finishing);+static void free_data(struct xz *); struct option_value { uint32_t dict_size;@@ -142,85 +143,72 @@ }; static int-common_setup(struct archive_write_filter *f)+common_setup(struct archive *a, const char *name, int code) {- struct private_data *data;- struct archive_write *a = (struct archive_write *)f->archive;- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- f->data = data;- data->compression_level = LZMA_PRESET_DEFAULT;- data->threads = 1;- f->open = &archive_compressor_xz_open;+ struct xz *xz;+ struct archive_write_filter *f;++ xz = calloc(1, sizeof(*xz));+ if (xz == NULL)+ goto memerr;+ xz->compression_level = LZMA_PRESET_DEFAULT;+ xz->threads = 1;++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = name;+ f->code = code;+ f->data = xz;+ f->options = archive_compressor_xz_options;+ f->open = archive_compressor_xz_open;+ f->write = archive_compressor_xz_write; f->close = archive_compressor_xz_close; f->free = archive_compressor_xz_free;- f->options = &archive_compressor_xz_options;+ return (ARCHIVE_OK);+memerr:+ free_data(xz);+ archive_set_error(a, ENOMEM, "Out of memory");+ return (ARCHIVE_FATAL); } /* * Add an xz compression filter to this write handle. */ int-archive_write_add_filter_xz(struct archive *_a)+archive_write_add_filter_xz(struct archive *a) {- struct archive_write_filter *f;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_XZ;- f->name = "xz";- }- return (r);++ return common_setup(a, "xz", ARCHIVE_FILTER_XZ); } /* LZMA is handled identically, we just need a different compression * code set. (The liblzma setup looks at the code to determine * the one place that XZ and LZMA require different handling.) */ int-archive_write_add_filter_lzma(struct archive *_a)+archive_write_add_filter_lzma(struct archive *a) {- struct archive_write_filter *f;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_LZMA;- f->name = "lzma";- }- return (r);++ return common_setup(a, "lzma", ARCHIVE_FILTER_LZMA); } int-archive_write_add_filter_lzip(struct archive *_a)+archive_write_add_filter_lzip(struct archive *a) {- struct archive_write_filter *f;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_LZIP;- f->name = "lzip";- }- return (r);++ return common_setup(a, "lzip", ARCHIVE_FILTER_LZIP); } static int archive_compressor_xz_init_stream(struct archive_write_filter *f,- struct private_data *data)+ struct xz *xz) { static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT; int ret;@@ -228,27 +216,27 @@ lzma_mt mt_options; #endif - data->stream = lzma_stream_init_data;- data->stream.next_out = data->compressed;- data->stream.avail_out = data->compressed_buffer_size;+ xz->stream = lzma_stream_init_data;+ xz->stream.next_out = xz->compressed;+ xz->stream.avail_out = xz->compressed_buffer_size; if (f->code == ARCHIVE_FILTER_XZ) { #ifdef HAVE_LZMA_STREAM_ENCODER_MT- if (data->threads != 1) {+ if (xz->threads != 1) { memset(&mt_options, 0, sizeof(mt_options));- mt_options.threads = data->threads;+ mt_options.threads = xz->threads; mt_options.timeout = 300;- mt_options.filters = data->lzmafilters;+ mt_options.filters = xz->lzmafilters; mt_options.check = LZMA_CHECK_CRC64;- ret = lzma_stream_encoder_mt(&(data->stream),+ ret = lzma_stream_encoder_mt(&(xz->stream), &mt_options); } else #endif- ret = lzma_stream_encoder(&(data->stream),- data->lzmafilters, LZMA_CHECK_CRC64);+ ret = lzma_stream_encoder(&(xz->stream),+ xz->lzmafilters, LZMA_CHECK_CRC64); } else if (f->code == ARCHIVE_FILTER_LZMA) {- ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);+ ret = lzma_alone_encoder(&(xz->stream), &xz->lzma_opt); } else { /* ARCHIVE_FILTER_LZIP */- int dict_size = data->lzma_opt.dict_size;+ int dict_size = xz->lzma_opt.dict_size; int ds, log2dic, wedges; /* Calculate a coded dictionary size */@@ -270,18 +258,18 @@ wedges = 0; ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f); - data->crc32 = 0;+ xz->crc32 = 0; /* Make a header */- data->compressed[0] = 0x4C;- data->compressed[1] = 0x5A;- data->compressed[2] = 0x49;- data->compressed[3] = 0x50;- data->compressed[4] = 1;/* Version */- data->compressed[5] = (unsigned char)ds;- data->stream.next_out += 6;- data->stream.avail_out -= 6;+ xz->compressed[0] = 0x4C;+ xz->compressed[1] = 0x5A;+ xz->compressed[2] = 0x49;+ xz->compressed[3] = 0x50;+ xz->compressed[4] = 1;/* Version */+ xz->compressed[5] = (unsigned char)ds;+ xz->stream.next_out += 6;+ xz->stream.avail_out -= 6; - ret = lzma_raw_encoder(&(data->stream), data->lzmafilters);+ ret = lzma_raw_encoder(&(xz->stream), xz->lzmafilters); } if (ret == LZMA_OK) return (ARCHIVE_OK);@@ -307,10 +295,10 @@ static int archive_compressor_xz_open(struct archive_write_filter *f) {- struct private_data *data = f->data;+ struct xz *xz = f->data; int ret; - if (data->compressed == NULL) {+ if (xz->compressed == NULL) { size_t bs = 65536, bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of the bytes@@ -321,49 +309,46 @@ else if (bpb != 0) bs -= bs % bpb; }- data->compressed_buffer_size = bs;- data->compressed = malloc(data->compressed_buffer_size);- if (data->compressed == NULL) {+ xz->compressed_buffer_size = bs;+ xz->compressed = malloc(xz->compressed_buffer_size);+ if (xz->compressed == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } } - f->write = archive_compressor_xz_write;- /* Initialize compression library. */ if (f->code == ARCHIVE_FILTER_LZIP) { const struct option_value *val =- &option_values[data->compression_level];+ &option_values[xz->compression_level]; - data->lzma_opt.dict_size = val->dict_size;- data->lzma_opt.preset_dict = NULL;- data->lzma_opt.preset_dict_size = 0;- data->lzma_opt.lc = LZMA_LC_DEFAULT;- data->lzma_opt.lp = LZMA_LP_DEFAULT;- data->lzma_opt.pb = LZMA_PB_DEFAULT;- data->lzma_opt.mode =- data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;- data->lzma_opt.nice_len = val->nice_len;- data->lzma_opt.mf = val->mf;- data->lzma_opt.depth = 0;- data->lzmafilters[0].id = LZMA_FILTER_LZMA1;- data->lzmafilters[0].options = &data->lzma_opt;- data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */+ xz->lzma_opt.dict_size = val->dict_size;+ xz->lzma_opt.preset_dict = NULL;+ xz->lzma_opt.preset_dict_size = 0;+ xz->lzma_opt.lc = LZMA_LC_DEFAULT;+ xz->lzma_opt.lp = LZMA_LP_DEFAULT;+ xz->lzma_opt.pb = LZMA_PB_DEFAULT;+ xz->lzma_opt.mode =+ xz->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;+ xz->lzma_opt.nice_len = val->nice_len;+ xz->lzma_opt.mf = val->mf;+ xz->lzma_opt.depth = 0;+ xz->lzmafilters[0].id = LZMA_FILTER_LZMA1;+ xz->lzmafilters[0].options = &xz->lzma_opt;+ xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ } else {- if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {+ if (lzma_lzma_preset(&xz->lzma_opt, xz->compression_level)) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing compression library"); }- data->lzmafilters[0].id = LZMA_FILTER_LZMA2;- data->lzmafilters[0].options = &data->lzma_opt;- data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */+ xz->lzmafilters[0].id = LZMA_FILTER_LZMA2;+ xz->lzmafilters[0].options = &xz->lzma_opt;+ xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ }- ret = archive_compressor_xz_init_stream(f, data);+ ret = archive_compressor_xz_init_stream(f, xz); if (ret == LZMA_OK) {- f->data = data;- return (0);+ return (ARCHIVE_OK); } return (ARCHIVE_FATAL); }@@ -375,7 +360,7 @@ archive_compressor_xz_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_data *data = (struct private_data *)f->data;+ struct xz *xz = f->data; if (strcmp(key, "compression-level") == 0) { if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -384,9 +369,9 @@ "compression-level invalid"); return (ARCHIVE_FAILED); }- data->compression_level = value[0] - '0';- if (data->compression_level > 9)- data->compression_level = 9;+ xz->compression_level = value[0] - '0';+ if (xz->compression_level > 9)+ xz->compression_level = 9; return (ARCHIVE_OK); } else if (strcmp(key, "threads") == 0) { char *endptr;@@ -400,17 +385,17 @@ errno = 0; val = strtoul(value, &endptr, 10); if (errno != 0 || *endptr != '\0' || val > (unsigned)INT_MAX) {- data->threads = 1;+ xz->threads = 1; archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "threads invalid"); return (ARCHIVE_FAILED); }- data->threads = (int)val;- if (data->threads == 0) {+ xz->threads = (int)val;+ if (xz->threads == 0) { #ifdef HAVE_LZMA_STREAM_ENCODER_MT- data->threads = lzma_cputhreads();+ xz->threads = lzma_cputhreads(); #else- data->threads = 1;+ xz->threads = 1; #endif } return (ARCHIVE_OK);@@ -429,18 +414,18 @@ archive_compressor_xz_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct xz *xz = f->data; int ret; /* Update statistics */- data->total_in += length;+ xz->total_in += length; if (f->code == ARCHIVE_FILTER_LZIP)- data->crc32 = lzma_crc32(buff, length, data->crc32);+ xz->crc32 = lzma_crc32(buff, length, xz->crc32); /* Compress input data to output buffer */- data->stream.next_in = buff;- data->stream.avail_in = length;- if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)+ xz->stream.next_in = buff;+ xz->stream.avail_in = length;+ if ((ret = drive_compressor(f, xz, 0)) != ARCHIVE_OK) return (ret); return (ARCHIVE_OK);@@ -453,34 +438,32 @@ static int archive_compressor_xz_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct xz *xz = f->data; int ret; - ret = drive_compressor(f, data, 1);+ ret = drive_compressor(f, xz, 1); if (ret == ARCHIVE_OK) {- data->total_out +=- data->compressed_buffer_size - data->stream.avail_out;+ xz->total_out +=+ xz->compressed_buffer_size - xz->stream.avail_out; ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size - data->stream.avail_out);+ xz->compressed,+ xz->compressed_buffer_size - xz->stream.avail_out); if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {- archive_le32enc(data->compressed, data->crc32);- archive_le64enc(data->compressed+4, data->total_in);- archive_le64enc(data->compressed+12, data->total_out + 20);+ archive_le32enc(xz->compressed, xz->crc32);+ archive_le64enc(xz->compressed+4, xz->total_in);+ archive_le64enc(xz->compressed+12, xz->total_out + 20); ret = __archive_write_filter(f->next_filter,- data->compressed, 20);+ xz->compressed, 20); } }- lzma_end(&(data->stream));+ lzma_end(&(xz->stream)); return ret; } static int archive_compressor_xz_free(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;- free(data->compressed);- free(data);+ free_data(f->data); f->data = NULL; return (ARCHIVE_OK); }@@ -494,34 +477,34 @@ */ static int drive_compressor(struct archive_write_filter *f,- struct private_data *data, int finishing)+ struct xz *xz, int finishing) { int ret; for (;;) {- if (data->stream.avail_out == 0) {- data->total_out += data->compressed_buffer_size;+ if (xz->stream.avail_out == 0) {+ xz->total_out += xz->compressed_buffer_size; ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size);+ xz->compressed,+ xz->compressed_buffer_size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL);- data->stream.next_out = data->compressed;- data->stream.avail_out = data->compressed_buffer_size;+ xz->stream.next_out = xz->compressed;+ xz->stream.avail_out = xz->compressed_buffer_size; } /* If there's nothing to do, we're done. */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && xz->stream.avail_in == 0) return (ARCHIVE_OK); - ret = lzma_code(&(data->stream),+ ret = lzma_code(&(xz->stream), finishing ? LZMA_FINISH : LZMA_RUN ); switch (ret) { case LZMA_OK: /* In non-finishing case, check if compressor * consumed everything */- if (!finishing && data->stream.avail_in == 0)+ if (!finishing && xz->stream.avail_in == 0) return (ARCHIVE_OK); /* In finishing case, this return always means * there's more work */@@ -537,7 +520,7 @@ archive_set_error(f->archive, ENOMEM, "lzma compression error: " "%ju MiB would have been needed",- (uintmax_t)((lzma_memusage(&(data->stream))+ (uintmax_t)((lzma_memusage(&(xz->stream)) + 1024 * 1024 -1) / (1024 * 1024))); return (ARCHIVE_FATAL);@@ -549,6 +532,15 @@ ret); return (ARCHIVE_FATAL); }+ }+}++static void+free_data(struct xz *xz)+{+ if (xz != NULL) {+ free(xz->compressed);+ free(xz); } }
c/archive_write_add_filter_zstd.c view
@@ -55,7 +55,7 @@ /* Don't compile this if we don't have zstd.h */ -struct private_data {+struct zstd { int compression_level; int threads; int long_distance;@@ -103,79 +103,77 @@ static int archive_compressor_zstd_free(struct archive_write_filter *); #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream static int drive_compressor(struct archive_write_filter *,- struct private_data *, int, const void *, size_t);+ struct zstd *, int, const void *, size_t); #endif+static void free_data(struct zstd *); /* * Add a zstd compression filter to this write handle. */ int-archive_write_add_filter_zstd(struct archive *_a)+archive_write_add_filter_zstd(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_data *data;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+ struct archive_write_filter *f;+ struct zstd *zstd;+ int r;++ archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_zstd"); - data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- f->data = data;- f->open = &archive_compressor_zstd_open;- f->options = &archive_compressor_zstd_options;- f->flush = &archive_compressor_zstd_flush;- f->close = &archive_compressor_zstd_close;- f->free = &archive_compressor_zstd_free;- f->code = ARCHIVE_FILTER_ZSTD;- f->name = "zstd";- data->compression_level = CLEVEL_DEFAULT;- data->threads = 0;- data->long_distance = 0;+ zstd = calloc(1, sizeof(*zstd));+ if (zstd == NULL)+ goto memerr;+ zstd->compression_level = CLEVEL_DEFAULT;+ zstd->threads = 0;+ zstd->long_distance = 0; #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream- data->frame_per_file = 0;- data->min_frame_in = 0;- data->max_frame_in = SIZE_MAX;- data->min_frame_out = 0;- data->max_frame_out = SIZE_MAX;- data->cur_frame_in = 0;- data->cur_frame_out = 0;- data->cstream = ZSTD_createCStream();- if (data->cstream == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM,- "Failed to allocate zstd compressor object");- return (ARCHIVE_FATAL);- }+ zstd->frame_per_file = 0;+ zstd->min_frame_in = 0;+ zstd->max_frame_in = SIZE_MAX;+ zstd->min_frame_out = 0;+ zstd->max_frame_out = SIZE_MAX;+ zstd->cur_frame_in = 0;+ zstd->cur_frame_out = 0;+ zstd->cstream = ZSTD_createCStream();+ if (zstd->cstream == NULL)+ goto memerr; - return (ARCHIVE_OK);+ r = ARCHIVE_OK; #else- data->pdata = __archive_write_program_allocate("zstd");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ zstd->pdata = __archive_write_program_allocate("zstd");+ if (zstd->pdata == NULL)+ goto memerr;++ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Using external zstd program");- return (ARCHIVE_WARN);+ r = ARCHIVE_WARN; #endif++ f = __archive_write_allocate_filter(a);+ if (f == NULL)+ goto memerr;+ f->name = "zstd";+ f->code = ARCHIVE_FILTER_ZSTD;+ f->data = zstd;+ f->options = archive_compressor_zstd_options;+ f->open = archive_compressor_zstd_open;+ f->write = archive_compressor_zstd_write;+ f->flush = archive_compressor_zstd_flush;+ f->close = archive_compressor_zstd_close;+ f->free = archive_compressor_zstd_free;++ return (r);+memerr:+ free_data(zstd);+ archive_set_error(a, ENOMEM, "Out of memory");+ return (ARCHIVE_FATAL); } static int archive_compressor_zstd_free(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;-#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream- ZSTD_freeCStream(data->cstream);- free(data->out.dst);-#else- __archive_write_program_free(data->pdata);-#endif- free(data);+ free_data(f->data); f->data = NULL; return (ARCHIVE_OK); }@@ -239,7 +237,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key, const char *value) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; if (strcmp(key, "compression-level") == 0) { intmax_t level;@@ -268,7 +266,7 @@ "compression-level out of range"); return (ARCHIVE_FAILED); }- data->compression_level = (int)level;+ zstd->compression_level = (int)level; return (ARCHIVE_OK); } else if (strcmp(key, "threads") == 0) { intmax_t threads;@@ -295,14 +293,14 @@ "threads out of rnage"); return (ARCHIVE_FAILED); }- data->threads = (int)threads;+ zstd->threads = (int)threads; return (ARCHIVE_OK); #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream } else if (strcmp(key, "frame-per-file") == 0) {- data->frame_per_file = 1;+ zstd->frame_per_file = 1; return (ARCHIVE_OK); } else if (strcmp(key, "min-frame-in") == 0) {- if (string_to_size(value, &data->min_frame_in) != ARCHIVE_OK) {+ if (string_to_size(value, &zstd->min_frame_in) != ARCHIVE_OK) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "min-frame-in invalid"); return (ARCHIVE_FAILED);@@ -310,7 +308,7 @@ return (ARCHIVE_OK); } else if (strcmp(key, "min-frame-out") == 0 || strcmp(key, "min-frame-size") == 0) {- if (string_to_size(value, &data->min_frame_out) != ARCHIVE_OK) {+ if (string_to_size(value, &zstd->min_frame_out) != ARCHIVE_OK) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "min-frame-out invalid"); return (ARCHIVE_FAILED);@@ -318,16 +316,16 @@ return (ARCHIVE_OK); } else if (strcmp(key, "max-frame-in") == 0 || strcmp(key, "max-frame-size") == 0) {- if (string_to_size(value, &data->max_frame_in) != ARCHIVE_OK ||- data->max_frame_in < 1024) {+ if (string_to_size(value, &zstd->max_frame_in) != ARCHIVE_OK ||+ zstd->max_frame_in < 1024) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "max-frame-size invalid"); return (ARCHIVE_FAILED); } return (ARCHIVE_OK); } else if (strcmp(key, "max-frame-out") == 0) {- if (string_to_size(value, &data->max_frame_out) != ARCHIVE_OK ||- data->max_frame_out < 1024) {+ if (string_to_size(value, &zstd->max_frame_out) != ARCHIVE_OK ||+ zstd->max_frame_out < 1024) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "max-frame-out invalid"); return (ARCHIVE_FAILED);@@ -363,7 +361,7 @@ if (((int)long_distance) < 10 || (int)long_distance > max_distance) return (ARCHIVE_FAILED); #endif- data->long_distance = (int)long_distance;+ zstd->long_distance = (int)long_distance; return (ARCHIVE_OK); } @@ -380,9 +378,9 @@ static int archive_compressor_zstd_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - if (data->out.dst == NULL) {+ if (zstd->out.dst == NULL) { size_t bs = ZSTD_CStreamOutSize(), bpb; if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { /* Buffer size should be a multiple number of@@ -393,31 +391,29 @@ else if (bpb != 0) bs -= bs % bpb; }- data->out.size = bs;- data->out.pos = 0;- data->out.dst = malloc(data->out.size);- if (data->out.dst == NULL) {+ zstd->out.size = bs;+ zstd->out.pos = 0;+ zstd->out.dst = malloc(zstd->out.size);+ if (zstd->out.dst == NULL) { archive_set_error(f->archive, ENOMEM, "Can't allocate data for compression buffer"); return (ARCHIVE_FATAL); } } - f->write = archive_compressor_zstd_write;-- if (ZSTD_isError(ZSTD_initCStream(data->cstream,- data->compression_level))) {+ if (ZSTD_isError(ZSTD_initCStream(zstd->cstream,+ zstd->compression_level))) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing zstd compressor object"); return (ARCHIVE_FATAL); } - ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads);+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_nbWorkers, zstd->threads); - ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_checksumFlag, 1);+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_checksumFlag, 1); #if ZSTD_VERSION_NUMBER >= MINVER_LONG- ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_windowLog, data->long_distance);+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_windowLog, zstd->long_distance); #endif return (ARCHIVE_OK);@@ -430,9 +426,9 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - return (drive_compressor(f, data, 0, buff, length));+ return (drive_compressor(f, zstd, 0, buff, length)); } /*@@ -441,15 +437,15 @@ static int archive_compressor_zstd_flush(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - if (data->frame_per_file && data->state == running) {- if (data->cur_frame_in > data->min_frame_in &&- data->cur_frame_out > data->min_frame_out) {- data->state = finishing;+ if (zstd->frame_per_file && zstd->state == running) {+ if (zstd->cur_frame_in > zstd->min_frame_in &&+ zstd->cur_frame_out > zstd->min_frame_out) {+ zstd->state = finishing; } }- return (drive_compressor(f, data, 1, NULL, 0));+ return (drive_compressor(f, zstd, 1, NULL, 0)); } /*@@ -458,11 +454,11 @@ static int archive_compressor_zstd_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - if (data->state == running)- data->state = finishing;- return (drive_compressor(f, data, 1, NULL, 0));+ if (zstd->state == running)+ zstd->state = finishing;+ return (drive_compressor(f, zstd, 1, NULL, 0)); } /*@@ -471,7 +467,7 @@ */ static int drive_compressor(struct archive_write_filter *f,- struct private_data *data, int flush, const void *src, size_t length)+ struct zstd *zstd, int flush, const void *src, size_t length) { ZSTD_inBuffer in = { .src = src, .size = length, .pos = 0 }; size_t ipos, opos, zstdret = 0;@@ -479,46 +475,46 @@ for (;;) { ipos = in.pos;- opos = data->out.pos;- switch (data->state) {+ opos = zstd->out.pos;+ switch (zstd->state) { case running: if (in.pos == in.size) return (ARCHIVE_OK);- zstdret = ZSTD_compressStream(data->cstream,- &data->out, &in);+ zstdret = ZSTD_compressStream(zstd->cstream,+ &zstd->out, &in); if (ZSTD_isError(zstdret)) goto zstd_fatal; break; case finishing:- zstdret = ZSTD_endStream(data->cstream, &data->out);+ zstdret = ZSTD_endStream(zstd->cstream, &zstd->out); if (ZSTD_isError(zstdret)) goto zstd_fatal; if (zstdret == 0)- data->state = resetting;+ zstd->state = resetting; break; case resetting:- ZSTD_CCtx_reset(data->cstream, ZSTD_reset_session_only);- data->cur_frame++;- data->cur_frame_in = 0;- data->cur_frame_out = 0;- data->state = running;+ ZSTD_CCtx_reset(zstd->cstream, ZSTD_reset_session_only);+ zstd->cur_frame++;+ zstd->cur_frame_in = 0;+ zstd->cur_frame_out = 0;+ zstd->state = running; break; }- data->cur_frame_in += in.pos - ipos;- data->cur_frame_out += data->out.pos - opos;- if (data->state == running) {- if (data->cur_frame_in >= data->max_frame_in ||- data->cur_frame_out >= data->max_frame_out) {- data->state = finishing;+ zstd->cur_frame_in += in.pos - ipos;+ zstd->cur_frame_out += zstd->out.pos - opos;+ if (zstd->state == running) {+ if (zstd->cur_frame_in >= zstd->max_frame_in ||+ zstd->cur_frame_out >= zstd->max_frame_out) {+ zstd->state = finishing; } }- if (data->out.pos == data->out.size ||- (flush && data->out.pos > 0)) {+ if (zstd->out.pos == zstd->out.size ||+ (flush && zstd->out.pos > 0)) { ret = __archive_write_filter(f->next_filter,- data->out.dst, data->out.pos);+ zstd->out.dst, zstd->out.pos); if (ret != ARCHIVE_OK) goto fatal;- data->out.pos = 0;+ zstd->out.pos = 0; } } zstd_fatal:@@ -529,12 +525,22 @@ return (ARCHIVE_FATAL); } +static void+free_data(struct zstd *zstd)+{+ if (zstd != NULL) {+ ZSTD_freeCStream(zstd->cstream);+ free(zstd->out.dst);+ free(zstd);+ }+}+ #else /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */ static int archive_compressor_zstd_open(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; struct archive_string as; int r; @@ -542,26 +548,25 @@ /* --no-check matches library default */ archive_strcpy(&as, "zstd --no-check"); - if (data->compression_level < CLEVEL_STD_MIN) {- archive_string_sprintf(&as, " --fast=%d", -data->compression_level);+ if (zstd->compression_level < CLEVEL_STD_MIN) {+ archive_string_sprintf(&as, " --fast=%d", -zstd->compression_level); } else {- archive_string_sprintf(&as, " -%d", data->compression_level);+ archive_string_sprintf(&as, " -%d", zstd->compression_level); } - if (data->compression_level > CLEVEL_STD_MAX) {+ if (zstd->compression_level > CLEVEL_STD_MAX) { archive_strcat(&as, " --ultra"); } - if (data->threads != 0) {- archive_string_sprintf(&as, " --threads=%d", data->threads);+ if (zstd->threads != 0) {+ archive_string_sprintf(&as, " --threads=%d", zstd->threads); } - if (data->long_distance != 0) {- archive_string_sprintf(&as, " --long=%d", data->long_distance);+ if (zstd->long_distance != 0) {+ archive_string_sprintf(&as, " --long=%d", zstd->long_distance); } - f->write = archive_compressor_zstd_write;- r = __archive_write_program_open(f, data->pdata, as.s);+ r = __archive_write_program_open(f, zstd->pdata, as.s); archive_string_free(&as); return (r); }@@ -570,9 +575,9 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff, size_t length) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - return __archive_write_program_write(f, data->pdata, buff, length);+ return __archive_write_program_write(f, zstd->pdata, buff, length); } static int@@ -586,9 +591,18 @@ static int archive_compressor_zstd_close(struct archive_write_filter *f) {- struct private_data *data = (struct private_data *)f->data;+ struct zstd *zstd = f->data; - return __archive_write_program_close(f, data->pdata);+ return __archive_write_program_close(f, zstd->pdata);+}++static void+free_data(struct zstd *zstd)+{+ if (zstd != NULL) {+ __archive_write_program_free(zstd->pdata);+ free(zstd);+ } } #endif /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */
c/archive_write_disk_posix.c view
@@ -300,7 +300,7 @@ uint32_t compressed_rsrc_position; uint32_t compressed_rsrc_position_v; /* Buffer for uncompressed data. */- char *uncompressed_buffer;+ unsigned char *uncompressed_buffer; size_t block_remaining_bytes; size_t file_remaining_bytes; #ifdef HAVE_ZLIB_H@@ -1254,7 +1254,7 @@ hfs_decompress(struct archive_write_disk *a) { uint32_t *block_info;- unsigned int block_count;+ uint32_t block_count; uint32_t data_pos, data_size; ssize_t r; ssize_t bytes_written, bytes_to_write;@@ -1277,10 +1277,10 @@ bytes_to_write = data_size -1; b = a->compressed_buffer + 1; } else {- uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;+ size_t dest_len = MAX_DECMPFS_BLOCK_SIZE; int zr; - zr = uncompress((Bytef *)a->uncompressed_buffer,+ zr = uncompress(a->uncompressed_buffer, &dest_len, a->compressed_buffer, data_size); if (zr != Z_OK) { archive_set_error(&a->archive,@@ -1289,7 +1289,7 @@ return (ARCHIVE_WARN); } bytes_to_write = dest_len;- b = (unsigned char *)a->uncompressed_buffer;+ b = a->uncompressed_buffer; } do { bytes_written = write(a->fd, b, bytes_to_write);@@ -1472,8 +1472,7 @@ if (a->decmpfs_block_count == (unsigned)-1) { void *new_block;- size_t new_size;- unsigned int block_count;+ size_t block_count, new_size; if (a->decmpfs_header_p == NULL) { new_block = malloc(MAX_DECMPFS_XATTR_SIZE@@ -1493,13 +1492,20 @@ archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], a->filesize); - /* Calculate a block count of the file. */- block_count =- (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /- MAX_DECMPFS_BLOCK_SIZE; /*+ * Calculate block count for the file.+ */+ block_count = (a->filesize + MAX_DECMPFS_BLOCK_SIZE - 1) /+ MAX_DECMPFS_BLOCK_SIZE;+ if (block_count > (SIZE_MAX - RSRC_H_SIZE - 4 - RSRC_F_SIZE) /+ (sizeof(uint32_t) * 2) || block_count > UINT32_MAX) {+ archive_set_error(&a->archive, EFBIG, "File too big");+ return (ARCHIVE_FATAL);+ }++ /* * Allocate buffer for resource fork.- * Set up related pointers;+ * Set up related pointers. */ new_size = RSRC_H_SIZE + /* header */@@ -1540,7 +1546,7 @@ a->decmpfs_block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); /* Set the block count to the resource fork. */- archive_le32enc(a->decmpfs_block_info++, block_count);+ archive_le32enc(a->decmpfs_block_info++, (uint32_t)block_count); /* Get the position where we are going to set compressed * data. */ a->compressed_rsrc_position =@@ -2369,7 +2375,7 @@ #endif if (r != 0) r = errno;- else if ((st.st_mode & AE_IFMT) == AE_IFREG) {+ else if (S_ISREG(st.st_mode)) { a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC | O_NOFOLLOW); __archive_ensure_cloexec_flag(a->fd);@@ -4344,7 +4350,7 @@ * with at least a writing mode(O_RDWR or O_WRONLY). it * makes the data fork uncompressed. */- dffd = open(datafork, 0);+ dffd = open(datafork, O_SYMLINK); if (dffd == -1) { archive_set_error(&a->archive, errno, "Failed to open the data fork for metadata");@@ -4446,14 +4452,16 @@ */ archive_strncpy(&datafork, pathname, p - pathname); archive_strcat(&datafork, p + 2);- if ( #ifdef HAVE_LSTAT- lstat(datafork.s, &st) == -1 ||+ if (lstat(datafork.s, &st) == -1)+ goto skip_appledouble; #else- la_stat(datafork.s, &st) == -1 ||+ if (la_stat(datafork.s, &st) == -1)+ goto skip_appledouble; #endif- (((st.st_mode & AE_IFMT) != AE_IFREG) &&- ((st.st_mode & AE_IFMT) != AE_IFDIR)))+ if (!S_ISREG(st.st_mode) &&+ !S_ISDIR(st.st_mode) &&+ !S_ISLNK(st.st_mode)) goto skip_appledouble; /*
c/archive_write_disk_set_standard_lookup.c view
@@ -45,6 +45,7 @@ #endif #include "archive.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" #include "archive_write_disk_private.h"@@ -134,7 +135,8 @@ break; if (r != ERANGE) break;- bufsize *= 2;+ if (archive_ckd_mul_size(&bufsize, bufsize, 2))+ break; free(allocated); allocated = malloc(bufsize); if (allocated == NULL)@@ -203,7 +205,8 @@ break; if (r != ERANGE) break;- bufsize *= 2;+ if (archive_ckd_mul_size(&bufsize, bufsize, 2))+ break; free(allocated); allocated = malloc(bufsize); if (allocated == NULL)
c/archive_write_disk_windows.c view
@@ -194,6 +194,8 @@ static int disk_unlink(const wchar_t *); static int disk_rmdir(const wchar_t *);+static int check_symlinks_by_path(struct archive_write_disk *,+ wchar_t *, size_t *, int); static int check_symlinks(struct archive_write_disk *); static int create_filesystem_object(struct archive_write_disk *); static struct fixup_entry *current_fixup(struct archive_write_disk *,@@ -244,8 +246,8 @@ ((((int64_t)(bhfi)->nFileSizeHigh) << 32) | (bhfi)->nFileSizeLow) static int-file_information(struct archive_write_disk *a, wchar_t *path,- BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat)+file_information(wchar_t *path, BY_HANDLE_FILE_INFORMATION *st,+ mode_t *mode, int sim_lstat) { HANDLE h; int r;@@ -282,10 +284,10 @@ ZeroMemory(&createExParams, sizeof(createExParams)); createExParams.dwSize = sizeof(createExParams); createExParams.dwFileFlags = flag;- h = CreateFile2(a->name, 0, 0,+ h = CreateFile2(path, 0, 0, OPEN_EXISTING, &createExParams); #else- h = CreateFileW(a->name, 0, 0, NULL,+ h = CreateFileW(path, 0, 0, NULL, OPEN_EXISTING, flag, NULL); #endif if (h == INVALID_HANDLE_VALUE &&@@ -629,6 +631,7 @@ DWORD attrs = 0; DWORD flags = 0; DWORD newflags = 0;+ DWORD lasterr = 0; len = wcslen(target); if (len == 0) {@@ -693,10 +696,14 @@ ret = CreateSymbolicLinkW(linkname, ttarget, newflags); /* * Prior to Windows 10 calling CreateSymbolicLinkW() will fail- * if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set+ * if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set; however,+ * trying this fallback if we fail due to a bad path will replace+ * ENOENT with EPERM and confuse later error recovery efforts. */ if (!ret) {- ret = CreateSymbolicLinkW(linkname, ttarget, flags);+ lasterr = GetLastError();+ if (lasterr != ERROR_PATH_NOT_FOUND)+ ret = CreateSymbolicLinkW(linkname, ttarget, flags); } free(ttarget); #endif@@ -741,7 +748,7 @@ * XXX At this point, symlinks should not be hit, otherwise * XXX a race occurred. Do we want to check explicitly for that? */- if (file_information(a, a->name, &a->st, NULL, 1) == 0) {+ if (file_information(a->name, &a->st, NULL, 1) == 0) { a->pst = &a->st; return (ARCHIVE_OK); }@@ -1516,7 +1523,7 @@ * such symlinks. We always need both source and target * information. */- r = file_information(a, a->name, &lst, &lst_mode, 1);+ r = file_information(a->name, &lst, &lst_mode, 1); if (r != 0) { archive_set_error(&a->archive, errno, "Can't stat existing object");@@ -1525,7 +1532,7 @@ if (lst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dirlnk = 1; /* In case of a symlink we need target information */- r = file_information(a, a->name, &a->st, &st_mode, 0);+ r = file_information(a->name, &a->st, &st_mode, 0); if (r != 0) { a->st = lst; st_mode = lst_mode;@@ -1653,6 +1660,7 @@ mode_t final_mode, mode; int r; DWORD attrs = 0;+ DWORD file_flags = 0; # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ CREATEFILE2_EXTENDED_PARAMETERS createExParams; #endif@@ -1675,6 +1683,22 @@ free(linksanitized); return (r); }++ if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {+ r = check_symlinks_by_path(a, linksanitized, NULL, 1);+ if (r != ARCHIVE_OK) {+ /*+ * Prevent extracting a hardlink to a symlink.+ * libarchive supports the POSIX feature of+ * hardlinks with data payloads, which would+ * provide a way to write through an otherwise+ * disallowed symlink.+ */+ free(linksanitized);+ return (r);+ }+ }+ linkfull = __la_win_permissive_name_w(linksanitized); free(linksanitized); namefull = __la_win_permissive_name_w(a->name);@@ -1752,6 +1776,13 @@ else disk_unlink(a->name); }++ /*+ * Since the symlink-safe path cache is just an optimization, and we+ * are about to create a new symlink, invalidating the cache prevents+ * incidentally writing through the entry we are about to create.+ */+ a->path_safe.s[0] = 0; #if HAVE_SYMLINK return symlink(linkname, a->name) ? errno : 0; #else@@ -1790,16 +1821,31 @@ case AE_IFREG: a->tmpname = NULL; fullname = a->name;+ if ((a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {+ /*+ * Creating a regular file is expected to fail with EEXIST if *any+ * object* exists at the target location.+ * SECURE_SYMLINKS deletes any symbolic link that would have been+ * written through. When it's off, though, we risk writing through+ * extant but broken symlinks unless we allow CreateFile to fail+ * on the link rather than creating its target.+ *+ * This is effectively O_EXCL.+ */+ file_flags |= FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS;+ }+ /* O_WRONLY | O_CREAT | O_EXCL */ # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ ZeroMemory(&createExParams, sizeof(createExParams)); createExParams.dwSize = sizeof(createExParams); createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;+ createExParams.dwFileFlags = file_flags; a->fh = CreateFile2(fullname, GENERIC_WRITE, 0, CREATE_NEW, &createExParams); #else a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL | file_flags, NULL); #endif if (a->fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME &&@@ -1810,7 +1856,7 @@ CREATE_NEW, &createExParams); #else a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL | file_flags, NULL); #endif } if (a->fh == INVALID_HANDLE_VALUE) {@@ -2075,9 +2121,10 @@ * recent paths. */ static int-check_symlinks(struct archive_write_disk *a)+check_symlinks_by_path(struct archive_write_disk *a,+ wchar_t *path, size_t *safe_len, int checking_linkname) {- wchar_t *pn, *p;+ wchar_t *pn, *p, *su; wchar_t c; int r; BY_HANDLE_FILE_INFORMATION st;@@ -2088,13 +2135,17 @@ * destination would be altered by a symlink. */ /* Whatever we checked last time doesn't need to be re-checked. */- pn = a->name;+ pn = path; p = a->path_safe.s; while ((*pn != '\0') && (*p == *pn)) ++p, ++pn; /* Skip leading backslashes */ while (*pn == '\\') ++pn;+ su = pn;+ /* The end-of-safe region, however, should not cover a partial leaf name */+ while (su > path && *su != '\\')+ --su; c = pn[0]; /* Keep going until we've checked the entire name. */ while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) {@@ -2104,13 +2155,20 @@ c = pn[0]; pn[0] = '\0'; /* Check that we haven't hit a symlink. */- r = file_information(a, a->name, &st, &st_mode, 1);+ r = file_information(path, &st, &st_mode, 1); if (r != 0) { /* We've hit a dir that doesn't exist; stop now. */ if (errno == ENOENT) break; } else if (S_ISLNK(st_mode)) { if (c == '\0') {+ if (checking_linkname) {+ archive_set_error(&a->archive, ELOOP,+ "Cannot write hardlink to symlink %ls",+ path);+ pn[0] = c;+ return (ARCHIVE_FAILED);+ } /* * Last element is a file or directory symlink. * Remove it so we can overwrite it with the@@ -2122,14 +2180,14 @@ } if (st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {- r = disk_rmdir(a->name);+ r = disk_rmdir(path); } else {- r = disk_unlink(a->name);+ r = disk_unlink(path); } if (r) { archive_set_error(&a->archive, errno, "Could not remove symlink %ls",- a->name);+ path); pn[0] = c; return (ARCHIVE_FAILED); }@@ -2143,11 +2201,16 @@ if (!S_ISLNK(a->mode)) { archive_set_error(&a->archive, -1, "Removing symlink %ls",- a->name);+ path);+ /*+ * We can safely return the entire path as a safe range,+ * having deleted the symlink at the leaf with no intent+ * to create another symlink.+ */+ su = pn; } /* Symlink gone. No more problem! */- pn[0] = c;- return (0);+ break; } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { /* User asked us to remove problems. */ if (a->flags &@@ -2156,14 +2219,14 @@ } if (st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {- r = disk_rmdir(a->name);+ r = disk_rmdir(path); } else {- r = disk_unlink(a->name);+ r = disk_unlink(path); } if (r != 0) { archive_set_error(&a->archive, EIO, "Cannot remove intervening "- "symlink %ls", a->name);+ "symlink %ls", path); pn[0] = c; return (ARCHIVE_FAILED); }@@ -2171,23 +2234,48 @@ } else { archive_set_error(&a->archive, ELOOP, "Cannot extract through symlink %ls",- a->name);+ path); pn[0] = c; return (ARCHIVE_FAILED); } }+ su = pn; if (!c) break; pn[0] = c; pn++; } pn[0] = c;- /* We've checked and/or cleaned the whole path, so remember it. */- archive_wstrcpy(&a->path_safe, a->name);+ if (safe_len)+ *safe_len = su - path; return (ARCHIVE_OK); } static int+check_symlinks(struct archive_write_disk *a)+{+ int r;+ size_t safe_len;+ r = check_symlinks_by_path(a, a->name, &safe_len, 0);++ if (r == ARCHIVE_OK) {+ /*+ * We've checked and/or cleaned the whole path, so remember the+ * portion check_symlinks_by_path returned as "safe" (typically+ * the parent of the entry we are about to create, unless that+ * entry was just unlinked.)+ *+ * We only cache path safety info for entry paths (which we+ * operate on in a->name). We do not cache safety info for+ * any other paths.+ */+ archive_wstrncpy(&a->path_safe, a->name, safe_len);+ }++ return (r);+}++static int guidword(wchar_t *p, int n) { int i;@@ -2456,7 +2544,7 @@ * here loses the ability to extract through symlinks. Also note * that this should not use the a->st cache. */- if (file_information(a, path, &st, &st_mode, 0) == 0) {+ if (file_information(path, &st, &st_mode, 0) == 0) { if (S_ISDIR(st_mode)) return (ARCHIVE_OK); if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {@@ -2523,7 +2611,7 @@ * don't add it to the fixup list here, as it's already been * added. */- if (file_information(a, path, &st, &st_mode, 0) == 0 &&+ if (file_information(path, &st, &st_mode, 0) == 0 && S_ISDIR(st_mode)) return (ARCHIVE_OK);
c/archive_write_private.h view
@@ -69,7 +69,7 @@ struct archive_write_filter *__archive_write_allocate_filter(struct archive *); int __archive_write_output(struct archive_write *, const void *, size_t);-int __archive_write_nulls(struct archive_write *, size_t);+int __archive_write_nulls(struct archive_write *, uint64_t); int __archive_write_filter(struct archive_write_filter *, const void *, size_t); struct archive_write {@@ -131,6 +131,8 @@ archive_passphrase_callback *passphrase_callback; void *passphrase_client_data; };++int __archive_write_unregister_format(struct archive_write *); /* * Utility function to format a USTAR header into a buffer. If
c/archive_write_set_format_7zip.c view
@@ -215,8 +215,6 @@ size_t total_number_dir_entry; size_t total_bytes_entry_name; size_t total_number_time_defined[3];- uint64_t total_bytes_compressed;- uint64_t total_bytes_uncompressed; uint64_t entry_bytes_remaining; uint32_t entry_crc32; uint32_t precode_crc32;@@ -358,8 +356,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_7zip"); /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); zip = calloc(1, sizeof(*zip)); if (zip == NULL) {@@ -415,9 +412,7 @@ static int _7z_options(struct archive_write *a, const char *key, const char *value) {- struct _7zip *zip;-- zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; if (strcmp(key, "compression") == 0) { const char *name = NULL;@@ -559,11 +554,10 @@ static int _7z_write_header(struct archive_write *a, struct archive_entry *entry) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; struct file *file; int r; - zip = (struct _7zip *)a->format_data; zip->cur_file = NULL; zip->entry_bytes_remaining = 0; @@ -667,12 +661,10 @@ static int write_to_temp(struct archive_write *a, const void *buff, size_t s) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; const unsigned char *p; ssize_t ws; - zip = (struct _7zip *)a->format_data;- /* * Open a temporary file. */@@ -705,7 +697,7 @@ compress_out(struct archive_write *a, const void *buff, size_t s, enum la_zaction run) {- struct _7zip *zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; int r; if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)@@ -751,11 +743,9 @@ static ssize_t _7z_write_data(struct archive_write *a, const void *buff, size_t s) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; ssize_t bytes; - zip = (struct _7zip *)a->format_data;- if (s > zip->entry_bytes_remaining) s = (size_t)zip->entry_bytes_remaining; if (s == 0 || zip->cur_file == NULL)@@ -771,11 +761,10 @@ static int _7z_finish_entry(struct archive_write *a) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; size_t s; ssize_t r; - zip = (struct _7zip *)a->format_data; if (zip->cur_file == NULL) return (ARCHIVE_OK); @@ -787,8 +776,6 @@ if (r < 0) return ((int)r); }- zip->total_bytes_compressed += zip->stream.total_in;- zip->total_bytes_uncompressed += zip->stream.total_out; zip->cur_file->crc32 = zip->entry_crc32; zip->cur_file = NULL; @@ -798,11 +785,10 @@ static int flush_wbuff(struct archive_write *a) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; int r; size_t s; - zip = (struct _7zip *)a->format_data; s = sizeof(zip->wbuff) - zip->wbuff_remaining; r = __archive_write_output(a, zip->wbuff, s); if (r != ARCHIVE_OK)@@ -814,10 +800,9 @@ static int copy_out(struct archive_write *a, uint64_t offset, uint64_t length) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; int r; - zip = (struct _7zip *)a->format_data; if (zip->temp_offset > 0 && lseek(zip->temp_fd, offset, SEEK_SET) < 0) { archive_set_error(&(a->archive), errno, "lseek failed");@@ -860,15 +845,13 @@ static int _7z_close(struct archive_write *a) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; unsigned char *wb; uint64_t header_offset, header_size, header_unpacksize; uint64_t length; uint32_t header_crc32; int r; - zip = (struct _7zip *)a->format_data;- if (zip->total_number_entry > 0) { struct archive_rb_node *n; uint64_t data_offset, data_size, data_unpacksize;@@ -1033,7 +1016,7 @@ static int make_substreamsInfo(struct archive_write *a, struct coder *coders) {- struct _7zip *zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; struct file *file; int r; @@ -1109,7 +1092,7 @@ uint64_t unpack_size, int num_coder, struct coder *coders, int substrm, uint32_t header_crc) {- struct _7zip *zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; uint8_t codec_buff[8]; int numFolders, fi; int codec_size;@@ -1301,8 +1284,8 @@ static int make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) {+ struct _7zip *zip = a->format_data; uint8_t filetime[8];- struct _7zip *zip = (struct _7zip *)a->format_data; struct file *file; int r; uint8_t b, mask;@@ -1390,7 +1373,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size, uint64_t unpack_size, int codernum, struct coder *coders) {- struct _7zip *zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; struct file *file; int r; uint8_t b, mask;@@ -1598,7 +1581,7 @@ static int _7z_free(struct archive_write *a) {- struct _7zip *zip = (struct _7zip *)a->format_data;+ struct _7zip *zip = a->format_data; /* Close the temporary file. */ if (zip->temp_fd >= 0)@@ -1636,13 +1619,12 @@ file_new(struct archive_write *a, struct archive_entry *entry, struct file **newfile) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; struct file *file; const char *u16; size_t u16len; int ret = ARCHIVE_OK; - zip = (struct _7zip *)a->format_data; *newfile = NULL; file = calloc(1, sizeof(*file));@@ -2260,7 +2242,7 @@ ppmd_write(void *p, Byte b) { struct archive_write *a = ((IByteOut *)p)->a;- struct _7zip *zip = (struct _7zip *)(a->format_data);+ struct _7zip *zip = a->format_data; struct la_zstream *lastrm = &(zip->stream); struct ppmd_stream *strm; @@ -2517,10 +2499,9 @@ _7z_compression_init_encoder(struct archive_write *a, unsigned compression, int compression_level) {- struct _7zip *zip;+ struct _7zip *zip = a->format_data; int r; - zip = (struct _7zip *)a->format_data; switch (compression) { case _7Z_DEFLATE: r = compression_init_encoder_deflate(
c/archive_write_set_format_ar.c view
@@ -40,10 +40,11 @@ #include "archive.h" #include "archive_entry.h" #include "archive_private.h"+#include "archive_string.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h" -struct ar_w {+struct ar { uint64_t entry_bytes_remaining; uint64_t entry_padding; int is_strtab;@@ -78,7 +79,6 @@ static int archive_write_ar_free(struct archive_write *); static int archive_write_ar_close(struct archive_write *); static int archive_write_ar_finish_entry(struct archive_write *);-static const char *ar_basename(const char *path); static int format_octal(int64_t v, char *p, int s); static int format_decimal(int64_t v, char *p, int s); @@ -120,11 +120,10 @@ static int archive_write_set_format_ar(struct archive_write *a) {- struct ar_w *ar;+ struct ar *ar; /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); ar = calloc(1, sizeof(*ar)); if (ar == NULL) {@@ -147,16 +146,18 @@ { int ret, append_fn; char buff[60];- char *ss, *se;- struct ar_w *ar;+ char *ss;+ struct ar *ar = a->format_data;+ struct archive_string se; const char *pathname; const char *filename;+ size_t filename_length; int64_t size; append_fn = 0;- ar = (struct ar_w *)a->format_data; ar->is_strtab = 0; filename = NULL;+ filename_length = 0; size = archive_entry_size(entry); @@ -215,12 +216,17 @@ * Otherwise, entry is a normal archive member. * Strip leading paths from filenames, if any. */- if ((filename = ar_basename(pathname)) == NULL) {+ filename = strrchr(pathname, '/');+ if (filename == NULL)+ filename = pathname;+ else if (filename[1] == '\0') { /* Reject filenames with trailing "/" */ archive_set_error(&a->archive, EINVAL, "Invalid filename"); return (ARCHIVE_WARN);- }+ } else+ filename++;+ filename_length = strlen(filename); if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) { /*@@ -229,10 +235,10 @@ * So, the longest filename here (without extension) is * actually 15 bytes. */- if (strlen(filename) <= 15) {+ if (filename_length <= 15) { memcpy(&buff[AR_name_offset],- filename, strlen(filename));- buff[AR_name_offset + strlen(filename)] = '/';+ filename, filename_length);+ buff[AR_name_offset + filename_length] = '/'; } else { /* * For filename longer than 15 bytes, GNU variant@@ -246,18 +252,10 @@ return (ARCHIVE_WARN); } - se = malloc(strlen(filename) + 3);- if (se == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate filename buffer");- return (ARCHIVE_FATAL);- }-- memcpy(se, filename, strlen(filename));- strcpy(se + strlen(filename), "/\n");-- ss = strstr(ar->strtab, se);- free(se);+ archive_string_init(&se);+ archive_string_sprintf(&se, "%s/\n", filename);+ ss = strstr(ar->strtab, se.s);+ archive_string_free(&se); if (ss == NULL) { archive_set_error(&a->archive, EINVAL,@@ -289,13 +287,13 @@ * The name is then written immediately following the * archive header. */- if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {- memcpy(&buff[AR_name_offset], filename, strlen(filename));- buff[AR_name_offset + strlen(filename)] = ' ';+ if (filename_length <= 16 && strchr(filename, ' ') == NULL) {+ memcpy(&buff[AR_name_offset], filename, filename_length);+ buff[AR_name_offset + filename_length] = ' '; } else { memcpy(buff + AR_name_offset, "#1/", 3);- if (format_decimal(strlen(filename),+ if (format_decimal(filename_length, buff + AR_name_offset + 3, AR_name_size - 3)) { archive_set_error(&a->archive, ERANGE,@@ -303,7 +301,7 @@ return (ARCHIVE_WARN); } append_fn = 1;- size += strlen(filename);+ size += filename_length; } } @@ -353,10 +351,10 @@ ar->entry_padding = ar->entry_bytes_remaining % 2; if (append_fn > 0) {- ret = __archive_write_output(a, filename, strlen(filename));+ ret = __archive_write_output(a, filename, filename_length); if (ret != ARCHIVE_OK) return (ret);- ar->entry_bytes_remaining -= strlen(filename);+ ar->entry_bytes_remaining -= filename_length; } return (ARCHIVE_OK);@@ -365,10 +363,9 @@ static ssize_t archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) {- struct ar_w *ar;+ struct ar *ar = a->format_data; int ret; - ar = (struct ar_w *)a->format_data; if (s > ar->entry_bytes_remaining) s = (size_t)ar->entry_bytes_remaining; @@ -401,9 +398,7 @@ static int archive_write_ar_free(struct archive_write *a) {- struct ar_w *ar;-- ar = (struct ar_w *)a->format_data;+ struct ar *ar = a->format_data; if (ar == NULL) return (ARCHIVE_OK);@@ -421,14 +416,13 @@ static int archive_write_ar_close(struct archive_write *a) {- struct ar_w *ar;+ struct ar *ar = a->format_data; int ret; /* * If we haven't written anything yet, we need to write * the ar global header now to make it a valid ar archive. */- ar = (struct ar_w *)a->format_data; if (!ar->wrote_global_header) { ar->wrote_global_header = 1; ret = __archive_write_output(a, "!<arch>\n", 8);@@ -441,11 +435,9 @@ static int archive_write_ar_finish_entry(struct archive_write *a) {- struct ar_w *ar;+ struct ar *ar = a->format_data; int ret; - ar = (struct ar_w *)a->format_data;- if (ar->entry_bytes_remaining != 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Entry remaining bytes larger than 0");@@ -545,25 +537,4 @@ *p++ = '9'; return (-1);-}--static const char *-ar_basename(const char *path)-{- const char *endp, *startp;-- endp = path + strlen(path) - 1;- /*- * For filename with trailing slash(es), we return- * NULL indicating an error.- */- if (*endp == '/')- return (NULL);-- /* Find the start of the base */- startp = endp;- while (startp > path && *(startp - 1) != '/')- startp--;- - return (startp); }
c/archive_write_set_format_cpio_binary.c view
@@ -40,6 +40,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h"@@ -182,8 +183,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); cpio = calloc(1, sizeof(*cpio)); if (cpio == NULL) {@@ -235,7 +235,7 @@ archive_write_binary_options(struct archive_write *a, const char *key, const char *val) {- struct cpio *cpio = (struct cpio *)a->format_data;+ struct cpio *cpio = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -307,10 +307,16 @@ /* Ensure space for the new mapping. */ if (cpio->ino_list_size <= cpio->ino_list_next) {- size_t newsize = cpio->ino_list_size < 512- ? 512 : cpio->ino_list_size * 2;- void *newlist = realloc(cpio->ino_list,- sizeof(cpio->ino_list[0]) * newsize);+ size_t newsize, size;+ if (cpio->ino_list_size < 512)+ newsize = 512;+ else if (archive_ckd_mul_size(&newsize,+ cpio->ino_list_size, 2))+ return (-1);+ if (archive_ckd_mul_size(&size,+ newsize, sizeof(cpio->ino_list[0])))+ return (-1);+ void *newlist = realloc(cpio->ino_list, size); if (newlist == NULL) return (-1); @@ -329,10 +335,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; struct archive_string_conv *sconv; - cpio = (struct cpio *)a->format_data; sconv = cpio->opt_sconv; if (sconv == NULL) { if (!cpio->init_default_conversion) {@@ -378,7 +383,7 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; const char *p, *path; int ret, ret_final; int64_t ino;@@ -387,7 +392,6 @@ struct archive_entry *entry_main; size_t len, pathlength; - cpio = (struct cpio *)a->format_data; ret_final = ARCHIVE_OK; sconv = get_sconv(a); @@ -561,10 +565,9 @@ static ssize_t archive_write_binary_data(struct archive_write *a, const void *buff, size_t s) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; int ret; - cpio = (struct cpio *)a->format_data; if (s > cpio->entry_bytes_remaining) s = (size_t)cpio->entry_bytes_remaining; @@ -598,9 +601,8 @@ static int archive_write_binary_free(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data; free(cpio->ino_list); free(cpio); a->format_data = NULL;@@ -610,9 +612,7 @@ static int archive_write_binary_finish_entry(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data;- return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining));+ return (__archive_write_nulls(a, cpio->entry_bytes_remaining)); }
c/archive_write_set_format_cpio_newc.c view
@@ -113,8 +113,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); cpio = calloc(1, sizeof(*cpio)); if (cpio == NULL) {@@ -138,7 +137,7 @@ archive_write_newc_options(struct archive_write *a, const char *key, const char *val) {- struct cpio *cpio = (struct cpio *)a->format_data;+ struct cpio *cpio = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -166,10 +165,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; struct archive_string_conv *sconv; - cpio = (struct cpio *)a->format_data; sconv = cpio->opt_sconv; if (sconv == NULL) { if (!cpio->init_default_conversion) {@@ -216,8 +214,8 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {+ struct cpio *cpio = a->format_data; int64_t ino;- struct cpio *cpio; const char *p, *path; int ret, ret_final; char h[c_header_size];@@ -226,7 +224,6 @@ size_t len, pathlength; int pad; - cpio = (struct cpio *)a->format_data; ret_final = ARCHIVE_OK; sconv = get_sconv(a); @@ -378,10 +375,9 @@ static ssize_t archive_write_newc_data(struct archive_write *a, const void *buff, size_t s) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; int ret; - cpio = (struct cpio *)a->format_data; if (s > cpio->entry_bytes_remaining) s = (size_t)cpio->entry_bytes_remaining; @@ -430,6 +426,8 @@ struct archive_entry *trailer; trailer = archive_entry_new();+ if (trailer == NULL)+ return ARCHIVE_FATAL; archive_entry_set_nlink(trailer, 1); archive_entry_set_size(trailer, 0); archive_entry_set_pathname(trailer, "TRAILER!!!");@@ -442,9 +440,8 @@ static int archive_write_newc_free(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data; free(cpio); a->format_data = NULL; return (ARCHIVE_OK);@@ -453,9 +450,8 @@ static int archive_write_newc_finish_entry(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data; return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining + cpio->padding));+ cpio->entry_bytes_remaining + cpio->padding)); }
c/archive_write_set_format_cpio_odc.c view
@@ -40,6 +40,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h"@@ -107,8 +108,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); cpio = calloc(1, sizeof(*cpio)); if (cpio == NULL) {@@ -132,7 +132,7 @@ archive_write_odc_options(struct archive_write *a, const char *key, const char *val) {- struct cpio *cpio = (struct cpio *)a->format_data;+ struct cpio *cpio = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -204,10 +204,16 @@ /* Ensure space for the new mapping. */ if (cpio->ino_list_size <= cpio->ino_list_next) {- size_t newsize = cpio->ino_list_size < 512- ? 512 : cpio->ino_list_size * 2;- void *newlist = realloc(cpio->ino_list,- sizeof(cpio->ino_list[0]) * newsize);+ size_t newsize, size;+ if (cpio->ino_list_size < 512)+ newsize = 512;+ else if (archive_ckd_mul_size(&newsize,+ cpio->ino_list_size, 2))+ return (-1);+ if (archive_ckd_mul_size(&size,+ newsize, sizeof(cpio->ino_list[0])))+ return (-1);+ void *newlist = realloc(cpio->ino_list, size); if (newlist == NULL) return (-1); @@ -226,10 +232,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; struct archive_string_conv *sconv; - cpio = (struct cpio *)a->format_data; sconv = cpio->opt_sconv; if (sconv == NULL) { if (!cpio->init_default_conversion) {@@ -275,7 +280,7 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; const char *p, *path; int ret, ret_final; int64_t ino;@@ -284,7 +289,6 @@ struct archive_entry *entry_main; size_t len, pathlength; - cpio = (struct cpio *)a->format_data; ret_final = ARCHIVE_OK; sconv = get_sconv(a); @@ -420,10 +424,9 @@ static ssize_t archive_write_odc_data(struct archive_write *a, const void *buff, size_t s) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; int ret; - cpio = (struct cpio *)a->format_data; if (s > cpio->entry_bytes_remaining) s = (size_t)cpio->entry_bytes_remaining; @@ -487,9 +490,8 @@ static int archive_write_odc_free(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data; free(cpio->ino_list); free(cpio); a->format_data = NULL;@@ -499,9 +501,8 @@ static int archive_write_odc_finish_entry(struct archive_write *a) {- struct cpio *cpio;+ struct cpio *cpio = a->format_data; - cpio = (struct cpio *)a->format_data;- return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining));+ return (__archive_write_nulls(a, + cpio->entry_bytes_remaining)); }
c/archive_write_set_format_gnutar.c view
@@ -174,6 +174,11 @@ struct archive_write *a = (struct archive_write *)_a; struct gnutar *gnutar; + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+ ARCHIVE_STATE_NEW, "archive_write_set_format_gnutar");++ (void)__archive_write_unregister_format(a);+ gnutar = calloc(1, sizeof(*gnutar)); if (gnutar == NULL) { archive_set_error(&a->archive, ENOMEM,@@ -197,7 +202,7 @@ archive_write_gnutar_options(struct archive_write *a, const char *key, const char *val) {- struct gnutar *gnutar = (struct gnutar *)a->format_data;+ struct gnutar *gnutar = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -231,9 +236,8 @@ static int archive_write_gnutar_free(struct archive_write *a) {- struct gnutar *gnutar;+ struct gnutar *gnutar = a->format_data; - gnutar = (struct gnutar *)a->format_data; free(gnutar); a->format_data = NULL; return (ARCHIVE_OK);@@ -242,12 +246,11 @@ static int archive_write_gnutar_finish_entry(struct archive_write *a) {- struct gnutar *gnutar;+ struct gnutar *gnutar = a->format_data; int ret; - gnutar = (struct gnutar *)a->format_data;- ret = __archive_write_nulls(a, (size_t)- (gnutar->entry_bytes_remaining + gnutar->entry_padding));+ ret = __archive_write_nulls(a,+ gnutar->entry_bytes_remaining + gnutar->entry_padding); gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; return (ret); }@@ -255,10 +258,9 @@ static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) {- struct gnutar *gnutar;+ struct gnutar *gnutar = a->format_data; int ret; - gnutar = (struct gnutar *)a->format_data; if (s > gnutar->entry_bytes_remaining) s = (size_t)gnutar->entry_bytes_remaining; ret = __archive_write_output(a, buff, s);@@ -272,15 +274,13 @@ archive_write_gnutar_header(struct archive_write *a, struct archive_entry *entry) {+ struct gnutar *gnutar = a->format_data; char buff[512]; int r, ret, ret2 = ARCHIVE_OK; char tartype;- struct gnutar *gnutar; struct archive_string_conv *sconv; struct archive_entry *entry_main; - gnutar = (struct gnutar *)a->format_data;- /* Setup default string conversion. */ if (gnutar->opt_sconv == NULL) { if (!gnutar->init_default_conversion) {@@ -494,6 +494,13 @@ size_t length = gnutar->linkname_length + 1; struct archive_entry *temp = archive_entry_new2(&a->archive); + if (temp == NULL) {+ archive_set_error(&a->archive, ENOMEM,+ "Can't allocate memory for Linkname");+ ret = ARCHIVE_FATAL;+ goto exit_write_header;+ }+ /* Uname/gname here don't really matter since no one reads them; * these are the values that GNU tar happens to use on FreeBSD. */ archive_entry_set_uname(temp, "root");@@ -524,6 +531,13 @@ size_t length = gnutar->pathname_length + 1; struct archive_entry *temp = archive_entry_new2(&a->archive); + if (temp == NULL) {+ archive_set_error(&a->archive, ENOMEM,+ "Can't allocate memory for Linkname");+ ret = ARCHIVE_FATAL;+ goto exit_write_header;+ }+ /* Uname/gname here don't really matter since no one reads them; * these are the values that GNU tar happens to use on FreeBSD. */ archive_entry_set_uname(temp, "root");@@ -589,14 +603,12 @@ archive_format_gnutar_header(struct archive_write *a, char h[512], struct archive_entry *entry, char tartype) {+ struct gnutar *gnutar = a->format_data; unsigned int checksum; int i, ret; size_t copy_length; const char *p;- struct gnutar *gnutar; - gnutar = (struct gnutar *)a->format_data;- ret = 0; /*@@ -652,7 +664,7 @@ copy_length = gnutar->gname_length; } if (copy_length > 0) {- if (strlen(p) > GNUTAR_gname_size)+ if (copy_length > GNUTAR_gname_size) copy_length = GNUTAR_gname_size; memcpy(h + GNUTAR_gname_offset, p, copy_length); }
c/archive_write_set_format_iso9660.c view
@@ -1059,8 +1059,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660"); /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); iso9660 = calloc(1, sizeof(*iso9660)); if (iso9660 == NULL) {@@ -1427,8 +1426,8 @@ break; case 'i': if (strcmp(key, "iso-level") == 0) {- if (value != NULL && value[1] == '\0' &&- (value[0] >= '1' && value[0] <= '4')) {+ if (value != NULL && value[0] >= '1' &&+ value[0] <= '4' && value[1] == '\0') { iso9660->opt.iso_level = value[0]-'0'; return (ARCHIVE_OK); }@@ -1529,13 +1528,11 @@ static int iso9660_write_header(struct archive_write *a, struct archive_entry *entry) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; struct isofile *file; struct isoent *isoent; int r, ret = ARCHIVE_OK; - iso9660 = a->format_data;- iso9660->cur_file = NULL; iso9660->bytes_remaining = 0; iso9660->need_multi_extent = 0;@@ -1677,7 +1674,7 @@ * order to reduce a extra memory copy. */ if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+ struct iso9660 *iso9660 = a->format_data; xs = s % LOGICAL_BLOCK_SIZE; iso9660->wbuff_offset += s - xs; if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)@@ -1859,11 +1856,9 @@ static int iso9660_close(struct archive_write *a) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; int ret, blocks; - iso9660 = a->format_data;- /* * Write remaining data out to the temporary file. */@@ -2121,11 +2116,9 @@ static int iso9660_free(struct archive_write *a) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; int i, ret; - iso9660 = a->format_data;- /* Close the temporary file. */ if (iso9660->temp_fd >= 0) close(iso9660->temp_fd);@@ -2921,10 +2914,10 @@ extra_tell_used_size(&ctl, length); if (extra_space(&ctl) < 6) { bp = extra_next_record(&ctl, 6);- nmmax = extra_space(&ctl);- if (nmmax > 0xff)- nmmax = 0xff; }+ nmmax = extra_space(&ctl);+ if (nmmax > 0xff)+ nmmax = 0xff; if (bp != NULL) { bp[1] = 'N'; bp[2] = 'M';@@ -3619,7 +3612,7 @@ static inline unsigned char * wb_buffptr(struct archive_write *a) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+ struct iso9660 *iso9660 = a->format_data; return (&(iso9660->wbuff[sizeof(iso9660->wbuff) - iso9660->wbuff_remaining]));@@ -3628,7 +3621,7 @@ static int wb_write_out(struct archive_write *a) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+ struct iso9660 *iso9660 = a->format_data; size_t wsize, nw; int r; @@ -3653,7 +3646,7 @@ static int wb_consume(struct archive_write *a, size_t size) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+ struct iso9660 *iso9660 = a->format_data; if (size > iso9660->wbuff_remaining || iso9660->wbuff_remaining == 0) {@@ -3674,7 +3667,7 @@ static int wb_set_offset(struct archive_write *a, int64_t off) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+ struct iso9660 *iso9660 = a->format_data; int64_t used, ext_bytes; if (iso9660->wbuff_type != WB_TO_TEMP) {@@ -3841,7 +3834,7 @@ static int write_VD(struct archive_write *a, struct vdd *vdd) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; unsigned char *bp; uint16_t volume_set_size = 1; char identifier[256];@@ -3850,7 +3843,6 @@ unsigned char vd_ver, fst_ver; int r; - iso9660 = a->format_data; switch (vdd->vdd_type) { case VDD_JOLIET: vdt = VDT_SUPPLEMENTARY;@@ -3988,10 +3980,9 @@ static int write_VD_boot_record(struct archive_write *a) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; unsigned char *bp; - iso9660 = a->format_data; bp = wb_buffptr(a) -1; /* Volume Descriptor Type */ set_VD_bp(bp, VDT_BOOT_RECORD, 1);@@ -4059,7 +4050,7 @@ static int write_information_block(struct archive_write *a) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; char buf[128]; const char *v; int opt, r;@@ -4067,7 +4058,6 @@ size_t info_size = LOGICAL_BLOCK_SIZE * NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK; - iso9660 = (struct iso9660 *)a->format_data; if (info_size > wb_remaining(a)) { r = wb_write_out(a); if (r != ARCHIVE_OK)@@ -4717,14 +4707,12 @@ static int isofile_gen_utility_names(struct archive_write *a, struct isofile *file) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; const char *pathname; char *p, *dirname, *slash; size_t len; int ret = ARCHIVE_OK; - iso9660 = a->format_data;- archive_string_empty(&(file->parentdir)); archive_string_empty(&(file->basename)); archive_string_empty(&(file->basename_utf16));@@ -5563,6 +5551,7 @@ static int isoent_tree(struct archive_write *a, struct isoent **isoentpp) {+ struct iso9660 *iso9660 = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -5570,7 +5559,6 @@ #else char name[256]; #endif- struct iso9660 *iso9660 = a->format_data; struct isoent *dent, *isoent, *np; struct isofile *f1, *f2; const char *fn, *p;@@ -5998,7 +5986,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent, struct idr *idr) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; struct isoent *np; char *p; int l, r;@@ -6014,9 +6002,8 @@ const int null_size = 1; if (isoent->children.cnt == 0)- return (0);+ return (ARCHIVE_OK); - iso9660 = a->format_data; char_map = idr->char_map; if (iso9660->opt.iso_level <= 3) { allow_ldots = 0;@@ -6258,7 +6245,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent, struct idr *idr) {- struct iso9660 *iso9660;+ struct iso9660 *iso9660 = a->format_data; struct isoent *np; unsigned char *p; size_t l;@@ -6271,9 +6258,8 @@ const int null_size = 2; if (isoent->children.cnt == 0)- return (0);+ return (ARCHIVE_OK); - iso9660 = a->format_data; if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME) ffmax = 206; else@@ -7522,8 +7508,9 @@ (uint32_t)archive_entry_size(file->entry); /* Calculate a size of Block Pointers of zisofs. */- _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)- >> file->zisofs.log2_bs;+ _ceil = (size_t)(((uint64_t)file->zisofs.uncompressed_size ++ (ZF_BLOCK_SIZE - 1))+ >> file->zisofs.log2_bs); iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1; iso9660->zisofs.block_pointers_idx = 0;
c/archive_write_set_format_mtree.c view
@@ -117,7 +117,7 @@ int64_t ino; }; -struct mtree_writer {+struct mtree { struct mtree_entry *mtree_entry; struct mtree_entry *root; struct mtree_entry *cur_dirent;@@ -220,10 +220,10 @@ struct attr_counter *, struct mtree_entry *); static struct attr_counter * attr_counter_new(struct mtree_entry *, struct attr_counter *);-static int attr_counter_set_collect(struct mtree_writer *,+static int attr_counter_set_collect(struct mtree *, struct mtree_entry *);-static void attr_counter_set_free(struct mtree_writer *);-static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);+static void attr_counter_set_free(struct mtree *);+static int get_global_set_keys(struct mtree *, struct mtree_entry *); static int mtree_entry_add_child_tail(struct mtree_entry *, struct mtree_entry *); static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,@@ -236,14 +236,14 @@ static void mtree_entry_free(struct mtree_entry *); static int mtree_entry_new(struct archive_write *, struct archive_entry *, struct mtree_entry **);-static void mtree_entry_register_free(struct mtree_writer *);-static void mtree_entry_register_init(struct mtree_writer *);+static void mtree_entry_register_free(struct mtree *);+static void mtree_entry_register_init(struct mtree *); static int mtree_entry_setup_filenames(struct archive_write *, struct mtree_entry *, struct archive_entry *); static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);-static void sum_init(struct mtree_writer *);-static void sum_update(struct mtree_writer *, const void *, size_t);-static void sum_final(struct mtree_writer *, struct reg_info *);+static void sum_init(struct mtree *);+static void sum_update(struct mtree *, const void *, size_t);+static void sum_final(struct mtree *, struct reg_info *); static void sum_write(struct archive_string *, struct reg_info *); static int write_mtree_entry(struct archive_write *, struct mtree_entry *); static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);@@ -358,7 +358,7 @@ * Indent a line as the mtree utility does so it is readable for people. */ static void-mtree_indent(struct mtree_writer *mtree)+mtree_indent(struct mtree *mtree) { int i, fn, nd, pd; const char *r, *s, *x;@@ -434,7 +434,7 @@ * collected by the attr_counter_set_collect() function. */ static void-write_global(struct mtree_writer *mtree)+write_global(struct mtree *mtree) { struct archive_string setstr; struct archive_string unsetstr;@@ -636,7 +636,7 @@ * Tabulate uid, gid, mode and fflags of a entry in order to be used for /set. */ static int-attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)+attr_counter_set_collect(struct mtree *mtree, struct mtree_entry *me) { struct attr_counter *ac, *last; struct attr_counter_set *acs = &mtree->acs;@@ -713,7 +713,7 @@ } static void-attr_counter_set_free(struct mtree_writer *mtree)+attr_counter_set_free(struct mtree *mtree) { struct attr_counter_set *acs = &mtree->acs; @@ -724,7 +724,7 @@ } static int-get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)+get_global_set_keys(struct mtree *mtree, struct mtree_entry *me) { int keys; @@ -913,7 +913,7 @@ archive_write_mtree_header(struct archive_write *a, struct archive_entry *entry) {- struct mtree_writer *mtree= a->format_data;+ struct mtree *mtree = a->format_data; struct mtree_entry *mtree_entry; int r, r2; @@ -956,7 +956,7 @@ static int write_mtree_entry(struct archive_write *a, struct mtree_entry *me) {- struct mtree_writer *mtree = a->format_data;+ struct mtree *mtree = a->format_data; struct archive_string *str; int keys, ret; @@ -1107,7 +1107,7 @@ static int write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n) {- struct mtree_writer *mtree = a->format_data;+ struct mtree *mtree = a->format_data; int ret; if (n->parentdir.s) {@@ -1142,7 +1142,7 @@ static int write_mtree_entry_tree(struct archive_write *a) {- struct mtree_writer *mtree = a->format_data;+ struct mtree *mtree = a->format_data; struct mtree_entry *np = mtree->root; struct archive_rb_node *n; int ret;@@ -1245,7 +1245,7 @@ static int archive_write_mtree_finish_entry(struct archive_write *a) {- struct mtree_writer *mtree = a->format_data;+ struct mtree *mtree = a->format_data; struct mtree_entry *me; if ((me = mtree->mtree_entry) == NULL)@@ -1261,7 +1261,7 @@ static int archive_write_mtree_close(struct archive_write *a) {- struct mtree_writer *mtree= a->format_data;+ struct mtree *mtree = a->format_data; int ret; if (mtree->root != NULL) {@@ -1278,7 +1278,7 @@ static ssize_t archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) {- struct mtree_writer *mtree= a->format_data;+ struct mtree *mtree = a->format_data; if (n > mtree->entry_bytes_remaining) n = (size_t)mtree->entry_bytes_remaining;@@ -1297,7 +1297,7 @@ static int archive_write_mtree_free(struct archive_write *a) {- struct mtree_writer *mtree= a->format_data;+ struct mtree *mtree = a->format_data; if (mtree == NULL) return (ARCHIVE_OK);@@ -1317,7 +1317,7 @@ archive_write_mtree_options(struct archive_write *a, const char *key, const char *value) {- struct mtree_writer *mtree= a->format_data;+ struct mtree *mtree = a->format_data; int keybit = 0; switch (key[0]) {@@ -1429,12 +1429,11 @@ archive_write_set_format_mtree_default(struct archive *_a, const char *fn) { struct archive_write *a = (struct archive_write *)_a;- struct mtree_writer *mtree;+ struct mtree *mtree; archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn); - if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); if ((mtree = calloc(1, sizeof(*mtree))) == NULL) { archive_set_error(&a->archive, ENOMEM,@@ -1481,9 +1480,7 @@ "archive_write_set_format_mtree_classic"); if (r == ARCHIVE_OK) { struct archive_write *a = (struct archive_write *)_a;- struct mtree_writer *mtree;-- mtree = (struct mtree_writer *)a->format_data;+ struct mtree *mtree = a->format_data; /* Set to output a mtree archive in classic format. */ mtree->classic = 1;@@ -1495,7 +1492,7 @@ } static void-sum_init(struct mtree_writer *mtree)+sum_init(struct mtree *mtree) { mtree->compute_sum = 0;@@ -1556,7 +1553,7 @@ } static void-sum_update(struct mtree_writer *mtree, const void *buff, size_t n)+sum_update(struct mtree *mtree, const void *buff, size_t n) { if (mtree->compute_sum & F_CKSUM) { /*@@ -1614,7 +1611,7 @@ } static void-sum_final(struct mtree_writer *mtree, struct reg_info *reg)+sum_final(struct mtree *mtree, struct reg_info *reg) { struct ae_digest digest; @@ -1995,7 +1992,7 @@ } static void-mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)+mtree_entry_register_add(struct mtree *mtree, struct mtree_entry *file) { file->next = NULL; *mtree->file_list.last = file;@@ -2003,14 +2000,14 @@ } static void-mtree_entry_register_init(struct mtree_writer *mtree)+mtree_entry_register_init(struct mtree *mtree) { mtree->file_list.first = NULL; mtree->file_list.last = &(mtree->file_list.first); } static void-mtree_entry_register_free(struct mtree_writer *mtree)+mtree_entry_register_free(struct mtree *mtree) { struct mtree_entry *file, *file_next; @@ -2073,6 +2070,7 @@ static int mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) {+ struct mtree *mtree = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -2080,7 +2078,6 @@ #else char name[256]; #endif- struct mtree_writer *mtree = (struct mtree_writer *)a->format_data; struct mtree_entry *dent, *file, *np; const char *fn, *p; int l, r;
c/archive_write_set_format_pax.c view
@@ -45,6 +45,8 @@ #include "archive_write_private.h" #include "archive_write_set_format_private.h" +#define PAX_MAX_ALIGN (1U << 20)+ struct sparse_block { struct sparse_block *next; int is_hole;@@ -64,6 +66,10 @@ struct archive_string_conv *sconv_utf8; int opt_binary; + /* If non-zero, align regular file data to this many bytes in the+ * uncompressed stream (power of two, multiple of 512). */+ size_t align;+ unsigned flags; #define WRITE_SCHILY_XATTR (1 << 0) #define WRITE_LIBARCHIVE_XATTR (1 << 1)@@ -79,6 +85,8 @@ static void add_pax_attr_time(struct archive_string *, const char *key, int64_t sec, unsigned long nanos);+static size_t add_pax_padding_prefix(struct archive_string *,+ size_t cur_len, size_t target_len); static int add_pax_acl(struct archive_write *, struct archive_entry *, struct pax *, int); static ssize_t archive_write_pax_data(struct archive_write *,@@ -90,6 +98,7 @@ struct archive_entry *); static int archive_write_pax_options(struct archive_write *, const char *, const char *);+static int write_pax_padding(struct archive_write *, size_t); static char *base64_encode(const char *src, size_t len); static char *build_gnu_sparse_name(char *dest, const char *src); static char *build_pax_attribute_name(char *dest, const char *src);@@ -136,8 +145,7 @@ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_format_pax"); - if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); pax = calloc(1, sizeof(*pax)); if (pax == NULL) {@@ -164,7 +172,7 @@ archive_write_pax_options(struct archive_write *a, const char *key, const char *val) {- struct pax *pax = (struct pax *)a->format_data;+ struct pax *pax = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -223,6 +231,25 @@ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "pax: invalid xattr header name"); return (ret);+ } else if (strcmp(key, "align") == 0) {+ unsigned long v;+ char *end;++ if (val == NULL || val[0] == 0) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "pax: align option needs a value");+ return (ARCHIVE_FAILED);+ }+ v = strtoul(val, &end, 10);+ if (*end != '\0' || v == 0 || (v % 512) != 0 ||+ (v & (v - 1)) != 0 || v > PAX_MAX_ALIGN) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "pax: align must be a power of two, a multiple "+ "of 512, and no larger than 1 MiB");+ return (ARCHIVE_FAILED);+ }+ pax->align = (size_t)v;+ return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options@@ -361,6 +388,81 @@ archive_strappend_char(as, '\n'); } +/*+ * Append the length/key prefix of an ignorable "LIBARCHIVE.pad" record whose+ * full length rounds the pax body up to 'target_len'. Return the number of+ * value/newline bytes that must be emitted after the in-memory header.+ */+static size_t+add_pax_padding_prefix(struct archive_string *as, size_t cur_len,+ size_t target_len)+{+ static const char key[] = "LIBARCHIVE.pad";+ char tmp[1 + 3 * sizeof(int64_t)];+ char *length;+ size_t prefix_len, record_len;++ if (target_len <= cur_len)+ return (0);+ record_len = target_len - cur_len;+ tmp[sizeof(tmp) - 1] = 0;+ length = format_int(tmp + sizeof(tmp) - 1, (int64_t)record_len);+ prefix_len = strlen(length) + 1 + sizeof(key) - 1 + 1;+ if (record_len <= prefix_len)+ return (0); /* not enough room; leave unaligned */++ archive_strcat(as, length);+ archive_strappend_char(as, ' ');+ archive_strcat(as, key);+ archive_strappend_char(as, '=');+ return (record_len - prefix_len);+}++/* Emit a deferred pax padding value followed by its record newline. */+static int+write_pax_padding(struct archive_write *a, size_t length)+{+ char padding[1024];++ if (length == 0)+ return (ARCHIVE_OK);+ memset(padding, 'X', sizeof(padding));+ while (length > 1) {+ size_t to_write = length - 1;+ int r;++ if (to_write > sizeof(padding))+ to_write = sizeof(padding);+ r = __archive_write_output(a, padding, to_write);+ if (r != ARCHIVE_OK)+ return (r);+ length -= to_write;+ }+ return (__archive_write_output(a, "\n", 1));+}++/*+ * For the pax "align" option: given entry offset 'off' (a multiple of 512) and+ * current extended-header body length 'l0', return the body length needed so+ * the file data (after the x header) lands on 'align', or 'l0' if already+ * aligned.+ */+static size_t+pax_align_body_len(uint64_t off, size_t l0, size_t align)+{+ uint64_t amask = (uint64_t)align - 1;+ /* Data offset with no extra padding (no x header when l0 == 0). */+ uint64_t natural_off = (l0 == 0) ? off + 512+ : off + 1024 + (((uint64_t)l0 + 511) & ~(uint64_t)511);++ if ((natural_off & amask) == 0)+ return (l0);++ /* Grow the body (past l0 plus pad-record room) to land data on align. */+ uint64_t base = off + 1024;+ return ((size_t)(((base + l0 + 64 + amask) & ~amask) - base));+}+ static void archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name, const void *value, size_t value_len)@@ -578,6 +680,7 @@ archive_write_pax_header(struct archive_write *a, struct archive_entry *entry_original) {+ struct pax *pax = a->format_data; struct archive_entry *entry_main; const char *p; const char *suffix;@@ -585,7 +688,6 @@ int acl_types; int sparse_count; uint64_t sparse_total, real_size;- struct pax *pax; const char *hardlink; const char *path = NULL, *linkpath = NULL; const char *uname = NULL, *gname = NULL;@@ -593,6 +695,7 @@ size_t mac_metadata_size; struct archive_string_conv *sconv; size_t hardlink_length, path_length, linkpath_length;+ size_t pax_header_padding = 0; size_t uname_length, gname_length; char paxbuff[512];@@ -604,7 +707,6 @@ ret = ARCHIVE_OK; need_extension = 0;- pax = (struct pax *)a->format_data; const time_t ustar_max_mtime = get_ustar_max_mtime(); @@ -1338,14 +1440,6 @@ archive_entry_set_size(entry_main, 0); /*- * Pax-restricted does not store data for hardlinks, in order- * to improve compatibility with ustar.- */- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&- hardlink != NULL)- archive_entry_set_size(entry_main, 0);-- /* * XXX Full pax interchange format does permit a hardlink * entry to have data associated with it. I'm not supporting * that here because the client expects me to tell them whether@@ -1411,6 +1505,21 @@ return (ARCHIVE_FATAL); } + /* Pad the extended header so contiguous file data starts on a pax->align+ * boundary (for reflinking); short and sparse files are left alone. */+ if (pax->align > 0+ && archive_entry_filetype(entry_main) == AE_IFREG+ && hardlink == NULL+ && sparse_count == 0+ && real_size >= (uint64_t)pax->align) {+ size_t l0 = archive_strlen(&(pax->pax_header));+ size_t needed = pax_align_body_len(+ (uint64_t)a->filter_first->bytes_written, l0, pax->align);+ if (needed != l0)+ pax_header_padding = add_pax_padding_prefix(+ &(pax->pax_header), l0, needed);+ }+ /* If we built any extended attributes, write that entry first. */ if (archive_strlen(&(pax->pax_header)) > 0) { struct archive_entry *pax_attr_entry;@@ -1419,11 +1528,20 @@ __LA_MODE_T mode; pax_attr_entry = archive_entry_new2(&a->archive);+ if (pax_attr_entry == NULL) {+ archive_set_error(&a->archive, ENOMEM,+ "Out of memory");+ archive_entry_free(entry_main);+ archive_string_free(&entry_name);+ return (ARCHIVE_FATAL);+ }+ p = entry_name.s; archive_entry_set_pathname(pax_attr_entry, build_pax_attribute_name(pax_entry_name, p)); archive_entry_set_size(pax_attr_entry,- archive_strlen(&(pax->pax_header)));+ archive_strlen(&(pax->pax_header)) ++ pax_header_padding); /* Copy uid/gid (but clip to ustar limits). */ uid = archive_entry_uid(entry_main); if (uid >= 1 << 18)@@ -1489,7 +1607,8 @@ return (ARCHIVE_FATAL); } - pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));+ pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header)) ++ pax_header_padding; pax->entry_padding = 0x1ff & (-(int64_t)pax->entry_bytes_remaining); @@ -1501,8 +1620,14 @@ archive_string_free(&entry_name); return (ARCHIVE_FATAL); }+ r = write_pax_padding(a, pax_header_padding);+ if (r != ARCHIVE_OK) {+ archive_entry_free(entry_main);+ archive_string_free(&entry_name);+ return (ARCHIVE_FATAL);+ } /* Pad out the end of the entry. */- r = __archive_write_nulls(a, (size_t)pax->entry_padding);+ r = __archive_write_nulls(a, pax->entry_padding); if (r != ARCHIVE_OK) { /* If a write fails, we're pretty much toast. */ archive_entry_free(entry_main);@@ -1574,18 +1699,21 @@ char *p; int need_slash = 0; /* Was there a trailing slash? */ size_t suffix_length = 98; /* 99 - 1 for trailing slash */- size_t insert_length;+ size_t insert_length, insert_name_length; /* Length of additional dir element to be added. */- if (insert == NULL)+ if (insert == NULL) {+ insert_name_length = 0; insert_length = 0;- else+ } else {+ insert_name_length = strlen(insert); /* +2 here allows for '/' before and after the insert. */- insert_length = strlen(insert) + 2;+ insert_length = insert_name_length + 2;+ } /* Step 0: Quick bailout in a common case. */ if (src_length < 100 && insert == NULL) {- strncpy(dest, src, src_length);+ memcpy(dest, src, src_length); dest[src_length] = '\0'; return (dest); }@@ -1607,6 +1735,26 @@ } break; }++ /*+ * Pathological case: after trimming trailing '/' characters and+ * '/.' path elements, there is no filename component left. This+ * happens for pathnames made entirely of '/' characters. Do not+ * attempt to compute filename_end - 1 in that case, which would+ * move the filename pointer in front of the input buffer and read+ * one byte out of bounds. Emit a root-like ustar name instead.+ */+ if (filename_end == src) {+ p = dest;+ if (insert != NULL) {+ strcpy(p, insert);+ p += strlen(insert);+ }+ *p++ = '/';+ *p = '\0';+ return (dest);+ }+ if (need_slash) suffix_length--; /* Find start of filename. */@@ -1647,24 +1795,22 @@ suffix_end++; /* Step 4: Build the new name. */- /* The OpenBSD strlcpy function is safer, but less portable. */- /* Rather than maintain two versions, just use the strncpy version. */ p = dest; if (prefix_end > prefix) {- strncpy(p, prefix, prefix_end - prefix);+ memcpy(p, prefix, (size_t)(prefix_end - prefix)); p += prefix_end - prefix; } if (suffix_end > suffix) {- strncpy(p, suffix, suffix_end - suffix);+ memcpy(p, suffix, (size_t)(suffix_end - suffix)); p += suffix_end - suffix; } if (insert != NULL) { /* Note: assume insert does not have leading or trailing '/' */- strcpy(p, insert);- p += strlen(insert);+ memcpy(p, insert, insert_name_length);+ p += insert_name_length; *p++ = '/'; }- strncpy(p, filename, filename_end - filename);+ memcpy(p, filename, (size_t)(filename_end - filename)); p += filename_end - filename; if (need_slash) *p++ = '/';@@ -1794,7 +1940,12 @@ } /* General case: build a ustar-compatible name adding- * "/GNUSparseFile/". */+ * "/GNUSparseFile.0/". */++ if (p == src) {+ strcpy(dest, "/GNUSparseFile.0/rootdir");+ return (dest);+ } build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0"); return (dest);@@ -1810,9 +1961,8 @@ static int archive_write_pax_free(struct archive_write *a) {- struct pax *pax;+ struct pax *pax = a->format_data; - pax = (struct pax *)a->format_data; if (pax == NULL) return (ARCHIVE_OK); @@ -1828,11 +1978,10 @@ static int archive_write_pax_finish_entry(struct archive_write *a) {- struct pax *pax;+ struct pax *pax = a->format_data; uint64_t remaining; int ret; - pax = (struct pax *)a->format_data; remaining = pax->entry_bytes_remaining; if (remaining == 0) { while (pax->sparse_list) {@@ -1844,7 +1993,7 @@ pax->sparse_list = sb; } }- ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));+ ret = __archive_write_nulls(a, remaining + pax->entry_padding); pax->entry_bytes_remaining = pax->entry_padding = 0; return (ret); }@@ -1852,13 +2001,11 @@ static ssize_t archive_write_pax_data(struct archive_write *a, const void *buff, size_t s) {- struct pax *pax;+ struct pax *pax = a->format_data; size_t ws; size_t total; int ret; - pax = (struct pax *)a->format_data;- /* * According to GNU PAX format 1.0, write a sparse map * before the body.@@ -1980,20 +2127,27 @@ 'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s', 't','u','v','w','x','y','z','0','1','2','3','4','5','6','7', '8','9','+','/' };- int v;+ uint32_t v; char *d, *out;+ size_t out_len; /* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */- out = malloc((len * 4 + 2) / 3 + 1);+ if (archive_ckd_mul_size(&out_len, len, 4) ||+ archive_ckd_add_size(&out_len, out_len, 2))+ return (NULL);+ out_len = out_len / 3;+ if (archive_ckd_add_size(&out_len, out_len, 1))+ return (NULL);+ out = malloc(out_len); if (out == NULL) return (NULL); d = out; /* Convert each group of 3 bytes into 4 characters. */ while (len >= 3) {- v = (((int)s[0] << 16) & 0xff0000)- | (((int)s[1] << 8) & 0xff00)- | (((int)s[2]) & 0x00ff);+ v = ((uint32_t)(unsigned char)s[0] << 16)+ | ((uint32_t)(unsigned char)s[1] << 8)+ | (uint32_t)(unsigned char)s[2]; s += 3; len -= 3; *d++ = digits[(v >> 18) & 0x3f];@@ -2005,13 +2159,13 @@ switch (len) { case 0: break; case 1:- v = (((int)s[0] << 16) & 0xff0000);+ v = ((uint32_t)(unsigned char)s[0] << 16); *d++ = digits[(v >> 18) & 0x3f]; *d++ = digits[(v >> 12) & 0x3f]; break; case 2:- v = (((int)s[0] << 16) & 0xff0000)- | (((int)s[1] << 8) & 0xff00);+ v = ((uint32_t)(unsigned char)s[0] << 16)+ | ((uint32_t)(unsigned char)s[1] << 8); *d++ = digits[(v >> 18) & 0x3f]; *d++ = digits[(v >> 12) & 0x3f]; *d++ = digits[(v >> 6) & 0x3f];
c/archive_write_set_format_raw.c view
@@ -55,8 +55,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_raw"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); raw = calloc(1, sizeof(*raw)); if (raw == NULL) {@@ -82,7 +81,7 @@ static int archive_write_raw_header(struct archive_write *a, struct archive_entry *entry) {- struct raw *raw = (struct raw *)a->format_data;+ struct raw *raw = a->format_data; if (archive_entry_filetype(entry) != AE_IFREG) { archive_set_error(&a->archive, ERANGE,@@ -116,9 +115,8 @@ static int archive_write_raw_free(struct archive_write *a) {- struct raw *raw;+ struct raw *raw = a->format_data; - raw = (struct raw *)a->format_data; free(raw); a->format_data = NULL; return (ARCHIVE_OK);
c/archive_write_set_format_shar.c view
@@ -98,11 +98,8 @@ } } -/*- * Set output format to 'shar' format.- */-int-archive_write_set_format_shar(struct archive *_a)+static int+shar_set_format(struct archive *_a, int dump) { struct archive_write *a = (struct archive_write *)_a; struct shar *shar;@@ -111,8 +108,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_shar"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); shar = calloc(1, sizeof(*shar)); if (shar == NULL) {@@ -121,50 +117,54 @@ } archive_string_init(&shar->work); archive_string_init(&shar->quoted_name);+ if (dump) {+ shar->dump = 1;+ a->format_write_data = archive_write_shar_data_uuencode;+ a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;+ a->archive.archive_format_name = "shar dump";+ } else {+ a->format_write_data = archive_write_shar_data_sed;+ a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;+ a->archive.archive_format_name = "shar";+ } a->format_data = shar; a->format_name = "shar"; a->format_write_header = archive_write_shar_header; a->format_close = archive_write_shar_close; a->format_free = archive_write_shar_free;- a->format_write_data = archive_write_shar_data_sed; a->format_finish_entry = archive_write_shar_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;- a->archive.archive_format_name = "shar"; return (ARCHIVE_OK); } /*+ * Set output format to 'shar' format.+ */+int+archive_write_set_format_shar(struct archive *a)+{+ return shar_set_format(a, 0);+}++/* * An alternate 'shar' that uses uudecode instead of 'sed' to encode * file contents and can therefore be used to archive binary files. * In addition, this variant also attempts to restore ownership, file modes, * and other extended file information. */ int-archive_write_set_format_shar_dump(struct archive *_a)+archive_write_set_format_shar_dump(struct archive *a) {- struct archive_write *a = (struct archive_write *)_a;- struct shar *shar;-- int ret = archive_write_set_format_shar(&a->archive);- if (ret != ARCHIVE_OK)- return ret;- shar = (struct shar *)a->format_data;- shar->dump = 1;- a->format_write_data = archive_write_shar_data_uuencode;- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;- a->archive.archive_format_name = "shar dump";- return (ARCHIVE_OK);+ return shar_set_format(a, 1); } static int archive_write_shar_header(struct archive_write *a, struct archive_entry *entry) {+ struct shar *shar = a->format_data; const char *linkname; const char *name; char *p, *pp;- struct shar *shar; - shar = (struct shar *)a->format_data; if (!shar->wrote_header) { archive_strcat(&shar->work, "#!/bin/sh\n"); archive_strcat(&shar->work, "# This is a shell archive\n");@@ -343,14 +343,13 @@ static ssize_t archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n) {+ struct shar *shar = a->format_data; static const size_t ensured = 65533;- struct shar *shar; const char *src; char *buf, *buf_end; int ret; size_t written = n; - shar = (struct shar *)a->format_data; if (!shar->has_data || n == 0) return (0); @@ -475,12 +474,11 @@ archive_write_shar_data_uuencode(struct archive_write *a, const void *buff, size_t length) {- struct shar *shar;+ struct shar *shar = a->format_data; const char *src; size_t n; int ret; - shar = (struct shar *)a->format_data; if (!shar->has_data) return (ARCHIVE_OK); src = (const char *)buff;@@ -524,13 +522,12 @@ static int archive_write_shar_finish_entry(struct archive_write *a) {+ struct shar *shar = a->format_data; const char *g, *p, *u;- struct shar *shar; int ret; - shar = (struct shar *)a->format_data; if (shar->entry == NULL)- return (0);+ return (ARCHIVE_OK); if (shar->dump) { /* Finish uuencoded data. */@@ -602,7 +599,7 @@ static int archive_write_shar_close(struct archive_write *a) {- struct shar *shar;+ struct shar *shar = a->format_data; int ret; /*@@ -610,8 +607,6 @@ * fix them all up at end-of-archive. */ - shar = (struct shar *)a->format_data;- /* * Only write the end-of-archive markers if the archive was * actually started. This avoids problems if someone sets@@ -640,9 +635,8 @@ static int archive_write_shar_free(struct archive_write *a) {- struct shar *shar;+ struct shar *shar = a->format_data; - shar = (struct shar *)a->format_data; if (shar == NULL) return (ARCHIVE_OK);
c/archive_write_set_format_ustar.c view
@@ -172,8 +172,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_ustar"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); /* Basic internal sanity test. */ if (sizeof(template_header) != 512) {@@ -206,7 +205,7 @@ archive_write_ustar_options(struct archive_write *a, const char *key, const char *val) {- struct ustar *ustar = (struct ustar *)a->format_data;+ struct ustar *ustar = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -234,14 +233,12 @@ static int archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) {+ struct ustar *ustar = a->format_data; char buff[512]; int ret, ret2;- struct ustar *ustar; struct archive_entry *entry_main; struct archive_string_conv *sconv; - ustar = (struct ustar *)a->format_data;- /* Setup default string conversion. */ if (ustar->opt_sconv == NULL) { if (!ustar->init_default_conversion) {@@ -736,9 +733,8 @@ static int archive_write_ustar_free(struct archive_write *a) {- struct ustar *ustar;+ struct ustar *ustar = a->format_data; - ustar = (struct ustar *)a->format_data; free(ustar); a->format_data = NULL; return (ARCHIVE_OK);@@ -747,12 +743,11 @@ static int archive_write_ustar_finish_entry(struct archive_write *a) {- struct ustar *ustar;+ struct ustar *ustar = a->format_data; int ret; - ustar = (struct ustar *)a->format_data; ret = __archive_write_nulls(a,- (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));+ ustar->entry_bytes_remaining + ustar->entry_padding); ustar->entry_bytes_remaining = ustar->entry_padding = 0; return (ret); }@@ -760,10 +755,9 @@ static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) {- struct ustar *ustar;+ struct ustar *ustar = a->format_data; int ret; - ustar = (struct ustar *)a->format_data; if (s > ustar->entry_bytes_remaining) s = (size_t)ustar->entry_bytes_remaining; ret = __archive_write_output(a, buff, s);
c/archive_write_set_format_v7tar.c view
@@ -149,8 +149,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar"); /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); /* Basic internal sanity test. */ if (sizeof(template_header) != 512) {@@ -183,7 +182,7 @@ archive_write_v7tar_options(struct archive_write *a, const char *key, const char *val) {- struct v7tar *v7tar = (struct v7tar *)a->format_data;+ struct v7tar *v7tar = a->format_data; int ret = ARCHIVE_FAILED; if (strcmp(key, "hdrcharset") == 0) {@@ -211,14 +210,12 @@ static int archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) {+ struct v7tar *v7tar = a->format_data; char buff[512]; int ret, ret2;- struct v7tar *v7tar; struct archive_entry *entry_main; struct archive_string_conv *sconv; - v7tar = (struct v7tar *)a->format_data;- /* Setup default string conversion. */ if (v7tar->opt_sconv == NULL) { if (!v7tar->init_default_conversion) {@@ -616,9 +613,8 @@ static int archive_write_v7tar_free(struct archive_write *a) {- struct v7tar *v7tar;+ struct v7tar *v7tar = a->format_data; - v7tar = (struct v7tar *)a->format_data; free(v7tar); a->format_data = NULL; return (ARCHIVE_OK);@@ -627,12 +623,11 @@ static int archive_write_v7tar_finish_entry(struct archive_write *a) {- struct v7tar *v7tar;+ struct v7tar *v7tar = a->format_data; int ret; - v7tar = (struct v7tar *)a->format_data; ret = __archive_write_nulls(a,- (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));+ v7tar->entry_bytes_remaining + v7tar->entry_padding); v7tar->entry_bytes_remaining = v7tar->entry_padding = 0; return (ret); }@@ -640,10 +635,9 @@ static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s) {- struct v7tar *v7tar;+ struct v7tar *v7tar = a->format_data; int ret; - v7tar = (struct v7tar *)a->format_data; if (s > v7tar->entry_bytes_remaining) s = (size_t)v7tar->entry_bytes_remaining; ret = __archive_write_output(a, buff, s);
c/archive_write_set_format_warc.c view
@@ -49,68 +49,81 @@ #include "archive_write_private.h" #include "archive_write_set_format_private.h" -struct warc_s {+/*+ * Overview of the WARC writer:+ *+ * This writer emits WARC/1.0 resource records for regular files. It+ * writes a warcinfo record once by default, unless the omit-warcinfo+ * option is used. Each resource record gets a WARC-Target-URI from+ * the entry pathname, a generated WARC-Record-ID, and a mandatory+ * Content-Length header.+ */++struct warc { unsigned int omit_warcinfo:1; time_t now;- mode_t typ;- unsigned int rng;- /* populated size */- uint64_t populz;+ mode_t filetype;+ /* Remaining bytes to write for the current entry */+ uint64_t entry_bytes_remaining; }; -static const char warcinfo[] =+#define WARC_HEADER_MAX_SIZE 512++static const char warcinfo_payload[] = "software: libarchive/" ARCHIVE_VERSION_ONLY_STRING "\r\n" "format: WARC file version 1.0\r\n"; -typedef enum {- WT_NONE,- /* warcinfo */- WT_INFO,- /* metadata */- WT_META,- /* resource */- WT_RSRC,- /* request, unsupported */- WT_REQ,- /* response, unsupported */- WT_RSP,- /* revisit, unsupported */- WT_RVIS,- /* conversion, unsupported */- WT_CONV,- /* continuation, unsupported at the moment */- WT_CONT,- /* invalid type */- LAST_WT-} warc_type_t;+enum warc_type {+ WARC_TYPE_NONE,+ /* WARC info */+ WARC_TYPE_INFO,+ /* Metadata */+ WARC_TYPE_METADATA,+ /* Resource */+ WARC_TYPE_RESOURCE,+ /* Request, unsupported */+ WARC_TYPE_REQUEST,+ /* Response, unsupported by this writer */+ WARC_TYPE_RESPONSE,+ /* Revisit, unsupported */+ WARC_TYPE_REVISIT,+ /* Conversion, unsupported */+ WARC_TYPE_CONVERSION,+ /* Continuation, currently unsupported */+ WARC_TYPE_CONTINUATION,+ WARC_TYPE_LAST+}; -typedef struct {- warc_type_t type;- const char *tgturi;- const char *recid;- time_t rtime;- time_t mtime;- const char *cnttyp;- uint64_t cntlen;-} warc_essential_hdr_t;+struct warc_header {+ enum warc_type type;+ const char *target_uri;+ const char *record_id;+ time_t record_time;+ time_t modification_time;+ const char *content_type;+ uint64_t content_length;+}; -typedef struct {- unsigned int u[4U];-} warc_uuid_t;+struct warc_uuid {+ unsigned int value[4U];+}; -static int _warc_options(struct archive_write*, const char *key, const char *v);-static int _warc_header(struct archive_write *a, struct archive_entry *entry);-static ssize_t _warc_data(struct archive_write *a, const void *buf, size_t sz);-static int _warc_finish_entry(struct archive_write *a);-static int _warc_close(struct archive_write *a);-static int _warc_free(struct archive_write *a);+static int archive_write_warc_options(struct archive_write *,+ const char *, const char *);+static int archive_write_warc_header(struct archive_write *,+ struct archive_entry *);+static ssize_t archive_write_warc_data(struct archive_write *, const void *,+ size_t);+static int archive_write_warc_finish_entry(struct archive_write *);+static int archive_write_warc_close(struct archive_write *);+static int archive_write_warc_free(struct archive_write *); -/* private routines */-static ssize_t _popul_ehdr(struct archive_string *t, size_t z, warc_essential_hdr_t);-static int _gen_uuid(warc_uuid_t *tgt);+static void warc_format_time(struct archive_string *, const char *, time_t);+static ssize_t warc_populate_header(struct archive_string *, size_t,+ struct warc_header);+static void warc_generate_uuid(struct warc_uuid *); - /* * Set output format to ISO 28500 (aka WARC) format. */@@ -118,103 +131,110 @@ archive_write_set_format_warc(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a;- struct warc_s *w;+ struct warc *warc; archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_format_warc"); /* If another format was already registered, unregister it. */- if (a->format_free != NULL) {- (a->format_free)(a);- }+ (void)__archive_write_unregister_format(a); - w = malloc(sizeof(*w));- if (w == NULL) {+ warc = malloc(sizeof(*warc));+ if (warc == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate warc data"); return (ARCHIVE_FATAL); }- /* by default we're emitting a file wide header */- w->omit_warcinfo = 0U;- /* obtain current time for date fields */- w->now = time(NULL);- /* reset file type info */- w->typ = 0;- /* also initialise our rng */- w->rng = (unsigned int)w->now;+ /* Emit a warcinfo record by default. */+ warc->omit_warcinfo = 0U;+ /* Use the current time for WARC-Date values. */+ warc->now = time(NULL);+ /* Reset file type information. */+ warc->filetype = 0; - a->format_data = w;+ a->format_data = warc; a->format_name = "WARC/1.0";- a->format_options = _warc_options;- a->format_write_header = _warc_header;- a->format_write_data = _warc_data;- a->format_close = _warc_close;- a->format_free = _warc_free;- a->format_finish_entry = _warc_finish_entry;+ a->format_options = archive_write_warc_options;+ a->format_write_header = archive_write_warc_header;+ a->format_write_data = archive_write_warc_data;+ a->format_close = archive_write_warc_close;+ a->format_free = archive_write_warc_free;+ a->format_finish_entry = archive_write_warc_finish_entry; a->archive.archive_format = ARCHIVE_FORMAT_WARC; a->archive.archive_format_name = "WARC/1.0"; return (ARCHIVE_OK); } --/* archive methods */ static int-_warc_options(struct archive_write *a, const char *key, const char *val)+archive_write_warc_options(struct archive_write *a, const char *key,+ const char *val) {- struct warc_s *w = a->format_data;+ struct warc *warc = a->format_data; if (strcmp(key, "omit-warcinfo") == 0) { if (val == NULL || strcmp(val, "true") == 0) {- /* great */- w->omit_warcinfo = 1U;+ /* Option accepted. */+ warc->omit_warcinfo = 1U; return (ARCHIVE_OK); } } - /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */+ /* ARCHIVE_WARN tells the options supervisor that this option was not+ * handled here. It will report an error if no module uses it. */ return (ARCHIVE_WARN); } static int-_warc_header(struct archive_write *a, struct archive_entry *entry)+archive_write_warc_header(struct archive_write *a, struct archive_entry *entry) {- struct warc_s *w = a->format_data;- struct archive_string hdr;-#define MAX_HDR_SIZE 512+ struct warc *warc = a->format_data;+ struct archive_string header; - /* check whether warcinfo record needs outputting */- if (!w->omit_warcinfo) {- ssize_t r;- warc_essential_hdr_t wi = {- WT_INFO,- /*uri*/NULL,- /*urn*/NULL,- /*rtm*/0,- /*mtm*/0,- /*cty*/"application/warc-fields",- /*len*/sizeof(warcinfo) - 1U,+ /* Emit the warcinfo record if needed. */+ if (!warc->omit_warcinfo) {+ ssize_t header_size;+ int ret;+ struct warc_header warcinfo_header = {+ WARC_TYPE_INFO,+ /* URI */NULL,+ /* Record ID */NULL,+ /* Record time */0,+ /* Modified time */0,+ /* Content type */"application/warc-fields",+ /* Content length */sizeof(warcinfo_payload) - 1U, };- wi.rtime = w->now;- wi.mtime = w->now;+ warcinfo_header.record_time = warc->now;+ warcinfo_header.modification_time = warc->now; - archive_string_init(&hdr);- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi);- if (r >= 0) {- /* jackpot! */- /* now also use HDR buffer for the actual warcinfo */- archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1);+ archive_string_init(&header);+ header_size = warc_populate_header(&header,+ WARC_HEADER_MAX_SIZE, warcinfo_header);+ if (header_size < 0) {+ archive_string_free(&header);+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "Cannot archive warcinfo record");+ return (ARCHIVE_FAILED);+ } - /* append end-of-record indicator */- archive_strncat(&hdr, "\r\n\r\n", 4);+ /* Reuse the header buffer for the warcinfo payload. */+ archive_strncat(&header, warcinfo_payload,+ sizeof(warcinfo_payload) - 1); - /* write to output stream */- __archive_write_output(a, hdr.s, archive_strlen(&hdr));+ /* Append the end-of-record indicator. */+ archive_strncat(&header, "\r\n\r\n", 4);++ /* Write the warcinfo record to the output stream. */+ ret = __archive_write_output(a, header.s,+ archive_strlen(&header));+ if (ret != ARCHIVE_OK) {+ archive_string_free(&header);+ return (ret); }- /* indicate we're done with file header writing */- w->omit_warcinfo = 1U;- archive_string_free(&hdr);++ /* Mark the file header as written. */+ warc->omit_warcinfo = 1U;+ archive_string_free(&header); } if (archive_entry_pathname(entry) == NULL) {@@ -223,222 +243,249 @@ return (ARCHIVE_WARN); } - w->typ = archive_entry_filetype(entry);- w->populz = 0U;- if (w->typ == AE_IFREG) {- warc_essential_hdr_t rh = {- WT_RSRC,- /*uri*/NULL,- /*urn*/NULL,- /*rtm*/0,- /*mtm*/0,- /*cty*/NULL,- /*len*/0,+ warc->filetype = archive_entry_filetype(entry);+ warc->entry_bytes_remaining = 0U;+ if (warc->filetype == AE_IFREG) {+ struct warc_header resource_header = {+ WARC_TYPE_RESOURCE,+ /* URI */NULL,+ /* Record ID */NULL,+ /* Record time */0,+ /* Modified time */0,+ /* Content type */NULL,+ /* Content length */0, };- ssize_t r;- rh.tgturi = archive_entry_pathname(entry);- rh.rtime = w->now;- rh.mtime = archive_entry_mtime(entry);- rh.cntlen = (size_t)archive_entry_size(entry);+ ssize_t header_size;+ int ret;+ int64_t size; - archive_string_init(&hdr);- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);- if (r < 0) {- /* don't bother */- archive_string_free(&hdr);- archive_set_error(- &a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "cannot archive file");- return (ARCHIVE_WARN);+ resource_header.target_uri = archive_entry_pathname(entry);+ resource_header.record_time = warc->now;+ resource_header.modification_time = archive_entry_mtime(entry);+ if (!archive_entry_size_is_set(entry)) {+ archive_set_error(&a->archive, -1,+ "Size required");+ return (ARCHIVE_FAILED); }- /* otherwise append to output stream */- __archive_write_output(a, hdr.s, r);- /* and let subsequent calls to _data() know about the size */- w->populz = rh.cntlen;- archive_string_free(&hdr);+ size = archive_entry_size(entry);+ if (size < 0) {+ archive_set_error(&a->archive, -1,+ "Size required");+ return (ARCHIVE_FAILED);+ }+ resource_header.content_length = (uint64_t)size;++ archive_string_init(&header);+ header_size = warc_populate_header(&header,+ WARC_HEADER_MAX_SIZE, resource_header);+ if (header_size < 0) {+ /* Header generation failed. */+ archive_string_free(&header);+ archive_set_error(&a->archive,+ ARCHIVE_ERRNO_FILE_FORMAT,+ "WARC resource header is too large");+ return (ARCHIVE_FATAL);+ }+ /* Append the header to the output stream. */+ ret = __archive_write_output(a, header.s, header_size);+ if (ret != ARCHIVE_OK) {+ archive_string_free(&header);+ return (ret);+ }+ /* Save the remaining size for subsequent data callbacks. */+ warc->entry_bytes_remaining = resource_header.content_length;+ archive_string_free(&header); return (ARCHIVE_OK); }- /* just resort to erroring as per Tim's advice */+ /* Report unsupported file types through the common helper. */ __archive_write_entry_filetype_unsupported( &a->archive, entry, "WARC"); return (ARCHIVE_FAILED); } static ssize_t-_warc_data(struct archive_write *a, const void *buf, size_t len)+archive_write_warc_data(struct archive_write *a, const void *buf, size_t len) {- struct warc_s *w = a->format_data;+ struct warc *warc = a->format_data; - if (w->typ == AE_IFREG) {- int rc;+ if (warc->filetype == AE_IFREG) {+ int ret; - /* never write more bytes than announced */- if (len > w->populz) {- len = (size_t)w->populz;+ /* Never write more bytes than announced. */+ if ((uint64_t)len > warc->entry_bytes_remaining) {+ len = (size_t)warc->entry_bytes_remaining; } - /* now then, out we put the whole shebang */- rc = __archive_write_output(a, buf, len);- if (rc != ARCHIVE_OK) {- return rc;+ /* Write the entry data. */+ ret = __archive_write_output(a, buf, len);+ if (ret != ARCHIVE_OK) {+ return (ret); }+ warc->entry_bytes_remaining -= len; }- return len;+ return (len); } static int-_warc_finish_entry(struct archive_write *a)+archive_write_warc_finish_entry(struct archive_write *a) {- static const char _eor[] = "\r\n\r\n";- struct warc_s *w = a->format_data;+ static const char end_of_record[] = "\r\n\r\n";+ struct warc *warc = a->format_data; - if (w->typ == AE_IFREG) {- int rc = __archive_write_output(a, _eor, sizeof(_eor) - 1U);+ if (warc->filetype == AE_IFREG) {+ int ret; - if (rc != ARCHIVE_OK) {- return rc;+ if (warc->entry_bytes_remaining != 0U) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "WARC entry is shorter than Content-Length");+ return (ARCHIVE_FATAL); }++ ret = __archive_write_output(a, end_of_record,+ sizeof(end_of_record) - 1U);+ if (ret != ARCHIVE_OK) {+ return (ret);+ } }- /* reset type info */- w->typ = 0;+ /* Reset file type information. */+ warc->filetype = 0; return (ARCHIVE_OK); } static int-_warc_close(struct archive_write *a)+archive_write_warc_close(struct archive_write *a) { (void)a; /* UNUSED */ return (ARCHIVE_OK); } static int-_warc_free(struct archive_write *a)+archive_write_warc_free(struct archive_write *a) {- struct warc_s *w = a->format_data;+ struct warc *warc = a->format_data; - free(w);+ free(warc); a->format_data = NULL; return (ARCHIVE_OK); } --/* private routines */+/* Like strftime(3), but for time_t objects. */ static void-xstrftime(struct archive_string *as, const char *fmt, time_t t)+warc_format_time(struct archive_string *str, const char *format, time_t t) {-/** like strftime(3) but for time_t objects */- struct tm *rt;+ struct tm *tm; #if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)- struct tm timeHere;+ struct tm tm_storage; #endif- char strtime[100];+ char time_string[100]; size_t len; #if defined(HAVE_GMTIME_S)- rt = gmtime_s(&timeHere, &t) ? NULL : &timeHere;+ tm = gmtime_s(&tm_storage, &t) ? NULL : &tm_storage; #elif defined(HAVE_GMTIME_R)- rt = gmtime_r(&t, &timeHere);+ tm = gmtime_r(&t, &tm_storage); #else- rt = gmtime(&t);+ tm = gmtime(&t); #endif- if (!rt)+ if (tm == NULL) return;- /* leave the hard yacker to our role model strftime() */- len = strftime(strtime, sizeof(strtime)-1, fmt, rt);- archive_strncat(as, strtime, len);+ /* Let strftime() handle the actual formatting. */+ len = strftime(time_string, sizeof(time_string) - 1, format, tm);+ archive_strncat(str, time_string, len); } static ssize_t-_popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)+warc_populate_header(struct archive_string *header_string, size_t max_size,+ struct warc_header header) {- static const char _ver[] = "WARC/1.0\r\n";- static const char * const _typ[LAST_WT] = {+ static const char version[] = "WARC/1.0\r\n";+ static const char * const record_types[WARC_TYPE_LAST] = { NULL, "warcinfo", "metadata", "resource", NULL };- char std_uuid[48U];+ char generated_record_id[48U]; - if (hdr.type == WT_NONE || hdr.type > WT_RSRC) {- /* brilliant, how exactly did we get here? */- return -1;+ if (header.type == WARC_TYPE_NONE || header.type > WARC_TYPE_RESOURCE) {+ /* Invalid record type for this writer. */+ return (-1); } - archive_strcpy(tgt, _ver);+ archive_strcpy(header_string, version); - archive_string_sprintf(tgt, "WARC-Type: %s\r\n", _typ[hdr.type]);+ archive_string_sprintf(header_string, "WARC-Type: %s\r\n",+ record_types[header.type]); - if (hdr.tgturi != NULL) {- /* check if there's a xyz:// */- static const char _uri[] = "";- static const char _fil[] = "file://";- const char *u;- const char *chk = strchr(hdr.tgturi, ':');+ if (header.target_uri != NULL) {+ const char *uri_prefix;+ const char *scheme = strchr(header.target_uri, ':'); - if (chk != NULL && chk[1U] == '/' && chk[2U] == '/') {- /* yep, it's definitely a URI */- u = _uri;+ /* Check whether the value already contains ://. */+ if (scheme != NULL && scheme[1U] == '/' && scheme[2U] == '/') {+ /* Already has a scheme-style :// prefix. */+ uri_prefix = ""; } else {- /* hm, best to prepend file:// then */- u = _fil;+ /* Prepend file:// for local paths. */+ uri_prefix = "file://"; }- archive_string_sprintf(tgt,- "WARC-Target-URI: %s%s\r\n", u, hdr.tgturi);+ archive_string_sprintf(header_string,+ "WARC-Target-URI: %s%s\r\n", uri_prefix,+ header.target_uri); } - /* record time is usually when the http is sent off,- * just treat the archive writing as such for a moment */- xstrftime(tgt, "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.rtime);+ /* Write WARC-Date from header.record_time. */+ warc_format_time(header_string,+ "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", header.record_time); - /* while we're at it, record the mtime */- xstrftime(tgt, "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.mtime);+ /* Also write Last-Modified from header.modification_time. */+ warc_format_time(header_string,+ "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n",+ header.modification_time); - if (hdr.recid == NULL) {- /* generate one, grrrr */- warc_uuid_t u;+ if (header.record_id == NULL) {+ /* Generate a record ID when one was not provided. */+ struct warc_uuid uuid; - _gen_uuid(&u);- /* Unfortunately, archive_string_sprintf does not- * handle the minimum number following '%'.- * So we have to use snprintf function here instead- * of archive_string_snprintf function. */-#if defined(_WIN32) && !defined(__CYGWIN__) && !( defined(_MSC_VER) && _MSC_VER >= 1900)+ warc_generate_uuid(&uuid);+ /* archive_string_sprintf() does not support minimum field widths, so+ * use snprintf() for UUID formatting. */+#if defined(_WIN32) && !defined(__CYGWIN__) && \+ !(defined(_MSC_VER) && _MSC_VER >= 1900) #define snprintf _snprintf #endif- snprintf(- std_uuid, sizeof(std_uuid),- "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",- u.u[0U],- u.u[1U] >> 16U, u.u[1U] & 0xffffU,- u.u[2U] >> 16U, u.u[2U] & 0xffffU,- u.u[3U]);- hdr.recid = std_uuid;+ snprintf(generated_record_id, sizeof(generated_record_id),+ "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",+ uuid.value[0U],+ uuid.value[1U] >> 16U, uuid.value[1U] & 0xffffU,+ uuid.value[2U] >> 16U, uuid.value[2U] & 0xffffU,+ uuid.value[3U]);+ header.record_id = generated_record_id; } - /* record-id is mandatory, fingers crossed we won't fail */- archive_string_sprintf(tgt, "WARC-Record-ID: %s\r\n", hdr.recid);+ /* WARC-Record-ID is mandatory. */+ archive_string_sprintf(header_string, "WARC-Record-ID: %s\r\n",+ header.record_id); - if (hdr.cnttyp != NULL) {- archive_string_sprintf(tgt, "Content-Type: %s\r\n", hdr.cnttyp);+ if (header.content_type != NULL) {+ archive_string_sprintf(header_string, "Content-Type: %s\r\n",+ header.content_type); } - /* next one is mandatory */- archive_string_sprintf(tgt, "Content-Length: %ju\r\n", (uintmax_t)hdr.cntlen);- /**/- archive_strncat(tgt, "\r\n", 2);+ /* Content-Length is mandatory. */+ archive_string_sprintf(header_string, "Content-Length: %ju\r\n",+ (uintmax_t)header.content_length);+ /* End of header. */+ archive_strncat(header_string, "\r\n", 2); - return (archive_strlen(tgt) >= tsz)? -1: (ssize_t)archive_strlen(tgt);+ return (archive_strlen(header_string) >= max_size) ?+ -1 : (ssize_t)archive_strlen(header_string); } -static int-_gen_uuid(warc_uuid_t *tgt)+static void+warc_generate_uuid(struct warc_uuid *uuid) {- archive_random(tgt->u, sizeof(tgt->u));- /* obey uuid version 4 rules */- tgt->u[1U] &= 0xffff0fffU;- tgt->u[1U] |= 0x4000U;- tgt->u[2U] &= 0x3fffffffU;- tgt->u[2U] |= 0x80000000U;- return 0;+ archive_random(uuid->value, sizeof(uuid->value));+ /* Apply UUID version 4 rules. */+ uuid->value[1U] &= 0xffff0fffU;+ uuid->value[1U] |= 0x4000U;+ uuid->value[2U] &= 0x3fffffffU;+ uuid->value[2U] |= 0x80000000U; }--/* archive_write_set_format_warc.c ends here */
c/archive_write_set_format_xar.c view
@@ -111,7 +111,7 @@ static int xml_writer_write_attribute(struct xml_writer *ctx, const char *key, const char *value); static int xml_writer_write_attributef(struct xml_writer *ctx, const char *key,- const char *format, ...);+ const char *format, ...) __LA_PRINTF(3, 4); static int xml_writer_write_string(struct xml_writer *ctx, const char *string); static int xml_writer_write_base64(struct xml_writer* ctx, const char *data, size_t start, size_t len);@@ -129,14 +129,20 @@ enum sumalg { CKSUM_NONE = 0, CKSUM_SHA1 = 1,- CKSUM_MD5 = 2+ CKSUM_MD5 = 2,+ CKSUM_SHA256 = 3,+ CKSUM_SHA512 = 4 }; #define MD5_SIZE 16 #define SHA1_SIZE 20-#define MAX_SUM_SIZE 20+#define SHA256_SIZE 32+#define SHA512_SIZE 64+#define MAX_SUM_SIZE 64 #define MD5_NAME "md5" #define SHA1_NAME "sha1"+#define SHA256_NAME "sha256"+#define SHA512_NAME "sha512" enum enctype { NONE,@@ -154,6 +160,12 @@ #ifdef ARCHIVE_HAS_SHA1 archive_sha1_ctx sha1ctx; #endif+#ifdef ARCHIVE_HAS_SHA256+ archive_sha256_ctx sha256ctx;+#endif+#ifdef ARCHIVE_HAS_SHA512+ archive_sha512_ctx sha512ctx;+#endif }; enum la_zaction {@@ -366,8 +378,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_xar"); /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); xar = calloc(1, sizeof(*xar)); if (xar == NULL) {@@ -380,22 +391,19 @@ file_init_hardlinks(xar); archive_string_init(&(xar->tstr)); archive_string_init(&(xar->vstr));+ archive_string_init(&(xar->cur_dirstr)); /* * Create the root directory. */ xar->root = file_create_virtual_dir(a, xar, "");- if (xar->root == NULL) {- free(xar);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate xar data");- return (ARCHIVE_FATAL);- }+ if (xar->root == NULL)+ goto memerr; xar->root->parent = xar->root; file_register(xar, xar->root); xar->cur_dirent = xar->root;- archive_string_init(&(xar->cur_dirstr));- archive_string_ensure(&(xar->cur_dirstr), 1);+ if (archive_string_ensure(&(xar->cur_dirstr), 1) == NULL)+ goto memerr; xar->cur_dirstr.s[0] = 0; /*@@ -422,14 +430,23 @@ a->archive.archive_format_name = "xar"; return (ARCHIVE_OK);++memerr:+ archive_string_free(&(xar->cur_dirstr));+ archive_string_free(&(xar->tstr));+ archive_string_free(&(xar->vstr));+ file_free_hardlinks(xar);+ file_free_register(xar);+ free(xar);+ archive_set_error(&a->archive, ENOMEM,+ "Can't allocate xar data");+ return (ARCHIVE_FATAL); } static int xar_options(struct archive_write *a, const char *key, const char *value) {- struct xar *xar;-- xar = (struct xar *)a->format_data;+ struct xar *xar = a->format_data; if (strcmp(key, "checksum") == 0) { if (value == NULL)@@ -440,6 +457,14 @@ xar->opt_sumalg = CKSUM_SHA1; else if (strcmp(value, "md5") == 0) xar->opt_sumalg = CKSUM_MD5;+#ifdef ARCHIVE_HAS_SHA256+ else if (strcmp(value, "sha256") == 0)+ xar->opt_sumalg = CKSUM_SHA256;+#endif+#ifdef ARCHIVE_HAS_SHA512+ else if (strcmp(value, "sha512") == 0)+ xar->opt_sumalg = CKSUM_SHA512;+#endif else { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,@@ -515,6 +540,14 @@ xar->opt_toc_sumalg = CKSUM_SHA1; else if (strcmp(value, "md5") == 0) xar->opt_toc_sumalg = CKSUM_MD5;+#ifdef ARCHIVE_HAS_SHA256+ else if (strcmp(value, "sha256") == 0)+ xar->opt_toc_sumalg = CKSUM_SHA256;+#endif+#ifdef ARCHIVE_HAS_SHA512+ else if (strcmp(value, "sha512") == 0)+ xar->opt_toc_sumalg = CKSUM_SHA512;+#endif else { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,@@ -559,12 +592,11 @@ static int xar_write_header(struct archive_write *a, struct archive_entry *entry) {- struct xar *xar;+ struct xar *xar = a->format_data; struct file *file; struct archive_entry *file_entry; int r, r2; - xar = (struct xar *)a->format_data; xar->cur_file = NULL; xar->bytes_remaining = 0; @@ -582,8 +614,10 @@ return (ARCHIVE_FATAL); } r2 = file_gen_utility_names(a, file);- if (r2 < ARCHIVE_WARN)+ if (r2 < ARCHIVE_WARN) {+ file_free(file); return (r2);+ } /* * Ignore a path which looks like the top of directory name@@ -672,20 +706,25 @@ checksum_init(&(xar->e_sumwrk), xar->opt_sumalg); r = xar_compression_init_encoder(a); - if (r != ARCHIVE_OK)+ if (r != ARCHIVE_OK) {+ struct chksumval sumval;++ checksum_final(&(xar->a_sumwrk), &sumval);+ checksum_final(&(xar->e_sumwrk), &sumval);+ xar->a_sumwrk.alg = CKSUM_NONE;+ xar->e_sumwrk.alg = CKSUM_NONE; return (r);- else+ } else return (r2); } static int write_to_temp(struct archive_write *a, const void *buff, size_t s) {- struct xar *xar;+ struct xar *xar = a->format_data; const unsigned char *p; ssize_t ws; - xar = (struct xar *)a->format_data; p = (const unsigned char *)buff; while (s) { ws = write(xar->temp_fd, p, s);@@ -704,14 +743,12 @@ static ssize_t xar_write_data(struct archive_write *a, const void *buff, size_t s) {- struct xar *xar;+ struct xar *xar = a->format_data; enum la_zaction run; size_t size = 0; size_t rsize; int r; - xar = (struct xar *)a->format_data;- if (s > xar->bytes_remaining) s = (size_t)xar->bytes_remaining; if (s == 0 || xar->cur_file == NULL)@@ -805,12 +842,11 @@ static int xar_finish_entry(struct archive_write *a) {- struct xar *xar;+ struct xar *xar = a->format_data; struct file *file; size_t s; ssize_t w; - xar = (struct xar *)a->format_data; if (xar->cur_file == NULL) return (ARCHIVE_OK); @@ -907,14 +943,13 @@ return (ARCHIVE_OK); } -static int+static int __LA_PRINTF(4, 5) xmlwrite_fstring(struct archive_write *a, struct xml_writer *writer, const char *key, const char *fmt, ...) {- struct xar *xar;+ struct xar *xar = a->format_data; va_list ap; - xar = (struct xar *)a->format_data; va_start(ap, fmt); archive_string_empty(&xar->vstr); archive_string_vsprintf(&xar->vstr, fmt, ap);@@ -1202,7 +1237,7 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer, struct file *file) {- struct xar *xar;+ struct xar *xar = a->format_data; const char *filetype, *filelink, *fflags; struct archive_string linkto; struct heap_data *heap;@@ -1210,7 +1245,6 @@ size_t len; int r, r2; - xar = (struct xar *)a->format_data; r2 = ARCHIVE_OK; /*@@ -1333,11 +1367,11 @@ return (ARCHIVE_FATAL); } r = xmlwrite_fstring(a, writer, "major",- "%d", archive_entry_rdevmajor(file->entry));+ "%ld", (long)archive_entry_rdevmajor(file->entry)); if (r < 0) return (ARCHIVE_FATAL); r = xmlwrite_fstring(a, writer, "minor",- "%d", archive_entry_rdevminor(file->entry));+ "%ld", (long)archive_entry_rdevminor(file->entry)); if (r < 0) return (ARCHIVE_FATAL); r = xml_writer_end_element(writer);@@ -1361,7 +1395,7 @@ return (ARCHIVE_FATAL); if (archive_entry_dev(file->entry) != 0) { r = xmlwrite_fstring(a, writer, "deviceno",- "%d", archive_entry_dev(file->entry));+ "%ld", (long)archive_entry_dev(file->entry)); if (r < 0) return (ARCHIVE_FATAL); }@@ -1572,7 +1606,7 @@ static int make_toc(struct archive_write *a) {- struct xar *xar;+ struct xar *xar = a->format_data; struct file *np; struct xml_writer *writer; const char* content;@@ -1580,8 +1614,6 @@ int algsize; int r, ret; - xar = (struct xar *)a->format_data;- ret = ARCHIVE_FATAL; /*@@ -1822,11 +1854,10 @@ static int flush_wbuff(struct archive_write *a) {- struct xar *xar;+ struct xar *xar = a->format_data; int r; size_t s; - xar = (struct xar *)a->format_data; s = sizeof(xar->wbuff) - xar->wbuff_remaining; r = __archive_write_output(a, xar->wbuff, s); if (r != ARCHIVE_OK)@@ -1838,10 +1869,9 @@ static int copy_out(struct archive_write *a, uint64_t offset, uint64_t length) {- struct xar *xar;+ struct xar *xar = a->format_data; int r; - xar = (struct xar *)a->format_data; if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) { archive_set_error(&(a->archive), errno, "lseek failed"); return (ARCHIVE_FATAL);@@ -1883,13 +1913,11 @@ static int xar_close(struct archive_write *a) {- struct xar *xar;+ struct xar *xar = a->format_data; unsigned char *wb; uint64_t length; int r; - xar = (struct xar *)a->format_data;- /* Empty! */ if (xar->root->children.first == NULL) return (ARCHIVE_OK);@@ -1949,9 +1977,7 @@ static int xar_free(struct archive_write *a) {- struct xar *xar;-- xar = (struct xar *)a->format_data;+ struct xar *xar = a->format_data; /* Close the temporary file. */ if (xar->temp_fd >= 0)@@ -2109,13 +2135,12 @@ static int file_gen_utility_names(struct archive_write *a, struct file *file) {- struct xar *xar;+ struct xar *xar = a->format_data; const char *pp; char *p, *dirname, *slash; size_t len; int r = ARCHIVE_OK; - xar = (struct xar *)a->format_data; archive_string_empty(&(file->parentdir)); archive_string_empty(&(file->basename)); archive_string_empty(&(file->symlink));@@ -2303,6 +2328,7 @@ static int file_tree(struct archive_write *a, struct file **filepp) {+ struct xar *xar = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -2310,7 +2336,6 @@ #else char name[256]; #endif- struct xar *xar = (struct xar *)a->format_data; struct file *dent, *file, *np; struct archive_entry *ent; const char *fn, *p;@@ -2414,8 +2439,12 @@ return (ARCHIVE_FATAL); } archive_string_free(&as);- if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)+ if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED) {+ file_free(vp);+ file_free(file);+ *filepp = NULL; return (ARCHIVE_FATAL);+ } file_add_child_tail(dent, vp); file_register(xar, vp); np = vp;@@ -2526,7 +2555,7 @@ static int file_register_hardlink(struct archive_write *a, struct file *file) {- struct xar *xar = (struct xar *)a->format_data;+ struct xar *xar = a->format_data; struct hardlink *hl; const char *pathname; @@ -2648,6 +2677,16 @@ case CKSUM_MD5: archive_md5_init(&(sumwrk->md5ctx)); break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_init(&(sumwrk->sha256ctx));+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_init(&(sumwrk->sha512ctx));+ break;+#endif } } @@ -2664,6 +2703,16 @@ case CKSUM_MD5: archive_md5_update(&(sumwrk->md5ctx), buff, size); break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_update(&(sumwrk->sha256ctx), buff, size);+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_update(&(sumwrk->sha512ctx), buff, size);+ break;+#endif } } @@ -2683,6 +2732,18 @@ archive_md5_final(&(sumwrk->md5ctx), sumval->val); sumval->len = MD5_SIZE; break;+#ifdef ARCHIVE_HAS_SHA256+ case CKSUM_SHA256:+ archive_sha256_final(&(sumwrk->sha256ctx), sumval->val);+ sumval->len = SHA256_SIZE;+ break;+#endif+#ifdef ARCHIVE_HAS_SHA512+ case CKSUM_SHA512:+ archive_sha512_final(&(sumwrk->sha512ctx), sumval->val);+ sumval->len = SHA512_SIZE;+ break;+#endif } sumval->alg = sumwrk->alg; }@@ -3132,10 +3193,9 @@ static int xar_compression_init_encoder(struct archive_write *a) {- struct xar *xar;+ struct xar *xar = a->format_data; int r; - xar = (struct xar *)a->format_data; switch (xar->opt_compression) { case GZIP: r = compression_init_encoder_gzip(@@ -3192,14 +3252,13 @@ static int save_xattrs(struct archive_write *a, struct file *file) {- struct xar *xar;+ struct xar *xar = a->format_data; const char *name; const void *value; struct heap_data *heap; size_t size; int count, r; - xar = (struct xar *)a->format_data; count = archive_entry_xattr_reset(file->entry); if (count == 0) return (ARCHIVE_OK);@@ -3211,6 +3270,12 @@ heap = calloc(1, sizeof(*heap)); if (heap == NULL) {+ struct chksumval sumval;++ checksum_final(&(xar->a_sumwrk), &sumval);+ checksum_final(&(xar->e_sumwrk), &sumval);+ xar->a_sumwrk.alg = CKSUM_NONE;+ xar->e_sumwrk.alg = CKSUM_NONE; archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for xattr"); return (ARCHIVE_FATAL);@@ -3248,6 +3313,10 @@ */ r = xar_compression_init_encoder(a); if (r != ARCHIVE_OK) {+ struct chksumval sumval;++ checksum_final(&(xar->a_sumwrk), &sumval);+ xar->a_sumwrk.alg = CKSUM_NONE; free(heap); return (ARCHIVE_FATAL); }@@ -3302,6 +3371,10 @@ return (SHA1_SIZE); case CKSUM_MD5: return (MD5_SIZE);+ case CKSUM_SHA256:+ return (SHA256_SIZE);+ case CKSUM_SHA512:+ return (SHA512_SIZE); } } @@ -3316,6 +3389,10 @@ return (SHA1_NAME); case CKSUM_MD5: return (MD5_NAME);+ case CKSUM_SHA256:+ return (SHA256_NAME);+ case CKSUM_SHA512:+ return (SHA512_NAME); } }
c/archive_write_set_format_zip.c view
@@ -68,6 +68,7 @@ #include "archive_entry.h" #include "archive_entry_locale.h" #include "archive_hmac_private.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_random_private.h" #include "archive_time_private.h"@@ -154,7 +155,6 @@ enum compression entry_compression; enum encryption entry_encryption; int entry_flags;- int experiments; struct trad_enc_ctx tctx; char tctx_valid; unsigned char trad_chkdat;@@ -235,7 +235,6 @@ struct archive_entry *); static int archive_write_zip_options(struct archive_write *, const char *, const char *);-static size_t path_length(struct archive_entry *); static int write_path(struct archive_entry *, struct archive_write *); static void copy_path(struct archive_entry *, unsigned char *); static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);@@ -730,8 +729,7 @@ ARCHIVE_STATE_NEW, "archive_write_set_format_zip"); /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);+ (void)__archive_write_unregister_format(a); zip = calloc(1, sizeof(*zip)); if (zip == NULL) {@@ -791,9 +789,9 @@ static int archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) {+ struct zip *zip = a->format_data; unsigned char local_header[32]; unsigned char local_extra[144];- struct zip *zip = a->format_data; unsigned char *e; unsigned char *cd_extra; size_t filename_length;@@ -959,8 +957,6 @@ #endif } }- filename_length = path_length(zip->entry);- /* Reject empty or overlong pathnames */ path = archive_entry_pathname(zip->entry); if (path == NULL || path[0] == '\0') {@@ -968,6 +964,10 @@ "ZIP format requires a non-empty pathname"); return (ARCHIVE_FAILED); }+ filename_length = strlen(path);+ /* Include the trailing slash added to directories. */+ if (type == AE_IFDIR && path[filename_length - 1] != '/')+ filename_length++; if (filename_length > 0xffff) { archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long for ZIP format");@@ -1066,8 +1066,13 @@ default: break; }- if (zip->entry_compression == COMPRESSION_STORE)- zip->entry_compressed_size += additional_size;+ if (zip->entry_compression == COMPRESSION_STORE &&+ archive_ckd_add_i64(&zip->entry_compressed_size,+ zip->entry_compressed_size, additional_size)) {+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+ "File size too large for encrypted ZIP entry");+ return (ARCHIVE_FAILED);+ } } /*@@ -1081,7 +1086,7 @@ * (compression might make file larger) */ if ((zip->flags & ZIP_FLAG_FORCE_ZIP64)- || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX)+ || (zip->entry_uncompressed_size > ZIP_4GB_MAX - additional_size) || (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED && zip->entry_compression != COMPRESSION_STORE)) { MIN_VERSION_NEEDED(45);@@ -1515,8 +1520,8 @@ static ssize_t archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) {- int ret; struct zip *zip = a->format_data;+ int ret; if ((int64_t)s > zip->entry_uncompressed_limit) s = (size_t)zip->entry_uncompressed_limit;@@ -2184,9 +2189,9 @@ static int archive_write_zip_close(struct archive_write *a) {+ struct zip *zip = a->format_data; uint8_t buff[64]; int64_t offset_start, offset_end;- struct zip *zip = a->format_data; struct cd_segment *segment; int ret; @@ -2256,10 +2261,9 @@ static int archive_write_zip_free(struct archive_write *a) {- struct zip *zip;+ struct zip *zip = a->format_data; struct cd_segment *segment; - zip = a->format_data; while (zip->central_directory != NULL) { segment = zip->central_directory; zip->central_directory = segment->next;@@ -2277,24 +2281,6 @@ free(zip); a->format_data = NULL; return (ARCHIVE_OK);-}--static size_t-path_length(struct archive_entry *entry)-{- mode_t type;- const char *path;- size_t len;-- type = archive_entry_filetype(entry);- path = archive_entry_pathname(entry);-- if (path == NULL)- return (0);- len = strlen(path);- if (type == AE_IFDIR && (path[0] == '\0' || path[len - 1] != '/'))- ++len; /* Space for the trailing / */- return len; } static int
libarchive-clib.cabal view
@@ -2,7 +2,7 @@ name: libarchive-clib -- this is actually corresponding to upstream's 3.8.6, -- but we had to fix configure.ac and PVP has no patch versions-version: 3.8.8+version: 3.8.9 license: BSD-2-Clause license-file: LICENSE copyright: Copyright: (c) 2018-2020 Vanessa McHale