From 83c0cc06002d9c3ae15c03bd1d4c2b1df399f1e1 Mon Sep 17 00:00:00 2001 From: Jonathan Dieter Date: Wed, 30 May 2018 14:01:35 +0300 Subject: [PATCH] Add support for specifying header information before reading file Signed-off-by: Jonathan Dieter --- include/zck.h | 7 ++-- src/lib/comp/comp.c | 17 ++++----- src/lib/zck.c | 82 +++++++++++++++++++++++++++++++++++-------- src/lib/zck_private.h | 3 +- src/zck.c | 4 +-- 5 files changed, 82 insertions(+), 31 deletions(-) diff --git a/include/zck.h b/include/zck.h index fffacf3..af70e4f 100644 --- a/include/zck.h +++ b/include/zck.h @@ -24,12 +24,14 @@ typedef enum zck_comp { typedef enum zck_ioption { ZCK_HASH_FULL_TYPE = 0, /* Set full file hash type, using zck_hash */ ZCK_HASH_CHUNK_TYPE, /* Set chunk hash type using zck_hash */ + ZCK_VAL_HEADER_HASH_TYPE, /* Set what the header hash type *should* be */ + ZCK_VAL_HEADER_LENGTH, /* Set what the header length *should* be */ ZCK_COMP_TYPE = 100, /* Set compression type using zck_comp */ - ZCK_COMP_DICT_SIZE, /* Set compression dictionary size */ ZCK_ZSTD_COMP_LEVEL = 1000 /* Set zstd compression level */ } zck_ioption; typedef enum zck_soption { + ZCK_VAL_HEADER_DIGEST = 0, /* Set what the header hash *should* be */ ZCK_COMP_DICT = 100 /* Set compression dictionary */ } zck_soption; @@ -108,7 +110,8 @@ void zck_free(zckCtx **zck); * Options *******************************************************************/ /* Set string option */ -int zck_set_soption(zckCtx *zck, zck_soption option, const void *value) +int zck_set_soption(zckCtx *zck, zck_soption option, const void *value, + size_t length) __attribute__ ((warn_unused_result)); /* Set integer option */ int zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) diff --git a/src/lib/comp/comp.c b/src/lib/comp/comp.c index cb04566..1277bb1 100644 --- a/src/lib/comp/comp.c +++ b/src/lib/comp/comp.c @@ -224,8 +224,6 @@ int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value) { } if(option == ZCK_COMP_TYPE) { return set_comp_type(zck, value); - } else if(option == ZCK_COMP_DICT_SIZE) { - zck->comp.dict_size = value; } else { if(zck && zck->comp.set_parameter) return zck->comp.set_parameter(&(zck->comp), option, &value); @@ -237,7 +235,8 @@ int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value) { return True; } -int comp_soption(zckCtx *zck, zck_soption option, const void *value) { +int comp_soption(zckCtx *zck, zck_soption option, const void *value, + size_t length) { VALIDATE(zck); /* Cannot change compression parameters after compression has started */ @@ -247,19 +246,15 @@ int comp_soption(zckCtx *zck, zck_soption option, const void *value) { return False; } if(option == ZCK_COMP_DICT) { - if(zck->comp.dict_size == 0) { - zck_log(ZCK_LOG_ERROR, - "Dict size must be set before adding dict\n"); - return False; - } - char *dict = zmalloc(zck->comp.dict_size); + char *dict = zmalloc(length); if(dict == NULL) { zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", - zck->comp.dict_size); + length); return False; } - memcpy(dict, value, zck->comp.dict_size); + memcpy(dict, value, length); zck->comp.dict = dict; + zck->comp.dict_size = length; } else { if(zck && zck->comp.set_parameter) return zck->comp.set_parameter(&(zck->comp), option, value); diff --git a/src/lib/zck.c b/src/lib/zck.c index 2f078e9..a9cec56 100644 --- a/src/lib/zck.c +++ b/src/lib/zck.c @@ -47,13 +47,50 @@ return False; \ } +#define VALIDATE_WRITE(f) VALIDATE(f); \ + if(f->mode != ZCK_MODE_WRITE) { \ + zck_log(ZCK_LOG_ERROR, \ + "zckCtx not opened for writing\n"); \ + return False; \ + } + int PUBLIC zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) { /* Set hash type */ if(option == ZCK_HASH_FULL_TYPE) { + VALIDATE_WRITE(zck); return set_full_hash_type(zck, value); } else if(option == ZCK_HASH_CHUNK_TYPE) { + VALIDATE_WRITE(zck); return set_chunk_hash_type(zck, value); + /* Validation options */ + } else if(option == ZCK_VAL_HEADER_HASH_TYPE) { + VALIDATE_READ(zck); + if(value < 0) { + zck_log(ZCK_LOG_ERROR, + "Header hash type can't be less than zero: %li\n", + value); + return False; + } + /* Make sure that header hash type is set before the header digest, + * otherwise we run the risk of a buffer overflow */ + if(zck->prep_digest != NULL) { + zck_log(ZCK_LOG_ERROR, + "For validation, you must set the header hash type " + "*before* the header digest itself\n"); + return False; + } + zck->prep_hash_type = value; + } else if(option == ZCK_VAL_HEADER_LENGTH) { + VALIDATE_READ(zck); + if(value < 0) { + zck_log(ZCK_LOG_ERROR, + "Header size validation can't be less than zero: %li\n", + value); + return False; + } + zck->prep_hdr_size = value; + /* Hash options */ } else if(option < 100) { /* Currently no hash options other than setting hash type, so bail */ @@ -62,31 +99,51 @@ int PUBLIC zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) { /* Compression options */ } else if(option < 2000) { + VALIDATE_WRITE(zck); return comp_ioption(zck, option, value); /* Unknown options */ } else { - zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value); + zck_log(ZCK_LOG_ERROR, "Unknown integer option %i\n", option); return False; } + return True; } -int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const void *value) { - /* Hash options */ - if(option < 100) { - /* Currently no hash options other than setting hash type, so bail */ - zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value); - return False; +int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const void *value, + size_t length) { + /* Validation options */ + if(option == ZCK_VAL_HEADER_DIGEST) { + VALIDATE_READ(zck); + zckHashType chk_type = {0}; + if(zck->prep_hash_type < 0) { + zck_log(ZCK_LOG_ERROR, + "For validation, you must set the header hash type " + "*before* the header digest itself\n"); + return False; + } + if(!zck_hash_setup(&chk_type, zck->prep_hash_type)) + return False; + if(chk_type.digest_size != length) { + zck_log(ZCK_LOG_ERROR, "Hash digest size mismatch for header " + "validation\n" + "Expected: %lu\nProvided: %lu\n", chk_type.digest_size, + length); + return False; + } + zck->prep_digest = zmalloc(length); + memcpy(zck->prep_digest, value, length); /* Compression options */ } else if(option < 2000) { - return comp_soption(zck, option, value); + return comp_soption(zck, option, value, length); /* Unknown options */ } else { - zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value); + zck_log(ZCK_LOG_ERROR, "Unknown string option %i\n", option); return False; } + return True; } int PUBLIC zck_close(zckCtx *zck) { VALIDATE(zck); @@ -345,15 +402,12 @@ int zck_import_dict(zckCtx *zck) { zck_log(ZCK_LOG_DEBUG, "Resetting compression\n"); if(!zck_comp_reset(zck)) return False; - zck_log(ZCK_LOG_DEBUG, "Setting dict size\n"); - if(!zck_set_ioption(zck, ZCK_COMP_DICT_SIZE, size)) - return False; zck_log(ZCK_LOG_DEBUG, "Setting dict\n"); - if(!zck_set_soption(zck, ZCK_COMP_DICT, data)) + if(!zck_set_soption(zck, ZCK_COMP_DICT, data, size)) return False; + free(data); if(!zck_comp_init(zck)) return False; - free(data); return True; } diff --git a/src/lib/zck_private.h b/src/lib/zck_private.h index 725ff10..a29a9be 100644 --- a/src/lib/zck_private.h +++ b/src/lib/zck_private.h @@ -261,7 +261,8 @@ ssize_t comp_read(zckCtx *zck, char *dst, size_t dst_size, int use_dict) __attribute__ ((warn_unused_result)); int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value) __attribute__ ((warn_unused_result)); -int comp_soption(zckCtx *zck, zck_soption option, const void *value) +int comp_soption(zckCtx *zck, zck_soption option, const void *value, + size_t length) __attribute__ ((warn_unused_result)); /* dl/range.c */ diff --git a/src/zck.c b/src/zck.c index aad3722..a3a688d 100644 --- a/src/zck.c +++ b/src/zck.c @@ -173,9 +173,7 @@ int main (int argc, char *argv[]) { exit(1); }*/ if(dict_size > 0) { - if(!zck_set_ioption(zck, ZCK_COMP_DICT_SIZE, dict_size)) - exit(1); - if(!zck_set_soption(zck, ZCK_COMP_DICT, dict)) + if(!zck_set_soption(zck, ZCK_COMP_DICT, dict, dict_size)) exit(1); } free(dict); -- 2.30.2