read_open_memory.c revision 328827
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: stable/11/contrib/libarchive/libarchive/test/read_open_memory.c 328827 2018-02-03 02:17:04Z 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 const unsigned char *start; 43 const unsigned char *p; 44 const 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, const void *buff, 57 size_t size, size_t read_size, int fullapi); 58 59 60int 61read_open_memory(struct archive *a, const 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, const 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, const 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, const void *buff, 87 size_t size, size_t read_size, int level) 88{ 89 struct read_memory_data *mine = NULL; 90 91 switch (level) { 92 case 3: 93 archive_read_set_seek_callback(a, memory_read_seek); 94 __LA_FALLTHROUGH; 95 case 2: 96 archive_read_set_open_callback(a, memory_read_open); 97 archive_read_set_skip_callback(a, memory_read_skip); 98 __LA_FALLTHROUGH; 99 case 1: 100 mine = malloc(sizeof(*mine)); 101 if (mine == NULL) { 102 archive_set_error(a, ENOMEM, "No memory"); 103 return (ARCHIVE_FATAL); 104 } 105 memset(mine, 0, sizeof(*mine)); 106 mine->start = mine->p = (const unsigned char *)buff; 107 mine->end = mine->start + size; 108 mine->read_size = read_size; 109 mine->copy_buff_offset = 32; 110 mine->copy_buff_size = read_size + mine->copy_buff_offset * 2; 111 mine->copy_buff = malloc(mine->copy_buff_size); 112 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 113 114 archive_read_set_read_callback(a, memory_read); 115 archive_read_set_close_callback(a, memory_read_close); 116 archive_read_set_callback_data(a, mine); 117 } 118 return archive_read_open1(a); 119} 120 121/* 122 * There's nothing to open. 123 */ 124static int 125memory_read_open(struct archive *a, void *client_data) 126{ 127 (void)a; /* UNUSED */ 128 (void)client_data; /* UNUSED */ 129 return (ARCHIVE_OK); 130} 131 132/* 133 * In order to exercise libarchive's internal read-combining logic, 134 * we deliberately copy data for each read to a separate buffer. 135 * That way, code that runs off the end of the provided data 136 * will screw up. 137 */ 138static ssize_t 139memory_read(struct archive *a, void *client_data, const void **buff) 140{ 141 struct read_memory_data *mine = (struct read_memory_data *)client_data; 142 ssize_t size; 143 144 (void)a; /* UNUSED */ 145 size = mine->end - mine->p; 146 if (size < 0) { 147 buff = NULL; 148 return 0; 149 } 150 if ((size_t)size > mine->read_size) 151 size = mine->read_size; 152 else 153 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 154 memcpy(mine->copy_buff + mine->copy_buff_offset, mine->p, size); 155 *buff = mine->copy_buff + mine->copy_buff_offset; 156 157 mine->p += size; 158 return ((ssize_t)size); 159} 160 161/* 162 * How mean can a skip() routine be? Let's try to find out. 163 */ 164static int64_t 165memory_read_skip(struct archive *a, void *client_data, int64_t skip) 166{ 167 struct read_memory_data *mine = (struct read_memory_data *)client_data; 168 169 (void)a; /* UNUSED */ 170 /* We can't skip by more than is available. */ 171 if ((off_t)skip > (off_t)(mine->end - mine->p)) 172 skip = mine->end - mine->p; 173 /* Always do small skips by prime amounts. */ 174 if (skip > 71) 175 skip = 71; 176 mine->p += skip; 177 return (skip); 178} 179 180/* 181 */ 182static int64_t 183memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence) 184{ 185 struct read_memory_data *mine = (struct read_memory_data *)client_data; 186 187 (void)a; /* UNUSED */ 188 switch (whence) { 189 case SEEK_SET: 190 mine->p = mine->start + offset; 191 break; 192 case SEEK_END: 193 mine->p = mine->end + offset; 194 break; 195 case SEEK_CUR: 196 mine->p += offset; 197 break; 198 } 199 if (mine->p < mine->start) { 200 mine->p = mine->start; 201 return ARCHIVE_FAILED; 202 } 203 if (mine->p > mine->end) { 204 mine->p = mine->end; 205 return ARCHIVE_FAILED; 206 } 207 return (mine->p - mine->start); 208} 209 210/* 211 * Close is just cleaning up our one small bit of data. 212 */ 213static int 214memory_read_close(struct archive *a, void *client_data) 215{ 216 struct read_memory_data *mine = (struct read_memory_data *)client_data; 217 (void)a; /* UNUSED */ 218 if (mine != NULL) 219 free(mine->copy_buff); 220 free(mine); 221 return (ARCHIVE_OK); 222} 223