archive_write_open_memory.c revision 228759
140123Sdes/*- 266830Sobrien * Copyright (c) 2003-2007 Tim Kientzle 3126310Smtm * All rights reserved. 466830Sobrien * 566830Sobrien * Redistribution and use in source and binary forms, with or without 666830Sobrien * modification, are permitted provided that the following conditions 766830Sobrien * are met: 866830Sobrien * 1. Redistributions of source code must retain the above copyright 966830Sobrien * notice, this list of conditions and the following disclaimer. 1066830Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1166830Sobrien * notice, this list of conditions and the following disclaimer in the 1266830Sobrien * documentation and/or other materials provided with the distribution. 1366830Sobrien * 1466830Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1566830Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1666830Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1766830Sobrien * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1866830Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1966830Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2066830Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2166830Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2266830Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2366830Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2466830Sobrien */ 2566830Sobrien 2666830Sobrien#include "archive_platform.h" 2783871Sobrien__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_memory.c,v 1.3 2007/01/09 08:05:56 kientzle Exp $"); 2850472Speter 2966830Sobrien#include <errno.h> 3037Srgrimes#include <stdlib.h> 3137Srgrimes#include <string.h> 3237Srgrimes 3337Srgrimes#include "archive.h" 3437Srgrimes 3537Srgrimes/* 3651231Ssheldonh * This is a little tricky. I used to allow the 3751231Ssheldonh * compression handling layer to fork the compressor, 3851231Ssheldonh * which means this write function gets invoked in 3951231Ssheldonh * a separate process. That would, of course, make it impossible 408460Sjkh * to actually use the data stored into memory here. 4137Srgrimes * Fortunately, none of the compressors fork today and 4237Srgrimes * I'm reluctant to use that route in the future but, if 4337Srgrimes * forking compressors ever do reappear, this will have 44130161Smtm * to get a lot more complicated. 4551231Ssheldonh */ 4637Srgrimes 47130161Smtmstruct write_memory_data { 4837Srgrimes size_t used; 4951231Ssheldonh size_t size; 5092441Scjc size_t * client_size; 5151231Ssheldonh unsigned char * buff; 5237Srgrimes}; 53114492Sdougb 54114492Sdougbstatic int memory_write_close(struct archive *, void *); 55114492Sdougbstatic int memory_write_open(struct archive *, void *); 56114492Sdougbstatic ssize_t memory_write(struct archive *, void *, const void *buff, size_t); 57114492Sdougb 5898189Sgordon/* 59114492Sdougb * Client provides a pointer to a block of memory to receive 60114492Sdougb * the data. The 'size' param both tells us the size of the 61114492Sdougb * client buffer and lets us tell the client the final size. 62114492Sdougb */ 63108200Sdillonint 64114492Sdougbarchive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) 65114492Sdougb{ 6698189Sgordon struct write_memory_data *mine; 6798189Sgordon 68114492Sdougb mine = (struct write_memory_data *)malloc(sizeof(*mine)); 69126743Spjd if (mine == NULL) { 70126743Spjd archive_set_error(a, ENOMEM, "No memory"); 71126743Spjd return (ARCHIVE_FATAL); 7298189Sgordon } 73114492Sdougb memset(mine, 0, sizeof(*mine)); 74114492Sdougb mine->buff = buff; 7588531Ssheldonh mine->size = buffSize; 7651231Ssheldonh mine->client_size = used; 7770109Sdougb return (archive_write_open(a, mine, 7837Srgrimes memory_write_open, memory_write, memory_write_close)); 7937Srgrimes} 80 81static int 82memory_write_open(struct archive *a, void *client_data) 83{ 84 struct write_memory_data *mine; 85 mine = client_data; 86 mine->used = 0; 87 if (mine->client_size != NULL) 88 *mine->client_size = mine->used; 89 /* Disable padding if it hasn't been set explicitly. */ 90 if (-1 == archive_write_get_bytes_in_last_block(a)) 91 archive_write_set_bytes_in_last_block(a, 1); 92 return (ARCHIVE_OK); 93} 94 95/* 96 * Copy the data into the client buffer. 97 * Note that we update mine->client_size on every write. 98 * In particular, this means the client can follow exactly 99 * how much has been written into their buffer at any time. 100 */ 101static ssize_t 102memory_write(struct archive *a, void *client_data, const void *buff, size_t length) 103{ 104 struct write_memory_data *mine; 105 mine = client_data; 106 107 if (mine->used + length > mine->size) { 108 archive_set_error(a, ENOMEM, "Buffer exhausted"); 109 return (ARCHIVE_FATAL); 110 } 111 memcpy(mine->buff + mine->used, buff, length); 112 mine->used += length; 113 if (mine->client_size != NULL) 114 *mine->client_size = mine->used; 115 return (length); 116} 117 118static int 119memory_write_close(struct archive *a, void *client_data) 120{ 121 struct write_memory_data *mine; 122 (void)a; /* UNUSED */ 123 mine = client_data; 124 free(mine); 125 return (ARCHIVE_OK); 126} 127