1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27228763Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#include <errno.h> 30228753Smm#include <stdlib.h> 31228753Smm#include <string.h> 32228753Smm 33228753Smm#include "archive.h" 34228753Smm 35228753Smm/* 36228753Smm * Glue to read an archive from a block of memory. 37228753Smm * 38228753Smm * This is mostly a huge help in building test harnesses; 39228753Smm * test programs can build archives in memory and read them 40228753Smm * back again without having to mess with files on disk. 41228753Smm */ 42228753Smm 43228753Smmstruct read_memory_data { 44232153Smm unsigned char *start; 45232153Smm unsigned char *p; 46228753Smm unsigned char *end; 47228753Smm ssize_t read_size; 48228753Smm}; 49228753Smm 50228753Smmstatic int memory_read_close(struct archive *, void *); 51228753Smmstatic int memory_read_open(struct archive *, void *); 52232153Smmstatic int64_t memory_read_seek(struct archive *, void *, int64_t offset, int whence); 53232153Smmstatic int64_t memory_read_skip(struct archive *, void *, int64_t request); 54228753Smmstatic ssize_t memory_read(struct archive *, void *, const void **buff); 55228753Smm 56228753Smmint 57228753Smmarchive_read_open_memory(struct archive *a, void *buff, size_t size) 58228753Smm{ 59228753Smm return archive_read_open_memory2(a, buff, size, size); 60228753Smm} 61228753Smm 62228753Smm/* 63228753Smm * Don't use _open_memory2() in production code; the archive_read_open_memory() 64228753Smm * version is the one you really want. This is just here so that 65228753Smm * test harnesses can exercise block operations inside the library. 66228753Smm */ 67228753Smmint 68228753Smmarchive_read_open_memory2(struct archive *a, void *buff, 69228753Smm size_t size, size_t read_size) 70228753Smm{ 71228753Smm struct read_memory_data *mine; 72228753Smm 73228753Smm mine = (struct read_memory_data *)malloc(sizeof(*mine)); 74228753Smm if (mine == NULL) { 75228753Smm archive_set_error(a, ENOMEM, "No memory"); 76228753Smm return (ARCHIVE_FATAL); 77228753Smm } 78228753Smm memset(mine, 0, sizeof(*mine)); 79232153Smm mine->start = mine->p = (unsigned char *)buff; 80232153Smm mine->end = mine->start + size; 81228753Smm mine->read_size = read_size; 82232153Smm archive_read_set_open_callback(a, memory_read_open); 83232153Smm archive_read_set_read_callback(a, memory_read); 84232153Smm archive_read_set_seek_callback(a, memory_read_seek); 85232153Smm archive_read_set_skip_callback(a, memory_read_skip); 86232153Smm archive_read_set_close_callback(a, memory_read_close); 87232153Smm archive_read_set_callback_data(a, mine); 88232153Smm return (archive_read_open1(a)); 89228753Smm} 90228753Smm 91228753Smm/* 92228753Smm * There's nothing to open. 93228753Smm */ 94228753Smmstatic int 95228753Smmmemory_read_open(struct archive *a, void *client_data) 96228753Smm{ 97228753Smm (void)a; /* UNUSED */ 98228753Smm (void)client_data; /* UNUSED */ 99228753Smm return (ARCHIVE_OK); 100228753Smm} 101228753Smm 102228753Smm/* 103228753Smm * This is scary simple: Just advance a pointer. Limiting 104228753Smm * to read_size is not technically necessary, but it exercises 105228753Smm * more of the internal logic when used with a small block size 106228753Smm * in a test harness. Production use should not specify a block 107228753Smm * size; then this is much faster. 108228753Smm */ 109228753Smmstatic ssize_t 110228753Smmmemory_read(struct archive *a, void *client_data, const void **buff) 111228753Smm{ 112228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 113228753Smm ssize_t size; 114228753Smm 115228753Smm (void)a; /* UNUSED */ 116232153Smm *buff = mine->p; 117232153Smm size = mine->end - mine->p; 118228753Smm if (size > mine->read_size) 119228753Smm size = mine->read_size; 120232153Smm mine->p += size; 121228753Smm return (size); 122228753Smm} 123228753Smm 124228753Smm/* 125228753Smm * Advancing is just as simple. Again, this is doing more than 126228753Smm * necessary in order to better exercise internal code when used 127228753Smm * as a test harness. 128228753Smm */ 129232153Smmstatic int64_t 130232153Smmmemory_read_skip(struct archive *a, void *client_data, int64_t skip) 131228753Smm{ 132228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 133228753Smm 134228753Smm (void)a; /* UNUSED */ 135232153Smm if ((int64_t)skip > (int64_t)(mine->end - mine->p)) 136232153Smm skip = mine->end - mine->p; 137228753Smm /* Round down to block size. */ 138228753Smm skip /= mine->read_size; 139228753Smm skip *= mine->read_size; 140232153Smm mine->p += skip; 141228753Smm return (skip); 142228753Smm} 143228753Smm 144228753Smm/* 145232153Smm * Seeking. 146232153Smm */ 147232153Smmstatic int64_t 148232153Smmmemory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence) 149232153Smm{ 150232153Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 151232153Smm 152232153Smm (void)a; /* UNUSED */ 153232153Smm switch (whence) { 154232153Smm case SEEK_SET: 155232153Smm mine->p = mine->start + offset; 156232153Smm break; 157232153Smm case SEEK_CUR: 158232153Smm mine->p += offset; 159232153Smm break; 160232153Smm case SEEK_END: 161232153Smm mine->p = mine->end + offset; 162232153Smm break; 163232153Smm default: 164232153Smm return ARCHIVE_FATAL; 165232153Smm } 166232153Smm if (mine->p < mine->start) { 167232153Smm mine->p = mine->start; 168232153Smm return ARCHIVE_FAILED; 169232153Smm } 170232153Smm if (mine->p > mine->end) { 171232153Smm mine->p = mine->end; 172232153Smm return ARCHIVE_FAILED; 173232153Smm } 174232153Smm return (mine->p - mine->start); 175232153Smm} 176232153Smm 177232153Smm/* 178228753Smm * Close is just cleaning up our one small bit of data. 179228753Smm */ 180228753Smmstatic int 181228753Smmmemory_read_close(struct archive *a, void *client_data) 182228753Smm{ 183228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 184228753Smm (void)a; /* UNUSED */ 185228753Smm free(mine); 186228753Smm return (ARCHIVE_OK); 187228753Smm} 188