]> git.ipfire.org Git - pakfire.git/commitdiff
archive: read: Add option to follow symlinks
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 6 Oct 2023 14:55:55 +0000 (14:55 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 6 Oct 2023 14:55:55 +0000 (14:55 +0000)
This is useful when we want to read some data from an archive which
requires us to follow a symlink.

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

index 236c05f6e6f2e08c01fe293334ee7e843331692d..f3a34dea93535dd656f1efb2d3a512d0f92452a7 100644 (file)
@@ -92,7 +92,7 @@ static PyObject* Archive_read(ArchiveObject* self, PyObject* args) {
        Py_BEGIN_ALLOW_THREADS
 
        // Try to open the file
-       f = pakfire_archive_read(self->archive, filename);
+       f = pakfire_archive_read(self->archive, filename, PAKFIRE_ARCHIVE_READ_FOLLOW_SYMLINKS);
        if (!f) {
                Py_BLOCK_THREADS
                PyErr_SetFromErrno(PyExc_OSError);
index 68c6d4d512bb5e21d33fefe76f8a7bdddae32025..85c5c228b83155671d43a6d5bcecfc80ab14badc 100644 (file)
@@ -44,6 +44,7 @@
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
 #include <pakfire/pakfire.h>
+#include <pakfire/path.h>
 #include <pakfire/private.h>
 #include <pakfire/repo.h>
 #include <pakfire/scriptlet.h>
@@ -581,6 +582,9 @@ struct pakfire_archive_read_cookie {
 
        // File handle opened by the cookie
        FILE* __f;
+
+       // Some flags
+       int flags;
 };
 
 static ssize_t __pakfire_archive_cookie_read(void* c, char* buffer, size_t size) {
@@ -615,6 +619,8 @@ static cookie_io_functions_t pakfire_archive_read_functions = {
 static int __pakfire_archive_read_filter(struct pakfire* pakfire, struct archive* a,
                struct archive_entry* e, void* data) {
        struct pakfire_archive_read_cookie* cookie = (struct pakfire_archive_read_cookie*)data;
+       const char* symlink = NULL;
+       int r;
 
        // Fetch path
        const char* p = archive_entry_pathname(e);
@@ -622,8 +628,31 @@ static int __pakfire_archive_read_filter(struct pakfire* pakfire, struct archive
                return PAKFIRE_WALK_ERROR;
 
        // We found a match
-       if (strcmp(cookie->path + 1, p) == 0)
+       if (strcmp(cookie->path + 1, p) == 0) {
+               if (cookie->flags & PAKFIRE_ARCHIVE_READ_FOLLOW_SYMLINKS) {
+                       switch (archive_entry_filetype(e)) {
+                               case AE_IFLNK:
+                                       break;
+
+                               default:
+                                       return PAKFIRE_WALK_DONE;
+                       }
+
+                       // Resolve the destination of the symlink
+                       symlink = archive_entry_symlink(e);
+                       if (!symlink)
+                               return PAKFIRE_WALK_ERROR;
+
+                       // Update path
+                       r = pakfire_path_merge(cookie->path, cookie->path, symlink);
+                       if (r)
+                               return PAKFIRE_WALK_ERROR;
+
+                       return PAKFIRE_WALK_AGAIN;
+               }
+
                return PAKFIRE_WALK_DONE;
+       }
 
        // Otherwise we skip the file
        return PAKFIRE_WALK_SKIP;
@@ -644,7 +673,7 @@ static int __pakfire_archive_read(struct pakfire* pakfire, struct archive* a,
        return PAKFIRE_WALK_DONE;
 }
 
-PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* path) {
+PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* path, int flags) {
        struct pakfire_archive_read_cookie* cookie = NULL;
        int r;
 
@@ -664,6 +693,9 @@ PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const
        // Store a reference to the archive
        cookie->archive = pakfire_archive_ref(archive);
 
+       // Store flags
+       cookie->flags = flags;
+
        // Store the path
        r = pakfire_string_set(cookie->path, path);
        if (r) {
@@ -680,6 +712,7 @@ PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const
        }
 
        // Open the archive
+AGAIN:
        cookie->a = open_archive(archive, cookie->f);
        if (!cookie->a)
                goto ERROR;
@@ -687,8 +720,19 @@ PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const
        // Walk through the archive
        r = pakfire_walk(archive->pakfire, cookie->a,
                __pakfire_archive_read, __pakfire_archive_read_filter, cookie);
-       if (r)
-               goto ERROR;
+       if (r) {
+               switch (-r) {
+                       case EAGAIN:
+                               if (cookie->a)
+                                       archive_read_free(cookie->a);
+                               if (cookie->f)
+                                       rewind(cookie->f);
+                               goto AGAIN;
+
+                       default:
+                               goto ERROR;
+               }
+       }
 
        // Nothing found
        if (!cookie->__f) {
index aa4c674ae3ca15aebcf0f7299f8da9a1a63a9fed..bf75bdc783e5da7bde9006df0ca581b640945679 100644 (file)
@@ -35,7 +35,11 @@ int pakfire_archive_open(struct pakfire_archive** archive, struct pakfire* pakfi
 struct pakfire_archive* pakfire_archive_ref(struct pakfire_archive* archive);
 struct pakfire_archive* pakfire_archive_unref(struct pakfire_archive* archive);
 
-FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* filename);
+enum pakfire_archive_read_flags {
+       PAKFIRE_ARCHIVE_READ_FOLLOW_SYMLINKS = (1 << 0),
+};
+
+FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* filename, int flags);
 int pakfire_archive_extract(struct pakfire_archive* archive,
        const char* path, const int flags);