archive_util.c revision 238856
1228753Smm/*- 2232153Smm * Copyright (c) 2009,2010 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: head/contrib/libarchive/libarchive/archive_util.c 238856 2012-07-28 06:38:44Z mm $"); 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 53232153Smm/* Generic initialization of 'struct archive' objects. */ 54228753Smmint 55232153Smm__archive_clean(struct archive *a) 56228753Smm{ 57232153Smm archive_string_conversion_free(a); 58232153Smm return (ARCHIVE_OK); 59228753Smm} 60228753Smm 61228753Smmint 62228753Smmarchive_version_number(void) 63228753Smm{ 64228753Smm return (ARCHIVE_VERSION_NUMBER); 65228753Smm} 66228753Smm 67228753Smmconst char * 68228753Smmarchive_version_string(void) 69228753Smm{ 70228753Smm return (ARCHIVE_VERSION_STRING); 71228753Smm} 72228753Smm 73228753Smmint 74228753Smmarchive_errno(struct archive *a) 75228753Smm{ 76228753Smm return (a->archive_error_number); 77228753Smm} 78228753Smm 79228753Smmconst char * 80228753Smmarchive_error_string(struct archive *a) 81228753Smm{ 82228753Smm 83228753Smm if (a->error != NULL && *a->error != '\0') 84228753Smm return (a->error); 85228753Smm else 86232153Smm return (NULL); 87228753Smm} 88228753Smm 89228753Smmint 90228753Smmarchive_file_count(struct archive *a) 91228753Smm{ 92228753Smm return (a->file_count); 93228753Smm} 94228753Smm 95228753Smmint 96228753Smmarchive_format(struct archive *a) 97228753Smm{ 98228753Smm return (a->archive_format); 99228753Smm} 100228753Smm 101228753Smmconst char * 102228753Smmarchive_format_name(struct archive *a) 103228753Smm{ 104228753Smm return (a->archive_format_name); 105228753Smm} 106228753Smm 107228753Smm 108228753Smmint 109228753Smmarchive_compression(struct archive *a) 110228753Smm{ 111232153Smm return archive_filter_code(a, 0); 112228753Smm} 113228753Smm 114228753Smmconst char * 115228753Smmarchive_compression_name(struct archive *a) 116228753Smm{ 117232153Smm return archive_filter_name(a, 0); 118228753Smm} 119228753Smm 120228753Smm 121228753Smm/* 122228753Smm * Return a count of the number of compressed bytes processed. 123228753Smm */ 124228753Smmint64_t 125228753Smmarchive_position_compressed(struct archive *a) 126228753Smm{ 127232153Smm return archive_filter_bytes(a, -1); 128228753Smm} 129228753Smm 130228753Smm/* 131228753Smm * Return a count of the number of uncompressed bytes processed. 132228753Smm */ 133228753Smmint64_t 134228753Smmarchive_position_uncompressed(struct archive *a) 135228753Smm{ 136232153Smm return archive_filter_bytes(a, 0); 137228753Smm} 138228753Smm 139228753Smmvoid 140228753Smmarchive_clear_error(struct archive *a) 141228753Smm{ 142228753Smm archive_string_empty(&a->error_string); 143228753Smm a->error = NULL; 144228753Smm a->archive_error_number = 0; 145228753Smm} 146228753Smm 147228753Smmvoid 148228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...) 149228753Smm{ 150228753Smm va_list ap; 151228753Smm 152228753Smm a->archive_error_number = error_number; 153228753Smm if (fmt == NULL) { 154228753Smm a->error = NULL; 155228753Smm return; 156228753Smm } 157228753Smm 158232153Smm archive_string_empty(&(a->error_string)); 159228753Smm va_start(ap, fmt); 160228753Smm archive_string_vsprintf(&(a->error_string), fmt, ap); 161228753Smm va_end(ap); 162228753Smm a->error = a->error_string.s; 163228753Smm} 164228753Smm 165228753Smmvoid 166228753Smmarchive_copy_error(struct archive *dest, struct archive *src) 167228753Smm{ 168228753Smm dest->archive_error_number = src->archive_error_number; 169228753Smm 170228753Smm archive_string_copy(&dest->error_string, &src->error_string); 171228753Smm dest->error = dest->error_string.s; 172228753Smm} 173228753Smm 174228753Smmvoid 175228753Smm__archive_errx(int retvalue, const char *msg) 176228753Smm{ 177228753Smm static const char *msg1 = "Fatal Internal Error in libarchive: "; 178228753Smm size_t s; 179228753Smm 180228753Smm s = write(2, msg1, strlen(msg1)); 181228753Smm (void)s; /* UNUSED */ 182228753Smm s = write(2, msg, strlen(msg)); 183228753Smm (void)s; /* UNUSED */ 184228753Smm s = write(2, "\n", 1); 185228753Smm (void)s; /* UNUSED */ 186228753Smm exit(retvalue); 187228753Smm} 188228753Smm 189228753Smm/* 190232153Smm * Create a temporary file 191228753Smm */ 192232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 193232153Smm 194232153Smm/* 195232153Smm * Do not use Windows tmpfile() function. 196232153Smm * It will make a temporary file under the root directory 197232153Smm * and it'll cause permission error if a user who is 198232153Smm * non-Administrator creates temporary files. 199232153Smm * Also Windows version of mktemp family including _mktemp_s 200232153Smm * are not secure. 201232153Smm */ 202228753Smmint 203232153Smm__archive_mktemp(const char *tmpdir) 204228753Smm{ 205232153Smm static const wchar_t num[] = { 206232153Smm L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 207232153Smm L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 208232153Smm L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 209232153Smm L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 210232153Smm L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 211232153Smm L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 212232153Smm L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 213232153Smm L'u', L'v', L'w', L'x', L'y', L'z' 214232153Smm }; 215232153Smm HCRYPTPROV hProv; 216232153Smm struct archive_wstring temp_name; 217232153Smm wchar_t *ws; 218232153Smm DWORD attr; 219232153Smm wchar_t *xp, *ep; 220232153Smm int fd; 221228753Smm 222232153Smm hProv = (HCRYPTPROV)NULL; 223232153Smm fd = -1; 224232153Smm ws = NULL; 225232153Smm archive_string_init(&temp_name); 226232153Smm 227232153Smm /* Get a temporary directory. */ 228232153Smm if (tmpdir == NULL) { 229232153Smm size_t l; 230232153Smm wchar_t *tmp; 231232153Smm 232232153Smm l = GetTempPathW(0, NULL); 233232153Smm if (l == 0) { 234232153Smm la_dosmaperr(GetLastError()); 235232153Smm goto exit_tmpfile; 236232153Smm } 237232153Smm tmp = malloc(l*sizeof(wchar_t)); 238232153Smm if (tmp == NULL) { 239232153Smm errno = ENOMEM; 240232153Smm goto exit_tmpfile; 241232153Smm } 242232153Smm GetTempPathW(l, tmp); 243232153Smm archive_wstrcpy(&temp_name, tmp); 244232153Smm free(tmp); 245232153Smm } else { 246238856Smm if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 247238856Smm strlen(tmpdir)) < 0) 248238856Smm goto exit_tmpfile; 249232153Smm if (temp_name.s[temp_name.length-1] != L'/') 250232153Smm archive_wstrappend_wchar(&temp_name, L'/'); 251228753Smm } 252228753Smm 253232153Smm /* Check if temp_name is a directory. */ 254232153Smm attr = GetFileAttributesW(temp_name.s); 255232153Smm if (attr == (DWORD)-1) { 256232153Smm if (GetLastError() != ERROR_FILE_NOT_FOUND) { 257232153Smm la_dosmaperr(GetLastError()); 258232153Smm goto exit_tmpfile; 259228753Smm } 260232153Smm ws = __la_win_permissive_name_w(temp_name.s); 261232153Smm if (ws == NULL) { 262232153Smm errno = EINVAL; 263232153Smm goto exit_tmpfile; 264232153Smm } 265232153Smm attr = GetFileAttributesW(ws); 266232153Smm if (attr == (DWORD)-1) { 267232153Smm la_dosmaperr(GetLastError()); 268232153Smm goto exit_tmpfile; 269232153Smm } 270228753Smm } 271232153Smm if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 272232153Smm errno = ENOTDIR; 273232153Smm goto exit_tmpfile; 274232153Smm } 275228753Smm 276232153Smm /* 277232153Smm * Create a temporary file. 278232153Smm */ 279232153Smm archive_wstrcat(&temp_name, L"libarchive_"); 280232153Smm xp = temp_name.s + archive_strlen(&temp_name); 281232153Smm archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 282232153Smm ep = temp_name.s + archive_strlen(&temp_name); 283228753Smm 284232153Smm if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 285232153Smm CRYPT_VERIFYCONTEXT)) { 286232153Smm la_dosmaperr(GetLastError()); 287232153Smm goto exit_tmpfile; 288232153Smm } 289232153Smm 290232153Smm for (;;) { 291232153Smm wchar_t *p; 292232153Smm HANDLE h; 293232153Smm 294232153Smm /* Generate a random file name through CryptGenRandom(). */ 295232153Smm p = xp; 296232153Smm if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) { 297232153Smm la_dosmaperr(GetLastError()); 298232153Smm goto exit_tmpfile; 299232153Smm } 300232153Smm for (; p < ep; p++) 301232153Smm *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 302232153Smm 303232153Smm free(ws); 304232153Smm ws = __la_win_permissive_name_w(temp_name.s); 305232153Smm if (ws == NULL) { 306232153Smm errno = EINVAL; 307232153Smm goto exit_tmpfile; 308232153Smm } 309232153Smm /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 310232153Smm * delete this temporary file immediately when this 311232153Smm * file closed. */ 312232153Smm h = CreateFileW(ws, 313232153Smm GENERIC_READ | GENERIC_WRITE | DELETE, 314232153Smm 0,/* Not share */ 315232153Smm NULL, 316232153Smm CREATE_NEW,/* Create a new file only */ 317232153Smm FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 318232153Smm NULL); 319232153Smm if (h == INVALID_HANDLE_VALUE) { 320232153Smm /* The same file already exists. retry with 321232153Smm * a new filename. */ 322232153Smm if (GetLastError() == ERROR_FILE_EXISTS) 323232153Smm continue; 324232153Smm /* Otherwise, fail creation temporary file. */ 325232153Smm la_dosmaperr(GetLastError()); 326232153Smm goto exit_tmpfile; 327232153Smm } 328232153Smm fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 329232153Smm if (fd == -1) { 330232153Smm CloseHandle(h); 331232153Smm goto exit_tmpfile; 332232153Smm } else 333232153Smm break;/* success! */ 334232153Smm } 335232153Smmexit_tmpfile: 336232153Smm if (hProv != (HCRYPTPROV)NULL) 337232153Smm CryptReleaseContext(hProv, 0); 338232153Smm free(ws); 339232153Smm archive_wstring_free(&temp_name); 340232153Smm return (fd); 341228753Smm} 342232153Smm 343232153Smm#else 344232153Smm 345232153Smmstatic int 346232153Smmget_tempdir(struct archive_string *temppath) 347232153Smm{ 348232153Smm const char *tmp; 349232153Smm 350232153Smm tmp = getenv("TMPDIR"); 351232153Smm if (tmp == NULL) 352232153Smm#ifdef _PATH_TMP 353232153Smm tmp = _PATH_TMP; 354232153Smm#else 355232153Smm tmp = "/tmp"; 356232153Smm#endif 357232153Smm archive_strcpy(temppath, tmp); 358232153Smm if (temppath->s[temppath->length-1] != '/') 359232153Smm archive_strappend_char(temppath, '/'); 360232153Smm return (ARCHIVE_OK); 361232153Smm} 362232153Smm 363232153Smm#if defined(HAVE_MKSTEMP) 364232153Smm 365232153Smm/* 366232153Smm * We can use mkstemp(). 367232153Smm */ 368232153Smm 369232153Smmint 370232153Smm__archive_mktemp(const char *tmpdir) 371232153Smm{ 372232153Smm struct archive_string temp_name; 373232153Smm int fd = -1; 374232153Smm 375232153Smm archive_string_init(&temp_name); 376232153Smm if (tmpdir == NULL) { 377232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 378232153Smm goto exit_tmpfile; 379232153Smm } else { 380232153Smm archive_strcpy(&temp_name, tmpdir); 381232153Smm if (temp_name.s[temp_name.length-1] != '/') 382232153Smm archive_strappend_char(&temp_name, '/'); 383232153Smm } 384232153Smm archive_strcat(&temp_name, "libarchive_XXXXXX"); 385232153Smm fd = mkstemp(temp_name.s); 386232153Smm if (fd < 0) 387232153Smm goto exit_tmpfile; 388232153Smm unlink(temp_name.s); 389232153Smmexit_tmpfile: 390232153Smm archive_string_free(&temp_name); 391232153Smm return (fd); 392232153Smm} 393232153Smm 394232153Smm#else 395232153Smm 396232153Smm/* 397232153Smm * We use a private routine. 398232153Smm */ 399232153Smm 400232153Smmint 401232153Smm__archive_mktemp(const char *tmpdir) 402232153Smm{ 403232153Smm static const char num[] = { 404232153Smm '0', '1', '2', '3', '4', '5', '6', '7', 405232153Smm '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 406232153Smm 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 407232153Smm 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 408232153Smm 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 409232153Smm 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 410232153Smm 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 411232153Smm 'u', 'v', 'w', 'x', 'y', 'z' 412232153Smm }; 413232153Smm struct archive_string temp_name; 414232153Smm struct stat st; 415232153Smm int fd; 416232153Smm char *tp, *ep; 417232153Smm unsigned seed; 418232153Smm 419232153Smm fd = -1; 420232153Smm archive_string_init(&temp_name); 421232153Smm if (tmpdir == NULL) { 422232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 423232153Smm goto exit_tmpfile; 424232153Smm } else 425232153Smm archive_strcpy(&temp_name, tmpdir); 426232153Smm if (temp_name.s[temp_name.length-1] == '/') { 427232153Smm temp_name.s[temp_name.length-1] = '\0'; 428232153Smm temp_name.length --; 429232153Smm } 430232153Smm if (stat(temp_name.s, &st) < 0) 431232153Smm goto exit_tmpfile; 432232153Smm if (!S_ISDIR(st.st_mode)) { 433232153Smm errno = ENOTDIR; 434232153Smm goto exit_tmpfile; 435232153Smm } 436232153Smm archive_strcat(&temp_name, "/libarchive_"); 437232153Smm tp = temp_name.s + archive_strlen(&temp_name); 438232153Smm archive_strcat(&temp_name, "XXXXXXXXXX"); 439232153Smm ep = temp_name.s + archive_strlen(&temp_name); 440232153Smm 441232153Smm fd = open("/dev/random", O_RDONLY); 442232153Smm if (fd < 0) 443232153Smm seed = time(NULL); 444232153Smm else { 445232153Smm if (read(fd, &seed, sizeof(seed)) < 0) 446232153Smm seed = time(NULL); 447232153Smm close(fd); 448232153Smm } 449232153Smm do { 450232153Smm char *p; 451232153Smm 452232153Smm p = tp; 453232153Smm while (p < ep) 454232153Smm *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 455232153Smm fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600); 456232153Smm } while (fd < 0 && errno == EEXIST); 457232153Smm if (fd < 0) 458232153Smm goto exit_tmpfile; 459232153Smm unlink(temp_name.s); 460232153Smmexit_tmpfile: 461232153Smm archive_string_free(&temp_name); 462232153Smm return (fd); 463232153Smm} 464232153Smm 465232153Smm#endif /* HAVE_MKSTEMP */ 466232153Smm#endif /* !_WIN32 || __CYGWIN__ */ 467