archive_read_data_into_fd.c revision 259065
1272343Sngie/*- 2272343Sngie * Copyright (c) 2003-2007 Tim Kientzle 3272343Sngie * All rights reserved. 4272343Sngie * 5272343Sngie * Redistribution and use in source and binary forms, with or without 6272343Sngie * modification, are permitted provided that the following conditions 7272343Sngie * are met: 8272343Sngie * 1. Redistributions of source code must retain the above copyright 9272343Sngie * notice, this list of conditions and the following disclaimer. 10272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer in the 12272343Sngie * documentation and/or other materials provided with the distribution. 13272343Sngie * 14272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15272343Sngie * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16272343Sngie * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17272343Sngie * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18272343Sngie * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19272343Sngie * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20272343Sngie * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21272343Sngie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22272343Sngie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23272343Sngie * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24272343Sngie */ 25272343Sngie 26272343Sngie#include "archive_platform.h" 27272343Sngie__FBSDID("$FreeBSD: releng/10.0/contrib/libarchive/libarchive/archive_read_data_into_fd.c 232153 2012-02-25 10:58:02Z mm $"); 28272343Sngie 29272343Sngie#ifdef HAVE_SYS_TYPES_H 30272343Sngie#include <sys/types.h> 31272343Sngie#endif 32272343Sngie#ifdef HAVE_ERRNO_H 33272343Sngie#include <errno.h> 34272343Sngie#endif 35272343Sngie#ifdef HAVE_UNISTD_H 36272343Sngie#include <unistd.h> 37272343Sngie#endif 38272343Sngie 39272343Sngie#include "archive.h" 40272343Sngie#include "archive_private.h" 41272343Sngie 42272343Sngie/* Maximum amount of data to write at one time. */ 43272343Sngie#define MAX_WRITE (1024 * 1024) 44272343Sngie 45272343Sngie/* 46272343Sngie * This implementation minimizes copying of data and is sparse-file aware. 47272343Sngie */ 48272343Sngiestatic int 49272343Sngiepad_to(struct archive *a, int fd, int can_lseek, 50272343Sngie size_t nulls_size, const char *nulls, 51272343Sngie int64_t target_offset, int64_t actual_offset) 52272343Sngie{ 53272343Sngie size_t to_write; 54272343Sngie ssize_t bytes_written; 55272343Sngie 56272343Sngie if (can_lseek) { 57272343Sngie actual_offset = lseek(fd, 58272343Sngie target_offset - actual_offset, SEEK_CUR); 59272343Sngie if (actual_offset != target_offset) { 60272343Sngie archive_set_error(a, errno, "Seek error"); 61272343Sngie return (ARCHIVE_FATAL); 62272343Sngie } 63272343Sngie return (ARCHIVE_OK); 64272343Sngie } 65272343Sngie while (target_offset > actual_offset) { 66272343Sngie to_write = nulls_size; 67272343Sngie if (target_offset < actual_offset + (int64_t)nulls_size) 68272343Sngie to_write = (size_t)(target_offset - actual_offset); 69272343Sngie bytes_written = write(fd, nulls, to_write); 70272343Sngie if (bytes_written < 0) { 71272343Sngie archive_set_error(a, errno, "Write error"); 72272343Sngie return (ARCHIVE_FATAL); 73272343Sngie } 74272343Sngie actual_offset += bytes_written; 75272343Sngie } 76272343Sngie return (ARCHIVE_OK); 77272343Sngie} 78272343Sngie 79272343Sngie 80272343Sngieint 81272343Sngiearchive_read_data_into_fd(struct archive *a, int fd) 82272343Sngie{ 83272343Sngie struct stat st; 84272343Sngie int r, r2; 85272343Sngie const void *buff; 86272343Sngie size_t size, bytes_to_write; 87272343Sngie ssize_t bytes_written; 88272343Sngie int64_t target_offset; 89272343Sngie int64_t actual_offset = 0; 90272343Sngie int can_lseek; 91272343Sngie char *nulls = NULL; 92272343Sngie size_t nulls_size = 16384; 93272343Sngie 94272343Sngie archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, 95272343Sngie "archive_read_data_into_fd"); 96272343Sngie 97272343Sngie can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode); 98272343Sngie if (!can_lseek) 99272343Sngie nulls = calloc(1, nulls_size); 100272343Sngie 101272343Sngie while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) == 102272343Sngie ARCHIVE_OK) { 103272343Sngie const char *p = buff; 104272343Sngie if (target_offset > actual_offset) { 105272343Sngie r = pad_to(a, fd, can_lseek, nulls_size, nulls, 106272343Sngie target_offset, actual_offset); 107272343Sngie if (r != ARCHIVE_OK) 108272343Sngie break; 109272343Sngie actual_offset = target_offset; 110272343Sngie } 111272343Sngie while (size > 0) { 112272343Sngie bytes_to_write = size; 113272343Sngie if (bytes_to_write > MAX_WRITE) 114272343Sngie bytes_to_write = MAX_WRITE; 115272343Sngie bytes_written = write(fd, p, bytes_to_write); 116272343Sngie if (bytes_written < 0) { 117272343Sngie archive_set_error(a, errno, "Write error"); 118272343Sngie r = ARCHIVE_FATAL; 119272343Sngie goto cleanup; 120272343Sngie } 121272343Sngie actual_offset += bytes_written; 122272343Sngie p += bytes_written; 123272343Sngie size -= bytes_written; 124272343Sngie } 125272343Sngie } 126272343Sngie 127272343Sngie if (r == ARCHIVE_EOF && target_offset > actual_offset) { 128272343Sngie r2 = pad_to(a, fd, can_lseek, nulls_size, nulls, 129272343Sngie target_offset, actual_offset); 130272343Sngie if (r2 != ARCHIVE_OK) 131272343Sngie r = r2; 132272343Sngie } 133272343Sngie 134272343Sngiecleanup: 135272343Sngie free(nulls); 136272343Sngie if (r != ARCHIVE_EOF) 137272343Sngie return (r); 138272343Sngie return (ARCHIVE_OK); 139272343Sngie} 140272343Sngie