1caf54c4fSMartin Matuska /*- 2cdf63a70SMartin Matuska * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA 3caf54c4fSMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle 4caf54c4fSMartin Matuska * All rights reserved. 5caf54c4fSMartin Matuska * 6caf54c4fSMartin Matuska * Redistribution and use in source and binary forms, with or without 7caf54c4fSMartin Matuska * modification, are permitted provided that the following conditions 8caf54c4fSMartin Matuska * are met: 9caf54c4fSMartin Matuska * 1. Redistributions of source code must retain the above copyright 10caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer. 11caf54c4fSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright 12caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer in the 13caf54c4fSMartin Matuska * documentation and/or other materials provided with the distribution. 14caf54c4fSMartin Matuska * 15caf54c4fSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16caf54c4fSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17caf54c4fSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18caf54c4fSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19caf54c4fSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20caf54c4fSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21caf54c4fSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22caf54c4fSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23caf54c4fSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24caf54c4fSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25caf54c4fSMartin Matuska */ 26caf54c4fSMartin Matuska 27caf54c4fSMartin Matuska #include "archive_platform.h" 286c22d9efSMartin Matuska __FBSDID("$FreeBSD$"); 29caf54c4fSMartin Matuska 30caf54c4fSMartin Matuska #ifdef HAVE_SYS_TYPES_H 31caf54c4fSMartin Matuska #include <sys/types.h> 32caf54c4fSMartin Matuska #endif 336c95142eSMartin Matuska #ifdef HAVE_ERRNO_H 346c95142eSMartin Matuska #include <errno.h> 356c95142eSMartin Matuska #endif 366c95142eSMartin Matuska #ifdef HAVE_FCNTL_H 376c95142eSMartin Matuska #include <fcntl.h> 386c95142eSMartin Matuska #endif 39caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H 40caf54c4fSMartin Matuska #include <stdlib.h> 41caf54c4fSMartin Matuska #endif 42caf54c4fSMartin Matuska #ifdef HAVE_STRING_H 43caf54c4fSMartin Matuska #include <string.h> 44caf54c4fSMartin Matuska #endif 456c95142eSMartin Matuska #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) 466c95142eSMartin Matuska #include <wincrypt.h> 476c95142eSMartin Matuska #endif 48cdf63a70SMartin Matuska #ifdef HAVE_ZLIB_H 49cdf63a70SMartin Matuska #include <zlib.h> 50cdf63a70SMartin Matuska #endif 51cdf63a70SMartin Matuska #ifdef HAVE_LZMA_H 52cdf63a70SMartin Matuska #include <lzma.h> 53cdf63a70SMartin Matuska #endif 54cdf63a70SMartin Matuska #ifdef HAVE_BZLIB_H 55cdf63a70SMartin Matuska #include <bzlib.h> 56cdf63a70SMartin Matuska #endif 57cdf63a70SMartin Matuska #ifdef HAVE_LZ4_H 58cdf63a70SMartin Matuska #include <lz4.h> 59cdf63a70SMartin Matuska #endif 60caf54c4fSMartin Matuska 61caf54c4fSMartin Matuska #include "archive.h" 62caf54c4fSMartin Matuska #include "archive_private.h" 63cdf63a70SMartin Matuska #include "archive_random_private.h" 64caf54c4fSMartin Matuska #include "archive_string.h" 65caf54c4fSMartin Matuska 66acc60b03SMartin Matuska #ifndef O_CLOEXEC 67acc60b03SMartin Matuska #define O_CLOEXEC 0 68acc60b03SMartin Matuska #endif 69acc60b03SMartin Matuska 70cdf63a70SMartin Matuska static int archive_utility_string_sort_helper(char **, unsigned int); 71cdf63a70SMartin Matuska 726c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */ 73caf54c4fSMartin Matuska int 746c95142eSMartin Matuska __archive_clean(struct archive *a) 75caf54c4fSMartin Matuska { 766c95142eSMartin Matuska archive_string_conversion_free(a); 776c95142eSMartin Matuska return (ARCHIVE_OK); 78caf54c4fSMartin Matuska } 79caf54c4fSMartin Matuska 80caf54c4fSMartin Matuska int 81caf54c4fSMartin Matuska archive_version_number(void) 82caf54c4fSMartin Matuska { 83caf54c4fSMartin Matuska return (ARCHIVE_VERSION_NUMBER); 84caf54c4fSMartin Matuska } 85caf54c4fSMartin Matuska 86caf54c4fSMartin Matuska const char * 87caf54c4fSMartin Matuska archive_version_string(void) 88caf54c4fSMartin Matuska { 89caf54c4fSMartin Matuska return (ARCHIVE_VERSION_STRING); 90caf54c4fSMartin Matuska } 91caf54c4fSMartin Matuska 92caf54c4fSMartin Matuska int 93caf54c4fSMartin Matuska archive_errno(struct archive *a) 94caf54c4fSMartin Matuska { 95caf54c4fSMartin Matuska return (a->archive_error_number); 96caf54c4fSMartin Matuska } 97caf54c4fSMartin Matuska 98caf54c4fSMartin Matuska const char * 99caf54c4fSMartin Matuska archive_error_string(struct archive *a) 100caf54c4fSMartin Matuska { 101caf54c4fSMartin Matuska 102caf54c4fSMartin Matuska if (a->error != NULL && *a->error != '\0') 103caf54c4fSMartin Matuska return (a->error); 104caf54c4fSMartin Matuska else 1056c95142eSMartin Matuska return (NULL); 106caf54c4fSMartin Matuska } 107caf54c4fSMartin Matuska 108caf54c4fSMartin Matuska int 109caf54c4fSMartin Matuska archive_file_count(struct archive *a) 110caf54c4fSMartin Matuska { 111caf54c4fSMartin Matuska return (a->file_count); 112caf54c4fSMartin Matuska } 113caf54c4fSMartin Matuska 114caf54c4fSMartin Matuska int 115caf54c4fSMartin Matuska archive_format(struct archive *a) 116caf54c4fSMartin Matuska { 117caf54c4fSMartin Matuska return (a->archive_format); 118caf54c4fSMartin Matuska } 119caf54c4fSMartin Matuska 120caf54c4fSMartin Matuska const char * 121caf54c4fSMartin Matuska archive_format_name(struct archive *a) 122caf54c4fSMartin Matuska { 123caf54c4fSMartin Matuska return (a->archive_format_name); 124caf54c4fSMartin Matuska } 125caf54c4fSMartin Matuska 126caf54c4fSMartin Matuska 127caf54c4fSMartin Matuska int 128caf54c4fSMartin Matuska archive_compression(struct archive *a) 129caf54c4fSMartin Matuska { 1306c95142eSMartin Matuska return archive_filter_code(a, 0); 131caf54c4fSMartin Matuska } 132caf54c4fSMartin Matuska 133caf54c4fSMartin Matuska const char * 134caf54c4fSMartin Matuska archive_compression_name(struct archive *a) 135caf54c4fSMartin Matuska { 1366c95142eSMartin Matuska return archive_filter_name(a, 0); 137caf54c4fSMartin Matuska } 138caf54c4fSMartin Matuska 139caf54c4fSMartin Matuska 140caf54c4fSMartin Matuska /* 141caf54c4fSMartin Matuska * Return a count of the number of compressed bytes processed. 142caf54c4fSMartin Matuska */ 143a2a3407cSMartin Matuska la_int64_t 144caf54c4fSMartin Matuska archive_position_compressed(struct archive *a) 145caf54c4fSMartin Matuska { 1466c95142eSMartin Matuska return archive_filter_bytes(a, -1); 147caf54c4fSMartin Matuska } 148caf54c4fSMartin Matuska 149caf54c4fSMartin Matuska /* 150caf54c4fSMartin Matuska * Return a count of the number of uncompressed bytes processed. 151caf54c4fSMartin Matuska */ 152a2a3407cSMartin Matuska la_int64_t 153caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a) 154caf54c4fSMartin Matuska { 1556c95142eSMartin Matuska return archive_filter_bytes(a, 0); 156caf54c4fSMartin Matuska } 157caf54c4fSMartin Matuska 158caf54c4fSMartin Matuska void 159caf54c4fSMartin Matuska archive_clear_error(struct archive *a) 160caf54c4fSMartin Matuska { 161caf54c4fSMartin Matuska archive_string_empty(&a->error_string); 162caf54c4fSMartin Matuska a->error = NULL; 163caf54c4fSMartin Matuska a->archive_error_number = 0; 164caf54c4fSMartin Matuska } 165caf54c4fSMartin Matuska 166caf54c4fSMartin Matuska void 167caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 168caf54c4fSMartin Matuska { 169caf54c4fSMartin Matuska va_list ap; 170caf54c4fSMartin Matuska 171caf54c4fSMartin Matuska a->archive_error_number = error_number; 172caf54c4fSMartin Matuska if (fmt == NULL) { 173caf54c4fSMartin Matuska a->error = NULL; 174caf54c4fSMartin Matuska return; 175caf54c4fSMartin Matuska } 176caf54c4fSMartin Matuska 1776c95142eSMartin Matuska archive_string_empty(&(a->error_string)); 178caf54c4fSMartin Matuska va_start(ap, fmt); 179caf54c4fSMartin Matuska archive_string_vsprintf(&(a->error_string), fmt, ap); 180caf54c4fSMartin Matuska va_end(ap); 181caf54c4fSMartin Matuska a->error = a->error_string.s; 182caf54c4fSMartin Matuska } 183caf54c4fSMartin Matuska 184caf54c4fSMartin Matuska void 185caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src) 186caf54c4fSMartin Matuska { 187caf54c4fSMartin Matuska dest->archive_error_number = src->archive_error_number; 188caf54c4fSMartin Matuska 189caf54c4fSMartin Matuska archive_string_copy(&dest->error_string, &src->error_string); 190caf54c4fSMartin Matuska dest->error = dest->error_string.s; 191caf54c4fSMartin Matuska } 192caf54c4fSMartin Matuska 193caf54c4fSMartin Matuska void 194caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg) 195caf54c4fSMartin Matuska { 196a7f7e457SMartin Matuska static const char msg1[] = "Fatal Internal Error in libarchive: "; 197caf54c4fSMartin Matuska size_t s; 198caf54c4fSMartin Matuska 199caf54c4fSMartin Matuska s = write(2, msg1, strlen(msg1)); 200caf54c4fSMartin Matuska (void)s; /* UNUSED */ 201caf54c4fSMartin Matuska s = write(2, msg, strlen(msg)); 202caf54c4fSMartin Matuska (void)s; /* UNUSED */ 203caf54c4fSMartin Matuska s = write(2, "\n", 1); 204caf54c4fSMartin Matuska (void)s; /* UNUSED */ 205caf54c4fSMartin Matuska exit(retvalue); 206caf54c4fSMartin Matuska } 207caf54c4fSMartin Matuska 208caf54c4fSMartin Matuska /* 2096c95142eSMartin Matuska * Create a temporary file 2106c95142eSMartin Matuska */ 2116c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 2126c95142eSMartin Matuska 2136c95142eSMartin Matuska /* 2146c95142eSMartin Matuska * Do not use Windows tmpfile() function. 2156c95142eSMartin Matuska * It will make a temporary file under the root directory 2166c95142eSMartin Matuska * and it'll cause permission error if a user who is 2176c95142eSMartin Matuska * non-Administrator creates temporary files. 2186c95142eSMartin Matuska * Also Windows version of mktemp family including _mktemp_s 2196c95142eSMartin Matuska * are not secure. 220caf54c4fSMartin Matuska */ 221f9762417SMartin Matuska static int 222f9762417SMartin Matuska __archive_mktempx(const char *tmpdir, wchar_t *template) 223caf54c4fSMartin Matuska { 224a7f7e457SMartin Matuska static const wchar_t prefix[] = L"libarchive_"; 225a7f7e457SMartin Matuska static const wchar_t suffix[] = L"XXXXXXXXXX"; 2266c95142eSMartin Matuska static const wchar_t num[] = { 2276c95142eSMartin Matuska L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 2286c95142eSMartin Matuska L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 2296c95142eSMartin Matuska L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 2306c95142eSMartin Matuska L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 2316c95142eSMartin Matuska L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 2326c95142eSMartin Matuska L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 2336c95142eSMartin Matuska L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 2346c95142eSMartin Matuska L'u', L'v', L'w', L'x', L'y', L'z' 2356c95142eSMartin Matuska }; 2366c95142eSMartin Matuska HCRYPTPROV hProv; 2376c95142eSMartin Matuska struct archive_wstring temp_name; 2386c95142eSMartin Matuska wchar_t *ws; 2396c95142eSMartin Matuska DWORD attr; 2406c95142eSMartin Matuska wchar_t *xp, *ep; 2416c95142eSMartin Matuska int fd; 242caf54c4fSMartin Matuska 2436c95142eSMartin Matuska hProv = (HCRYPTPROV)NULL; 2446c95142eSMartin Matuska fd = -1; 2456c95142eSMartin Matuska ws = NULL; 246f9762417SMartin Matuska 247f9762417SMartin Matuska if (template == NULL) { 2486c95142eSMartin Matuska archive_string_init(&temp_name); 2496c95142eSMartin Matuska 2506c95142eSMartin Matuska /* Get a temporary directory. */ 2516c95142eSMartin Matuska if (tmpdir == NULL) { 2526c95142eSMartin Matuska size_t l; 2536c95142eSMartin Matuska wchar_t *tmp; 2546c95142eSMartin Matuska 2556c95142eSMartin Matuska l = GetTempPathW(0, NULL); 2566c95142eSMartin Matuska if (l == 0) { 2576c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2586c95142eSMartin Matuska goto exit_tmpfile; 2596c95142eSMartin Matuska } 2606c95142eSMartin Matuska tmp = malloc(l*sizeof(wchar_t)); 2616c95142eSMartin Matuska if (tmp == NULL) { 2626c95142eSMartin Matuska errno = ENOMEM; 2636c95142eSMartin Matuska goto exit_tmpfile; 2646c95142eSMartin Matuska } 265acc60b03SMartin Matuska GetTempPathW((DWORD)l, tmp); 2666c95142eSMartin Matuska archive_wstrcpy(&temp_name, tmp); 2676c95142eSMartin Matuska free(tmp); 268caf54c4fSMartin Matuska } else { 269fd082e96SMartin Matuska if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 270fd082e96SMartin Matuska strlen(tmpdir)) < 0) 271fd082e96SMartin Matuska goto exit_tmpfile; 2726c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != L'/') 2736c95142eSMartin Matuska archive_wstrappend_wchar(&temp_name, L'/'); 274caf54c4fSMartin Matuska } 2756c95142eSMartin Matuska 2766c95142eSMartin Matuska /* Check if temp_name is a directory. */ 2776c95142eSMartin Matuska attr = GetFileAttributesW(temp_name.s); 2786c95142eSMartin Matuska if (attr == (DWORD)-1) { 2796c95142eSMartin Matuska if (GetLastError() != ERROR_FILE_NOT_FOUND) { 2806c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2816c95142eSMartin Matuska goto exit_tmpfile; 2826c95142eSMartin Matuska } 2836c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 2846c95142eSMartin Matuska if (ws == NULL) { 2856c95142eSMartin Matuska errno = EINVAL; 2866c95142eSMartin Matuska goto exit_tmpfile; 2876c95142eSMartin Matuska } 2886c95142eSMartin Matuska attr = GetFileAttributesW(ws); 2896c95142eSMartin Matuska if (attr == (DWORD)-1) { 2906c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2916c95142eSMartin Matuska goto exit_tmpfile; 2926c95142eSMartin Matuska } 2936c95142eSMartin Matuska } 2946c95142eSMartin Matuska if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 2956c95142eSMartin Matuska errno = ENOTDIR; 2966c95142eSMartin Matuska goto exit_tmpfile; 2976c95142eSMartin Matuska } 2986c95142eSMartin Matuska 2996c95142eSMartin Matuska /* 3006c95142eSMartin Matuska * Create a temporary file. 3016c95142eSMartin Matuska */ 302cdf63a70SMartin Matuska archive_wstrcat(&temp_name, prefix); 303cdf63a70SMartin Matuska archive_wstrcat(&temp_name, suffix); 3046c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 305cdf63a70SMartin Matuska xp = ep - wcslen(suffix); 306f9762417SMartin Matuska template = temp_name.s; 307f9762417SMartin Matuska } else { 308f9762417SMartin Matuska xp = wcschr(template, L'X'); 309f9762417SMartin Matuska if (xp == NULL) /* No X, programming error */ 310f9762417SMartin Matuska abort(); 311f9762417SMartin Matuska for (ep = xp; *ep == L'X'; ep++) 312f9762417SMartin Matuska continue; 313f9762417SMartin Matuska if (*ep) /* X followed by non X, programming error */ 314f9762417SMartin Matuska abort(); 315f9762417SMartin Matuska } 3166c95142eSMartin Matuska 3176c95142eSMartin Matuska if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 3186c95142eSMartin Matuska CRYPT_VERIFYCONTEXT)) { 3196c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3206c95142eSMartin Matuska goto exit_tmpfile; 3216c95142eSMartin Matuska } 3226c95142eSMartin Matuska 3236c95142eSMartin Matuska for (;;) { 3246c95142eSMartin Matuska wchar_t *p; 3256c95142eSMartin Matuska HANDLE h; 3266c95142eSMartin Matuska 3276c95142eSMartin Matuska /* Generate a random file name through CryptGenRandom(). */ 3286c95142eSMartin Matuska p = xp; 329acc60b03SMartin Matuska if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 330acc60b03SMartin Matuska (BYTE*)p)) { 3316c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3326c95142eSMartin Matuska goto exit_tmpfile; 3336c95142eSMartin Matuska } 3346c95142eSMartin Matuska for (; p < ep; p++) 3356c95142eSMartin Matuska *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 3366c95142eSMartin Matuska 3376c95142eSMartin Matuska free(ws); 338f9762417SMartin Matuska ws = __la_win_permissive_name_w(template); 3396c95142eSMartin Matuska if (ws == NULL) { 3406c95142eSMartin Matuska errno = EINVAL; 3416c95142eSMartin Matuska goto exit_tmpfile; 3426c95142eSMartin Matuska } 343f9762417SMartin Matuska if (template == temp_name.s) { 344f9762417SMartin Matuska attr = FILE_ATTRIBUTE_TEMPORARY | 345f9762417SMartin Matuska FILE_FLAG_DELETE_ON_CLOSE; 346f9762417SMartin Matuska } else { 347f9762417SMartin Matuska /* mkstemp */ 348f9762417SMartin Matuska attr = FILE_ATTRIBUTE_NORMAL; 349f9762417SMartin Matuska } 3506c95142eSMartin Matuska h = CreateFileW(ws, 3516c95142eSMartin Matuska GENERIC_READ | GENERIC_WRITE | DELETE, 3526c95142eSMartin Matuska 0,/* Not share */ 3536c95142eSMartin Matuska NULL, 3546c95142eSMartin Matuska CREATE_NEW,/* Create a new file only */ 355f9762417SMartin Matuska attr, 3566c95142eSMartin Matuska NULL); 3576c95142eSMartin Matuska if (h == INVALID_HANDLE_VALUE) { 3586c95142eSMartin Matuska /* The same file already exists. retry with 3596c95142eSMartin Matuska * a new filename. */ 3606c95142eSMartin Matuska if (GetLastError() == ERROR_FILE_EXISTS) 3616c95142eSMartin Matuska continue; 3626c95142eSMartin Matuska /* Otherwise, fail creation temporary file. */ 3636c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3646c95142eSMartin Matuska goto exit_tmpfile; 3656c95142eSMartin Matuska } 3666c95142eSMartin Matuska fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 3676c95142eSMartin Matuska if (fd == -1) { 368*f55be4fcSMartin Matuska la_dosmaperr(GetLastError()); 3696c95142eSMartin Matuska CloseHandle(h); 3706c95142eSMartin Matuska goto exit_tmpfile; 3716c95142eSMartin Matuska } else 3726c95142eSMartin Matuska break;/* success! */ 3736c95142eSMartin Matuska } 3746c95142eSMartin Matuska exit_tmpfile: 3756c95142eSMartin Matuska if (hProv != (HCRYPTPROV)NULL) 3766c95142eSMartin Matuska CryptReleaseContext(hProv, 0); 3776c95142eSMartin Matuska free(ws); 378f9762417SMartin Matuska if (template == temp_name.s) 3796c95142eSMartin Matuska archive_wstring_free(&temp_name); 3806c95142eSMartin Matuska return (fd); 3816c95142eSMartin Matuska } 3826c95142eSMartin Matuska 383f9762417SMartin Matuska int 384f9762417SMartin Matuska __archive_mktemp(const char *tmpdir) 385f9762417SMartin Matuska { 386f9762417SMartin Matuska return __archive_mktempx(tmpdir, NULL); 387f9762417SMartin Matuska } 388f9762417SMartin Matuska 389f9762417SMartin Matuska int 390f9762417SMartin Matuska __archive_mkstemp(wchar_t *template) 391f9762417SMartin Matuska { 392f9762417SMartin Matuska return __archive_mktempx(NULL, template); 393f9762417SMartin Matuska } 394f9762417SMartin Matuska 3956c95142eSMartin Matuska #else 3966c95142eSMartin Matuska 3976c95142eSMartin Matuska static int 3986c95142eSMartin Matuska get_tempdir(struct archive_string *temppath) 3996c95142eSMartin Matuska { 4006c95142eSMartin Matuska const char *tmp; 4016c95142eSMartin Matuska 4026c95142eSMartin Matuska tmp = getenv("TMPDIR"); 4036c95142eSMartin Matuska if (tmp == NULL) 4046c95142eSMartin Matuska #ifdef _PATH_TMP 4056c95142eSMartin Matuska tmp = _PATH_TMP; 4066c95142eSMartin Matuska #else 4076c95142eSMartin Matuska tmp = "/tmp"; 4086c95142eSMartin Matuska #endif 4096c95142eSMartin Matuska archive_strcpy(temppath, tmp); 4106c95142eSMartin Matuska if (temppath->s[temppath->length-1] != '/') 4116c95142eSMartin Matuska archive_strappend_char(temppath, '/'); 4126c95142eSMartin Matuska return (ARCHIVE_OK); 4136c95142eSMartin Matuska } 4146c95142eSMartin Matuska 4156c95142eSMartin Matuska #if defined(HAVE_MKSTEMP) 4166c95142eSMartin Matuska 4176c95142eSMartin Matuska /* 4186c95142eSMartin Matuska * We can use mkstemp(). 4196c95142eSMartin Matuska */ 4206c95142eSMartin Matuska 4216c95142eSMartin Matuska int 4226c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 4236c95142eSMartin Matuska { 4246c95142eSMartin Matuska struct archive_string temp_name; 4256c95142eSMartin Matuska int fd = -1; 4266c95142eSMartin Matuska 4276c95142eSMartin Matuska archive_string_init(&temp_name); 4286c95142eSMartin Matuska if (tmpdir == NULL) { 4296c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4306c95142eSMartin Matuska goto exit_tmpfile; 431caf54c4fSMartin Matuska } else { 4326c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4336c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != '/') 4346c95142eSMartin Matuska archive_strappend_char(&temp_name, '/'); 435caf54c4fSMartin Matuska } 4366c95142eSMartin Matuska archive_strcat(&temp_name, "libarchive_XXXXXX"); 4376c95142eSMartin Matuska fd = mkstemp(temp_name.s); 4386c95142eSMartin Matuska if (fd < 0) 4396c95142eSMartin Matuska goto exit_tmpfile; 440acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4416c95142eSMartin Matuska unlink(temp_name.s); 4426c95142eSMartin Matuska exit_tmpfile: 4436c95142eSMartin Matuska archive_string_free(&temp_name); 4446c95142eSMartin Matuska return (fd); 445caf54c4fSMartin Matuska } 446caf54c4fSMartin Matuska 447f9762417SMartin Matuska int 448f9762417SMartin Matuska __archive_mkstemp(char *template) 449f9762417SMartin Matuska { 450f9762417SMartin Matuska int fd = -1; 451f9762417SMartin Matuska fd = mkstemp(template); 452f9762417SMartin Matuska if (fd >= 0) 453f9762417SMartin Matuska __archive_ensure_cloexec_flag(fd); 454f9762417SMartin Matuska return (fd); 455f9762417SMartin Matuska } 456f9762417SMartin Matuska 457f9762417SMartin Matuska #else /* !HAVE_MKSTEMP */ 4586c95142eSMartin Matuska 4596c95142eSMartin Matuska /* 4606c95142eSMartin Matuska * We use a private routine. 4616c95142eSMartin Matuska */ 4626c95142eSMartin Matuska 463f9762417SMartin Matuska static int 464f9762417SMartin Matuska __archive_mktempx(const char *tmpdir, char *template) 4656c95142eSMartin Matuska { 4666c95142eSMartin Matuska static const char num[] = { 4676c95142eSMartin Matuska '0', '1', '2', '3', '4', '5', '6', '7', 4686c95142eSMartin Matuska '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 4696c95142eSMartin Matuska 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 4706c95142eSMartin Matuska 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 4716c95142eSMartin Matuska 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 4726c95142eSMartin Matuska 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 4736c95142eSMartin Matuska 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 4746c95142eSMartin Matuska 'u', 'v', 'w', 'x', 'y', 'z' 4756c95142eSMartin Matuska }; 4766c95142eSMartin Matuska struct archive_string temp_name; 4776c95142eSMartin Matuska struct stat st; 4786c95142eSMartin Matuska int fd; 4796c95142eSMartin Matuska char *tp, *ep; 4806c95142eSMartin Matuska 4816c95142eSMartin Matuska fd = -1; 482f9762417SMartin Matuska if (template == NULL) { 4836c95142eSMartin Matuska archive_string_init(&temp_name); 4846c95142eSMartin Matuska if (tmpdir == NULL) { 4856c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4866c95142eSMartin Matuska goto exit_tmpfile; 4876c95142eSMartin Matuska } else 4886c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4896c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] == '/') { 4906c95142eSMartin Matuska temp_name.s[temp_name.length-1] = '\0'; 4916c95142eSMartin Matuska temp_name.length --; 492caf54c4fSMartin Matuska } 49352c2bb75SMartin Matuska if (la_stat(temp_name.s, &st) < 0) 4946c95142eSMartin Matuska goto exit_tmpfile; 4956c95142eSMartin Matuska if (!S_ISDIR(st.st_mode)) { 4966c95142eSMartin Matuska errno = ENOTDIR; 4976c95142eSMartin Matuska goto exit_tmpfile; 4986c95142eSMartin Matuska } 4996c95142eSMartin Matuska archive_strcat(&temp_name, "/libarchive_"); 5006c95142eSMartin Matuska tp = temp_name.s + archive_strlen(&temp_name); 5016c95142eSMartin Matuska archive_strcat(&temp_name, "XXXXXXXXXX"); 5026c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 503f9762417SMartin Matuska template = temp_name.s; 504f9762417SMartin Matuska } else { 505f9762417SMartin Matuska tp = strchr(template, 'X'); 506f9762417SMartin Matuska if (tp == NULL) /* No X, programming error */ 507f9762417SMartin Matuska abort(); 508f9762417SMartin Matuska for (ep = tp; *ep == 'X'; ep++) 509f9762417SMartin Matuska continue; 510f9762417SMartin Matuska if (*ep) /* X followed by non X, programming error */ 511f9762417SMartin Matuska abort(); 512f9762417SMartin Matuska } 5136c95142eSMartin Matuska 5146c95142eSMartin Matuska do { 5156c95142eSMartin Matuska char *p; 5166c95142eSMartin Matuska 5176c95142eSMartin Matuska p = tp; 518cdf63a70SMartin Matuska archive_random(p, ep - p); 519cdf63a70SMartin Matuska while (p < ep) { 520cdf63a70SMartin Matuska int d = *((unsigned char *)p) % sizeof(num); 521cdf63a70SMartin Matuska *p++ = num[d]; 522cdf63a70SMartin Matuska } 523f9762417SMartin Matuska fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 524acc60b03SMartin Matuska 0600); 5256c95142eSMartin Matuska } while (fd < 0 && errno == EEXIST); 5266c95142eSMartin Matuska if (fd < 0) 5276c95142eSMartin Matuska goto exit_tmpfile; 528acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 529f9762417SMartin Matuska if (template == temp_name.s) 5306c95142eSMartin Matuska unlink(temp_name.s); 5316c95142eSMartin Matuska exit_tmpfile: 532f9762417SMartin Matuska if (template == temp_name.s) 5336c95142eSMartin Matuska archive_string_free(&temp_name); 5346c95142eSMartin Matuska return (fd); 535caf54c4fSMartin Matuska } 536caf54c4fSMartin Matuska 537f9762417SMartin Matuska int 538f9762417SMartin Matuska __archive_mktemp(const char *tmpdir) 539f9762417SMartin Matuska { 540f9762417SMartin Matuska return __archive_mktempx(tmpdir, NULL); 541f9762417SMartin Matuska } 542f9762417SMartin Matuska 543f9762417SMartin Matuska int 544f9762417SMartin Matuska __archive_mkstemp(char *template) 545f9762417SMartin Matuska { 546f9762417SMartin Matuska return __archive_mktempx(NULL, template); 547f9762417SMartin Matuska } 548f9762417SMartin Matuska 549f9762417SMartin Matuska #endif /* !HAVE_MKSTEMP */ 5506c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */ 551acc60b03SMartin Matuska 552acc60b03SMartin Matuska /* 553acc60b03SMartin Matuska * Set FD_CLOEXEC flag to a file descriptor if it is not set. 554acc60b03SMartin Matuska * We have to set the flag if the platform does not provide O_CLOEXEC 555acc60b03SMartin Matuska * or F_DUPFD_CLOEXEC flags. 556acc60b03SMartin Matuska * 557acc60b03SMartin Matuska * Note: This function is absolutely called after creating a new file 558acc60b03SMartin Matuska * descriptor even if the platform seemingly provides O_CLOEXEC or 559acc60b03SMartin Matuska * F_DUPFD_CLOEXEC macros because it is possible that the platform 560acc60b03SMartin Matuska * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 561acc60b03SMartin Matuska */ 562acc60b03SMartin Matuska void 563acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd) 564acc60b03SMartin Matuska { 565acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 566cfa49a9bSMartin Matuska (void)fd; /* UNUSED */ 567acc60b03SMartin Matuska #else 568acc60b03SMartin Matuska int flags; 569acc60b03SMartin Matuska 570acc60b03SMartin Matuska if (fd >= 0) { 571acc60b03SMartin Matuska flags = fcntl(fd, F_GETFD); 572acc60b03SMartin Matuska if (flags != -1 && (flags & FD_CLOEXEC) == 0) 573acc60b03SMartin Matuska fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 574acc60b03SMartin Matuska } 575acc60b03SMartin Matuska #endif 576acc60b03SMartin Matuska } 577cdf63a70SMartin Matuska 578cdf63a70SMartin Matuska /* 579cdf63a70SMartin Matuska * Utility function to sort a group of strings using quicksort. 580cdf63a70SMartin Matuska */ 581cdf63a70SMartin Matuska static int 582cdf63a70SMartin Matuska archive_utility_string_sort_helper(char **strings, unsigned int n) 583cdf63a70SMartin Matuska { 584cdf63a70SMartin Matuska unsigned int i, lesser_count, greater_count; 585cdf63a70SMartin Matuska char **lesser, **greater, **tmp, *pivot; 586cdf63a70SMartin Matuska int retval1, retval2; 587cdf63a70SMartin Matuska 588cdf63a70SMartin Matuska /* A list of 0 or 1 elements is already sorted */ 589cdf63a70SMartin Matuska if (n <= 1) 590cdf63a70SMartin Matuska return (ARCHIVE_OK); 591cdf63a70SMartin Matuska 592cdf63a70SMartin Matuska lesser_count = greater_count = 0; 593cdf63a70SMartin Matuska lesser = greater = NULL; 594cdf63a70SMartin Matuska pivot = strings[0]; 595cdf63a70SMartin Matuska for (i = 1; i < n; i++) 596cdf63a70SMartin Matuska { 597cdf63a70SMartin Matuska if (strcmp(strings[i], pivot) < 0) 598cdf63a70SMartin Matuska { 599cdf63a70SMartin Matuska lesser_count++; 600cdf63a70SMartin Matuska tmp = (char **)realloc(lesser, 601cdf63a70SMartin Matuska lesser_count * sizeof(char *)); 602cdf63a70SMartin Matuska if (!tmp) { 603cdf63a70SMartin Matuska free(greater); 604cdf63a70SMartin Matuska free(lesser); 605cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 606cdf63a70SMartin Matuska } 607cdf63a70SMartin Matuska lesser = tmp; 608cdf63a70SMartin Matuska lesser[lesser_count - 1] = strings[i]; 609cdf63a70SMartin Matuska } 610cdf63a70SMartin Matuska else 611cdf63a70SMartin Matuska { 612cdf63a70SMartin Matuska greater_count++; 613cdf63a70SMartin Matuska tmp = (char **)realloc(greater, 614cdf63a70SMartin Matuska greater_count * sizeof(char *)); 615cdf63a70SMartin Matuska if (!tmp) { 616cdf63a70SMartin Matuska free(greater); 617cdf63a70SMartin Matuska free(lesser); 618cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 619cdf63a70SMartin Matuska } 620cdf63a70SMartin Matuska greater = tmp; 621cdf63a70SMartin Matuska greater[greater_count - 1] = strings[i]; 622cdf63a70SMartin Matuska } 623cdf63a70SMartin Matuska } 624cdf63a70SMartin Matuska 625cdf63a70SMartin Matuska /* quicksort(lesser) */ 626cdf63a70SMartin Matuska retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 627cdf63a70SMartin Matuska for (i = 0; i < lesser_count; i++) 628cdf63a70SMartin Matuska strings[i] = lesser[i]; 629cdf63a70SMartin Matuska free(lesser); 630cdf63a70SMartin Matuska 631cdf63a70SMartin Matuska /* pivot */ 632cdf63a70SMartin Matuska strings[lesser_count] = pivot; 633cdf63a70SMartin Matuska 634cdf63a70SMartin Matuska /* quicksort(greater) */ 635cdf63a70SMartin Matuska retval2 = archive_utility_string_sort_helper(greater, greater_count); 636cdf63a70SMartin Matuska for (i = 0; i < greater_count; i++) 637cdf63a70SMartin Matuska strings[lesser_count + 1 + i] = greater[i]; 638cdf63a70SMartin Matuska free(greater); 639cdf63a70SMartin Matuska 640cdf63a70SMartin Matuska return (retval1 < retval2) ? retval1 : retval2; 641cdf63a70SMartin Matuska } 642cdf63a70SMartin Matuska 643cdf63a70SMartin Matuska int 644cdf63a70SMartin Matuska archive_utility_string_sort(char **strings) 645cdf63a70SMartin Matuska { 646cdf63a70SMartin Matuska unsigned int size = 0; 647cdf63a70SMartin Matuska while (strings[size] != NULL) 648cdf63a70SMartin Matuska size++; 649cdf63a70SMartin Matuska return archive_utility_string_sort_helper(strings, size); 650cdf63a70SMartin Matuska } 651