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