archive_read_open_memory.c revision 229592
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 "archive_platform.h" 27__FBSDID("$FreeBSD: stable/9/contrib/libarchive/libarchive/archive_read_open_memory.c 229592 2012-01-05 12:06:54Z mm $"); 28 29#include <errno.h> 30#include <stdlib.h> 31#include <string.h> 32 33#include "archive.h" 34 35/* 36 * Glue to read an archive from a block of memory. 37 * 38 * This is mostly a huge help in building test harnesses; 39 * test programs can build archives in memory and read them 40 * back again without having to mess with files on disk. 41 */ 42 43struct read_memory_data { 44 unsigned char *buffer; 45 unsigned char *end; 46 ssize_t read_size; 47}; 48 49static int memory_read_close(struct archive *, void *); 50static int memory_read_open(struct archive *, void *); 51#if ARCHIVE_API_VERSION < 2 52static ssize_t memory_read_skip(struct archive *, void *, size_t request); 53#else 54static off_t memory_read_skip(struct archive *, void *, off_t request); 55#endif 56static ssize_t memory_read(struct archive *, void *, const void **buff); 57 58int 59archive_read_open_memory(struct archive *a, void *buff, size_t size) 60{ 61 return archive_read_open_memory2(a, buff, size, size); 62} 63 64/* 65 * Don't use _open_memory2() in production code; the archive_read_open_memory() 66 * version is the one you really want. This is just here so that 67 * test harnesses can exercise block operations inside the library. 68 */ 69int 70archive_read_open_memory2(struct archive *a, void *buff, 71 size_t size, size_t read_size) 72{ 73 struct read_memory_data *mine; 74 75 mine = (struct read_memory_data *)malloc(sizeof(*mine)); 76 if (mine == NULL) { 77 archive_set_error(a, ENOMEM, "No memory"); 78 return (ARCHIVE_FATAL); 79 } 80 memset(mine, 0, sizeof(*mine)); 81 mine->buffer = (unsigned char *)buff; 82 mine->end = mine->buffer + size; 83 mine->read_size = read_size; 84 return (archive_read_open2(a, mine, memory_read_open, 85 memory_read, memory_read_skip, memory_read_close)); 86} 87 88/* 89 * There's nothing to open. 90 */ 91static int 92memory_read_open(struct archive *a, void *client_data) 93{ 94 (void)a; /* UNUSED */ 95 (void)client_data; /* UNUSED */ 96 return (ARCHIVE_OK); 97} 98 99/* 100 * This is scary simple: Just advance a pointer. Limiting 101 * to read_size is not technically necessary, but it exercises 102 * more of the internal logic when used with a small block size 103 * in a test harness. Production use should not specify a block 104 * size; then this is much faster. 105 */ 106static ssize_t 107memory_read(struct archive *a, void *client_data, const void **buff) 108{ 109 struct read_memory_data *mine = (struct read_memory_data *)client_data; 110 ssize_t size; 111 112 (void)a; /* UNUSED */ 113 *buff = mine->buffer; 114 size = mine->end - mine->buffer; 115 if (size > mine->read_size) 116 size = mine->read_size; 117 mine->buffer += size; 118 return (size); 119} 120 121/* 122 * Advancing is just as simple. Again, this is doing more than 123 * necessary in order to better exercise internal code when used 124 * as a test harness. 125 */ 126#if ARCHIVE_API_VERSION < 2 127static ssize_t 128memory_read_skip(struct archive *a, void *client_data, size_t skip) 129#else 130static off_t 131memory_read_skip(struct archive *a, void *client_data, off_t skip) 132#endif 133{ 134 struct read_memory_data *mine = (struct read_memory_data *)client_data; 135 136 (void)a; /* UNUSED */ 137 if ((off_t)skip > (off_t)(mine->end - mine->buffer)) 138 skip = mine->end - mine->buffer; 139 /* Round down to block size. */ 140 skip /= mine->read_size; 141 skip *= mine->read_size; 142 mine->buffer += skip; 143 return (skip); 144} 145 146/* 147 * Close is just cleaning up our one small bit of data. 148 */ 149static int 150memory_read_close(struct archive *a, void *client_data) 151{ 152 struct read_memory_data *mine = (struct read_memory_data *)client_data; 153 (void)a; /* UNUSED */ 154 free(mine); 155 return (ARCHIVE_OK); 156} 157