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$"); 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 41 struct 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 51 static int memory_read_close(struct archive *, void *); 52 static int memory_read_open(struct archive *, void *); 53 static int64_t memory_read_seek(struct archive *, void *, int64_t request, int whence); 54 static int64_t memory_read_skip(struct archive *, void *, int64_t request); 55 static ssize_t memory_read(struct archive *, void *, const void **buff); 56 static int read_open_memory_internal(struct archive *a, const void *buff, 57 size_t size, size_t read_size, int fullapi); 58 59 60 int 61 read_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 */ 70 int 71 read_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 */ 79 int 80 read_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 85 static int 86 read_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 */ 124 static int 125 memory_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 */ 138 static ssize_t 139 memory_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 */ 164 static int64_t 165 memory_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 */ 182 static int64_t 183 memory_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 */ 213 static int 214 memory_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