1caf54c4fSMartin Matuska /*-
2caf54c4fSMartin Matuska  * Copyright (c) 2003-2007 Tim Kientzle
3caf54c4fSMartin Matuska  * All rights reserved.
4caf54c4fSMartin Matuska  *
5caf54c4fSMartin Matuska  * Redistribution and use in source and binary forms, with or without
6caf54c4fSMartin Matuska  * modification, are permitted provided that the following conditions
7caf54c4fSMartin Matuska  * are met:
8caf54c4fSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
9caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
10caf54c4fSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
11caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
12caf54c4fSMartin Matuska  *    documentation and/or other materials provided with the distribution.
13caf54c4fSMartin Matuska  *
14caf54c4fSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15caf54c4fSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16caf54c4fSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17caf54c4fSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18caf54c4fSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19caf54c4fSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20caf54c4fSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21caf54c4fSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22caf54c4fSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23caf54c4fSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24caf54c4fSMartin Matuska  */
25caf54c4fSMartin Matuska 
26caf54c4fSMartin Matuska #include "test.h"
27caf54c4fSMartin Matuska 
28caf54c4fSMartin Matuska #include <errno.h>
29caf54c4fSMartin Matuska #include <stdlib.h>
30caf54c4fSMartin Matuska #include <string.h>
31caf54c4fSMartin Matuska 
32caf54c4fSMartin Matuska /*
33caf54c4fSMartin Matuska  * Read an archive from a block of memory.
34caf54c4fSMartin Matuska  *
35caf54c4fSMartin Matuska  * This is identical to archive_read_open_memory(), except
36caf54c4fSMartin Matuska  * that it goes out of its way to be a little bit unpleasant,
37caf54c4fSMartin Matuska  * in order to better test the libarchive internals.
38caf54c4fSMartin Matuska  */
39caf54c4fSMartin Matuska 
40caf54c4fSMartin Matuska struct read_memory_data {
41cdf63a70SMartin Matuska 	const unsigned char	*start;
42cdf63a70SMartin Matuska 	const unsigned char	*p;
43cdf63a70SMartin Matuska 	const unsigned char	*end;
44caf54c4fSMartin Matuska 	size_t	 read_size;
45caf54c4fSMartin Matuska 	size_t copy_buff_size;
46caf54c4fSMartin Matuska 	size_t copy_buff_offset;
47caf54c4fSMartin Matuska 	char *copy_buff;
48caf54c4fSMartin Matuska };
49caf54c4fSMartin Matuska 
50caf54c4fSMartin Matuska static int	memory_read_close(struct archive *, void *);
51caf54c4fSMartin Matuska static int	memory_read_open(struct archive *, void *);
526c95142eSMartin Matuska static int64_t	memory_read_seek(struct archive *, void *, int64_t request, int whence);
536c95142eSMartin Matuska static int64_t	memory_read_skip(struct archive *, void *, int64_t request);
54caf54c4fSMartin Matuska static ssize_t	memory_read(struct archive *, void *, const void **buff);
55cdf63a70SMartin Matuska static int	read_open_memory_internal(struct archive *a, const void *buff,
56caf54c4fSMartin Matuska     size_t size, size_t read_size, int fullapi);
57caf54c4fSMartin Matuska 
58caf54c4fSMartin Matuska 
59caf54c4fSMartin Matuska int
read_open_memory(struct archive * a,const void * buff,size_t size,size_t read_size)60cdf63a70SMartin Matuska read_open_memory(struct archive *a, const void *buff, size_t size, size_t read_size)
61caf54c4fSMartin Matuska {
626c95142eSMartin Matuska 	return read_open_memory_internal(a, buff, size, read_size, 2);
63caf54c4fSMartin Matuska }
64caf54c4fSMartin Matuska 
65caf54c4fSMartin Matuska /*
66caf54c4fSMartin Matuska  * As above, but don't register any optional part of the API, to verify
67caf54c4fSMartin Matuska  * that internals work correctly with just the minimal entry points.
68caf54c4fSMartin Matuska  */
69caf54c4fSMartin Matuska int
read_open_memory_minimal(struct archive * a,const void * buff,size_t size,size_t read_size)70cdf63a70SMartin Matuska read_open_memory_minimal(struct archive *a, const void *buff, size_t size, size_t read_size)
71caf54c4fSMartin Matuska {
726c95142eSMartin Matuska 	return read_open_memory_internal(a, buff, size, read_size, 1);
736c95142eSMartin Matuska }
746c95142eSMartin Matuska 
756c95142eSMartin Matuska /*
766c95142eSMartin Matuska  * Include a seek callback as well.
776c95142eSMartin Matuska  */
786c95142eSMartin Matuska int
read_open_memory_seek(struct archive * a,const void * buff,size_t size,size_t read_size)79cdf63a70SMartin Matuska read_open_memory_seek(struct archive *a, const void *buff, size_t size, size_t read_size)
806c95142eSMartin Matuska {
816c95142eSMartin Matuska 	return read_open_memory_internal(a, buff, size, read_size, 3);
82caf54c4fSMartin Matuska }
83caf54c4fSMartin Matuska 
84caf54c4fSMartin Matuska static int
read_open_memory_internal(struct archive * a,const void * buff,size_t size,size_t read_size,int level)85cdf63a70SMartin Matuska read_open_memory_internal(struct archive *a, const void *buff,
866c95142eSMartin Matuska     size_t size, size_t read_size, int level)
87caf54c4fSMartin Matuska {
8863ecfce8SEnji Cooper 	struct read_memory_data *mine = NULL;
89caf54c4fSMartin Matuska 
9063ecfce8SEnji Cooper 	switch (level) {
9163ecfce8SEnji Cooper 	case 3:
9263ecfce8SEnji Cooper 		archive_read_set_seek_callback(a, memory_read_seek);
93a2a3407cSMartin Matuska 		__LA_FALLTHROUGH;
9463ecfce8SEnji Cooper 	case 2:
9563ecfce8SEnji Cooper 		archive_read_set_open_callback(a, memory_read_open);
9663ecfce8SEnji Cooper 		archive_read_set_skip_callback(a, memory_read_skip);
97a2a3407cSMartin Matuska 		__LA_FALLTHROUGH;
9863ecfce8SEnji Cooper 	case 1:
9963ecfce8SEnji Cooper 		mine = malloc(sizeof(*mine));
100caf54c4fSMartin Matuska 		if (mine == NULL) {
101caf54c4fSMartin Matuska 			archive_set_error(a, ENOMEM, "No memory");
102caf54c4fSMartin Matuska 			return (ARCHIVE_FATAL);
103caf54c4fSMartin Matuska 		}
104caf54c4fSMartin Matuska 		memset(mine, 0, sizeof(*mine));
105cdf63a70SMartin Matuska 		mine->start = mine->p = (const unsigned char *)buff;
1066c95142eSMartin Matuska 		mine->end = mine->start + size;
107caf54c4fSMartin Matuska 		mine->read_size = read_size;
108caf54c4fSMartin Matuska 		mine->copy_buff_offset = 32;
109caf54c4fSMartin Matuska 		mine->copy_buff_size = read_size + mine->copy_buff_offset * 2;
110caf54c4fSMartin Matuska 		mine->copy_buff = malloc(mine->copy_buff_size);
111caf54c4fSMartin Matuska 		memset(mine->copy_buff, 0xA5, mine->copy_buff_size);
1126c95142eSMartin Matuska 
1136c95142eSMartin Matuska 		archive_read_set_read_callback(a, memory_read);
1146c95142eSMartin Matuska 		archive_read_set_close_callback(a, memory_read_close);
1156c95142eSMartin Matuska 		archive_read_set_callback_data(a, mine);
1166c95142eSMartin Matuska 	}
1176c95142eSMartin Matuska 	return archive_read_open1(a);
118caf54c4fSMartin Matuska }
119caf54c4fSMartin Matuska 
120caf54c4fSMartin Matuska /*
121caf54c4fSMartin Matuska  * There's nothing to open.
122caf54c4fSMartin Matuska  */
123caf54c4fSMartin Matuska static int
memory_read_open(struct archive * a,void * client_data)124caf54c4fSMartin Matuska memory_read_open(struct archive *a, void *client_data)
125caf54c4fSMartin Matuska {
126caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
127caf54c4fSMartin Matuska 	(void)client_data; /* UNUSED */
128caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
129caf54c4fSMartin Matuska }
130caf54c4fSMartin Matuska 
131caf54c4fSMartin Matuska /*
132caf54c4fSMartin Matuska  * In order to exercise libarchive's internal read-combining logic,
133caf54c4fSMartin Matuska  * we deliberately copy data for each read to a separate buffer.
134caf54c4fSMartin Matuska  * That way, code that runs off the end of the provided data
135caf54c4fSMartin Matuska  * will screw up.
136caf54c4fSMartin Matuska  */
137caf54c4fSMartin Matuska static ssize_t
memory_read(struct archive * a,void * client_data,const void ** buff)138caf54c4fSMartin Matuska memory_read(struct archive *a, void *client_data, const void **buff)
139caf54c4fSMartin Matuska {
140caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
1416c95142eSMartin Matuska 	ssize_t size;
142caf54c4fSMartin Matuska 
143caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
1446c95142eSMartin Matuska 	size = mine->end - mine->p;
1456c95142eSMartin Matuska 	if (size < 0) {
1466c95142eSMartin Matuska 		buff = NULL;
1476c95142eSMartin Matuska 		return 0;
1486c95142eSMartin Matuska 	}
1496c95142eSMartin Matuska 	if ((size_t)size > mine->read_size)
150caf54c4fSMartin Matuska 		size = mine->read_size;
151caf54c4fSMartin Matuska 	else
152caf54c4fSMartin Matuska 		memset(mine->copy_buff, 0xA5, mine->copy_buff_size);
1536c95142eSMartin Matuska 	memcpy(mine->copy_buff + mine->copy_buff_offset, mine->p, size);
154caf54c4fSMartin Matuska 	*buff = mine->copy_buff + mine->copy_buff_offset;
155caf54c4fSMartin Matuska 
1566c95142eSMartin Matuska         mine->p += size;
157caf54c4fSMartin Matuska 	return ((ssize_t)size);
158caf54c4fSMartin Matuska }
159caf54c4fSMartin Matuska 
160caf54c4fSMartin Matuska /*
161caf54c4fSMartin Matuska  * How mean can a skip() routine be?  Let's try to find out.
162caf54c4fSMartin Matuska  */
1636c95142eSMartin Matuska static int64_t
memory_read_skip(struct archive * a,void * client_data,int64_t skip)1646c95142eSMartin Matuska memory_read_skip(struct archive *a, void *client_data, int64_t skip)
165caf54c4fSMartin Matuska {
166caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
167caf54c4fSMartin Matuska 
168caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
169caf54c4fSMartin Matuska 	/* We can't skip by more than is available. */
1706c95142eSMartin Matuska 	if ((off_t)skip > (off_t)(mine->end - mine->p))
1716c95142eSMartin Matuska 		skip = mine->end - mine->p;
172caf54c4fSMartin Matuska 	/* Always do small skips by prime amounts. */
173caf54c4fSMartin Matuska 	if (skip > 71)
174caf54c4fSMartin Matuska 		skip = 71;
1756c95142eSMartin Matuska 	mine->p += skip;
176caf54c4fSMartin Matuska 	return (skip);
177caf54c4fSMartin Matuska }
178caf54c4fSMartin Matuska 
179caf54c4fSMartin Matuska /*
1806c95142eSMartin Matuska  */
1816c95142eSMartin Matuska static int64_t
memory_read_seek(struct archive * a,void * client_data,int64_t offset,int whence)1826c95142eSMartin Matuska memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
1836c95142eSMartin Matuska {
1846c95142eSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
1856c95142eSMartin Matuska 
1866c95142eSMartin Matuska 	(void)a; /* UNUSED */
1876c95142eSMartin Matuska 	switch (whence) {
1886c95142eSMartin Matuska 	case SEEK_SET:
1896c95142eSMartin Matuska 		mine->p = mine->start + offset;
1906c95142eSMartin Matuska 		break;
1916c95142eSMartin Matuska 	case SEEK_END:
1926c95142eSMartin Matuska 		mine->p = mine->end + offset;
1936c95142eSMartin Matuska 		break;
1946c95142eSMartin Matuska 	case SEEK_CUR:
1956c95142eSMartin Matuska 		mine->p += offset;
1966c95142eSMartin Matuska 		break;
1976c95142eSMartin Matuska 	}
1986c95142eSMartin Matuska 	if (mine->p < mine->start) {
1996c95142eSMartin Matuska 		mine->p = mine->start;
2006c95142eSMartin Matuska 		return ARCHIVE_FAILED;
2016c95142eSMartin Matuska 	}
2026c95142eSMartin Matuska 	if (mine->p > mine->end) {
2036c95142eSMartin Matuska 		mine->p = mine->end;
2046c95142eSMartin Matuska 		return ARCHIVE_FAILED;
2056c95142eSMartin Matuska 	}
2066c95142eSMartin Matuska 	return (mine->p - mine->start);
2076c95142eSMartin Matuska }
2086c95142eSMartin Matuska 
2096c95142eSMartin Matuska /*
210caf54c4fSMartin Matuska  * Close is just cleaning up our one small bit of data.
211caf54c4fSMartin Matuska  */
212caf54c4fSMartin Matuska static int
memory_read_close(struct archive * a,void * client_data)213caf54c4fSMartin Matuska memory_read_close(struct archive *a, void *client_data)
214caf54c4fSMartin Matuska {
215caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
216caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
21763ecfce8SEnji Cooper 	if (mine != NULL)
218caf54c4fSMartin Matuska 		free(mine->copy_buff);
219caf54c4fSMartin Matuska 	free(mine);
220caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
221caf54c4fSMartin Matuska }
222