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