]> git.ipfire.org Git - pakfire.git/commitdiff
package: Calculate digests
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 20 Sep 2021 11:15:58 +0000 (11:15 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 20 Sep 2021 11:15:58 +0000 (11:15 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/package.c
src/libpakfire/archive.c
src/libpakfire/db.c
src/libpakfire/include/pakfire/package.h
src/libpakfire/package.c

index b308dca0df3105f6b98a87c927f5e260a0f2c115..b6b4dc9c152cfe7a1b5abdd4f24fd25a96c168d0 100644 (file)
@@ -194,10 +194,16 @@ static void Package_set_uuid(PackageObject* self, PyObject* value) {
 }
 
 static PyObject* Package_get_hexdigest(PackageObject* self, enum pakfire_package_digests type) {
-       const char* hexdigest = pakfire_package_get_hexdigest(self->package, type);
+       enum pakfire_package_digests digest = PAKFIRE_PACKAGE_DIGEST_NONE;
+
+       const char* hexdigest = pakfire_package_get_hexdigest(self->package, &digest);
        if (!hexdigest)
                Py_RETURN_NONE;
 
+       // Is this the requested type?
+       if (digest != type)
+               Py_RETURN_NONE;
+
        return PyUnicode_FromString(hexdigest);
 }
 
index 38873a436b67f3a4add6aba34f74dcec2e102401..c58d1c0fe6e1fadf019def74717bfb029522d27c 100644 (file)
@@ -1870,12 +1870,99 @@ PAKFIRE_EXPORT ssize_t pakfire_archive_get_size(struct pakfire_archive* archive)
        return buf.st_size;
 }
 
+static int pakfire_archive_calculate_digest(struct pakfire_archive* archive,
+               enum pakfire_package_digests digest, unsigned char* output, size_t* length) {
+       int r = 1;
+
+       const EVP_MD* md = NULL;
+
+       // Select hash function
+       switch (digest) {
+               case PAKFIRE_PACKAGE_DIGEST_SHA512:
+                       md = EVP_sha512();
+                       break;
+
+               case PAKFIRE_PACKAGE_DIGEST_SHA256:
+                       md = EVP_sha256();
+                       break;
+
+               default:
+                       errno = ENOTSUP;
+                       return 1;
+       }
+
+       // Initialize context
+       EVP_MD_CTX* ctx = EVP_MD_CTX_new();
+       if (!ctx) {
+               ERROR(archive->pakfire, "Could not initialize EVP context: %m\n");
+               goto ERROR;
+       }
+
+       r = EVP_DigestInit_ex(ctx, md, NULL);
+       if (r != 1) {
+               ERROR(archive->pakfire, "EVP_DigestInit_ex failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               r = 1;
+               goto ERROR;
+       }
+
+       char buffer[64 * 1024];
+
+       // Feed archive into the hash functions
+       while (!feof(archive->f)) {
+               size_t bytes_read = fread(buffer, 1, sizeof(buffer), archive->f);
+
+               if (ferror(archive->f)) {
+                       ERROR(archive->pakfire, "Error reading from file: %m\n");
+                       goto ERROR;
+               }
+
+               r = EVP_DigestUpdate(ctx, buffer, bytes_read);
+               if (r != 1) {
+                       ERROR(archive->pakfire, "EVP_DigestUpdate failed: %s\n",
+                               ERR_error_string(ERR_get_error(), NULL));
+                       r = 1;
+                       goto ERROR;
+               }
+       }
+
+       // Finalise hash function
+       r = EVP_DigestFinal_ex(ctx, output, (unsigned int*)length);
+       if (r != 1) {
+               ERROR(archive->pakfire, "EVP_DigestFinal_ex failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               r = 1;
+               goto ERROR;
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       // Cleanup
+       if (ctx)
+               EVP_MD_CTX_free(ctx);
+
+       rewind(archive->f);
+
+       return r;
+}
+
 /*
        Copy all metadata from this archive to the package object
 */
 PAKFIRE_EXPORT int pakfire_archive_make_package(struct pakfire_archive* archive,
                struct pakfire_repo* repo, struct pakfire_package** package) {
        struct pakfire_repo* dummy = NULL;
+       unsigned char digest[EVP_MAX_MD_SIZE];
+       size_t digest_length = 0;
+       int r;
+
+       // Calculate digest
+       r = pakfire_archive_calculate_digest(archive, PAKFIRE_PACKAGE_DIGEST_SHA512,
+               digest, &digest_length);
+       if (r)
+               return r;
 
        // Use dummy repo if no repository was passed
        if (!repo) {
@@ -2063,6 +2150,9 @@ PAKFIRE_EXPORT int pakfire_archive_make_package(struct pakfire_archive* archive,
                pakfire_filelist_unref(filelist);
        }
 
+       // Set digests
+       pakfire_package_set_digest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA512, digest);
+
        *package = pkg;
 
        // Cleanup
index 445254f80659ad992f89565fd8d89ad524776e34..0dc703d382184e02155bea835fa76365da932daa 100644 (file)
@@ -1096,22 +1096,27 @@ int pakfire_db_add_package(struct pakfire_db* db,
                goto ROLLBACK;
        }
 
-       // Bind digest_sha512
-       const char* digest_sha512 = pakfire_package_get_hexdigest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA512);
+       enum pakfire_package_digests digest = PAKFIRE_PACKAGE_DIGEST_NONE;
 
-       r = sqlite3_bind_text(stmt, 8, digest_sha512, -1, NULL);
-       if (r) {
-               ERROR(db->pakfire, "Could not bind digest_sha512: %s\n", sqlite3_errmsg(db->handle));
-               goto ROLLBACK;
-       }
+       const char* hexdigest = pakfire_package_get_hexdigest(pkg, &digest);
+       switch (digest) {
+               case PAKFIRE_PACKAGE_DIGEST_SHA512:
+                       r = sqlite3_bind_text(stmt, 8, hexdigest, -1, NULL);
+                       if (r) {
+                               ERROR(db->pakfire, "Could not bind digest_sha512: %s\n", sqlite3_errmsg(db->handle));
+                               goto ROLLBACK;
+                       }
+                       break;
 
-       // Bind digest_sha256
-       const char* digest_sha256 = pakfire_package_get_hexdigest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA256);
+               case PAKFIRE_PACKAGE_DIGEST_SHA256:
+                       r = sqlite3_bind_text(stmt, 9, hexdigest, -1, NULL);
+                       if (r) {
+                               ERROR(db->pakfire, "Could not bind digest_sha256: %s\n", sqlite3_errmsg(db->handle));
+                               goto ROLLBACK;
+                       }
 
-       r = sqlite3_bind_text(stmt, 9, digest_sha256, -1, NULL);
-       if (r) {
-               ERROR(db->pakfire, "Could not bind digest_sha256: %s\n", sqlite3_errmsg(db->handle));
-               goto ROLLBACK;
+               case PAKFIRE_PACKAGE_DIGEST_NONE:
+                       break;
        }
 
        // Bind license
index 990f69243c2a3e3fa7034a8f456a92e2b86b537a..aebc85ef55ec61c13714aef7ad2c3bfb87193bd0 100644 (file)
@@ -31,8 +31,9 @@ struct pakfire_package;
 #include <pakfire/repo.h>
 
 enum pakfire_package_digests {
-       PAKFIRE_PACKAGE_DIGEST_SHA256,
-       PAKFIRE_PACKAGE_DIGEST_SHA512,
+       PAKFIRE_PACKAGE_DIGEST_NONE   = 0,
+       PAKFIRE_PACKAGE_DIGEST_SHA256 = 1 << 0,
+       PAKFIRE_PACKAGE_DIGEST_SHA512 = 1 << 1,
 };
 
 struct pakfire_package* pakfire_package_create(struct pakfire* pakfire, struct pakfire_repo* repo,
@@ -57,9 +58,9 @@ void pakfire_package_set_arch(struct pakfire_package* pkg, const char* arch);
 const char* pakfire_package_get_uuid(struct pakfire_package* pkg);
 void pakfire_package_set_uuid(struct pakfire_package* pkg, const char* uuid);
 const unsigned char* pakfire_package_get_digest(struct pakfire_package* pkg,
-       enum pakfire_package_digests type);
+       enum pakfire_package_digests* type);
 const char* pakfire_package_get_hexdigest(struct pakfire_package* pkg,
-       enum pakfire_package_digests type);
+       enum pakfire_package_digests* type);
 int pakfire_package_set_digest(struct pakfire_package* pkg,
        enum pakfire_package_digests type, const unsigned char* digest);
 int pakfire_package_set_hexdigest(struct pakfire_package* pkg,
index 0fcd6353c323e8532f6781ac2cc49a87f038ef92..beeeaf1bdbee4456897b57fe0acafd7442f457ad 100644 (file)
@@ -375,57 +375,72 @@ PAKFIRE_EXPORT void pakfire_package_set_uuid(struct pakfire_package* pkg, const
        pakfire_package_set_string(pkg, SOLVABLE_PKGID, uuid);
 }
 
-static Id pakfire_package_digest2id(enum pakfire_package_digests type) {
-       Id id = 0;
+static enum pakfire_package_digests pakfire_package_id2digest(Id id) {
+       switch (id) {
+               case REPOKEY_TYPE_SHA512:
+                       return PAKFIRE_PACKAGE_DIGEST_SHA512;
 
-       switch (type) {
-               case PAKFIRE_PACKAGE_DIGEST_SHA256:
-                       id = REPOKEY_TYPE_SHA256;
-                       break;
-
-               case PAKFIRE_PACKAGE_DIGEST_SHA512:
-                       id = REPOKEY_TYPE_SHA512;
-                       break;
+               case REPOKEY_TYPE_SHA256:
+                       return PAKFIRE_PACKAGE_DIGEST_SHA256;
        }
 
-       // Type is invalid
-       if (!id)
-               errno = EINVAL;
-
-       return id;
+       return PAKFIRE_PACKAGE_DIGEST_NONE;
 }
 
 PAKFIRE_EXPORT const unsigned char* pakfire_package_get_digest(
-               struct pakfire_package* pkg, enum pakfire_package_digests type) {
+               struct pakfire_package* pkg, enum pakfire_package_digests* type) {
        Solvable* s = get_solvable(pkg);
+       Id id;
 
-       Id id = pakfire_package_digest2id(type);
-       if (!id)
-               return NULL;
+       const unsigned char* checksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &id);
 
-       return solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &id);
+       // Convert ID to digest type
+       *type = pakfire_package_id2digest(id);
+       if (!*type) {
+               errno = ENOTSUP;
+               checksum = NULL;
+       }
+
+       return checksum;
 }
 
 PAKFIRE_EXPORT const char* pakfire_package_get_hexdigest(
-               struct pakfire_package* pkg, enum pakfire_package_digests type) {
+               struct pakfire_package* pkg, enum pakfire_package_digests* type) {
        Solvable* s = get_solvable(pkg);
+       Id id;
 
-       Id id = pakfire_package_digest2id(type);
-       if (!id)
-               return NULL;
+       const char* checksum = solvable_lookup_checksum(s, SOLVABLE_CHECKSUM, &id);
 
-       return solvable_lookup_checksum(s, SOLVABLE_CHECKSUM, &id);
+       // Convert ID to digest type
+       *type = pakfire_package_id2digest(id);
+       if (!*type) {
+               errno = ENOTSUP;
+               checksum = NULL;
+       }
+
+       return checksum;
 }
 
 PAKFIRE_EXPORT int pakfire_package_set_digest(struct pakfire_package* pkg,
                enum pakfire_package_digests type, const unsigned char* digest) {
        Solvable* s = get_solvable(pkg);
        Pool* pool = s->repo->pool;
+       Id id;
        int r = 1;
 
-       Id id = pakfire_package_digest2id(type);
-       if (!id)
-               return 1;
+       switch (type) {
+               case PAKFIRE_PACKAGE_DIGEST_SHA256:
+                       id = REPOKEY_TYPE_SHA256;
+                       break;
+
+               case PAKFIRE_PACKAGE_DIGEST_SHA512:
+                       id = REPOKEY_TYPE_SHA512;
+                       break;
+
+               default:
+                       errno = ENOTSUP;
+                       return 1;
+       }
 
        struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
 
@@ -446,11 +461,14 @@ ERROR:
 
 static size_t pakfire_package_digest_length(enum pakfire_package_digests digest) {
        switch (digest) {
+               case PAKFIRE_PACKAGE_DIGEST_SHA512:
+                       return 64;
+
                case PAKFIRE_PACKAGE_DIGEST_SHA256:
                        return 32;
 
-               case PAKFIRE_PACKAGE_DIGEST_SHA512:
-                       return 64;
+               case PAKFIRE_PACKAGE_DIGEST_NONE:
+                       return 0;
        }
 
        return 0;
@@ -554,13 +572,15 @@ PAKFIRE_EXPORT void pakfire_package_set_maintainer(struct pakfire_package* pkg,
 
 static int pakfire_package_make_cache_path(struct pakfire_package* pkg) {
        const char* filename = pakfire_package_get_filename(pkg);
-       const char* checksum = pakfire_package_get_hexdigest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA256);
 
-       if (!checksum || strlen(checksum) < 3)
+       enum pakfire_package_digests digest = PAKFIRE_PACKAGE_DIGEST_NONE;
+       const char* hexdigest = pakfire_package_get_hexdigest(pkg, &digest);
+
+       if (!hexdigest || strlen(hexdigest) < 3)
                return 1;
 
        return pakfire_make_cache_path(pkg->pakfire, pkg->path,
-               "%c%c/%s/%s", checksum[0], checksum[1], checksum + 2, filename);
+               "%c%c/%s/%s", hexdigest[0], hexdigest[1], hexdigest + 2, filename);
 }
 
 PAKFIRE_EXPORT const char* pakfire_package_get_path(struct pakfire_package* pkg) {
@@ -998,15 +1018,22 @@ PAKFIRE_EXPORT char* pakfire_package_dump(struct pakfire_package* pkg, int flags
                if (build_id)
                        pakfire_package_dump_add_line(&string, _("Build ID"), build_id);
 
-               // Digest SHA512
-               const char* digest_sha512 = pakfire_package_get_hexdigest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA512);
-               if (digest_sha512)
-                       pakfire_package_dump_add_line(&string, _("SHA512 Digest"), digest_sha512);
+               enum pakfire_package_digests digest = PAKFIRE_PACKAGE_DIGEST_NONE;
+
+               // Digest
+               const char* hexdigest = pakfire_package_get_hexdigest(pkg, &digest);
+               switch (digest) {
+                       case PAKFIRE_PACKAGE_DIGEST_SHA512:
+                               pakfire_package_dump_add_line(&string, _("SHA512 Digest"), hexdigest);
+                               break;
 
-               // Digest SHA256
-               const char* digest_sha256 = pakfire_package_get_hexdigest(pkg, PAKFIRE_PACKAGE_DIGEST_SHA256);
-               if (digest_sha256)
-                       pakfire_package_dump_add_line(&string, _("SHA256 Digest"), digest_sha256);
+                       case PAKFIRE_PACKAGE_DIGEST_SHA256:
+                               pakfire_package_dump_add_line(&string, _("SHA256 Digest"), hexdigest);
+                               break;
+
+                       case PAKFIRE_PACKAGE_DIGEST_NONE:
+                               break;
+               }
 
                // Build time
                time_t build_time = pakfire_package_get_build_time(pkg);