]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/packager.c
packager: Set creation time and ownership for files
[people/ms/pakfire.git] / src / libpakfire / packager.c
CommitLineData
6aeb48e6
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2021 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
1ea1f35b
MT
22#include <fcntl.h>
23#include <linux/limits.h>
6aeb48e6 24#include <stdlib.h>
da08f989
MT
25#include <sys/stat.h>
26#include <sys/types.h>
05cfc2c9 27#include <time.h>
da08f989 28#include <unistd.h>
6aeb48e6 29
1ea1f35b 30#include <archive.h>
da08f989 31#include <archive_entry.h>
1ea1f35b 32
2adc4a4a 33#include <pakfire/archive.h>
436677a3 34#include <pakfire/constants.h>
1ba1869e
MT
35#include <pakfire/file.h>
36#include <pakfire/filelist.h>
1ea1f35b 37#include <pakfire/logging.h>
6aeb48e6
MT
38#include <pakfire/package.h>
39#include <pakfire/packager.h>
40#include <pakfire/pakfire.h>
41#include <pakfire/private.h>
677e9e5b 42#include <pakfire/pwd.h>
6aeb48e6
MT
43#include <pakfire/types.h>
44
da08f989
MT
45#define BUFFER_SIZE 64 * 1024
46
6aeb48e6
MT
47struct pakfire_packager {
48 Pakfire pakfire;
49 int nrefs;
05cfc2c9 50 time_t time_created;
6aeb48e6
MT
51
52 PakfirePackage pkg;
1ba1869e 53 PakfireFilelist filelist;
1ea1f35b 54
738b3582
MT
55 // Reader
56 struct archive* reader;
57
58 // Payload
1ea1f35b 59 struct archive* payload;
7836e21b 60 FILE* fpayload;
6aeb48e6
MT
61};
62
1ea1f35b 63static int pakfire_packager_create_payload(struct pakfire_packager* p, int compress) {
7836e21b
MT
64 char path[] = "/tmp/.pakfire-payload.XXXXXX";
65
1ea1f35b 66 p->payload = archive_write_new();
427fdd80
MT
67 if (!p->payload) {
68 ERROR(p->pakfire, "archive_write_new() failed\n");
69 return 1;
70 }
1ea1f35b
MT
71
72 // Use the PAX format
73 int r = archive_write_set_format_pax(p->payload);
74 if (r) {
75 ERROR(p->pakfire, "Could not set format to PAX: %s\n",
76 archive_error_string(p->payload));
77 return r;
78 }
79
80 // Add filters to compress the payload
81 if (compress) {
82 // Enable Zstd
83 r = archive_write_add_filter_zstd(p->payload);
84 if (r) {
85 ERROR(p->pakfire, "Could not enable Zstandard compression: %s\n",
86 archive_error_string(p->payload));
87 return r;
88 }
89
90 // Set compression level to highest
91 r = archive_write_set_filter_option(p->payload, NULL, "compression-level", "19");
92 if (r) {
93 ERROR(p->pakfire, "Could not set Zstandard compression level: %s\n",
94 archive_error_string(p->payload));
95 return r;
96 }
97 }
98
7836e21b
MT
99 // Create a new temporary file
100 int fd = mkostemp(path, O_CLOEXEC);
1ea1f35b
MT
101 if (fd < 0) {
102 ERROR(p->pakfire, "mkostemp() failed: %s\n", strerror(errno));
103 return 1;
104 }
105
7836e21b
MT
106 // Unlink the file straight away
107 unlink(path);
108
109 // Convert the file descriptor into a file handle
110 p->fpayload = fdopen(fd, "w+");
111 if (!p->fpayload) {
112 close(fd);
113
114 return 1;
115 }
116
117 // Write archive to file
118 r = archive_write_open_FILE(p->payload, p->fpayload);
1ea1f35b
MT
119 if (r)
120 return r;
121
122 return 0;
123}
124
125static void pakfire_packager_free(struct pakfire_packager* packager) {
126 if (packager->payload)
127 archive_write_free(packager->payload);
128
7836e21b
MT
129 if (packager->fpayload)
130 fclose(packager->fpayload);
131
738b3582
MT
132 if (packager->reader)
133 archive_free(packager->reader);
134
1ba1869e 135 pakfire_filelist_unref(packager->filelist);
1ea1f35b
MT
136 pakfire_package_unref(packager->pkg);
137 pakfire_unref(packager->pakfire);
138}
139
677e9e5b
MT
140static const char* pakfire_packager_user_lookup(void* data, la_int64_t uid) {
141 Pakfire pakfire = (Pakfire)data;
142
143 // Fast path for "root"
144 if (uid == 0)
145 return "root";
146
147 // Find a matching entry in /etc/passwd
148 struct passwd* entry = pakfire_getpwuid(pakfire, uid);
149 if (!entry) {
150 ERROR(pakfire, "Could not retrieve uname for %ld: %s\n", uid, strerror(errno));
151 return 0;
152 }
153
154 DEBUG(pakfire, "Mapping UID %ld to %s\n", uid, entry->pw_name);
155
156 return entry->pw_name;
157}
158
159static const char* pakfire_packager_group_lookup(void* data, la_int64_t gid) {
160 Pakfire pakfire = (Pakfire)data;
161
162 // Fast path for "root"
163 if (gid == 0)
164 return "root";
165
166 // Find a matching entry in /etc/group
167 struct group* entry = pakfire_getgrgid(pakfire, gid);
168 if (!entry) {
169 ERROR(pakfire, "Could not retrieve gname for %ld: %s\n", gid, strerror(errno));
170 return 0;
171 }
172
173 DEBUG(pakfire, "Mapping GID %ld to %s\n", gid, entry->gr_name);
174
175 return entry->gr_name;
176}
177
0682aeb3
MT
178static int pakfire_packager_create_reader(struct pakfire_packager* p) {
179 // Open a reader
180 p->reader = archive_read_disk_new();
181 if (!p->reader) {
182 ERROR(p->pakfire, "archive_read_disk_new() failed\n");
183 return 1;
184 }
185
186 // Do not read fflags
187 int r = archive_read_disk_set_behavior(p->reader, ARCHIVE_READDISK_NO_FFLAGS);
188 if (r) {
189 ERROR(p->pakfire, "Could not change behavior of reader: %s\n",
190 archive_error_string(p->reader));
191 return 1;
192 }
193
677e9e5b
MT
194 // Install our own routine for user/group lookups
195 archive_read_disk_set_uname_lookup(p->reader, p->pakfire,
196 pakfire_packager_user_lookup, NULL);
197 archive_read_disk_set_gname_lookup(p->reader, p->pakfire,
198 pakfire_packager_group_lookup, NULL);
199
0682aeb3
MT
200 return 0;
201}
202
6aeb48e6
MT
203PAKFIRE_EXPORT int pakfire_packager_create(struct pakfire_packager** packager,
204 PakfirePackage pkg) {
205 struct pakfire_packager* p = calloc(1, sizeof(*p));
206 if (!p)
207 return ENOMEM;
208
05cfc2c9
MT
209 // Save creation time
210 p->time_created = time(NULL);
211
6aeb48e6
MT
212 // Initialize reference counting
213 p->nrefs = 1;
214
215 // Store a reference to Pakfire
216 p->pakfire = pakfire_package_get_pakfire(pkg);
217
218 // Store a reference to the package
219 p->pkg = pakfire_package_ref(pkg);
220
1ba1869e 221 // Create a new filelist
883b3be9 222 int r = pakfire_filelist_create(&p->filelist, p->pakfire);
1ba1869e
MT
223 if (r)
224 goto ERROR;
225
0682aeb3
MT
226 // Create reader
227 r = pakfire_packager_create_reader(p);
1ba1869e
MT
228 if (r)
229 goto ERROR;
1ea1f35b 230
0682aeb3
MT
231 // Start payload
232 r = pakfire_packager_create_payload(p, 1);
233 if (r)
738b3582 234 goto ERROR;
738b3582 235
6aeb48e6
MT
236 *packager = p;
237
238 return 0;
1ba1869e
MT
239
240ERROR:
241 pakfire_packager_free(p);
242
243 return r;
6aeb48e6
MT
244}
245
6aeb48e6
MT
246PAKFIRE_EXPORT struct pakfire_packager* pakfire_packager_ref(
247 struct pakfire_packager* packager) {
248 ++packager->nrefs;
249
250 return packager;
251}
252
253PAKFIRE_EXPORT struct pakfire_packager* pakfire_packager_unref(
254 struct pakfire_packager* packager) {
255 if (--packager->nrefs > 0)
256 return packager;
257
258 pakfire_packager_free(packager);
259
260 return NULL;
261}
da08f989 262
7836e21b
MT
263static int pakfire_packager_copy_data(struct pakfire_packager* packager,
264 struct archive* a, FILE* f) {
265 char buffer[BUFFER_SIZE];
266
267 while (!feof(f)) {
268 // Read a block from file
269 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
270
271 // Check if any error occured
272 if (ferror(f)) {
273 ERROR(packager->pakfire, "Error reading from file: %s\n", strerror(errno));
274 return 1;
275 }
276
277 // Write the block to the archive
278 ssize_t bytes_written = archive_write_data(a, buffer, bytes_read);
279 if (bytes_written < 0) {
280 ERROR(packager->pakfire, "Error writing data to archive: %s\n",
281 archive_error_string(a));
282 return 1;
283 }
284 }
285
286 return 0;
287}
288
98e85f1c
MT
289static int pakfire_packager_write_file_from_buffer(struct pakfire_packager* packager,
290 struct archive* a, const char* filename, const char* buffer) {
291 // Create a new file entry
292 struct archive_entry* entry = archive_entry_new();
293 if (!entry)
294 return 1;
295
296 // Set filename
297 archive_entry_set_pathname(entry, filename);
298
299 // This is a regular file
300 archive_entry_set_filetype(entry, AE_IFREG);
301 archive_entry_set_perm(entry, 0644);
302
05cfc2c9
MT
303 // Set ownership
304 archive_entry_set_uname(entry, "root");
305 archive_entry_set_uid(entry, 0);
306 archive_entry_set_gname(entry, "root");
307 archive_entry_set_gid(entry, 0);
308
309 // Set times
310 archive_entry_set_birthtime(entry, packager->time_created, 0);
311 archive_entry_set_ctime(entry, packager->time_created, 0);
312 archive_entry_set_mtime(entry, packager->time_created, 0);
313 archive_entry_set_atime(entry, packager->time_created, 0);
314
98e85f1c
MT
315 // Set length
316 archive_entry_set_size(entry, strlen(buffer));
317
318 // This is the end of the header
319 int r = archive_write_header(a, entry);
320 if (r) {
321 ERROR(packager->pakfire, "Error writing header: %s\n", archive_error_string(a));
322 archive_entry_free(entry);
323 return r;
324 }
325
326 // Write content
327 r = archive_write_data(a, buffer, strlen(buffer));
328 if (r < 0) {
329 ERROR(packager->pakfire, "Error writing data: %s\n", archive_error_string(a));
330 archive_entry_free(entry);
331 return r;
332 }
333
334 archive_entry_free(entry);
335
336 return 0;
337}
338
436677a3
MT
339static int pakfire_packager_write_format(struct pakfire_packager* packager,
340 struct archive* a) {
341 const char buffer[] = TO_STRING(PACKAGE_FORMAT) "\n";
342
a18d6f8b
MT
343 return pakfire_packager_write_file_from_buffer(packager, a,
344 PAKFIRE_ARCHIVE_FN_FORMAT, buffer);
436677a3
MT
345}
346
98e85f1c
MT
347static char* pakfire_package_make_metadata(struct pakfire_packager* packager) {
348 PakfirePackage pkg = packager->pkg;
349
350 char* buffer = NULL;
351 int r;
352
353 // Print version information
354 r = asprintf(&buffer, "# Pakfire %s\n\n", PACKAGE_VERSION);
355 if (r < 0)
356 goto ERROR;
357
358 // Write package information
359 r = asprintf(&buffer, "%s# Package information\npackage\n", buffer);
360 if (r < 0)
361 goto ERROR;
362
363 // Write package name
364 r = asprintf(&buffer, "%s\tname = %s\n", buffer, pakfire_package_get_name(pkg));
365 if (r < 0)
366 goto ERROR;
367
368 // Write package version
369 r = asprintf(&buffer, "%s\tversion = %s\n", buffer, pakfire_package_get_version(pkg));
370 if (r < 0)
371 goto ERROR;
372
373 // Write package release
374 r = asprintf(&buffer, "%s\trelease = %s\n", buffer, pakfire_package_get_release(pkg));
375 if (r < 0)
376 goto ERROR;
377
378 // Write package epoch
379 r = asprintf(&buffer, "%s\tepoch = %lu\n", buffer, pakfire_package_get_epoch(pkg));
380 if (r < 0)
381 goto ERROR;
382
383 // Write package arch
384 r = asprintf(&buffer, "%s\tarch = %s\n", buffer, pakfire_package_get_arch(pkg));
385 if (r < 0)
386 goto ERROR;
387
388 // Write package UUID
389 r = asprintf(&buffer, "%s\tuuid = %s\n", buffer, pakfire_package_get_uuid(pkg));
390 if (r < 0)
391 goto ERROR;
392
393 // Write package groups
394 const char* groups = pakfire_package_get_groups(pkg);
395 if (groups) {
396 r = asprintf(&buffer, "%s\tgroups = %s\n", buffer, groups);
397 if (r < 0)
398 goto ERROR;
399 }
400
401 // Write package maintainer
402 const char* maintainer = pakfire_package_get_maintainer(pkg);
403 if (maintainer) {
404 r = asprintf(&buffer, "%s\tmaintainer = %s\n", buffer, maintainer);
405 if (r < 0)
406 goto ERROR;
407 }
408
409 // Write package url
410 const char* url = pakfire_package_get_maintainer(pkg);
411 if (url) {
412 r = asprintf(&buffer, "%s\turl = %s\n", buffer, url);
413 if (r < 0)
414 goto ERROR;
415 }
416
417 // Write package license
418 const char* license = pakfire_package_get_license(pkg);
419 if (license) {
420 r = asprintf(&buffer, "%s\tlicense = %s\n", buffer, license);
421 if (r < 0)
422 goto ERROR;
423 }
424
425 // Write package summary
426 const char* summary = pakfire_package_get_summary(pkg);
427 if (summary) {
428 r = asprintf(&buffer, "%s\tsummary = %s\n", buffer, summary);
429 if (r < 0)
430 goto ERROR;
431 }
432
433 // XXX description
434
435 size_t size = pakfire_package_get_installsize(pkg);
436 r = asprintf(&buffer, "%s\tsize = %zu\n", buffer, size);
437 if (r < 0)
438 goto ERROR;
439
440 // End package block
441 r = asprintf(&buffer, "%send\n\n", buffer);
442 if (r < 0)
443 goto ERROR;
444
445 // Write build information
446 r = asprintf(&buffer, "%s# Build information\nbuild\n", buffer);
447 if (r < 0)
448 goto ERROR;
449
450 // Write build host
451 const char* build_host = pakfire_package_get_build_host(pkg);
452 if (build_host) {
453 r = asprintf(&buffer, "%s\thost = %s\n", buffer, build_host);
454 if (r < 0)
455 goto ERROR;
456 }
457
458#if 0
459 // Write build id
460 const char* build_id = pakfire_package_get_build_id(pkg);
461 if (build_id) {
462 r = asprintf(&buffer, "%s\tid = %s\n", buffer, build_id);
463 if (r < 0)
464 goto ERROR;
465 }
466#endif
467
468 // Write build host
469 time_t build_time = pakfire_package_get_build_time(pkg);
470 if (build_host) {
471 r = asprintf(&buffer, "%s\ttime = %lu\n", buffer, build_time);
472 if (r < 0)
473 goto ERROR;
474 }
475
476 // End build block
477 r = asprintf(&buffer, "%send\n\n", buffer);
478 if (r < 0)
479 goto ERROR;
480
481#if 0
482 // Write distribution information
483 r = asprintf(&buffer, "%s# Distribution information\ndistribution\n", buffer);
484 if (r < 0)
485 goto ERROR;
486
487 // End distribution block
488 r = asprintf(&buffer, "%send\n\n", buffer);
489 if (r < 0)
490 goto ERROR;
491#endif
492
493 // Write dependency information
494 r = asprintf(&buffer, "%s# Dependency information\ndependencies\n", buffer);
495 if (r < 0)
496 goto ERROR;
497
498 const struct dependencies {
499 const char* type;
500 PakfireRelationList (*func)(PakfirePackage pkg);
501 } dependencies[] = {
502 { "prerequires", pakfire_package_get_prerequires },
503 { "requires", pakfire_package_get_requires },
504 { "provides", pakfire_package_get_provides },
505 { "conflicts", pakfire_package_get_conflicts },
506 { "obsoletes", pakfire_package_get_obsoletes },
507 { "recommends", pakfire_package_get_recommends },
508 { "suggests", pakfire_package_get_suggests },
509 { "supplements", pakfire_package_get_supplements },
510 { "enhances", pakfire_package_get_enhances },
511 { NULL },
512 };
513
514 for (const struct dependencies* d = dependencies; d->type; d++) {
515 PakfireRelationList list = d->func(pkg);
516 if (!list)
517 continue;
518
519 size_t l = pakfire_relationlist_size(list);
520
521 // Skip for empty lists
522 if (l == 0) {
523 pakfire_relationlist_unref(list);
524 continue;
525 }
526
527 // Write header
528 r = asprintf(&buffer, "%s\t%s\n", buffer, d->type);
529 if (r < 0) {
530 pakfire_relationlist_unref(list);
531 goto ERROR;
532 }
533
534 for (unsigned int i = 0; i < l; i++) {
535 PakfireRelation rel = pakfire_relationlist_get(list, i);
536
537 char* s = pakfire_relation_str(rel);
538 if (s) {
539 r = asprintf(&buffer, "%s\t\t%s\n", buffer, s);
540 free(s);
541 if (r < 0) {
542 pakfire_relationlist_unref(list);
543 pakfire_relation_unref(rel);
544 goto ERROR;
545 }
546 }
547
548 pakfire_relation_unref(rel);
549 }
550
551 // End block
552 r = asprintf(&buffer, "%s\tend\n", buffer);
553 if (r < 0)
554 goto ERROR;
555
556 pakfire_relationlist_unref(list);
557 }
558
559 // End dependencies block
560 r = asprintf(&buffer, "%send\n\n", buffer);
561 if (r < 0)
562 goto ERROR;
563
564 // EOF
565 r = asprintf(&buffer, "%s# EOF\n", buffer);
566 if (r < 0)
567 goto ERROR;
568
569 return buffer;
570
571ERROR:
572 if (buffer)
573 free(buffer);
574
575 return NULL;
576}
577
578static int pakfire_packager_write_metadata(struct pakfire_packager* packager,
579 struct archive* a) {
580 // Make metadata
581 char* buffer = pakfire_package_make_metadata(packager);
582 if (!buffer)
583 return 1;
584
585 DEBUG(packager->pakfire, "Generated package metadata:\n%s", buffer);
586
587 // Write buffer
588 int r = pakfire_packager_write_file_from_buffer(packager, a,
589 PAKFIRE_ARCHIVE_FN_METADATA, buffer);
590
591 free(buffer);
592
593 return r;
594}
595
2adc4a4a
MT
596static int pakfire_packager_write_payload(struct pakfire_packager* packager,
597 struct archive* a) {
598 struct stat st;
599
600 // Close the payload
601 if (packager->payload) {
602 archive_write_free(packager->payload);
603 packager->payload = NULL;
604 }
605
606 // Reset fd to beginning of the file
607 rewind(packager->fpayload);
608
609 int fd = fileno(packager->fpayload);
610
611 // Stat the payload file
612 int r = fstat(fd, &st);
613 if (r) {
614 ERROR(packager->pakfire, "stat() on fd %d failed: %s\n", fd, strerror(errno));
615 return 1;
616 }
617
618 // Create a new file entry
619 struct archive_entry* entry = archive_entry_new();
620 if (!entry)
621 return 1;
622
623 // Set filename
624 archive_entry_set_pathname(entry, PAKFIRE_ARCHIVE_FN_PAYLOAD);
625
626 // This is a regular file
627 archive_entry_set_filetype(entry, AE_IFREG);
628 archive_entry_set_perm(entry, 0644);
629
630 // Set the file size
631 archive_entry_set_size(entry, st.st_size);
632
633 // This is the end of the header
634 r = archive_write_header(a, entry);
635 if (r) {
636 ERROR(packager->pakfire, "Error writing header: %s\n", archive_error_string(a));
637 goto ERROR;
638 }
639
640 // Copy data
641 r = pakfire_packager_copy_data(packager, a, packager->fpayload);
642 if (r)
643 goto ERROR;
644
645 // Success
646 r = 0;
647
648ERROR:
649 archive_entry_free(entry);
650
651 return r;
652}
653
436677a3
MT
654/*
655 This function is being called at the end when all data has been added to the package.
656
657 It will create a new archive and write the package to the given file descriptor.
658*/
659PAKFIRE_EXPORT char* pakfire_packager_finish(struct pakfire_packager* packager, FILE* f) {
660 char* filename = NULL;
661
fafe383d
MT
662 // Store total instal size
663 pakfire_package_set_installsize(packager->pkg,
664 pakfire_filelist_total_filesize(packager->filelist));
665
436677a3
MT
666 // Open a new archive
667 struct archive* a = archive_write_new();
668 if (!a) {
669 ERROR(packager->pakfire, "archive_write_new() failed\n");
670 goto ERROR;
671 }
672
673 // Use the PAX format
674 int r = archive_write_set_format_pax(a);
675 if (r) {
676 ERROR(packager->pakfire, "Could not set format to PAX: %s\n",
677 archive_error_string(a));
678 goto ERROR;
679 }
680
681 // Write archive to f
682 r = archive_write_open_FILE(a, f);
683 if (r) {
684 ERROR(packager->pakfire, "archive_write_open_FILE() failed: %s\n",
685 archive_error_string(a));
686 goto ERROR;
687 }
688
689 // Start with the format file
690 r = pakfire_packager_write_format(packager, a);
691 if (r)
692 goto ERROR;
693
98e85f1c
MT
694 // Write the metadata
695 r = pakfire_packager_write_metadata(packager, a);
696 if (r)
697 goto ERROR;
698
2adc4a4a
MT
699 // Write the payload
700 r = pakfire_packager_write_payload(packager, a);
701 if (r)
702 goto ERROR;
703
436677a3
MT
704 // XXX set filename
705
706ERROR:
707 if (a)
708 archive_free(a);
709
710 return filename;
711}
712
da08f989
MT
713PAKFIRE_EXPORT int pakfire_packager_add(struct pakfire_packager* packager,
714 const char* path) {
715 FILE* f = NULL;
da08f989
MT
716
717 // Check if path is set
718 if (!path)
719 return EINVAL;
720
7836e21b
MT
721 // Payload has already been closed
722 if (!packager->payload)
723 return EINVAL;
724
da08f989
MT
725 // Create a new file entry
726 struct archive_entry* entry = archive_entry_new();
727 if (!entry)
728 return ENOMEM;
729
730 // Set path in archive
731 archive_entry_set_pathname(entry, path);
732
738b3582
MT
733 // Read all attributes from file
734 int r = archive_read_disk_entry_from_file(packager->reader, entry, -1, NULL);
735 if (r) {
736 ERROR(packager->pakfire, "Could not read attributes from %s: %s\n",
737 path, strerror(errno));
738 goto ERROR;
739 }
da08f989
MT
740
741 // Write the header
742 r = archive_write_header(packager->payload, entry);
743 if (r) {
744 ERROR(packager->pakfire, "Error writing file header: %s\n",
745 archive_error_string(packager->payload));
746 goto ERROR;
747 }
748
749 // Copy the data of regular files
750 if (archive_entry_filetype(entry) == AE_IFREG) {
751 f = fopen(path, "r");
752 if (!f) {
753 ERROR(packager->pakfire, "Could not open %s: %s\n", path, strerror(errno));
754 r = errno;
755 goto ERROR;
756 }
757
7836e21b
MT
758 r = pakfire_packager_copy_data(packager, packager->payload, f);
759 if (r)
760 goto ERROR;
da08f989
MT
761 }
762
c138b06e
MT
763 // Create a file
764 PakfireFile file;
765 r = pakfire_file_create(&file, packager->pakfire);
766 if (r)
767 goto ERROR;
768
769 r = pakfire_file_copy_archive_entry(file, entry);
770 if (r)
771 goto ERROR;
772
1ba1869e
MT
773 // Append the file to the filelist
774 pakfire_filelist_append(packager->filelist, file);
775
da08f989
MT
776 // Successful
777 r = 0;
778
779ERROR:
1ba1869e
MT
780 pakfire_file_unref(file);
781
da08f989
MT
782 if (entry)
783 archive_entry_free(entry);
784
785 if (f)
786 fclose(f);
787
788 return r;
789}