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