From cccbf646c3151ffeb9b34faae9b9a7f0b77eb559 Mon Sep 17 00:00:00 2001 From: Jonathan Dieter Date: Wed, 6 Jun 2018 11:36:18 +0300 Subject: [PATCH] Move functions out of zck.h to more appropriate files Signed-off-by: Jonathan Dieter --- src/lib/hash/hash.c | 250 ++++++++++++++++- src/lib/header.c | 23 ++ src/lib/index/index_read.c | 12 + src/lib/zck.c | 561 ++++++++++--------------------------- src/lib/zck_private.h | 23 +- 5 files changed, 442 insertions(+), 427 deletions(-) diff --git a/src/lib/hash/hash.c b/src/lib/hash/hash.c index 61d0213..29f5560 100644 --- a/src/lib/hash/hash.c +++ b/src/lib/hash/hash.c @@ -39,6 +39,27 @@ return False; \ } +#define VALIDATE_READ(f) VALIDATE(f); \ + if(f->mode != ZCK_MODE_READ) { \ + zck_log(ZCK_LOG_ERROR, \ + "zckCtx not opened for reading\n"); \ + 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; \ + } +/* This needs to be updated to the largest hash size every time a new hash type + * is added */ +int get_max_hash_size() { + return SHA256_DIGEST_SIZE; +} + + + static char unknown[] = "Unknown(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; const static char *HASH_NAME[] = { @@ -46,10 +67,83 @@ const static char *HASH_NAME[] = { "SHA-256" }; -/* This needs to be updated to the largest hash size every time a new hash type - * is added */ -int get_max_hash_size() { - return SHA256_DIGEST_SIZE; +static int validate_checksums(zckCtx *zck, zck_log_type bad_checksums) { + VALIDATE_READ(zck); + char buf[BUF_SIZE]; + + if(zck->data_offset == 0) { + zck_log(ZCK_LOG_ERROR, "Header hasn't been read yet\n"); + return 0; + } + + hash_close(&(zck->check_full_hash)); + if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) + return 0; + + if(!seek_data(zck->fd, zck->data_offset, SEEK_SET)) + return 0; + + /* Check each chunk checksum */ + int all_good = True; + for(zckIndexItem *idx = zck->index.first; idx; idx = idx->next) { + if(idx == zck->index.first && idx->length == 0) { + idx->valid = 1; + continue; + } + + if(!hash_init(&(zck->check_chunk_hash), &(zck->chunk_hash_type))) + return 0; + + size_t rlen = 0; + while(rlen < idx->comp_length) { + size_t rsize = BUF_SIZE; + if(BUF_SIZE > idx->comp_length - rlen) + rsize = idx->comp_length - rlen; + if(read_data(zck->fd, buf, rsize) != rsize) + zck_log(ZCK_LOG_DEBUG, "No more data\n"); + if(!hash_update(&(zck->check_chunk_hash), buf, rsize)) + return 0; + if(!hash_update(&(zck->check_full_hash), buf, rsize)) + return 0; + rlen += rsize; + } + int valid_chunk = validate_chunk(zck, idx, bad_checksums); + if(!valid_chunk) + return 0; + idx->valid = valid_chunk; + if(all_good && valid_chunk != 1) + all_good = False; + } + int valid_file = -1; + if(all_good) { + /* Check data checksum */ + valid_file = validate_file(zck, bad_checksums); + if(!valid_file) + return 0; + + /* If data checksum failed, invalidate *all* chunks */ + if(valid_file == -1) + for(zckIndexItem *idx = zck->index.first; idx; idx = idx->next) + idx->valid = -1; + } + + /* Go back to beginning of data section */ + if(!seek_data(zck->fd, zck->data_offset, SEEK_SET)) + return 0; + + /* Reinitialize data checksum */ + if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) + return 0; + + return valid_file; +} + +char *get_digest_string(const char *digest, int size) { + char *str = zmalloc(size*2+1); + + for(int i=0; icheck_chunk_hash)); + if(digest == NULL) { + zck_log(ZCK_LOG_ERROR, + "Unable to calculate %s checksum for chunk\n"); + return 0; + } + if(idx->comp_length == 0) + memset(digest, 0, idx->digest_size); + zck_log(ZCK_LOG_DEBUG, "Checking chunk checksum\n"); + char *pdigest = zck_get_chunk_digest(idx); + zck_log(ZCK_LOG_DEBUG, "Expected chunk checksum: %s\n", pdigest); + free(pdigest); + pdigest = get_digest_string(digest, idx->digest_size); + zck_log(ZCK_LOG_DEBUG, "Calculated chunk checksum: %s\n", pdigest); + free(pdigest); + if(memcmp(digest, idx->digest, idx->digest_size) != 0) { + free(digest); + zck_log(bad_checksum, "Chunk checksum failed!\n"); + return -1; + } + zck_log(ZCK_LOG_DEBUG, "Chunk checksum valid\n"); + free(digest); + return 1; +} + +int validate_current_chunk(zckCtx *zck) { + VALIDATE(zck); + + return validate_chunk(zck, zck->comp.data_idx, ZCK_LOG_ERROR); +} + +int validate_file(zckCtx *zck, zck_log_type bad_checksums) { + VALIDATE(zck); + char *digest = hash_finalize(&(zck->check_full_hash)); + if(digest == NULL) { + zck_log(ZCK_LOG_ERROR, + "Unable to calculate %s checksum for full file\n"); + return 0; + } + zck_log(ZCK_LOG_DEBUG, "Checking data checksum\n"); + char *cks = get_digest_string(zck->full_hash_digest, + zck->hash_type.digest_size); + zck_log(ZCK_LOG_DEBUG, "Expected data checksum: %s\n", cks); + free(cks); + cks = get_digest_string(digest, zck->hash_type.digest_size); + zck_log(ZCK_LOG_DEBUG, "Calculated data checksum: %s\n", cks); + free(cks); + if(memcmp(digest, zck->full_hash_digest, zck->hash_type.digest_size) != 0) { + free(digest); + zck_log(bad_checksums, "Data checksum failed!\n"); + return -1; + } + zck_log(ZCK_LOG_DEBUG, "Data checksum valid\n"); + free(digest); + return 1; +} + +int validate_header(zckCtx *zck) { + VALIDATE(zck); + char *digest = hash_finalize(&(zck->check_full_hash)); + if(digest == NULL) { + zck_log(ZCK_LOG_ERROR, + "Unable to calculate %s checksum for header\n"); + return 0; + } + zck_log(ZCK_LOG_DEBUG, "Checking header checksum\n"); + char *cks = get_digest_string(zck->header_digest, + zck->hash_type.digest_size); + zck_log(ZCK_LOG_DEBUG, "Expected header checksum: %s\n", cks); + free(cks); + cks = get_digest_string(digest, zck->hash_type.digest_size); + zck_log(ZCK_LOG_DEBUG, "Calculated header checksum: %s\n", cks); + free(cks); + if(memcmp(digest, zck->header_digest, zck->hash_type.digest_size) != 0) { + free(digest); + zck_log(ZCK_LOG_ERROR, "Header checksum failed!\n"); + return -1; + } + zck_log(ZCK_LOG_DEBUG, "Header checksum valid\n"); + free(digest); + + if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) + return 0; + + return 1; +} + /* Returns 1 if data hash matches, -1 if it doesn't and 0 if error */ int PUBLIC zck_validate_data_checksum(zckCtx *zck) { hash_close(&(zck->check_full_hash)); @@ -225,3 +415,55 @@ const char PUBLIC *zck_hash_name_from_type(int hash_type) { } return HASH_NAME[hash_type]; } + +int PUBLIC zck_get_full_hash_type(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->hash_type.type; +} + +ssize_t PUBLIC zck_get_full_digest_size(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->hash_type.digest_size; +} + +int PUBLIC zck_get_chunk_hash_type(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->index.hash_type; +} + +ssize_t PUBLIC zck_get_chunk_digest_size(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->index.digest_size; +} + +char PUBLIC *zck_get_header_digest(zckCtx *zck) { + if(zck == NULL) + return NULL; + return get_digest_string(zck->header_digest, zck->hash_type.digest_size); +} + +char PUBLIC *zck_get_data_digest(zckCtx *zck) { + if(zck == NULL) + return NULL; + return get_digest_string(zck->full_hash_digest, zck->hash_type.digest_size); +} + +char PUBLIC *zck_get_chunk_digest(zckIndexItem *item) { + if(item == NULL) + return NULL; + return get_digest_string(item->digest, item->digest_size); +} + +/* Returns 1 if all chunks are valid, -1 if even one isn't and 0 if error */ +int PUBLIC zck_find_valid_chunks(zckCtx *zck) { + return validate_checksums(zck, ZCK_LOG_DEBUG); +} + +/* Returns 1 if all checksums matched, -1 if even one doesn't and 0 if error */ +int PUBLIC zck_validate_checksums(zckCtx *zck) { + return validate_checksums(zck, ZCK_LOG_WARNING); +} diff --git a/src/lib/header.c b/src/lib/header.c index 485c3b2..c6fda47 100644 --- a/src/lib/header.c +++ b/src/lib/header.c @@ -532,3 +532,26 @@ int PUBLIC zck_read_header(zckCtx *zck) { return False; return True; } + +ssize_t PUBLIC zck_get_header_length(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->lead_size + zck->header_length; +} + +ssize_t PUBLIC zck_get_lead_length(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->lead_size; +} + +ssize_t PUBLIC zck_get_data_length(zckCtx *zck) { + zckIndexItem *idx = zck->index.first; + while(idx->next != NULL) + idx = idx->next; + return idx->start + idx->comp_length; +} + +ssize_t PUBLIC zck_get_length(zckCtx *zck) { + return zck_get_header_length(zck) + zck_get_data_length(zck); +} diff --git a/src/lib/index/index_read.c b/src/lib/index/index_read.c index e1ea38c..d59524f 100644 --- a/src/lib/index/index_read.c +++ b/src/lib/index/index_read.c @@ -108,6 +108,18 @@ int index_read(zckCtx *zck, char *data, size_t size, size_t max_length) { return True; } +ssize_t PUBLIC zck_get_index_count(zckCtx *zck) { + if(zck == NULL) + return -1; + return zck->index.count; +} + +zckIndex PUBLIC *zck_get_index(zckCtx *zck) { + if(zck == NULL) + return NULL; + return &(zck->index); +} + int PUBLIC zck_missing_chunks(zckCtx *zck) { if(zck == NULL) { zck_log(ZCK_LOG_ERROR, "zckCtx not initialized\n"); diff --git a/src/lib/zck.c b/src/lib/zck.c index 515d652..ff204a4 100644 --- a/src/lib/zck.c +++ b/src/lib/zck.c @@ -60,63 +60,38 @@ int PUBLIC zck_get_min_download_size() { return 5 + MAX_COMP_SIZE*2 + get_max_hash_size(); } -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 */ - zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value); - return False; - - /* Compression options */ - } else if(option < 2000) { - VALIDATE_WRITE(zck); - return comp_ioption(zck, option, value); - /* Unknown options */ - } else { - zck_log(ZCK_LOG_ERROR, "Unknown integer option %i\n", option); - return False; +static void zck_clear(zckCtx *zck) { + if(zck == NULL) + return; + index_free(zck); + if(zck->header) + free(zck->header); + zck->fd = -1; + zck->header = NULL; + zck->header_size = 0; + if(!comp_close(zck)) + zck_log(ZCK_LOG_WARNING, "Unable to close compression\n"); + hash_close(&(zck->full_hash)); + hash_close(&(zck->check_full_hash)); + hash_close(&(zck->check_chunk_hash)); + clear_work_index(zck); + if(zck->full_hash_digest) { + free(zck->full_hash_digest); + zck->full_hash_digest = NULL; + } + if(zck->header_digest) { + free(zck->header_digest); + zck->header_digest = NULL; + } + if(zck->temp_fd) { + close(zck->temp_fd); + zck->temp_fd = 0; } - return True; } -int hex_to_int (char c) { +static int hex_to_int (char c) { if (c >= 97) c = c - 32; int result = (c / 16 - 3) * 10 + (c % 16); @@ -125,7 +100,7 @@ int hex_to_int (char c) { return result; } -char *ascii_checksum_to_bin (char *checksum) { +static char *ascii_checksum_to_bin (char *checksum) { int cl = strlen(checksum); char *raw_checksum = zmalloc(cl/2); if(raw_checksum == NULL) { @@ -145,6 +120,72 @@ char *ascii_checksum_to_bin (char *checksum) { return raw_checksum; } +int get_tmp_fd() { + int temp_fd; + char *fname = NULL; + char template[] = "zcktempXXXXXX"; + char *tmpdir = getenv("TMPDIR"); + + if(tmpdir == NULL) { + tmpdir = "/tmp/"; + } + fname = zmalloc(strlen(template) + strlen(tmpdir) + 2); + if(fname == NULL) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", + strlen(template) + strlen(tmpdir) + 2); + return -1; + } + strncpy(fname, tmpdir, strlen(tmpdir)); + strncpy(fname+strlen(tmpdir), "/", 2); + strncpy(fname+strlen(tmpdir)+1, template, strlen(template)); + + temp_fd = mkstemp(fname); + if(temp_fd < 0) { + free(fname); + zck_log(ZCK_LOG_ERROR, "Unable to create temporary file\n"); + return -1; + } + if(unlink(fname) < 0) { + free(fname); + zck_log(ZCK_LOG_ERROR, "Unable to delete temporary file\n"); + return -1; + } + free(fname); + return temp_fd; +} + +int import_dict(zckCtx *zck) { + VALIDATE(zck); + + size_t size = zck->index.first->length; + + /* No dict */ + if(size == 0) + return True; + + zck_log(ZCK_LOG_DEBUG, "Reading compression dict\n"); + char *data = zmalloc(size); + if(data == NULL) { + zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", size); + return False; + } + if(comp_read(zck, data, size, 0) != size) { + zck_log(ZCK_LOG_ERROR, "Error reading compressed dict\n"); + return False; + } + zck_log(ZCK_LOG_DEBUG, "Resetting compression\n"); + if(!comp_reset(zck)) + return False; + zck_log(ZCK_LOG_DEBUG, "Setting dict\n"); + if(!comp_soption(zck, ZCK_COMP_DICT, data, size)) + return False; + if(!comp_init(zck)) + return False; + free(data); + + return True; +} + int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const char *value, size_t length) { char *data = zmalloc(length); @@ -193,6 +234,63 @@ int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const char *value, } return True; } + +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 */ + zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value); + return False; + + /* Compression options */ + } else if(option < 2000) { + VALIDATE_WRITE(zck); + return comp_ioption(zck, option, value); + + /* Unknown options */ + } else { + zck_log(ZCK_LOG_ERROR, "Unknown integer option %i\n", option); + return False; + } + return True; +} + int PUBLIC zck_close(zckCtx *zck) { VALIDATE(zck); @@ -221,35 +319,6 @@ int PUBLIC zck_close(zckCtx *zck) { return True; } -void zck_clear(zckCtx *zck) { - if(zck == NULL) - return; - index_free(zck); - if(zck->header) - free(zck->header); - zck->fd = -1; - zck->header = NULL; - zck->header_size = 0; - if(!comp_close(zck)) - zck_log(ZCK_LOG_WARNING, "Unable to close compression\n"); - hash_close(&(zck->full_hash)); - hash_close(&(zck->check_full_hash)); - hash_close(&(zck->check_chunk_hash)); - clear_work_index(zck); - if(zck->full_hash_digest) { - free(zck->full_hash_digest); - zck->full_hash_digest = NULL; - } - if(zck->header_digest) { - free(zck->header_digest); - zck->header_digest = NULL; - } - if(zck->temp_fd) { - close(zck->temp_fd); - zck->temp_fd = 0; - } -} - void PUBLIC zck_free(zckCtx **zck) { if(*zck == NULL) return; @@ -327,334 +396,6 @@ iw_error: return NULL; } -int PUBLIC zck_get_full_hash_type(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->hash_type.type; -} - -ssize_t PUBLIC zck_get_full_digest_size(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->hash_type.digest_size; -} - -int PUBLIC zck_get_chunk_hash_type(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->index.hash_type; -} - -ssize_t PUBLIC zck_get_chunk_digest_size(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->index.digest_size; -} - -ssize_t PUBLIC zck_get_index_count(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->index.count; -} - -zckIndex PUBLIC *zck_get_index(zckCtx *zck) { - if(zck == NULL) - return NULL; - return &(zck->index); -} - -char *get_digest_string(const char *digest, int size) { - char *str = zmalloc(size*2+1); - - for(int i=0; iheader_digest, zck->hash_type.digest_size); -} - -char PUBLIC *zck_get_data_digest(zckCtx *zck) { - if(zck == NULL) - return NULL; - return get_digest_string(zck->full_hash_digest, zck->hash_type.digest_size); -} - -char PUBLIC *zck_get_chunk_digest(zckIndexItem *item) { - if(item == NULL) - return NULL; - return get_digest_string(item->digest, item->digest_size); -} - -ssize_t PUBLIC zck_get_header_length(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->lead_size + zck->header_length; -} - -ssize_t PUBLIC zck_get_lead_length(zckCtx *zck) { - if(zck == NULL) - return -1; - return zck->lead_size; -} - -ssize_t PUBLIC zck_get_data_length(zckCtx *zck) { - zckIndexItem *idx = zck->index.first; - while(idx->next != NULL) - idx = idx->next; - return idx->start + idx->comp_length; -} - -ssize_t PUBLIC zck_get_length(zckCtx *zck) { - return zck_get_header_length(zck) + zck_get_data_length(zck); -} - -int get_tmp_fd() { - int temp_fd; - char *fname = NULL; - char template[] = "zcktempXXXXXX"; - char *tmpdir = getenv("TMPDIR"); - - if(tmpdir == NULL) { - tmpdir = "/tmp/"; - } - fname = zmalloc(strlen(template) + strlen(tmpdir) + 2); - if(fname == NULL) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", - strlen(template) + strlen(tmpdir) + 2); - return -1; - } - strncpy(fname, tmpdir, strlen(tmpdir)); - strncpy(fname+strlen(tmpdir), "/", 2); - strncpy(fname+strlen(tmpdir)+1, template, strlen(template)); - - temp_fd = mkstemp(fname); - if(temp_fd < 0) { - free(fname); - zck_log(ZCK_LOG_ERROR, "Unable to create temporary file\n"); - return -1; - } - if(unlink(fname) < 0) { - free(fname); - zck_log(ZCK_LOG_ERROR, "Unable to delete temporary file\n"); - return -1; - } - free(fname); - return temp_fd; -} - -int import_dict(zckCtx *zck) { - VALIDATE(zck); - - size_t size = zck->index.first->length; - - /* No dict */ - if(size == 0) - return True; - - zck_log(ZCK_LOG_DEBUG, "Reading compression dict\n"); - char *data = zmalloc(size); - if(data == NULL) { - zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", size); - return False; - } - if(comp_read(zck, data, size, 0) != size) { - zck_log(ZCK_LOG_ERROR, "Error reading compressed dict\n"); - return False; - } - zck_log(ZCK_LOG_DEBUG, "Resetting compression\n"); - if(!comp_reset(zck)) - return False; - zck_log(ZCK_LOG_DEBUG, "Setting dict\n"); - if(!comp_soption(zck, ZCK_COMP_DICT, data, size)) - return False; - if(!comp_init(zck)) - return False; - free(data); - - return True; -} - -/* Validate chunk, returning -1 if checksum fails, 1 if good, 0 if error */ -int validate_chunk(zckCtx *zck, zckIndexItem *idx, - zck_log_type bad_checksum) { - VALIDATE(zck); - if(idx == NULL) { - zck_log(ZCK_LOG_ERROR, "Index not initialized\n"); - return 0; - } - - char *digest = hash_finalize(&(zck->check_chunk_hash)); - if(digest == NULL) { - zck_log(ZCK_LOG_ERROR, - "Unable to calculate %s checksum for chunk\n"); - return 0; - } - if(idx->comp_length == 0) - memset(digest, 0, idx->digest_size); - zck_log(ZCK_LOG_DEBUG, "Checking chunk checksum\n"); - char *pdigest = zck_get_chunk_digest(idx); - zck_log(ZCK_LOG_DEBUG, "Expected chunk checksum: %s\n", pdigest); - free(pdigest); - pdigest = get_digest_string(digest, idx->digest_size); - zck_log(ZCK_LOG_DEBUG, "Calculated chunk checksum: %s\n", pdigest); - free(pdigest); - if(memcmp(digest, idx->digest, idx->digest_size) != 0) { - free(digest); - zck_log(bad_checksum, "Chunk checksum failed!\n"); - return -1; - } - zck_log(ZCK_LOG_DEBUG, "Chunk checksum valid\n"); - free(digest); - return 1; -} - -int validate_current_chunk(zckCtx *zck) { - VALIDATE(zck); - - return validate_chunk(zck, zck->comp.data_idx, ZCK_LOG_ERROR); -} - -int validate_file(zckCtx *zck, zck_log_type bad_checksums) { - VALIDATE(zck); - char *digest = hash_finalize(&(zck->check_full_hash)); - if(digest == NULL) { - zck_log(ZCK_LOG_ERROR, - "Unable to calculate %s checksum for full file\n"); - return 0; - } - zck_log(ZCK_LOG_DEBUG, "Checking data checksum\n"); - char *cks = get_digest_string(zck->full_hash_digest, - zck->hash_type.digest_size); - zck_log(ZCK_LOG_DEBUG, "Expected data checksum: %s\n", cks); - free(cks); - cks = get_digest_string(digest, zck->hash_type.digest_size); - zck_log(ZCK_LOG_DEBUG, "Calculated data checksum: %s\n", cks); - free(cks); - if(memcmp(digest, zck->full_hash_digest, zck->hash_type.digest_size) != 0) { - free(digest); - zck_log(bad_checksums, "Data checksum failed!\n"); - return -1; - } - zck_log(ZCK_LOG_DEBUG, "Data checksum valid\n"); - free(digest); - return 1; -} - -int validate_header(zckCtx *zck) { - VALIDATE(zck); - char *digest = hash_finalize(&(zck->check_full_hash)); - if(digest == NULL) { - zck_log(ZCK_LOG_ERROR, - "Unable to calculate %s checksum for header\n"); - return 0; - } - zck_log(ZCK_LOG_DEBUG, "Checking header checksum\n"); - char *cks = get_digest_string(zck->header_digest, - zck->hash_type.digest_size); - zck_log(ZCK_LOG_DEBUG, "Expected header checksum: %s\n", cks); - free(cks); - cks = get_digest_string(digest, zck->hash_type.digest_size); - zck_log(ZCK_LOG_DEBUG, "Calculated header checksum: %s\n", cks); - free(cks); - if(memcmp(digest, zck->header_digest, zck->hash_type.digest_size) != 0) { - free(digest); - zck_log(ZCK_LOG_ERROR, "Header checksum failed!\n"); - return -1; - } - zck_log(ZCK_LOG_DEBUG, "Header checksum valid\n"); - free(digest); - - if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) - return 0; - - return 1; -} - -int validate_checksums(zckCtx *zck, zck_log_type bad_checksums) { - VALIDATE_READ(zck); - char buf[BUF_SIZE]; - - if(zck->data_offset == 0) { - zck_log(ZCK_LOG_ERROR, "Header hasn't been read yet\n"); - return 0; - } - - hash_close(&(zck->check_full_hash)); - if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) - return 0; - - if(!seek_data(zck->fd, zck->data_offset, SEEK_SET)) - return 0; - - /* Check each chunk checksum */ - int all_good = True; - for(zckIndexItem *idx = zck->index.first; idx; idx = idx->next) { - if(idx == zck->index.first && idx->length == 0) { - idx->valid = 1; - continue; - } - - if(!hash_init(&(zck->check_chunk_hash), &(zck->chunk_hash_type))) - return 0; - - size_t rlen = 0; - while(rlen < idx->comp_length) { - size_t rsize = BUF_SIZE; - if(BUF_SIZE > idx->comp_length - rlen) - rsize = idx->comp_length - rlen; - if(read_data(zck->fd, buf, rsize) != rsize) - zck_log(ZCK_LOG_DEBUG, "No more data\n"); - if(!hash_update(&(zck->check_chunk_hash), buf, rsize)) - return 0; - if(!hash_update(&(zck->check_full_hash), buf, rsize)) - return 0; - rlen += rsize; - } - int valid_chunk = validate_chunk(zck, idx, bad_checksums); - if(!valid_chunk) - return 0; - idx->valid = valid_chunk; - if(all_good && valid_chunk != 1) - all_good = False; - } - int valid_file = -1; - if(all_good) { - /* Check data checksum */ - valid_file = validate_file(zck, bad_checksums); - if(!valid_file) - return 0; - - /* If data checksum failed, invalidate *all* chunks */ - if(valid_file == -1) - for(zckIndexItem *idx = zck->index.first; idx; idx = idx->next) - idx->valid = -1; - } - - /* Go back to beginning of data section */ - if(!seek_data(zck->fd, zck->data_offset, SEEK_SET)) - return 0; - - /* Reinitialize data checksum */ - if(!hash_init(&(zck->check_full_hash), &(zck->hash_type))) - return 0; - - return valid_file; -} - -/* Returns 1 if all chunks are valid, -1 if even one isn't and 0 if error */ -int PUBLIC zck_find_valid_chunks(zckCtx *zck) { - return validate_checksums(zck, ZCK_LOG_DEBUG); -} - -/* Returns 1 if all checksums matched, -1 if even one doesn't and 0 if error */ -int PUBLIC zck_validate_checksums(zckCtx *zck) { - return validate_checksums(zck, ZCK_LOG_WARNING); -} - int PUBLIC zck_get_fd(zckCtx *zck) { return zck->fd; } diff --git a/src/lib/zck_private.h b/src/lib/zck_private.h index 4e4c549..fff79b3 100644 --- a/src/lib/zck_private.h +++ b/src/lib/zck_private.h @@ -160,18 +160,7 @@ int get_tmp_fd() __attribute__ ((warn_unused_result)); int import_dict(zckCtx *zck) __attribute__ ((warn_unused_result)); -int validate_chunk(zckCtx *zck, zckIndexItem *idx, zck_log_type bad_checksum) - __attribute__ ((warn_unused_result)); -int validate_file(zckCtx *zck, zck_log_type bad_checksums) - __attribute__ ((warn_unused_result)); -int validate_current_chunk(zckCtx *zck) - __attribute__ ((warn_unused_result)); -int validate_header(zckCtx *zck) - __attribute__ ((warn_unused_result)); -const char *hash_name_from_type(int hash_type) - __attribute__ ((warn_unused_result)); -char *get_digest_string(const char *digest, int size) - __attribute__ ((warn_unused_result)); + /* hash/hash.h */ int hash_setup(zckHashType *ht, int h) @@ -183,7 +172,13 @@ int hash_update(zckHash *hash, const char *message, const size_t size) char *hash_finalize(zckHash *hash) __attribute__ ((warn_unused_result)); void hash_close(zckHash *hash); -const char *zck_hash_get_printable(const char *digest, zckHashType *type) +int validate_chunk(zckCtx *zck, zckIndexItem *idx, zck_log_type bad_checksum) + __attribute__ ((warn_unused_result)); +int validate_file(zckCtx *zck, zck_log_type bad_checksums) + __attribute__ ((warn_unused_result)); +int validate_current_chunk(zckCtx *zck) + __attribute__ ((warn_unused_result)); +int validate_header(zckCtx *zck) __attribute__ ((warn_unused_result)); int set_full_hash_type(zckCtx *zck, int hash_type) __attribute__ ((warn_unused_result)); @@ -191,6 +186,8 @@ int set_chunk_hash_type(zckCtx *zck, int hash_type) __attribute__ ((warn_unused_result)); int get_max_hash_size() __attribute__ ((warn_unused_result)); +char *get_digest_string(const char *digest, int size) + __attribute__ ((warn_unused_result)); /* index/index.c */ -- 2.30.2