#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)
l->pakfire = pakfire_ref(pakfire);
l->nrefs = 1;
+ // Initialise files
+ TAILQ_INIT(&l->files);
+
*list = l;
return 0;
}
}
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
pakfire_file_unref(file);
}
- // Sort the filelist
- pakfire_filelist_sort(list);
-
// Success
r = 0;
}
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;
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;
}
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);
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;
}
}
int pakfire_filelist_cleanup(struct pakfire_filelist* list) {
+ struct pakfire_filelist_element* element = NULL;
int r;
// Nothing to do if the filelist is empty
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;
}