From: Michael Tremer Date: Fri, 6 Oct 2023 14:55:55 +0000 (+0000) Subject: archive: read: Add option to follow symlinks X-Git-Tag: 0.9.30~1529 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=695e76f492bb7a1e96c823ec595149bd0c8778ff;p=pakfire.git archive: read: Add option to follow symlinks 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 --- diff --git a/src/_pakfire/archive.c b/src/_pakfire/archive.c index 236c05f6e..f3a34dea9 100644 --- a/src/_pakfire/archive.c +++ b/src/_pakfire/archive.c @@ -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); diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 68c6d4d51..85c5c228b 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -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) { diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index aa4c674ae..bf75bdc78 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -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);