Home | History | Annotate | Line # | Download | only in test
      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 (skip > 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