1/*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "archive_platform.h" 27__FBSDID("$FreeBSD$"); 28 29#include <errno.h> 30#include <stdlib.h> 31#include <string.h> 32 33#include "archive.h" 34 35/* 36 * This is a little tricky. I used to allow the 37 * compression handling layer to fork the compressor, 38 * which means this write function gets invoked in 39 * a separate process. That would, of course, make it impossible 40 * to actually use the data stored into memory here. 41 * Fortunately, none of the compressors fork today and 42 * I'm reluctant to use that route in the future but, if 43 * forking compressors ever do reappear, this will have 44 * to get a lot more complicated. 45 */ 46 47struct write_memory_data { 48 size_t used; 49 size_t size; 50 size_t * client_size; 51 unsigned char * buff; 52}; 53 54static int memory_write_close(struct archive *, void *); 55static int memory_write_open(struct archive *, void *); 56static ssize_t memory_write(struct archive *, void *, const void *buff, size_t); 57 58/* 59 * Client provides a pointer to a block of memory to receive 60 * the data. The 'size' param both tells us the size of the 61 * client buffer and lets us tell the client the final size. 62 */ 63int 64archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) 65{ 66 struct write_memory_data *mine; 67 68 mine = (struct write_memory_data *)malloc(sizeof(*mine)); 69 if (mine == NULL) { 70 archive_set_error(a, ENOMEM, "No memory"); 71 return (ARCHIVE_FATAL); 72 } 73 memset(mine, 0, sizeof(*mine)); 74 mine->buff = buff; 75 mine->size = buffSize; 76 mine->client_size = used; 77 return (archive_write_open(a, mine, 78 memory_write_open, memory_write, memory_write_close)); 79} 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