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_UNCOMP_HEADER, /* Header should contain uncompressed size, too */
ZCK_COMP_TYPE = 100, /* Set compression type using zck_comp */
ZCK_MANUAL_CHUNK, /* Disable auto-chunking */
ZCK_CHUNK_MIN, /* Minimum chunk size when manual chunking */
/* Get digest size of chunk hash type */
ssize_t zck_get_chunk_digest_size(zckCtx *zck)
__attribute__ ((warn_unused_result));
+/* Get uncompressed chunk digest */
+char *zck_get_chunk_digest_uncompressed(zckChunk *item)
+ __attribute__ ((warn_unused_result));
/* Get chunk data */
ssize_t zck_get_chunk_data(zckChunk *idx, char *dst, size_t dst_size)
__attribute__ ((warn_unused_result));
free(dst);
return -1;
}
+ if(zck->has_uncompressed_source && !hash_update(zck, &(zck->work_index_hash_uncomp), src, src_size))
+ return -1;
free(dst);
return src_size;
}
}
if(add_index)
if(!index_new_chunk(zck, &(info->index), idx->digest, idx->digest_size,
- end-start+1, end-start+1, idx, false)) {
+ idx->digest_uncompressed, end-start+1, end-start+1, idx, false)) {
free(new);
return NULL;
}
return get_digest_string(item->digest, item->digest_size);
}
+char PUBLIC *zck_get_chunk_digest_uncompressed(zckChunk *item) {
+ if(item == NULL)
+ return NULL;
+ if (!item->zck->has_uncompressed_source) {
+ return NULL;
+ }
+ return get_digest_string(item->digest_uncompressed, item->digest_size_uncompressed);
+}
+
+
/* 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) {
VALIDATE_READ_BOOL(zck);
zck->has_optional_elems = flags & 2;
if(zck->has_optional_elems)
flags -= 2;
+ zck->has_uncompressed_source = flags & 4;
+ if(zck->has_uncompressed_source)
+ flags -= 4;
+
flags = flags & (SIZE_MAX - 1);
if(flags != 0) {
set_fatal_error(zck, "Unknown flags(s) set");
}
char *header = NULL;
- zck_log(ZCK_LOG_DEBUG, "Reading index");
if(zck->lead_size + zck->preface_size + zck->index_size >
zck->header_size) {
set_fatal_error(zck, "Read past end of header");
return false;
}
header = zck->header + zck->lead_size + zck->preface_size;
+ zck_log(ZCK_LOG_DEBUG, "Reading index at 0x%x", (unsigned long)(zck->lead_size + zck->preface_size));
int max_length = zck->header_size - (zck->lead_size + zck->preface_size);
if(!index_read(zck, header, zck->index_size, max_length))
return false;
size_t flags = 0;
if(zck->has_streams)
flags &= 1;
+ if(zck->has_uncompressed_source)
+ flags |= 4;
compint_from_size(header+length, flags, &length);
/* Write out compression type and index size */
return;
hash_close(&(zck->work_index_hash));
+ hash_close(&(zck->work_index_hash_uncomp));
if(zck->work_index_item)
index_free_item(&(zck->work_index_item));
}
clear_work_index(zck);
zck->work_index_item = zmalloc(sizeof(zckChunk));
- if(!hash_init(zck, &(zck->work_index_hash), &(zck->chunk_hash_type)))
+ if(!hash_init(zck, &(zck->work_index_hash), &(zck->chunk_hash_type)) ||
+ (!hash_init(zck, &(zck->work_index_hash_uncomp), &(zck->chunk_hash_type))))
return false;
return true;
}
static bool finish_chunk(zckIndex *index, zckChunk *item, char *digest,
- bool valid, zckCtx *zck) {
+ char *digest_uncompressed, bool valid, zckCtx *zck) {
VALIDATE_BOOL(zck);
ALLOCD_BOOL(zck, index);
ALLOCD_BOOL(zck, item);
item->digest = zmalloc(index->digest_size);
+ item->digest_uncompressed = zmalloc(index->digest_size);
if(digest) {
memcpy(item->digest, digest, index->digest_size);
item->digest_size = index->digest_size;
}
+ if(digest_uncompressed) {
+ memcpy(item->digest_uncompressed, digest_uncompressed, index->digest_size);
+ item->digest_size_uncompressed = index->digest_size;
+ }
item->start = index->length;
item->valid = valid;
item->zck = zck;
index->last = item;
index->count += 1;
index->length += item->comp_length;
+
+ char *s = get_digest_string(digest, index->digest_size);
+ if (zck->has_uncompressed_source) {
+ char *s1 = get_digest_string(digest_uncompressed, index->digest_size);
+ zck_log(ZCK_LOG_DEBUG, "Index %d digest %s digest uncomp %s", index->count, s, s1);
+ free(s1);
+ } else
+ zck_log(ZCK_LOG_DEBUG, "Index %d digest %s", index->count, s);
+ free(s);
return true;
}
if(zck->index.first) {
zckChunk *tmp = zck->index.first;
while(tmp) {
- index_malloc += zck->index.digest_size + MAX_COMP_SIZE*2;
+ index_malloc += (zck->has_uncompressed_source + 1) * zck->index.digest_size +
+ MAX_COMP_SIZE * 2;
tmp = tmp->next;
}
}
/* Write digest */
memcpy(index+index_size, tmp->digest, zck->index.digest_size);
index_size += zck->index.digest_size;
+ /* Write digest for uncompressed if any */
+ if (zck->has_uncompressed_source) {
+ memcpy(index+index_size, tmp->digest_uncompressed, zck->index.digest_size);
+ index_size += zck->index.digest_size;
+ }
/* Write compressed size */
compint_from_size(index+index_size, tmp->comp_length,
&index_size);
}
bool index_new_chunk(zckCtx *zck, zckIndex *index, char *digest,
- int digest_size, size_t comp_size, size_t orig_size,
+ int digest_size, char *digest_uncompressed, size_t comp_size, size_t orig_size,
zckChunk *src, bool finished) {
VALIDATE_BOOL(zck);
chk->comp_length = comp_size;
chk->length = orig_size;
chk->src = src;
- return finish_chunk(index, chk, digest, finished, zck);
+ return finish_chunk(index, chk, digest, digest_uncompressed, finished, zck);
}
bool index_add_to_chunk(zckCtx *zck, char *data, size_t comp_size,
return false;
char *digest = NULL;
+ char *digest_uncompressed = NULL;
if(zck->work_index_item->length > 0) {
/* Finalize chunk checksum */
digest = hash_finalize(zck, &(zck->work_index_hash));
zck_hash_name_from_type(zck->index.hash_type));
return false;
}
+ digest_uncompressed = hash_finalize(zck, &(zck->work_index_hash_uncomp));
+ if(digest_uncompressed == NULL) {
+ set_fatal_error(zck, "Unable to calculate %s checksum for new chunk",
+ zck_hash_name_from_type(zck->index.hash_type));
+ free(digest);
+ return false;
+ }
} else {
digest = zmalloc(zck->chunk_hash_type.digest_size);
+ digest_uncompressed = zmalloc(zck->chunk_hash_type.digest_size);
}
- if(!finish_chunk(&(zck->index), zck->work_index_item, digest, true, zck)) {
+ if(!finish_chunk(&(zck->index), zck->work_index_item, digest, digest_uncompressed, true, zck)) {
free(digest);
+ free(digest_uncompressed);
return false;
}
free(digest);
+ free(digest_uncompressed);
zck->work_index_item = NULL;
hash_close(&(zck->work_index_hash));
+ hash_close(&(zck->work_index_hash_uncomp));
return true;
}
new);
length += zck->index.digest_size;
+ /* Read uncompressed entry digest, if any */
+ if (zck->has_uncompressed_source) {
+ /* same size for digest as compressed */
+ new->digest_uncompressed = zmalloc(zck->index.digest_size);
+ memcpy(new->digest_uncompressed, data+length, zck->index.digest_size);
+ new->digest_size_uncompressed = zck->index.digest_size;
+ length += zck->index.digest_size;
+ }
/* Read and store entry length */
size_t chunk_length = 0;
if(!compint_to_size(zck, &chunk_length, data+length, &length,
}
zck->prep_hdr_size = value;
+ } else if(option == ZCK_UNCOMP_HEADER) {
+ zck->has_uncompressed_source = 1;
/* Hash options */
} else if(option < 100) {
/* Currently no hash options other than setting hash type, so bail */
struct zckChunk {
char *digest;
int digest_size;
+ char *digest_uncompressed;
+ int digest_size_uncompressed;
int valid;
size_t number;
size_t start;
zckIndex index;
zckChunk *work_index_item;
zckHash work_index_hash;
+ zckChunk *work_index_item_uncomp;
+ zckHash work_index_hash_uncomp;
size_t stream;
int has_streams;
int has_optional_elems;
+ int has_uncompressed_source;
char *read_buf;
size_t read_buf_size;
bool index_create(zckCtx *zck)
__attribute__ ((warn_unused_result));
bool index_new_chunk(zckCtx *zck, zckIndex *index, char *digest, int digest_size,
- size_t comp_size, size_t orig_size, zckChunk *src, bool valid)
+ char* digest_uncompressed, size_t comp_size, size_t orig_size, zckChunk *src, bool valid)
__attribute__ ((warn_unused_result));
bool index_add_to_chunk(zckCtx *zck, char *data, size_t comp_size,
size_t orig_size)
"Set zstd compression dictionary to FILE"},
{"manual-chunk", 'm', 0, 0,
"Don't do any automatic chunking (implies -s)"},
+ {"uncompressed", 'u', 0, 0,
+ "Add extension in header for uncompressed data"},
{"version", 'V', 0, 0, "Show program version"},
{ 0 }
};
char *output;
char *dict;
bool exit;
+ bool uncompressed;
};
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
case 'D':
arguments->dict = arg;
break;
+ case 'u':
+ arguments->uncompressed = true;
+ break;
case 'V':
version();
arguments->exit = true;
}
}
+ if(arguments.uncompressed) {
+ if(!zck_set_ioption(zck, ZCK_UNCOMP_HEADER, 1)) {
+ dprintf(STDERR_FILENO, "%s\n", zck_get_error(zck));
+ exit(1);
+ }
+ }
char *data;
int in_fd = open(arguments.args[0], O_RDONLY);
off_t in_size = 0;
dprintf(STDERR_FILENO, "%s", zck_get_error(zck));
exit(1);
}
- printf("%12lu %s %12lu %12lu %12lu",
+ char *digest_uncompressed = zck_get_chunk_digest_uncompressed(chk);
+ if (!digest_uncompressed)
+ digest_uncompressed = "";
+
+ printf("%12lu %s %s %12lu %12lu %12lu",
(long unsigned)zck_get_chunk_number(chk),
digest,
+ digest_uncompressed,
(long unsigned)zck_get_chunk_start(chk),
(long unsigned)zck_get_chunk_comp_size(chk),
(long unsigned)zck_get_chunk_size(chk));