chiark / gitweb /
import: add image verification using gpg
[elogind.git] / src / import / import-job.c
index 5a4ea69cb205c9f6ac3610d5887dc153410a85d0..6de32686c5003533f5a8ec3eed1fd97c20ea1038 100644 (file)
@@ -38,10 +38,14 @@ ImportJob* import_job_unref(ImportJob *j) {
         else if (j->compressed == IMPORT_JOB_GZIP)
                 inflateEnd(&j->gzip);
 
+        if (j->hash_context)
+                gcry_md_close(j->hash_context);
+
         free(j->url);
         free(j->etag);
         strv_free(j->old_etags);
         free(j->payload);
+        free(j->sha256);
 
         free(j);
 
@@ -57,9 +61,10 @@ static void import_job_finish(ImportJob *j, int ret) {
             j->state == IMPORT_JOB_FAILED)
                 return;
 
-        if (ret == 0)
+        if (ret == 0) {
                 j->state = IMPORT_JOB_DONE;
-        else {
+                log_info("Download of %s complete.", j->url);
+        } else {
                 j->state = IMPORT_JOB_FAILED;
                 j->error = ret;
         }
@@ -93,6 +98,7 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
                 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) {
@@ -118,6 +124,25 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
                 goto finish;
         }
 
+        if (j->hash_context) {
+                uint8_t *k;
+
+                k = gcry_md_read(j->hash_context, GCRY_MD_SHA256);
+                if (!k) {
+                        log_error("Failed to get checksum.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                j->sha256 = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256));
+                if (!j->sha256) {
+                        r = log_oom();
+                        goto finish;
+                }
+
+                log_debug("SHA256 of %s is %s.", j->url, j->sha256);
+        }
+
         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 */
@@ -150,14 +175,12 @@ finish:
         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 (j->written_uncompressed + sz < j->written_uncompressed) {
                 log_error("File too large, overflow");
@@ -203,7 +226,6 @@ static int import_job_write_compressed(ImportJob *j, void *p, size_t sz) {
         assert(j);
         assert(p);
         assert(sz > 0);
-        assert(j->disk_fd >= 0);
 
         if (j->written_compressed + sz < j->written_compressed) {
                 log_error("File too large, overflow");
@@ -221,6 +243,9 @@ static int import_job_write_compressed(ImportJob *j, void *p, size_t sz) {
                 return -EFBIG;
         }
 
+        if (j->hash_context)
+                gcry_md_write(j->hash_context, p, sz);
+
         switch (j->compressed) {
 
         case IMPORT_JOB_UNCOMPRESSED:
@@ -310,6 +335,13 @@ static int import_job_open_disk(ImportJob *j) {
                 }
         }
 
+        if (j->calc_hash) {
+                if (gcry_md_open(&j->hash_context, GCRY_MD_SHA256, 0) != 0) {
+                        log_error("Failed to initialize hash context.");
+                        return -EIO;
+                }
+        }
+
         return 0;
 }
 
@@ -368,6 +400,7 @@ static int import_job_detect_compression(ImportJob *j) {
 
         j->payload = NULL;
         j->payload_size = 0;
+        j->payload_allocated = 0;
 
         j->state = IMPORT_JOB_RUNNING;
 
@@ -457,6 +490,7 @@ static size_t import_job_header_callback(void *contents, size_t size, size_t nme
 
                 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;
                 }
@@ -481,7 +515,7 @@ static size_t import_job_header_callback(void *contents, size_t size, size_t nme
                                 goto fail;
                         }
 
-                        log_info("Downloading %s.", format_bytes(bytes, sizeof(bytes), j->content_length));
+                        log_info("Downloading %s for %s.", format_bytes(bytes, sizeof(bytes), j->content_length), j->url);
                 }
 
                 return sz;
@@ -518,7 +552,8 @@ static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl
         n = now(CLOCK_MONOTONIC);
 
         if (n > j->last_status_usec + USEC_PER_SEC &&
-            percent != j->progress_percent) {
+            percent != j->progress_percent &&
+            dlnow < dltotal) {
                 char buf[FORMAT_TIMESPAN_MAX];
 
                 if (n - j->start_usec > USEC_PER_SEC && dlnow > 0) {