lzma_end(&j->xz);
else if (j->compressed == IMPORT_JOB_GZIP)
inflateEnd(&j->gzip);
+ else if (j->compressed == IMPORT_JOB_BZIP2)
+ BZ2_bzDecompressEnd(&j->bzip2);
+
+ if (j->checksum_context)
+ gcry_md_close(j->checksum_context);
free(j->url);
free(j->etag);
strv_free(j->old_etags);
free(j->payload);
+ free(j->checksum);
free(j);
return NULL;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(ImportJob*, import_job_unref);
-
static void import_job_finish(ImportJob *j, int ret) {
assert(j);
if (ret == 0) {
j->state = IMPORT_JOB_DONE;
+ j->progress_percent = 100;
log_info("Download of %s complete.", j->url);
} else {
j->state = IMPORT_JOB_FAILED;
goto finish;
} else if (status == 304) {
log_info("Image already downloaded. Skipping download.");
+ j->etag_exists = true;
r = 0;
goto finish;
} else if (status >= 300) {
goto finish;
}
+ if (j->checksum_context) {
+ uint8_t *k;
+
+ k = gcry_md_read(j->checksum_context, GCRY_MD_SHA256);
+ if (!k) {
+ log_error("Failed to get checksum.");
+ r = -EIO;
+ goto finish;
+ }
+
+ j->checksum = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256));
+ if (!j->checksum) {
+ r = log_oom();
+ goto finish;
+ }
+
+ log_debug("SHA256 of %s is %s.", j->url, j->checksum);
+ }
+
if (j->disk_fd >= 0 && j->allow_sparse) {
/* Make sure the file size is right, in case the file was
* sparse and we just seeked for the last part */
import_job_finish(j, r);
}
-
static int import_job_write_uncompressed(ImportJob *j, void *p, size_t sz) {
ssize_t n;
assert(j);
assert(p);
- assert(sz > 0);
- assert(j->disk_fd >= 0);
+
+ if (sz <= 0)
+ return 0;
if (j->written_uncompressed + sz < j->written_uncompressed) {
log_error("File too large, overflow");
if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz))
return log_oom();
- memcpy((uint8_t*) j->payload + j->payload_size, p, sz);
+ memcpy(j->payload + j->payload_size, p, sz);
j->payload_size += sz;
}
assert(j);
assert(p);
- assert(sz > 0);
- assert(j->disk_fd >= 0);
+
+ if (sz <= 0)
+ return 0;
if (j->written_compressed + sz < j->written_compressed) {
log_error("File too large, overflow");
return -EFBIG;
}
+ if (j->checksum_context)
+ gcry_md_write(j->checksum_context, p, sz);
+
switch (j->compressed) {
case IMPORT_JOB_UNCOMPRESSED:
break;
+ case IMPORT_JOB_BZIP2:
+ j->bzip2.next_in = p;
+ j->bzip2.avail_in = sz;
+
+ while (j->bzip2.avail_in > 0) {
+ uint8_t buffer[16 * 1024];
+
+ j->bzip2.next_out = (char*) buffer;
+ j->bzip2.avail_out = sizeof(buffer);
+
+ r = BZ2_bzDecompress(&j->bzip2);
+ if (r != BZ_OK && r != BZ_STREAM_END) {
+ log_error("Decompression error.");
+ return -EIO;
+ }
+
+ r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->bzip2.avail_out);
+ if (r < 0)
+ return r;
+ }
+
+ break;
+
default:
assert_not_reached("Unknown compression");
}
}
}
+ if (j->calc_checksum) {
+ if (gcry_md_open(&j->checksum_context, GCRY_MD_SHA256, 0) != 0) {
+ log_error("Failed to initialize hash context.");
+ return -EIO;
+ }
+ }
+
return 0;
}
static const uint8_t gzip_signature[] = {
0x1f, 0x8b
};
+ static const uint8_t bzip2_signature[] = {
+ 'B', 'Z', 'h'
+ };
_cleanup_free_ uint8_t *stub = NULL;
size_t stub_size;
assert(j);
- if (j->payload_size < MAX(sizeof(xz_signature), sizeof(gzip_signature)))
+ if (j->payload_size < MAX3(sizeof(xz_signature),
+ sizeof(gzip_signature),
+ sizeof(bzip2_signature)))
return 0;
if (memcmp(j->payload, xz_signature, sizeof(xz_signature)) == 0)
j->compressed = IMPORT_JOB_XZ;
else if (memcmp(j->payload, gzip_signature, sizeof(gzip_signature)) == 0)
j->compressed = IMPORT_JOB_GZIP;
+ else if (memcmp(j->payload, bzip2_signature, sizeof(bzip2_signature)) == 0)
+ j->compressed = IMPORT_JOB_BZIP2;
else
j->compressed = IMPORT_JOB_UNCOMPRESSED;
log_debug("Stream is XZ compressed: %s", yes_no(j->compressed == IMPORT_JOB_XZ));
log_debug("Stream is GZIP compressed: %s", yes_no(j->compressed == IMPORT_JOB_GZIP));
+ log_debug("Stream is BZIP2 compressed: %s", yes_no(j->compressed == IMPORT_JOB_BZIP2));
if (j->compressed == IMPORT_JOB_XZ) {
lzma_ret xzr;
return -EIO;
}
}
+ if (j->compressed == IMPORT_JOB_BZIP2) {
+ r = BZ2_bzDecompressInit(&j->bzip2, 0, 0);
+ if (r != BZ_OK) {
+ log_error("Failed to initialize bzip2 decoder.");
+ return -EIO;
+ }
+ }
r = import_job_open_disk(j);
if (r < 0)
goto fail;
}
- memcpy((uint8_t*) j->payload + j->payload_size, contents, sz);
+ memcpy(j->payload + j->payload_size, contents, sz);
j->payload_size += sz;
r = import_job_detect_compression(j);
if (strv_contains(j->old_etags, j->etag)) {
log_info("Image already downloaded. Skipping download.");
+ j->etag_exists = true;
import_job_finish(j, 0);
return sz;
}
return sz;
}
+ if (j->on_header) {
+ r = j->on_header(j, contents, sz);
+ if (r < 0)
+ goto fail;
+ }
+
return sz;
fail:
char buf[FORMAT_TIMESPAN_MAX];
if (n - j->start_usec > USEC_PER_SEC && dlnow > 0) {
+ char y[FORMAT_BYTES_MAX];
usec_t left, done;
done = n - j->start_usec;
left = (usec_t) (((double) done * (double) dltotal) / dlnow) - done;
- log_info("Got %u%% of %s. %s left.", percent, j->url, format_timespan(buf, sizeof(buf), left, USEC_PER_SEC));
+ log_info("Got %u%% of %s. %s left at %s/s.",
+ percent,
+ j->url,
+ format_timespan(buf, sizeof(buf), left, USEC_PER_SEC),
+ format_bytes(y, sizeof(y), (uint64_t) ((double) dlnow / ((double) done / (double) USEC_PER_SEC))));
} else
log_info("Got %u%% of %s.", percent, j->url);
j->progress_percent = percent;
j->last_status_usec = n;
+
+ if (j->on_progress)
+ j->on_progress(j);
}
return 0;
if (!hdr)
return -ENOMEM;
- j->request_header = curl_slist_new(hdr, NULL);
- if (!j->request_header)
- return -ENOMEM;
+ if (!j->request_header) {
+ j->request_header = curl_slist_new(hdr, NULL);
+ if (!j->request_header)
+ return -ENOMEM;
+ } else {
+ struct curl_slist *l;
+
+ l = curl_slist_append(j->request_header, hdr);
+ if (!l)
+ return -ENOMEM;
+
+ j->request_header = l;
+ }
+ }
+ if (j->request_header) {
if (curl_easy_setopt(j->curl, CURLOPT_HTTPHEADER, j->request_header) != CURLE_OK)
return -EIO;
}