]> git.ipfire.org Git - people/ms/pakfire.git/commitdiff
walk: Attempt to create some common function to walk through archives
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 1 Sep 2022 19:04:40 +0000 (19:04 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 1 Sep 2022 19:04:40 +0000 (19:04 +0000)
We are (re-)implementing this over and over again with different, but
very similar features, so it might make a lot more sense to try to unify
this code.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/compress.c
src/libpakfire/include/pakfire/compress.h

index d763a20dfb685c9442119339369b4d7cc546b246..1bc9776bbb1d2738626bda9aae599779a4cc54ee 100644 (file)
@@ -135,61 +135,9 @@ ERROR:
        return r;
 }
 
-static int pakfire_archive_walk_entries(struct pakfire_archive* archive, struct archive* a,
-               int (*callback)(struct pakfire_archive* archive, struct archive* a,
-                       struct archive_entry* e, void* data),
-               int (*filter_callback)(struct pakfire_archive* archive, struct archive* a,
-                       struct archive_entry* e, void* data),
-               void* data) {
-       struct archive_entry* e = NULL;
-
-       // Walk through the archive
-       while (1) {
-               int r = archive_read_next_header(a, &e);
-
-               // Return OK when we reached the end of the archive
-               if (r == ARCHIVE_EOF)
-                       return ARCHIVE_OK;
-
-               // Raise any other errors
-               else if (r)
-                       return r;
-
-               // Call the filter callback before we call the actual callback
-               if (filter_callback) {
-                       r = filter_callback(archive, a, e, data);
-
-                       // End processing the archive if the filter callback asked us to
-                       if (r == ARCHIVE_EOF)
-                               break;
-
-                       // Skip this file
-                       else if (r == ARCHIVE_RETRY)
-                               continue;
-
-                       // Raise any errors
-                       else if (r)
-                               return r;
-               }
-
-               // Run callback
-               if (callback) {
-                       r = callback(archive, a, e, data);
-                       if (r)
-                               return r;
-               }
-       }
-
-       return 0;
-}
-
 static int pakfire_archive_walk(struct pakfire_archive* archive,
-               int (*callback)(struct pakfire_archive* archive, struct archive* a,
-                       struct archive_entry* e, void* data),
-               int (*filter_callback)(struct pakfire_archive* archive, struct archive* a,
-                       struct archive_entry* e, void* data),
-               void* data) {
-       struct archive* a;
+               pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback, void* data) {
+       struct archive* a = NULL;
 
        // Open the archive file
        int r = open_archive(archive, &a);
@@ -197,10 +145,11 @@ static int pakfire_archive_walk(struct pakfire_archive* archive,
                return r;
 
        // Walk through the archive
-       r = pakfire_archive_walk_entries(archive, a, callback, filter_callback, data);
+       r = pakfire_walk(archive->pakfire, a, callback, filter_callback, data);
 
        // Close the archive
-       close_archive(archive, a);
+       if (a)
+               close_archive(archive, a);
 
        return r;
 }
@@ -512,8 +461,10 @@ static int pakfire_archive_parse_scriptlet(struct pakfire_archive* archive,
        return 0;
 }
 
-static int __pakfire_archive_read_metadata(struct pakfire_archive* archive,
-               struct archive* a, struct archive_entry* entry, void* p) {
+static int __pakfire_archive_read_metadata(struct pakfire* pakfire, struct archive* a,
+               struct archive_entry* entry, void* p) {
+       struct pakfire_archive* archive = (struct pakfire_archive*)p;
+
        char* data = NULL;
        size_t length = 0;
        int r;
@@ -572,8 +523,10 @@ ERROR:
        return r;
 }
 
-static int __pakfire_archive_filter_metadata(struct pakfire_archive* archive,
-               struct archive* a, struct archive_entry* entry, void* data) {
+static int __pakfire_archive_filter_metadata(struct pakfire* pakfire,
+               struct archive* a, struct archive_entry* entry, void* p) {
+       struct pakfire_archive* archive = (struct pakfire_archive*)p;
+
        const char* path = archive_entry_pathname(entry);
 
        // Format >= 6
@@ -765,13 +718,17 @@ ERROR:
 }
 
 struct pakfire_archive_read {
+       struct pakfire_archive* archive;
        const char* path;
        char** data;
        size_t* length;
 };
 
-static int __pakfire_archive_filter_payload(struct pakfire_archive* archive,
-               struct archive* a, struct archive_entry* entry, void* data) {
+static int __pakfire_archive_filter_payload(struct pakfire* pakfire,
+               struct archive* a, struct archive_entry* entry, void* p) {
+       struct pakfire_archive_read* _read = (struct pakfire_archive_read*)p;
+       struct pakfire_archive* archive = _read->archive;
+
        const char* path = NULL;
 
        // Format >= 6
@@ -787,15 +744,15 @@ static int __pakfire_archive_filter_payload(struct pakfire_archive* archive,
        return ARCHIVE_OK;
 }
 
-static int __pakfire_archive_read_payload(struct pakfire_archive* archive,
-               struct archive* a, struct archive_entry* entry, void* data) {
-       struct pakfire_archive_read* _read = (struct pakfire_archive_read*)data;
+static int __pakfire_archive_read_payload(struct pakfire* pakfire,
+               struct archive* a, struct archive_entry* entry, void* p) {
+       struct pakfire_archive_read* _read = (struct pakfire_archive_read*)p;
        int r;
 
        const char* path = archive_entry_pathname(entry);
 
        if (strcmp(_read->path, path) == 0) {
-               r = pakfire_archive_copy_data_to_buffer(archive->pakfire, a, entry,
+               r = pakfire_archive_copy_data_to_buffer(pakfire, a, entry,
                        _read->data, _read->length);
                if (r)
                        return r;
index c05a538032b1ae75fccd51a9dab7f010ad98ae07..5eca7616065e9475df25a40c7c4974ce9e4aeb44 100644 (file)
@@ -518,6 +518,78 @@ ERROR:
        return NULL;
 }
 
+/*
+       Helper function to conditionally walk through an archive
+       and perform actions based on the callback.
+*/
+int pakfire_walk(struct pakfire* pakfire, struct archive* archive,
+               pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback,
+               void* p) {
+       struct archive_entry* entry = NULL;
+       int r;
+
+       // Walk through the archive
+       for (;;) {
+               r = archive_read_next_header(archive, &entry);
+
+               // Handle the return code
+               switch (r) {
+                       // Return OK when we reached the end of the archive
+                       case ARCHIVE_EOF:
+                               return 0;
+
+                       // Raise any other errors
+                       default:
+                               return r;
+               }
+
+               // Call the filter callback before we call the actual callback
+               if (filter_callback) {
+                       r = filter_callback(pakfire, archive, entry, p);
+
+                       // Handle the return code
+                       switch (r) {
+                               case PAKFIRE_WALK_OK:
+                                       break;
+
+                               case PAKFIRE_WALK_DONE:
+                                       DEBUG(pakfire, "Filter callback sent DONE\n");
+                                       return 0;
+
+                               case PAKFIRE_WALK_SKIP:
+                                       DEBUG(pakfire, "Filter callback sent SKIP\n");
+                                       continue;
+
+                               // Raise any other errors
+                               default:
+                                       DEBUG(pakfire, "Filter callback received an error: %d\n", r);
+                                       return r;
+                       }
+               }
+
+               // Run callback
+               if (callback) {
+                       r = callback(pakfire, archive, entry, p);
+
+                       // Handle the return code
+                       switch (r) {
+                               case PAKFIRE_WALK_OK:
+                                       break;
+
+                               case PAKFIRE_WALK_DONE:
+                                       DEBUG(pakfire, "Callback sent DONE\n");
+                                       return 0;
+
+                               // Raise any other errors
+                               default:
+                                       return r;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 // Common extraction
 
 struct pakfire_extract {
index 9ade14a2046e671fb2fe229bf17da3b622c75bea..b3c3629a690bec8fb67ca0807e75d5ec63ee7af0 100644 (file)
@@ -36,6 +36,26 @@ FILE* pakfire_xzfopen(FILE* f, const char* mode);
 // ZSTD
 FILE* pakfire_zstdfopen(FILE* f, const char* mode);
 
+// Walk
+
+typedef int (*pakfire_walk_callback)
+       (struct pakfire* pakfire, struct archive* a, struct archive_entry* e, void* p);
+typedef int (*pakfire_walk_filter_callback)
+       (struct pakfire* pakfire, struct archive* a, struct archive_entry* e, void* p);
+
+enum pakfire_walk_codes {
+       PAKFIRE_WALK_OK    = 0,
+
+       // After this code has been sent, we will not process any further entries
+       PAKFIRE_WALK_DONE  = -10,
+
+       // Request the next entry (only in filter callback)
+       PAKFIRE_WALK_SKIP  = -20,
+};
+
+int pakfire_walk(struct pakfire* pakfire, struct archive* archive,
+       pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback, void* p);
+
 // Extract
 enum pakfire_extract_flags {
        PAKFIRE_EXTRACT_DRY_RUN         = (1 << 0),