archive_read_data_into_fd.c revision 228761
153451Speter/*-
253473Sobrien * Copyright (c) 2003-2007 Tim Kientzle
353451Speter * All rights reserved.
453451Speter *
553451Speter * Redistribution and use in source and binary forms, with or without
653451Speter * modification, are permitted provided that the following conditions
753451Speter * are met:
853451Speter * 1. Redistributions of source code must retain the above copyright
953451Speter *    notice, this list of conditions and the following disclaimer.
1053451Speter * 2. Redistributions in binary form must reproduce the above copyright
1153451Speter *    notice, this list of conditions and the following disclaimer in the
1253451Speter *    documentation and/or other materials provided with the distribution.
1353451Speter *
1453451Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1553451Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1653473Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1753451Speter * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1853451Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1953451Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2053473Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2153473Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2253451Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2353451Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2453451Speter */
2553451Speter
2653451Speter#include "archive_platform.h"
27131557Stjr__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/05/23 05:01:29 cperciva Exp $");
2853473Sobrien
2953473Sobrien#ifdef HAVE_SYS_TYPES_H
3053473Sobrien#include <sys/types.h>
3153473Sobrien#endif
3253473Sobrien#ifdef HAVE_ERRNO_H
3353473Sobrien#include <errno.h>
3453473Sobrien#endif
3553473Sobrien#ifdef HAVE_UNISTD_H
3653473Sobrien#include <unistd.h>
37131557Stjr#endif
38131557Stjr
39131557Stjr#include "archive.h"
40131557Stjr#include "archive_private.h"
41131557Stjr
42131557Stjr/* Maximum amount of data to write at one time. */
43131557Stjr#define	MAX_WRITE	(1024 * 1024)
44131557Stjr
4553473Sobrien/*
4653473Sobrien * This implementation minimizes copying of data and is sparse-file aware.
4753473Sobrien */
4853451Speterint
4953473Sobrienarchive_read_data_into_fd(struct archive *a, int fd)
5053451Speter{
5153473Sobrien	int r;
5253451Speter	const void *buff;
5353451Speter	size_t size, bytes_to_write;
5453451Speter	ssize_t bytes_written, total_written;
5553451Speter	off_t offset;
5653451Speter	off_t output_offset;
5753473Sobrien
5853451Speter	__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_into_fd");
5953473Sobrien
6053451Speter	total_written = 0;
6153451Speter	output_offset = 0;
6253451Speter
6353451Speter	while ((r = archive_read_data_block(a, &buff, &size, &offset)) ==
6453451Speter	    ARCHIVE_OK) {
6553451Speter		const char *p = buff;
6653451Speter		if (offset > output_offset) {
6753451Speter			output_offset = lseek(fd,
6853451Speter			    offset - output_offset, SEEK_CUR);
6953451Speter			if (output_offset != offset) {
7053451Speter				archive_set_error(a, errno, "Seek error");
7153451Speter				return (ARCHIVE_FATAL);
7253451Speter			}
7353451Speter		}
7453451Speter		while (size > 0) {
7553451Speter			bytes_to_write = size;
7653451Speter			if (bytes_to_write > MAX_WRITE)
7753451Speter				bytes_to_write = MAX_WRITE;
7853451Speter			bytes_written = write(fd, p, bytes_to_write);
7953451Speter			if (bytes_written < 0) {
8053451Speter				archive_set_error(a, errno, "Write error");
8153451Speter				return (ARCHIVE_FATAL);
8253451Speter			}
8353451Speter			output_offset += bytes_written;
8453451Speter			total_written += bytes_written;
8553451Speter			p += bytes_written;
8653451Speter			size -= bytes_written;
8753451Speter		}
8853451Speter	}
8953451Speter
9053451Speter	if (r != ARCHIVE_EOF)
9153451Speter		return (r);
9253451Speter	return (ARCHIVE_OK);
9353451Speter}
9453451Speter