1/* 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of Apple nor the names of any contributors 13 * may be used to endorse or promote products derived from this software 14 * without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27*/ 28/* 29 * Portions Copyright 2006, Apple Computer, Inc. 30 * Christopher Ryan <ryanc@apple.com> 31*/ 32 33#define _FILE_OFFSET_BITS 64 34#include <stdlib.h> 35#include <stdio.h> 36#include <fcntl.h> 37#include <errno.h> 38#include <string.h> 39#include <limits.h> 40#include <unistd.h> 41#include <inttypes.h> 42#include <sys/types.h> 43 44#include "xar.h" 45#include "filetree.h" 46#include "archive.h" 47#include "io.h" 48#include "arcmod.h" 49 50#ifndef O_EXLOCK 51#define O_EXLOCK 0 52#endif 53 54struct _data_context{ 55 int fd; 56 void *buffer; 57 size_t length; 58 off_t offset; 59 off_t total; 60}; 61 62#define DATA_CONTEXT(x) ((struct _data_context*)(x)) 63 64int32_t xar_data_read(xar_t x, xar_file_t f, void *inbuf, size_t bsize, void *context) { 65 int32_t r; 66 67 /* read from buffer, rather then fd,if available */ 68 if(DATA_CONTEXT(context)->length){ 69 char *readbuf = (char *)DATA_CONTEXT(context)->buffer; 70 size_t sizetoread = DATA_CONTEXT(context)->length - DATA_CONTEXT(context)->offset; 71 72 if( !sizetoread){ 73 return 0; 74 } 75 76 if( sizetoread > bsize ){ 77 sizetoread = bsize; 78 } 79 80 /* dont read passed the end of the buffer */ 81 if((DATA_CONTEXT(context)->offset + sizetoread) > DATA_CONTEXT(context)->length){ 82 return -1; 83 //sizetoread = (DATA_CONTEXT(context)->offset + sizetoread) - DATA_CONTEXT(context)->length; 84 } 85 86 readbuf += DATA_CONTEXT(context)->offset; 87 memcpy(inbuf,readbuf,sizetoread); 88 89 DATA_CONTEXT(context)->total += sizetoread; 90 DATA_CONTEXT(context)->offset += sizetoread; 91 92 return sizetoread; 93 } 94 95 while(1) { 96 r = read(DATA_CONTEXT(context)->fd, inbuf, bsize); 97 if( (r < 0) && (errno == EINTR) ) 98 continue; 99 DATA_CONTEXT(context)->total += r; 100 return r; 101 } 102 103} 104 105int32_t xar_data_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 106 int32_t r; 107 size_t off = 0; 108 109 /* read from buffer, rather then fd,if available */ 110 if(DATA_CONTEXT(context)->length){ 111 char *writebuf = (char *)DATA_CONTEXT(context)->buffer; 112 113 /* dont write passed the end of the buffer */ 114 if((DATA_CONTEXT(context)->offset + len) > DATA_CONTEXT(context)->length){ 115 return -1; 116 } 117 118 writebuf += DATA_CONTEXT(context)->offset; 119 memcpy(writebuf,buf,len); 120 121 DATA_CONTEXT(context)->offset += len; 122 123 return len; 124 } 125 126 do { 127 r = write(DATA_CONTEXT(context)->fd, ((char *)buf)+off, len-off); 128 if( (r < 0) && (errno != EINTR) ) 129 return r; 130 off += r; 131 } while( off < len ); 132 return off; 133} 134 135/* xar_data_archive 136 * This is the arcmod archival entry point for archiving the file's 137 * data into the heap file. 138 */ 139int32_t xar_data_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) { 140 const char *opt; 141 int32_t retval = 0; 142 struct _data_context context; 143 xar_prop_t tmpp; 144 145 memset(&context,0,sizeof(struct _data_context)); 146 147 if( !xar_check_prop(x, "data") ) 148 return 0; 149 150 xar_prop_get(f, "type", &opt); 151 if(!opt) return 0; 152 if( strcmp(opt, "file") != 0 ) { 153 if( strcmp(opt, "hardlink") == 0 ) { 154 opt = xar_attr_get(f, "type", "link"); 155 if( !opt ) 156 return 0; 157 if( strcmp(opt, "original") != 0 ) 158 return 0; 159 /* else, we're an original hardlink, so keep going */ 160 } else 161 return 0; 162 } 163 164 if( 0 == len ){ 165 context.fd = open(file, O_RDONLY); 166 if( context.fd < 0 ) { 167 xar_err_new(x); 168 xar_err_set_file(x, f); 169 xar_err_set_string(x, "io: Could not open file"); 170 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_CREATION); 171 return -1; 172 } 173 }else{ 174 context.buffer = (void *)buffer; 175 context.length = len; 176 context.offset = 0; 177 } 178 179#ifdef F_NOCACHE 180 fcntl(context.fd, F_NOCACHE, 1); 181#endif 182 183 tmpp = xar_prop_pset(f, NULL, "data", NULL); 184 retval = XAR(x)->attrcopy_to_heap(x, f, tmpp, xar_data_read,(void *)(&context)); 185 if( context.total == 0 ) 186 xar_prop_unset(f, "data"); 187 188 if(context.fd > 0){ 189 close(context.fd); 190 context.fd = -1; 191 } 192 193 return retval; 194} 195 196int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { 197 const char *opt; 198 int32_t retval = 0; 199 struct _data_context context; 200 xar_prop_t tmpp; 201 202 memset(&context,0,sizeof(struct _data_context)); 203 204 /* Only regular files are copied in and out of the heap here */ 205 xar_prop_get(f, "type", &opt); 206 if( !opt ) return 0; 207 if( strcmp(opt, "file") != 0 ) { 208 if( strcmp(opt, "hardlink") == 0 ) { 209 opt = xar_attr_get(f, "type", "link"); 210 if( !opt ) 211 return 0; 212 if( strcmp(opt, "original") != 0 ) 213 return 0; 214 /* else, we're an original hardlink, so keep going */ 215 } else 216 return 0; 217 } 218 219 if ( len ){ 220 context.length = len; 221 context.buffer = buffer; 222 context.offset = 0; 223 }else{ 224 /* mode 600 since other modules may need to operate on the file 225 * prior to the real permissions being set. 226 */ 227 context.fd = open(file, O_RDWR|O_TRUNC|O_EXLOCK, 0600); 228 if( context.fd < 0 ) { 229 xar_err_new(x); 230 xar_err_set_file(x, f); 231 xar_err_set_string(x, "io: Could not create file"); 232 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 233 return -1; 234 } 235 236 } 237 238 tmpp = xar_prop_pfirst(f); 239 if( tmpp ) 240 tmpp = xar_prop_find(tmpp, "data"); 241 if( !tmpp ) { 242 close(context.fd); 243 return 0; 244 } 245 retval = XAR(x)->attrcopy_from_heap(x, f, tmpp, xar_data_write, (void *)(&context)); 246 247 if( context.fd > 0 ){ 248 close(context.fd); 249 context.fd = -1; 250 } 251 252 return retval; 253} 254 255int32_t xar_data_verify(xar_t x, xar_file_t f) 256{ 257 const char *opt; 258 struct _data_context context; 259 xar_prop_t tmpp; 260 261 memset(&context,0,sizeof(struct _data_context)); 262 263 /* Only regular files are copied in and out of the heap here */ 264 xar_prop_get(f, "type", &opt); 265 if( !opt ) return 0; 266 if( strcmp(opt, "directory") == 0 ) { 267 return 0; 268 } 269 270 tmpp = xar_prop_pfirst(f); 271 if( tmpp ) 272 tmpp = xar_prop_find(tmpp, "data"); 273 274 if (!tmpp) // It appears that xar can have truely empty files, aka, no data. We should just fail to verify these files. 275 return 0; // After all, the checksum of blank is meaningless. So, failing to do so will cause a crash. 276 277 return XAR(x)->attrcopy_from_heap(x, f, tmpp, NULL , (void *)(&context)); 278} 279