]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
filelists: Refactor the entire module
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 21 Feb 2023 16:04:57 +0000 (16:04 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 21 Feb 2023 16:04:57 +0000 (16:04 +0000)
This carries some changes that will allow us more flexibility with
filelists as they are now based on a slightly easier to manage data
structure.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/filelist.c

index eb5e92623bee5df1a8f98aa022871b865fee3232..82df96fd2cebff8dc9683ad5fef9e64fb7aa401e 100644 (file)
@@ -23,6 +23,7 @@
 #include <fts.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/queue.h>
 
 #include <archive.h>
 
 #include <pakfire/string.h>
 #include <pakfire/util.h>
 
+struct pakfire_filelist_element {
+       TAILQ_ENTRY(pakfire_filelist_element) nodes;
+
+       struct pakfire_file* file;
+};
+
 struct pakfire_filelist {
        struct pakfire* pakfire;
        int nrefs;
 
-       struct pakfire_file** elements;
-       size_t elements_size;
-
-       size_t size;
+       TAILQ_HEAD(entries, pakfire_filelist_element) files;
 };
 
-static int pakfire_filelist_grow(struct pakfire_filelist* list, size_t size) {
-       struct pakfire_file** elements = reallocarray(list->elements,
-               list->elements_size + size, sizeof(*list->elements));
-       if (!elements)
-               return -errno;
-
-       list->elements = elements;
-       list->elements_size += size;
-
-       return 0;
-}
-
 PAKFIRE_EXPORT int pakfire_filelist_create(struct pakfire_filelist** list, struct pakfire* pakfire) {
        struct pakfire_filelist* l = calloc(1, sizeof(*l));
        if (!l)
@@ -66,6 +58,9 @@ PAKFIRE_EXPORT int pakfire_filelist_create(struct pakfire_filelist** list, struc
        l->pakfire = pakfire_ref(pakfire);
        l->nrefs = 1;
 
+       // Initialise files
+       TAILQ_INIT(&l->files);
+
        *list = l;
        return 0;
 }
@@ -91,76 +86,96 @@ PAKFIRE_EXPORT struct pakfire_filelist* pakfire_filelist_unref(struct pakfire_fi
 }
 
 PAKFIRE_EXPORT size_t pakfire_filelist_size(struct pakfire_filelist* list) {
-       return list->size;
+       struct pakfire_filelist_element* element = NULL;
+       size_t size = 0;
+
+       TAILQ_FOREACH(element, &list->files, nodes)
+               size++;
+
+       return size;
 }
 
 size_t pakfire_filelist_total_size(struct pakfire_filelist* list) {
-       struct pakfire_file* file = NULL;
+       struct pakfire_filelist_element* element = NULL;
        size_t size = 0;
 
-       for (unsigned int i = 0; i < list->size; i++) {
-               file = list->elements[i];
-
-               size += pakfire_file_get_size(file);
-       }
+       TAILQ_FOREACH(element, &list->files, nodes)
+               size += pakfire_file_get_size(element->file);
 
        return size;
 }
 
 PAKFIRE_EXPORT int pakfire_filelist_is_empty(struct pakfire_filelist* list) {
-       return list->size == 0;
+       return TAILQ_EMPTY(&list->files);
 }
 
 PAKFIRE_EXPORT void pakfire_filelist_clear(struct pakfire_filelist* list) {
-       if (!list->elements)
-               return;
+       struct pakfire_filelist_element* element = NULL;
+
+       while (!TAILQ_EMPTY(&list->files)) {
+               // Fetch the first element
+               element = TAILQ_FIRST(&list->files);
 
-       for (unsigned int i = 0; i < list->size; i++)
-               pakfire_file_unref(list->elements[i]);
+               // Remove it from the list
+               TAILQ_REMOVE(&list->files, element, nodes);
 
-       free(list->elements);
-       list->elements = NULL;
-       list->elements_size = 0;
+               // Dereference the file
+               pakfire_file_unref(element->file);
 
-       list->size = 0;
+               // Free it all
+               free(element);
+       }
 }
 
 PAKFIRE_EXPORT struct pakfire_file* pakfire_filelist_get(struct pakfire_filelist* list, size_t index) {
-       if (index >= list->size)
-               return NULL;
+       struct pakfire_filelist_element* element = NULL;
+
+       // Fetch the first element
+       element = TAILQ_FIRST(&list->files);
+
+       while (element && index--)
+               element = TAILQ_NEXT(element, nodes);
 
-       return pakfire_file_ref(list->elements[index]);
+       return pakfire_file_ref(element->file);
 }
 
 PAKFIRE_EXPORT int pakfire_filelist_append(struct pakfire_filelist* list, struct pakfire_file* file) {
-       if (!file)
-               return EINVAL;
+       struct pakfire_filelist_element* element = NULL;
+       struct pakfire_filelist_element* e = NULL;
 
-       // Check if we have any space left
-       if (list->size >= list->elements_size) {
-               int r = pakfire_filelist_grow(list, 64);
-               if (r)
-                       return r;
+       // Allocate a new element
+       element = calloc(1, sizeof *element);
+       if (!element) {
+               ERROR(list->pakfire, "Could not allocate a new filelist element: %m\n");
+               return 1;
        }
 
-       list->elements[list->size++] = pakfire_file_ref(file);
+       // Reference the file
+       element->file = pakfire_file_ref(file);
 
-       return 0;
-}
+       // Fetch the last element
+       e = TAILQ_LAST(&list->files, entries);
 
-static int __sort(const void* ptr1, const void* ptr2) {
-       struct pakfire_file* file1 = (struct pakfire_file*)ptr1;
-       struct pakfire_file* file2 = (struct pakfire_file*)ptr2;
+       // Skip all elements that are "greater than" the element we want to add
+       while (e) {
+               if (pakfire_file_cmp(e->file, file) > 0)
+                       break;
+
+               e = TAILQ_PREV(e, entries, nodes);
+       }
 
-       return pakfire_file_cmp(file1, file2);
+       // If we found an element on the list, we will append after it,
+       // otherwise we add right at the start.
+       if (e)
+               TAILQ_INSERT_AFTER(&list->files, e, element, nodes);
+       else
+               TAILQ_INSERT_HEAD(&list->files, element, nodes);
+
+       return 0;
 }
 
 PAKFIRE_EXPORT void pakfire_filelist_sort(struct pakfire_filelist* list) {
-       // Nothing to do on empty list
-       if (pakfire_filelist_is_empty(list))
-               return;
-
-       qsort(list->elements, list->size, sizeof(*list->elements), __sort);
+       return; // XXX NOOP - filelists are now always sorted
 }
 
 // Returns true if s contains globbing characters
@@ -331,9 +346,6 @@ int pakfire_filelist_scan(struct pakfire_filelist* list, const char* root,
                pakfire_file_unref(file);
        }
 
-       // Sort the filelist
-       pakfire_filelist_sort(list);
-
        // Success
        r = 0;
 
@@ -346,15 +358,15 @@ ERROR:
 }
 
 int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern) {
+       struct pakfire_filelist_element* element = NULL;
+
        if (!pattern) {
                errno = EINVAL;
                return -1;
        }
 
-       for (unsigned int i = 0; i < list->size; i++) {
-               struct pakfire_file* file = list->elements[i];
-
-               const char* path = pakfire_file_get_path(file);
+       TAILQ_FOREACH(element, &list->files, nodes) {
+               const char* path = pakfire_file_get_path(element->file);
                if (!path)
                        return -1;
 
@@ -368,15 +380,13 @@ int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern
 
 int pakfire_filelist_walk(struct pakfire_filelist* list,
                pakfire_filelist_walk_callback callback, void* data) {
-       struct pakfire_file* file = NULL;
+       struct pakfire_filelist_element* element = NULL;
        int r = 0;
 
        // Call the callback once for every element on the list
-       for (unsigned int i = 0; i < list->size; i++) {
-               file = list->elements[i];
-
+       TAILQ_FOREACH(element, &list->files, nodes) {
                // Call the callback
-               r = callback(list->pakfire, file, data);
+               r = callback(list->pakfire, element->file, data);
                if (r)
                        break;
        }
@@ -415,12 +425,14 @@ int pakfire_filelist_dump(struct pakfire_filelist* list, int debug) {
        Verifies all files on the filelist
 */
 int pakfire_filelist_verify(struct pakfire_filelist* list, struct pakfire_filelist* errors) {
+       struct pakfire_filelist_element* element = NULL;
        struct pakfire_progressbar* progressbar = NULL;
-       struct pakfire_file* file = NULL;
        int status;
        int r;
 
-       DEBUG(list->pakfire, "Verifying filelist (%zu file(s))...\n", list->size);
+       const size_t length = pakfire_filelist_size(list);
+
+       DEBUG(list->pakfire, "Verifying filelist (%zu file(s))...\n", length);
 
        // Setup progressbar
        r = pakfire_progressbar_create(&progressbar, NULL);
@@ -448,23 +460,21 @@ int pakfire_filelist_verify(struct pakfire_filelist* list, struct pakfire_fileli
                goto ERROR;
 
        // Start the progressbar
-       r = pakfire_progressbar_start(progressbar, list->size);
+       r = pakfire_progressbar_start(progressbar, length);
        if (r)
                goto ERROR;
 
        // Iterate over the entire list
-       for (unsigned int i = 0; i < list->size; i++) {
-               file = list->elements[i];
-
+       TAILQ_FOREACH(element, &list->files, nodes) {
                // Verify the file
-               r = pakfire_file_verify(file, &status);
+               r = pakfire_file_verify(element->file, &status);
                if (r)
                        goto ERROR;
 
                // If the verification failed, we append it to the errors list
                if (status) {
                        // Append the file to the error list
-                       r = pakfire_filelist_append(errors, file);
+                       r = pakfire_filelist_append(errors, element->file);
                        if (r)
                                goto ERROR;
                }
@@ -488,6 +498,7 @@ ERROR:
 }
 
 int pakfire_filelist_cleanup(struct pakfire_filelist* list) {
+       struct pakfire_filelist_element* element = NULL;
        int r;
 
        // Nothing to do if the filelist is empty
@@ -495,8 +506,8 @@ int pakfire_filelist_cleanup(struct pakfire_filelist* list) {
                return 0;
 
        // Walk through the list backwards
-       for (int i = list->size - 1; i >= 0; i--) {
-               r = pakfire_file_cleanup(list->elements[i]);
+       TAILQ_FOREACH_REVERSE(element, &list->files, entries, nodes) {
+               r = pakfire_file_cleanup(element->file);
                if (r)
                        return r;
        }