]> git.ipfire.org Git - pakfire.git/commitdiff
repo: Refactor scanning once again
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 25 Oct 2024 16:38:49 +0000 (16:38 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 25 Oct 2024 16:38:49 +0000 (16:38 +0000)
I was being lazy. We need to scan recursively.

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

index 52c2b05cb83dee071a8b91c2f183af762b96d8bc..2af6ea74cf755d8e156143c358148e9c0fb3653f 100644 (file)
@@ -18,9 +18,9 @@
 #                                                                             #
 #############################################################################*/
 
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <fts.h>
 #include <linux/limits.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -1529,15 +1529,85 @@ PAKFIRE_EXPORT int pakfire_repo_clean(struct pakfire_repo* repo, int flags) {
        return pakfire_rmtree(cache_path, 0);
 }
 
-static int pakfire_repo_scan_archive(struct pakfire_repo* repo, const char* path) {
+struct pakfire_repo_scan_ctx {
+       // Progress
+       struct pakfire_progress* progress;
+
+       // Flags
+       int flags;
+
+       // Counter
+       unsigned int num_archives;
+};
+
+typedef int (*pakfire_repo_scan_callback)(
+       struct pakfire_repo* repo, struct pakfire_repo_scan_ctx* scan_ctx, FTSENT* entry);
+
+static int __pakfire_repo_scan(struct pakfire_repo* repo,
+               struct pakfire_repo_scan_ctx* scan_ctx, pakfire_repo_scan_callback callback) {
+       FTSENT* entry = NULL;
+       FTS* fts = NULL;
+       int r;
+
+       // Fetch the repository path
+       const char* path = pakfire_repo_get_path(repo);
+       if (!path)
+               return -EINVAL;
+
+       char* paths[] = {
+               (char*)path, NULL,
+        };
+
+       // Open the path
+       fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL);
+       if (!fts) {
+               ERROR(repo->ctx, "Could not open %s: %m\n", path);
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Scan for everything
+       for (;;) {
+               entry = fts_read(fts);
+               if (!entry)
+                       break;
+
+               // We only care about actual files
+               if (!(entry->fts_info & FTS_F))
+                       continue;
+
+               // Skip anything that doesn't have the correct file extension
+               if (!pakfire_path_match("**.pfm", entry->fts_path))
+                       continue;
+
+               // Call the callback
+               r = callback(repo, scan_ctx, entry);
+               if (r)
+                       goto ERROR;
+       }
+
+ERROR:
+       if (fts)
+               fts_close(fts);
+
+       return r;
+}
+
+static int __pakfire_repo_scan_count(struct pakfire_repo* repo,
+               struct pakfire_repo_scan_ctx* scan_ctx, FTSENT* entry) {
+       ++scan_ctx->num_archives;
+
+       return 0;
+}
+
+static int __pakfire_repo_scan_archive(struct pakfire_repo* repo,
+               struct pakfire_repo_scan_ctx* scan_ctx, FTSENT* entry) {
        struct pakfire_archive* archive = NULL;
        struct pakfire_package* package = NULL;
        int r;
 
-       DEBUG(repo->ctx, "Scanning %s...\n", path);
-
        // Open archive
-       r = pakfire_archive_open(&archive, repo->pakfire, path);
+       r = pakfire_archive_open(&archive, repo->pakfire, entry->fts_path);
        if (r < 0)
                goto ERROR;
 
@@ -1546,6 +1616,9 @@ static int pakfire_repo_scan_archive(struct pakfire_repo* repo, const char* path
        if (r < 0)
                goto ERROR;
 
+       // Increment progress bar
+       pakfire_progress_increment(scan_ctx->progress, 1);
+
 ERROR:
        if (package)
                pakfire_package_unref(package);
@@ -1555,22 +1628,14 @@ ERROR:
        return r;
 }
 
-static int pakfire_repo_scan_filter(const struct dirent* dirent) {
-       // Skip anything hidden
-       if (*dirent->d_name == '.')
-               return 0;
-
-       return !!pakfire_path_match("**.pfm", dirent->d_name);
-}
-
 PAKFIRE_EXPORT int pakfire_repo_scan(struct pakfire_repo* repo, int flags) {
-       struct pakfire_progress* progress = NULL;
-       struct dirent** archives = NULL;
-       char archive[PATH_MAX];
-       int num_archives = 0;
-       int fd = -EBADF;
        int r;
 
+       // Scan context
+       struct pakfire_repo_scan_ctx scan_ctx = {
+               .flags = flags,
+       };
+
        // Fetch name
        const char* name = pakfire_repo_get_name(repo);
 
@@ -1579,63 +1644,41 @@ PAKFIRE_EXPORT int pakfire_repo_scan(struct pakfire_repo* repo, int flags) {
        if (!path)
                return -EINVAL;
 
-       // Open path
-       fd = open(path, O_DIRECTORY|O_CLOEXEC);
-       if (fd < 0) {
-               switch (errno) {
-                       // If the directory does not exist, there is nothing to scan
-                       case ENOENT:
-                               r = 0;
-                               goto ERROR;
-
-                       default:
-                               r = -errno;
-                               goto ERROR;
-               }
-       }
-
-       // Find all archives in the directory
-       num_archives = scandirat(fd, ".", &archives, pakfire_repo_scan_filter, versionsort);
-       if (num_archives < 0) {
-               r = num_archives;
-               goto ERROR;
-       }
-
        // Create progress indicator
-       r = pakfire_progress_create(&progress, repo->ctx,
+       r = pakfire_progress_create(&scan_ctx.progress, repo->ctx,
                        PAKFIRE_PROGRESS_SHOW_COUNTER|PAKFIRE_PROGRESS_SHOW_ELAPSED_TIME, NULL);
        if (r)
                goto ERROR;
 
        // Add title to progress
-       r = pakfire_progress_set_title(progress, _("Scanning %s"), name);
+       r = pakfire_progress_set_title(scan_ctx.progress, _("Scanning %s"), name);
        if (r)
                goto ERROR;
 
-       // Start progress
-       r = pakfire_progress_start(progress, num_archives);
+       // Start progress (so that we will let the user know something is happening if
+       // scanning for files takes a little bit longer...)
+       r = pakfire_progress_start(scan_ctx.progress, 0);
        if (r < 0)
                goto ERROR;
 
-       // Scan all packages
-       for (int i = 0; i < num_archives; i++) {
-               r = pakfire_path_append(archive, path, archives[i]->d_name);
-               if (r < 0)
-                       goto ERROR;
+       // Count how many files we have
+       r = __pakfire_repo_scan(repo, &scan_ctx, __pakfire_repo_scan_count);
+       if (r < 0)
+               goto ERROR;
 
-               r = pakfire_repo_scan_archive(repo, archive);
-               if (r < 0)
-                       goto ERROR;
+       // Update the progressbar
+       pakfire_progress_set_max_value(scan_ctx.progress, scan_ctx.num_archives);
 
-               // Increment progress bar
-               pakfire_progress_increment(progress, 1);
-       }
+       // Scan all packages
+       r = __pakfire_repo_scan(repo, &scan_ctx, __pakfire_repo_scan_archive);
+       if (r < 0)
+               goto ERROR;
 
        // Mark repository data as changed
        pakfire_repo_has_changed(repo);
 
        // Finish the progress
-       r = pakfire_progress_finish(progress);
+       r = pakfire_progress_finish(scan_ctx.progress);
        if (r < 0)
                goto ERROR;
 
@@ -1643,15 +1686,8 @@ PAKFIRE_EXPORT int pakfire_repo_scan(struct pakfire_repo* repo, int flags) {
        r = 0;
 
 ERROR:
-       if (archives) {
-               for (int i = 0; i < num_archives; i++)
-                       free(archives[i]);
-               free(archives);
-       }
-       if (progress)
-               pakfire_progress_unref(progress);
-       if (fd >= 0)
-               close(fd);
+       if (scan_ctx.progress)
+               pakfire_progress_unref(scan_ctx.progress);
 
        return r;
 }