import-job.c revision 7079cfeffb6d520f20ddff53fd78467e72e6cc94
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering This file is part of systemd.
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering Copyright 2015 Lennart Poettering
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering systemd is free software; you can redistribute it and/or modify it
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering under the terms of the GNU Lesser General Public License as published by
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering (at your option) any later version.
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering systemd is distributed in the hope that it will be useful, but
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering Lesser General Public License for more details.
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering You should have received a copy of the GNU Lesser General Public License
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2b442ac87838be7c326c984d8751c96dee7258abLennart PoetteringImportJob* import_job_unref(ImportJob *j) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering curl_glue_remove_and_free(j->glue, j->curl);
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering else if (j->compressed == IMPORT_JOB_GZIP)
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering else if (j->compressed == IMPORT_JOB_BZIP2)
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poetteringstatic void import_job_finish(ImportJob *j, int ret) {
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_info("Download of %s complete.", j->url);
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poetteringvoid import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &j) != CURLE_OK)
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering if (!j || j->state == IMPORT_JOB_DONE || j->state == IMPORT_JOB_FAILED)
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_error("Transfer failed: %s", curl_easy_strerror(result));
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_info("Image already downloaded. Skipping download.");
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_error("HTTP request to %s failed with code %li.", j->url, status);
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_error("HTTP request to %s finished with unexpected code %li.", j->url, status);
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering log_error("Premature connection termination.");
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering if (j->content_length != (uint64_t) -1 &&
a3db237b8f1b97867395e1419f39b8ba5749b777Lennart Poettering j->content_length != j->written_compressed) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering k = gcry_md_read(j->checksum_context, GCRY_MD_SHA256);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering j->checksum = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256));
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering log_debug("SHA256 of %s is %s.", j->url, j->checksum);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->disk_fd >= 0 && j->allow_sparse) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering /* Make sure the file size is right, in case the file was
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering * sparse and we just seeked for the last part */
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (ftruncate(j->disk_fd, j->written_uncompressed) < 0) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering log_error_errno(errno, "Failed to truncate file: %m");
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering (void) fsetxattr(j->disk_fd, "user.source_etag", j->etag, strlen(j->etag), 0);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering (void) fsetxattr(j->disk_fd, "user.source_url", j->url, strlen(j->url), 0);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->mtime != 0) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering (void) fd_setcrtime(j->disk_fd, j->mtime);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poetteringstatic int import_job_write_uncompressed(ImportJob *j, void *p, size_t sz) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->written_uncompressed + sz < j->written_uncompressed) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->written_uncompressed + sz > j->uncompressed_max) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering log_error("File overly large, refusing");
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering log_error_errno(errno, "Failed to write file: %m");
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz))
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering memcpy(j->payload + j->payload_size, p, sz);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poetteringstatic int import_job_write_compressed(ImportJob *j, void *p, size_t sz) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->written_compressed + sz < j->written_compressed) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->written_compressed + sz > j->compressed_max) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering log_error("File overly large, refusing.");
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (j->content_length != (uint64_t) -1 &&
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering j->written_compressed + sz > j->content_length) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering gcry_md_write(j->checksum_context, p, sz);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering r = import_job_write_uncompressed(j, p, sz);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering if (lzr != LZMA_OK && lzr != LZMA_STREAM_END) {
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->xz.avail_out);
2b442ac87838be7c326c984d8751c96dee7258abLennart Poettering r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->gzip.avail_out);
72667f0890372a952a7c5b8cc498ec3cf9440973Lennart Poettering r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->bzip2.avail_out);
72667f0890372a952a7c5b8cc498ec3cf9440973Lennart Poettering assert_not_reached("Unknown compression");
2b442ac87838be7c326c984d8751c96dee7258abLennart Poetteringstatic int import_job_open_disk(ImportJob *j) {
if (j->disk_fd >= 0) {
j->allow_sparse = true;
j->allow_sparse = false;
if (j->calc_checksum) {
return -EIO;
assert(j);
sizeof(gzip_signature),
sizeof(bzip2_signature)))
return -EIO;
if (r != Z_OK) {
return -EIO;
if (r != BZ_OK) {
return -EIO;
r = import_job_open_disk(j);
j->payload_size = 0;
j->payload_allocated = 0;
static size_t import_job_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
assert(j);
switch (j->state) {
case IMPORT_JOB_ANALYZING:
r = log_oom();
goto fail;
r = import_job_detect_compression(j);
goto fail;
case IMPORT_JOB_RUNNING:
goto fail;
case IMPORT_JOB_DONE:
case IMPORT_JOB_FAILED:
r = -ESTALE;
goto fail;
return sz;
fail:
import_job_finish(j, r);
static size_t import_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
char *etag;
assert(j);
r = -ESTALE;
goto fail;
log_oom();
goto fail;
j->etag_exists = true;
import_job_finish(j, 0);
return sz;
return sz;
log_oom();
goto fail;
r = -EFBIG;
goto fail;
return sz;
log_oom();
goto fail;
return sz;
if (j->on_header) {
goto fail;
return sz;
fail:
import_job_finish(j, r);
static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
unsigned percent;
usec_t n;
assert(j);
if (dltotal <= 0)
char y[FORMAT_BYTES_MAX];
j->url,
j->last_status_usec = n;
if (j->on_progress)
j->on_progress(j);
return -ENOMEM;
if (!j->url)
return -ENOMEM;
*ret = j;
j = NULL;
assert(j);
return -EBUSY;
if (!cc)
return -ENOMEM;
if (!hdr)
return -ENOMEM;
if (!j->request_header) {
if (!j->request_header)
return -ENOMEM;
struct curl_slist *l;
return -ENOMEM;
j->request_header = l;
if (j->request_header) {
return -EIO;
return -EIO;
return -EIO;
return -EIO;
return -EIO;
return -EIO;
return -EIO;
return -EIO;