zckIndexItem *first;
} zckIndex;
+/* Contains a single range */
+typedef struct zckRangeItem {
+ size_t start;
+ size_t end;
+ struct zckRangeItem *next;
+ struct zckRangeItem *prev;
+} zckRangeItem;
+
+/* Contains a series of ranges, information about them, a link to the first
+ * range item, and an index describing what information is in the ranges */
+typedef struct zckRange {
+ unsigned int count;
+ zckRangeItem *first;
+ zckIndex index;
+} zckRange;
/*******************************************************************
* Reading a zchunk file
void zck_set_log_level(zck_log_type ll);
/* Validate the chunk and data checksums for the current file.
* Returns -1 for error, 0 for invalid checksum and 1 for valid checksum */
-int zck_validate_checksums(zckCtx *zck);
+int zck_validate_checksums(zckCtx *zck)
+ __attribute__ ((warn_unused_result));
+/* Validate just the data checksum for the current file */
+int zck_validate_data_checksum(zckCtx *zck)
+ __attribute__ ((warn_unused_result));
+/* Get a zckRange of ranges that need to still be downloaded.
+ * max_ranges is the maximum number of ranges supported in a single request
+ * by the server. If the server supports unlimited ranges, set to -1
+ * Returns NULL if there's an error */
+zckRange *zck_get_dl_range(zckCtx *zck, int max_ranges)
+ __attribute__ ((warn_unused_result));
+/* Get a string representation of a zckRange */
+char *zck_get_range_char(zckRange *range)
+ __attribute__ ((warn_unused_result));
+/* Get file descriptor attached to zchunk context */
+int zck_get_fd(zckCtx *zck)
+ __attribute__ ((warn_unused_result));
/*******************************************************************
* The functions should be all you need to read and write a zchunk
/* Initialize zchunk context */
zckCtx *zck_create()
__attribute__ ((warn_unused_result));
-/* Get header length (header + index) */
+/* Get lead length */
+ssize_t zck_get_lead_length(zckCtx *zck)
+ __attribute__ ((warn_unused_result));
+/* Get header length (lead + preface + index + sigs) */
ssize_t zck_get_header_length(zckCtx *zck)
__attribute__ ((warn_unused_result));
/* Get data length */
/* Initialize zchunk for reading using advanced options */
zckCtx *zck_init_adv_read (int src_fd)
__attribute__ ((warn_unused_result));
+/* Read zchunk lead */
+int zck_read_lead(zckCtx *zck)
+ __attribute__ ((warn_unused_result));
/* Read zchunk header */
int zck_read_header(zckCtx *zck)
__attribute__ ((warn_unused_result));
int zck_get_full_hash_type(zckCtx *zck)
__attribute__ ((warn_unused_result));
/* Get digest size of overall hash type */
-int zck_get_full_digest_size(zckCtx *zck)
+ssize_t zck_get_full_digest_size(zckCtx *zck)
__attribute__ ((warn_unused_result));
/* Get chunk hash type */
int zck_get_chunk_hash_type(zckCtx *zck)
__attribute__ ((warn_unused_result));
/* Get digest size of chunk hash type */
-int zck_get_chunk_digest_size(zckCtx *zck)
+ssize_t zck_get_chunk_digest_size(zckCtx *zck)
__attribute__ ((warn_unused_result));
/* Get name of hash type */
const char *zck_hash_name_from_type(int hash_type)
__attribute__ ((warn_unused_result));
-/* Check data hash */
-int zck_hash_check_data(zckCtx *zck, int dst_fd)
- __attribute__ ((warn_unused_result));
+
/*******************************************************************
* Downloading (should this go in a separate header and library?)
*******************************************************************/
-/* Contains a single range */
-typedef struct zckRangeItem {
- size_t start;
- size_t end;
- struct zckRangeItem *next;
- struct zckRangeItem *prev;
-} zckRangeItem;
-
-/* Contains a series of ranges, information about them, a link to the first
- * range item, and an index describing what information is in the ranges */
-typedef struct zckRange {
- unsigned int count;
- unsigned int segments;
- unsigned int max_ranges;
- zckRangeItem *first;
- zckIndex index;
-} zckRange;
+typedef size_t (*zck_wcb)(void *ptr, size_t l, size_t c, void *dl_v);
typedef struct zckDLPriv zckDLPriv;
/* Contains a zchunk download context */
typedef struct zckDL {
size_t dl;
size_t ul;
- int dst_fd;
- char *boundary;
+ zck_wcb write_cb;
+ void *wdata;
+ zck_wcb header_cb;
+ void *hdrdata;
zckRange info;
zckDLPriv *priv;
struct zckCtx *zck;
/*******************************************************************
* Ranges
*******************************************************************/
-/* Update info with the maximum number of ranges in a single request */
-int zck_range_calc_segments(zckRange *info, unsigned int max_ranges)
- __attribute__ ((warn_unused_result));
/* Get any matching chunks from src and put them in the right place in tgt */
-int zck_dl_copy_src_chunks(zckRange *info, zckCtx *src, zckCtx *tgt)
- __attribute__ ((warn_unused_result));
-/* Get index of chunks not available in src, and put them in info */
-int zck_range_get_need_dl(zckRange *info, zckCtx *zck_src, zckCtx *zck_tgt)
- __attribute__ ((warn_unused_result));
-/* Get array of range request strings. ra must be allocated to size
- * info->segments, and the strings must be freed by the caller after use */
-int zck_range_get_array(zckRange *info, char **ra)
+int zck_copy_chunks(zckCtx *src, zckCtx *tgt)
__attribute__ ((warn_unused_result));
/* Free any resources in zckRange */
void zck_range_close(zckRange *info);
/* Get range string from start and end location */
char *zck_get_range(size_t start, size_t end)
__attribute__ ((warn_unused_result));
-
+/* Get the minimum size needed to download in order to know how large the header
+ * is */
+int get_min_download_size()
+ __attribute__ ((warn_unused_result));
/*******************************************************************
* Downloading
*******************************************************************/
-/* Initialize curl stuff, should be run at beginning of any program using any
- * following functions */
-void zck_dl_global_init();
-/* Clean up curl stuff, should be run at end of any program using any following
- * functions */
-void zck_dl_global_cleanup();
-
/* Initialize zchunk download context */
-zckDL *zck_dl_init()
+zckDL *zck_dl_init(zckCtx *zck)
__attribute__ ((warn_unused_result));
+/* Reset zchunk download context for reuse */
+void zck_dl_reset(zckDL *dl);
/* Free zchunk download context */
void zck_dl_free(zckDL **dl);
+/* Write callback. You *must* pass this and your initialized zchunk download
+ * context to the downloader when downloading a zchunk file. If you have your
+ * own callback, set dl->write_cb to your callback and dl->wdata to your
+ * callback data. */
+size_t zck_write_chunk_cb(void *ptr, size_t l, size_t c, void *dl_v);
+size_t zck_write_zck_header_cb(void *ptr, size_t l, size_t c, void *dl_v);
+size_t zck_header_cb(char *b, size_t l, size_t c, void *dl_v);
/* Clear regex used for extracting download ranges from multipart download */
void zck_dl_clear_regex(zckDL *dl);
/* Download and process the header from url */
/* Get number of bytes uploaded using download context */
size_t zck_dl_get_bytes_uploaded(zckDL *dl)
__attribute__ ((warn_unused_result));
+
/* Download ranges specified in dl->info from url */
-int zck_dl_range(zckDL *dl, char *url)
- __attribute__ ((warn_unused_result));
-/* Return string with range request from start to end (inclusive) */
-char *zck_dl_get_range(unsigned int start, unsigned int end)
- __attribute__ ((warn_unused_result));
+/*int zck_dl_range(zckDL *dl, char *url)
+ __attribute__ ((warn_unused_result));*/
#endif
}
/* Free zckDL regex's used for downloading ranges */
-void zck_dl_free_dl_regex(zckDL *dl) {
+static void free_dl_regex(zckDL *dl) {
if(dl == NULL || dl->priv == NULL)
return;
+ if(dl->priv->hdr_regex) {
+ regfree(dl->priv->hdr_regex);
+ free(dl->priv->hdr_regex);
+ dl->priv->hdr_regex = NULL;
+ }
if(dl->priv->dl_regex) {
regfree(dl->priv->dl_regex);
free(dl->priv->dl_regex);
}
/* Write zeros to tgt->fd in location of tgt_idx */
-int zck_dl_write_zero(zckCtx *tgt, zckIndexItem *tgt_idx) {
+static int zero_chunk(zckCtx *tgt, zckIndexItem *tgt_idx) {
char buf[BUF_SIZE] = {0};
size_t to_read = tgt_idx->comp_length;
if(!seek_data(tgt->fd, tgt->data_offset + tgt_idx->start, SEEK_SET))
return True;
}
-int zck_dl_write(zckDL *dl, const char *at, size_t length) {
- VALIDATE(dl);
- VALIDATE(dl->priv);
- if(dl->priv->write_in_chunk < length)
- length = dl->priv->write_in_chunk;
- if(!write_data(dl->dst_fd, at, length))
- return -1;
- dl->priv->write_in_chunk -= length;
- return length;
-}
-
-int zck_dl_md_write(zckDL *dl, const char *at, size_t length) {
+static int dl_write(zckDL *dl, const char *at, size_t length) {
VALIDATE(dl);
VALIDATE(dl->priv);
int wb = 0;
if(dl->priv->write_in_chunk > 0) {
- wb = zck_dl_write(dl, at, length);
+ if(dl->priv->write_in_chunk < length)
+ wb = dl->priv->write_in_chunk;
+ if(!write_data(dl->zck->fd, at, wb))
+ return -1;
+ dl->priv->write_in_chunk -= wb;
if(!zck_hash_update(dl->priv->chunk_hash, at, wb))
return 0;
if(wb < 0)
return wb;
}
-int zck_dl_write_chunk(zckDL *dl) {
+static int validate_chunk(zckDL *dl) {
VALIDATE(dl);
VALIDATE(dl->priv);
if(dl->priv->chunk_hash == NULL) {
dl->priv->tgt_check->digest_size) != 0) {
zck_log(ZCK_LOG_WARNING,
"Downloaded chunk failed hash check\n");
- if(!zck_dl_write_zero(dl->zck, dl->priv->tgt_check))
+ if(!zero_chunk(dl->zck, dl->priv->tgt_check))
return False;
} else {
dl->priv->tgt_check->valid = True;
zck_log(ZCK_LOG_ERROR, "zckCtx index not initialized\n");
return 0;
}
- int wb = zck_dl_md_write(dl, at, length);
+ int wb = dl_write(dl, at, length);
if(dl->priv->write_in_chunk == 0) {
/* Check whether we just finished downloading a chunk and verify it */
- if(dl->priv->tgt_check && !zck_dl_write_chunk(dl))
+ if(dl->priv->tgt_check && !validate_chunk(dl))
return False;
zckIndexItem *idx = dl->info.index.first;
while(idx) {
&(dl->zck->chunk_hash_type)))
return 0;
dl->priv->write_in_chunk = idx->comp_length;
- if(!seek_data(dl->dst_fd,
+ if(!seek_data(dl->zck->fd,
dl->zck->data_offset + tgt_idx->start,
SEEK_SET))
return 0;
return wb + wb2;
}
-char *zck_dl_get_range_char(unsigned int start, unsigned int end) {
- zckRangeItem r = {0};
- zckRangeItem *range = &r;
-
- r.start = start;
- r.end = end;
- char *range_header = zck_range_get_char(&range, 2);
- return range_header;
+size_t PUBLIC zck_write_zck_header_cb(void *ptr, size_t l, size_t c, void *dl_v) {
+ if(dl_v == NULL)
+ return 0;
+ zckDL *dl = (zckDL*)dl_v;
+ size_t wb = 0;
+ dl->dl += l*c;
+ wb = write(dl->zck->fd, ptr, l*c);
+ if(dl->write_cb)
+ dl->write_cb(ptr, l, c, dl->wdata);
+ return wb;
}
-static size_t dl_write_data(void *ptr, size_t l, size_t c, void *dl_v) {
+size_t PUBLIC zck_write_chunk_cb(void *ptr, size_t l, size_t c, void *dl_v) {
if(dl_v == NULL)
return 0;
zckDL *dl = (zckDL*)dl_v;
size_t wb = 0;
dl->dl += l*c;
- if(dl->boundary != NULL) {
+ if(dl->priv->boundary != NULL) {
int retval = zck_multipart_extract(dl, ptr, l*c);
if(retval == 0)
wb = 0;
else
wb = l*c;
- } else if(dl->priv->is_chunk) {
+ } else {
int retval = zck_dl_write_range(dl, ptr, l*c);
if(retval == 0)
wb = 0;
else
wb = l*c;
- } else {
- wb = write(dl->dst_fd, ptr, l*c);
}
+ if(dl->write_cb)
+ dl->write_cb(ptr, l, c, dl->wdata);
return wb;
}
-int zck_dl_write_and_verify(zckRange *info, zckCtx *src, zckCtx *tgt,
- zckIndexItem *src_idx, zckIndexItem *tgt_idx) {
+int write_and_verify_chunk(zckCtx *src, zckCtx *tgt, zckIndexItem *src_idx,
+ zckIndexItem *tgt_idx) {
static char buf[BUF_SIZE] = {0};
size_t to_read = src_idx->comp_length;
pdigest = get_digest_string(digest, src_idx->digest_size);
zck_log(ZCK_LOG_WARNING, "Target hash: %s\n", pdigest);
free(pdigest);
- if(!zck_dl_write_zero(tgt, tgt_idx))
- return False;
- if(!zck_range_add(info, tgt_idx, tgt))
+ if(!zero_chunk(tgt, tgt_idx))
return False;
} else {
tgt_idx->valid = True;
- zck_log(ZCK_LOG_DEBUG, "Writing %lu bytes at %lu\n",
+ zck_log(ZCK_LOG_DEBUG, "Wrote %lu bytes at %lu\n",
tgt_idx->comp_length, tgt_idx->start);
}
free(digest);
return True;
}
-int PUBLIC zck_dl_copy_src_chunks(zckRange *info, zckCtx *src, zckCtx *tgt) {
+int PUBLIC zck_copy_chunks(zckCtx *src, zckCtx *tgt) {
zckIndex *tgt_info = zck_get_index(tgt);
zckIndex *src_info = zck_get_index(src);
zckIndexItem *tgt_idx = tgt_info->first;
zckIndexItem *src_idx = src_info->first;
while(tgt_idx) {
+ /* No need to copy already valid chunk */
+ if(tgt_idx->valid)
+ continue;
+
int found = False;
src_idx = src_info->first;
while(src_idx) {
if(tgt_idx->comp_length == src_idx->comp_length &&
tgt_idx->length == src_idx->length &&
+ tgt_idx->digest_size == src_idx->digest_size &&
memcmp(tgt_idx->digest, src_idx->digest,
tgt_idx->digest_size) == 0) {
found = True;
src_idx = src_idx->next;
}
/* Write out found chunk, then verify that it's valid */
- if(found && !zck_dl_write_and_verify(info, src, tgt, src_idx, tgt_idx))
- return False;
- if(!found && !zck_range_add(info, tgt_idx, tgt))
- return False;
+ if(found)
+ write_and_verify_chunk(src, tgt, src_idx, tgt_idx);
tgt_idx = tgt_idx->next;
}
return True;
}
-static size_t get_header(char *b, size_t l, size_t c, void *dl_v) {
+size_t PUBLIC zck_header_cb(char *b, size_t l, size_t c, void *dl_v) {
if(dl_v == NULL)
return 0;
zckDL *dl = (zckDL*)dl_v;
- return zck_multipart_get_boundary(dl, b, c*l);
-}
-
-int zck_dl_range_chk_chunk(zckDL *dl, char *url, int is_chunk) {
- if(dl == NULL || dl->priv == NULL || dl->info.first == NULL) {
- zck_log(ZCK_LOG_ERROR, "Struct not defined\n");
- return False;
- }
- if(dl->priv->parser_started) {
- zck_log(ZCK_LOG_ERROR, "Multipart parser already started\n");
- return False;
- }
- if(dl->info.segments == 0)
- dl->info.segments = 1;
- dl->priv->is_chunk = is_chunk;
-
- char **ra = calloc(sizeof(char*), dl->info.segments);
- if(!zck_range_get_array(&(dl->info), ra)) {
- free(ra);
- return False;
- }
- CURLcode res;
-
- for(int i=0; i<dl->info.segments; i++) {
- if(dl->priv->dl_regex != NULL)
- zck_dl_free_dl_regex(dl);
- if(dl->boundary != NULL)
- free(dl->boundary);
-
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_URL, url);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_FOLLOWLOCATION, 1L);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_HEADERFUNCTION, get_header);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_HEADERDATA, dl);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_WRITEFUNCTION, dl_write_data);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_WRITEDATA, dl);
- curl_easy_setopt(dl->priv->curl_ctx, CURLOPT_RANGE, ra[i]);
- res = curl_easy_perform(dl->priv->curl_ctx);
- free(ra[i]);
-
- if(res != CURLE_OK) {
- zck_log(ZCK_LOG_ERROR, "Download failed: %s\n",
- curl_easy_strerror(res));
- return False;
- }
- long code;
- curl_easy_getinfo (dl->priv->curl_ctx, CURLINFO_RESPONSE_CODE, &code);
- if (code != 206 && code != 200) {
- zck_log(ZCK_LOG_ERROR, "HTTP Error: %li when download %s\n", code,
- url);
- return False;
- }
- zck_dl_clear_regex(dl);
- }
- free(ra);
- return True;
-}
-
-int PUBLIC zck_dl_range(zckDL *dl, char *url) {
- return zck_dl_range_chk_chunk(dl, url, 1);
-}
+ size_t retval = zck_multipart_get_boundary(dl, b, c*l);
-int zck_dl_bytes(zckDL *dl, char *url, size_t bytes, size_t start,
- size_t *buffer_len) {
- if(dl == NULL) {
- zck_log(ZCK_LOG_ERROR, "zckDL not initialized\n");
- return False;
- }
- if(start + bytes > *buffer_len) {
- zckIndexItem idx = {0};
-
- zck_log(ZCK_LOG_DEBUG, "Seeking to end of temporary file\n");
- if(lseek(dl->dst_fd, 0, SEEK_END) == -1) {
- zck_log(ZCK_LOG_ERROR, "Seek to end of temporary file failed: %s\n",
- strerror(errno));
- return False;
- }
- zck_log(ZCK_LOG_DEBUG, "Downloading %lu bytes at position %lu\n", start+bytes-*buffer_len, *buffer_len);
- idx.start = *buffer_len;
- idx.comp_length = start+bytes-*buffer_len;
- zck_range_close(&(dl->info));
- if(!zck_range_add(&(dl->info), &idx, NULL))
- return False;
- if(!zck_dl_range_chk_chunk(dl, url, 0))
- return False;
- zck_range_close(&(dl->info));
- *buffer_len = start+bytes;
- zck_log(ZCK_LOG_DEBUG, "Seeking to position %lu\n", start);
- if(lseek(dl->dst_fd, start, SEEK_SET) == -1) {
- zck_log(ZCK_LOG_ERROR,
- "Seek to byte %lu of temporary file failed: %s\n", start,
- strerror(errno));
- return False;
- }
- }
- return True;
+ if(dl->header_cb)
+ dl->header_cb(b, l, c, dl->hdrdata);
+ return c*l;
}
int zck_zero_bytes(zckDL *dl, size_t bytes, size_t start, size_t *buffer_len) {
char buf[BUF_SIZE] = {0};
if(start + bytes > *buffer_len) {
zck_log(ZCK_LOG_DEBUG, "Seeking to end of temporary file\n");
- if(lseek(dl->dst_fd, 0, SEEK_END) == -1) {
+ if(lseek(dl->zck->fd, 0, SEEK_END) == -1) {
zck_log(ZCK_LOG_ERROR, "Seek to end of temporary file failed: %s\n",
strerror(errno));
return False;
size_t wb = BUF_SIZE;
if(write + wb > start + bytes)
wb = (start + bytes) - write;
- if(!write_data(dl->dst_fd, buf, wb))
+ if(!write_data(dl->zck->fd, buf, wb))
return False;
write += wb;
}
zck_log(ZCK_LOG_DEBUG, "Wrote %lu zeros at position %lu\n", start+bytes-*buffer_len, *buffer_len);
*buffer_len = start+bytes;
zck_log(ZCK_LOG_DEBUG, "Seeking to position %lu\n", start);
- if(lseek(dl->dst_fd, start, SEEK_SET) == -1) {
+ if(lseek(dl->zck->fd, start, SEEK_SET) == -1) {
zck_log(ZCK_LOG_ERROR,
"Seek to byte %lu of temporary file failed: %s\n", start,
strerror(errno));
return True;
}
-/* Download header */
-int PUBLIC zck_dl_get_header(zckCtx *zck, zckDL *dl, char *url) {
- if(zck == NULL) {
- zck_log(ZCK_LOG_ERROR, "zckCtx not initialized\n");
- return False;
- }
- if(dl == NULL) {
- zck_log(ZCK_LOG_ERROR, "zckDL not initialized\n");
- return False;
- }
- size_t buffer_len = 0;
- size_t start = 0;
- zck->fd = dl->dst_fd;
-
- /* Download first hundred bytes and read magic and hash type */
- if(!zck_dl_bytes(dl, url, 200, start, &buffer_len))
- return False;
- if(!read_lead_1(zck))
- return False;
- start = tell_data(dl->dst_fd);
-
- if(!zck_dl_bytes(dl, url, zck->lead_size + zck->hash_type.digest_size,
- start, &buffer_len))
- return False;
- if(!read_lead_2(zck))
- return False;
- zck_log(ZCK_LOG_DEBUG, "Header hash: (%s)",
- zck_hash_name_from_type(zck_get_full_hash_type(zck)));
- char *digest = zck_get_header_digest(zck);
- zck_log(ZCK_LOG_DEBUG, "%s\n", digest);
- free(digest);
- start = tell_data(dl->dst_fd);
-
- /* If we haven't downloaded enough for the index hash plus a few others, do
- * it now */
- if(!zck_dl_bytes(dl, url, zck->lead_size + zck->header_length,
- start, &buffer_len))
- return False;
-
- /* Verify header checksum */
- if(!validate_header(zck))
- return False;
- zck_hash_close(&(zck->check_full_hash));
-
- /* Read the header */
- if(!read_preface(zck))
- return False;
- start += zck->preface_size;
- zck_log(ZCK_LOG_DEBUG, "Index size: %llu\n", zck->index_size);
-
- /* Read the index */
- if(!read_index(zck))
- return False;
-
- /* Read signatures */
- if(!read_sig(zck))
- return False;
-
- /* Write zeros to rest of file */
- zckIndex *info = &(dl->info.index);
- info->hash_type = zck->index.hash_type;
- zck_log(ZCK_LOG_DEBUG, "Writing zeros to rest of file: %llu\n", zck->index.length + zck->index_size + start);
- if(!zck_zero_bytes(dl, zck->index.length, zck->data_offset, &buffer_len))
- return False;
- return True;
-}
size_t PUBLIC zck_dl_get_bytes_downloaded(zckDL *dl) {
VALIDATE(dl);
return dl->ul;
}
-void PUBLIC zck_dl_global_init() {
- curl_global_init(CURL_GLOBAL_ALL);
-}
-
-void PUBLIC zck_dl_global_cleanup() {
- curl_global_cleanup();
-}
-
/* Free zckDL header regex used for downloading ranges */
void zck_dl_clear_regex(zckDL *dl) {
if(dl == NULL || dl->priv == NULL)
return;
- zck_dl_free_dl_regex(dl);
+ free_dl_regex(dl);
if(dl->priv->hdr_regex) {
regfree(dl->priv->hdr_regex);
free(dl->priv->hdr_regex);
}
/* Initialize zckDL. When finished, zckDL *must* be freed by zck_dl_free() */
-zckDL PUBLIC *zck_dl_init() {
+zckDL PUBLIC *zck_dl_init(zckCtx *zck) {
zckDL *dl = zmalloc(sizeof(zckDL));
if(!dl) {
zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for zckDL\n",
sizeof(zckMP));
return NULL;
}
- dl->priv->curl_ctx = curl_easy_init();
- if(!dl->priv->curl_ctx) {
- zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes for dl->curl_ctx\n",
- sizeof(CURL));
- return NULL;
- }
+ dl->zck = zck;
return dl;
}
/* Free zckDL and set pointer to NULL */
-void PUBLIC zck_dl_free(zckDL **dl) {
- if(!*dl)
+void PUBLIC zck_dl_reset(zckDL *dl) {
+ if(!dl)
return;
- if((*dl)->priv) {
- if((*dl)->priv->mp) {
- if((*dl)->priv->mp->buffer)
- free((*dl)->priv->mp->buffer);
- free((*dl)->priv->mp);
+ if(dl->priv) {
+ if(dl->priv->mp) {
+ if(dl->priv->mp->buffer)
+ free(dl->priv->mp->buffer);
+ free(dl->priv->mp);
}
- zck_dl_clear_regex(*dl);
- curl_easy_cleanup((*dl)->priv->curl_ctx);
- free((*dl)->priv);
+ zck_dl_clear_regex(dl);
+ if(dl->priv->boundary)
+ free(dl->priv->boundary);
+ free(dl->priv);
}
- if((*dl)->info.first)
- zck_range_close(&((*dl)->info));
- if((*dl)->boundary)
- free((*dl)->boundary);
+ zckCtx *zck = dl->zck;
+ if(dl->info.first)
+ zck_range_close(&(dl->info));
+ memset(dl, 0, sizeof(zckDL));
+ dl->zck = zck;
+}
+
+/* Free zckDL and set pointer to NULL */
+void PUBLIC zck_dl_free(zckDL **dl) {
+ zck_dl_reset(*dl);
free(*dl);
*dl = NULL;
}
return True;
}
-int PUBLIC zck_range_calc_segments(zckRange *info, unsigned int max_ranges) {
- if(max_ranges == 0)
- return False;
- info->segments = (info->count + max_ranges - 1) / max_ranges;
- info->max_ranges = max_ranges;
- return True;
-}
-
-int zck_range_get_need_dl(zckRange *info, zckCtx *zck_src, zckCtx *zck_tgt) {
- zckIndex *tgt_info = zck_get_index(zck_tgt);
- zckIndex *src_info = zck_get_index(zck_src);
- zckIndexItem *tgt_idx = tgt_info->first;
- zckIndexItem *src_idx = src_info->first;
- while(tgt_idx) {
- int found = False;
- src_idx = src_info->first;
-
- while(src_idx) {
- if(memcmp(tgt_idx->digest, src_idx->digest, tgt_idx->digest_size) == 0) {
- found = True;
- break;
- }
- src_idx = src_idx->next;
- }
- if(!found)
- if(!zck_range_add(info, tgt_idx, zck_tgt))
- return False;
-
- tgt_idx = tgt_idx->next;
- }
- return True;
-}
-
-char *zck_range_get_char(zckRangeItem **range, int max_ranges) {
+char PUBLIC *zck_get_range_char(zckRange *range) {
int buf_size=32768;
char *output=malloc(buf_size);
if(!output) {
int loc = 0;
int count = 0;
- while(*range) {
+ zckRangeItem *ri = range->first;
+ while(ri) {
int length = snprintf(output+loc, buf_size-loc, "%lu-%lu,",
- (long unsigned)(*range)->start,
- (long unsigned)(*range)->end);
+ (long unsigned)ri->start,
+ (long unsigned)ri->end);
if(length < 0) {
zck_log(ZCK_LOG_ERROR, "Unable to get range: %s\n",
strerror(errno));
}
loc += length;
count++;
- *range = (*range)->next;
- if(count == max_ranges)
- break;
+ ri = ri->next;
}
output[loc-1]='\0'; // Remove final comma
output = realloc(output, loc);
return output;
}
-char PUBLIC *zck_get_range(size_t start, size_t end) {
- zckRangeItem range = {0};
- range.start = start;
- range.end = end;
- zckRangeItem *r = ⦥
- return zck_range_get_char(&r, 1);
-}
+zckRange PUBLIC *zck_get_dl_range(zckCtx *zck, int max_ranges) {
+ zckRange *range = zmalloc(sizeof(zckRange));
+ if(range == NULL) {
+ zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n",
+ sizeof(zckRange));
+ return NULL;
+ }
+ zckIndexItem **range_idx = &(range->index.first);
+ zckIndexItem *idx = zck->index.first;
+ size_t start = 0;
+ while(idx) {
+ if(idx->valid)
+ continue;
+ if(!zck_range_add(range, idx, zck)) {
+ zck_range_close(range);
+ return NULL;
+ }
+ *range_idx = copy_index_item(idx);
+ if(*range_idx == NULL) {
+ zck_range_close(range);
+ return NULL;
+ }
+ (*range_idx)->start = start;
+ range_idx = &((*range_idx)->next);
+ start += idx->comp_length;
-int zck_range_get_array(zckRange *info, char **ra) {
- if(!info) {
- zck_log(ZCK_LOG_ERROR, "zckRange not allocated\n");
- return False;
+ if(max_ranges >= 0 && range->count >= max_ranges)
+ break;
+ idx = idx->next;
}
- zckRangeItem *tmp = info->first;
- for(int i=0; i<info->segments; i++) {
- ra[i] = zck_range_get_char(&tmp, info->max_ranges);
- if(ra[i] == NULL)
- return False;
+ return range;
+}
+
+int zck_range_get_need_dl(zckRange *info, zckCtx *zck_src, zckCtx *zck_tgt) {
+ zckIndex *tgt_info = zck_get_index(zck_tgt);
+ zckIndex *src_info = zck_get_index(zck_src);
+ zckIndexItem *tgt_idx = tgt_info->first;
+ zckIndexItem *src_idx = src_info->first;
+ while(tgt_idx) {
+ int found = False;
+ src_idx = src_info->first;
+
+ while(src_idx) {
+ if(memcmp(tgt_idx->digest, src_idx->digest, tgt_idx->digest_size) == 0) {
+ found = True;
+ break;
+ }
+ src_idx = src_idx->next;
+ }
+ if(!found)
+ if(!zck_range_add(info, tgt_idx, zck_tgt))
+ return False;
+
+ tgt_idx = tgt_idx->next;
}
return True;
}
-int zck_range_get_max(zckRange *info, char *url) {
- return True;
+char PUBLIC *zck_get_range(size_t start, size_t end) {
+ zckRange range = {0};
+ zckRangeItem ri = {0};
+ range.first = &ri;
+ ri.start = start;
+ ri.end = end;
+ return zck_get_range_char(&range);
}