// The archive to write to
struct archive* archive;
+ // Resolver for hardlinks
+ struct archive_entry_linkresolver* linkresolver;
+
// The filelist of all files to write
struct pakfire_filelist* filelist;
return 0;
}
-static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file, void* p) {
- struct archive_entry* entry = NULL;
+static int __pakfire_compress_entry(struct pakfire* pakfire, struct pakfire_file* file,
+ struct pakfire_compress* data, struct archive_entry* entry) {
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;
- }
+ int r;
// Write the header
r = archive_write_header(data->archive, entry);
goto ERROR;
}
- // Copy the data of regular files
- if (type == S_IFREG) {
+ // Copy the data if there is any
+ if (archive_entry_size(entry)) {
// Open the file
f = pakfire_file_open(file);
if (!f) {
if (r)
goto ERROR;
+ERROR:
+ if (f)
+ fclose(f);
+
+ return r;
+}
+
+static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file, void* p) {
+ struct archive_entry* entry = NULL;
+ struct archive_entry* sparse_entry = NULL;
+ int r = 1;
+
+ struct pakfire_compress* data = (struct pakfire_compress*)p;
+
+ // Fetch the file size
+ 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;
+ }
+
+ // Perform search for hardlinks
+ archive_entry_linkify(data->linkresolver, &entry, &sparse_entry);
+
+ // Write the main entry
+ if (entry) {
+ r = __pakfire_compress_entry(pakfire, file, data, entry);
+ if (r)
+ goto ERROR;
+ }
+
+ // Write the sparse entry
+ if (sparse_entry) {
+ r = __pakfire_compress_entry(pakfire, file, data, sparse_entry);
+ if (r)
+ goto ERROR;
+ }
+
+ // Query the link resolver for any more entries
+ for (;;) {
+ // Free the entry
+ if (entry) {
+ archive_entry_free(entry);
+ entry = NULL;
+ }
+
+ // Free the sparse entry
+ if (sparse_entry) {
+ archive_entry_free(sparse_entry);
+ sparse_entry = NULL;
+ }
+
+ // Fetch the next entry
+ archive_entry_linkify(data->linkresolver, &entry, &sparse_entry);
+ if (!entry)
+ break;
+
+ // Write the entry to the archive
+ r = __pakfire_compress_entry(pakfire, file, data, entry);
+ 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);
+ if (sparse_entry)
+ archive_entry_free(sparse_entry);
return r;
}
pakfire_progressbar_start(data.progressbar, size);
}
+ // Setup the link resolver
+ data.linkresolver = archive_entry_linkresolver_new();
+ if (!data.linkresolver) {
+ ERROR(pakfire, "Could not setup link resolver: m\n");
+ goto ERROR;
+ }
+
+ // Set the link resolver strategy
+ archive_entry_linkresolver_set_strategy(data.linkresolver, archive_format(archive));
+
// Walk through the entire filelist
r = pakfire_filelist_walk(filelist, __pakfire_compress, &data);
if (r)
ERROR:
if (data.progressbar)
pakfire_progressbar_unref(data.progressbar);
+ if (data.linkresolver)
+ archive_entry_linkresolver_free(data.linkresolver);
return r;
}