1/* 2 * Copyright (c) 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 2003, Apple Computer, Inc. 35 * filetype_name() and associated structure. 36 * DRI: Kevin Van Vechten <kvv@apple.com> 37 */ 38/* 39 * Portions Copyright 2006, Apple Computer, Inc. 40 * Christopher Ryan <ryanc@apple.com> 41*/ 42 43#define _FILE_OFFSET_BITS 64 44 45#include "config.h" 46#ifndef HAVE_ASPRINTF 47#include "asprintf.h" 48#endif 49#include <stdlib.h> 50#include <stdio.h> 51#include <stdarg.h> 52#include <inttypes.h> 53#include <sys/types.h> 54#include <sys/stat.h> 55#include <sys/time.h> 56#include <fcntl.h> 57#include <time.h> 58#include <pwd.h> 59#include <grp.h> 60#include <string.h> 61#include <unistd.h> 62#include <limits.h> 63#include <errno.h> 64#include <libxml/hash.h> 65#include <libxml/xmlstring.h> 66#ifdef HAVE_SYS_ACL_H 67#include <sys/acl.h> 68#endif 69#include "xar.h" 70#include "arcmod.h" 71#include "archive.h" 72#include "util.h" 73 74#ifndef LLONG_MIN 75#define LLONG_MIN LONG_LONG_MIN 76#endif 77 78#ifndef LLONG_MAX 79#define LLONG_MAX LONG_LONG_MAX 80#endif 81 82static struct { 83 const char *name; 84 mode_t type; 85} filetypes [] = { 86 { "file", S_IFREG }, 87 { "directory", S_IFDIR }, 88 { "symlink", S_IFLNK }, 89 { "fifo", S_IFIFO }, 90 { "character special", S_IFCHR }, 91 { "block special", S_IFBLK }, 92 { "socket", S_IFSOCK }, 93#ifdef S_IFWHT 94 { "whiteout", S_IFWHT }, 95#endif 96 { NULL, 0 } 97}; 98 99static const char * filetype_name (mode_t mode) { 100 unsigned int i; 101 for (i = 0; filetypes[i].name; i++) 102 if (mode == filetypes[i].type) 103 return (filetypes[i].name); 104 return ("unknown"); 105} 106 107static xar_file_t xar_link_lookup(xar_t x, dev_t dev, ino_t ino, xar_file_t f) { 108 char key[32]; 109 xar_file_t ret; 110 111 memset(key, 0, sizeof(key)); 112 snprintf(key, sizeof(key)-1, "%08" DEV_HEXSTRING "%08" INO_HEXSTRING, DEV_CAST dev, INO_CAST ino); 113 ret = xmlHashLookup(XAR(x)->ino_hash, BAD_CAST(key)); 114 if( ret == NULL ) { 115 xmlHashAddEntry(XAR(x)->ino_hash, BAD_CAST(key), XAR_FILE(f)); 116 return NULL; 117 } 118 return ret; 119} 120 121static int32_t aacls(xar_t x, xar_file_t f, const char *file) { 122#ifdef HAVE_SYS_ACL_H 123#if !defined(__APPLE__) 124 acl_t a; 125 const char *type; 126 127 xar_prop_get(f, "type", &type); 128 if( !type || (strcmp(type, "symlink") == 0) ) 129 return 0; 130 131 if( !xar_check_prop(x, "acl") ) 132 return 0; 133 134 a = acl_get_file(file, ACL_TYPE_DEFAULT); 135 if( a ) { 136 char *t; 137 acl_entry_t e; 138 139 /* If the acl is empty, or not valid, skip it */ 140 if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) 141 goto NEXT; 142 143 t = acl_to_text(a, NULL); 144 if( t ) { 145 xar_prop_set(f, "acl/default", t); 146 acl_free(t); 147 } 148 acl_free(a); 149 } 150NEXT: 151 152 a = acl_get_file(file, ACL_TYPE_ACCESS); 153 if( a ) { 154 char *t; 155 acl_entry_t e; 156 157 /* If the acl is empty, or not valid, skip it */ 158 if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) 159 goto DONE; 160 161 t = acl_to_text(a, NULL); 162 if( t ) { 163 xar_prop_set(f, "acl/access", t); 164 acl_free(t); 165 } 166 acl_free(a); 167 } 168DONE: 169#else /* !__APPLE__ */ 170 acl_entry_t e = NULL; 171 acl_t a; 172 int i; 173 174 if( !xar_check_prop(x, "acl") ) 175 return 0; 176 177 a = acl_get_file(file, ACL_TYPE_EXTENDED); 178 if( !a ) 179 return 0; 180 181 for( i = 0; acl_get_entry(a, e == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &e) == 0; i++ ) { 182 char *t; 183 t = acl_to_text(a, NULL); 184 if( t ) { 185 xar_prop_set(f, "acl/appleextended", t); 186 acl_free(t); 187 } 188 189 } 190 acl_free(a); 191#endif /* !__APPLE__ */ 192#endif 193 return 0; 194} 195 196static int32_t eacls(xar_t x, xar_file_t f, const char *file) { 197#ifdef HAVE_SYS_ACL_H 198#if !defined(__APPLE__) 199 const char *t; 200 acl_t a; 201 const char *type; 202 203 xar_prop_get(f, "type", &type); 204 if( !type || (strcmp(type, "symlink") == 0) ) 205 return 0; 206 207 208 xar_prop_get(f, "acl/default", &t); 209 if( t ) { 210 a = acl_from_text(t); 211 if( !a ) { 212 xar_err_new(x); 213 xar_err_set_errno(x, errno); 214 xar_err_set_string(x, "Error extracting default acl from toc"); 215 xar_err_set_file(x, f); 216 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 217 } else { 218 if( acl_set_file(file, ACL_TYPE_DEFAULT, a) != 0 ) { 219 xar_err_new(x); 220 xar_err_set_errno(x, errno); 221 xar_err_set_string(x, "Error setting default acl"); 222 xar_err_set_file(x, f); 223 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 224 } 225 } 226 } 227 228 xar_prop_get(f, "acl/access", &t); 229 if( t ) { 230 a = acl_from_text(t); 231 if( !a ) { 232 xar_err_new(x); 233 xar_err_set_errno(x, errno); 234 xar_err_set_string(x, "Error extracting access acl from toc"); 235 xar_err_set_file(x, f); 236 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 237 } else { 238 if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { 239 xar_err_new(x); 240 xar_err_set_errno(x, errno); 241 xar_err_set_string(x, "Error setting access acl"); 242 xar_err_set_file(x, f); 243 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 244 } 245 acl_free(a); 246 } 247 } 248#else /* !__APPLE__ */ 249 const char *t; 250 acl_t a; 251 252 xar_prop_get(f, "acl/appleextended", &t); 253 if( t ) { 254 a = acl_from_text(t); 255 if( !a ) { 256 xar_err_new(x); 257 xar_err_set_errno(x, errno); 258 xar_err_set_string(x, "Error extracting access acl from toc"); 259 xar_err_set_file(x, f); 260 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 261 } else { 262 if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { 263 xar_err_new(x); 264 xar_err_set_errno(x, errno); 265 xar_err_set_string(x, "Error setting access acl"); 266 xar_err_set_file(x, f); 267 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 268 } 269 acl_free(a); 270 } 271 } 272#endif /* !__APPLE__ */ 273#endif 274 return 0; 275} 276 277#ifdef HAVE_STRUCT_STAT_ST_FLAGS 278#define XAR_FLAG_FORK "flags" 279static void x_addflag(xar_file_t f, const char *name) { 280 char opt[1024]; 281 memset(opt, 0, sizeof(opt)); 282 snprintf(opt, sizeof(opt)-1, "%s/%s", XAR_FLAG_FORK, name); 283 xar_prop_set(f, opt, NULL); 284 return; 285} 286#endif 287 288static int32_t flags_archive(xar_t x, xar_file_t f, const struct stat *sb) { 289#ifdef HAVE_STRUCT_STAT_ST_FLAGS 290 if( !sb->st_flags ) 291 return 0; 292 293 if( !xar_check_prop(x, XAR_FLAG_FORK) ) 294 return 0; 295#ifdef UF_NODUMP 296 if( sb->st_flags & UF_NODUMP ) 297 x_addflag(f, "UserNoDump"); 298#endif 299#ifdef UF_IMMUTABLE 300 if( sb->st_flags & UF_IMMUTABLE ) 301 x_addflag(f, "UserImmutable"); 302#endif 303#ifdef UF_APPEND 304 if( sb->st_flags & UF_APPEND ) 305 x_addflag(f, "UserAppend"); 306#endif 307#ifdef UF_OPAQUE 308 if( sb->st_flags & UF_OPAQUE ) 309 x_addflag(f, "UserOpaque"); 310#endif 311#ifdef SF_ARCHIVED 312 if( sb->st_flags & SF_ARCHIVED ) 313 x_addflag(f, "SystemArchived"); 314#endif 315#ifdef SF_IMMUTABLE 316 if( sb->st_flags & SF_IMMUTABLE ) 317 x_addflag(f, "SystemImmutable"); 318#endif 319#ifdef SF_APPEND 320 if( sb->st_flags & SF_APPEND ) 321 x_addflag(f, "SystemAppend"); 322#endif 323 324#endif /* HAVE_STRUCT_STAT_ST_FLAGS */ 325 return 0; 326} 327 328#ifdef HAVE_CHFLAGS 329static int32_t x_getprop(xar_file_t f, const char *name, char **value) { 330 char v[1024]; 331 memset(v, 0, sizeof(v)); 332 snprintf(v, sizeof(v)-1, "%s/%s", XAR_FLAG_FORK, name); 333 return xar_prop_get(f, v, (const char **)value); 334} 335#endif 336 337int32_t xar_flags_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { 338#ifdef HAVE_CHFLAGS 339 char *tmp; 340 u_int flags = 0; 341 342 if( xar_prop_get(f, XAR_FLAG_FORK, NULL) ) 343 return 0; 344 345#ifdef UF_NODUMP 346 if( x_getprop(f, "UserNoDump", (char **)&tmp) == 0 ) 347 flags |= UF_NODUMP; 348#endif 349#ifdef UF_IMMUTABLE 350 if( x_getprop(f, "UserImmutable", (char **)&tmp) == 0 ) 351 flags |= UF_IMMUTABLE; 352#endif 353#ifdef UF_APPEND 354 if( x_getprop(f, "UserAppend", (char **)&tmp) == 0 ) 355 flags |= UF_APPEND; 356#endif 357#ifdef UF_OPAQUE 358 if( x_getprop(f, "UserOpaque", (char **)&tmp) == 0 ) 359 flags |= UF_OPAQUE; 360#endif 361#ifdef SF_ARCHIVED 362 if( x_getprop(f, "SystemArchived", (char **)&tmp) == 0 ) 363 flags |= SF_ARCHIVED; 364#endif 365#ifdef SF_IMMUTABLE 366 if( x_getprop(f, "SystemImmutable", (char **)&tmp) == 0 ) 367 flags |= SF_IMMUTABLE; 368#endif 369#ifdef SF_APPEND 370 if( x_getprop(f, "SystemAppend", (char **)&tmp) == 0 ) 371 flags |= SF_APPEND; 372#endif 373 374 if( !flags ) 375 return 0; 376 377 if( chflags(file, flags) != 0 ) { 378 char e[1024]; 379 memset(e, 0, sizeof(e)); 380 snprintf(e, sizeof(e)-1, "chflags: %s", strerror(errno)); 381 xar_err_new(x); 382 xar_err_set_file(x, f); 383 xar_err_set_string(x, e); 384 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 385 return -1; 386 } 387#endif 388 389 return 0; 390} 391 392int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) { 393 char *tmpstr; 394 struct passwd *pw; 395 struct group *gr; 396 char time[128]; 397 struct tm t; 398 const char *type; 399 400 /* no stat attributes for data from a buffer, it is just a file */ 401 if(len){ 402 if( xar_check_prop(x, "type") ) 403 xar_prop_set(f, "type", "file"); 404 return 0; 405 } 406 407 if( S_ISREG(XAR(x)->sbcache.st_mode) && (XAR(x)->sbcache.st_nlink > 1) ) { 408 xar_file_t tmpf; 409 const char *id = xar_attr_get(f, NULL, "id"); 410 if( !id ) { 411 xar_err_new(x); 412 xar_err_set_file(x, f); 413 xar_err_set_string(x, "stat: No file id for file"); 414 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_CREATION); 415 return -1; 416 } 417 tmpf = xar_link_lookup(x, XAR(x)->sbcache.st_dev, XAR(x)->sbcache.st_ino, f); 418 if( xar_check_prop(x, "type") ) { 419 xar_prop_set(f, "type", "hardlink"); 420 if( tmpf ) { 421 const char *id; 422 id = xar_attr_get(tmpf, NULL, "id"); 423 xar_attr_set(f, "type", "link", id); 424 } else { 425 xar_attr_set(f, "type", "link", "original"); 426 } 427 } 428 } else { 429 type = filetype_name(XAR(x)->sbcache.st_mode & S_IFMT); 430 if( xar_check_prop(x, "type") ) 431 xar_prop_set(f, "type", type); 432 } 433 434 /* Record major/minor device node numbers */ 435 if( xar_check_prop(x, "device") && (S_ISBLK(XAR(x)->sbcache.st_mode) || S_ISCHR(XAR(x)->sbcache.st_mode))) { 436 uint32_t major, minor; 437 char tmpstr[12]; 438 xar_devmake(XAR(x)->sbcache.st_rdev, &major, &minor); 439 memset(tmpstr, 0, sizeof(tmpstr)); 440 snprintf(tmpstr, sizeof(tmpstr)-1, "%u", major); 441 xar_prop_set(f, "device/major", tmpstr); 442 memset(tmpstr, 0, sizeof(tmpstr)); 443 snprintf(tmpstr, sizeof(tmpstr)-1, "%u", minor); 444 xar_prop_set(f, "device/minor", tmpstr); 445 } 446 447 if( S_ISLNK(XAR(x)->sbcache.st_mode) ) { 448 char link[4096]; 449 struct stat lsb; 450 451 memset(link, 0, sizeof(link)); 452 readlink(file, link, sizeof(link)-1); 453 xar_prop_set(f, "link", link); 454 if( stat(file, &lsb) != 0 ) { 455 xar_attr_set(f, "link", "type", "broken"); 456 } else { 457 type = filetype_name(lsb.st_mode & S_IFMT); 458 xar_attr_set(f, "link", "type", type); 459 } 460 } 461 462 if( xar_check_prop(x, "inode") ) { 463 asprintf(&tmpstr, "%"INO_STRING, XAR(x)->sbcache.st_ino); 464 xar_prop_set(f, "inode", tmpstr); 465 free(tmpstr); 466 } 467 468 if( xar_check_prop(x, "deviceno") ) { 469 asprintf(&tmpstr, "%"DEV_STRING, XAR(x)->sbcache.st_dev); 470 xar_prop_set(f, "deviceno", tmpstr); 471 free(tmpstr); 472 } 473 474 if( xar_check_prop(x, "mode") ) { 475 asprintf(&tmpstr, "%04o", XAR(x)->sbcache.st_mode & (~S_IFMT)); 476 xar_prop_set(f, "mode", tmpstr); 477 free(tmpstr); 478 } 479 480 if( xar_check_prop(x, "uid") ) { 481 asprintf(&tmpstr, "%"PRIu64, (uint64_t)XAR(x)->sbcache.st_uid); 482 xar_prop_set(f, "uid", tmpstr); 483 free(tmpstr); 484 } 485 486 if( xar_check_prop(x, "user") ) { 487 pw = getpwuid(XAR(x)->sbcache.st_uid); 488 if( pw ) 489 xar_prop_set(f, "user", pw->pw_name); 490 } 491 492 if( xar_check_prop(x, "gid") ) { 493 asprintf(&tmpstr, "%"PRIu64, (uint64_t)XAR(x)->sbcache.st_gid); 494 xar_prop_set(f, "gid", tmpstr); 495 free(tmpstr); 496 } 497 498 if( xar_check_prop(x, "group") ) { 499 gr = getgrgid(XAR(x)->sbcache.st_gid); 500 if( gr ) 501 xar_prop_set(f, "group", gr->gr_name); 502 } 503 504 if( xar_check_prop(x, "atime") ) { 505 gmtime_r(&XAR(x)->sbcache.st_atime, &t); 506 memset(time, 0, sizeof(time)); 507 strftime(time, sizeof(time), "%FT%T", &t); 508 strcat(time, "Z"); 509 xar_prop_set(f, "atime", time); 510 } 511 512 if( xar_check_prop(x, "mtime") ) { 513 gmtime_r(&XAR(x)->sbcache.st_mtime, &t); 514 memset(time, 0, sizeof(time)); 515 strftime(time, sizeof(time), "%FT%T", &t); 516 strcat(time, "Z"); 517 xar_prop_set(f, "mtime", time); 518 } 519 520 if( xar_check_prop(x, "ctime") ) { 521 gmtime_r(&XAR(x)->sbcache.st_ctime, &t); 522 memset(time, 0, sizeof(time)); 523 strftime(time, sizeof(time), "%FT%T", &t); 524 strcat(time, "Z"); 525 xar_prop_set(f, "ctime", time); 526 } 527 528 flags_archive(x, f, &(XAR(x)->sbcache)); 529 530 aacls(x, f, file); 531 532 return 0; 533} 534 535int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { 536 const char *opt; 537 int32_t m=0, mset=0; 538 uid_t u; 539 gid_t g; 540 const char *timestr; 541 struct tm t; 542 enum {ATIME=0, MTIME}; 543 struct timeval tv[2]; 544 char savesuid = 0; 545 546 /* when writing to a buffer, there are no permissions to set */ 547 if ( len ) 548 return 0; 549 550 /* in case we don't find anything useful in the archive */ 551 u = geteuid(); 552 g = getegid(); 553 554 opt = xar_opt_get(x, XAR_OPT_OWNERSHIP); 555 if( opt && (strcmp(opt, XAR_OPT_VAL_SYMBOLIC) == 0) ) { 556 struct passwd *pw; 557 struct group *gr; 558 559 xar_prop_get(f, "user", &opt); 560 if( opt ) { 561 pw = getpwnam(opt); 562 if( pw ) { 563 u = pw->pw_uid; 564 } 565 } 566 xar_prop_get(f, "group", &opt); 567 if( opt ) { 568 gr = getgrnam(opt); 569 if( gr ) { 570 g = gr->gr_gid; 571 } 572 } 573 savesuid = 1; 574 } 575 if( opt && (strcmp(opt, XAR_OPT_VAL_NUMERIC) == 0) ) { 576 xar_prop_get(f, "uid", &opt); 577 if( opt ) { 578 long long tmp; 579 tmp = strtol(opt, NULL, 10); 580 if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { 581 return -1; 582 } 583 u = (uid_t)tmp; 584 } 585 586 xar_prop_get(f, "gid", &opt); 587 if( opt ) { 588 long long tmp; 589 tmp = strtol(opt, NULL, 10); 590 if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { 591 return -1; 592 } 593 g = (gid_t)tmp; 594 } 595 savesuid = 1; 596 } 597 598 opt = xar_opt_get(x, XAR_OPT_SAVESUID); 599 if( opt && (strcmp(opt, XAR_OPT_VAL_TRUE) == 0) ) { 600 savesuid = 1; 601 } 602 603 xar_prop_get(f, "mode", &opt); 604 if( opt ) { 605 long long tmp; 606 tmp = strtoll(opt, NULL, 8); 607 if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { 608 return -1; 609 } 610 m = (mode_t)tmp; 611 if( !savesuid ) { 612 m &= ~S_ISUID; 613 m &= ~S_ISGID; 614 } 615 mset = 1; 616 } 617 618 xar_prop_get(f, "type", &opt); 619 if( opt && !mset ) { 620 mode_t u = umask(0); 621 umask(u); 622 if( strcmp(opt, "directory") == 0 ) { 623 m = (mode_t)(0777 & ~u); 624 } else { 625 m = (mode_t)(0666 & ~u); 626 } 627 mset = 1; 628 } 629 if( opt && (strcmp(opt, "symlink") == 0) ) { 630#ifdef HAVE_LCHOWN 631 if( lchown(file, u, g) ) { 632 xar_err_new(x); 633 xar_err_set_file(x, f); 634 xar_err_set_string(x, "perm: could not lchown symlink"); 635 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 636 m &= ~S_ISUID; 637 m &= ~S_ISGID; 638 } 639#ifdef HAVE_LCHMOD 640 if( mset ) 641 if( lchmod(file, m) ) { 642 xar_err_new(x); 643 xar_err_set_file(x, f); 644 xar_err_set_string(x, "perm: could not lchmod symlink"); 645 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 646 } 647#endif 648#endif 649 } else { 650 if( chown(file, u, g) ) { 651 xar_err_new(x); 652 xar_err_set_file(x, f); 653 xar_err_set_string(x, "perm: could not chown file"); 654 xar_err_set_errno(x, errno); 655 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 656 m &= ~S_ISUID; 657 m &= ~S_ISGID; 658 } 659 if( mset ) 660 if( chmod(file, m) ) { 661 xar_err_new(x); 662 xar_err_set_file(x, f); 663 xar_err_set_string(x, "perm: could not chmod file"); 664 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 665 } 666 } 667 668 eacls(x, f, file); 669 670 memset(tv, 0, sizeof(struct timeval) * 2); 671 xar_prop_get(f, "atime", ×tr); 672 if( timestr ) { 673 memset(&t, 0, sizeof(t)); 674 strptime(timestr, "%FT%T", &t); 675 tv[ATIME].tv_sec = timegm(&t); 676 } else { 677 tv[ATIME].tv_sec = time(NULL); 678 } 679 680 xar_prop_get(f, "mtime", ×tr); 681 if( timestr ) { 682 memset(&t, 0, sizeof(t)); 683 strptime(timestr, "%FT%T", &t); 684 tv[MTIME].tv_sec = timegm(&t); 685 } else { 686 tv[MTIME].tv_sec = time(NULL); 687 } 688 utimes(file, tv); 689 690 return 0; 691} 692 693int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { 694 const char *opt; 695 int ret, fd; 696 mode_t modet = 0; 697 698 xar_prop_get(f, "type", &opt); 699 if(opt && (strcmp(opt, "character special") == 0)) 700 modet = S_IFCHR; 701 if(opt && (strcmp(opt, "block special") == 0)) 702 modet = S_IFBLK; 703 704 if( modet ) { 705 uint32_t major, minor; 706 long long tmpll; 707 dev_t devt; 708 709 xar_prop_get(f, "device/major", &opt); 710 tmpll = strtoll(opt, NULL, 10); 711 if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) 712 return -1; 713 if( (tmpll < 0) || (tmpll > 255) ) 714 return -1; 715 major = tmpll; 716 717 xar_prop_get(f, "device/minor", &opt); 718 tmpll = strtoll(opt, NULL, 10); 719 if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) 720 return -1; 721 if( (tmpll < 0) || (tmpll > 255) ) 722 return -1; 723 minor = tmpll; 724 725 devt = xar_makedev(major, minor); 726 unlink(file); 727 if( mknod(file, modet, devt) ) { 728 xar_err_new(x); 729 xar_err_set_file(x, f); 730 xar_err_set_string(x, "mknod: Could not create character device"); 731 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 732 return -1; 733 } 734 return 0; 735 } 736 if(opt && (strcmp(opt, "directory") == 0)) { 737 ret = mkdir(file, 0700); 738 if( (ret != 0) && (errno != EEXIST) ) { 739 xar_err_new(x); 740 xar_err_set_file(x, f); 741 xar_err_set_string(x, "stat: Could not create directory"); 742 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 743 return ret; 744 } 745 return 0; 746 } 747 if(opt && (strcmp(opt, "symlink") == 0)) { 748 xar_prop_get(f, "link", &opt); 749 if( opt ) { 750 unlink(file); 751 ret = symlink(opt, file); 752 if( ret != 0 ) { 753 xar_err_new(x); 754 xar_err_set_file(x, f); 755 xar_err_set_string(x, "stat: Could not create symlink"); 756 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 757 } 758 return ret; 759 } 760 } 761 if(opt && (strcmp(opt, "hardlink") == 0)) { 762 xar_file_t tmpf; 763 opt = xar_attr_get(f, "type", "link"); 764 if( !opt ) 765 return 0; 766 if( strcmp(opt, "original") == 0 ) 767 goto CREATEFILE; 768 769 tmpf = xmlHashLookup(XAR(x)->link_hash, BAD_CAST(opt)); 770 if( !tmpf ) { 771 xar_err_new(x); 772 xar_err_set_file(x, f); 773 xar_err_set_string(x, "stat: Encountered hardlink with no original"); 774 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 775 return -1; 776 } 777 778 unlink(file); 779 if( link(XAR_FILE(tmpf)->fspath, file) != 0 ) { 780 if( errno == ENOENT ) { 781 xar_iter_t i; 782 const char *ptr; 783 i = xar_iter_new(); 784 for(ptr = xar_prop_first(tmpf, i); ptr; ptr = xar_prop_next(i)) { 785 xar_iter_t a; 786 const char *val = NULL; 787 const char *akey, *aval; 788 if( strncmp("data", ptr, 4) != 0 ) 789 continue; 790 791 if( xar_prop_get(tmpf, ptr, &val) ) 792 continue; 793 794 xar_prop_set(f, ptr, val); 795 a = xar_iter_new(); 796 for(akey = xar_attr_first(tmpf, ptr, a); akey; akey = xar_attr_next(a)) { 797 aval = xar_attr_get(tmpf, ptr, akey); 798 xar_attr_set(f, ptr, akey, aval); 799 } 800 xar_iter_free(a); 801 } 802 xar_iter_free(i); 803 xar_attr_set(f, "type", "link", "original"); 804 return 0; 805 } else { 806 xar_err_new(x); 807 xar_err_set_file(x, f); 808 xar_err_set_string(x, "stat: Could not link hardlink to original"); 809 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 810 return -1; 811 } 812 } 813 return 0; 814 } 815 816 if(opt && (strcmp(opt, "fifo") == 0)) { 817 unlink(file); 818 if( mkfifo(file, 0) ) { 819 xar_err_new(x); 820 xar_err_set_file(x, f); 821 xar_err_set_string(x, "mkfifo: Could not create fifo"); 822 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 823 return -1; 824 } 825 return 0; 826 } 827 828 /* skip sockets */ 829 if(opt && (strcmp(opt, "socket") == 0)) { 830 return 0; 831 } 832 833CREATEFILE: 834 if (!file) 835 return 0; 836 837 unlink(file); 838 fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600); 839 if( fd > 0 ) 840 close(fd); 841 return 0; 842} 843