1228753Smm/*- 2248616Smm * Copyright (c) 2009-2012 Michihiro NAKAJIMA 3228753Smm * Copyright (c) 2003-2007 Tim Kientzle 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28228763Smm__FBSDID("$FreeBSD$"); 29228753Smm 30228753Smm#ifdef HAVE_SYS_TYPES_H 31228753Smm#include <sys/types.h> 32228753Smm#endif 33232153Smm#ifdef HAVE_ERRNO_H 34232153Smm#include <errno.h> 35232153Smm#endif 36232153Smm#ifdef HAVE_FCNTL_H 37232153Smm#include <fcntl.h> 38232153Smm#endif 39228753Smm#ifdef HAVE_STDLIB_H 40228753Smm#include <stdlib.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_STRING_H 43228753Smm#include <string.h> 44228753Smm#endif 45232153Smm#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) 46232153Smm#include <wincrypt.h> 47232153Smm#endif 48228753Smm 49228753Smm#include "archive.h" 50228753Smm#include "archive_private.h" 51228753Smm#include "archive_string.h" 52228753Smm 53248616Smm#ifndef O_CLOEXEC 54248616Smm#define O_CLOEXEC 0 55248616Smm#endif 56248616Smm 57232153Smm/* Generic initialization of 'struct archive' objects. */ 58228753Smmint 59232153Smm__archive_clean(struct archive *a) 60228753Smm{ 61232153Smm archive_string_conversion_free(a); 62232153Smm return (ARCHIVE_OK); 63228753Smm} 64228753Smm 65228753Smmint 66228753Smmarchive_version_number(void) 67228753Smm{ 68228753Smm return (ARCHIVE_VERSION_NUMBER); 69228753Smm} 70228753Smm 71228753Smmconst char * 72228753Smmarchive_version_string(void) 73228753Smm{ 74228753Smm return (ARCHIVE_VERSION_STRING); 75228753Smm} 76228753Smm 77228753Smmint 78228753Smmarchive_errno(struct archive *a) 79228753Smm{ 80228753Smm return (a->archive_error_number); 81228753Smm} 82228753Smm 83228753Smmconst char * 84228753Smmarchive_error_string(struct archive *a) 85228753Smm{ 86228753Smm 87228753Smm if (a->error != NULL && *a->error != '\0') 88228753Smm return (a->error); 89228753Smm else 90232153Smm return (NULL); 91228753Smm} 92228753Smm 93228753Smmint 94228753Smmarchive_file_count(struct archive *a) 95228753Smm{ 96228753Smm return (a->file_count); 97228753Smm} 98228753Smm 99228753Smmint 100228753Smmarchive_format(struct archive *a) 101228753Smm{ 102228753Smm return (a->archive_format); 103228753Smm} 104228753Smm 105228753Smmconst char * 106228753Smmarchive_format_name(struct archive *a) 107228753Smm{ 108228753Smm return (a->archive_format_name); 109228753Smm} 110228753Smm 111228753Smm 112228753Smmint 113228753Smmarchive_compression(struct archive *a) 114228753Smm{ 115232153Smm return archive_filter_code(a, 0); 116228753Smm} 117228753Smm 118228753Smmconst char * 119228753Smmarchive_compression_name(struct archive *a) 120228753Smm{ 121232153Smm return archive_filter_name(a, 0); 122228753Smm} 123228753Smm 124228753Smm 125228753Smm/* 126228753Smm * Return a count of the number of compressed bytes processed. 127228753Smm */ 128228753Smmint64_t 129228753Smmarchive_position_compressed(struct archive *a) 130228753Smm{ 131232153Smm return archive_filter_bytes(a, -1); 132228753Smm} 133228753Smm 134228753Smm/* 135228753Smm * Return a count of the number of uncompressed bytes processed. 136228753Smm */ 137228753Smmint64_t 138228753Smmarchive_position_uncompressed(struct archive *a) 139228753Smm{ 140232153Smm return archive_filter_bytes(a, 0); 141228753Smm} 142228753Smm 143228753Smmvoid 144228753Smmarchive_clear_error(struct archive *a) 145228753Smm{ 146228753Smm archive_string_empty(&a->error_string); 147228753Smm a->error = NULL; 148228753Smm a->archive_error_number = 0; 149228753Smm} 150228753Smm 151228753Smmvoid 152228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...) 153228753Smm{ 154228753Smm va_list ap; 155228753Smm 156228753Smm a->archive_error_number = error_number; 157228753Smm if (fmt == NULL) { 158228753Smm a->error = NULL; 159228753Smm return; 160228753Smm } 161228753Smm 162232153Smm archive_string_empty(&(a->error_string)); 163228753Smm va_start(ap, fmt); 164228753Smm archive_string_vsprintf(&(a->error_string), fmt, ap); 165228753Smm va_end(ap); 166228753Smm a->error = a->error_string.s; 167228753Smm} 168228753Smm 169228753Smmvoid 170228753Smmarchive_copy_error(struct archive *dest, struct archive *src) 171228753Smm{ 172228753Smm dest->archive_error_number = src->archive_error_number; 173228753Smm 174228753Smm archive_string_copy(&dest->error_string, &src->error_string); 175228753Smm dest->error = dest->error_string.s; 176228753Smm} 177228753Smm 178228753Smmvoid 179228753Smm__archive_errx(int retvalue, const char *msg) 180228753Smm{ 181228753Smm static const char *msg1 = "Fatal Internal Error in libarchive: "; 182228753Smm size_t s; 183228753Smm 184228753Smm s = write(2, msg1, strlen(msg1)); 185228753Smm (void)s; /* UNUSED */ 186228753Smm s = write(2, msg, strlen(msg)); 187228753Smm (void)s; /* UNUSED */ 188228753Smm s = write(2, "\n", 1); 189228753Smm (void)s; /* UNUSED */ 190228753Smm exit(retvalue); 191228753Smm} 192228753Smm 193228753Smm/* 194232153Smm * Create a temporary file 195228753Smm */ 196232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 197232153Smm 198232153Smm/* 199232153Smm * Do not use Windows tmpfile() function. 200232153Smm * It will make a temporary file under the root directory 201232153Smm * and it'll cause permission error if a user who is 202232153Smm * non-Administrator creates temporary files. 203232153Smm * Also Windows version of mktemp family including _mktemp_s 204232153Smm * are not secure. 205232153Smm */ 206228753Smmint 207232153Smm__archive_mktemp(const char *tmpdir) 208228753Smm{ 209232153Smm static const wchar_t num[] = { 210232153Smm L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 211232153Smm L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 212232153Smm L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 213232153Smm L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 214232153Smm L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 215232153Smm L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 216232153Smm L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 217232153Smm L'u', L'v', L'w', L'x', L'y', L'z' 218232153Smm }; 219232153Smm HCRYPTPROV hProv; 220232153Smm struct archive_wstring temp_name; 221232153Smm wchar_t *ws; 222232153Smm DWORD attr; 223232153Smm wchar_t *xp, *ep; 224232153Smm int fd; 225228753Smm 226232153Smm hProv = (HCRYPTPROV)NULL; 227232153Smm fd = -1; 228232153Smm ws = NULL; 229232153Smm archive_string_init(&temp_name); 230232153Smm 231232153Smm /* Get a temporary directory. */ 232232153Smm if (tmpdir == NULL) { 233232153Smm size_t l; 234232153Smm wchar_t *tmp; 235232153Smm 236232153Smm l = GetTempPathW(0, NULL); 237232153Smm if (l == 0) { 238232153Smm la_dosmaperr(GetLastError()); 239232153Smm goto exit_tmpfile; 240232153Smm } 241232153Smm tmp = malloc(l*sizeof(wchar_t)); 242232153Smm if (tmp == NULL) { 243232153Smm errno = ENOMEM; 244232153Smm goto exit_tmpfile; 245232153Smm } 246248616Smm GetTempPathW((DWORD)l, tmp); 247232153Smm archive_wstrcpy(&temp_name, tmp); 248232153Smm free(tmp); 249232153Smm } else { 250238856Smm if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 251238856Smm strlen(tmpdir)) < 0) 252238856Smm goto exit_tmpfile; 253232153Smm if (temp_name.s[temp_name.length-1] != L'/') 254232153Smm archive_wstrappend_wchar(&temp_name, L'/'); 255228753Smm } 256228753Smm 257232153Smm /* Check if temp_name is a directory. */ 258232153Smm attr = GetFileAttributesW(temp_name.s); 259232153Smm if (attr == (DWORD)-1) { 260232153Smm if (GetLastError() != ERROR_FILE_NOT_FOUND) { 261232153Smm la_dosmaperr(GetLastError()); 262232153Smm goto exit_tmpfile; 263228753Smm } 264232153Smm ws = __la_win_permissive_name_w(temp_name.s); 265232153Smm if (ws == NULL) { 266232153Smm errno = EINVAL; 267232153Smm goto exit_tmpfile; 268232153Smm } 269232153Smm attr = GetFileAttributesW(ws); 270232153Smm if (attr == (DWORD)-1) { 271232153Smm la_dosmaperr(GetLastError()); 272232153Smm goto exit_tmpfile; 273232153Smm } 274228753Smm } 275232153Smm if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 276232153Smm errno = ENOTDIR; 277232153Smm goto exit_tmpfile; 278232153Smm } 279228753Smm 280232153Smm /* 281232153Smm * Create a temporary file. 282232153Smm */ 283232153Smm archive_wstrcat(&temp_name, L"libarchive_"); 284232153Smm xp = temp_name.s + archive_strlen(&temp_name); 285232153Smm archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 286232153Smm ep = temp_name.s + archive_strlen(&temp_name); 287228753Smm 288232153Smm if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 289232153Smm CRYPT_VERIFYCONTEXT)) { 290232153Smm la_dosmaperr(GetLastError()); 291232153Smm goto exit_tmpfile; 292232153Smm } 293232153Smm 294232153Smm for (;;) { 295232153Smm wchar_t *p; 296232153Smm HANDLE h; 297232153Smm 298232153Smm /* Generate a random file name through CryptGenRandom(). */ 299232153Smm p = xp; 300248616Smm if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 301248616Smm (BYTE*)p)) { 302232153Smm la_dosmaperr(GetLastError()); 303232153Smm goto exit_tmpfile; 304232153Smm } 305232153Smm for (; p < ep; p++) 306232153Smm *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 307232153Smm 308232153Smm free(ws); 309232153Smm ws = __la_win_permissive_name_w(temp_name.s); 310232153Smm if (ws == NULL) { 311232153Smm errno = EINVAL; 312232153Smm goto exit_tmpfile; 313232153Smm } 314232153Smm /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 315232153Smm * delete this temporary file immediately when this 316232153Smm * file closed. */ 317232153Smm h = CreateFileW(ws, 318232153Smm GENERIC_READ | GENERIC_WRITE | DELETE, 319232153Smm 0,/* Not share */ 320232153Smm NULL, 321232153Smm CREATE_NEW,/* Create a new file only */ 322232153Smm FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 323232153Smm NULL); 324232153Smm if (h == INVALID_HANDLE_VALUE) { 325232153Smm /* The same file already exists. retry with 326232153Smm * a new filename. */ 327232153Smm if (GetLastError() == ERROR_FILE_EXISTS) 328232153Smm continue; 329232153Smm /* Otherwise, fail creation temporary file. */ 330232153Smm la_dosmaperr(GetLastError()); 331232153Smm goto exit_tmpfile; 332232153Smm } 333232153Smm fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 334232153Smm if (fd == -1) { 335232153Smm CloseHandle(h); 336232153Smm goto exit_tmpfile; 337232153Smm } else 338232153Smm break;/* success! */ 339232153Smm } 340232153Smmexit_tmpfile: 341232153Smm if (hProv != (HCRYPTPROV)NULL) 342232153Smm CryptReleaseContext(hProv, 0); 343232153Smm free(ws); 344232153Smm archive_wstring_free(&temp_name); 345232153Smm return (fd); 346228753Smm} 347232153Smm 348232153Smm#else 349232153Smm 350232153Smmstatic int 351232153Smmget_tempdir(struct archive_string *temppath) 352232153Smm{ 353232153Smm const char *tmp; 354232153Smm 355232153Smm tmp = getenv("TMPDIR"); 356232153Smm if (tmp == NULL) 357232153Smm#ifdef _PATH_TMP 358232153Smm tmp = _PATH_TMP; 359232153Smm#else 360232153Smm tmp = "/tmp"; 361232153Smm#endif 362232153Smm archive_strcpy(temppath, tmp); 363232153Smm if (temppath->s[temppath->length-1] != '/') 364232153Smm archive_strappend_char(temppath, '/'); 365232153Smm return (ARCHIVE_OK); 366232153Smm} 367232153Smm 368232153Smm#if defined(HAVE_MKSTEMP) 369232153Smm 370232153Smm/* 371232153Smm * We can use mkstemp(). 372232153Smm */ 373232153Smm 374232153Smmint 375232153Smm__archive_mktemp(const char *tmpdir) 376232153Smm{ 377232153Smm struct archive_string temp_name; 378232153Smm int fd = -1; 379232153Smm 380232153Smm archive_string_init(&temp_name); 381232153Smm if (tmpdir == NULL) { 382232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 383232153Smm goto exit_tmpfile; 384232153Smm } else { 385232153Smm archive_strcpy(&temp_name, tmpdir); 386232153Smm if (temp_name.s[temp_name.length-1] != '/') 387232153Smm archive_strappend_char(&temp_name, '/'); 388232153Smm } 389232153Smm archive_strcat(&temp_name, "libarchive_XXXXXX"); 390232153Smm fd = mkstemp(temp_name.s); 391232153Smm if (fd < 0) 392232153Smm goto exit_tmpfile; 393248616Smm __archive_ensure_cloexec_flag(fd); 394232153Smm unlink(temp_name.s); 395232153Smmexit_tmpfile: 396232153Smm archive_string_free(&temp_name); 397232153Smm return (fd); 398232153Smm} 399232153Smm 400232153Smm#else 401232153Smm 402232153Smm/* 403232153Smm * We use a private routine. 404232153Smm */ 405232153Smm 406232153Smmint 407232153Smm__archive_mktemp(const char *tmpdir) 408232153Smm{ 409232153Smm static const char num[] = { 410232153Smm '0', '1', '2', '3', '4', '5', '6', '7', 411232153Smm '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 412232153Smm 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 413232153Smm 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 414232153Smm 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 415232153Smm 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 416232153Smm 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 417232153Smm 'u', 'v', 'w', 'x', 'y', 'z' 418232153Smm }; 419232153Smm struct archive_string temp_name; 420232153Smm struct stat st; 421232153Smm int fd; 422232153Smm char *tp, *ep; 423232153Smm unsigned seed; 424232153Smm 425232153Smm fd = -1; 426232153Smm archive_string_init(&temp_name); 427232153Smm if (tmpdir == NULL) { 428232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 429232153Smm goto exit_tmpfile; 430232153Smm } else 431232153Smm archive_strcpy(&temp_name, tmpdir); 432232153Smm if (temp_name.s[temp_name.length-1] == '/') { 433232153Smm temp_name.s[temp_name.length-1] = '\0'; 434232153Smm temp_name.length --; 435232153Smm } 436232153Smm if (stat(temp_name.s, &st) < 0) 437232153Smm goto exit_tmpfile; 438232153Smm if (!S_ISDIR(st.st_mode)) { 439232153Smm errno = ENOTDIR; 440232153Smm goto exit_tmpfile; 441232153Smm } 442232153Smm archive_strcat(&temp_name, "/libarchive_"); 443232153Smm tp = temp_name.s + archive_strlen(&temp_name); 444232153Smm archive_strcat(&temp_name, "XXXXXXXXXX"); 445232153Smm ep = temp_name.s + archive_strlen(&temp_name); 446232153Smm 447248616Smm fd = open("/dev/random", O_RDONLY | O_CLOEXEC); 448248616Smm __archive_ensure_cloexec_flag(fd); 449232153Smm if (fd < 0) 450232153Smm seed = time(NULL); 451232153Smm else { 452232153Smm if (read(fd, &seed, sizeof(seed)) < 0) 453232153Smm seed = time(NULL); 454232153Smm close(fd); 455232153Smm } 456232153Smm do { 457232153Smm char *p; 458232153Smm 459232153Smm p = tp; 460232153Smm while (p < ep) 461232153Smm *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 462248616Smm fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 463248616Smm 0600); 464232153Smm } while (fd < 0 && errno == EEXIST); 465232153Smm if (fd < 0) 466232153Smm goto exit_tmpfile; 467248616Smm __archive_ensure_cloexec_flag(fd); 468232153Smm unlink(temp_name.s); 469232153Smmexit_tmpfile: 470232153Smm archive_string_free(&temp_name); 471232153Smm return (fd); 472232153Smm} 473232153Smm 474232153Smm#endif /* HAVE_MKSTEMP */ 475232153Smm#endif /* !_WIN32 || __CYGWIN__ */ 476248616Smm 477248616Smm/* 478248616Smm * Set FD_CLOEXEC flag to a file descriptor if it is not set. 479248616Smm * We have to set the flag if the platform does not provide O_CLOEXEC 480248616Smm * or F_DUPFD_CLOEXEC flags. 481248616Smm * 482248616Smm * Note: This function is absolutely called after creating a new file 483248616Smm * descriptor even if the platform seemingly provides O_CLOEXEC or 484248616Smm * F_DUPFD_CLOEXEC macros because it is possible that the platform 485248616Smm * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 486248616Smm */ 487248616Smmvoid 488248616Smm__archive_ensure_cloexec_flag(int fd) 489248616Smm{ 490248616Smm#if defined(_WIN32) && !defined(__CYGWIN__) 491248616Smm (void)fd; /* UNSED */ 492248616Smm#else 493248616Smm int flags; 494248616Smm 495248616Smm if (fd >= 0) { 496248616Smm flags = fcntl(fd, F_GETFD); 497248616Smm if (flags != -1 && (flags & FD_CLOEXEC) == 0) 498248616Smm fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 499248616Smm } 500248616Smm#endif 501248616Smm} 502