160b4ad09SPeter Avalos /*-
260b4ad09SPeter Avalos  * Copyright (c) 2003-2007 Tim Kientzle
360b4ad09SPeter Avalos  * All rights reserved.
460b4ad09SPeter Avalos  *
560b4ad09SPeter Avalos  * Redistribution and use in source and binary forms, with or without
660b4ad09SPeter Avalos  * modification, are permitted provided that the following conditions
760b4ad09SPeter Avalos  * are met:
860b4ad09SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
960b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1060b4ad09SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1160b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1260b4ad09SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1360b4ad09SPeter Avalos  *
1460b4ad09SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1560b4ad09SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1660b4ad09SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1760b4ad09SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1860b4ad09SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1960b4ad09SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2060b4ad09SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2160b4ad09SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2260b4ad09SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2360b4ad09SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460b4ad09SPeter Avalos  */
2560b4ad09SPeter Avalos 
2660b4ad09SPeter Avalos #include "archive_platform.h"
279c82a63eSPeter Avalos __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_file.c 201093 2009-12-28 02:28:44Z kientzle $");
2860b4ad09SPeter Avalos 
2960b4ad09SPeter Avalos #ifdef HAVE_SYS_STAT_H
3060b4ad09SPeter Avalos #include <sys/stat.h>
3160b4ad09SPeter Avalos #endif
3260b4ad09SPeter Avalos #ifdef HAVE_ERRNO_H
3360b4ad09SPeter Avalos #include <errno.h>
3460b4ad09SPeter Avalos #endif
3560b4ad09SPeter Avalos #ifdef HAVE_FCNTL_H
3660b4ad09SPeter Avalos #include <fcntl.h>
3760b4ad09SPeter Avalos #endif
389c82a63eSPeter Avalos #ifdef HAVE_IO_H
399c82a63eSPeter Avalos #include <io.h>
409c82a63eSPeter Avalos #endif
4160b4ad09SPeter Avalos #ifdef HAVE_STDLIB_H
4260b4ad09SPeter Avalos #include <stdlib.h>
4360b4ad09SPeter Avalos #endif
4460b4ad09SPeter Avalos #ifdef HAVE_STRING_H
4560b4ad09SPeter Avalos #include <string.h>
4660b4ad09SPeter Avalos #endif
4760b4ad09SPeter Avalos #ifdef HAVE_UNISTD_H
4860b4ad09SPeter Avalos #include <unistd.h>
4960b4ad09SPeter Avalos #endif
5060b4ad09SPeter Avalos 
5160b4ad09SPeter Avalos #include "archive.h"
5260b4ad09SPeter Avalos 
5360b4ad09SPeter Avalos struct read_FILE_data {
5460b4ad09SPeter Avalos 	FILE    *f;
5560b4ad09SPeter Avalos 	size_t	 block_size;
5660b4ad09SPeter Avalos 	void	*buffer;
5760b4ad09SPeter Avalos 	char	 can_skip;
5860b4ad09SPeter Avalos };
5960b4ad09SPeter Avalos 
6060b4ad09SPeter Avalos static int	file_close(struct archive *, void *);
6160b4ad09SPeter Avalos static ssize_t	file_read(struct archive *, void *, const void **buff);
62c09f92d2SPeter Avalos static int64_t	file_skip(struct archive *, void *, int64_t request);
6360b4ad09SPeter Avalos 
6460b4ad09SPeter Avalos int
archive_read_open_FILE(struct archive * a,FILE * f)6560b4ad09SPeter Avalos archive_read_open_FILE(struct archive *a, FILE *f)
6660b4ad09SPeter Avalos {
678029ab02SPeter Avalos 	struct stat st;
6860b4ad09SPeter Avalos 	struct read_FILE_data *mine;
698029ab02SPeter Avalos 	size_t block_size = 128 * 1024;
708029ab02SPeter Avalos 	void *b;
7160b4ad09SPeter Avalos 
729c82a63eSPeter Avalos 	archive_clear_error(a);
7360b4ad09SPeter Avalos 	mine = (struct read_FILE_data *)malloc(sizeof(*mine));
748029ab02SPeter Avalos 	b = malloc(block_size);
758029ab02SPeter Avalos 	if (mine == NULL || b == NULL) {
7660b4ad09SPeter Avalos 		archive_set_error(a, ENOMEM, "No memory");
7760b4ad09SPeter Avalos 		free(mine);
788029ab02SPeter Avalos 		free(b);
7960b4ad09SPeter Avalos 		return (ARCHIVE_FATAL);
8060b4ad09SPeter Avalos 	}
818029ab02SPeter Avalos 	mine->block_size = block_size;
828029ab02SPeter Avalos 	mine->buffer = b;
8360b4ad09SPeter Avalos 	mine->f = f;
8460b4ad09SPeter Avalos 	/*
858029ab02SPeter Avalos 	 * If we can't fstat() the file, it may just be that it's not
86*6b384f39SPeter Avalos 	 * a file.  (On some platforms, FILE * objects can wrap I/O
87*6b384f39SPeter Avalos 	 * streams that don't support fileno()).  As a result, fileno()
88*6b384f39SPeter Avalos 	 * should be used cautiously.)
8960b4ad09SPeter Avalos 	 */
9060b4ad09SPeter Avalos 	if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
9160b4ad09SPeter Avalos 		archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
928029ab02SPeter Avalos 		/* Enable the seek optimization only for regular files. */
9360b4ad09SPeter Avalos 		mine->can_skip = 1;
948029ab02SPeter Avalos 	} else
958029ab02SPeter Avalos 		mine->can_skip = 0;
9660b4ad09SPeter Avalos 
979c82a63eSPeter Avalos #if defined(__CYGWIN__) || defined(_WIN32)
989c82a63eSPeter Avalos 	setmode(fileno(mine->f), O_BINARY);
999c82a63eSPeter Avalos #endif
1009c82a63eSPeter Avalos 
101c09f92d2SPeter Avalos 	archive_read_set_read_callback(a, file_read);
102c09f92d2SPeter Avalos 	archive_read_set_skip_callback(a, file_skip);
103c09f92d2SPeter Avalos 	archive_read_set_close_callback(a, file_close);
104c09f92d2SPeter Avalos 	archive_read_set_callback_data(a, mine);
105c09f92d2SPeter Avalos 	return (archive_read_open1(a));
10660b4ad09SPeter Avalos }
10760b4ad09SPeter Avalos 
10860b4ad09SPeter Avalos static ssize_t
file_read(struct archive * a,void * client_data,const void ** buff)10960b4ad09SPeter Avalos file_read(struct archive *a, void *client_data, const void **buff)
11060b4ad09SPeter Avalos {
11160b4ad09SPeter Avalos 	struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
112d4d8193eSPeter Avalos 	size_t bytes_read;
11360b4ad09SPeter Avalos 
11460b4ad09SPeter Avalos 	*buff = mine->buffer;
11560b4ad09SPeter Avalos 	bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
116d4d8193eSPeter Avalos 	if (bytes_read < mine->block_size && ferror(mine->f)) {
11760b4ad09SPeter Avalos 		archive_set_error(a, errno, "Error reading file");
11860b4ad09SPeter Avalos 	}
11960b4ad09SPeter Avalos 	return (bytes_read);
12060b4ad09SPeter Avalos }
12160b4ad09SPeter Avalos 
122c09f92d2SPeter Avalos static int64_t
file_skip(struct archive * a,void * client_data,int64_t request)123c09f92d2SPeter Avalos file_skip(struct archive *a, void *client_data, int64_t request)
12460b4ad09SPeter Avalos {
12560b4ad09SPeter Avalos 	struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
126c09f92d2SPeter Avalos #if HAVE_FSEEKO
127c09f92d2SPeter Avalos 	off_t skip = (off_t)request;
128c09f92d2SPeter Avalos #elif HAVE__FSEEKI64
129c09f92d2SPeter Avalos 	int64_t skip = request;
130c09f92d2SPeter Avalos #else
131c09f92d2SPeter Avalos 	long skip = (long)request;
132c09f92d2SPeter Avalos #endif
133c09f92d2SPeter Avalos 	int skip_bits = sizeof(skip) * 8 - 1;
13460b4ad09SPeter Avalos 
13560b4ad09SPeter Avalos 	(void)a; /* UNUSED */
13660b4ad09SPeter Avalos 
13760b4ad09SPeter Avalos 	/*
13860b4ad09SPeter Avalos 	 * If we can't skip, return 0 as the amount we did step and
13960b4ad09SPeter Avalos 	 * the caller will work around by reading and discarding.
14060b4ad09SPeter Avalos 	 */
14160b4ad09SPeter Avalos 	if (!mine->can_skip)
14260b4ad09SPeter Avalos 		return (0);
14360b4ad09SPeter Avalos 	if (request == 0)
14460b4ad09SPeter Avalos 		return (0);
14560b4ad09SPeter Avalos 
146c09f92d2SPeter Avalos 	/* If request is too big for a long or an off_t, reduce it. */
147c09f92d2SPeter Avalos 	if (sizeof(request) > sizeof(skip)) {
148c09f92d2SPeter Avalos 		int64_t max_skip =
149c09f92d2SPeter Avalos 		    (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
150c09f92d2SPeter Avalos 		if (request > max_skip)
151c09f92d2SPeter Avalos 			skip = max_skip;
152c09f92d2SPeter Avalos 	}
153c09f92d2SPeter Avalos 
154*6b384f39SPeter Avalos #ifdef __ANDROID__
155*6b384f39SPeter Avalos         /* fileno() isn't safe on all platforms ... see above. */
156*6b384f39SPeter Avalos 	if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
157*6b384f39SPeter Avalos #elif HAVE_FSEEKO
158c09f92d2SPeter Avalos 	if (fseeko(mine->f, skip, SEEK_CUR) != 0)
159c09f92d2SPeter Avalos #elif HAVE__FSEEKI64
160c09f92d2SPeter Avalos 	if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
16160b4ad09SPeter Avalos #else
162c09f92d2SPeter Avalos 	if (fseek(mine->f, skip, SEEK_CUR) != 0)
16360b4ad09SPeter Avalos #endif
16460b4ad09SPeter Avalos 	{
16560b4ad09SPeter Avalos 		mine->can_skip = 0;
16660b4ad09SPeter Avalos 		return (0);
16760b4ad09SPeter Avalos 	}
16860b4ad09SPeter Avalos 	return (request);
16960b4ad09SPeter Avalos }
17060b4ad09SPeter Avalos 
17160b4ad09SPeter Avalos static int
file_close(struct archive * a,void * client_data)17260b4ad09SPeter Avalos file_close(struct archive *a, void *client_data)
17360b4ad09SPeter Avalos {
17460b4ad09SPeter Avalos 	struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
17560b4ad09SPeter Avalos 
17660b4ad09SPeter Avalos 	(void)a; /* UNUSED */
17760b4ad09SPeter Avalos 	free(mine->buffer);
17860b4ad09SPeter Avalos 	free(mine);
17960b4ad09SPeter Avalos 	return (ARCHIVE_OK);
18060b4ad09SPeter Avalos }
181