archive_util.c revision 232153
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 232153 2012-02-25 10:58:02Z 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 { 246232153Smm archive_wstring_append_from_mbs(&temp_name, tmpdir, 247232153Smm strlen(tmpdir)); 248232153Smm if (temp_name.s[temp_name.length-1] != L'/') 249232153Smm archive_wstrappend_wchar(&temp_name, L'/'); 250228753Smm } 251228753Smm 252232153Smm /* Check if temp_name is a directory. */ 253232153Smm attr = GetFileAttributesW(temp_name.s); 254232153Smm if (attr == (DWORD)-1) { 255232153Smm if (GetLastError() != ERROR_FILE_NOT_FOUND) { 256232153Smm la_dosmaperr(GetLastError()); 257232153Smm goto exit_tmpfile; 258228753Smm } 259232153Smm ws = __la_win_permissive_name_w(temp_name.s); 260232153Smm if (ws == NULL) { 261232153Smm errno = EINVAL; 262232153Smm goto exit_tmpfile; 263232153Smm } 264232153Smm attr = GetFileAttributesW(ws); 265232153Smm if (attr == (DWORD)-1) { 266232153Smm la_dosmaperr(GetLastError()); 267232153Smm goto exit_tmpfile; 268232153Smm } 269228753Smm } 270232153Smm if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 271232153Smm errno = ENOTDIR; 272232153Smm goto exit_tmpfile; 273232153Smm } 274228753Smm 275232153Smm /* 276232153Smm * Create a temporary file. 277232153Smm */ 278232153Smm archive_wstrcat(&temp_name, L"libarchive_"); 279232153Smm xp = temp_name.s + archive_strlen(&temp_name); 280232153Smm archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 281232153Smm ep = temp_name.s + archive_strlen(&temp_name); 282228753Smm 283232153Smm if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 284232153Smm CRYPT_VERIFYCONTEXT)) { 285232153Smm la_dosmaperr(GetLastError()); 286232153Smm goto exit_tmpfile; 287232153Smm } 288232153Smm 289232153Smm for (;;) { 290232153Smm wchar_t *p; 291232153Smm HANDLE h; 292232153Smm 293232153Smm /* Generate a random file name through CryptGenRandom(). */ 294232153Smm p = xp; 295232153Smm if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) { 296232153Smm la_dosmaperr(GetLastError()); 297232153Smm goto exit_tmpfile; 298232153Smm } 299232153Smm for (; p < ep; p++) 300232153Smm *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 301232153Smm 302232153Smm free(ws); 303232153Smm ws = __la_win_permissive_name_w(temp_name.s); 304232153Smm if (ws == NULL) { 305232153Smm errno = EINVAL; 306232153Smm goto exit_tmpfile; 307232153Smm } 308232153Smm /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 309232153Smm * delete this temporary file immediately when this 310232153Smm * file closed. */ 311232153Smm h = CreateFileW(ws, 312232153Smm GENERIC_READ | GENERIC_WRITE | DELETE, 313232153Smm 0,/* Not share */ 314232153Smm NULL, 315232153Smm CREATE_NEW,/* Create a new file only */ 316232153Smm FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 317232153Smm NULL); 318232153Smm if (h == INVALID_HANDLE_VALUE) { 319232153Smm /* The same file already exists. retry with 320232153Smm * a new filename. */ 321232153Smm if (GetLastError() == ERROR_FILE_EXISTS) 322232153Smm continue; 323232153Smm /* Otherwise, fail creation temporary file. */ 324232153Smm la_dosmaperr(GetLastError()); 325232153Smm goto exit_tmpfile; 326232153Smm } 327232153Smm fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 328232153Smm if (fd == -1) { 329232153Smm CloseHandle(h); 330232153Smm goto exit_tmpfile; 331232153Smm } else 332232153Smm break;/* success! */ 333232153Smm } 334232153Smmexit_tmpfile: 335232153Smm if (hProv != (HCRYPTPROV)NULL) 336232153Smm CryptReleaseContext(hProv, 0); 337232153Smm free(ws); 338232153Smm archive_wstring_free(&temp_name); 339232153Smm return (fd); 340228753Smm} 341232153Smm 342232153Smm#else 343232153Smm 344232153Smmstatic int 345232153Smmget_tempdir(struct archive_string *temppath) 346232153Smm{ 347232153Smm const char *tmp; 348232153Smm 349232153Smm tmp = getenv("TMPDIR"); 350232153Smm if (tmp == NULL) 351232153Smm#ifdef _PATH_TMP 352232153Smm tmp = _PATH_TMP; 353232153Smm#else 354232153Smm tmp = "/tmp"; 355232153Smm#endif 356232153Smm archive_strcpy(temppath, tmp); 357232153Smm if (temppath->s[temppath->length-1] != '/') 358232153Smm archive_strappend_char(temppath, '/'); 359232153Smm return (ARCHIVE_OK); 360232153Smm} 361232153Smm 362232153Smm#if defined(HAVE_MKSTEMP) 363232153Smm 364232153Smm/* 365232153Smm * We can use mkstemp(). 366232153Smm */ 367232153Smm 368232153Smmint 369232153Smm__archive_mktemp(const char *tmpdir) 370232153Smm{ 371232153Smm struct archive_string temp_name; 372232153Smm int fd = -1; 373232153Smm 374232153Smm archive_string_init(&temp_name); 375232153Smm if (tmpdir == NULL) { 376232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 377232153Smm goto exit_tmpfile; 378232153Smm } else { 379232153Smm archive_strcpy(&temp_name, tmpdir); 380232153Smm if (temp_name.s[temp_name.length-1] != '/') 381232153Smm archive_strappend_char(&temp_name, '/'); 382232153Smm } 383232153Smm archive_strcat(&temp_name, "libarchive_XXXXXX"); 384232153Smm fd = mkstemp(temp_name.s); 385232153Smm if (fd < 0) 386232153Smm goto exit_tmpfile; 387232153Smm unlink(temp_name.s); 388232153Smmexit_tmpfile: 389232153Smm archive_string_free(&temp_name); 390232153Smm return (fd); 391232153Smm} 392232153Smm 393232153Smm#else 394232153Smm 395232153Smm/* 396232153Smm * We use a private routine. 397232153Smm */ 398232153Smm 399232153Smmint 400232153Smm__archive_mktemp(const char *tmpdir) 401232153Smm{ 402232153Smm static const char num[] = { 403232153Smm '0', '1', '2', '3', '4', '5', '6', '7', 404232153Smm '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 405232153Smm 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 406232153Smm 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 407232153Smm 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 408232153Smm 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 409232153Smm 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 410232153Smm 'u', 'v', 'w', 'x', 'y', 'z' 411232153Smm }; 412232153Smm struct archive_string temp_name; 413232153Smm struct stat st; 414232153Smm int fd; 415232153Smm char *tp, *ep; 416232153Smm unsigned seed; 417232153Smm 418232153Smm fd = -1; 419232153Smm archive_string_init(&temp_name); 420232153Smm if (tmpdir == NULL) { 421232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 422232153Smm goto exit_tmpfile; 423232153Smm } else 424232153Smm archive_strcpy(&temp_name, tmpdir); 425232153Smm if (temp_name.s[temp_name.length-1] == '/') { 426232153Smm temp_name.s[temp_name.length-1] = '\0'; 427232153Smm temp_name.length --; 428232153Smm } 429232153Smm if (stat(temp_name.s, &st) < 0) 430232153Smm goto exit_tmpfile; 431232153Smm if (!S_ISDIR(st.st_mode)) { 432232153Smm errno = ENOTDIR; 433232153Smm goto exit_tmpfile; 434232153Smm } 435232153Smm archive_strcat(&temp_name, "/libarchive_"); 436232153Smm tp = temp_name.s + archive_strlen(&temp_name); 437232153Smm archive_strcat(&temp_name, "XXXXXXXXXX"); 438232153Smm ep = temp_name.s + archive_strlen(&temp_name); 439232153Smm 440232153Smm fd = open("/dev/random", O_RDONLY); 441232153Smm if (fd < 0) 442232153Smm seed = time(NULL); 443232153Smm else { 444232153Smm if (read(fd, &seed, sizeof(seed)) < 0) 445232153Smm seed = time(NULL); 446232153Smm close(fd); 447232153Smm } 448232153Smm do { 449232153Smm char *p; 450232153Smm 451232153Smm p = tp; 452232153Smm while (p < ep) 453232153Smm *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 454232153Smm fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600); 455232153Smm } while (fd < 0 && errno == EEXIST); 456232153Smm if (fd < 0) 457232153Smm goto exit_tmpfile; 458232153Smm unlink(temp_name.s); 459232153Smmexit_tmpfile: 460232153Smm archive_string_free(&temp_name); 461232153Smm return (fd); 462232153Smm} 463232153Smm 464232153Smm#endif /* HAVE_MKSTEMP */ 465232153Smm#endif /* !_WIN32 || __CYGWIN__ */ 466