1 /*- 2 * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA 3 * Copyright (c) 2003-2007 Tim Kientzle 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD$"); 29 30 #ifdef HAVE_SYS_TYPES_H 31 #include <sys/types.h> 32 #endif 33 #ifdef HAVE_ERRNO_H 34 #include <errno.h> 35 #endif 36 #ifdef HAVE_FCNTL_H 37 #include <fcntl.h> 38 #endif 39 #ifdef HAVE_STDLIB_H 40 #include <stdlib.h> 41 #endif 42 #ifdef HAVE_STRING_H 43 #include <string.h> 44 #endif 45 #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) 46 #include <wincrypt.h> 47 #endif 48 #ifdef HAVE_ZLIB_H 49 #include <zlib.h> 50 #endif 51 #ifdef HAVE_LZMA_H 52 #include <lzma.h> 53 #endif 54 #ifdef HAVE_BZLIB_H 55 #include <bzlib.h> 56 #endif 57 #ifdef HAVE_LZ4_H 58 #include <lz4.h> 59 #endif 60 61 #include "archive.h" 62 #include "archive_private.h" 63 #include "archive_random_private.h" 64 #include "archive_string.h" 65 66 #ifndef O_CLOEXEC 67 #define O_CLOEXEC 0 68 #endif 69 70 static int archive_utility_string_sort_helper(char **, unsigned int); 71 72 /* Generic initialization of 'struct archive' objects. */ 73 int 74 __archive_clean(struct archive *a) 75 { 76 archive_string_conversion_free(a); 77 return (ARCHIVE_OK); 78 } 79 80 int 81 archive_version_number(void) 82 { 83 return (ARCHIVE_VERSION_NUMBER); 84 } 85 86 const char * 87 archive_version_string(void) 88 { 89 return (ARCHIVE_VERSION_STRING); 90 } 91 92 const char * 93 archive_version_details(void) 94 { 95 static struct archive_string str; 96 static int init = 0; 97 const char *zlib = archive_zlib_version(); 98 const char *liblzma = archive_liblzma_version(); 99 const char *bzlib = archive_bzlib_version(); 100 const char *liblz4 = archive_liblz4_version(); 101 102 if (!init) { 103 archive_string_init(&str); 104 105 archive_strcat(&str, ARCHIVE_VERSION_STRING); 106 if (zlib != NULL) { 107 archive_strcat(&str, " zlib/"); 108 archive_strcat(&str, zlib); 109 } 110 if (liblzma) { 111 archive_strcat(&str, " liblzma/"); 112 archive_strcat(&str, liblzma); 113 } 114 if (bzlib) { 115 const char *p = bzlib; 116 const char *sep = strchr(p, ','); 117 if (sep == NULL) 118 sep = p + strlen(p); 119 archive_strcat(&str, " bz2lib/"); 120 archive_strncat(&str, p, sep - p); 121 } 122 if (liblz4) { 123 archive_strcat(&str, " liblz4/"); 124 archive_strcat(&str, liblz4); 125 } 126 } 127 return str.s; 128 } 129 130 const char * 131 archive_zlib_version(void) 132 { 133 #ifdef HAVE_ZLIB_H 134 return ZLIB_VERSION; 135 #else 136 return NULL; 137 #endif 138 } 139 140 const char * 141 archive_liblzma_version(void) 142 { 143 #ifdef HAVE_LZMA_H 144 return LZMA_VERSION_STRING; 145 #else 146 return NULL; 147 #endif 148 } 149 150 const char * 151 archive_bzlib_version(void) 152 { 153 #ifdef HAVE_BZLIB_H 154 return BZ2_bzlibVersion(); 155 #else 156 return NULL; 157 #endif 158 } 159 160 const char * 161 archive_liblz4_version(void) 162 { 163 #if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) 164 #define str(s) #s 165 #define NUMBER(x) str(x) 166 return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE); 167 #undef NUMBER 168 #undef str 169 #else 170 return NULL; 171 #endif 172 } 173 174 int 175 archive_errno(struct archive *a) 176 { 177 return (a->archive_error_number); 178 } 179 180 const char * 181 archive_error_string(struct archive *a) 182 { 183 184 if (a->error != NULL && *a->error != '\0') 185 return (a->error); 186 else 187 return (NULL); 188 } 189 190 int 191 archive_file_count(struct archive *a) 192 { 193 return (a->file_count); 194 } 195 196 int 197 archive_format(struct archive *a) 198 { 199 return (a->archive_format); 200 } 201 202 const char * 203 archive_format_name(struct archive *a) 204 { 205 return (a->archive_format_name); 206 } 207 208 209 int 210 archive_compression(struct archive *a) 211 { 212 return archive_filter_code(a, 0); 213 } 214 215 const char * 216 archive_compression_name(struct archive *a) 217 { 218 return archive_filter_name(a, 0); 219 } 220 221 222 /* 223 * Return a count of the number of compressed bytes processed. 224 */ 225 int64_t 226 archive_position_compressed(struct archive *a) 227 { 228 return archive_filter_bytes(a, -1); 229 } 230 231 /* 232 * Return a count of the number of uncompressed bytes processed. 233 */ 234 int64_t 235 archive_position_uncompressed(struct archive *a) 236 { 237 return archive_filter_bytes(a, 0); 238 } 239 240 void 241 archive_clear_error(struct archive *a) 242 { 243 archive_string_empty(&a->error_string); 244 a->error = NULL; 245 a->archive_error_number = 0; 246 } 247 248 void 249 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 250 { 251 va_list ap; 252 253 a->archive_error_number = error_number; 254 if (fmt == NULL) { 255 a->error = NULL; 256 return; 257 } 258 259 archive_string_empty(&(a->error_string)); 260 va_start(ap, fmt); 261 archive_string_vsprintf(&(a->error_string), fmt, ap); 262 va_end(ap); 263 a->error = a->error_string.s; 264 } 265 266 void 267 archive_copy_error(struct archive *dest, struct archive *src) 268 { 269 dest->archive_error_number = src->archive_error_number; 270 271 archive_string_copy(&dest->error_string, &src->error_string); 272 dest->error = dest->error_string.s; 273 } 274 275 void 276 __archive_errx(int retvalue, const char *msg) 277 { 278 static const char *msg1 = "Fatal Internal Error in libarchive: "; 279 size_t s; 280 281 s = write(2, msg1, strlen(msg1)); 282 (void)s; /* UNUSED */ 283 s = write(2, msg, strlen(msg)); 284 (void)s; /* UNUSED */ 285 s = write(2, "\n", 1); 286 (void)s; /* UNUSED */ 287 exit(retvalue); 288 } 289 290 /* 291 * Create a temporary file 292 */ 293 #if defined(_WIN32) && !defined(__CYGWIN__) 294 295 /* 296 * Do not use Windows tmpfile() function. 297 * It will make a temporary file under the root directory 298 * and it'll cause permission error if a user who is 299 * non-Administrator creates temporary files. 300 * Also Windows version of mktemp family including _mktemp_s 301 * are not secure. 302 */ 303 int 304 __archive_mktemp(const char *tmpdir) 305 { 306 static const wchar_t *prefix = L"libarchive_"; 307 static const wchar_t *suffix = L"XXXXXXXXXX"; 308 static const wchar_t num[] = { 309 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 310 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 311 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 312 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 313 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 314 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 315 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 316 L'u', L'v', L'w', L'x', L'y', L'z' 317 }; 318 HCRYPTPROV hProv; 319 struct archive_wstring temp_name; 320 wchar_t *ws; 321 DWORD attr; 322 wchar_t *xp, *ep; 323 int fd; 324 325 hProv = (HCRYPTPROV)NULL; 326 fd = -1; 327 ws = NULL; 328 archive_string_init(&temp_name); 329 330 /* Get a temporary directory. */ 331 if (tmpdir == NULL) { 332 size_t l; 333 wchar_t *tmp; 334 335 l = GetTempPathW(0, NULL); 336 if (l == 0) { 337 la_dosmaperr(GetLastError()); 338 goto exit_tmpfile; 339 } 340 tmp = malloc(l*sizeof(wchar_t)); 341 if (tmp == NULL) { 342 errno = ENOMEM; 343 goto exit_tmpfile; 344 } 345 GetTempPathW((DWORD)l, tmp); 346 archive_wstrcpy(&temp_name, tmp); 347 free(tmp); 348 } else { 349 if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 350 strlen(tmpdir)) < 0) 351 goto exit_tmpfile; 352 if (temp_name.s[temp_name.length-1] != L'/') 353 archive_wstrappend_wchar(&temp_name, L'/'); 354 } 355 356 /* Check if temp_name is a directory. */ 357 attr = GetFileAttributesW(temp_name.s); 358 if (attr == (DWORD)-1) { 359 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 360 la_dosmaperr(GetLastError()); 361 goto exit_tmpfile; 362 } 363 ws = __la_win_permissive_name_w(temp_name.s); 364 if (ws == NULL) { 365 errno = EINVAL; 366 goto exit_tmpfile; 367 } 368 attr = GetFileAttributesW(ws); 369 if (attr == (DWORD)-1) { 370 la_dosmaperr(GetLastError()); 371 goto exit_tmpfile; 372 } 373 } 374 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 375 errno = ENOTDIR; 376 goto exit_tmpfile; 377 } 378 379 /* 380 * Create a temporary file. 381 */ 382 archive_wstrcat(&temp_name, prefix); 383 archive_wstrcat(&temp_name, suffix); 384 ep = temp_name.s + archive_strlen(&temp_name); 385 xp = ep - wcslen(suffix); 386 387 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 388 CRYPT_VERIFYCONTEXT)) { 389 la_dosmaperr(GetLastError()); 390 goto exit_tmpfile; 391 } 392 393 for (;;) { 394 wchar_t *p; 395 HANDLE h; 396 397 /* Generate a random file name through CryptGenRandom(). */ 398 p = xp; 399 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 400 (BYTE*)p)) { 401 la_dosmaperr(GetLastError()); 402 goto exit_tmpfile; 403 } 404 for (; p < ep; p++) 405 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 406 407 free(ws); 408 ws = __la_win_permissive_name_w(temp_name.s); 409 if (ws == NULL) { 410 errno = EINVAL; 411 goto exit_tmpfile; 412 } 413 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 414 * delete this temporary file immediately when this 415 * file closed. */ 416 h = CreateFileW(ws, 417 GENERIC_READ | GENERIC_WRITE | DELETE, 418 0,/* Not share */ 419 NULL, 420 CREATE_NEW,/* Create a new file only */ 421 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 422 NULL); 423 if (h == INVALID_HANDLE_VALUE) { 424 /* The same file already exists. retry with 425 * a new filename. */ 426 if (GetLastError() == ERROR_FILE_EXISTS) 427 continue; 428 /* Otherwise, fail creation temporary file. */ 429 la_dosmaperr(GetLastError()); 430 goto exit_tmpfile; 431 } 432 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 433 if (fd == -1) { 434 CloseHandle(h); 435 goto exit_tmpfile; 436 } else 437 break;/* success! */ 438 } 439 exit_tmpfile: 440 if (hProv != (HCRYPTPROV)NULL) 441 CryptReleaseContext(hProv, 0); 442 free(ws); 443 archive_wstring_free(&temp_name); 444 return (fd); 445 } 446 447 #else 448 449 static int 450 get_tempdir(struct archive_string *temppath) 451 { 452 const char *tmp; 453 454 tmp = getenv("TMPDIR"); 455 if (tmp == NULL) 456 #ifdef _PATH_TMP 457 tmp = _PATH_TMP; 458 #else 459 tmp = "/tmp"; 460 #endif 461 archive_strcpy(temppath, tmp); 462 if (temppath->s[temppath->length-1] != '/') 463 archive_strappend_char(temppath, '/'); 464 return (ARCHIVE_OK); 465 } 466 467 #if defined(HAVE_MKSTEMP) 468 469 /* 470 * We can use mkstemp(). 471 */ 472 473 int 474 __archive_mktemp(const char *tmpdir) 475 { 476 struct archive_string temp_name; 477 int fd = -1; 478 479 archive_string_init(&temp_name); 480 if (tmpdir == NULL) { 481 if (get_tempdir(&temp_name) != ARCHIVE_OK) 482 goto exit_tmpfile; 483 } else { 484 archive_strcpy(&temp_name, tmpdir); 485 if (temp_name.s[temp_name.length-1] != '/') 486 archive_strappend_char(&temp_name, '/'); 487 } 488 archive_strcat(&temp_name, "libarchive_XXXXXX"); 489 fd = mkstemp(temp_name.s); 490 if (fd < 0) 491 goto exit_tmpfile; 492 __archive_ensure_cloexec_flag(fd); 493 unlink(temp_name.s); 494 exit_tmpfile: 495 archive_string_free(&temp_name); 496 return (fd); 497 } 498 499 #else 500 501 /* 502 * We use a private routine. 503 */ 504 505 int 506 __archive_mktemp(const char *tmpdir) 507 { 508 static const char num[] = { 509 '0', '1', '2', '3', '4', '5', '6', '7', 510 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 511 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 512 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 513 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 514 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 515 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 516 'u', 'v', 'w', 'x', 'y', 'z' 517 }; 518 struct archive_string temp_name; 519 struct stat st; 520 int fd; 521 char *tp, *ep; 522 523 fd = -1; 524 archive_string_init(&temp_name); 525 if (tmpdir == NULL) { 526 if (get_tempdir(&temp_name) != ARCHIVE_OK) 527 goto exit_tmpfile; 528 } else 529 archive_strcpy(&temp_name, tmpdir); 530 if (temp_name.s[temp_name.length-1] == '/') { 531 temp_name.s[temp_name.length-1] = '\0'; 532 temp_name.length --; 533 } 534 if (stat(temp_name.s, &st) < 0) 535 goto exit_tmpfile; 536 if (!S_ISDIR(st.st_mode)) { 537 errno = ENOTDIR; 538 goto exit_tmpfile; 539 } 540 archive_strcat(&temp_name, "/libarchive_"); 541 tp = temp_name.s + archive_strlen(&temp_name); 542 archive_strcat(&temp_name, "XXXXXXXXXX"); 543 ep = temp_name.s + archive_strlen(&temp_name); 544 545 do { 546 char *p; 547 548 p = tp; 549 archive_random(p, ep - p); 550 while (p < ep) { 551 int d = *((unsigned char *)p) % sizeof(num); 552 *p++ = num[d]; 553 } 554 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 555 0600); 556 } while (fd < 0 && errno == EEXIST); 557 if (fd < 0) 558 goto exit_tmpfile; 559 __archive_ensure_cloexec_flag(fd); 560 unlink(temp_name.s); 561 exit_tmpfile: 562 archive_string_free(&temp_name); 563 return (fd); 564 } 565 566 #endif /* HAVE_MKSTEMP */ 567 #endif /* !_WIN32 || __CYGWIN__ */ 568 569 /* 570 * Set FD_CLOEXEC flag to a file descriptor if it is not set. 571 * We have to set the flag if the platform does not provide O_CLOEXEC 572 * or F_DUPFD_CLOEXEC flags. 573 * 574 * Note: This function is absolutely called after creating a new file 575 * descriptor even if the platform seemingly provides O_CLOEXEC or 576 * F_DUPFD_CLOEXEC macros because it is possible that the platform 577 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 578 */ 579 void 580 __archive_ensure_cloexec_flag(int fd) 581 { 582 #if defined(_WIN32) && !defined(__CYGWIN__) 583 (void)fd; /* UNUSED */ 584 #else 585 int flags; 586 587 if (fd >= 0) { 588 flags = fcntl(fd, F_GETFD); 589 if (flags != -1 && (flags & FD_CLOEXEC) == 0) 590 fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 591 } 592 #endif 593 } 594 595 /* 596 * Utility function to sort a group of strings using quicksort. 597 */ 598 static int 599 archive_utility_string_sort_helper(char **strings, unsigned int n) 600 { 601 unsigned int i, lesser_count, greater_count; 602 char **lesser, **greater, **tmp, *pivot; 603 int retval1, retval2; 604 605 /* A list of 0 or 1 elements is already sorted */ 606 if (n <= 1) 607 return (ARCHIVE_OK); 608 609 lesser_count = greater_count = 0; 610 lesser = greater = NULL; 611 pivot = strings[0]; 612 for (i = 1; i < n; i++) 613 { 614 if (strcmp(strings[i], pivot) < 0) 615 { 616 lesser_count++; 617 tmp = (char **)realloc(lesser, 618 lesser_count * sizeof(char *)); 619 if (!tmp) { 620 free(greater); 621 free(lesser); 622 return (ARCHIVE_FATAL); 623 } 624 lesser = tmp; 625 lesser[lesser_count - 1] = strings[i]; 626 } 627 else 628 { 629 greater_count++; 630 tmp = (char **)realloc(greater, 631 greater_count * sizeof(char *)); 632 if (!tmp) { 633 free(greater); 634 free(lesser); 635 return (ARCHIVE_FATAL); 636 } 637 greater = tmp; 638 greater[greater_count - 1] = strings[i]; 639 } 640 } 641 642 /* quicksort(lesser) */ 643 retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 644 for (i = 0; i < lesser_count; i++) 645 strings[i] = lesser[i]; 646 free(lesser); 647 648 /* pivot */ 649 strings[lesser_count] = pivot; 650 651 /* quicksort(greater) */ 652 retval2 = archive_utility_string_sort_helper(greater, greater_count); 653 for (i = 0; i < greater_count; i++) 654 strings[lesser_count + 1 + i] = greater[i]; 655 free(greater); 656 657 return (retval1 < retval2) ? retval1 : retval2; 658 } 659 660 int 661 archive_utility_string_sort(char **strings) 662 { 663 unsigned int size = 0; 664 while (strings[size] != NULL) 665 size++; 666 return archive_utility_string_sort_helper(strings, size); 667 } 668