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 */ 143caf54c4fSMartin Matuska 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 */ 152caf54c4fSMartin Matuska 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 { 196*a7f7e457SMartin 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 */ 221caf54c4fSMartin Matuska int 2226c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 223caf54c4fSMartin Matuska { 224*a7f7e457SMartin Matuska static const wchar_t prefix[] = L"libarchive_"; 225*a7f7e457SMartin 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; 2466c95142eSMartin Matuska archive_string_init(&temp_name); 2476c95142eSMartin Matuska 2486c95142eSMartin Matuska /* Get a temporary directory. */ 2496c95142eSMartin Matuska if (tmpdir == NULL) { 2506c95142eSMartin Matuska size_t l; 2516c95142eSMartin Matuska wchar_t *tmp; 2526c95142eSMartin Matuska 2536c95142eSMartin Matuska l = GetTempPathW(0, NULL); 2546c95142eSMartin Matuska if (l == 0) { 2556c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2566c95142eSMartin Matuska goto exit_tmpfile; 2576c95142eSMartin Matuska } 2586c95142eSMartin Matuska tmp = malloc(l*sizeof(wchar_t)); 2596c95142eSMartin Matuska if (tmp == NULL) { 2606c95142eSMartin Matuska errno = ENOMEM; 2616c95142eSMartin Matuska goto exit_tmpfile; 2626c95142eSMartin Matuska } 263acc60b03SMartin Matuska GetTempPathW((DWORD)l, tmp); 2646c95142eSMartin Matuska archive_wstrcpy(&temp_name, tmp); 2656c95142eSMartin Matuska free(tmp); 266caf54c4fSMartin Matuska } else { 267fd082e96SMartin Matuska if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 268fd082e96SMartin Matuska strlen(tmpdir)) < 0) 269fd082e96SMartin Matuska goto exit_tmpfile; 2706c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != L'/') 2716c95142eSMartin Matuska archive_wstrappend_wchar(&temp_name, L'/'); 272caf54c4fSMartin Matuska } 2736c95142eSMartin Matuska 2746c95142eSMartin Matuska /* Check if temp_name is a directory. */ 2756c95142eSMartin Matuska attr = GetFileAttributesW(temp_name.s); 2766c95142eSMartin Matuska if (attr == (DWORD)-1) { 2776c95142eSMartin Matuska if (GetLastError() != ERROR_FILE_NOT_FOUND) { 2786c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2796c95142eSMartin Matuska goto exit_tmpfile; 2806c95142eSMartin Matuska } 2816c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 2826c95142eSMartin Matuska if (ws == NULL) { 2836c95142eSMartin Matuska errno = EINVAL; 2846c95142eSMartin Matuska goto exit_tmpfile; 2856c95142eSMartin Matuska } 2866c95142eSMartin Matuska attr = GetFileAttributesW(ws); 2876c95142eSMartin Matuska if (attr == (DWORD)-1) { 2886c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2896c95142eSMartin Matuska goto exit_tmpfile; 2906c95142eSMartin Matuska } 2916c95142eSMartin Matuska } 2926c95142eSMartin Matuska if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 2936c95142eSMartin Matuska errno = ENOTDIR; 2946c95142eSMartin Matuska goto exit_tmpfile; 2956c95142eSMartin Matuska } 2966c95142eSMartin Matuska 2976c95142eSMartin Matuska /* 2986c95142eSMartin Matuska * Create a temporary file. 2996c95142eSMartin Matuska */ 300cdf63a70SMartin Matuska archive_wstrcat(&temp_name, prefix); 301cdf63a70SMartin Matuska archive_wstrcat(&temp_name, suffix); 3026c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 303cdf63a70SMartin Matuska xp = ep - wcslen(suffix); 3046c95142eSMartin Matuska 3056c95142eSMartin Matuska if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 3066c95142eSMartin Matuska CRYPT_VERIFYCONTEXT)) { 3076c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3086c95142eSMartin Matuska goto exit_tmpfile; 3096c95142eSMartin Matuska } 3106c95142eSMartin Matuska 3116c95142eSMartin Matuska for (;;) { 3126c95142eSMartin Matuska wchar_t *p; 3136c95142eSMartin Matuska HANDLE h; 3146c95142eSMartin Matuska 3156c95142eSMartin Matuska /* Generate a random file name through CryptGenRandom(). */ 3166c95142eSMartin Matuska p = xp; 317acc60b03SMartin Matuska if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 318acc60b03SMartin Matuska (BYTE*)p)) { 3196c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3206c95142eSMartin Matuska goto exit_tmpfile; 3216c95142eSMartin Matuska } 3226c95142eSMartin Matuska for (; p < ep; p++) 3236c95142eSMartin Matuska *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 3246c95142eSMartin Matuska 3256c95142eSMartin Matuska free(ws); 3266c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 3276c95142eSMartin Matuska if (ws == NULL) { 3286c95142eSMartin Matuska errno = EINVAL; 3296c95142eSMartin Matuska goto exit_tmpfile; 3306c95142eSMartin Matuska } 3316c95142eSMartin Matuska /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 3326c95142eSMartin Matuska * delete this temporary file immediately when this 3336c95142eSMartin Matuska * file closed. */ 3346c95142eSMartin Matuska h = CreateFileW(ws, 3356c95142eSMartin Matuska GENERIC_READ | GENERIC_WRITE | DELETE, 3366c95142eSMartin Matuska 0,/* Not share */ 3376c95142eSMartin Matuska NULL, 3386c95142eSMartin Matuska CREATE_NEW,/* Create a new file only */ 3396c95142eSMartin Matuska FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 3406c95142eSMartin Matuska NULL); 3416c95142eSMartin Matuska if (h == INVALID_HANDLE_VALUE) { 3426c95142eSMartin Matuska /* The same file already exists. retry with 3436c95142eSMartin Matuska * a new filename. */ 3446c95142eSMartin Matuska if (GetLastError() == ERROR_FILE_EXISTS) 3456c95142eSMartin Matuska continue; 3466c95142eSMartin Matuska /* Otherwise, fail creation temporary file. */ 3476c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3486c95142eSMartin Matuska goto exit_tmpfile; 3496c95142eSMartin Matuska } 3506c95142eSMartin Matuska fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 3516c95142eSMartin Matuska if (fd == -1) { 3526c95142eSMartin Matuska CloseHandle(h); 3536c95142eSMartin Matuska goto exit_tmpfile; 3546c95142eSMartin Matuska } else 3556c95142eSMartin Matuska break;/* success! */ 3566c95142eSMartin Matuska } 3576c95142eSMartin Matuska exit_tmpfile: 3586c95142eSMartin Matuska if (hProv != (HCRYPTPROV)NULL) 3596c95142eSMartin Matuska CryptReleaseContext(hProv, 0); 3606c95142eSMartin Matuska free(ws); 3616c95142eSMartin Matuska archive_wstring_free(&temp_name); 3626c95142eSMartin Matuska return (fd); 3636c95142eSMartin Matuska } 3646c95142eSMartin Matuska 3656c95142eSMartin Matuska #else 3666c95142eSMartin Matuska 3676c95142eSMartin Matuska static int 3686c95142eSMartin Matuska get_tempdir(struct archive_string *temppath) 3696c95142eSMartin Matuska { 3706c95142eSMartin Matuska const char *tmp; 3716c95142eSMartin Matuska 3726c95142eSMartin Matuska tmp = getenv("TMPDIR"); 3736c95142eSMartin Matuska if (tmp == NULL) 3746c95142eSMartin Matuska #ifdef _PATH_TMP 3756c95142eSMartin Matuska tmp = _PATH_TMP; 3766c95142eSMartin Matuska #else 3776c95142eSMartin Matuska tmp = "/tmp"; 3786c95142eSMartin Matuska #endif 3796c95142eSMartin Matuska archive_strcpy(temppath, tmp); 3806c95142eSMartin Matuska if (temppath->s[temppath->length-1] != '/') 3816c95142eSMartin Matuska archive_strappend_char(temppath, '/'); 3826c95142eSMartin Matuska return (ARCHIVE_OK); 3836c95142eSMartin Matuska } 3846c95142eSMartin Matuska 3856c95142eSMartin Matuska #if defined(HAVE_MKSTEMP) 3866c95142eSMartin Matuska 3876c95142eSMartin Matuska /* 3886c95142eSMartin Matuska * We can use mkstemp(). 3896c95142eSMartin Matuska */ 3906c95142eSMartin Matuska 3916c95142eSMartin Matuska int 3926c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 3936c95142eSMartin Matuska { 3946c95142eSMartin Matuska struct archive_string temp_name; 3956c95142eSMartin Matuska int fd = -1; 3966c95142eSMartin Matuska 3976c95142eSMartin Matuska archive_string_init(&temp_name); 3986c95142eSMartin Matuska if (tmpdir == NULL) { 3996c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4006c95142eSMartin Matuska goto exit_tmpfile; 401caf54c4fSMartin Matuska } else { 4026c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4036c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != '/') 4046c95142eSMartin Matuska archive_strappend_char(&temp_name, '/'); 405caf54c4fSMartin Matuska } 4066c95142eSMartin Matuska archive_strcat(&temp_name, "libarchive_XXXXXX"); 4076c95142eSMartin Matuska fd = mkstemp(temp_name.s); 4086c95142eSMartin Matuska if (fd < 0) 4096c95142eSMartin Matuska goto exit_tmpfile; 410acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4116c95142eSMartin Matuska unlink(temp_name.s); 4126c95142eSMartin Matuska exit_tmpfile: 4136c95142eSMartin Matuska archive_string_free(&temp_name); 4146c95142eSMartin Matuska return (fd); 415caf54c4fSMartin Matuska } 416caf54c4fSMartin Matuska 4176c95142eSMartin Matuska #else 4186c95142eSMartin Matuska 4196c95142eSMartin Matuska /* 4206c95142eSMartin Matuska * We use a private routine. 4216c95142eSMartin Matuska */ 4226c95142eSMartin Matuska 4236c95142eSMartin Matuska int 4246c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 4256c95142eSMartin Matuska { 4266c95142eSMartin Matuska static const char num[] = { 4276c95142eSMartin Matuska '0', '1', '2', '3', '4', '5', '6', '7', 4286c95142eSMartin Matuska '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 4296c95142eSMartin Matuska 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 4306c95142eSMartin Matuska 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 4316c95142eSMartin Matuska 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 4326c95142eSMartin Matuska 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 4336c95142eSMartin Matuska 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 4346c95142eSMartin Matuska 'u', 'v', 'w', 'x', 'y', 'z' 4356c95142eSMartin Matuska }; 4366c95142eSMartin Matuska struct archive_string temp_name; 4376c95142eSMartin Matuska struct stat st; 4386c95142eSMartin Matuska int fd; 4396c95142eSMartin Matuska char *tp, *ep; 4406c95142eSMartin Matuska 4416c95142eSMartin Matuska fd = -1; 4426c95142eSMartin Matuska archive_string_init(&temp_name); 4436c95142eSMartin Matuska if (tmpdir == NULL) { 4446c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4456c95142eSMartin Matuska goto exit_tmpfile; 4466c95142eSMartin Matuska } else 4476c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4486c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] == '/') { 4496c95142eSMartin Matuska temp_name.s[temp_name.length-1] = '\0'; 4506c95142eSMartin Matuska temp_name.length --; 451caf54c4fSMartin Matuska } 4526c95142eSMartin Matuska if (stat(temp_name.s, &st) < 0) 4536c95142eSMartin Matuska goto exit_tmpfile; 4546c95142eSMartin Matuska if (!S_ISDIR(st.st_mode)) { 4556c95142eSMartin Matuska errno = ENOTDIR; 4566c95142eSMartin Matuska goto exit_tmpfile; 4576c95142eSMartin Matuska } 4586c95142eSMartin Matuska archive_strcat(&temp_name, "/libarchive_"); 4596c95142eSMartin Matuska tp = temp_name.s + archive_strlen(&temp_name); 4606c95142eSMartin Matuska archive_strcat(&temp_name, "XXXXXXXXXX"); 4616c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 4626c95142eSMartin Matuska 4636c95142eSMartin Matuska do { 4646c95142eSMartin Matuska char *p; 4656c95142eSMartin Matuska 4666c95142eSMartin Matuska p = tp; 467cdf63a70SMartin Matuska archive_random(p, ep - p); 468cdf63a70SMartin Matuska while (p < ep) { 469cdf63a70SMartin Matuska int d = *((unsigned char *)p) % sizeof(num); 470cdf63a70SMartin Matuska *p++ = num[d]; 471cdf63a70SMartin Matuska } 472acc60b03SMartin Matuska fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 473acc60b03SMartin Matuska 0600); 4746c95142eSMartin Matuska } while (fd < 0 && errno == EEXIST); 4756c95142eSMartin Matuska if (fd < 0) 4766c95142eSMartin Matuska goto exit_tmpfile; 477acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4786c95142eSMartin Matuska unlink(temp_name.s); 4796c95142eSMartin Matuska exit_tmpfile: 4806c95142eSMartin Matuska archive_string_free(&temp_name); 4816c95142eSMartin Matuska return (fd); 482caf54c4fSMartin Matuska } 483caf54c4fSMartin Matuska 4846c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */ 4856c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */ 486acc60b03SMartin Matuska 487acc60b03SMartin Matuska /* 488acc60b03SMartin Matuska * Set FD_CLOEXEC flag to a file descriptor if it is not set. 489acc60b03SMartin Matuska * We have to set the flag if the platform does not provide O_CLOEXEC 490acc60b03SMartin Matuska * or F_DUPFD_CLOEXEC flags. 491acc60b03SMartin Matuska * 492acc60b03SMartin Matuska * Note: This function is absolutely called after creating a new file 493acc60b03SMartin Matuska * descriptor even if the platform seemingly provides O_CLOEXEC or 494acc60b03SMartin Matuska * F_DUPFD_CLOEXEC macros because it is possible that the platform 495acc60b03SMartin Matuska * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 496acc60b03SMartin Matuska */ 497acc60b03SMartin Matuska void 498acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd) 499acc60b03SMartin Matuska { 500acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 501cfa49a9bSMartin Matuska (void)fd; /* UNUSED */ 502acc60b03SMartin Matuska #else 503acc60b03SMartin Matuska int flags; 504acc60b03SMartin Matuska 505acc60b03SMartin Matuska if (fd >= 0) { 506acc60b03SMartin Matuska flags = fcntl(fd, F_GETFD); 507acc60b03SMartin Matuska if (flags != -1 && (flags & FD_CLOEXEC) == 0) 508acc60b03SMartin Matuska fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 509acc60b03SMartin Matuska } 510acc60b03SMartin Matuska #endif 511acc60b03SMartin Matuska } 512cdf63a70SMartin Matuska 513cdf63a70SMartin Matuska /* 514cdf63a70SMartin Matuska * Utility function to sort a group of strings using quicksort. 515cdf63a70SMartin Matuska */ 516cdf63a70SMartin Matuska static int 517cdf63a70SMartin Matuska archive_utility_string_sort_helper(char **strings, unsigned int n) 518cdf63a70SMartin Matuska { 519cdf63a70SMartin Matuska unsigned int i, lesser_count, greater_count; 520cdf63a70SMartin Matuska char **lesser, **greater, **tmp, *pivot; 521cdf63a70SMartin Matuska int retval1, retval2; 522cdf63a70SMartin Matuska 523cdf63a70SMartin Matuska /* A list of 0 or 1 elements is already sorted */ 524cdf63a70SMartin Matuska if (n <= 1) 525cdf63a70SMartin Matuska return (ARCHIVE_OK); 526cdf63a70SMartin Matuska 527cdf63a70SMartin Matuska lesser_count = greater_count = 0; 528cdf63a70SMartin Matuska lesser = greater = NULL; 529cdf63a70SMartin Matuska pivot = strings[0]; 530cdf63a70SMartin Matuska for (i = 1; i < n; i++) 531cdf63a70SMartin Matuska { 532cdf63a70SMartin Matuska if (strcmp(strings[i], pivot) < 0) 533cdf63a70SMartin Matuska { 534cdf63a70SMartin Matuska lesser_count++; 535cdf63a70SMartin Matuska tmp = (char **)realloc(lesser, 536cdf63a70SMartin Matuska lesser_count * sizeof(char *)); 537cdf63a70SMartin Matuska if (!tmp) { 538cdf63a70SMartin Matuska free(greater); 539cdf63a70SMartin Matuska free(lesser); 540cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 541cdf63a70SMartin Matuska } 542cdf63a70SMartin Matuska lesser = tmp; 543cdf63a70SMartin Matuska lesser[lesser_count - 1] = strings[i]; 544cdf63a70SMartin Matuska } 545cdf63a70SMartin Matuska else 546cdf63a70SMartin Matuska { 547cdf63a70SMartin Matuska greater_count++; 548cdf63a70SMartin Matuska tmp = (char **)realloc(greater, 549cdf63a70SMartin Matuska greater_count * sizeof(char *)); 550cdf63a70SMartin Matuska if (!tmp) { 551cdf63a70SMartin Matuska free(greater); 552cdf63a70SMartin Matuska free(lesser); 553cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 554cdf63a70SMartin Matuska } 555cdf63a70SMartin Matuska greater = tmp; 556cdf63a70SMartin Matuska greater[greater_count - 1] = strings[i]; 557cdf63a70SMartin Matuska } 558cdf63a70SMartin Matuska } 559cdf63a70SMartin Matuska 560cdf63a70SMartin Matuska /* quicksort(lesser) */ 561cdf63a70SMartin Matuska retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 562cdf63a70SMartin Matuska for (i = 0; i < lesser_count; i++) 563cdf63a70SMartin Matuska strings[i] = lesser[i]; 564cdf63a70SMartin Matuska free(lesser); 565cdf63a70SMartin Matuska 566cdf63a70SMartin Matuska /* pivot */ 567cdf63a70SMartin Matuska strings[lesser_count] = pivot; 568cdf63a70SMartin Matuska 569cdf63a70SMartin Matuska /* quicksort(greater) */ 570cdf63a70SMartin Matuska retval2 = archive_utility_string_sort_helper(greater, greater_count); 571cdf63a70SMartin Matuska for (i = 0; i < greater_count; i++) 572cdf63a70SMartin Matuska strings[lesser_count + 1 + i] = greater[i]; 573cdf63a70SMartin Matuska free(greater); 574cdf63a70SMartin Matuska 575cdf63a70SMartin Matuska return (retval1 < retval2) ? retval1 : retval2; 576cdf63a70SMartin Matuska } 577cdf63a70SMartin Matuska 578cdf63a70SMartin Matuska int 579cdf63a70SMartin Matuska archive_utility_string_sort(char **strings) 580cdf63a70SMartin Matuska { 581cdf63a70SMartin Matuska unsigned int size = 0; 582cdf63a70SMartin Matuska while (strings[size] != NULL) 583cdf63a70SMartin Matuska size++; 584cdf63a70SMartin Matuska return archive_utility_string_sort_helper(strings, size); 585cdf63a70SMartin Matuska } 586