16b384f39SPeter Avalos /*-
26b384f39SPeter Avalos * Copyright (c) 2003-2007 Tim Kientzle
36b384f39SPeter Avalos * All rights reserved.
46b384f39SPeter Avalos *
56b384f39SPeter Avalos * Redistribution and use in source and binary forms, with or without
66b384f39SPeter Avalos * modification, are permitted provided that the following conditions
76b384f39SPeter Avalos * are met:
86b384f39SPeter Avalos * 1. Redistributions of source code must retain the above copyright
96b384f39SPeter Avalos * notice, this list of conditions and the following disclaimer.
106b384f39SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
116b384f39SPeter Avalos * notice, this list of conditions and the following disclaimer in the
126b384f39SPeter Avalos * documentation and/or other materials provided with the distribution.
136b384f39SPeter Avalos *
146b384f39SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
156b384f39SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
166b384f39SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
176b384f39SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
186b384f39SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
196b384f39SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
206b384f39SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
216b384f39SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
226b384f39SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
236b384f39SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
246b384f39SPeter Avalos */
256b384f39SPeter Avalos
266b384f39SPeter Avalos #include "archive_platform.h"
276b384f39SPeter Avalos __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");
286b384f39SPeter Avalos
296b384f39SPeter Avalos #ifdef HAVE_SYS_TYPES_H
306b384f39SPeter Avalos #include <sys/types.h>
316b384f39SPeter Avalos #endif
326b384f39SPeter Avalos #ifdef HAVE_ERRNO_H
336b384f39SPeter Avalos #include <errno.h>
346b384f39SPeter Avalos #endif
356b384f39SPeter Avalos #ifdef HAVE_STRING_H
366b384f39SPeter Avalos #include <string.h>
376b384f39SPeter Avalos #endif
386b384f39SPeter Avalos
396b384f39SPeter Avalos #include "archive.h"
406b384f39SPeter Avalos #include "archive_entry.h"
416b384f39SPeter Avalos #include "archive_private.h"
426b384f39SPeter Avalos #include "archive_read_private.h"
436b384f39SPeter Avalos
446b384f39SPeter Avalos static int copy_data(struct archive *ar, struct archive *aw);
456b384f39SPeter Avalos static int archive_read_extract_cleanup(struct archive_read *);
466b384f39SPeter Avalos
476b384f39SPeter Avalos
486b384f39SPeter Avalos /* Retrieve an extract object without initialising the associated
496b384f39SPeter Avalos * archive_write_disk object.
506b384f39SPeter Avalos */
516b384f39SPeter Avalos struct archive_read_extract *
__archive_read_get_extract(struct archive_read * a)526b384f39SPeter Avalos __archive_read_get_extract(struct archive_read *a)
536b384f39SPeter Avalos {
546b384f39SPeter Avalos if (a->extract == NULL) {
55e95abc47Szrj a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract));
566b384f39SPeter Avalos if (a->extract == NULL) {
576b384f39SPeter Avalos archive_set_error(&a->archive, ENOMEM, "Can't extract");
586b384f39SPeter Avalos return (NULL);
596b384f39SPeter Avalos }
606b384f39SPeter Avalos a->cleanup_archive_extract = archive_read_extract_cleanup;
616b384f39SPeter Avalos }
626b384f39SPeter Avalos return (a->extract);
636b384f39SPeter Avalos }
646b384f39SPeter Avalos
656b384f39SPeter Avalos /*
666b384f39SPeter Avalos * Cleanup function for archive_extract.
676b384f39SPeter Avalos */
686b384f39SPeter Avalos static int
archive_read_extract_cleanup(struct archive_read * a)696b384f39SPeter Avalos archive_read_extract_cleanup(struct archive_read *a)
706b384f39SPeter Avalos {
716b384f39SPeter Avalos int ret = ARCHIVE_OK;
726b384f39SPeter Avalos
736b384f39SPeter Avalos if (a->extract->ad != NULL) {
746b384f39SPeter Avalos ret = archive_write_free(a->extract->ad);
756b384f39SPeter Avalos }
766b384f39SPeter Avalos free(a->extract);
776b384f39SPeter Avalos a->extract = NULL;
786b384f39SPeter Avalos return (ret);
796b384f39SPeter Avalos }
806b384f39SPeter Avalos
816b384f39SPeter Avalos int
archive_read_extract2(struct archive * _a,struct archive_entry * entry,struct archive * ad)826b384f39SPeter Avalos archive_read_extract2(struct archive *_a, struct archive_entry *entry,
836b384f39SPeter Avalos struct archive *ad)
846b384f39SPeter Avalos {
856b384f39SPeter Avalos struct archive_read *a = (struct archive_read *)_a;
866b384f39SPeter Avalos int r, r2;
876b384f39SPeter Avalos
886b384f39SPeter Avalos /* Set up for this particular entry. */
896b384f39SPeter Avalos if (a->skip_file_set)
906b384f39SPeter Avalos archive_write_disk_set_skip_file(ad,
916b384f39SPeter Avalos a->skip_file_dev, a->skip_file_ino);
926b384f39SPeter Avalos r = archive_write_header(ad, entry);
936b384f39SPeter Avalos if (r < ARCHIVE_WARN)
946b384f39SPeter Avalos r = ARCHIVE_WARN;
956b384f39SPeter Avalos if (r != ARCHIVE_OK)
966b384f39SPeter Avalos /* If _write_header failed, copy the error. */
976b384f39SPeter Avalos archive_copy_error(&a->archive, ad);
986b384f39SPeter Avalos else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)
996b384f39SPeter Avalos /* Otherwise, pour data into the entry. */
1006b384f39SPeter Avalos r = copy_data(_a, ad);
1016b384f39SPeter Avalos r2 = archive_write_finish_entry(ad);
1026b384f39SPeter Avalos if (r2 < ARCHIVE_WARN)
1036b384f39SPeter Avalos r2 = ARCHIVE_WARN;
1046b384f39SPeter Avalos /* Use the first message. */
1056b384f39SPeter Avalos if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
1066b384f39SPeter Avalos archive_copy_error(&a->archive, ad);
1076b384f39SPeter Avalos /* Use the worst error return. */
1086b384f39SPeter Avalos if (r2 < r)
1096b384f39SPeter Avalos r = r2;
1106b384f39SPeter Avalos return (r);
1116b384f39SPeter Avalos }
1126b384f39SPeter Avalos
1136b384f39SPeter Avalos void
archive_read_extract_set_progress_callback(struct archive * _a,void (* progress_func)(void *),void * user_data)1146b384f39SPeter Avalos archive_read_extract_set_progress_callback(struct archive *_a,
1156b384f39SPeter Avalos void (*progress_func)(void *), void *user_data)
1166b384f39SPeter Avalos {
1176b384f39SPeter Avalos struct archive_read *a = (struct archive_read *)_a;
1186b384f39SPeter Avalos struct archive_read_extract *extract = __archive_read_get_extract(a);
1196b384f39SPeter Avalos if (extract != NULL) {
1206b384f39SPeter Avalos extract->extract_progress = progress_func;
1216b384f39SPeter Avalos extract->extract_progress_user_data = user_data;
1226b384f39SPeter Avalos }
1236b384f39SPeter Avalos }
1246b384f39SPeter Avalos
1256b384f39SPeter Avalos static int
copy_data(struct archive * ar,struct archive * aw)1266b384f39SPeter Avalos copy_data(struct archive *ar, struct archive *aw)
1276b384f39SPeter Avalos {
1286b384f39SPeter Avalos int64_t offset;
1296b384f39SPeter Avalos const void *buff;
1306b384f39SPeter Avalos struct archive_read_extract *extract;
1316b384f39SPeter Avalos size_t size;
1326b384f39SPeter Avalos int r;
1336b384f39SPeter Avalos
1346b384f39SPeter Avalos extract = __archive_read_get_extract((struct archive_read *)ar);
1356b384f39SPeter Avalos if (extract == NULL)
1366b384f39SPeter Avalos return (ARCHIVE_FATAL);
1376b384f39SPeter Avalos for (;;) {
1386b384f39SPeter Avalos r = archive_read_data_block(ar, &buff, &size, &offset);
1396b384f39SPeter Avalos if (r == ARCHIVE_EOF)
1406b384f39SPeter Avalos return (ARCHIVE_OK);
1416b384f39SPeter Avalos if (r != ARCHIVE_OK)
1426b384f39SPeter Avalos return (r);
1436b384f39SPeter Avalos r = (int)archive_write_data_block(aw, buff, size, offset);
1446b384f39SPeter Avalos if (r < ARCHIVE_WARN)
1456b384f39SPeter Avalos r = ARCHIVE_WARN;
1466b384f39SPeter Avalos if (r < ARCHIVE_OK) {
1476b384f39SPeter Avalos archive_set_error(ar, archive_errno(aw),
1486b384f39SPeter Avalos "%s", archive_error_string(aw));
1496b384f39SPeter Avalos return (r);
1506b384f39SPeter Avalos }
1516b384f39SPeter Avalos if (extract->extract_progress)
1526b384f39SPeter Avalos (extract->extract_progress)
1536b384f39SPeter Avalos (extract->extract_progress_user_data);
1546b384f39SPeter Avalos }
1556b384f39SPeter Avalos }
156