]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/packager.c
dist: Refactor downloading sources
[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
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
47struct 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 63static 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
125static 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
140PAKFIRE_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
177ERROR:
178 pakfire_packager_free(p);
179
180 return r;
6aeb48e6
MT
181}
182
6aeb48e6
MT
183PAKFIRE_EXPORT struct pakfire_packager* pakfire_packager_ref(
184 struct pakfire_packager* packager) {
185 ++packager->nrefs;
186
187 return packager;
188}
189
190PAKFIRE_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
200PAKFIRE_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
221static 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
247static 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
279static 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
309static 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
317static 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
541ERROR:
542 if (buffer)
543 free(buffer);
544
545 return NULL;
546}
547
548static 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
566static 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
609ERROR:
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
620PAKFIRE_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
668ERROR:
669 if (a)
670 archive_free(a);
671
96d2c7bc 672 return r;
436677a3
MT
673}
674
da08f989 675PAKFIRE_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
752ERROR:
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}