]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/archive.c
archive: read: Correctly fail if we cannot find a file
[people/stevee/pakfire.git] / src / libpakfire / archive.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 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>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/sendfile.h>
27 #include <sys/stat.h>
28
29 // libarchive
30 #include <archive.h>
31 #include <archive_entry.h>
32
33 // JSON-C
34 #include <json.h>
35
36 #include <pakfire/archive.h>
37 #include <pakfire/compress.h>
38 #include <pakfire/dependencies.h>
39 #include <pakfire/digest.h>
40 #include <pakfire/file.h>
41 #include <pakfire/filelist.h>
42 #include <pakfire/i18n.h>
43 #include <pakfire/jail.h>
44 #include <pakfire/logging.h>
45 #include <pakfire/package.h>
46 #include <pakfire/pakfire.h>
47 #include <pakfire/private.h>
48 #include <pakfire/repo.h>
49 #include <pakfire/scriptlet.h>
50 #include <pakfire/string.h>
51 #include <pakfire/util.h>
52
53 #define MAX_SCRIPTLETS 9
54
55 struct pakfire_archive {
56 struct pakfire* pakfire;
57 int nrefs;
58
59 char path[PATH_MAX];
60 FILE* f;
61 struct stat stat;
62
63 struct pakfire_package* package;
64
65 // metadata
66 unsigned int format;
67 struct json_object* metadata;
68
69 struct pakfire_filelist* filelist;
70
71 // Scriptlets
72 struct pakfire_scriptlet* scriptlets[MAX_SCRIPTLETS];
73 unsigned int num_scriptlets;
74
75 // Digests
76 struct pakfire_digests digests;
77
78 // Verify Status
79 int verify;
80 };
81
82 static FILE* pakfire_archive_clone_file(struct pakfire_archive* archive) {
83 int fd = fileno(archive->f);
84 if (fd < 0) {
85 ERROR(archive->pakfire, "Could not fetch the archive's file descriptor: %m\n");
86 return NULL;
87 }
88
89 // Duplicate the file descriptor
90 fd = dup(fd);
91 if (fd < 0) {
92 ERROR(archive->pakfire, "Could not duplicate the file descriptor: %m\n");
93 return NULL;
94 }
95
96 // Re-open a file handle
97 return fdopen(fd, "r");
98 }
99
100 static int pakfire_archive_compute_digests(struct pakfire_archive* archive) {
101 int r;
102
103 // Start reading at the beginning
104 rewind(archive->f);
105
106 // Calculate digest
107 r = pakfire_digests_compute_from_file(archive->pakfire, &archive->digests,
108 PAKFIRE_ARCHIVE_CHECKSUM, archive->f);
109 if (r)
110 ERROR(archive->pakfire, "Could not calculate digest of %s: %m\n", archive->path);
111
112 return r;
113 }
114
115 /*
116 A helper function to close the archive and reset our data structures
117 */
118 static void close_archive(struct pakfire_archive* archive, struct archive* a) {
119 if (a)
120 archive_read_free(a);
121 }
122
123 /*
124 A helper function that opens the archive for reading
125 */
126 static struct archive* open_archive(struct pakfire_archive* archive, FILE* f) {
127 // If no special file descriptor has been given we use the open one
128 if (!f)
129 f = archive->f;
130
131 // Create a new archive object
132 struct archive* a = archive_read_new();
133 if (!a)
134 return NULL;
135
136 // Archives must be uncompressed tarballs
137 archive_read_support_format_tar(a);
138
139 // Archives are compressed using Zstandard
140 archive_read_support_filter_zstd(a);
141
142 // Start reading from the beginning
143 rewind(f);
144
145 // Try opening the archive file
146 int r = archive_read_open_FILE(a, f);
147 if (r) {
148 ERROR(archive->pakfire, "Could not open archive %s: %s\n",
149 archive->path, archive_error_string(a));
150 goto ERROR;
151 }
152
153 // Success
154 return a;
155
156 ERROR:
157 close_archive(archive, a);
158
159 return NULL;
160 }
161
162 static int pakfire_archive_walk(struct pakfire_archive* archive,
163 pakfire_walk_callback callback, pakfire_walk_filter_callback filter_callback, void* data) {
164 int r;
165
166 // Open the archive file
167 struct archive* a = open_archive(archive, NULL);
168 if (!a)
169 return 1;
170
171 // Walk through the archive
172 r = pakfire_walk(archive->pakfire, a, callback, filter_callback, data);
173
174 // Close the archive
175 if (a)
176 close_archive(archive, a);
177
178 return r;
179 }
180
181 static void pakfire_archive_free(struct pakfire_archive* archive) {
182 // Close the file
183 if (archive->f)
184 fclose(archive->f);
185
186 // Free scriptlets
187 for (unsigned int i = 0; i < archive->num_scriptlets; i++)
188 pakfire_scriptlet_unref(archive->scriptlets[i]);
189
190 if (archive->filelist)
191 pakfire_filelist_unref(archive->filelist);
192 if (archive->package)
193 pakfire_package_unref(archive->package);
194 if (archive->metadata)
195 json_object_put(archive->metadata);
196 pakfire_unref(archive->pakfire);
197 free(archive);
198 }
199
200 static int pakfire_archive_create(struct pakfire_archive** archive, struct pakfire* pakfire) {
201 struct pakfire_archive* a = calloc(1, sizeof(*a));
202 if (!a)
203 return ENOMEM;
204
205 a->pakfire = pakfire_ref(pakfire);
206 a->nrefs = 1;
207
208 *archive = a;
209 return 0;
210 }
211
212 PAKFIRE_EXPORT struct pakfire_archive* pakfire_archive_ref(struct pakfire_archive* archive) {
213 ++archive->nrefs;
214
215 return archive;
216 }
217
218 PAKFIRE_EXPORT struct pakfire_archive* pakfire_archive_unref(struct pakfire_archive* archive) {
219 if (--archive->nrefs > 0)
220 return archive;
221
222 pakfire_archive_free(archive);
223
224 return NULL;
225 }
226
227 static struct pakfire_package* pakfire_archive_get_package(struct pakfire_archive* archive) {
228 if (!archive->package) {
229 int r = pakfire_archive_make_package(archive, NULL, &archive->package);
230 if (r)
231 return NULL;
232 }
233
234 return pakfire_package_ref(archive->package);
235 }
236
237 // Metadata
238
239 static int pakfire_archive_parse_json_metadata(struct pakfire_archive* archive,
240 const char* data, const size_t length) {
241 int r = 1;
242
243 // Create tokener
244 struct json_tokener* tokener = json_tokener_new();
245 if (!tokener) {
246 ERROR(archive->pakfire, "Could not allocate JSON tokener: %m\n");
247 goto ERROR;
248 }
249
250 // Parse JSON from buffer
251 archive->metadata = json_tokener_parse_ex(tokener, data, length);
252 if (!archive->metadata) {
253 enum json_tokener_error error = json_tokener_get_error(tokener);
254
255 ERROR(archive->pakfire, "JSON parsing error: %s\n",
256 json_tokener_error_desc(error));
257 goto ERROR;
258 }
259
260 DEBUG(archive->pakfire, "Successfully parsed package metadata:\n%s\n",
261 json_object_to_json_string_ext(archive->metadata,
262 JSON_C_TO_STRING_PRETTY|JSON_C_TO_STRING_PRETTY_TAB));
263
264 // Success
265 r = 0;
266
267 ERROR:
268 if (tokener)
269 json_tokener_free(tokener);
270
271 return r;
272 }
273
274 static int pakfire_archive_parse_format(struct pakfire_archive* archive,
275 const char* data, const size_t length) {
276 // Check if format has already been set
277 if (archive->format) {
278 ERROR(archive->pakfire, "Archive format has already been parsed\n");
279 errno = EINVAL;
280 return 1;
281 }
282
283 // Parse the format
284 archive->format = strtoul(data, NULL, 10);
285
286 switch (archive->format) {
287 // Handle all supported formats
288 case 6:
289 break;
290
291 // Break on anything else
292 default:
293 ERROR(archive->pakfire, "This version of Pakfire does not support "
294 "archive format %d\n", archive->format);
295 errno = EINVAL;
296 return 1;
297 }
298
299 DEBUG(archive->pakfire, "Archive format is %d\n", archive->format);
300
301 return 0;
302 }
303
304 static int pakfire_archive_parse_scriptlet(struct pakfire_archive* archive,
305 const char* path, const char* data, const size_t length) {
306 struct pakfire_scriptlet* scriptlet = NULL;
307 const char* type = NULL;
308 int r;
309
310 // Check for any available space
311 if (archive->num_scriptlets >= MAX_SCRIPTLETS) {
312 ERROR(archive->pakfire, "Too many scriptlets\n");
313 errno = ENOBUFS;
314 return 1;
315 }
316
317 // Determine type
318 type = pakfire_path_relpath(".scriptlets/", path);
319 if (!type) {
320 ERROR(archive->pakfire, "Could not determine the scriptlet type from '%s'\n", path);
321 errno = EINVAL;
322 return 1;
323 }
324
325 // Allocate a scriptlet
326 r = pakfire_scriptlet_create(&scriptlet, archive->pakfire, type, data, length);
327 if (r)
328 return r;
329
330 // Store scriptlet
331 archive->scriptlets[archive->num_scriptlets++] = scriptlet;
332
333 return 0;
334 }
335
336 static int __pakfire_archive_read_metadata(struct pakfire* pakfire, struct archive* a,
337 struct archive_entry* entry, void* p) {
338 struct pakfire_archive* archive = (struct pakfire_archive*)p;
339
340 char* data = NULL;
341 size_t length = 0;
342 int r;
343
344 const char* path = archive_entry_pathname(entry);
345
346 DEBUG(pakfire, "Reading metadata file: %s\n", path);
347
348 // Load the file into memory
349 r = pakfire_archive_copy_data_to_buffer(archive->pakfire, a, entry, &data, &length);
350 if (r) {
351 ERROR(archive->pakfire, "Could not read data from archive: %s\n",
352 archive_error_string(a));
353 goto ERROR;
354 }
355
356 // Format >= 6
357 if (archive->format >= 6) {
358 // Parse PKGINFO
359 if (strcmp(path, ".PKGINFO") == 0) {
360 r = pakfire_archive_parse_json_metadata(archive, data, length);
361 if (r)
362 goto ERROR;
363
364 // Parse scriptlets
365 } else if (pakfire_string_startswith(path, ".scriptlets/")) {
366 r = pakfire_archive_parse_scriptlet(archive, path, data, length);
367 if (r)
368 goto ERROR;
369 }
370
371 // pakfire-format
372 } else if (strcmp(path, "pakfire-format") == 0) {
373 r = pakfire_archive_parse_format(archive, data, length);
374 if (r)
375 goto ERROR;
376 }
377
378 ERROR:
379 if (data)
380 free(data);
381
382 return r;
383 }
384
385 static int __pakfire_archive_filter_metadata(struct pakfire* pakfire,
386 struct archive* a, struct archive_entry* entry, void* p) {
387 struct pakfire_archive* archive = (struct pakfire_archive*)p;
388
389 const char* path = archive_entry_pathname(entry);
390
391 // Format >= 6
392 if (archive->format >= 6) {
393 // Anything that starts with "." is a metadata file
394 if (*path == '.')
395 return PAKFIRE_WALK_OK;
396
397 // Otherwise, the payload begins
398 return PAKFIRE_WALK_END;
399
400 // The pakfire-format file is part of the metadata
401 } else if (strcmp(path, "pakfire-format") == 0) {
402 return PAKFIRE_WALK_OK;
403 }
404
405 // Unknown file
406 return PAKFIRE_WALK_ERROR;
407 }
408
409 static int pakfire_archive_read_metadata(struct pakfire_archive* archive) {
410 int r;
411
412 // Check if the archive file actually has any contect
413 if (!archive->stat.st_size) {
414 ERROR(archive->pakfire, "Trying to open an empty archive file\n");
415 errno = EINVAL;
416 return 1;
417 }
418
419 DEBUG(archive->pakfire, "Reading archive metadata...\n");
420
421 // Walk through the archive
422 r = pakfire_archive_walk(archive, __pakfire_archive_read_metadata,
423 __pakfire_archive_filter_metadata, archive);
424 if (r)
425 return r;
426
427 // Check if we could successfully read something
428 if (!archive->format) {
429 ERROR(archive->pakfire, "Archive has an unknown format\n");
430 errno = EINVAL;
431 return 1;
432 }
433
434 // Check if we have read some metadata
435 if (!archive->metadata) {
436 ERROR(archive->pakfire, "Archive has no metadata\n");
437 errno = EINVAL;
438 return 1;
439 }
440
441 return 0;
442 }
443
444 static int pakfire_archive_try_open(struct pakfire_archive* archive, const char* path) {
445 int r;
446
447 if (!path) {
448 errno = EINVAL;
449 return 1;
450 }
451
452 DEBUG(archive->pakfire, "Opening archive %s\n", path);
453
454 // Store path
455 pakfire_string_set(archive->path, path);
456
457 // Open the file (and keep the file descriptor open)
458 archive->f = fopen(archive->path, "r");
459 if (!archive->f)
460 return 1;
461
462 // Let the kernel know, that we will read the file sequentially
463 r = posix_fadvise(fileno(archive->f), 0, 0, POSIX_FADV_SEQUENTIAL);
464 if (r) {
465 ERROR(archive->pakfire, "posix_fadvise() failed: %m\n");
466 goto ERROR;
467 }
468
469 // Call stat() on f
470 r = fstat(fileno(archive->f), &archive->stat);
471 if (r) {
472 ERROR(archive->pakfire, "Could not stat archive: %m\n");
473 goto ERROR;
474 }
475
476 // Read all package metadata
477 r = pakfire_archive_read_metadata(archive);
478 if (r) {
479 ERROR(archive->pakfire, "Could not open archive: %m\n");
480 goto ERROR;
481 }
482
483 ERROR:
484 return r;
485 }
486
487 PAKFIRE_EXPORT int pakfire_archive_open(struct pakfire_archive** archive, struct pakfire* pakfire, const char* path) {
488 int r = pakfire_archive_create(archive, pakfire);
489 if (r)
490 return r;
491
492 r = pakfire_archive_try_open(*archive, path);
493 if (r)
494 goto ERROR;
495
496 return 0;
497
498 ERROR:
499 pakfire_archive_unref(*archive);
500 *archive = NULL;
501
502 return r;
503 }
504
505 static struct json_object* pakfire_archive_metadata_get_object(
506 struct pakfire_archive* archive, const char* key1, const char* key2) {
507 struct json_object* object = archive->metadata;
508 int r;
509
510 const char* keys[] = {
511 key1,
512 key2,
513 NULL,
514 };
515
516 // Walk through all keys
517 for (const char** key = keys; *key; key++) {
518 // Try finding a matching JSON object
519 r = json_object_object_get_ex(object, *key, &object);
520 if (!r) {
521 DEBUG(archive->pakfire, "Could not find JSON object at '%s': %m\n", *key);
522 break;
523 }
524 }
525
526 return object;
527 }
528
529 static const char* pakfire_archive_metadata_get(
530 struct pakfire_archive* archive, const char* key1, const char* key2) {
531 // Try finding an object
532 struct json_object* object = pakfire_archive_metadata_get_object(archive, key1, key2);
533 if (!object)
534 return NULL;
535
536 // Return the object as string
537 return json_object_get_string(object);
538 }
539
540 static int64_t pakfire_archive_metadata_get_int64(
541 struct pakfire_archive* archive, const char* key1, const char* key2) {
542 // Try finding an object
543 struct json_object* object = pakfire_archive_metadata_get_object(archive, key1, key2);
544 if (!object)
545 return 0;
546
547 // Return the object as integer
548 return json_object_get_int64(object);
549 }
550
551 static int __pakfire_archive_filter_payload(struct pakfire* pakfire,
552 struct archive* a, struct archive_entry* entry, void* p) {
553 const char* path = archive_entry_pathname(entry);
554 if (!path)
555 return PAKFIRE_WALK_ERROR;
556
557 switch (*path) {
558 case 'p':
559 if (strcmp(path, "pakfire-format") == 0)
560 return PAKFIRE_WALK_SKIP;
561
562 // Fallthrough
563
564 case '.':
565 return PAKFIRE_WALK_SKIP;
566
567 // The first file that isn't metadata, so we are done calling the filter callback
568 default:
569 return PAKFIRE_WALK_DONE;
570 }
571 }
572
573 /*
574 Read files from the archive
575 */
576 struct pakfire_archive_read_cookie {
577 // A reference to the archive
578 struct pakfire_archive* archive;
579
580 // A copy of the underlying file descriptor
581 FILE* f;
582
583 // The opened archive
584 struct archive* a;
585 };
586
587 static ssize_t __pakfire_archive_cookie_read(void* c, char* buffer, size_t size) {
588 struct pakfire_archive_read_cookie* cookie = (struct pakfire_archive_read_cookie*)c;
589
590 // Read the data directly from the archive
591 return archive_read_data(cookie->a, buffer, size);
592 }
593
594 static int __pakfire_archive_cookie_close(void* c) {
595 struct pakfire_archive_read_cookie* cookie = (struct pakfire_archive_read_cookie*)c;
596
597 if (cookie->archive)
598 pakfire_archive_unref(cookie->archive);
599 if (cookie->a)
600 archive_read_free(cookie->a);
601 if (cookie->f)
602 fclose(cookie->f);
603
604 // Free the cookie
605 free(cookie);
606
607 return 0;
608 }
609
610 static cookie_io_functions_t pakfire_archive_read_functions = {
611 .read = __pakfire_archive_cookie_read,
612 .close = __pakfire_archive_cookie_close,
613 };
614
615 PAKFIRE_EXPORT FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* path) {
616 struct pakfire_archive_read_cookie* cookie = NULL;
617 FILE* f = NULL;
618 int r;
619
620 // Check if path is absolute
621 if (!path || *path != '/') {
622 errno = EINVAL;
623 return NULL;
624 }
625
626 // Strip leading / from filenames, because tarballs don't use any leading slashes
627 path = pakfire_path_relpath("/", path);
628 if (!path)
629 return NULL;
630
631 // Allocate a cookie
632 cookie = calloc(1, sizeof(*cookie));
633 if (!cookie) {
634 ERROR(archive->pakfire, "Could not allocate a cookie: %m\n");
635 goto ERROR;
636 }
637
638 // Store a reference to the archive
639 cookie->archive = pakfire_archive_ref(archive);
640
641 // Clone the archive file descriptor to read the file independently
642 cookie->f = pakfire_archive_clone_file(archive);
643 if (!cookie->f) {
644 ERROR(archive->pakfire, "Could not duplicate file descriptor for %s: %m\n",
645 archive->path);
646 goto ERROR;
647 }
648
649 // Open the archive
650 cookie->a = open_archive(archive, cookie->f);
651 if (!cookie->a)
652 goto ERROR;
653
654 // Tries to find a matching file in the archive
655 int __pakfire_archive_read_filter(struct pakfire* pakfire, struct archive* a,
656 struct archive_entry* e, void* data) {
657 // Stop reading the archive after we have found our file
658 if (f)
659 return PAKFIRE_WALK_END;
660
661 // Fetch path
662 const char* p = archive_entry_pathname(e);
663 if (!p)
664 return PAKFIRE_WALK_ERROR;
665
666 // We found a match
667 if (strcmp(path, p) == 0)
668 return PAKFIRE_WALK_OK;
669
670 // Otherwise we skip the file
671 return PAKFIRE_WALK_SKIP;
672 }
673
674 // Reads a matching file into memory
675 int __pakfire_archive_read(struct pakfire* pakfire, struct archive* a,
676 struct archive_entry* e, void* data) {
677 // Create a file descriptor
678 f = fopencookie(cookie, "r", pakfire_archive_read_functions);
679 if (!f) {
680 ERROR(pakfire, "Could not open /%s: %m\n", path);
681 return PAKFIRE_WALK_ERROR;
682 }
683
684 return PAKFIRE_WALK_DONE;
685 }
686
687 // Walk through the archive
688 r = pakfire_walk(archive->pakfire, cookie->a,
689 __pakfire_archive_read, __pakfire_archive_read_filter, NULL);
690 if (r)
691 goto ERROR;
692
693 // Nothing found
694 if (!f) {
695 ERROR(archive->pakfire, "Could not find /%s\n", path);
696
697 // No such file or directory
698 errno = ENOENT;
699 goto ERROR;
700 }
701
702 return f;
703
704 ERROR:
705 if (cookie)
706 __pakfire_archive_cookie_close(cookie);
707
708 return NULL;
709 }
710
711 int pakfire_archive_copy(struct pakfire_archive* archive, const char* path) {
712 if (!path) {
713 errno = EINVAL;
714 return 1;
715 }
716
717 // Determine the file size
718 ssize_t size = pakfire_archive_get_size(archive);
719 if (size < 0)
720 return 1;
721
722 DEBUG(archive->pakfire, "Copying %s to %s...\n", archive->path, path);
723
724 // Ensure we copy from the very beginning
725 rewind(archive->f);
726
727 // Ensure the parent directory exists
728 pakfire_mkparentdir(path, 0755);
729
730 // Open destination file
731 FILE* f = fopen(path, "w");
732 if (!f)
733 return 1;
734
735 int r = 1;
736
737 // Copy everything
738 ssize_t bytes_written = sendfile(fileno(f), fileno(archive->f), NULL, size);
739 if (bytes_written < size) {
740 ERROR(archive->pakfire, "Could not copy archive (%zu byte(s) written): %m\n",
741 bytes_written);
742 goto ERROR;
743 }
744
745 // Success
746 r = 0;
747
748 ERROR:
749 fclose(f);
750
751 // Delete the file on error
752 if (r)
753 unlink(path);
754
755 return r;
756 }
757
758 static int pakfire_archive_link(struct pakfire_archive* archive, const char* path) {
759 int r;
760
761 // Check if path is set
762 if (!path) {
763 errno = EINVAL;
764 return 1;
765 }
766
767 DEBUG(archive->pakfire, "Linking %s to %s...\n", archive->path, path);
768
769 // Delete the destination file (if it exists)
770 unlink(path);
771
772 // Create the new link
773 r = link(archive->path, path);
774 if (r) {
775 DEBUG(archive->pakfire, "Could not create hardlink %s: %m\n", path);
776 return r;
777 }
778
779 return 0;
780 }
781
782 int pakfire_archive_link_or_copy(struct pakfire_archive* archive, const char* path) {
783 int r;
784
785 // Try to create a hardlink
786 r = pakfire_archive_link(archive, path);
787 if (r) {
788 switch (errno) {
789 // Try to copy the file if we could not create a hardlink
790 case EPERM:
791 r = pakfire_archive_copy(archive, path);
792
793 default:
794 break;
795 }
796 }
797
798 return r;
799 }
800
801 static int __pakfire_archive_extract(struct pakfire_archive* archive, int flags) {
802 struct pakfire_filelist* filelist = NULL;
803 struct pakfire_package* pkg = NULL;
804 struct archive* a = NULL;
805 char prefix[PATH_MAX] = "";
806 int r = 1;
807
808 // Fetch package
809 pkg = pakfire_archive_get_package(archive);
810 if (!pkg)
811 goto ERROR;
812
813 // Fetch NEVRA
814 const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA);
815
816 DEBUG(archive->pakfire, "Extracting %s\n", archive->path);
817
818 // Set prefix for source packages
819 if (pakfire_package_is_source(pkg)) {
820 r = pakfire_string_format(prefix, "/usr/src/packages/%s", nevra);
821 if (r)
822 goto ERROR;
823 }
824
825 // Load the filelist (if not done already)
826 if (!archive->filelist) {
827 r = pakfire_filelist_create(&filelist, archive->pakfire);
828 if (r)
829 goto ERROR;
830 }
831
832 // Open the archive
833 a = open_archive(archive, NULL);
834 if (!a) {
835 r = 1;
836 goto ERROR;
837 }
838
839 // Extract
840 r = pakfire_extract(archive->pakfire, a, archive->stat.st_size,
841 filelist, prefix, nevra, __pakfire_archive_filter_payload, flags);
842 if (r)
843 goto ERROR;
844
845 // Store the filelist permanently
846 if (!archive->filelist)
847 archive->filelist = pakfire_filelist_ref(filelist);
848
849 ERROR:
850 if (filelist)
851 pakfire_filelist_unref(filelist);
852 if (pkg)
853 pakfire_package_unref(pkg);
854 if (a)
855 close_archive(archive, a);
856
857 return r;
858 }
859
860 PAKFIRE_EXPORT int pakfire_archive_extract(struct pakfire_archive* archive) {
861 return __pakfire_archive_extract(archive, 0);
862 }
863
864 PAKFIRE_EXPORT const char* pakfire_archive_get_path(struct pakfire_archive* archive) {
865 return archive->path;
866 }
867
868 PAKFIRE_EXPORT unsigned int pakfire_archive_get_format(struct pakfire_archive* archive) {
869 return archive->format;
870 }
871
872 static int pakfire_archive_load_filelist(struct pakfire_archive* archive) {
873 // Perform a dry-run extraction
874 return __pakfire_archive_extract(archive,
875 PAKFIRE_EXTRACT_DRY_RUN|PAKFIRE_EXTRACT_NO_PROGRESS);
876 }
877
878 PAKFIRE_EXPORT struct pakfire_filelist* pakfire_archive_get_filelist(struct pakfire_archive* archive) {
879 if (!archive->filelist) {
880 int r = pakfire_archive_load_filelist(archive);
881 if (r)
882 return NULL;
883 }
884
885 if (!archive->filelist)
886 return NULL;
887
888 return pakfire_filelist_ref(archive->filelist);
889 }
890
891 PAKFIRE_EXPORT int pakfire_archive_verify(struct pakfire_archive* archive, int* status) {
892 // XXX currently not implemented
893 return 0;
894 }
895
896 PAKFIRE_EXPORT ssize_t pakfire_archive_get_size(struct pakfire_archive* archive) {
897 return archive->stat.st_size;
898 }
899
900 int pakfire_archive_check_digest(struct pakfire_archive* archive,
901 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
902 size_t computed_length = 0;
903 int r;
904
905 // Compute the digest
906 r = pakfire_archive_compute_digests(archive);
907 if (r)
908 return r;
909
910 // Compare computed with expected digest
911 r = pakfire_digests_compare_one(archive->pakfire, &archive->digests,
912 type, digest, length);
913 if (r) {
914 const unsigned char* computed_digest = pakfire_digest_get(
915 &archive->digests, type, &computed_length);
916
917 char* expected_hexdigest = __pakfire_hexlify(digest, length);
918 char* computed_hexdigest = __pakfire_hexlify(computed_digest, computed_length);
919
920 ERROR(archive->pakfire, "Archive digest does not match for %s:\n", archive->path);
921 ERROR(archive->pakfire, " Expected: %s\n", expected_hexdigest);
922 ERROR(archive->pakfire, " Computed: %s\n", computed_hexdigest);
923
924 if (expected_hexdigest)
925 free(expected_hexdigest);
926 if (computed_hexdigest)
927 free(computed_hexdigest);
928
929 return r;
930 }
931
932 return r;
933 }
934
935 static int pakfire_archive_import_filelist_from_json(
936 struct pakfire_archive* archive, struct pakfire_package* package) {
937 struct json_object* array = NULL;
938 int r;
939
940 // Fetch the array with the filelist
941 array = pakfire_archive_metadata_get_object(archive, "filelist", NULL);
942 if (!array) {
943 ERROR(archive->pakfire, "Archive has no filelist: %m\n");
944 return 1;
945 }
946
947 // Determine the length of the array
948 const size_t length = json_object_array_length(array);
949
950 // End here if the array is empty
951 if (!length)
952 return 0;
953
954 // Walk through all items in this array
955 for (unsigned int i = 0; i < length; i++) {
956 struct json_object* item = json_object_array_get_idx(array, i);
957 if (!item)
958 continue;
959
960 // Extract the path value
961 const char* path = json_object_get_string(item);
962 if (!path)
963 continue;
964
965 // Append the file to the package
966 r = pakfire_package_append_file(package, path);
967 if (r)
968 return r;
969 }
970
971 return 0;
972 }
973
974 static int pakfire_archive_make_package_from_json(struct pakfire_archive* archive,
975 struct pakfire_repo* repo, struct pakfire_package** package) {
976 struct pakfire_package* pkg = NULL;
977 int r;
978
979 // Calculate digest
980 r = pakfire_archive_compute_digests(archive);
981 if (r)
982 return r;
983
984 // Fetch the most basic package information
985 const char* name = pakfire_archive_metadata_get(archive, "name", NULL);
986 const char* evr = pakfire_archive_metadata_get(archive, "evr", NULL);
987 const char* arch = pakfire_archive_metadata_get(archive, "arch", NULL);
988
989 // Create a new package object
990 r = pakfire_package_create(&pkg, archive->pakfire, repo, name, evr, arch);
991 if (r)
992 return r;
993
994 #ifdef ENABLE_DEBUG
995 const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA);
996
997 DEBUG(archive->pakfire, "Created package %s (%p) from archive %p\n",
998 nevra, pkg, archive);
999 #endif
1000
1001 // Set path
1002 pakfire_package_set_string(pkg, PAKFIRE_PKG_PATH, archive->path);
1003
1004 // Set digest
1005 switch (PAKFIRE_ARCHIVE_CHECKSUM) {
1006 case PAKFIRE_DIGEST_SHA2_512:
1007 pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM,
1008 archive->digests.sha2_512, sizeof(archive->digests.sha2_512));
1009 break;
1010
1011 case PAKFIRE_DIGEST_SHA2_256:
1012 pakfire_package_set_digest(pkg, PAKFIRE_ARCHIVE_CHECKSUM,
1013 archive->digests.sha2_256, sizeof(archive->digests.sha2_256));
1014 break;
1015
1016 case PAKFIRE_DIGEST_UNDEFINED:
1017 r = 1;
1018 goto ERROR;
1019 }
1020
1021 // Vendor
1022 const char* vendor = pakfire_archive_metadata_get(archive, "vendor", NULL);
1023 if (vendor) {
1024 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_VENDOR, vendor);
1025 if (r)
1026 goto ERROR;
1027 }
1028
1029 // UUID
1030 const char* uuid = pakfire_archive_metadata_get(archive, "uuid", NULL);
1031 if (uuid) {
1032 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_UUID, uuid);
1033 if (r)
1034 goto ERROR;
1035 }
1036
1037 // Groups
1038 const char* groups = pakfire_archive_metadata_get(archive, "groups", NULL);
1039 if (groups) {
1040 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_GROUPS, groups);
1041 if (r)
1042 goto ERROR;
1043 }
1044
1045 // Distribution
1046 const char* distro = pakfire_archive_metadata_get(archive, "distribution", NULL);
1047 if (distro) {
1048 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_DISTRO, distro);
1049 if (r)
1050 goto ERROR;
1051 }
1052
1053 // Packager
1054 const char* packager = pakfire_archive_metadata_get(archive, "packager", NULL);
1055 if (packager) {
1056 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_PACKAGER, packager);
1057 if (r)
1058 goto ERROR;
1059 }
1060
1061 // URL
1062 const char* url = pakfire_archive_metadata_get(archive, "url", NULL);
1063 if (url) {
1064 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_URL, url);
1065 if (r)
1066 goto ERROR;
1067 }
1068
1069 // License
1070 const char* license = pakfire_archive_metadata_get(archive, "license", NULL);
1071 if (license) {
1072 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_LICENSE, license);
1073 if (r)
1074 goto ERROR;
1075 }
1076
1077 // Summary
1078 const char* summary = pakfire_archive_metadata_get(archive, "summary", NULL);
1079 if (summary) {
1080 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SUMMARY, summary);
1081 if (r)
1082 goto ERROR;
1083 }
1084
1085 // Description
1086 const char* description = pakfire_archive_metadata_get(archive, "description", NULL);
1087 if (description) {
1088 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_DESCRIPTION, description);
1089 if (r)
1090 goto ERROR;
1091 }
1092
1093 // Installed package size
1094 size_t installsize = pakfire_archive_metadata_get_int64(archive, "size", NULL);
1095 if (installsize) {
1096 r = pakfire_package_set_num(pkg, PAKFIRE_PKG_INSTALLSIZE, installsize);
1097 if (r)
1098 goto ERROR;
1099 }
1100
1101 // Download size
1102 r = pakfire_package_set_num(pkg,
1103 PAKFIRE_PKG_DOWNLOADSIZE, pakfire_archive_get_size(archive));
1104 if (r)
1105 goto ERROR;
1106
1107 // Build Host
1108 const char* build_host = pakfire_archive_metadata_get(archive, "build", "host");
1109 if (build_host) {
1110 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_BUILD_HOST, build_host);
1111 if (r)
1112 goto ERROR;
1113 }
1114
1115 // Build ID
1116 const char* build_id = pakfire_archive_metadata_get(archive, "build", "id");
1117 if (build_id) {
1118 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_BUILD_ID, build_id);
1119 if (r)
1120 goto ERROR;
1121 }
1122
1123 // Build Time
1124 time_t build_time = pakfire_archive_metadata_get_int64(archive, "build", "time");
1125 if (build_time) {
1126 r = pakfire_package_set_num(pkg, PAKFIRE_PKG_BUILD_TIME, build_time);
1127 if (r)
1128 goto ERROR;
1129 }
1130
1131 // Source package
1132 const char* source_name = pakfire_archive_metadata_get(archive, "build", "source-name");
1133 if (source_name) {
1134 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_NAME, source_name);
1135 if (r)
1136 goto ERROR;
1137 }
1138
1139 // Source EVR
1140 const char* source_evr = pakfire_archive_metadata_get(archive, "build", "source-evr");
1141 if (source_evr) {
1142 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_EVR, source_evr);
1143 if (r)
1144 goto ERROR;
1145 }
1146
1147 // Source arch
1148 const char* source_arch = pakfire_archive_metadata_get(archive, "build", "source-arch");
1149 if (source_arch) {
1150 r = pakfire_package_set_string(pkg, PAKFIRE_PKG_SOURCE_ARCH, source_arch);
1151 if (r)
1152 goto ERROR;
1153 }
1154
1155 // Dependencies
1156 for (const struct pakfire_dep* dep = pakfire_deps; dep->key; dep++) {
1157 struct json_object* array = pakfire_archive_metadata_get_object(
1158 archive, "dependencies", dep->name);
1159 if (!array)
1160 continue;
1161
1162 // Determine the length of the array
1163 const size_t length = json_object_array_length(array);
1164 if (!length)
1165 continue;
1166
1167 // Walk through all items in this array
1168 for (unsigned int i = 0; i < length; i++) {
1169 struct json_object* item = json_object_array_get_idx(array, i);
1170 if (!item)
1171 continue;
1172
1173 // Extract the string value
1174 const char* string = json_object_get_string(item);
1175 if (!string)
1176 continue;
1177
1178 // Add the dependency to the package
1179 r = pakfire_package_add_dep(pkg, dep->key, string);
1180 if (r)
1181 goto ERROR;
1182 }
1183 }
1184
1185 // Import the filelist
1186 r = pakfire_archive_import_filelist_from_json(archive, pkg);
1187 if (r)
1188 goto ERROR;
1189
1190 // Success!
1191 *package = pkg;
1192 r = 0;
1193
1194 ERROR:
1195 return r;
1196 }
1197
1198 /*
1199 Copy all metadata from this archive to the package object
1200 */
1201 PAKFIRE_EXPORT int pakfire_archive_make_package(struct pakfire_archive* archive,
1202 struct pakfire_repo* repo, struct pakfire_package** package) {
1203 struct pakfire_repo* dummy = NULL;
1204 int r;
1205
1206 // Use dummy repo if no repository was passed
1207 if (!repo) {
1208 dummy = pakfire_get_repo(archive->pakfire, PAKFIRE_REPO_DUMMY);
1209 if (!dummy)
1210 return 1;
1211
1212 repo = dummy;
1213 }
1214
1215 // Make package from JSON metadata
1216 r = pakfire_archive_make_package_from_json(archive, repo, package);
1217
1218 // Free dummy repository
1219 if (dummy)
1220 pakfire_repo_unref(dummy);
1221
1222 return r;
1223 }
1224
1225 struct pakfire_scriptlet* pakfire_archive_get_scriptlet(
1226 struct pakfire_archive* archive, const char* type) {
1227 struct pakfire_scriptlet* scriptlet = NULL;
1228
1229 for (unsigned int i = 0; i < archive->num_scriptlets; i++) {
1230 scriptlet = archive->scriptlets[i];
1231
1232 // Fetch type
1233 const char* t = pakfire_scriptlet_get_type(scriptlet);
1234
1235 // Compare type
1236 if (strcmp(t, type) == 0)
1237 return pakfire_scriptlet_ref(scriptlet);
1238 }
1239
1240 return NULL;
1241 }
1242
1243 /*
1244 systemd sysusers
1245 */
1246 static int __pakfire_archive_filter_systemd_sysusers(struct pakfire* pakfire,
1247 struct archive* a, struct archive_entry* e, void* data) {
1248 const char* path = archive_entry_pathname(e);
1249
1250 if (!pakfire_path_match("/usr/lib/sysusers.d/*.conf", path))
1251 return PAKFIRE_WALK_SKIP;
1252
1253 return PAKFIRE_WALK_OK;
1254 }
1255
1256 static int pakfire_archive_stream_payload(struct pakfire* pakfire, void* data, int fd) {
1257 char buffer[1024];
1258
1259 struct archive* a = (struct archive*)data;
1260
1261 // Read a block from the input archive
1262 ssize_t bytes_read = archive_read_data(a, buffer, sizeof(buffer));
1263 if (bytes_read < 0) {
1264 ERROR(pakfire, "Could not read from archive: %s\n", archive_error_string(a));
1265 return 1;
1266 }
1267
1268 // We have consumed everything
1269 if (bytes_read == 0)
1270 return EOF;
1271
1272 // Write the data to the output file descriptor
1273 ssize_t bytes_written = write(fd, buffer, bytes_read);
1274 if (bytes_written < 0) {
1275 ERROR(pakfire, "Could not stream output: %m\n");
1276 return 1;
1277 }
1278
1279 return 0;
1280 }
1281
1282 static int __pakfire_archive_handle_systemd_sysusers(struct pakfire* pakfire,
1283 struct archive* a, struct archive_entry* e, void* data) {
1284 struct pakfire_jail* jail = NULL;
1285 char replace[PATH_MAX];
1286 int r;
1287
1288 // Fetch path
1289 const char* path = archive_entry_pathname(e);
1290
1291 // Format --replace
1292 r = pakfire_string_format(replace, "--replace=/%s", path);
1293 if (r)
1294 goto ERROR;
1295
1296 const char* argv[] = { "/usr/bin/systemd-sysusers", replace, "-", NULL };
1297
1298 // Create a new jail
1299 r = pakfire_jail_create(&jail, pakfire);
1300 if (r)
1301 goto ERROR;
1302
1303 r = pakfire_jail_exec(jail, argv, pakfire_archive_stream_payload, NULL, a,
1304 PAKFIRE_JAIL_NOENT_OK);
1305
1306 ERROR:
1307 if (jail)
1308 pakfire_jail_unref(jail);
1309
1310 return r;
1311 }
1312
1313 int pakfire_archive_apply_systemd_sysusers(struct pakfire_archive* archive) {
1314 pakfire_archive_walk(archive,
1315 __pakfire_archive_filter_systemd_sysusers, __pakfire_archive_handle_systemd_sysusers, NULL);
1316
1317 return 0;
1318 }