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: head/lib/libarchive/test/read_open_memory.c 191183 2009-04-17 01:06:31Z kientzle $"); 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 *buffer; 43 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 50static int memory_read_close(struct archive *, void *); 51static int memory_read_open(struct archive *, void *); 52static off_t memory_read_skip(struct archive *, void *, off_t request); 53static ssize_t memory_read(struct archive *, void *, const void **buff); 54static int read_open_memory_internal(struct archive *a, void *buff, 55 size_t size, size_t read_size, int fullapi); 56 57 58int 59read_open_memory(struct archive *a, void *buff, size_t size, size_t read_size) 60{ 61 return read_open_memory_internal(a, buff, size, read_size, 1); 62} 63 64/* 65 * As above, but don't register any optional part of the API, to verify 66 * that internals work correctly with just the minimal entry points. 67 */ 68int 69read_open_memory2(struct archive *a, void *buff, size_t size, size_t read_size) 70{ 71 return read_open_memory_internal(a, buff, size, read_size, 0); 72} 73 74static int 75read_open_memory_internal(struct archive *a, void *buff, 76 size_t size, size_t read_size, int fullapi) 77{ 78 struct read_memory_data *mine; 79 80 mine = (struct read_memory_data *)malloc(sizeof(*mine)); 81 if (mine == NULL) { 82 archive_set_error(a, ENOMEM, "No memory"); 83 return (ARCHIVE_FATAL); 84 } 85 memset(mine, 0, sizeof(*mine)); 86 mine->buffer = (unsigned char *)buff; 87 mine->end = mine->buffer + size; 88 mine->read_size = read_size; 89 mine->copy_buff_offset = 32; 90 mine->copy_buff_size = read_size + mine->copy_buff_offset * 2; 91 mine->copy_buff = malloc(mine->copy_buff_size); 92 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 93 if (fullapi) 94 return (archive_read_open2(a, mine, memory_read_open, 95 memory_read, memory_read_skip, memory_read_close)); 96 else 97 return (archive_read_open2(a, mine, NULL, 98 memory_read, NULL, memory_read_close)); 99} 100 101/* 102 * There's nothing to open. 103 */ 104static int 105memory_read_open(struct archive *a, void *client_data) 106{ 107 (void)a; /* UNUSED */ 108 (void)client_data; /* UNUSED */ 109 return (ARCHIVE_OK); 110} 111 112/* 113 * In order to exercise libarchive's internal read-combining logic, 114 * we deliberately copy data for each read to a separate buffer. 115 * That way, code that runs off the end of the provided data 116 * will screw up. 117 */ 118static ssize_t 119memory_read(struct archive *a, void *client_data, const void **buff) 120{ 121 struct read_memory_data *mine = (struct read_memory_data *)client_data; 122 size_t size; 123 124 (void)a; /* UNUSED */ 125 size = mine->end - mine->buffer; 126 if (size > mine->read_size) 127 size = mine->read_size; 128 else 129 memset(mine->copy_buff, 0xA5, mine->copy_buff_size); 130 memcpy(mine->copy_buff + mine->copy_buff_offset, mine->buffer, size); 131 *buff = mine->copy_buff + mine->copy_buff_offset; 132 133 mine->buffer += size; 134 return ((ssize_t)size); 135} 136 137/* 138 * How mean can a skip() routine be? Let's try to find out. 139 */ 140static off_t 141memory_read_skip(struct archive *a, void *client_data, off_t skip) 142{ 143 struct read_memory_data *mine = (struct read_memory_data *)client_data; 144 145 (void)a; /* UNUSED */ 146 /* We can't skip by more than is available. */ 147 if ((off_t)skip > (off_t)(mine->end - mine->buffer)) 148 skip = mine->end - mine->buffer; 149 /* Always do small skips by prime amounts. */ 150 if (skip > 71) 151 skip = 71; 152 mine->buffer += skip; 153 return (skip); 154} 155 156/* 157 * Close is just cleaning up our one small bit of data. 158 */ 159static int 160memory_read_close(struct archive *a, void *client_data) 161{ 162 struct read_memory_data *mine = (struct read_memory_data *)client_data; 163 (void)a; /* UNUSED */ 164 free(mine->copy_buff); 165 free(mine); 166 return (ARCHIVE_OK); 167} 168