return 0;
}
+static int pakfire_archive_walk_entries(PakfireArchive archive, struct archive* a,
+ int (*callback)(PakfireArchive archive, struct archive* a, struct archive_entry* e, void* data),
+ void* data) {
+ struct archive_entry* e = NULL;
+
+ // Walk through the archive
+ while (1) {
+ int r = archive_read_next_header(a, &e);
+
+ // Return OK when we reached the end of the archive
+ if (r == ARCHIVE_EOF)
+ return ARCHIVE_OK;
+
+ // Raise any other errors
+ else if (r)
+ return r;
+
+ // Run callback
+ r = callback(archive, a, e, data);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
static int pakfire_archive_walk(PakfireArchive archive,
int (*callback)(PakfireArchive archive, struct archive* a, struct archive_entry* e, void* data),
void* data) {
struct archive* a;
- struct archive_entry* e;
// Open the archive file
int r = archive_open(archive, &a);
return r;
// Walk through the archive
- while (1) {
- r = archive_read_next_header(a, &e);
- if (r)
- break;
-
- // Run callback
- r = callback(archive, a, e, data);
- if (r)
- break;
- }
+ r = pakfire_archive_walk_entries(archive, a, callback, data);
// Close the archive
archive_read_free(a);
return pakfire_parser_get(archive->parser, namespace, key);
}
-static int archive_extract(PakfireArchive archive, struct archive* a, const char* prefix) {
- if (!a)
- return EINVAL;
-
- struct archive_entry* entry = NULL;
- int r;
- PakfireFile file;
-
- // Reset the filelist
- if (archive->filelist)
- pakfire_filelist_clear(archive->filelist);
-
- struct archive* writer = pakfire_make_archive_disk_writer(archive->pakfire);
- if (!writer)
- return 1;
-
- for (;;) {
- r = archive_read_next_header(a, &entry);
-
- // Reached the end of the archive.
- if (r == ARCHIVE_EOF) {
- r = ARCHIVE_OK;
- break;
- }
-
- // Create a new file object
- r = pakfire_file_create(&file, archive->pakfire);
- if (r)
- return r;
-
- // Import attributes
- r = pakfire_file_copy_archive_entry(file, entry);
- if (r)
- return r;
-
- const char* archive_pathname = archive_entry_pathname(entry);
- size_t size = archive_entry_size(entry);
-
- // Prepend the prefix to the path the file is extracted to.
- char* pathname = pakfire_path_join(prefix, archive_pathname);
- archive_entry_set_pathname(entry, pathname);
-
- DEBUG(archive->pakfire, "Extracting %s (%zu bytes)\n", pathname, size);
- free(pathname);
-
- // Update hardlink targets
- const char* hardlink = archive_entry_hardlink(entry);
- if (hardlink) {
- // Make new hardlink target relative to prefix
- char* h = pakfire_path_join(prefix, hardlink);
-
- // Update the entry
- archive_entry_set_hardlink(entry, h);
- free(h);
- }
-
- // Create file & payload
- r = archive_read_extract2(a, entry, writer);
- if (r != ARCHIVE_OK) {
- ERROR(archive->pakfire, "Could not extract file /%s: %s\n",
- archive_pathname, archive_error_string(writer));
- pakfire_file_unref(file);
- break;
- }
-
- // Append file to filelist
- r = pakfire_filelist_append(archive->filelist, file);
- if (r)
- break;
-
- pakfire_file_unref(file);
- }
-
- archive_write_close(writer);
- archive_write_free(writer);
-
- return r;
-}
-
PAKFIRE_EXPORT int pakfire_archive_read(PakfireArchive archive, const char* filename,
char** data, size_t* data_size, int flags) {
struct archive* a;
return prefix;
}
+struct pakfire_archive_extractor {
+ struct archive* writer;
+ const char* prefix;
+ PakfireFilelist filelist;
+};
+
+static int pakfire_archive_extract_entry(PakfireArchive archive,
+ struct archive* a, struct archive_entry* entry, void* data) {
+ struct pakfire_archive_extractor* extractor = (struct pakfire_archive_extractor*)data;
+
+ PakfireFile file = NULL;
+ char* buffer;
+ int r = 1;
+
+ // Create a new file object if there is a filelist
+ if (extractor->filelist) {
+ r = pakfire_file_create(&file, archive->pakfire);
+ if (r)
+ goto ERROR;
+
+ // Import attributes
+ r = pakfire_file_copy_archive_entry(file, entry);
+ if (r)
+ goto ERROR;
+
+ // Append it to the filelist
+ r = pakfire_filelist_append(extractor->filelist, file);
+ if (r)
+ goto ERROR;
+ }
+
+ // Fetch the paths
+ const char* path = archive_entry_pathname(entry);
+
+ DEBUG(archive->pakfire, "Extracting %s\n", path);
+
+ // Prepend the prefix
+ if (extractor->prefix) {
+ buffer = pakfire_path_join(extractor->prefix, path);
+ if (!buffer)
+ goto ERROR;
+
+ archive_entry_set_pathname(entry, buffer);
+ free(buffer);
+
+ // Update hardlink destination
+ const char* link = archive_entry_hardlink(entry);
+ if (link) {
+ buffer = pakfire_path_join(extractor->prefix, link);
+ if (!buffer)
+ goto ERROR;
+
+ archive_entry_set_hardlink(entry, buffer);
+ free(buffer);
+ }
+ }
+
+ // Create file & extract payload
+ r = archive_read_extract2(a, entry, extractor->writer);
+ if (r != ARCHIVE_OK) {
+ ERROR(archive->pakfire, "Could not extract file /%s: %s\n",
+ path, archive_error_string(extractor->writer));
+ goto ERROR;
+ }
+
+ERROR:
+ if (file)
+ pakfire_file_unref(file);
+
+ return r;
+}
+
PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* prefix, int flags) {
- struct archive* a;
+ struct archive* a = NULL;
struct archive* payload = NULL;
+ struct archive* writer = NULL;
// Use default path if nothing is set
if (!prefix)
goto ERROR;
}
+ // Allocate writer
+ writer = pakfire_make_archive_disk_writer(archive->pakfire);
+ if (!writer)
+ goto ERROR;
+
+ struct pakfire_archive_extractor extractor = {
+ .writer = writer,
+ .prefix = prefix,
+ };
+
// Extract everything
- r = archive_extract(archive, (payload) ? payload : a, prefix);
+ r = pakfire_archive_walk_entries(archive, (payload) ? payload : a,
+ pakfire_archive_extract_entry, &extractor);
ERROR:
+ if (writer)
+ archive_write_free(writer);
if (payload)
archive_read_free(payload);
archive_read_free(a);