1/* 2 * Copyright (c) 2005-2007 Rob Braun 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 * 3. Neither the name of Rob Braun nor the names of his contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 03-Apr-2005 31 * DRI: Rob Braun <bbraun@synack.net> 32 */ 33/* 34 * Portions Copyright 2006, Apple Computer, Inc. 35 * Christopher Ryan <ryanc@apple.com> 36*/ 37 38#include <stdio.h> 39#include <stdint.h> 40#include <sys/types.h> 41#include <arpa/inet.h> 42#include <string.h> 43#include <unistd.h> 44#include <errno.h> 45#include <time.h> 46#include "config.h" 47#ifndef HAVE_ASPRINTF 48#include "asprintf.h" 49#endif 50#include "xar.h" 51#include "archive.h" 52#include "filetree.h" 53 54 55 56uint64_t xar_ntoh64(uint64_t num) { 57 int t = 1234; 58 union conv { 59 uint64_t i64; 60 uint32_t i32[2]; 61 } *in, out; 62 63 if( ntohl(t) == t ) { 64 out.i64 = num; 65 return out.i64; 66 } 67 in = (union conv *)# 68 out.i32[1] = ntohl(in->i32[0]); 69 out.i32[0] = ntohl(in->i32[1]); 70 return(out.i64); 71} 72 73uint32_t xar_swap32(uint32_t num) { 74 uint8_t *one, *two; 75 uint32_t ret; 76 77 two = (uint8_t *)&ret; 78 one = (uint8_t *)# 79 two[3] = one[0]; 80 two[2] = one[1]; 81 two[1] = one[2]; 82 two[0] = one[3]; 83 84 return ret; 85} 86 87/* xar_get_path 88 * Summary: returns the archive path of the file f. 89 * Caller needs to free the return value. 90 */ 91char *xar_get_path(xar_file_t f) { 92 char *ret, *tmp; 93 const char *name; 94 xar_file_t i; 95 96 xar_prop_get(f, "name", &name); 97 ret = strdup(name); 98 for(i = XAR_FILE(f)->parent; i; i = XAR_FILE(i)->parent) { 99 const char *name; 100 xar_prop_get(i, "name", &name); 101 tmp = ret; 102 asprintf(&ret, "%s/%s", name, tmp); 103 free(tmp); 104 } 105 106 return ret; 107} 108 109off_t xar_get_heap_offset(xar_t x) { 110 return XAR(x)->toc_count + sizeof(xar_header_t); 111} 112 113/* xar_read_fd 114 * Summary: Reads from a file descriptor a certain number of bytes to a specific 115 * buffer. This simple wrapper just handles certain retryable error situations. 116 * Returns -1 when it fails fatally; the number of bytes read otherwise. 117 */ 118ssize_t xar_read_fd( int fd, void * buffer, size_t nbytes ) { 119 ssize_t rb; 120 ssize_t off = 0; 121 122 while ( off < nbytes ) { 123 rb = read(fd, ((char *)buffer)+off, nbytes-off); 124 if( (rb < 1 ) && (errno != EINTR) && (errno != EAGAIN) ) 125 return -1; 126 off += rb; 127 } 128 129 return off; 130} 131 132/* xar_write_fd 133 * Summary: Writes from a buffer to a file descriptor. Like xar_read_fd it 134 * also just handles certain retryable error situations. 135 * Returs -1 when it fails fatally; the number of bytes written otherwise. 136 */ 137ssize_t xar_write_fd( int fd, void * buffer, size_t nbytes ) { 138 ssize_t rb; 139 ssize_t off = 0; 140 141 while ( off < nbytes ) { 142 rb = write(fd, ((char *)buffer)+off, nbytes-off); 143 if( (rb < 1 ) && (errno != EINTR) && (errno != EAGAIN) ) 144 return -1; 145 off += rb; 146 } 147 148 return off; 149} 150 151dev_t xar_makedev(uint32_t major, uint32_t minor) 152{ 153#ifdef makedev 154 return makedev(major, minor); 155#else 156 return (major << 8) | minor; 157#endif 158} 159 160void xar_devmake(dev_t dev, uint32_t *out_major, uint32_t *out_minor) 161{ 162#ifdef major 163 *out_major = major(dev); 164#else 165 *out_major = (dev >> 8) & 0xFF; 166#endif 167#ifdef minor 168 *out_minor = minor(dev); 169#else 170 *out_minor = dev & 0xFF; 171#endif 172 return; 173} 174 175char* xar_path_nextcomponent(char** path_to_advance) { 176 char* component_start = *path_to_advance; 177 unsigned int component_length = 1; 178 char* out_component = NULL; 179 180 if (**path_to_advance == '\0') // If we're trying to look at the end of the path, punt 181 return NULL; 182 183 for (; **path_to_advance && (**path_to_advance != '/'); ++(*path_to_advance), ++component_length) { 184 if (**path_to_advance == '\\') { // Escape ignores next char 185 ++(*path_to_advance); 186 ++component_length; 187 continue; 188 } 189 } 190 191 if (**path_to_advance == '/') { 192 ++(*path_to_advance); 193 } 194 195 out_component = (char*)malloc(component_length); 196 strncpy(out_component, component_start, component_length); 197 198 out_component[component_length-1] = 0; 199 200 return out_component; 201} 202 203 204int xar_path_issane(char* path) { 205 char* path_walker = path; 206 char* component = NULL; 207 int path_depth = 0; 208 209 // Ban 0 length / absolute paths. 210 if (strlen(path) == 0 || path[0] == '/') 211 return 0; 212 213 while (component = xar_path_nextcomponent(&path_walker)) { 214 215 if (strlen(component) == 0 || strcmp(component, ".") == 0) { // Since // is legal, and '.' is legal it's possible to have empty path elements. Ignore them 216 free(component); 217 continue; 218 } 219 220 if (strcmp(component, "..")) 221 ++path_depth; 222 else 223 --path_depth; 224 225 free(component); 226 227 if (path_depth < 0) // We've escaped our root, this path is not sane. 228 return 0; 229 } 230 231 return 1; 232} 233 234 235 236 237#ifndef HAVE_STRMODE 238#include "strmode.h" 239#endif 240 241char *xar_get_type(xar_t x, xar_file_t f) { 242 const char *type = NULL; 243 xar_prop_get(f, "type", &type); 244 if( type == NULL ) 245 type = "unknown"; 246 return strdup(type); 247} 248 249char *xar_get_size(xar_t x, xar_file_t f) { 250 const char *size = NULL; 251 const char *type = NULL; 252 253 xar_prop_get(f, "type", &type); 254 if( type != NULL ) { 255 if( strcmp(type, "hardlink") == 0 ) { 256 const char *link = NULL; 257 link = xar_attr_get(f, "type", "link"); 258 if( link ) { 259 if( strcmp(link, "original") != 0 ) { 260 xar_iter_t i; 261 i = xar_iter_new(); 262 if( i ) { 263 xar_file_t tmpf; 264 for(tmpf = xar_file_first(x, i); tmpf; tmpf = xar_file_next(i)) { 265 const char *id; 266 id = xar_attr_get(tmpf, NULL, "id"); 267 if( !id ) continue; 268 if( strcmp(id, link) == 0 ) { 269 f = tmpf; 270 break; 271 } 272 } 273 } 274 xar_iter_free(i); 275 } 276 } 277 } 278 } 279 xar_prop_get(f, "data/size", &size); 280 if( size == NULL ) 281 size = "0"; 282 return strdup(size); 283} 284 285char *xar_get_mode(xar_t x, xar_file_t f) { 286 const char *mode = NULL; 287 const char *type = NULL; 288 char *ret; 289 mode_t m; 290 xar_prop_get(f, "mode", &mode); 291 if( mode == NULL ) 292 return strdup("??????????"); 293 errno = 0; 294 m = strtoll(mode, 0, 8); 295 if( errno ) 296 return strdup("??????????"); 297 298 xar_prop_get(f, "type", &type); 299 if( type == NULL ) 300 return strdup("??????????"); 301 302 if( strcmp(type, "file") == 0 ) 303 m |= S_IFREG; 304 else if( strcmp(type, "hardlink") == 0 ) 305 m |= S_IFREG; 306 else if( strcmp(type, "directory") == 0 ) 307 m |= S_IFDIR; 308 else if( strcmp(type, "symlink") == 0 ) 309 m |= S_IFLNK; 310 else if( strcmp(type, "fifo") == 0 ) 311 m |= S_IFIFO; 312 else if( strcmp(type, "character special") == 0 ) 313 m |= S_IFCHR; 314 else if( strcmp(type, "block special") == 0 ) 315 m |= S_IFBLK; 316 else if( strcmp(type, "socket") == 0 ) 317 m |= S_IFSOCK; 318#ifdef S_IFWHT 319 else if( strcmp(type, "whiteout") == 0 ) 320 m |= S_IFWHT; 321#endif 322 323 ret = calloc(12,1); 324 strmode(m, ret); 325 326 return ret; 327} 328 329char *xar_get_owner(xar_t x, xar_file_t f) { 330 const char *user = NULL; 331 332 xar_prop_get(f, "user", &user); 333 if( !user ) 334 return strdup("unknown"); 335 return strdup(user); 336} 337 338char *xar_get_group(xar_t x, xar_file_t f) { 339 const char *group = NULL; 340 341 xar_prop_get(f, "group", &group); 342 if( !group ) 343 return strdup("unknown"); 344 return strdup(group); 345} 346 347char *xar_get_mtime(xar_t x, xar_file_t f) { 348 const char *mtime = NULL; 349 char *tmp; 350 struct tm tm; 351 352 xar_prop_get(f, "mtime", &mtime); 353 if( !mtime ) 354 mtime = "1970-01-01T00:00:00Z"; 355 356 strptime(mtime, "%FT%T", &tm); 357 tmp = calloc(128,1); 358 strftime(tmp, 127, "%F %T", &tm); 359 return tmp; 360} 361