#include <errno.h>
#include <stdlib.h>
-#include <sys/queue.h>
// libarchive
#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_ctx* ctx;
struct pakfire* pakfire;
int nrefs;
- TAILQ_HEAD(entries, pakfire_filelist_element) files;
+ struct pakfire_file** files;
+ unsigned int num_files;
};
PAKFIRE_EXPORT int pakfire_filelist_create(struct pakfire_filelist** list, struct pakfire* pakfire) {
// Initialize the reference counter
l->nrefs = 1;
- // Initialise files
- TAILQ_INIT(&l->files);
-
// Return the pointer
*list = l;
pakfire_unref(list->pakfire);
if (list->ctx)
pakfire_ctx_unref(list->ctx);
+ if (list->files)
+ free(list->files);
free(list);
}
}
PAKFIRE_EXPORT size_t pakfire_filelist_length(struct pakfire_filelist* list) {
- struct pakfire_filelist_element* element = NULL;
- size_t size = 0;
-
- TAILQ_FOREACH(element, &list->files, nodes)
- size++;
-
- return size;
+ return list->num_files;
}
size_t pakfire_filelist_total_size(struct pakfire_filelist* list) {
- struct pakfire_filelist_element* element = NULL;
size_t size = 0;
- TAILQ_FOREACH(element, &list->files, nodes)
- size += pakfire_file_get_size(element->file);
+ for (unsigned int i = 0; i < list->num_files; i++)
+ size += pakfire_file_get_size(list->files[i]);
return size;
}
PAKFIRE_EXPORT int pakfire_filelist_is_empty(struct pakfire_filelist* list) {
- return TAILQ_EMPTY(&list->files);
+ return list->num_files == 0;
}
PAKFIRE_EXPORT void pakfire_filelist_clear(struct pakfire_filelist* list) {
- struct pakfire_filelist_element* element = NULL;
-
- while (!TAILQ_EMPTY(&list->files)) {
- // Fetch the first element
- element = TAILQ_FIRST(&list->files);
-
- // Remove it from the list
- TAILQ_REMOVE(&list->files, element, nodes);
-
- // Dereference the file
- pakfire_file_unref(element->file);
-
- // Free it all
- free(element);
- }
+ for (unsigned int i = 0; i < list->num_files; i++)
+ pakfire_file_unref(list->files[i]);
}
PAKFIRE_EXPORT struct pakfire_file* pakfire_filelist_get(struct pakfire_filelist* list, size_t index) {
- struct pakfire_filelist_element* element = NULL;
-
- // Fetch the first element
- element = TAILQ_FIRST(&list->files);
-
- while (element && index--)
- element = TAILQ_NEXT(element, nodes);
-
- if (!element)
+ // Check that index is in range
+ if (index >= list->num_files) {
+ errno = ERANGE;
return NULL;
+ }
- return pakfire_file_ref(element->file);
+ return pakfire_file_ref(list->files[index]);
}
/*
Checks if the file is already on the list
*/
static int pakfire_filelist_has_file(struct pakfire_filelist* list, struct pakfire_file* file) {
- struct pakfire_filelist_element* e = NULL;
-
- TAILQ_FOREACH(e, &list->files, nodes) {
- if (e->file == file)
- return 1;
+ for (unsigned int i = 0; i < list->num_files; i++) {
+ if (list->files[i] == file)
+ return i;
}
- return 0;
+ // Not found
+ return -1;
}
-PAKFIRE_EXPORT int pakfire_filelist_add(struct pakfire_filelist* list, struct pakfire_file* file) {
- struct pakfire_filelist_element* element = NULL;
- struct pakfire_filelist_element* e = NULL;
+static int pakfire_filelist_search(struct pakfire_filelist* list, struct pakfire_file* file) {
+ int i;
+ int r;
- // Do not do anything if the file is already on the list
- if (pakfire_filelist_has_file(list, file))
- return 0;
+ // Set starting points
+ int lo = 0;
+ int hi = list->num_files - 1;
- // Allocate a new element
- element = calloc(1, sizeof *element);
- if (!element) {
- ERROR(list->ctx, "Could not allocate a new filelist element: %m\n");
- return 1;
+ while (lo <= hi) {
+ // Find the middle
+ i = lo + (hi - lo) / 2;
+
+ // Compare the files
+ r = pakfire_file_cmp(list->files[i], file);
+
+ // We have an exact match!
+ if (r == 0)
+ return i;
+
+ // Move to the right
+ else if (r < 0)
+ lo = i + 1;
+
+ // Move to the left
+ else if (r > 0)
+ hi = i - 1;
}
- // Reference the file
- element->file = pakfire_file_ref(file);
+ // Not found (so put it at the end)
+ return list->num_files;
+}
- // Fetch the last element
- e = TAILQ_LAST(&list->files, entries);
+PAKFIRE_EXPORT int pakfire_filelist_add(struct pakfire_filelist* list, struct pakfire_file* file) {
+ // Do not do anything if the file is already on the list
+ if (pakfire_filelist_has_file(list, file) >= 0)
+ return 0;
- // Skip all elements that are "greater than" the element we want to add
- while (e) {
- if (pakfire_file_cmp(e->file, file) <= 0)
- break;
+ // Find the index where the file should go
+ int i = pakfire_filelist_search(list, file);
- e = TAILQ_PREV(e, entries, nodes);
+ // Make space
+ list->files = reallocarray(list->files, list->num_files + 1, sizeof(*list->files));
+ if (!list->files) {
+ ERROR(list->ctx, "Could not allocate filelist: %m\n");
+ return -errno;
}
- // 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);
+ // Move everything up one slot
+ memmove(list->files + i + 1, list->files + i, list->num_files - i);
+
+ // Store the file
+ list->files[i] = pakfire_file_ref(file);
+
+ // The list is now longer
+ ++list->num_files;
return 0;
}
static int pakfire_filelist_remove(struct pakfire_filelist* list, struct pakfire_file* file) {
- struct pakfire_filelist_element* element = NULL;
+ // Check if the file is on the list
+ int i = pakfire_filelist_has_file(list, file);
- TAILQ_FOREACH(element, &list->files, nodes) {
- if (element->file == file) {
- // Remove the element from the list
- TAILQ_REMOVE(&list->files, element, nodes);
+ // Do nothing if the file is not on the list
+ if (i < 0)
+ return 0;
- // Free the element
- pakfire_file_unref(element->file);
- free(element);
+ // Remove the reference
+ pakfire_file_unref(list->files[i]);
- return 0;
- }
- }
+ // Fill the gap
+ memmove(list->files + i, list->files + i + 1, list->num_files - i - 1);
+
+ // The list is now shorter
+ --list->num_files;
return 0;
}
static int __pakfire_filelist_remove_one(
struct pakfire_ctx* ctx, struct pakfire_file* file, void* data) {
- struct pakfire_filelist* list = (struct pakfire_filelist*)data;
+ struct pakfire_filelist* list = data;
// Remove the file from the given filelist
return pakfire_filelist_remove(list, file);
}
int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern) {
- struct pakfire_filelist_element* element = NULL;
-
- if (!pattern) {
- errno = EINVAL;
- return -1;
- }
+ if (!pattern)
+ return -EINVAL;
- TAILQ_FOREACH(element, &list->files, nodes) {
- const char* path = pakfire_file_get_path(element->file);
+ for (unsigned int i = 0; i < list->num_files; i++) {
+ const char* path = pakfire_file_get_path(list->files[i]);
if (!path)
- return -1;
+ return -errno;
if (pakfire_path_match(pattern, path))
return 1;
int pakfire_filelist_walk(struct pakfire_filelist* list,
pakfire_filelist_walk_callback callback, void* data, int flags) {
struct pakfire_progress* progress = NULL;
- struct pakfire_filelist_element* element = NULL;
int r = 0;
// Show progress when iterating over the filelist
}
// Call the callback once for every element on the list
- TAILQ_FOREACH(element, &list->files, nodes) {
+ for (unsigned int i = 0; i < list->num_files; i++) {
// Increment the progress
if (progress)
pakfire_progress_increment(progress, 1);
// Call the callback
- r = callback(list->ctx, element->file, data);
+ r = callback(list->ctx, list->files[i], 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_progress* progress = NULL;
int status;
int r;
goto ERROR;
// Iterate over the entire list
- TAILQ_FOREACH(element, &list->files, nodes) {
+ for (unsigned int i = 0; i < list->num_files; i++) {
// Verify the file
- r = pakfire_file_verify(element->file, &status);
+ r = pakfire_file_verify(list->files[i], &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_add(errors, element->file);
+ r = pakfire_filelist_add(errors, list->files[i]);
if (r)
goto ERROR;
}
}
int pakfire_filelist_cleanup(struct pakfire_filelist* list, int flags) {
- struct pakfire_filelist_element* element = NULL;
int r;
// Nothing to do if the filelist is empty
return 0;
// Walk through the list backwards
- TAILQ_FOREACH_REVERSE(element, &list->files, entries, nodes) {
- r = pakfire_file_cleanup(element->file, flags);
+ for (int i = list->num_files - 1; i >= 0; i--) {
+ r = pakfire_file_cleanup(list->files[i], flags);
if (r)
return r;
}