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 int 93 archive_errno(struct archive *a) 94 { 95 return (a->archive_error_number); 96 } 97 98 const char * 99 archive_error_string(struct archive *a) 100 { 101 102 if (a->error != NULL && *a->error != '\0') 103 return (a->error); 104 else 105 return (NULL); 106 } 107 108 int 109 archive_file_count(struct archive *a) 110 { 111 return (a->file_count); 112 } 113 114 int 115 archive_format(struct archive *a) 116 { 117 return (a->archive_format); 118 } 119 120 const char * 121 archive_format_name(struct archive *a) 122 { 123 return (a->archive_format_name); 124 } 125 126 127 int 128 archive_compression(struct archive *a) 129 { 130 return archive_filter_code(a, 0); 131 } 132 133 const char * 134 archive_compression_name(struct archive *a) 135 { 136 return archive_filter_name(a, 0); 137 } 138 139 140 /* 141 * Return a count of the number of compressed bytes processed. 142 */ 143 int64_t 144 archive_position_compressed(struct archive *a) 145 { 146 return archive_filter_bytes(a, -1); 147 } 148 149 /* 150 * Return a count of the number of uncompressed bytes processed. 151 */ 152 int64_t 153 archive_position_uncompressed(struct archive *a) 154 { 155 return archive_filter_bytes(a, 0); 156 } 157 158 void 159 archive_clear_error(struct archive *a) 160 { 161 archive_string_empty(&a->error_string); 162 a->error = NULL; 163 a->archive_error_number = 0; 164 } 165 166 void 167 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 168 { 169 va_list ap; 170 171 a->archive_error_number = error_number; 172 if (fmt == NULL) { 173 a->error = NULL; 174 return; 175 } 176 177 archive_string_empty(&(a->error_string)); 178 va_start(ap, fmt); 179 archive_string_vsprintf(&(a->error_string), fmt, ap); 180 va_end(ap); 181 a->error = a->error_string.s; 182 } 183 184 void 185 archive_copy_error(struct archive *dest, struct archive *src) 186 { 187 dest->archive_error_number = src->archive_error_number; 188 189 archive_string_copy(&dest->error_string, &src->error_string); 190 dest->error = dest->error_string.s; 191 } 192 193 void 194 __archive_errx(int retvalue, const char *msg) 195 { 196 static const char msg1[] = "Fatal Internal Error in libarchive: "; 197 size_t s; 198 199 s = write(2, msg1, strlen(msg1)); 200 (void)s; /* UNUSED */ 201 s = write(2, msg, strlen(msg)); 202 (void)s; /* UNUSED */ 203 s = write(2, "\n", 1); 204 (void)s; /* UNUSED */ 205 exit(retvalue); 206 } 207 208 /* 209 * Create a temporary file 210 */ 211 #if defined(_WIN32) && !defined(__CYGWIN__) 212 213 /* 214 * Do not use Windows tmpfile() function. 215 * It will make a temporary file under the root directory 216 * and it'll cause permission error if a user who is 217 * non-Administrator creates temporary files. 218 * Also Windows version of mktemp family including _mktemp_s 219 * are not secure. 220 */ 221 int 222 __archive_mktemp(const char *tmpdir) 223 { 224 static const wchar_t prefix[] = L"libarchive_"; 225 static const wchar_t suffix[] = L"XXXXXXXXXX"; 226 static const wchar_t num[] = { 227 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 228 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 229 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 230 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 231 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 232 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 233 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 234 L'u', L'v', L'w', L'x', L'y', L'z' 235 }; 236 HCRYPTPROV hProv; 237 struct archive_wstring temp_name; 238 wchar_t *ws; 239 DWORD attr; 240 wchar_t *xp, *ep; 241 int fd; 242 243 hProv = (HCRYPTPROV)NULL; 244 fd = -1; 245 ws = NULL; 246 archive_string_init(&temp_name); 247 248 /* Get a temporary directory. */ 249 if (tmpdir == NULL) { 250 size_t l; 251 wchar_t *tmp; 252 253 l = GetTempPathW(0, NULL); 254 if (l == 0) { 255 la_dosmaperr(GetLastError()); 256 goto exit_tmpfile; 257 } 258 tmp = malloc(l*sizeof(wchar_t)); 259 if (tmp == NULL) { 260 errno = ENOMEM; 261 goto exit_tmpfile; 262 } 263 GetTempPathW((DWORD)l, tmp); 264 archive_wstrcpy(&temp_name, tmp); 265 free(tmp); 266 } else { 267 if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 268 strlen(tmpdir)) < 0) 269 goto exit_tmpfile; 270 if (temp_name.s[temp_name.length-1] != L'/') 271 archive_wstrappend_wchar(&temp_name, L'/'); 272 } 273 274 /* Check if temp_name is a directory. */ 275 attr = GetFileAttributesW(temp_name.s); 276 if (attr == (DWORD)-1) { 277 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 278 la_dosmaperr(GetLastError()); 279 goto exit_tmpfile; 280 } 281 ws = __la_win_permissive_name_w(temp_name.s); 282 if (ws == NULL) { 283 errno = EINVAL; 284 goto exit_tmpfile; 285 } 286 attr = GetFileAttributesW(ws); 287 if (attr == (DWORD)-1) { 288 la_dosmaperr(GetLastError()); 289 goto exit_tmpfile; 290 } 291 } 292 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 293 errno = ENOTDIR; 294 goto exit_tmpfile; 295 } 296 297 /* 298 * Create a temporary file. 299 */ 300 archive_wstrcat(&temp_name, prefix); 301 archive_wstrcat(&temp_name, suffix); 302 ep = temp_name.s + archive_strlen(&temp_name); 303 xp = ep - wcslen(suffix); 304 305 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 306 CRYPT_VERIFYCONTEXT)) { 307 la_dosmaperr(GetLastError()); 308 goto exit_tmpfile; 309 } 310 311 for (;;) { 312 wchar_t *p; 313 HANDLE h; 314 315 /* Generate a random file name through CryptGenRandom(). */ 316 p = xp; 317 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 318 (BYTE*)p)) { 319 la_dosmaperr(GetLastError()); 320 goto exit_tmpfile; 321 } 322 for (; p < ep; p++) 323 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 324 325 free(ws); 326 ws = __la_win_permissive_name_w(temp_name.s); 327 if (ws == NULL) { 328 errno = EINVAL; 329 goto exit_tmpfile; 330 } 331 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 332 * delete this temporary file immediately when this 333 * file closed. */ 334 h = CreateFileW(ws, 335 GENERIC_READ | GENERIC_WRITE | DELETE, 336 0,/* Not share */ 337 NULL, 338 CREATE_NEW,/* Create a new file only */ 339 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 340 NULL); 341 if (h == INVALID_HANDLE_VALUE) { 342 /* The same file already exists. retry with 343 * a new filename. */ 344 if (GetLastError() == ERROR_FILE_EXISTS) 345 continue; 346 /* Otherwise, fail creation temporary file. */ 347 la_dosmaperr(GetLastError()); 348 goto exit_tmpfile; 349 } 350 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 351 if (fd == -1) { 352 CloseHandle(h); 353 goto exit_tmpfile; 354 } else 355 break;/* success! */ 356 } 357 exit_tmpfile: 358 if (hProv != (HCRYPTPROV)NULL) 359 CryptReleaseContext(hProv, 0); 360 free(ws); 361 archive_wstring_free(&temp_name); 362 return (fd); 363 } 364 365 #else 366 367 static int 368 get_tempdir(struct archive_string *temppath) 369 { 370 const char *tmp; 371 372 tmp = getenv("TMPDIR"); 373 if (tmp == NULL) 374 #ifdef _PATH_TMP 375 tmp = _PATH_TMP; 376 #else 377 tmp = "/tmp"; 378 #endif 379 archive_strcpy(temppath, tmp); 380 if (temppath->s[temppath->length-1] != '/') 381 archive_strappend_char(temppath, '/'); 382 return (ARCHIVE_OK); 383 } 384 385 #if defined(HAVE_MKSTEMP) 386 387 /* 388 * We can use mkstemp(). 389 */ 390 391 int 392 __archive_mktemp(const char *tmpdir) 393 { 394 struct archive_string temp_name; 395 int fd = -1; 396 397 archive_string_init(&temp_name); 398 if (tmpdir == NULL) { 399 if (get_tempdir(&temp_name) != ARCHIVE_OK) 400 goto exit_tmpfile; 401 } else { 402 archive_strcpy(&temp_name, tmpdir); 403 if (temp_name.s[temp_name.length-1] != '/') 404 archive_strappend_char(&temp_name, '/'); 405 } 406 archive_strcat(&temp_name, "libarchive_XXXXXX"); 407 fd = mkstemp(temp_name.s); 408 if (fd < 0) 409 goto exit_tmpfile; 410 __archive_ensure_cloexec_flag(fd); 411 unlink(temp_name.s); 412 exit_tmpfile: 413 archive_string_free(&temp_name); 414 return (fd); 415 } 416 417 #else 418 419 /* 420 * We use a private routine. 421 */ 422 423 int 424 __archive_mktemp(const char *tmpdir) 425 { 426 static const char num[] = { 427 '0', '1', '2', '3', '4', '5', '6', '7', 428 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 429 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 430 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 431 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 432 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 433 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 434 'u', 'v', 'w', 'x', 'y', 'z' 435 }; 436 struct archive_string temp_name; 437 struct stat st; 438 int fd; 439 char *tp, *ep; 440 441 fd = -1; 442 archive_string_init(&temp_name); 443 if (tmpdir == NULL) { 444 if (get_tempdir(&temp_name) != ARCHIVE_OK) 445 goto exit_tmpfile; 446 } else 447 archive_strcpy(&temp_name, tmpdir); 448 if (temp_name.s[temp_name.length-1] == '/') { 449 temp_name.s[temp_name.length-1] = '\0'; 450 temp_name.length --; 451 } 452 if (stat(temp_name.s, &st) < 0) 453 goto exit_tmpfile; 454 if (!S_ISDIR(st.st_mode)) { 455 errno = ENOTDIR; 456 goto exit_tmpfile; 457 } 458 archive_strcat(&temp_name, "/libarchive_"); 459 tp = temp_name.s + archive_strlen(&temp_name); 460 archive_strcat(&temp_name, "XXXXXXXXXX"); 461 ep = temp_name.s + archive_strlen(&temp_name); 462 463 do { 464 char *p; 465 466 p = tp; 467 archive_random(p, ep - p); 468 while (p < ep) { 469 int d = *((unsigned char *)p) % sizeof(num); 470 *p++ = num[d]; 471 } 472 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 473 0600); 474 } while (fd < 0 && errno == EEXIST); 475 if (fd < 0) 476 goto exit_tmpfile; 477 __archive_ensure_cloexec_flag(fd); 478 unlink(temp_name.s); 479 exit_tmpfile: 480 archive_string_free(&temp_name); 481 return (fd); 482 } 483 484 #endif /* HAVE_MKSTEMP */ 485 #endif /* !_WIN32 || __CYGWIN__ */ 486 487 /* 488 * Set FD_CLOEXEC flag to a file descriptor if it is not set. 489 * We have to set the flag if the platform does not provide O_CLOEXEC 490 * or F_DUPFD_CLOEXEC flags. 491 * 492 * Note: This function is absolutely called after creating a new file 493 * descriptor even if the platform seemingly provides O_CLOEXEC or 494 * F_DUPFD_CLOEXEC macros because it is possible that the platform 495 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 496 */ 497 void 498 __archive_ensure_cloexec_flag(int fd) 499 { 500 #if defined(_WIN32) && !defined(__CYGWIN__) 501 (void)fd; /* UNUSED */ 502 #else 503 int flags; 504 505 if (fd >= 0) { 506 flags = fcntl(fd, F_GETFD); 507 if (flags != -1 && (flags & FD_CLOEXEC) == 0) 508 fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 509 } 510 #endif 511 } 512 513 /* 514 * Utility function to sort a group of strings using quicksort. 515 */ 516 static int 517 archive_utility_string_sort_helper(char **strings, unsigned int n) 518 { 519 unsigned int i, lesser_count, greater_count; 520 char **lesser, **greater, **tmp, *pivot; 521 int retval1, retval2; 522 523 /* A list of 0 or 1 elements is already sorted */ 524 if (n <= 1) 525 return (ARCHIVE_OK); 526 527 lesser_count = greater_count = 0; 528 lesser = greater = NULL; 529 pivot = strings[0]; 530 for (i = 1; i < n; i++) 531 { 532 if (strcmp(strings[i], pivot) < 0) 533 { 534 lesser_count++; 535 tmp = (char **)realloc(lesser, 536 lesser_count * sizeof(char *)); 537 if (!tmp) { 538 free(greater); 539 free(lesser); 540 return (ARCHIVE_FATAL); 541 } 542 lesser = tmp; 543 lesser[lesser_count - 1] = strings[i]; 544 } 545 else 546 { 547 greater_count++; 548 tmp = (char **)realloc(greater, 549 greater_count * sizeof(char *)); 550 if (!tmp) { 551 free(greater); 552 free(lesser); 553 return (ARCHIVE_FATAL); 554 } 555 greater = tmp; 556 greater[greater_count - 1] = strings[i]; 557 } 558 } 559 560 /* quicksort(lesser) */ 561 retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 562 for (i = 0; i < lesser_count; i++) 563 strings[i] = lesser[i]; 564 free(lesser); 565 566 /* pivot */ 567 strings[lesser_count] = pivot; 568 569 /* quicksort(greater) */ 570 retval2 = archive_utility_string_sort_helper(greater, greater_count); 571 for (i = 0; i < greater_count; i++) 572 strings[lesser_count + 1 + i] = greater[i]; 573 free(greater); 574 575 return (retval1 < retval2) ? retval1 : retval2; 576 } 577 578 int 579 archive_utility_string_sort(char **strings) 580 { 581 unsigned int size = 0; 582 while (strings[size] != NULL) 583 size++; 584 return archive_utility_string_sort_helper(strings, size); 585 } 586