return r;
}
+
+// Common compression
+
+struct pakfire_compress {
+ // Reference to Pakfire
+ struct pakfire* pakfire;
+
+ // Flags
+ int flags;
+
+ // The archive to write to
+ struct archive* archive;
+
+ // The filelist of all files to write
+ struct pakfire_filelist* filelist;
+
+ // The progressbar
+ struct pakfire_progressbar* progressbar;
+
+ // Digests to write to the archive
+ int digests;
+};
+
+static int pakfire_compress_progressbar_create(struct pakfire_progressbar** progressbar,
+ const char* message, int flags) {
+ int r;
+
+ // Create the progressbar
+ r = pakfire_progressbar_create(progressbar, NULL);
+ if (r)
+ return r;
+
+ // Add message
+ if (message) {
+ r = pakfire_progressbar_add_string(*progressbar, "%s", message);
+ if (r)
+ return r;
+ }
+
+ // Add bar
+ r = pakfire_progressbar_add_bar(*progressbar);
+ if (r)
+ return r;
+
+ // Add throughput
+ if (flags & PAKFIRE_COMPRESS_SHOW_THROUGHPUT) {
+ r = pakfire_progressbar_add_transfer_speed(*progressbar);
+ if (r)
+ return r;
+ }
+
+ // Add percentage
+ r = pakfire_progressbar_add_percentage(*progressbar);
+ if (r)
+ return r;
+
+ // Success
+ return 0;
+}
+
+static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file, void* p) {
+ struct archive_entry* entry = NULL;
+ FILE* f = NULL;
+ int r = 1;
+
+ struct pakfire_compress* data = (struct pakfire_compress*)p;
+
+ // Fetch type
+ const mode_t type = pakfire_file_get_type(file);
+
+ // Fetch the filelist
+ const size_t size = pakfire_file_get_size(file);
+
+ // Generate file metadata into an archive entry
+ entry = pakfire_file_archive_entry(file, data->digests);
+ if (!entry) {
+ r = 1;
+ goto ERROR;
+ }
+
+ // Write the header
+ r = archive_write_header(data->archive, entry);
+ if (r) {
+ ERROR(pakfire, "Error writing file header: %s\n",
+ archive_error_string(data->archive));
+ goto ERROR;
+ }
+
+ // Copy the data of regular files
+ if (type == S_IFREG) {
+ // Open the file
+ f = pakfire_file_open(file);
+ if (!f) {
+ r = 1;
+ goto ERROR;
+ }
+
+ // Copy the payload into the archive
+ r = pakfire_archive_copy_data_from_file(pakfire, data->archive, f);
+ if (r)
+ goto ERROR;
+ }
+
+ // Write trailer
+ r = archive_write_finish_entry(data->archive);
+ if (r)
+ goto ERROR;
+
+ // Update the progressbar
+ if (data->progressbar)
+ pakfire_progressbar_increment(data->progressbar, size);
+
+ERROR:
+ if (f)
+ fclose(f);
+ if (entry)
+ archive_entry_free(entry);
+
+ return r;
+}
+
+int pakfire_compress(struct pakfire* pakfire, struct archive* archive,
+ struct pakfire_filelist* filelist, const char* message, int flags, int digests) {
+ int r = 1;
+
+ struct pakfire_compress data = {
+ .pakfire = pakfire,
+ .archive = archive,
+ .filelist = filelist,
+ .flags = flags,
+ .digests = digests,
+ };
+
+ // Should we show a progress bar?
+ const int no_progress = flags & PAKFIRE_COMPRESS_NO_PROGRESS;
+
+ // Fetch the length of the filelist
+ const size_t size = pakfire_filelist_total_size(filelist);
+
+ // Create the progressbar
+ if (!no_progress) {
+ r = pakfire_compress_progressbar_create(&data.progressbar, message, flags);
+ if (r)
+ goto ERROR;
+
+ // Start progressbar
+ pakfire_progressbar_start(data.progressbar, size);
+ }
+
+ // Walk through the entire filelist
+ r = pakfire_filelist_walk(filelist, __pakfire_compress, &data);
+ if (r)
+ goto ERROR;
+
+ // Finish the progressbar
+ if (data.progressbar)
+ pakfire_progressbar_finish(data.progressbar);
+
+ERROR:
+ if (data.progressbar)
+ pakfire_progressbar_unref(data.progressbar);
+
+ return r;
+}
int pakfire_snapshot_create(struct pakfire* pakfire, const char* path) {
struct pakfire_filelist* filelist = NULL;
- struct archive* a = NULL;
+ struct archive* archive = NULL;
int r = 1;
// Check input
// Sort the filelist in place
pakfire_filelist_sort(filelist);
- a = pakfire_snapshot_create_archive(pakfire, path);
- if (!a) {
+ archive = pakfire_snapshot_create_archive(pakfire, path);
+ if (!archive) {
ERROR(pakfire, "Could not open archive for writing\n");
goto ERROR;
}
- for (unsigned int i = 0; i < size; i++) {
- struct pakfire_file* file = pakfire_filelist_get(filelist, i);
- if (!file)
- continue;
-
- FILE* f = NULL;
-
- // Make archive entry
- struct archive_entry* entry = pakfire_file_archive_entry(file, PAKFIRE_DIGEST_UNDEFINED);
- if (!entry) {
- ERROR(pakfire, "Could not make archive entry from file: %m\n");
- r = 1;
- goto OUT;
- }
-
- // Write header
- r = archive_write_header(a, entry);
- if (r) {
- ERROR(pakfire, "Could not write header: %s\n", archive_error_string(a));
- goto OUT;
- }
-
- // Copy payload
- if (archive_entry_filetype(entry) == AE_IFREG) {
- f = pakfire_file_open(file);
- if (!f) {
- r = 1;
- goto OUT;
- }
-
- r = pakfire_archive_copy_data_from_file(pakfire, a, f);
- if (r) {
- ERROR(pakfire, "Could not copy %s\n", archive_entry_pathname(entry));
- goto OUT;
- }
- }
-
- // Write trailer
- r = archive_write_finish_entry(a);
- if (r)
- goto OUT;
-
-OUT:
- if (file)
- pakfire_file_unref(file);
- if (f)
- fclose(f);
-
- // Move on to ERROR
- if (r)
- goto ERROR;
- }
+ // Write the payload to the archive
+ r = pakfire_compress(pakfire, archive, filelist, _("Writing snapshot..."),
+ PAKFIRE_COMPRESS_SHOW_THROUGHPUT, 0);
+ if (r)
+ goto ERROR;
// Close archive
- r = archive_write_close(a);
+ r = archive_write_close(archive);
if (r) {
- ERROR(pakfire, "Could not close archive: %s\n", archive_error_string(a));
+ ERROR(pakfire, "Could not close archive: %s\n", archive_error_string(archive));
goto ERROR;
}
ERROR:
if (filelist)
pakfire_filelist_unref(filelist);
- if (a)
- archive_write_free(a);
+ if (archive)
+ archive_write_free(archive);
return r;
}