]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/packager.c
packager: Add new function that accepts a file object
[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
b59c9fa2
MT
33#include <json.h>
34
2adc4a4a 35#include <pakfire/archive.h>
436677a3 36#include <pakfire/constants.h>
1ea1f35b 37#include <pakfire/logging.h>
6aeb48e6
MT
38#include <pakfire/package.h>
39#include <pakfire/packager.h>
40#include <pakfire/pakfire.h>
677e9e5b 41#include <pakfire/pwd.h>
d973a13d 42#include <pakfire/string.h>
f57ad279 43#include <pakfire/util.h>
6aeb48e6
MT
44
45struct pakfire_packager {
ac4c607b 46 struct pakfire* pakfire;
6aeb48e6 47 int nrefs;
05cfc2c9 48 time_t time_created;
6aeb48e6 49
31480bee 50 struct pakfire_package* pkg;
bb06d548 51 char filename[PATH_MAX];
1ea1f35b 52
738b3582
MT
53 // Reader
54 struct archive* reader;
55
56 // Payload
1ea1f35b 57 struct archive* payload;
7836e21b 58 FILE* fpayload;
e282863a 59 size_t installsize;
bee2e8a7 60 unsigned int files;
106d2edd
MT
61
62 struct pakfire_scriptlet** scriptlets;
63 unsigned int num_scriptlets;
6aeb48e6
MT
64};
65
af14aefb 66static int pakfire_packager_create_payload(struct pakfire_packager* p) {
6bf2cf50 67 char path[] = PAKFIRE_TMP_DIR "/pakfire-payload.XXXXXX";
7836e21b 68
1ea1f35b 69 p->payload = archive_write_new();
427fdd80
MT
70 if (!p->payload) {
71 ERROR(p->pakfire, "archive_write_new() failed\n");
72 return 1;
73 }
1ea1f35b
MT
74
75 // Use the PAX format
76 int r = archive_write_set_format_pax(p->payload);
77 if (r) {
78 ERROR(p->pakfire, "Could not set format to PAX: %s\n",
79 archive_error_string(p->payload));
80 return r;
81 }
82
7836e21b 83 // Create a new temporary file
265a7974 84 p->fpayload = pakfire_mktemp(path);
f57ad279 85 if (!p->fpayload)
1ea1f35b 86 return 1;
1ea1f35b 87
7836e21b 88 // Unlink the file straight away
265a7974 89 unlink(path);
7836e21b 90
7836e21b
MT
91 // Write archive to file
92 r = archive_write_open_FILE(p->payload, p->fpayload);
1ea1f35b
MT
93 if (r)
94 return r;
95
c62f6f57
MT
96 // Add a requirement for the cryptographic algorithms we are using
97 pakfire_package_add_requires(p->pkg, "pakfire(Digest-SHA512)");
655bb44a 98 pakfire_package_add_requires(p->pkg, "pakfire(Digest-SHA256)");
c62f6f57 99
1ea1f35b
MT
100 return 0;
101}
102
103static void pakfire_packager_free(struct pakfire_packager* packager) {
106d2edd
MT
104 // Scriptlets
105 if (packager->scriptlets) {
106 for (unsigned int i = 0; i < packager->num_scriptlets; i++)
9dd7b1aa 107 pakfire_scriptlet_unref(packager->scriptlets[i]);
106d2edd
MT
108 free(packager->scriptlets);
109 }
110
4eab5079 111 // Payload
1ea1f35b
MT
112 if (packager->payload)
113 archive_write_free(packager->payload);
114
7836e21b
MT
115 if (packager->fpayload)
116 fclose(packager->fpayload);
117
738b3582 118 if (packager->reader)
66817062 119 archive_read_free(packager->reader);
738b3582 120
1ea1f35b
MT
121 pakfire_package_unref(packager->pkg);
122 pakfire_unref(packager->pakfire);
51105783 123 free(packager);
1ea1f35b
MT
124}
125
22b8e37b 126int pakfire_packager_create(struct pakfire_packager** packager,
5d7a93ec 127 struct pakfire* pakfire, struct pakfire_package* pkg) {
6aeb48e6
MT
128 struct pakfire_packager* p = calloc(1, sizeof(*p));
129 if (!p)
130 return ENOMEM;
131
e282863a
MT
132 int r = 1;
133
05cfc2c9
MT
134 // Save creation time
135 p->time_created = time(NULL);
136
6aeb48e6
MT
137 // Initialize reference counting
138 p->nrefs = 1;
139
140 // Store a reference to Pakfire
5d7a93ec 141 p->pakfire = pakfire_ref(pakfire);
6aeb48e6
MT
142
143 // Store a reference to the package
144 p->pkg = pakfire_package_ref(pkg);
145
cd2c2cfb
MT
146 // Set build host
147 pakfire_package_set_build_host(pkg, pakfire_hostname());
148
149 // Set build time
150 pakfire_package_set_build_time(pkg, p->time_created);
151
0682aeb3 152 // Create reader
66817062
MT
153 p->reader = pakfire_make_archive_disk_reader(p->pakfire, 1);
154 if (!p->reader)
1ba1869e 155 goto ERROR;
1ea1f35b 156
0682aeb3 157 // Start payload
af14aefb 158 r = pakfire_packager_create_payload(p);
0682aeb3 159 if (r)
738b3582 160 goto ERROR;
738b3582 161
6aeb48e6
MT
162 *packager = p;
163
164 return 0;
1ba1869e
MT
165
166ERROR:
167 pakfire_packager_free(p);
168
169 return r;
6aeb48e6
MT
170}
171
22b8e37b 172struct pakfire_packager* pakfire_packager_ref(
6aeb48e6
MT
173 struct pakfire_packager* packager) {
174 ++packager->nrefs;
175
176 return packager;
177}
178
22b8e37b 179struct pakfire_packager* pakfire_packager_unref(
6aeb48e6
MT
180 struct pakfire_packager* packager) {
181 if (--packager->nrefs > 0)
182 return packager;
183
184 pakfire_packager_free(packager);
185
186 return NULL;
187}
da08f989 188
22b8e37b 189const char* pakfire_packager_filename(struct pakfire_packager* packager) {
bb06d548
MT
190 if (!*packager->filename) {
191 const char* filename = pakfire_package_get_filename(packager->pkg);
192
193 // Add arch
194 if (pakfire_package_is_source(packager->pkg))
195 pakfire_string_set(packager->filename, filename);
196 else {
197 const char* arch = pakfire_package_get_arch(packager->pkg);
198
199 pakfire_string_format(packager->filename, "%s/%s", arch, filename);
200 }
201 }
202
203 return packager->filename;
96d2c7bc
MT
204}
205
28700a5b 206static struct archive_entry* pakfire_packager_create_file(
95b81a98 207 struct pakfire_packager* packager, const char* filename, size_t size, mode_t mode) {
98e85f1c
MT
208 // Create a new file entry
209 struct archive_entry* entry = archive_entry_new();
210 if (!entry)
28700a5b 211 return NULL;
98e85f1c
MT
212
213 // Set filename
214 archive_entry_set_pathname(entry, filename);
215
216 // This is a regular file
217 archive_entry_set_filetype(entry, AE_IFREG);
95b81a98 218 archive_entry_set_perm(entry, mode);
98e85f1c 219
28700a5b
MT
220 // Set size
221 archive_entry_set_size(entry, size);
222
05cfc2c9
MT
223 // Set ownership
224 archive_entry_set_uname(entry, "root");
225 archive_entry_set_uid(entry, 0);
226 archive_entry_set_gname(entry, "root");
227 archive_entry_set_gid(entry, 0);
228
229 // Set times
230 archive_entry_set_birthtime(entry, packager->time_created, 0);
231 archive_entry_set_ctime(entry, packager->time_created, 0);
232 archive_entry_set_mtime(entry, packager->time_created, 0);
233 archive_entry_set_atime(entry, packager->time_created, 0);
234
28700a5b
MT
235 return entry;
236}
237
238static int pakfire_packager_write_file_from_buffer(struct pakfire_packager* packager,
bfdad796 239 struct archive* a, const char* filename, mode_t mode, const char* buffer) {
28700a5b
MT
240 size_t size = strlen(buffer);
241
242 // Create a new file
7e346194
MT
243 struct archive_entry* entry = pakfire_packager_create_file(packager, filename, size, mode);
244 if (!entry) {
245 ERROR(packager->pakfire, "Could not create file '%s'\n", filename);
28700a5b 246 return 1;
7e346194 247 }
98e85f1c
MT
248
249 // This is the end of the header
250 int r = archive_write_header(a, entry);
251 if (r) {
252 ERROR(packager->pakfire, "Error writing header: %s\n", archive_error_string(a));
265a7974 253 goto ERROR;
98e85f1c
MT
254 }
255
256 // Write content
257 r = archive_write_data(a, buffer, strlen(buffer));
258 if (r < 0) {
259 ERROR(packager->pakfire, "Error writing data: %s\n", archive_error_string(a));
265a7974 260 goto ERROR;
98e85f1c
MT
261 }
262
265a7974
MT
263 // Success
264 r = 0;
265
266ERROR:
98e85f1c
MT
267 archive_entry_free(entry);
268
265a7974 269 return r;
98e85f1c
MT
270}
271
436677a3
MT
272static int pakfire_packager_write_format(struct pakfire_packager* packager,
273 struct archive* a) {
274 const char buffer[] = TO_STRING(PACKAGE_FORMAT) "\n";
275
7e346194
MT
276 DEBUG(packager->pakfire, "Writing package format\n");
277
bfdad796 278 int r = pakfire_packager_write_file_from_buffer(packager, a,
0dbfb5e1 279 "pakfire-format", 0444, buffer);
a6dd151e
MT
280 if (r)
281 return r;
282
283 // Add package format marker
284 pakfire_package_add_requires(packager->pkg,
285 "pakfire(PackageFormat-" TO_STRING(PACKAGE_FORMAT) ")");
286
287 return 0;
436677a3
MT
288}
289
b59c9fa2
MT
290static char* pakfire_packager_make_metadata(struct pakfire_packager* packager) {
291 char* result = NULL;
98e85f1c 292
b59c9fa2
MT
293 // Convert all package metadata to JSON
294 struct json_object* md = pakfire_package_to_json(packager->pkg);
295 if (!md)
98e85f1c
MT
296 goto ERROR;
297
b59c9fa2 298 // Serialize JSON to file
ef4a2e77 299 const char* s = json_object_to_json_string_ext(md, 0);
b59c9fa2 300 if (!s)
98e85f1c
MT
301 goto ERROR;
302
b59c9fa2
MT
303 // Copy result onto heap
304 result = strdup(s);
305 if (!result)
98e85f1c 306 goto ERROR;
98e85f1c
MT
307
308ERROR:
b59c9fa2
MT
309 // Free metadata
310 if (md)
311 json_object_put(md);
98e85f1c 312
b59c9fa2 313 return result;
98e85f1c
MT
314}
315
316static int pakfire_packager_write_metadata(struct pakfire_packager* packager,
bfdad796 317 struct archive* a) {
98e85f1c 318 // Make metadata
b59c9fa2 319 char* buffer = pakfire_packager_make_metadata(packager);
98e85f1c
MT
320 if (!buffer)
321 return 1;
322
b59c9fa2 323 DEBUG(packager->pakfire, "Generated package metadata:\n%s\n", buffer);
98e85f1c
MT
324
325 // Write buffer
bfdad796 326 int r = pakfire_packager_write_file_from_buffer(packager, a,
9f6b177b 327 ".PKGINFO", 0444, buffer);
98e85f1c
MT
328
329 free(buffer);
330
331 return r;
332}
333
1b4e7c7b
MT
334static int pakfire_packager_copy_archive(struct pakfire_packager* packager,
335 struct archive* a, FILE* f) {
336 struct archive* payload = NULL;
337 struct archive_entry* entry = NULL;
338 int r;
2adc4a4a 339
1b4e7c7b 340 DEBUG(packager->pakfire, "Copying payload\n");
2adc4a4a
MT
341
342 // Reset fd to beginning of the file
4eab5079 343 rewind(f);
2adc4a4a 344
1b4e7c7b
MT
345 // Re-open the payload archive for reading
346 payload = archive_read_new();
347 if (!payload) {
348 ERROR(packager->pakfire, "Could not create archive reader: %m\n");
349 r = 1;
350 goto ERROR;
351 }
2adc4a4a 352
1b4e7c7b
MT
353 // We expect a tar archive
354 r = archive_read_support_format_tar(payload);
2adc4a4a 355 if (r) {
1b4e7c7b
MT
356 ERROR(packager->pakfire, "Could not add support for tar: %s\n",
357 archive_error_string(payload));
358 goto ERROR;
2adc4a4a
MT
359 }
360
1b4e7c7b
MT
361 // Open the file handle
362 r = archive_read_open_FILE(payload, f);
2adc4a4a 363 if (r) {
1b4e7c7b
MT
364 ERROR(packager->pakfire, "Could not open payload: %s\n",
365 archive_error_string(payload));
2adc4a4a
MT
366 goto ERROR;
367 }
368
1b4e7c7b
MT
369 // Copy all files into our archive
370 for (;;) {
371 r = archive_read_next_header(payload, &entry);
7e346194 372
1b4e7c7b
MT
373 // End when we have reached the end of the archive
374 if (r == ARCHIVE_EOF) {
375 r = 0;
376 break;
377 }
378
379 // Raise any other errors
380 else if (r) {
381 ERROR(packager->pakfire, "Could not read next header: %s\n",
382 archive_error_string(payload));
383 goto ERROR;
384 }
385
386 // Write the entry
387 r = archive_write_header(a, entry);
388 if (r) {
389 ERROR(packager->pakfire, "Could not write entry: %s\n",
390 archive_error_string(a));
391 goto ERROR;
392 }
393
394 // Copy the data
395 r = pakfire_archive_copy_data(packager->pakfire, payload, a);
396 if (r)
397 goto ERROR;
7e346194 398 }
2adc4a4a
MT
399
400 // Success
401 r = 0;
402
403ERROR:
1b4e7c7b
MT
404 if (payload)
405 archive_read_free(payload);
2adc4a4a
MT
406
407 return r;
408}
409
106d2edd 410static int pakfire_packager_write_scriptlet(struct pakfire_packager* packager,
bfdad796 411 struct archive* a, struct pakfire_scriptlet* scriptlet) {
106d2edd
MT
412 char filename[PATH_MAX];
413 size_t size;
414 int r;
415
416 // Fetch type
417 const char* type = pakfire_scriptlet_get_type(scriptlet);
418
419 DEBUG(packager->pakfire, "Writing scriptlet '%s' to package\n", type);
420
421 // Make filename
9f6b177b 422 r = pakfire_string_format(filename, ".scriptlets/%s", type);
a60955af 423 if (r)
106d2edd
MT
424 return r;
425
426 // Fetch scriptlet
427 const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
428
429 // Write file
bfdad796 430 return pakfire_packager_write_file_from_buffer(packager, a, filename, 0544, data);
106d2edd
MT
431}
432
436677a3
MT
433/*
434 This function is being called at the end when all data has been added to the package.
435
436 It will create a new archive and write the package to the given file descriptor.
437*/
22b8e37b 438int pakfire_packager_finish(struct pakfire_packager* packager, FILE* f) {
1b4e7c7b 439 struct archive* a = NULL;
96d2c7bc 440 int r = 1;
436677a3 441
1b4e7c7b
MT
442 // Close the payload
443 if (packager->payload) {
444 r = archive_write_free(packager->payload);
445 if (r) {
446 ERROR(packager->pakfire, "Could not close payload: %s\n",
447 archive_error_string(packager->payload));
448 goto ERROR;
449 }
450 packager->payload = NULL;
451 }
452
555b6dd2
MT
453 // Add requires feature markers
454 if (pakfire_package_has_rich_deps(packager->pkg))
455 pakfire_package_add_requires(packager->pkg, "pakfire(RichDependencies)");
456
508e2030 457 // Store total install size
e282863a 458 pakfire_package_set_installsize(packager->pkg, packager->installsize);
fafe383d 459
508e2030
MT
460 // Dump package metadata
461 char* dump = pakfire_package_dump(packager->pkg, PAKFIRE_PKG_DUMP_LONG);
462 if (dump) {
463 INFO(packager->pakfire, "%s\n", dump);
464 free(dump);
465 }
466
436677a3 467 // Open a new archive
1b4e7c7b 468 a = archive_write_new();
436677a3
MT
469 if (!a) {
470 ERROR(packager->pakfire, "archive_write_new() failed\n");
471 goto ERROR;
472 }
473
474 // Use the PAX format
96d2c7bc 475 r = archive_write_set_format_pax(a);
436677a3
MT
476 if (r) {
477 ERROR(packager->pakfire, "Could not set format to PAX: %s\n",
478 archive_error_string(a));
479 goto ERROR;
480 }
481
63476763
MT
482 // Store any extended attributes in the SCHILY headers
483 r = archive_write_set_format_option(a, "pax", "xattrheader", "SCHILY");
484 if (r) {
485 ERROR(packager->pakfire, "Could not set xattrheader option: %s\n",
486 archive_error_string(a));
487 return r;
488 }
489
490 // Enable Zstd
491 r = archive_write_add_filter_zstd(a);
492 if (r) {
493 ERROR(packager->pakfire, "Could not enable Zstandard compression: %s\n",
494 archive_error_string(a));
495 return r;
496 }
497
498 // Set compression level to highest
499 r = archive_write_set_filter_option(a, NULL, "compression-level", "22");
500 if (r) {
501 ERROR(packager->pakfire, "Could not set Zstandard compression level: %s\n",
502 archive_error_string(a));
503 return r;
504 }
505
506 // Add feature marker
507 pakfire_package_add_requires(packager->pkg, "pakfire(Compress-Zstandard)");
508
509 // Do not pad the last block
510 archive_write_set_bytes_in_last_block(a, 1);
511
436677a3
MT
512 // Write archive to f
513 r = archive_write_open_FILE(a, f);
514 if (r) {
515 ERROR(packager->pakfire, "archive_write_open_FILE() failed: %s\n",
516 archive_error_string(a));
517 goto ERROR;
518 }
519
520 // Start with the format file
521 r = pakfire_packager_write_format(packager, a);
265a7974
MT
522 if (r) {
523 ERROR(packager->pakfire, "Could not add format file to archive: %s\n",
524 archive_error_string(a));
436677a3 525 goto ERROR;
265a7974 526 }
436677a3 527
98e85f1c 528 // Write the metadata
bfdad796 529 r = pakfire_packager_write_metadata(packager, a);
265a7974
MT
530 if (r) {
531 ERROR(packager->pakfire, "Could not add metadata file to archive: %s\n",
532 archive_error_string(a));
98e85f1c 533 goto ERROR;
265a7974 534 }
98e85f1c 535
d8856104
MT
536 // Write scriptlets
537 for (unsigned int i = 0; i < packager->num_scriptlets; i++) {
538 r = pakfire_packager_write_scriptlet(packager, a, packager->scriptlets[i]);
539 if (r) {
540 ERROR(packager->pakfire, "Could not add scriptlet to the archive: %m\n");
541 goto ERROR;
542 }
543 }
544
bfdad796 545 // Write the payload
bee2e8a7 546 if (packager->files) {
1b4e7c7b 547 r = pakfire_packager_copy_archive(packager, a, packager->fpayload);
bee2e8a7
MT
548 if (r) {
549 ERROR(packager->pakfire, "Could not add payload to archive: %s\n",
550 archive_error_string(a));
551 goto ERROR;
552 }
265a7974
MT
553 }
554
96d2c7bc
MT
555 // Success
556 r = 0;
436677a3
MT
557
558ERROR:
559 if (a)
265a7974 560 archive_write_free(a);
436677a3 561
96d2c7bc 562 return r;
436677a3
MT
563}
564
22b8e37b 565int pakfire_packager_finish_to_directory(struct pakfire_packager* packager,
45448dbd 566 const char* target, char** result) {
48c6f2e7 567 char path[PATH_MAX];
bb06d548 568 char tmppath[PATH_MAX];
48c6f2e7
MT
569 int r = 1;
570
571 // target cannot be empty
572 if (!target) {
573 errno = EINVAL;
574 return 1;
575 }
576
bb06d548
MT
577 // Get the filename of the package
578 const char* filename = pakfire_packager_filename(packager);
579 if (!filename) {
b1772bfb 580 ERROR(packager->pakfire, "Could not generate filename for package: %m\n");
bb06d548
MT
581 r = 1;
582 goto ERROR;
583 }
584
585 // Make the package path
586 r = pakfire_string_format(path, "%s/%s", target, filename);
a60955af 587 if (r)
bb06d548
MT
588 goto ERROR;
589
590 // Create the parent directory
520ce66c 591 r = pakfire_mkparentdir(path, 0755);
bb06d548
MT
592 if (r)
593 goto ERROR;
594
48c6f2e7 595 // Create a temporary file in the target directory
bb06d548 596 r = pakfire_string_format(tmppath, "%s.XXXXXX", path);
a60955af 597 if (r)
bb06d548 598 goto ERROR;
48c6f2e7
MT
599
600 // Create a temporary result file
bb06d548 601 FILE* f = pakfire_mktemp(tmppath);
48c6f2e7
MT
602 if (!f)
603 goto ERROR;
604
605 // Write the finished package
606 r = pakfire_packager_finish(packager, f);
bb06d548
MT
607 fclose(f);
608
48c6f2e7 609 if (r) {
b1772bfb 610 ERROR(packager->pakfire, "pakfire_packager_finish() failed: %m\n");
48c6f2e7
MT
611 goto ERROR;
612 }
613
48c6f2e7 614 // Move the temporary file to destination
bb06d548
MT
615 r = rename(tmppath, path);
616 if (r) {
b1772bfb 617 ERROR(packager->pakfire, "Could not move %s to %s: %m\n", tmppath, path);
48c6f2e7 618 goto ERROR;
bb06d548 619 }
48c6f2e7 620
bb06d548 621 INFO(packager->pakfire, "Package written to %s\n", path);
48c6f2e7 622
45448dbd
MT
623 // Store result path if requested
624 if (result) {
625 *result = strdup(path);
626 if (!*result) {
627 r = 1;
628 goto ERROR;
629 }
630 }
631
48c6f2e7
MT
632 // Success
633 r = 0;
634
635ERROR:
636 // Remove temporary file
bb06d548
MT
637 if (r && *tmppath)
638 unlink(tmppath);
48c6f2e7 639
bb06d548 640 return r;
48c6f2e7
MT
641}
642
85b59296
MT
643static int pakfire_packager_add_file(struct pakfire_packager* packager,
644 struct pakfire_file* file) {
645 struct archive_entry* entry = NULL;
da08f989 646 FILE* f = NULL;
85b59296 647 int r;
da08f989 648
85b59296
MT
649 // Check input
650 if (!file) {
255d4488
MT
651 errno = EINVAL;
652 return 1;
653 }
da08f989 654
7836e21b 655 // Payload has already been closed
85b59296
MT
656 if (!packager->payload) {
657 ERROR(packager->pakfire, "Payload has already been closed\n");
730ebb9f
MT
658 errno = EPERM;
659 return 1;
660 }
661
85b59296
MT
662 // Fetch path
663 const char* path = pakfire_file_get_path(file);
da08f989 664
85b59296
MT
665 // Fetch filetype
666 const mode_t filetype = pakfire_file_get_type(file);
7e346194 667
85b59296
MT
668 // Files cannot have an empty path
669 if (!*path) {
670 ERROR(packager->pakfire, "Cannot add a file with an empty path\n");
671 errno = EPERM;
672 return 1;
da08f989 673
85b59296
MT
674 // Hidden files cannot be added
675 } else if (*path == '.') {
676 ERROR(packager->pakfire, "Hidden files cannot be added to a package: %s\n", path);
677 errno = EPERM;
678 return 1;
738b3582 679 }
da08f989 680
85b59296
MT
681 DEBUG(packager->pakfire, "Adding file to payload: %s\n", path);
682
2ed2b519
MT
683 // Overwrite a couple of things for source archives
684 if (pakfire_package_is_source(packager->pkg)) {
85b59296 685#if 0
2ed2b519 686 // Reset permissions
85b59296
MT
687 pakfire_file_set_perms(file, 0644);
688#endif
2ed2b519
MT
689
690 // Reset file ownership
85b59296
MT
691 pakfire_file_set_user(file, "root");
692 pakfire_file_set_group(file, "root");
2ed2b519
MT
693 }
694
85b59296
MT
695 // Open the file
696 f = pakfire_file_open(file);
697 if (!f)
010e5fc8 698 goto ERROR;
85b59296
MT
699
700#if 0
701 // Add digests for regular files
702 if (filetype == AE_IFREG) {
703 r = pakfire_packager_compute_digests(packager, entry, f);
704 if (r) {
705 ERROR(packager->pakfire, "Could not compute digests: %m\n")
706 goto ERROR;
707 }
708
709 // Rewind the file descriptor
710 rewind(f);
010e5fc8 711 }
85b59296
MT
712#endif
713
714 // Generate file metadata into an archive entry
715 entry = pakfire_file_archive_entry(file);
716 if (!entry)
717 goto ERROR;
010e5fc8 718
da08f989
MT
719 // Write the header
720 r = archive_write_header(packager->payload, entry);
721 if (r) {
722 ERROR(packager->pakfire, "Error writing file header: %s\n",
723 archive_error_string(packager->payload));
724 goto ERROR;
725 }
726
010e5fc8 727 // Copy the data of regular files
85b59296 728 if (filetype == S_IFREG) {
010e5fc8 729 // Copy the payload into the archive
619aa811 730 r = pakfire_archive_copy_data_from_file(packager->pakfire, packager->payload, f);
010e5fc8
MT
731 if (r)
732 goto ERROR;
010e5fc8
MT
733 }
734
e282863a 735 // Increment installsize
85b59296 736 packager->installsize += pakfire_file_get_size(file);
1ba1869e 737
bee2e8a7
MT
738 // Increment file counter
739 packager->files++;
740
da08f989
MT
741ERROR:
742 if (entry)
743 archive_entry_free(entry);
da08f989
MT
744 if (f)
745 fclose(f);
746
747 return r;
748}
106d2edd 749
85b59296
MT
750int pakfire_packager_add(struct pakfire_packager* packager,
751 const char* sourcepath, const char* path) {
752 struct pakfire_file* file = NULL;
753 int r = 1;
754
755 // Check if path is set
756 if (!sourcepath) {
757 errno = EINVAL;
758 return 1;
759 }
760
761 // Use basename if path isn't set
762 if (!path) {
763 path = strrchr(sourcepath, '/');
764 if (path)
765 path++;
766 }
767
768 // Create a new file entry
769 struct archive_entry* entry = archive_entry_new();
770 if (!entry)
771 return 1;
772
773 // Set the source path
774 archive_entry_copy_sourcepath(entry, sourcepath);
775
776 // Set path in archive
777 if (path)
778 archive_entry_set_pathname(entry, path);
779
780 // Read all attributes from file
781 r = archive_read_disk_entry_from_file(packager->reader, entry, -1, NULL);
782 if (r) {
783 ERROR(packager->pakfire, "Could not read attributes from %s: %m\n", path);
784 goto ERROR;
785 }
786
787 // Convert to file
788 r = pakfire_file_create_from_archive_entry(&file, packager->pakfire, entry);
789 if (r)
790 goto ERROR;
791
792 // Call the main function
793 r = pakfire_packager_add_file(packager, file);
794
795ERROR:
796 if (file)
797 pakfire_file_unref(file);
798
799 return r;
800}
801
106d2edd
MT
802int pakfire_packager_add_scriptlet(struct pakfire_packager* packager,
803 struct pakfire_scriptlet* scriptlet) {
804 if (!scriptlet) {
805 errno = EINVAL;
806 return 1;
807 }
808
809 // Extend array
810 packager->scriptlets = reallocarray(packager->scriptlets,
811 packager->num_scriptlets + 1, sizeof(*packager->scriptlets));
812 if (!packager->scriptlets)
813 return 1;
814
815 // Append scriptlet
816 packager->scriptlets[packager->num_scriptlets++] = pakfire_scriptlet_ref(scriptlet);
817
818 return 0;
819}