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