// Digests
struct pakfire_digests digests;
+ // Progress (when extracting)
+ struct pakfire_progress* progress;
+
// Verify Status
int verify;
};
return NULL;
}
-static int pakfire_archive_walk(struct pakfire_archive* archive,
- pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback, void* data) {
+/*
+ Helper function to conditionally walk through an archive
+ and perform actions based on the callback.
+*/
+static int pakfire_archive_walk(struct pakfire_archive* archive, struct archive* a,
+ pakfire_archive_walk_callback walk_callback,
+ pakfire_archive_walk_filter_callback filter_callback, void* p) {
+ struct archive_entry* entry = NULL;
int r;
- // Open the archive file
- struct archive* a = open_archive(archive, NULL);
+ // Walk through the archive
+ for (;;) {
+ r = archive_read_next_header(a, &entry);
+
+ // Handle the return code
+ switch (r) {
+ // Fall through if everything is okay
+ case ARCHIVE_OK:
+ break;
+
+ // Return OK when we reached the end of the archive
+ case ARCHIVE_EOF:
+ return 0;
+
+ // Raise any other errors
+ default:
+ return r;
+ }
+
+ // Call the filter callback before we call the actual callback
+ if (filter_callback) {
+ r = filter_callback(archive->ctx, archive, a, entry, p);
+
+ // Handle the return code
+ switch (r) {
+ case PAKFIRE_WALK_OK:
+ break;
+
+ case PAKFIRE_WALK_END:
+ CTX_DEBUG(archive->ctx, "Filter callback sent END\n");
+ return 0;
+
+ case PAKFIRE_WALK_SKIP:
+ CTX_DEBUG(archive->ctx, "Filter callback sent SKIP\n");
+ continue;
+
+ case PAKFIRE_WALK_DONE:
+ CTX_DEBUG(archive->ctx, "Filter callback sent DONE\n");
+
+ // Clear the callback function
+ filter_callback = NULL;
+ break;
+
+ case PAKFIRE_WALK_AGAIN:
+ CTX_DEBUG(archive->ctx, "Filter callback sent AGAIN\n");
+ return -EAGAIN;
+
+ // Raise any other errors
+ default:
+ CTX_DEBUG(archive->ctx, "Filter callback returned an error: %d\n", r);
+ return r;
+ }
+ }
+
+ // Run callback
+ if (walk_callback) {
+ r = walk_callback(archive->ctx, archive, a, entry, p);
+
+ // Handle the return code
+ switch (r) {
+ case PAKFIRE_WALK_OK:
+ break;
+
+ case PAKFIRE_WALK_DONE:
+ CTX_DEBUG(archive->ctx, "Callback sent DONE\n");
+ return 0;
+
+ // Raise any other errors
+ default:
+ return r;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pakfire_archive_open_and_walk(struct pakfire_archive* archive,
+ pakfire_archive_walk_callback walk_callback, pakfire_archive_walk_filter_callback filter_callback, void* data) {
+ struct archive* a = NULL;
+ int r;
+
+ // Open the archive
+ a = open_archive(archive, NULL);
if (!a)
return -errno;
- // Walk through the archive
- r = pakfire_walk(archive->ctx, a, callback, filter_callback, data);
+ // Walk...
+ r = pakfire_archive_walk(archive, a, walk_callback, filter_callback, data);
- // Close the archive
+ERROR:
if (a)
archive_read_free(a);
for (unsigned int i = 0; i < archive->num_scriptlets; i++)
pakfire_scriptlet_unref(archive->scriptlets[i]);
+ if (archive->progress)
+ pakfire_progress_unref(archive->progress);
if (archive->filelist)
pakfire_filelist_unref(archive->filelist);
if (archive->package)
return archive;
pakfire_archive_free(archive);
-
return NULL;
}
return r;
}
-static int __pakfire_archive_read_metadata(struct pakfire_ctx* ctx, struct archive* a,
- struct archive_entry* entry, void* p) {
- struct pakfire_archive* archive = (struct pakfire_archive*)p;
-
+static int __pakfire_archive_read_metadata(struct pakfire_ctx* ctx,
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* entry, void* p) {
char* data = NULL;
size_t length = 0;
int r;
// Load the file into memory
r = pakfire_archive_copy_data_to_buffer(archive, a, entry, &data, &length);
if (r) {
- CTX_ERROR(archive->ctx, "Could not read data from archive: %s\n",
- archive_error_string(a));
+ CTX_ERROR(ctx, "Could not read data from archive: %s\n", archive_error_string(a));
goto ERROR;
}
}
static int __pakfire_archive_filter_metadata(struct pakfire_ctx* ctx,
- struct archive* a, struct archive_entry* entry, void* p) {
- struct pakfire_archive* archive = (struct pakfire_archive*)p;
-
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* entry, void* p) {
const char* path = archive_entry_pathname(entry);
// Format >= 6
}
static int pakfire_archive_read_metadata(struct pakfire_archive* archive) {
+ struct archive* a = NULL;
int r;
+ CTX_DEBUG(archive->ctx, "Reading archive metadata...\n");
+
+ // Open the archive
+ a = open_archive(archive, NULL);
+ if (!a) {
+ r = -errno;
+ goto ERROR;
+ }
+
// Check if the archive file actually has any contect
if (!archive->stat.st_size) {
CTX_ERROR(archive->ctx, "Trying to open an empty archive file\n");
- return -EINVAL;
+ r = -EINVAL;
+ goto ERROR;
}
- CTX_DEBUG(archive->ctx, "Reading archive metadata...\n");
-
// Walk through the archive
- r = pakfire_archive_walk(archive, __pakfire_archive_read_metadata,
- __pakfire_archive_filter_metadata, archive);
+ r = pakfire_archive_walk(archive, a,
+ __pakfire_archive_read_metadata, __pakfire_archive_filter_metadata, NULL);
if (r)
- return r;
+ goto ERROR;
// Check if we could successfully read something
if (!archive->format) {
CTX_DEBUG(archive->ctx, "Archive has an unknown format\n");
- return -ENOMSG;
+ r = -ENOMSG;
+ goto ERROR;
}
// Check if we have read some metadata
if (!archive->metadata) {
CTX_DEBUG(archive->ctx, "Archive has no metadata\n");
- return -ENOMSG;
+ r = -ENOMSG;
+ goto ERROR;
}
- return 0;
+ERROR:
+ if (a)
+ archive_read_close(a);
+
+ return r;
}
static int pakfire_archive_try_open(struct pakfire_archive* archive) {
// Store path
r = pakfire_string_set(a->path, path);
if (r < 0)
- return r;
+ goto ERROR;
// Try to open the archive
r = pakfire_archive_try_open(a);
}
static int pakfire_archive_filter_payload(struct pakfire_ctx* ctx,
- struct archive* a, struct archive_entry* entry, void* p) {
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* entry, void* p) {
const char* path = archive_entry_pathname(entry);
if (!path)
return PAKFIRE_WALK_ERROR;
};
// Tries to find a matching file in the archive
-static int pakfire_archive_read_filter(struct pakfire_ctx* ctx, struct archive* a,
- struct archive_entry* e, void* data) {
+static int pakfire_archive_read_filter(struct pakfire_ctx* ctx,
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* e, void* data) {
struct pakfire_archive_read_cookie* cookie = data;
const char* symlink = NULL;
int r;
}
// Reads a matching file into memory
-static int __pakfire_archive_read(struct pakfire_ctx* ctx, struct archive* a,
- struct archive_entry* e, void* data) {
+static int __pakfire_archive_read(struct pakfire_ctx* ctx,
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* e, void* data) {
struct pakfire_archive_read_cookie* cookie = data;
// Create a file descriptor
goto ERROR;
// Walk through the archive
- r = pakfire_walk(archive->ctx, cookie->a, __pakfire_archive_read,
+ r = pakfire_archive_walk(archive, cookie->a, __pakfire_archive_read,
pakfire_archive_read_filter, cookie);
if (r) {
switch (-r) {
return r;
}
-static int __pakfire_archive_extract(struct pakfire_archive* archive,
- const char* path, int flags) {
- struct pakfire_filelist* filelist = NULL;
+/*
+ Extraction
+*/
+
+struct pakfire_extract_state {
+ struct pakfire_archive* archive;
+
+ // Archive
+ struct archive* a;
+
+ // Prefix
+ const char* prefix;
+
+ // Flags
+ int flags;
+};
+
+static void pakfire_extract_progress(void* data) {
+ struct pakfire_extract_state* state = data;
+
+ // Fetch how many bytes have been read
+ const size_t position = archive_filter_bytes(state->a, -1);
+
+ // Update progress
+ pakfire_progress_update(state->archive->progress, position);
+}
+
+static int pakfire_archive_extract_one(struct pakfire_ctx* ctx,
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* entry, void* data) {
+ struct pakfire_file* file = NULL;
+ struct vfs_cap_data cap_data = {};
+ char buffer[PATH_MAX];
+ int r;
+
+ struct pakfire_extract_state* state = data;
+
+ // Fetch path
+ const char* path = archive_entry_pathname(entry);
+
+ // Make sure we have a leading slash on the filelist
+ if (!pakfire_string_startswith(path, "/")) {
+ r = pakfire_string_format(buffer, "/%s", path);
+ if (r < 0)
+ goto ERROR;
+
+ // Store the new name
+ archive_entry_set_pathname(entry, buffer);
+
+ // Update the path pointer
+ path = archive_entry_pathname(entry);
+ }
+
+ // Generate a file object
+ r = pakfire_file_create_from_archive_entry(&file, archive->pakfire, entry);
+ if (r)
+ goto ERROR;
+
+ // Add entry to filelist (if requested)
+ if (archive->filelist) {
+ // Append the file to the list
+ r = pakfire_filelist_add(archive->filelist, file);
+ if (r)
+ goto ERROR;
+ }
+
+ const int configfile = pakfire_file_has_flag(file, PAKFIRE_FILE_CONFIG);
+
+ // Prepend the prefix
+ if (*state->prefix) {
+ // Compose file path
+ r = pakfire_path_append(buffer, state->prefix, path);
+ if (r < 0) {
+ CTX_ERROR(ctx, "Could not compose file path: %m\n");
+ goto ERROR;
+ }
+
+ // Set file path
+ archive_entry_set_pathname(entry, buffer);
+
+ // Update hardlink destination
+ const char* link = archive_entry_hardlink(entry);
+ if (link) {
+ r = pakfire_path_append(buffer, state->prefix, link);
+ if (r < 0) {
+ CTX_ERROR(ctx, "Could not compose hardlink path: %m\n");
+ goto ERROR;
+ }
+
+ // Set hardlink path
+ archive_entry_set_hardlink(entry, buffer);
+ }
+ }
+
+ if (configfile) {
+ // Fetch path again since we changed it
+ path = archive_entry_pathname(entry);
+
+ if (pakfire_path_exists(path)) {
+ CTX_DEBUG(ctx, "The configuration file %s exists\n",
+ pakfire_file_get_path(file));
+
+ r = pakfire_string_format(buffer, "%s.paknew", path);
+ if (r < 0) {
+ CTX_ERROR(ctx, "Could not compose path for configuration file: %m\n");
+ goto ERROR;
+ }
+
+ // Set the path again
+ archive_entry_set_pathname(entry, buffer);
+ }
+ }
+
+ // We are done if we are running in dry-run mode
+ if (state->flags & PAKFIRE_EXTRACT_DRY_RUN)
+ goto ERROR;
+
+ struct archive* writer = pakfire_get_disk_writer(archive->pakfire);
+
+ // Fetch path again since we changed it
+ path = archive_entry_pathname(entry);
+
+ CTX_DEBUG(ctx, "Extracting %s\n", path);
+
+ // Remove any extended attributes which we never write to disk
+ archive_entry_xattr_clear(entry);
+
+ // Set capabilities
+ if (pakfire_file_has_caps(file)) {
+ r = pakfire_file_write_fcaps(file, &cap_data);
+ if (r)
+ goto ERROR;
+
+ // Store capabilities in archive entry
+ archive_entry_xattr_add_entry(entry,
+ "security.capability", &cap_data, sizeof(cap_data));
+ }
+
+ // Write payload
+ r = archive_read_extract2(state->a, entry, writer);
+ switch (r) {
+ case ARCHIVE_OK:
+ r = 0;
+ break;
+
+ case ARCHIVE_WARN:
+ CTX_ERROR(ctx, "%s\n", archive_error_string(writer));
+
+ // Pretend everything has been okay
+ r = 0;
+ break;
+
+ case ARCHIVE_FATAL:
+ CTX_ERROR(ctx, "%s\n", archive_error_string(writer));
+ r = 1;
+ break;
+ }
+
+ERROR:
+ if (file)
+ pakfire_file_unref(file);
+
+ return r;
+}
+
+static int __pakfire_archive_extract(struct pakfire_archive* archive, const char* path, int flags) {
struct pakfire_package* pkg = NULL;
+ char prefix[PATH_MAX] = "/";
struct archive* a = NULL;
- char prefix[PATH_MAX] = "";
- int r = 1;
+ int r;
+
+ CTX_DEBUG(archive->ctx, "Extracting %s\n", archive->path);
+
+ int progress_flags = PAKFIRE_PROGRESS_SHOW_PERCENTAGE;
+
+ // Should we show any progress?
+ if (flags & PAKFIRE_EXTRACT_NO_PROGRESS)
+ progress_flags |= PAKFIRE_PROGRESS_NO_PROGRESS;
+
+ // Show throughput?
+ if (flags & PAKFIRE_EXTRACT_SHOW_THROUGHPUT)
+ progress_flags |= PAKFIRE_PROGRESS_SHOW_TRANSFER_SPEED;
// Fetch package
pkg = pakfire_archive_get_package(archive);
- if (!pkg)
+ if (!pkg) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Open the archive
+ a = open_archive(archive, NULL);
+ if (!a) {
+ r = -errno;
goto ERROR;
+ }
// Fetch NEVRA
const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA);
- CTX_DEBUG(archive->ctx, "Extracting %s\n", archive->path);
+ // Create the progress indicator
+ r = pakfire_progress_create(&archive->progress, archive->ctx, progress_flags, NULL);
+ if (r < 0)
+ goto ERROR;
+
+ // Set the title
+ r = pakfire_progress_set_title(archive->progress, "%s", nevra);
+ if (r < 0)
+ goto ERROR;
// Copy everything to path if set
if (path) {
r = pakfire_string_set(prefix, path);
- if (r)
+ if (r < 0)
goto ERROR;
// Set prefix for source packages
} else if (pakfire_package_is_source(pkg)) {
r = pakfire_path(archive->pakfire, prefix, "/usr/src/packages/%s", nevra);
- if (r)
+ if (r < 0)
goto ERROR;
// Otherwise extract relative to the pakfire root
} else {
r = pakfire_path(archive->pakfire, prefix, "%s", "/");
- if (r)
+ if (r < 0)
goto ERROR;
}
// Load the filelist (if not done already)
if (!archive->filelist) {
- r = pakfire_filelist_create(&filelist, archive->pakfire);
- if (r)
+ r = pakfire_filelist_create(&archive->filelist, archive->pakfire);
+ if (r < 0)
goto ERROR;
}
- // Open the archive
- a = open_archive(archive, NULL);
- if (!a) {
- r = 1;
+ // Create state
+ struct pakfire_extract_state state = {
+ .archive = archive,
+ .a = a,
+ .prefix = prefix,
+ .flags = flags,
+ };
+
+ // Register progress callback
+ archive_read_extract_set_progress_callback(a, pakfire_extract_progress, &state);
+
+ // Start progress
+ r = pakfire_progress_start(archive->progress, archive->stat.st_size);
+ if (r < 0)
goto ERROR;
- }
- // Extract
- r = pakfire_extract(archive->pakfire, a, archive->stat.st_size,
- filelist, prefix, nevra, pakfire_archive_filter_payload, flags);
+ // Walk through the entire archive and extract everything
+ r = pakfire_archive_walk(archive, a,
+ pakfire_archive_extract_one, pakfire_archive_filter_payload, &state);
if (r)
goto ERROR;
- // Store the filelist permanently
- if (!archive->filelist)
- archive->filelist = pakfire_filelist_ref(filelist);
-
ERROR:
- if (filelist)
- pakfire_filelist_unref(filelist);
+ // Finish the progress
+ pakfire_progress_finish(archive->progress);
+
if (pkg)
pakfire_package_unref(pkg);
if (a)
systemd sysusers
*/
static int pakfire_archive_filter_systemd_sysusers(struct pakfire_ctx* ctx,
- struct archive* a, struct archive_entry* e, void* data) {
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* e, void* data) {
const char* path = archive_entry_pathname(e);
if (!pakfire_path_match("usr/lib/sysusers.d/*.conf", path))
}
static int pakfire_archive_handle_systemd_sysusers(struct pakfire_ctx* ctx,
- struct archive* a, struct archive_entry* e, void* data) {
+ struct pakfire_archive* archive, struct archive* a, struct archive_entry* e, void* data) {
struct pakfire_jail* jail = NULL;
char replace[PATH_MAX];
int r;
- struct pakfire* pakfire = data;
-
// Fetch path
const char* path = archive_entry_pathname(e);
const char* argv[] = { "/usr/bin/systemd-sysusers", replace, "-", NULL };
// Create a new jail
- r = pakfire_jail_create(&jail, pakfire);
+ r = pakfire_jail_create(&jail, archive->pakfire);
if (r)
goto ERROR;
}
int pakfire_archive_apply_systemd_sysusers(struct pakfire_archive* archive) {
- pakfire_archive_walk(archive, pakfire_archive_handle_systemd_sysusers,
- pakfire_archive_filter_systemd_sysusers, archive->pakfire);
+ struct archive* a = NULL;
+
+ // Open the archive
+ a = open_archive(archive, NULL);
+ if (!a)
+ return -errno;
+
+ pakfire_archive_walk(archive, a, pakfire_archive_handle_systemd_sysusers,
+ pakfire_archive_filter_systemd_sysusers, NULL);
+
+ if (a)
+ archive_read_free(a);
return 0;
}
return NULL;
}
-/*
- Helper function to conditionally walk through an archive
- and perform actions based on the callback.
-*/
-int pakfire_walk(struct pakfire_ctx* ctx, struct archive* archive,
- pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback,
- void* p) {
- struct archive_entry* entry = NULL;
- int r;
-
- // Walk through the archive
- for (;;) {
- r = archive_read_next_header(archive, &entry);
-
- // Handle the return code
- switch (r) {
- // Fall through if everything is okay
- case ARCHIVE_OK:
- break;
-
- // Return OK when we reached the end of the archive
- case ARCHIVE_EOF:
- return 0;
-
- // Raise any other errors
- default:
- return r;
- }
-
- // Call the filter callback before we call the actual callback
- if (filter_callback) {
- r = filter_callback(ctx, archive, entry, p);
-
- // Handle the return code
- switch (r) {
- case PAKFIRE_WALK_OK:
- break;
-
- case PAKFIRE_WALK_END:
- CTX_DEBUG(ctx, "Filter callback sent END\n");
- return 0;
-
- case PAKFIRE_WALK_SKIP:
- CTX_DEBUG(ctx, "Filter callback sent SKIP\n");
- continue;
-
- case PAKFIRE_WALK_DONE:
- CTX_DEBUG(ctx, "Filter callback sent DONE\n");
-
- // Clear the callback function
- filter_callback = NULL;
- break;
-
- case PAKFIRE_WALK_AGAIN:
- CTX_DEBUG(ctx, "Filter callback sent AGAIN\n");
- return -EAGAIN;
-
- // Raise any other errors
- default:
- CTX_DEBUG(ctx, "Filter callback returned an error: %d\n", r);
- return r;
- }
- }
-
- // Run callback
- if (callback) {
- r = callback(ctx, archive, entry, p);
-
- // Handle the return code
- switch (r) {
- case PAKFIRE_WALK_OK:
- break;
-
- case PAKFIRE_WALK_DONE:
- CTX_DEBUG(ctx, "Callback sent DONE\n");
- return 0;
-
- // Raise any other errors
- default:
- return r;
- }
- }
- }
-
- return 0;
-}
-
-// Common extraction
-
-struct pakfire_extract {
- // Reference to Pakfire
- struct pakfire* pakfire;
-
- // Flags
- int flags;
-
- // The archive to extract
- struct archive* archive;
-
- // The filelist of all extracted files
- struct pakfire_filelist* filelist;
-
- // Prepend this prefix
- const char* prefix;
-
- // The writer
- struct archive* writer;
-
- // The progress indicator
- struct pakfire_progress* progress;
-};
-
-static void pakfire_extract_progress(void* p) {
- struct pakfire_extract* data = (struct pakfire_extract*)p;
-
- // Fetch how many bytes have been read
- const size_t position = archive_filter_bytes(data->archive, -1);
-
- // Update progress
- pakfire_progress_update(data->progress, position);
-}
-
-static int __pakfire_extract(struct pakfire_ctx* ctx, struct archive* a,
- struct archive_entry* entry, void* p) {
- struct pakfire_file* file = NULL;
- struct vfs_cap_data cap_data = {};
- char buffer[PATH_MAX];
- int r;
-
- struct pakfire_extract* data = (struct pakfire_extract*)p;
-
- // Fetch path
- const char* path = archive_entry_pathname(entry);
-
- // Make sure we have a leading slash on the filelist
- if (!pakfire_string_startswith(path, "/")) {
- r = pakfire_string_format(buffer, "/%s", path);
- if (r)
- goto ERROR;
-
- // Store the new name
- archive_entry_set_pathname(entry, buffer);
-
- // Update the path pointer
- path = archive_entry_pathname(entry);
- }
-
- // Generate a file object
- r = pakfire_file_create_from_archive_entry(&file, data->pakfire, entry);
- if (r)
- goto ERROR;
-
- // Add entry to filelist (if requested)
- if (data->filelist) {
- // Append the file to the list
- r = pakfire_filelist_add(data->filelist, file);
- if (r)
- goto ERROR;
- }
-
- const int configfile = pakfire_file_has_flag(file, PAKFIRE_FILE_CONFIG);
-
- // Prepend the prefix
- if (*data->prefix) {
- // Compose file path
- r = pakfire_path_append(buffer, data->prefix, path);
- if (r) {
- CTX_ERROR(ctx, "Could not compose file path: %m\n");
- goto ERROR;
- }
-
- // Set file path
- archive_entry_set_pathname(entry, buffer);
-
- // Update hardlink destination
- const char* link = archive_entry_hardlink(entry);
- if (link) {
- r = pakfire_path_append(buffer, data->prefix, link);
- if (r) {
- CTX_ERROR(ctx, "Could not compose hardlink path: %m\n");
- goto ERROR;
- }
-
- // Set hardlink path
- archive_entry_set_hardlink(entry, buffer);
- }
- }
-
- if (configfile) {
- // Fetch path again since we changed it
- path = archive_entry_pathname(entry);
-
- if (pakfire_path_exists(path)) {
- CTX_DEBUG(ctx, "The configuration file %s exists\n",
- pakfire_file_get_path(file));
-
- r = pakfire_string_format(buffer, "%s.paknew", path);
- if (r) {
- CTX_ERROR(ctx, "Could not compose path for configuration file: %m\n");
- goto ERROR;
- }
-
- // Set the path again
- archive_entry_set_pathname(entry, buffer);
- }
- }
-
- // Create file & extract payload
- if (data->writer) {
- // Fetch path again since we changed it
- path = archive_entry_pathname(entry);
-
- CTX_DEBUG(ctx, "Extracting %s\n", path);
-
- // Remove any extended attributes which we never write to disk
- archive_entry_xattr_clear(entry);
-
- // Set capabilities
- if (pakfire_file_has_caps(file)) {
- r = pakfire_file_write_fcaps(file, &cap_data);
- if (r)
- goto ERROR;
-
- // Store capabilities in archive entry
- archive_entry_xattr_add_entry(entry, "security.capability",
- &cap_data, sizeof(cap_data));
- }
-
- // Write payload
- r = archive_read_extract2(data->archive, entry, data->writer);
- switch (r) {
- case ARCHIVE_OK:
- r = 0;
- break;
-
- case ARCHIVE_WARN:
- CTX_ERROR(ctx, "%s\n", archive_error_string(data->writer));
-
- // Pretend everything has been okay
- r = 0;
- break;
-
- case ARCHIVE_FATAL:
- CTX_ERROR(ctx, "%s\n", archive_error_string(data->writer));
- r = 1;
- break;
- }
- }
-
-ERROR:
- if (file)
- pakfire_file_unref(file);
-
- return r;
-}
-
-int pakfire_extract(struct pakfire* pakfire, struct archive* archive,
- size_t size, struct pakfire_filelist* filelist,
- const char* prefix, const char* message,
- pakfire_walk_filter_callback filter_callback, int flags) {
- int progress_flags = PAKFIRE_PROGRESS_SHOW_PERCENTAGE;
- int r = 1;
-
- struct pakfire_ctx* ctx = pakfire_ctx(pakfire);
-
- // Use / if no prefix is set
- if (!prefix)
- prefix = "/";
-
- struct pakfire_extract data = {
- .pakfire = pakfire,
- .archive = archive,
- .filelist = filelist,
- .prefix = prefix,
- .flags = flags,
- .writer = NULL,
- };
-
- // Is this a dry run?
- const int dry_run = flags & PAKFIRE_EXTRACT_DRY_RUN;
-
- // Allocate writer
- if (!dry_run) {
- data.writer = pakfire_make_archive_disk_writer(pakfire, 1);
- if (!data.writer) {
- CTX_ERROR(ctx, "Could not create disk writer: %m\n");
- r = 1;
- goto ERROR;
- }
- }
-
- // Should we show any progress?
- if (flags & PAKFIRE_EXTRACT_NO_PROGRESS)
- progress_flags |= PAKFIRE_PROGRESS_NO_PROGRESS;
-
- // Show throughput?
- if (flags & PAKFIRE_EXTRACT_SHOW_THROUGHPUT)
- progress_flags |= PAKFIRE_PROGRESS_SHOW_TRANSFER_SPEED;
-
- // Create the progress indicator
- r = pakfire_progress_create(&data.progress, ctx, progress_flags, NULL);
- if (r)
- goto ERROR;
-
- // Set the title
- r = pakfire_progress_set_title(data.progress, "%s", message);
- if (r)
- goto ERROR;
-
- // Register progress callback
- archive_read_extract_set_progress_callback(data.archive,
- pakfire_extract_progress, &data);
-
- // Start progress
- r = pakfire_progress_start(data.progress, size);
- if (r)
- goto ERROR;
-
- // Walk through the entire archive
- r = pakfire_walk(ctx, archive, __pakfire_extract, filter_callback, &data);
- if (r)
- goto ERROR;
-
- // Finish the progress
- r = pakfire_progress_finish(data.progress);
- if (r)
- goto ERROR;
-
-ERROR:
- if (data.progress)
- pakfire_progress_unref(data.progress);
- if (data.writer)
- archive_write_free(data.writer);
- if (ctx)
- pakfire_ctx_unref(ctx);
-
- return r;
-}
-
// Common compression
struct pakfire_compress {