From: Michael Tremer Date: Fri, 10 Mar 2023 16:34:48 +0000 (+0000) Subject: archive: Be more efficient when reading single files X-Git-Tag: 0.9.29~332 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a914a843da0f53cd6bb43074d55d8509d7a0c89;p=pakfire.git archive: Be more efficient when reading single files Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index f840e1afd..69849ec76 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -525,13 +525,6 @@ static int64_t pakfire_archive_metadata_get_int64( return json_object_get_int64(object); } -struct pakfire_archive_read { - struct pakfire_archive* archive; - const char* path; - char** data; - size_t* length; -}; - static int __pakfire_archive_filter_payload(struct pakfire* pakfire, struct archive* a, struct archive_entry* entry, void* p) { const char* path = archive_entry_pathname(entry); @@ -556,44 +549,62 @@ static int __pakfire_archive_filter_payload(struct pakfire* pakfire, PAKFIRE_EXPORT int pakfire_archive_read(struct pakfire_archive* archive, const char* path, char** data, size_t* length) { + int found = 0; int r; - // Strip leading / from filenames, because tarballs don't use any leading slashes - path = pakfire_path_relpath("/", path); + // Check if path is absolute + if (!path || *path != '/') { + errno = EINVAL; + return 1; - // Check inputs - if (!path || !data || !length) { + // Check other inputs + } else if (!data || !length) { errno = EINVAL; return 1; } - // Reset data - *data = NULL; + // Strip leading / from filenames, because tarballs don't use any leading slashes + path = pakfire_path_relpath("/", path); + if (!path) + return 1; - int __pakfire_archive_read(struct pakfire* pakfire, struct archive* a, + // Tries to find a matching file in the archive + int __pakfire_archive_read_filter(struct pakfire* pakfire, struct archive* a, struct archive_entry* e, void* __data) { - // Fetch the path of this entry + // Stop reading the archive after we have found our file + if (found) + return PAKFIRE_WALK_END; + + // Fetch path const char* p = archive_entry_pathname(e); if (!p) - return 1; + return PAKFIRE_WALK_ERROR; - if (strcmp(path, p) == 0) { - r = pakfire_archive_copy_data_to_buffer(pakfire, a, e, data, length); - if (r) - return r; - } + // We found a match + if (strcmp(path, p) == 0) + return PAKFIRE_WALK_OK; - return 0; + // Otherwise we skip the file + return PAKFIRE_WALK_SKIP; + } + + // Reads a matching file into memory + int __pakfire_archive_read(struct pakfire* pakfire, struct archive* a, + struct archive_entry* e, void* __data) { + // We have found our file + found = 1; + + return pakfire_archive_copy_data_to_buffer(pakfire, a, e, data, length); } // Walk through the archive r = pakfire_archive_walk(archive, - __pakfire_archive_read, __pakfire_archive_filter_payload, NULL); + __pakfire_archive_read, __pakfire_archive_read_filter, NULL); if (r) return r; // Nothing found - if (!*data) { + if (!found) { // No such file or directory errno = ENOENT;