1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#include <errno.h> 30228753Smm#include <stdlib.h> 31228753Smm#include <string.h> 32228753Smm 33228753Smm#include "archive.h" 34228753Smm 35228753Smm/* 36228753Smm * This is a little tricky. I used to allow the 37228753Smm * compression handling layer to fork the compressor, 38228753Smm * which means this write function gets invoked in 39228753Smm * a separate process. That would, of course, make it impossible 40228753Smm * to actually use the data stored into memory here. 41228753Smm * Fortunately, none of the compressors fork today and 42228753Smm * I'm reluctant to use that route in the future but, if 43228753Smm * forking compressors ever do reappear, this will have 44228753Smm * to get a lot more complicated. 45228753Smm */ 46228753Smm 47228753Smmstruct write_memory_data { 48228753Smm size_t used; 49228753Smm size_t size; 50228753Smm size_t * client_size; 51228753Smm unsigned char * buff; 52228753Smm}; 53228753Smm 54228753Smmstatic int memory_write_close(struct archive *, void *); 55228753Smmstatic int memory_write_open(struct archive *, void *); 56228753Smmstatic ssize_t memory_write(struct archive *, void *, const void *buff, size_t); 57228753Smm 58228753Smm/* 59228753Smm * Client provides a pointer to a block of memory to receive 60228753Smm * the data. The 'size' param both tells us the size of the 61228753Smm * client buffer and lets us tell the client the final size. 62228753Smm */ 63228753Smmint 64228753Smmarchive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) 65228753Smm{ 66228753Smm struct write_memory_data *mine; 67228753Smm 68228753Smm mine = (struct write_memory_data *)malloc(sizeof(*mine)); 69228753Smm if (mine == NULL) { 70228753Smm archive_set_error(a, ENOMEM, "No memory"); 71228753Smm return (ARCHIVE_FATAL); 72228753Smm } 73228753Smm memset(mine, 0, sizeof(*mine)); 74228753Smm mine->buff = buff; 75228753Smm mine->size = buffSize; 76228753Smm mine->client_size = used; 77228753Smm return (archive_write_open(a, mine, 78228753Smm memory_write_open, memory_write, memory_write_close)); 79228753Smm} 80228753Smm 81228753Smmstatic int 82228753Smmmemory_write_open(struct archive *a, void *client_data) 83228753Smm{ 84228753Smm struct write_memory_data *mine; 85228753Smm mine = client_data; 86228753Smm mine->used = 0; 87228753Smm if (mine->client_size != NULL) 88228753Smm *mine->client_size = mine->used; 89228753Smm /* Disable padding if it hasn't been set explicitly. */ 90228753Smm if (-1 == archive_write_get_bytes_in_last_block(a)) 91228753Smm archive_write_set_bytes_in_last_block(a, 1); 92228753Smm return (ARCHIVE_OK); 93228753Smm} 94228753Smm 95228753Smm/* 96228753Smm * Copy the data into the client buffer. 97228753Smm * Note that we update mine->client_size on every write. 98228753Smm * In particular, this means the client can follow exactly 99228753Smm * how much has been written into their buffer at any time. 100228753Smm */ 101228753Smmstatic ssize_t 102228753Smmmemory_write(struct archive *a, void *client_data, const void *buff, size_t length) 103228753Smm{ 104228753Smm struct write_memory_data *mine; 105228753Smm mine = client_data; 106228753Smm 107228753Smm if (mine->used + length > mine->size) { 108228753Smm archive_set_error(a, ENOMEM, "Buffer exhausted"); 109228753Smm return (ARCHIVE_FATAL); 110228753Smm } 111228753Smm memcpy(mine->buff + mine->used, buff, length); 112228753Smm mine->used += length; 113228753Smm if (mine->client_size != NULL) 114228753Smm *mine->client_size = mine->used; 115228753Smm return (length); 116228753Smm} 117228753Smm 118228753Smmstatic int 119228753Smmmemory_write_close(struct archive *a, void *client_data) 120228753Smm{ 121228753Smm struct write_memory_data *mine; 122228753Smm (void)a; /* UNUSED */ 123228753Smm mine = client_data; 124228753Smm free(mine); 125228753Smm return (ARCHIVE_OK); 126228753Smm} 127