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