]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Compute BLAKE2 checksum when extracting files
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 7 Mar 2021 23:56:59 +0000 (23:56 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 7 Mar 2021 23:56:59 +0000 (23:56 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/include/pakfire/util.h
src/libpakfire/util.c

index b41d769181ba0e8c6a9318c064989d043280ec58..eb05acb3e4a1519995f42245923e3094a71f9877 100644 (file)
@@ -617,35 +617,76 @@ PAKFIRE_EXPORT char* pakfire_archive_get(PakfireArchive archive, const char* nam
        return pakfire_parser_get(archive->parser, namespace, key);
 }
 
-static int archive_copy_data(Pakfire pakfire, struct archive* in, struct archive* out) {
-       int r;
-       const void* buff;
+static int archive_copy_data(Pakfire pakfire, struct archive* in, struct archive* out,
+               char** hexdigest) {
+       EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
+
+       // Initialize digest
+       int r = EVP_DigestInit_ex(mdctx, EVP_blake2s256(), NULL);
+       if (r != 1) {
+               ERROR(pakfire, "Could not setup digest function: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               r = 1;
+               goto ERROR;
+       }
 
+       const void* buffer;
        size_t size;
        off_t offset;
 
        for (;;) {
-               r = archive_read_data_block(in, &buff, &size, &offset);
+               // Read a block of data
+               r = archive_read_data_block(in, &buffer, &size, &offset);
                if (r == ARCHIVE_EOF)
                        break;
 
                if (r != ARCHIVE_OK) {
                        ERROR(pakfire, "Could not read data from archive: %s\n",
                                archive_error_string(in));
+                       goto ERROR;
+               }
 
-                       return r;
+               // Update digest
+               r = EVP_DigestUpdate(mdctx, buffer, size);
+               if (r != 1) {
+                       ERROR(pakfire, "EVP_DigestUpdate failed: %s\n",
+                               ERR_error_string(ERR_get_error(), NULL));
+                       r = 1;
+                       goto ERROR;
                }
 
-               r = archive_write_data_block(out, buff, size, offset);
+               // Write the data
+               r = archive_write_data_block(out, buffer, size, offset);
                if (r != ARCHIVE_OK) {
                        ERROR(pakfire, "Could not write data to disk: %s\n",
                                archive_error_string(out));
-
-                       return r;
+                       goto ERROR;
                }
        }
 
-       return 0;
+       char digest[EVP_MAX_MD_SIZE];
+       size_t digest_length;
+
+       // Finalize the digest
+       r = EVP_DigestFinal_ex(mdctx, (unsigned char*)digest, (unsigned int*)&digest_length);
+       if (r != 1) {
+               ERROR(pakfire, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+               goto ERROR;
+       }
+
+       // Convert to hex
+       *hexdigest = pakfire_hexlify(digest, digest_length);
+
+       DEBUG(pakfire, "Computed digest of %zu bytes: %s\n", digest_length, *hexdigest);
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (mdctx)
+               EVP_MD_CTX_free(mdctx);
+
+       return r;
 }
 
 static int archive_extract(Pakfire pakfire, struct archive* a, const char* prefix) {
@@ -698,6 +739,8 @@ static int archive_extract(Pakfire pakfire, struct archive* a, const char* prefi
                        free(h);
                }
 
+               char* hexdigest = NULL;
+
                // Create file
                r = archive_write_header(ext, entry);
                if (r != ARCHIVE_OK) {
@@ -708,7 +751,7 @@ static int archive_extract(Pakfire pakfire, struct archive* a, const char* prefi
 
                // Copy payload
                if (size > 0) {
-                       r = archive_copy_data(pakfire, a, ext);
+                       r = archive_copy_data(pakfire, a, ext, &hexdigest);
                        if (r != ARCHIVE_OK)
                                break;
                }
@@ -735,6 +778,9 @@ static int archive_extract(Pakfire pakfire, struct archive* a, const char* prefi
                                break;
                }
 
+               if (hexdigest)
+                       free(hexdigest);
+
                if (r != ARCHIVE_OK)
                        break;
        }
index c4ef1bf3fc8267f4db8e46080132edac5298cf6b..2deb4faad3a052c9f459c72374db1282428c4266 100644 (file)
@@ -61,6 +61,8 @@ char* pakfire_generate_uuid();
 int pakfire_string_endswith(const char* s, const char* suffix);
 char* pakfire_lstrip(const char* s);
 
+char* pakfire_hexlify(const char* digest, const size_t length);
+
 #endif
 
 #endif /* PAKFIRE_UTIL_H */
index 9f0b054ac1299a4cd5d1a660c7392b70df1460ed..e4daba7f397c9b67194ee44bc46629500f93cc1e 100644 (file)
@@ -476,3 +476,23 @@ PAKFIRE_EXPORT char* pakfire_generate_uuid() {
 
        return ret;
 }
+
+char* pakfire_hexlify(const char* digest, const size_t length) {
+       const char* hexdigits = "0123456789abcdef";
+
+       char* s = malloc((length * 2) + 1);
+       if (!s)
+               return NULL;
+
+       for (unsigned int i = 0, j = 0; i < length; i++) {
+               char b = digest[i];
+
+               s[j++] = hexdigits[(b >> 4) & 0xf];
+               s[j++] = hexdigits[(b & 0x0f)];
+       }
+
+       // Terminate result
+       s[length * 2] = '\0';
+
+       return s;
+}