]> git.ipfire.org Git - pakfire.git/commitdiff
packager: Write checksums in mtree format
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 22 May 2021 12:32:17 +0000 (12:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 22 May 2021 12:32:17 +0000 (12:32 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/packager.c

index fcc730e6cd14adf192730a72e1b641549dc6c7b2..948aa360bf787de93741a1417a3896388dd4c0c5 100644 (file)
@@ -61,9 +61,77 @@ struct pakfire_packager {
        size_t installsize;
 };
 
+static int pakfire_packager_create_mtree(Pakfire pakfire, struct archive** mtree,
+               FILE** f, const char** fields) {
+       char path[] = "/tmp/.pakfire-mtree.XXXXXX";
+       int r;
+
+       // Create an mtree
+       *mtree = archive_write_new();
+       if (!*mtree) {
+               ERROR(pakfire, "archive_write_new() failed\n");
+               goto ERROR;
+       }
+
+       // Use mtree format
+       r = archive_write_set_format_mtree(*mtree);
+       if (r) {
+               ERROR(pakfire, "Could not set format to mtree: %s\n",
+                       archive_error_string(*mtree));
+               goto ERROR;
+       }
+
+       // Always compress using Zstd
+       r = archive_write_add_filter_zstd(*mtree);
+       if (r) {
+               ERROR(pakfire, "Could not enable Zstandard compression: %s\n",
+                       archive_error_string(*mtree));
+               goto ERROR;
+       }
+
+       // Enable mtree fields
+       if (fields) {
+               for (const char** field = fields; *field; field++) {
+                       r = archive_write_set_options(*mtree, *field);
+                       if (r) {
+                               ERROR(pakfire, "Could not set mtree options %s: %s\n",
+                                       *field, archive_error_string(*mtree));
+                               goto ERROR;
+                       }
+               }
+       }
+
+       // Create a new temporary file
+       *f = pakfire_mktemp(path);
+       if (!*f)
+               goto ERROR;
+
+       // Unlink the file straight away
+       unlink(path);
+
+       // Write mtree to file
+       r = archive_write_open_FILE(*mtree, *f);
+       if (r)
+               goto ERROR;
+
+       return 0;
+
+ERROR:
+       if (*mtree) {
+               archive_write_free(*mtree);
+               *mtree = NULL;
+       }
+
+       if (*f) {
+               fclose(*f);
+               *f = NULL;
+       }
+
+       return 1;
+}
+
 static int pakfire_packager_create_payload(struct pakfire_packager* p) {
-       char payload_path[] = "/tmp/.pakfire-payload.XXXXXX";
-       char mtree_path[] = "/tmp/.pakfire-mtree.XXXXXX";
+       char path[] = "/tmp/.pakfire-payload.XXXXXX";
 
        // Do not compress source packages
        const int compress = !pakfire_package_is_source(p->pkg);
@@ -108,41 +176,18 @@ static int pakfire_packager_create_payload(struct pakfire_packager* p) {
        }
 
        // Create a new temporary file
-       p->fpayload = pakfire_mktemp(payload_path);
+       p->fpayload = pakfire_mktemp(path);
        if (!p->fpayload)
                return 1;
 
        // Unlink the file straight away
-       unlink(payload_path);
+       unlink(path);
 
        // Write archive to file
        r = archive_write_open_FILE(p->payload, p->fpayload);
        if (r)
                return r;
 
-       // Create an mtree
-       p->mtree = archive_write_new();
-       if (!p->mtree) {
-               ERROR(p->pakfire, "archive_write_new() failed\n");
-               return 1;
-       }
-
-       // Use mtree format
-       r = archive_write_set_format_mtree(p->mtree);
-       if (r) {
-               ERROR(p->pakfire, "Could not set format to mtree: %s\n",
-                       archive_error_string(p->mtree));
-               return r;
-       }
-
-       // Always compress using Zstd
-       r = archive_write_add_filter_zstd(p->mtree);
-       if (r) {
-               ERROR(p->pakfire, "Could not enable Zstandard compression: %s\n",
-                       archive_error_string(p->mtree));
-               return r;
-       }
-
        static const char* mtree_fields[] = {
                // Disable the default
                "!all",
@@ -165,28 +210,12 @@ static int pakfire_packager_create_payload(struct pakfire_packager* p) {
                NULL,
        };
 
-       // Enable mtree fields
-       for (const char** field = mtree_fields; *field; field++) {
-               r = archive_write_set_options(p->mtree, *field);
-               if (r) {
-                       ERROR(p->pakfire, "Could not set mtree options %s: %s\n",
-                               *field, archive_error_string(p->mtree));
-                       return r;
-               }
-       }
-
-       // Create a new temporary file
-       p->fmtree = pakfire_mktemp(mtree_path);
-       if (!p->fmtree)
-               return 1;
-
-       // Unlink the file straight away
-       unlink(mtree_path);
-
-       // Write mtree to file
-       r = archive_write_open_FILE(p->mtree, p->fmtree);
-       if (r)
+       // Create an mtree
+       r = pakfire_packager_create_mtree(p->pakfire, &p->mtree, &p->fmtree, mtree_fields);
+       if (r) {
+               ERROR(p->pakfire, "Could not create mtree\n");
                return r;
+       }
 
        return 0;
 }
@@ -278,6 +307,8 @@ static int pakfire_packager_copy_data(struct pakfire_packager* packager,
                struct archive* a, FILE* f) {
        char buffer[BUFFER_SIZE];
 
+       rewind(f);
+
        while (!feof(f)) {
                // Read a block from file
                size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
@@ -333,7 +364,7 @@ static struct archive_entry* pakfire_packager_create_file(
 }
 
 static int pakfire_packager_write_file_from_buffer(struct pakfire_packager* packager,
-               struct archive* a, const char* filename, const char* buffer) {
+               struct archive* a, struct archive* mtree, const char* filename, const char* buffer) {
        size_t size = strlen(buffer);
 
        // Create a new file
@@ -345,28 +376,40 @@ static int pakfire_packager_write_file_from_buffer(struct pakfire_packager* pack
        int r = archive_write_header(a, entry);
        if (r) {
                ERROR(packager->pakfire, "Error writing header: %s\n", archive_error_string(a));
-               archive_entry_free(entry);
-               return r;
+               goto ERROR;
        }
 
        // Write content
        r = archive_write_data(a, buffer, strlen(buffer));
        if (r < 0) {
                ERROR(packager->pakfire, "Error writing data: %s\n", archive_error_string(a));
-               archive_entry_free(entry);
-               return r;
+               goto ERROR;
+       }
+
+       // Add this file to the mtree
+       if (mtree) {
+               r = archive_write_header(mtree, entry);
+               if (r) {
+                       ERROR(packager->pakfire, "Error adding file to mtree: %s\n",
+                               archive_error_string(mtree));
+                       goto ERROR;
+               }
        }
 
+       // Success
+       r = 0;
+
+ERROR:
        archive_entry_free(entry);
 
-       return 0;
+       return r;
 }
 
 static int pakfire_packager_write_format(struct pakfire_packager* packager,
                struct archive* a) {
        const char buffer[] = TO_STRING(PACKAGE_FORMAT) "\n";
 
-       int r = pakfire_packager_write_file_from_buffer(packager, a,
+       int r = pakfire_packager_write_file_from_buffer(packager, a, NULL,
                PAKFIRE_ARCHIVE_FN_FORMAT, buffer);
        if (r)
                return r;
@@ -578,7 +621,7 @@ ERROR:
 }
 
 static int pakfire_packager_write_metadata(struct pakfire_packager* packager,
-               struct archive* a) {
+               struct archive* a, struct archive* mtree) {
        // Make metadata
        char* buffer = pakfire_package_make_metadata(packager);
        if (!buffer)
@@ -587,7 +630,7 @@ static int pakfire_packager_write_metadata(struct pakfire_packager* packager,
        DEBUG(packager->pakfire, "Generated package metadata:\n%s", buffer);
 
        // Write buffer
-       int r = pakfire_packager_write_file_from_buffer(packager, a,
+       int r = pakfire_packager_write_file_from_buffer(packager, a, mtree,
                PAKFIRE_ARCHIVE_FN_METADATA, buffer);
 
        free(buffer);
@@ -596,7 +639,8 @@ static int pakfire_packager_write_metadata(struct pakfire_packager* packager,
 }
 
 static int pakfire_packager_write_archive(struct pakfire_packager* packager,
-               struct archive* a, const char* filename, struct archive** payload, FILE* f) {
+               struct archive* a, struct archive* mtree, const char* filename,
+               struct archive** payload, FILE* f) {
        struct stat st;
 
        // Close the payload
@@ -635,6 +679,23 @@ static int pakfire_packager_write_archive(struct pakfire_packager* packager,
        if (r)
                goto ERROR;
 
+       // Add this file to the mtree
+       if (mtree) {
+               r = archive_write_header(mtree, entry);
+               if (r) {
+                       ERROR(packager->pakfire, "Error adding file to mtree: %s\n",
+                               archive_error_string(mtree));
+                       goto ERROR;
+               }
+
+               r = pakfire_packager_copy_data(packager, mtree, f);
+               if (r) {
+                       ERROR(packager->pakfire, "Error copying data to mtree: %s\n",
+                               archive_error_string(mtree));
+                       goto ERROR;
+               }
+       }
+
        // Success
        r = 0;
 
@@ -650,6 +711,8 @@ ERROR:
        It will create a new archive and write the package to the given file descriptor.
 */
 PAKFIRE_EXPORT int pakfire_packager_finish(struct pakfire_packager* packager, FILE* f) {
+       struct archive* mtree = NULL;
+       FILE* fmtree = NULL;
        int r = 1;
 
        // Store total instal size
@@ -678,34 +741,88 @@ PAKFIRE_EXPORT int pakfire_packager_finish(struct pakfire_packager* packager, FI
                goto ERROR;
        }
 
+       static const char* mtree_fields[] = {
+               // Disable everything
+               "!all",
+
+               // Include the file size
+               "size",
+
+               // Add the checksums
+               "sha512",
+               "sha256",
+
+               NULL,
+       };
+
+       // Create an mtree for the checksums
+       r = pakfire_packager_create_mtree(packager->pakfire, &mtree, &fmtree, mtree_fields);
+       if (r) {
+               ERROR(packager->pakfire, "Could not create mtree\n");
+               goto ERROR;
+       }
+
        // Start with the format file
        r = pakfire_packager_write_format(packager, a);
-       if (r)
+       if (r) {
+               ERROR(packager->pakfire, "Could not add format file to archive: %s\n",
+                       archive_error_string(a));
                goto ERROR;
+       }
 
        // Write the metadata
-       r = pakfire_packager_write_metadata(packager, a);
-       if (r)
+       r = pakfire_packager_write_metadata(packager, a, mtree);
+       if (r) {
+               ERROR(packager->pakfire, "Could not add metadata file to archive: %s\n",
+                       archive_error_string(a));
                goto ERROR;
+       }
 
        // Write the filelist in mtree format
-       r = pakfire_packager_write_archive(packager, a, PAKFIRE_ARCHIVE_FN_FILELIST,
+       r = pakfire_packager_write_archive(packager, a, mtree, PAKFIRE_ARCHIVE_FN_FILELIST,
                &packager->mtree, packager->fmtree);
-       if (r)
+       if (r) {
+               ERROR(packager->pakfire, "Could not add filelist to archive: %s\n",
+                       archive_error_string(a));
                goto ERROR;
+       }
 
        // Write the payload
-       r = pakfire_packager_write_archive(packager, a, PAKFIRE_ARCHIVE_FN_PAYLOAD,
+       r = pakfire_packager_write_archive(packager, a, mtree, PAKFIRE_ARCHIVE_FN_PAYLOAD,
                &packager->payload, packager->fpayload);
-       if (r)
+       if (r) {
+               ERROR(packager->pakfire, "Could not add payload to archive: %s\n",
+                       archive_error_string(a));
                goto ERROR;
+       }
+
+       // Finish checksums
+       r = archive_write_finish_entry(mtree);
+       if (r) {
+               ERROR(packager->pakfire, "Could not finish mtree: %s\n",
+                       archive_error_string(mtree));
+               goto ERROR;
+       }
+
+       // Write the payload
+       r = pakfire_packager_write_archive(packager, a, NULL, PAKFIRE_ARCHIVE_FN_CHECKSUMS,
+               &mtree, fmtree);
+       if (r) {
+               ERROR(packager->pakfire, "Could not add checksums to archive: %s\n",
+                       archive_error_string(a));
+               goto ERROR;
+       }
 
        // Success
        r = 0;
 
 ERROR:
        if (a)
-               archive_free(a);
+               archive_write_free(a);
+       if (mtree)
+               archive_write_free(mtree);
+       if (fmtree)
+               fclose(fmtree);
 
        return r;
 }