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 28 #ifdef HAVE_SYS_STAT_H 29 #include <sys/stat.h> 30 #endif 31 #ifdef HAVE_ERRNO_H 32 #include <errno.h> 33 #endif 34 #ifdef HAVE_FCNTL_H 35 #include <fcntl.h> 36 #endif 37 #ifdef HAVE_IO_H 38 #include <io.h> 39 #endif 40 #ifdef HAVE_STDLIB_H 41 #include <stdlib.h> 42 #endif 43 #ifdef HAVE_STRING_H 44 #include <string.h> 45 #endif 46 #ifdef HAVE_UNISTD_H 47 #include <unistd.h> 48 #endif 49 50 #include "archive.h" 51 #include "archive_platform_stat.h" 52 53 struct read_FILE_data { 54 FILE *f; 55 size_t block_size; 56 int64_t size; 57 void *buffer; 58 char can_skip; 59 }; 60 61 static int FILE_close(struct archive *, void *); 62 static ssize_t FILE_read(struct archive *, void *, const void **buff); 63 static int64_t FILE_seek(struct archive *, void *, int64_t, int); 64 static int64_t FILE_skip(struct archive *, void *, int64_t); 65 66 int 67 archive_read_open_FILE(struct archive *a, FILE *f) 68 { 69 la_seek_stat_t st; 70 struct read_FILE_data *mine; 71 size_t block_size = 128 * 1024; 72 void *b; 73 74 archive_clear_error(a); 75 mine = calloc(1, sizeof(*mine)); 76 b = malloc(block_size); 77 if (mine == NULL || b == NULL) { 78 archive_set_error(a, ENOMEM, "No memory"); 79 free(mine); 80 free(b); 81 return (ARCHIVE_FATAL); 82 } 83 mine->block_size = block_size; 84 mine->buffer = b; 85 mine->f = f; 86 /* 87 * If we can't fstat() the file, it may just be that it's not 88 * a file. (On some platforms, FILE * objects can wrap I/O 89 * streams that don't support fileno()). As a result, fileno() 90 * should be used cautiously.) 91 */ 92 if (la_seek_fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { 93 archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); 94 /* Enable the seek optimization only for regular files. */ 95 mine->can_skip = 1; 96 mine->size = st.st_size; 97 } 98 99 #if defined(__CYGWIN__) || defined(_WIN32) 100 setmode(fileno(mine->f), O_BINARY); 101 #endif 102 103 archive_read_set_read_callback(a, FILE_read); 104 archive_read_set_skip_callback(a, FILE_skip); 105 archive_read_set_seek_callback(a, FILE_seek); 106 archive_read_set_close_callback(a, FILE_close); 107 archive_read_set_callback_data(a, mine); 108 return (archive_read_open1(a)); 109 } 110 111 static ssize_t 112 FILE_read(struct archive *a, void *client_data, const void **buff) 113 { 114 struct read_FILE_data *mine = (struct read_FILE_data *)client_data; 115 size_t bytes_read; 116 117 *buff = mine->buffer; 118 bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f); 119 if (bytes_read < mine->block_size && ferror(mine->f)) { 120 archive_set_error(a, errno, "Error reading file"); 121 } 122 return (bytes_read); 123 } 124 125 static int64_t 126 FILE_skip(struct archive *a, void *client_data, int64_t request) 127 { 128 struct read_FILE_data *mine = (struct read_FILE_data *)client_data; 129 #if HAVE__FSEEKI64 130 int64_t skip = request; 131 #elif HAVE_FSEEKO 132 off_t skip = (off_t)request; 133 #else 134 long skip = (long)request; 135 #endif 136 int64_t old_offset, new_offset = -1; 137 int skip_bits = sizeof(skip) * 8 - 1; 138 139 (void)a; /* UNUSED */ 140 141 /* 142 * If we can't skip, return 0 as the amount we did step and 143 * the caller will work around by reading and discarding. 144 */ 145 if (!mine->can_skip) 146 return (0); 147 if (request == 0) 148 return (0); 149 150 /* If request is too big for a long or an off_t, reduce it. */ 151 if (sizeof(request) > sizeof(skip)) { 152 const int64_t max_skip = 153 (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; 154 if (request > max_skip) 155 skip = max_skip; 156 } 157 158 #ifdef __ANDROID__ 159 /* fileno() isn't safe on all platforms ... see above. */ 160 old_offset = lseek(fileno(mine->f), 0, SEEK_CUR); 161 #elif HAVE__FSEEKI64 162 old_offset = _ftelli64(mine->f); 163 #elif HAVE_FSEEKO 164 old_offset = ftello(mine->f); 165 #else 166 old_offset = ftell(mine->f); 167 #endif 168 if (old_offset >= 0) { 169 if (old_offset < mine->size && 170 skip <= mine->size - old_offset) { 171 #ifdef __ANDROID__ 172 new_offset = lseek(fileno(mine->f), skip, SEEK_CUR); 173 #elif HAVE__FSEEKI64 174 if (_fseeki64(mine->f, skip, SEEK_CUR) == 0) 175 new_offset = _ftelli64(mine->f); 176 #elif HAVE_FSEEKO 177 if (fseeko(mine->f, skip, SEEK_CUR) == 0) 178 new_offset = ftello(mine->f); 179 #else 180 if (fseek(mine->f, skip, SEEK_CUR) == 0) 181 new_offset = ftell(mine->f); 182 #endif 183 if (new_offset >= 0) 184 return (new_offset - old_offset); 185 } 186 } 187 188 mine->can_skip = 0; 189 return (0); 190 } 191 192 /* 193 * TODO: Store the offset and use it in the read callback. 194 */ 195 static int64_t 196 FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) 197 { 198 struct read_FILE_data *mine = (struct read_FILE_data *)client_data; 199 #if HAVE__FSEEKI64 200 int64_t seek = request; 201 #elif HAVE_FSEEKO 202 off_t seek = (off_t)request; 203 #else 204 long seek = (long)request; 205 #endif 206 int seek_bits = sizeof(seek) * 8 - 1; 207 (void)a; /* UNUSED */ 208 209 /* Do not perform a seek which cannot be fulfilled. */ 210 if (sizeof(request) > sizeof(seek)) { 211 const int64_t max_seek = 212 (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; 213 const int64_t min_seek = ~max_seek; 214 if (request < min_seek || request > max_seek) { 215 errno = EOVERFLOW; 216 goto err; 217 } 218 } 219 220 #ifdef __ANDROID__ 221 /* Newer Android versions have fseeko...to meditate. */ 222 int64_t ret = lseek(fileno(mine->f), seek, whence); 223 if (ret >= 0) { 224 return ret; 225 } 226 #elif HAVE__FSEEKI64 227 if (_fseeki64(mine->f, seek, whence) == 0) { 228 return _ftelli64(mine->f); 229 } 230 #elif HAVE_FSEEKO 231 if (fseeko(mine->f, seek, whence) == 0) { 232 return ftello(mine->f); 233 } 234 #else 235 if (fseek(mine->f, seek, whence) == 0) { 236 return ftell(mine->f); 237 } 238 #endif 239 /* If we arrive here, the input is corrupted or truncated so fail. */ 240 err: 241 archive_set_error(a, errno, "Error seeking in FILE* pointer"); 242 return (ARCHIVE_FATAL); 243 } 244 245 static int 246 FILE_close(struct archive *a, void *client_data) 247 { 248 struct read_FILE_data *mine = (struct read_FILE_data *)client_data; 249 250 (void)a; /* UNUSED */ 251 free(mine->buffer); 252 free(mine); 253 return (ARCHIVE_OK); 254 } 255