read_open_memory.c revision 272461
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 "test.h" 27__FBSDID("$FreeBSD: releng/10.1/contrib/libarchive/libarchive/test/read_open_memory.c 238856 2012-07-28 06:38:44Z mm $"); 28 29#include <errno.h> 30#include <stdlib.h> 31#include <string.h> 32 33/* 34 * Read an archive from a block of memory. 35 * 36 * This is identical to archive_read_open_memory(), except 37 * that it goes out of its way to be a little bit unpleasant, 38 * in order to better test the libarchive internals. 39 */ 40 41struct read_memory_data { 42 unsigned char *start; 43 unsigned char *p; 44 unsigned char *end; 45 size_t read_size; 46 size_t copy_buff_size; 47 size_t copy_buff_offset; 48 char *copy_buff; 49}; 50 51static int memory_read_close(struct archive *, void *); 52static int memory_read_open(struct archive *, void *); 53static int64_t memory_read_seek(struct archive *, void *, int64_t request, int whence); 54static int64_t memory_read_skip(struct archive *, void *, int64_t request); 55static ssize_t memory_read(struct archive *, void *, const void **buff); 56static int read_open_memory_internal(struct archive *a, void *buff, 57 size_t size, size_t read_size, int fullapi); 58 59 60int 61read_open_memory(struct archive *a, void *buff, size_t size, size_t read_size) 62{ 63 return read_open_memory_internal(a, buff, size, read_size, 2); 64} 65 66/* 67 * As above, but don't register any optional part of the API, to verify 68 * that internals work correctly with just the minimal entry points. 69 */ 70int 71read_open_memory_minimal(struct archive *a, void *buff, size_t size, size_t read_size) 72{ 73 return read_open_memory_internal(a, buff, size, read_size, 1); 74} 75 76/* 77 * Include a seek callback as well. 78 */ 79int 80read_open_memory_seek(struct archive *a, void *buff, size_t size, size_t read_size) 81{ 82 return read_open_memory_internal(a, buff, size, read_size, 3); 83} 84 85static int 86read_open_memory_internal(struct archive *a, void *buff, 87 size_t size, size_t read_size, int level) 88{ 89 struct read_memory_data *mine; 90 91 mine = (struct read_memory_data *)malloc(sizeof(*mine)); 92 if (mine == NULL) { 93 archive_set_error(a, ENOMEM, "No memory"); 94 return (ARCHIVE_FATAL); 95 } 96 memset(mine, 0, sizeof(*mine)); 97 mine->start = mine->p = (unsigned char *)buff; 98 mine->end = mine->start + size; 99 mine->read_size = read_size; 100 mine->copy_buff_offset = 32; 101 mine->copy_buff_size = read_size + mine->copy_buff_offset * 2; 102 mine->copy_buff = malloc(mine->copy_buff_size); 103 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 104 105 switch (level) { 106 case 3: 107 archive_read_set_seek_callback(a, memory_read_seek); 108 case 2: 109 archive_read_set_open_callback(a, memory_read_open); 110 archive_read_set_skip_callback(a, memory_read_skip); 111 case 1: 112 archive_read_set_read_callback(a, memory_read); 113 archive_read_set_close_callback(a, memory_read_close); 114 archive_read_set_callback_data(a, mine); 115 } 116 return archive_read_open1(a); 117} 118 119/* 120 * There's nothing to open. 121 */ 122static int 123memory_read_open(struct archive *a, void *client_data) 124{ 125 (void)a; /* UNUSED */ 126 (void)client_data; /* UNUSED */ 127 return (ARCHIVE_OK); 128} 129 130/* 131 * In order to exercise libarchive's internal read-combining logic, 132 * we deliberately copy data for each read to a separate buffer. 133 * That way, code that runs off the end of the provided data 134 * will screw up. 135 */ 136static ssize_t 137memory_read(struct archive *a, void *client_data, const void **buff) 138{ 139 struct read_memory_data *mine = (struct read_memory_data *)client_data; 140 ssize_t size; 141 142 (void)a; /* UNUSED */ 143 size = mine->end - mine->p; 144 if (size < 0) { 145 buff = NULL; 146 return 0; 147 } 148 if ((size_t)size > mine->read_size) 149 size = mine->read_size; 150 else 151 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 152 memcpy(mine->copy_buff + mine->copy_buff_offset, mine->p, size); 153 *buff = mine->copy_buff + mine->copy_buff_offset; 154 155 mine->p += size; 156 return ((ssize_t)size); 157} 158 159/* 160 * How mean can a skip() routine be? Let's try to find out. 161 */ 162static int64_t 163memory_read_skip(struct archive *a, void *client_data, int64_t skip) 164{ 165 struct read_memory_data *mine = (struct read_memory_data *)client_data; 166 167 (void)a; /* UNUSED */ 168 /* We can't skip by more than is available. */ 169 if ((off_t)skip > (off_t)(mine->end - mine->p)) 170 skip = mine->end - mine->p; 171 /* Always do small skips by prime amounts. */ 172 if (skip > 71) 173 skip = 71; 174 mine->p += skip; 175 return (skip); 176} 177 178/* 179 */ 180static int64_t 181memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence) 182{ 183 struct read_memory_data *mine = (struct read_memory_data *)client_data; 184 185 (void)a; /* UNUSED */ 186 switch (whence) { 187 case SEEK_SET: 188 mine->p = mine->start + offset; 189 break; 190 case SEEK_END: 191 mine->p = mine->end + offset; 192 break; 193 case SEEK_CUR: 194 mine->p += offset; 195 break; 196 } 197 if (mine->p < mine->start) { 198 mine->p = mine->start; 199 return ARCHIVE_FAILED; 200 } 201 if (mine->p > mine->end) { 202 mine->p = mine->end; 203 return ARCHIVE_FAILED; 204 } 205 return (mine->p - mine->start); 206} 207 208/* 209 * Close is just cleaning up our one small bit of data. 210 */ 211static int 212memory_read_close(struct archive *a, void *client_data) 213{ 214 struct read_memory_data *mine = (struct read_memory_data *)client_data; 215 (void)a; /* UNUSED */ 216 free(mine->copy_buff); 217 free(mine); 218 return (ARCHIVE_OK); 219} 220