}
/* Check whether last downloaded chunk is valid and zero it out if it isn't */
-static int validate_chunk(zckDL *dl) {
+static int set_chunk_valid(zckDL *dl) {
VALIDATE(dl);
VALIDATE(dl->priv);
- if(dl->priv->chunk_hash == NULL) {
- zck_log(ZCK_LOG_ERROR, "Chunk hash not initialized\n");
- return False;
- }
- char *digest = hash_finalize(dl->priv->chunk_hash);
- free(dl->priv->chunk_hash);
- if(memcmp(digest, dl->priv->tgt_check->digest,
- dl->priv->tgt_check->digest_size) != 0) {
- zck_log(ZCK_LOG_WARNING,
- "Downloaded chunk failed hash check\n");
+
+ int retval = validate_chunk(dl->zck, dl->priv->tgt_check, ZCK_LOG_WARNING);
+ if(retval < 1) {
if(!zero_chunk(dl->zck, dl->priv->tgt_check))
return False;
dl->priv->tgt_check->valid = -1;
+ if(retval == 0)
+ return False;
} else {
dl->priv->tgt_check->valid = 1;
}
dl->priv->tgt_check = NULL;
- dl->priv->chunk_hash = NULL;
- free(digest);
return True;
}
if(!write_data(dl->zck->fd, at, wb))
return -1;
dl->priv->write_in_chunk -= wb;
- if(!hash_update(dl->priv->chunk_hash, at, wb))
+ if(!hash_update(&(dl->zck->check_chunk_hash), at, wb))
return -1;
zck_log(ZCK_LOG_DEBUG, "Writing %lu bytes\n", wb);
dl->priv->dl_chunk_data += wb;
return 0;
if(dl->priv->write_in_chunk == 0) {
/* Check whether we just finished downloading a chunk and verify it */
- if(dl->priv->tgt_check && !validate_chunk(dl)) {
- dl->priv->tgt_check->valid = -1;
+ if(dl->priv->tgt_check && !set_chunk_valid(dl))
return False;
- }
- zckIndexItem *idx = dl->range->index.first;
- while(idx) {
+
+ for(zckIndexItem *idx = dl->range->index.first; idx; idx = idx->next) {
if(dl->priv->dl_chunk_data == idx->start) {
- zckIndexItem *tgt_idx = dl->zck->index.first;
- while(tgt_idx) {
+ for(zckIndexItem *tgt_idx = dl->zck->index.first; tgt_idx;
+ tgt_idx = tgt_idx->next) {
if(tgt_idx->valid == 1)
- tgt_idx = tgt_idx->next;
+ continue;
if(idx->comp_length == tgt_idx->comp_length &&
memcmp(idx->digest, tgt_idx->digest,
idx->digest_size) == 0) {
dl->priv->tgt_check = tgt_idx;
- dl->priv->chunk_hash = zmalloc(sizeof(zckHash));
- if(!hash_init(dl->priv->chunk_hash,
+ if(!hash_init(&(dl->zck->check_chunk_hash),
&(dl->zck->chunk_hash_type)))
return 0;
dl->priv->write_in_chunk = idx->comp_length;
return 0;
idx = NULL;
tgt_idx = NULL;
- } else {
- tgt_idx = tgt_idx->next;
+ break;
}
}
}
- if(idx)
- idx = idx->next;
+ if(!idx)
+ break;
}
}
int wb2 = 0;
int set_chunk_hash_type(zckCtx *zck, int hash_type) {
VALIDATE(zck);
memset(&(zck->chunk_hash_type), 0, sizeof(zckHashType));
- zck_log(ZCK_LOG_INFO, "Setting chunk hash to %s\n",
+ zck_log(ZCK_LOG_DEBUG, "Setting chunk hash to %s\n",
zck_hash_name_from_type(hash_type));
if(!hash_setup(&(zck->chunk_hash_type), hash_type)) {
zck_log(ZCK_LOG_ERROR, "Unable to set chunk hash to %s\n",
return True;
}
-/* Returns 1 if data hash matches, 0 if it doesn't and -1 if failure */
+/* 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));
if(!seek_data(zck->fd, zck->data_offset, SEEK_SET))
return -1;
char buf[BUF_SIZE] = {0};
zckIndexItem *idx = zck->index.first;
- zck_log(ZCK_LOG_INFO, "Checking full hash\n");
+ zck_log(ZCK_LOG_DEBUG, "Checking full hash\n");
while(idx) {
size_t to_read = idx->comp_length;
while(to_read > 0) {
}
idx = idx->next;
}
- return validate_file(zck);
+ return validate_file(zck, ZCK_LOG_WARNING);
}
const char PUBLIC *zck_hash_name_from_type(int hash_type) {
return False;
if(!hash_update(&(zck->check_full_hash), header, zck->header_length))
return False;
- if(!validate_header(zck))
+ if(validate_header(zck) < 1)
return False;
return True;
}
zck->temp_fd = 0;
}
} else {
- if(!validate_file(zck))
+ if(validate_file(zck, ZCK_LOG_WARNING) < 1)
return False;
}
index_free(zck);
if(zck->header)
free(zck->header);
+ zck->fd = -1;
zck->header = NULL;
zck->header_size = 0;
if(!comp_close(zck))
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 -1;
+ 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 -1;
+ return 0;
}
if(idx->comp_length == 0)
memset(digest, 0, idx->digest_size);
if(memcmp(digest, idx->digest, idx->digest_size) != 0) {
free(digest);
zck_log(bad_checksum, "Chunk checksum failed!\n");
- return 0;
+ return -1;
}
zck_log(ZCK_LOG_DEBUG, "Chunk checksum valid\n");
free(digest);
return validate_chunk(zck, zck->comp.data_idx, ZCK_LOG_ERROR);
}
-int validate_file(zckCtx *zck) {
+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 -1;
+ 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_INFO, "Expected data checksum: %s\n", cks);
+ 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_INFO, "Calculated data checksum: %s\n", cks);
+ 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(ZCK_LOG_ERROR, "Data checksum failed!\n");
- return 0;
+ zck_log(bad_checksums, "Data checksum failed!\n");
+ return -1;
}
zck_log(ZCK_LOG_DEBUG, "Data checksum valid\n");
free(digest);
if(digest == NULL) {
zck_log(ZCK_LOG_ERROR,
"Unable to calculate %s checksum for header\n");
- return -1;
+ 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_INFO, "Expected header checksum: %s\n", cks);
+ 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_INFO, "Calculated header checksum: %s\n", cks);
+ 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 0;
+ return -1;
}
zck_log(ZCK_LOG_DEBUG, "Header checksum valid\n");
free(digest);
if(!hash_init(&(zck->check_full_hash), &(zck->hash_type)))
- return -1;
+ return 0;
return 1;
}
-int PUBLIC zck_validate_checksums(zckCtx *zck) {
+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 -1;
+ return 0;
}
hash_close(&(zck->check_full_hash));
if(!hash_init(&(zck->check_full_hash), &(zck->hash_type)))
- return -1;
+ return 0;
if(!seek_data(zck->fd, zck->data_offset, SEEK_SET))
- return -1;
+ return 0;
/* Check each chunk checksum */
- zckIndexItem *idx = zck->index.first;
int all_good = True;
- while(idx) {
+ 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 -1;
+ return 0;
size_t rlen = 0;
while(rlen < idx->comp_length) {
if(BUF_SIZE > idx->comp_length - rlen)
rsize = idx->comp_length - rlen;
if(read_data(zck->fd, buf, rsize) != rsize)
- return 0;
+ zck_log(ZCK_LOG_DEBUG, "No more data\n");
if(!hash_update(&(zck->check_chunk_hash), buf, rsize))
- return -1;
+ return 0;
if(!hash_update(&(zck->check_full_hash), buf, rsize))
- return -1;
+ return 0;
rlen += rsize;
}
- int valid_chunk = validate_chunk(zck, idx, ZCK_LOG_ERROR);
- if(valid_chunk < 0)
- return -1;
+ int valid_chunk = validate_chunk(zck, idx, bad_checksums);
+ if(!valid_chunk)
+ return 0;
idx->valid = valid_chunk;
- if(all_good && !valid_chunk)
+ if(all_good && valid_chunk != 1)
all_good = False;
- idx = idx->next;
}
- if(!all_good)
- return 0;
-
- /* Check data checksum */
- int valid_file = validate_file(zck);
- if(valid_file < 0)
- return -1;
+ 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 -1;
+ return 0;
/* Reinitialize data checksum */
if(!hash_init(&(zck->check_full_hash), &(zck->hash_type)))
- return -1;
+ 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;
}
regex_t *end_regex;
regex_t *hdr_regex;
zckIndexItem *tgt_check;
- zckHash *chunk_hash;
} zckDLPriv;
typedef struct zckComp {
__attribute__ ((warn_unused_result));
int import_dict(zckCtx *zck)
__attribute__ ((warn_unused_result));
-int validate_file(zckCtx *zck)
+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));
__attribute__ ((warn_unused_result));
/* header.c */
-int validate_header(zckCtx *zck)
- __attribute__ ((warn_unused_result));
int read_preface(zckCtx *zck)
__attribute__ ((warn_unused_result));
int read_index(zckCtx *zck)
strerror(errno));
return 0;
}
- printf("Seeking to location %lu\n", start);
}
return 1;
}
if(!zck_read_lead(dl->zck))
return 0;
start = zck_get_lead_length(dl->zck);
- printf("Now we need %lu bytes\n", zck_get_header_length(dl->zck) - start);
if(!dl_bytes(&dl_ctx, url, zck_get_header_length(dl->zck) - start,
start, &buffer_len, log_level))
return 0;
}
} else {
/* If file is already fully downloaded, let's get out of here! */
- if(zck_validate_checksums(zck_tgt)) {
+ int retval = zck_find_valid_chunks(zck_tgt);
+ if(retval == 0) {
+ exit_val = 10;
+ goto out;
+ }
+ if(retval == 1) {
+ printf("Missing chunks: 0\n");
printf("Downloaded %lu bytes\n",
(long unsigned)zck_dl_get_bytes_downloaded(dl));
ftruncate(dst_fd, zck_get_length(zck_tgt));
exit_val = 0;
- //goto out;
+ goto out;
}
if(zck_src && !zck_copy_chunks(zck_src, zck_tgt)) {
exit_val = 10;
goto out;
}
+ zck_reset_failed_chunks(zck_tgt);
dlCtx dl_ctx = {0};
dl_ctx.dl = dl;
dl_ctx.curl = curl_ctx;