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