xref: /freebsd/contrib/libarchive/libarchive/archive_read_open_memory.c (revision bd66c1b43e33540205dbc1187c2f2a15c58b57ba)
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 "archive_platform.h"
27caf54c4fSMartin Matuska 
28caf54c4fSMartin Matuska #include <errno.h>
29caf54c4fSMartin Matuska #include <stdlib.h>
30caf54c4fSMartin Matuska #include <string.h>
31caf54c4fSMartin Matuska 
32caf54c4fSMartin Matuska #include "archive.h"
33caf54c4fSMartin Matuska 
34caf54c4fSMartin Matuska /*
35caf54c4fSMartin Matuska  * Glue to read an archive from a block of memory.
36caf54c4fSMartin Matuska  *
37caf54c4fSMartin Matuska  * This is mostly a huge help in building test harnesses;
38caf54c4fSMartin Matuska  * test programs can build archives in memory and read them
39caf54c4fSMartin Matuska  * back again without having to mess with files on disk.
40caf54c4fSMartin Matuska  */
41caf54c4fSMartin Matuska 
42caf54c4fSMartin Matuska struct read_memory_data {
43cdf63a70SMartin Matuska 	const unsigned char	*start;
44cdf63a70SMartin Matuska 	const unsigned char	*p;
45cdf63a70SMartin Matuska 	const unsigned char	*end;
46caf54c4fSMartin Matuska 	ssize_t	 read_size;
47caf54c4fSMartin Matuska };
48caf54c4fSMartin Matuska 
49caf54c4fSMartin Matuska static int	memory_read_close(struct archive *, void *);
50caf54c4fSMartin Matuska static int	memory_read_open(struct archive *, void *);
516c95142eSMartin Matuska static int64_t	memory_read_seek(struct archive *, void *, int64_t offset, int whence);
526c95142eSMartin Matuska static int64_t	memory_read_skip(struct archive *, void *, int64_t request);
53caf54c4fSMartin Matuska static ssize_t	memory_read(struct archive *, void *, const void **buff);
54caf54c4fSMartin Matuska 
55caf54c4fSMartin Matuska int
archive_read_open_memory(struct archive * a,const void * buff,size_t size)56cdf63a70SMartin Matuska archive_read_open_memory(struct archive *a, const void *buff, size_t size)
57caf54c4fSMartin Matuska {
58caf54c4fSMartin Matuska 	return archive_read_open_memory2(a, buff, size, size);
59caf54c4fSMartin Matuska }
60caf54c4fSMartin Matuska 
61caf54c4fSMartin Matuska /*
62caf54c4fSMartin Matuska  * Don't use _open_memory2() in production code; the archive_read_open_memory()
63caf54c4fSMartin Matuska  * version is the one you really want.  This is just here so that
64caf54c4fSMartin Matuska  * test harnesses can exercise block operations inside the library.
65caf54c4fSMartin Matuska  */
66caf54c4fSMartin Matuska int
archive_read_open_memory2(struct archive * a,const void * buff,size_t size,size_t read_size)67cdf63a70SMartin Matuska archive_read_open_memory2(struct archive *a, const void *buff,
68caf54c4fSMartin Matuska     size_t size, size_t read_size)
69caf54c4fSMartin Matuska {
70caf54c4fSMartin Matuska 	struct read_memory_data *mine;
71caf54c4fSMartin Matuska 
72*bd66c1b4SMartin Matuska 	mine = calloc(1, sizeof(*mine));
73caf54c4fSMartin Matuska 	if (mine == NULL) {
74caf54c4fSMartin Matuska 		archive_set_error(a, ENOMEM, "No memory");
75caf54c4fSMartin Matuska 		return (ARCHIVE_FATAL);
76caf54c4fSMartin Matuska 	}
77cdf63a70SMartin Matuska 	mine->start = mine->p = (const unsigned char *)buff;
786c95142eSMartin Matuska 	mine->end = mine->start + size;
79caf54c4fSMartin Matuska 	mine->read_size = read_size;
806c95142eSMartin Matuska 	archive_read_set_open_callback(a, memory_read_open);
816c95142eSMartin Matuska 	archive_read_set_read_callback(a, memory_read);
826c95142eSMartin Matuska 	archive_read_set_seek_callback(a, memory_read_seek);
836c95142eSMartin Matuska 	archive_read_set_skip_callback(a, memory_read_skip);
846c95142eSMartin Matuska 	archive_read_set_close_callback(a, memory_read_close);
856c95142eSMartin Matuska 	archive_read_set_callback_data(a, mine);
866c95142eSMartin Matuska 	return (archive_read_open1(a));
87caf54c4fSMartin Matuska }
88caf54c4fSMartin Matuska 
89caf54c4fSMartin Matuska /*
90caf54c4fSMartin Matuska  * There's nothing to open.
91caf54c4fSMartin Matuska  */
92caf54c4fSMartin Matuska static int
memory_read_open(struct archive * a,void * client_data)93caf54c4fSMartin Matuska memory_read_open(struct archive *a, void *client_data)
94caf54c4fSMartin Matuska {
95caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
96caf54c4fSMartin Matuska 	(void)client_data; /* UNUSED */
97caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
98caf54c4fSMartin Matuska }
99caf54c4fSMartin Matuska 
100caf54c4fSMartin Matuska /*
101caf54c4fSMartin Matuska  * This is scary simple:  Just advance a pointer.  Limiting
102caf54c4fSMartin Matuska  * to read_size is not technically necessary, but it exercises
103caf54c4fSMartin Matuska  * more of the internal logic when used with a small block size
104caf54c4fSMartin Matuska  * in a test harness.  Production use should not specify a block
105caf54c4fSMartin Matuska  * size; then this is much faster.
106caf54c4fSMartin Matuska  */
107caf54c4fSMartin Matuska static ssize_t
memory_read(struct archive * a,void * client_data,const void ** buff)108caf54c4fSMartin Matuska memory_read(struct archive *a, void *client_data, const void **buff)
109caf54c4fSMartin Matuska {
110caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
111caf54c4fSMartin Matuska 	ssize_t size;
112caf54c4fSMartin Matuska 
113caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
1146c95142eSMartin Matuska 	*buff = mine->p;
1156c95142eSMartin Matuska 	size = mine->end - mine->p;
116caf54c4fSMartin Matuska 	if (size > mine->read_size)
117caf54c4fSMartin Matuska 		size = mine->read_size;
1186c95142eSMartin Matuska         mine->p += size;
119caf54c4fSMartin Matuska 	return (size);
120caf54c4fSMartin Matuska }
121caf54c4fSMartin Matuska 
122caf54c4fSMartin Matuska /*
123caf54c4fSMartin Matuska  * Advancing is just as simple.  Again, this is doing more than
124caf54c4fSMartin Matuska  * necessary in order to better exercise internal code when used
125caf54c4fSMartin Matuska  * as a test harness.
126caf54c4fSMartin Matuska  */
1276c95142eSMartin Matuska static int64_t
memory_read_skip(struct archive * a,void * client_data,int64_t skip)1286c95142eSMartin Matuska memory_read_skip(struct archive *a, void *client_data, int64_t skip)
129caf54c4fSMartin Matuska {
130caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
131caf54c4fSMartin Matuska 
132caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
1336c95142eSMartin Matuska 	if ((int64_t)skip > (int64_t)(mine->end - mine->p))
1346c95142eSMartin Matuska 		skip = mine->end - mine->p;
135caf54c4fSMartin Matuska 	/* Round down to block size. */
136caf54c4fSMartin Matuska 	skip /= mine->read_size;
137caf54c4fSMartin Matuska 	skip *= mine->read_size;
1386c95142eSMartin Matuska 	mine->p += skip;
139caf54c4fSMartin Matuska 	return (skip);
140caf54c4fSMartin Matuska }
141caf54c4fSMartin Matuska 
142caf54c4fSMartin Matuska /*
1436c95142eSMartin Matuska  * Seeking.
1446c95142eSMartin Matuska  */
1456c95142eSMartin Matuska static int64_t
memory_read_seek(struct archive * a,void * client_data,int64_t offset,int whence)1466c95142eSMartin Matuska memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
1476c95142eSMartin Matuska {
1486c95142eSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
1496c95142eSMartin Matuska 
1506c95142eSMartin Matuska 	(void)a; /* UNUSED */
1516c95142eSMartin Matuska 	switch (whence) {
1526c95142eSMartin Matuska 	case SEEK_SET:
1536c95142eSMartin Matuska 		mine->p = mine->start + offset;
1546c95142eSMartin Matuska 		break;
1556c95142eSMartin Matuska 	case SEEK_CUR:
1566c95142eSMartin Matuska 		mine->p += offset;
1576c95142eSMartin Matuska 		break;
1586c95142eSMartin Matuska 	case SEEK_END:
1596c95142eSMartin Matuska 		mine->p = mine->end + offset;
1606c95142eSMartin Matuska 		break;
1616c95142eSMartin Matuska 	default:
1626c95142eSMartin Matuska 		return ARCHIVE_FATAL;
1636c95142eSMartin Matuska 	}
1646c95142eSMartin Matuska 	if (mine->p < mine->start) {
1656c95142eSMartin Matuska 		mine->p = mine->start;
1666c95142eSMartin Matuska 		return ARCHIVE_FAILED;
1676c95142eSMartin Matuska 	}
1686c95142eSMartin Matuska 	if (mine->p > mine->end) {
1696c95142eSMartin Matuska 		mine->p = mine->end;
1706c95142eSMartin Matuska 		return ARCHIVE_FAILED;
1716c95142eSMartin Matuska 	}
1726c95142eSMartin Matuska 	return (mine->p - mine->start);
1736c95142eSMartin Matuska }
1746c95142eSMartin Matuska 
1756c95142eSMartin Matuska /*
176caf54c4fSMartin Matuska  * Close is just cleaning up our one small bit of data.
177caf54c4fSMartin Matuska  */
178caf54c4fSMartin Matuska static int
memory_read_close(struct archive * a,void * client_data)179caf54c4fSMartin Matuska memory_read_close(struct archive *a, void *client_data)
180caf54c4fSMartin Matuska {
181caf54c4fSMartin Matuska 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
182caf54c4fSMartin Matuska 	(void)a; /* UNUSED */
183caf54c4fSMartin Matuska 	free(mine);
184caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
185caf54c4fSMartin Matuska }
186