1caf54c4fSMartin Matuska /*- 2*acc60b03SMartin Matuska * Copyright (c) 2009-2012 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 48caf54c4fSMartin Matuska 49caf54c4fSMartin Matuska #include "archive.h" 50caf54c4fSMartin Matuska #include "archive_private.h" 51caf54c4fSMartin Matuska #include "archive_string.h" 52caf54c4fSMartin Matuska 53*acc60b03SMartin Matuska #ifndef O_CLOEXEC 54*acc60b03SMartin Matuska #define O_CLOEXEC 0 55*acc60b03SMartin Matuska #endif 56*acc60b03SMartin Matuska 576c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */ 58caf54c4fSMartin Matuska int 596c95142eSMartin Matuska __archive_clean(struct archive *a) 60caf54c4fSMartin Matuska { 616c95142eSMartin Matuska archive_string_conversion_free(a); 626c95142eSMartin Matuska return (ARCHIVE_OK); 63caf54c4fSMartin Matuska } 64caf54c4fSMartin Matuska 65caf54c4fSMartin Matuska int 66caf54c4fSMartin Matuska archive_version_number(void) 67caf54c4fSMartin Matuska { 68caf54c4fSMartin Matuska return (ARCHIVE_VERSION_NUMBER); 69caf54c4fSMartin Matuska } 70caf54c4fSMartin Matuska 71caf54c4fSMartin Matuska const char * 72caf54c4fSMartin Matuska archive_version_string(void) 73caf54c4fSMartin Matuska { 74caf54c4fSMartin Matuska return (ARCHIVE_VERSION_STRING); 75caf54c4fSMartin Matuska } 76caf54c4fSMartin Matuska 77caf54c4fSMartin Matuska int 78caf54c4fSMartin Matuska archive_errno(struct archive *a) 79caf54c4fSMartin Matuska { 80caf54c4fSMartin Matuska return (a->archive_error_number); 81caf54c4fSMartin Matuska } 82caf54c4fSMartin Matuska 83caf54c4fSMartin Matuska const char * 84caf54c4fSMartin Matuska archive_error_string(struct archive *a) 85caf54c4fSMartin Matuska { 86caf54c4fSMartin Matuska 87caf54c4fSMartin Matuska if (a->error != NULL && *a->error != '\0') 88caf54c4fSMartin Matuska return (a->error); 89caf54c4fSMartin Matuska else 906c95142eSMartin Matuska return (NULL); 91caf54c4fSMartin Matuska } 92caf54c4fSMartin Matuska 93caf54c4fSMartin Matuska int 94caf54c4fSMartin Matuska archive_file_count(struct archive *a) 95caf54c4fSMartin Matuska { 96caf54c4fSMartin Matuska return (a->file_count); 97caf54c4fSMartin Matuska } 98caf54c4fSMartin Matuska 99caf54c4fSMartin Matuska int 100caf54c4fSMartin Matuska archive_format(struct archive *a) 101caf54c4fSMartin Matuska { 102caf54c4fSMartin Matuska return (a->archive_format); 103caf54c4fSMartin Matuska } 104caf54c4fSMartin Matuska 105caf54c4fSMartin Matuska const char * 106caf54c4fSMartin Matuska archive_format_name(struct archive *a) 107caf54c4fSMartin Matuska { 108caf54c4fSMartin Matuska return (a->archive_format_name); 109caf54c4fSMartin Matuska } 110caf54c4fSMartin Matuska 111caf54c4fSMartin Matuska 112caf54c4fSMartin Matuska int 113caf54c4fSMartin Matuska archive_compression(struct archive *a) 114caf54c4fSMartin Matuska { 1156c95142eSMartin Matuska return archive_filter_code(a, 0); 116caf54c4fSMartin Matuska } 117caf54c4fSMartin Matuska 118caf54c4fSMartin Matuska const char * 119caf54c4fSMartin Matuska archive_compression_name(struct archive *a) 120caf54c4fSMartin Matuska { 1216c95142eSMartin Matuska return archive_filter_name(a, 0); 122caf54c4fSMartin Matuska } 123caf54c4fSMartin Matuska 124caf54c4fSMartin Matuska 125caf54c4fSMartin Matuska /* 126caf54c4fSMartin Matuska * Return a count of the number of compressed bytes processed. 127caf54c4fSMartin Matuska */ 128caf54c4fSMartin Matuska int64_t 129caf54c4fSMartin Matuska archive_position_compressed(struct archive *a) 130caf54c4fSMartin Matuska { 1316c95142eSMartin Matuska return archive_filter_bytes(a, -1); 132caf54c4fSMartin Matuska } 133caf54c4fSMartin Matuska 134caf54c4fSMartin Matuska /* 135caf54c4fSMartin Matuska * Return a count of the number of uncompressed bytes processed. 136caf54c4fSMartin Matuska */ 137caf54c4fSMartin Matuska int64_t 138caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a) 139caf54c4fSMartin Matuska { 1406c95142eSMartin Matuska return archive_filter_bytes(a, 0); 141caf54c4fSMartin Matuska } 142caf54c4fSMartin Matuska 143caf54c4fSMartin Matuska void 144caf54c4fSMartin Matuska archive_clear_error(struct archive *a) 145caf54c4fSMartin Matuska { 146caf54c4fSMartin Matuska archive_string_empty(&a->error_string); 147caf54c4fSMartin Matuska a->error = NULL; 148caf54c4fSMartin Matuska a->archive_error_number = 0; 149caf54c4fSMartin Matuska } 150caf54c4fSMartin Matuska 151caf54c4fSMartin Matuska void 152caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 153caf54c4fSMartin Matuska { 154caf54c4fSMartin Matuska va_list ap; 155caf54c4fSMartin Matuska 156caf54c4fSMartin Matuska a->archive_error_number = error_number; 157caf54c4fSMartin Matuska if (fmt == NULL) { 158caf54c4fSMartin Matuska a->error = NULL; 159caf54c4fSMartin Matuska return; 160caf54c4fSMartin Matuska } 161caf54c4fSMartin Matuska 1626c95142eSMartin Matuska archive_string_empty(&(a->error_string)); 163caf54c4fSMartin Matuska va_start(ap, fmt); 164caf54c4fSMartin Matuska archive_string_vsprintf(&(a->error_string), fmt, ap); 165caf54c4fSMartin Matuska va_end(ap); 166caf54c4fSMartin Matuska a->error = a->error_string.s; 167caf54c4fSMartin Matuska } 168caf54c4fSMartin Matuska 169caf54c4fSMartin Matuska void 170caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src) 171caf54c4fSMartin Matuska { 172caf54c4fSMartin Matuska dest->archive_error_number = src->archive_error_number; 173caf54c4fSMartin Matuska 174caf54c4fSMartin Matuska archive_string_copy(&dest->error_string, &src->error_string); 175caf54c4fSMartin Matuska dest->error = dest->error_string.s; 176caf54c4fSMartin Matuska } 177caf54c4fSMartin Matuska 178caf54c4fSMartin Matuska void 179caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg) 180caf54c4fSMartin Matuska { 181caf54c4fSMartin Matuska static const char *msg1 = "Fatal Internal Error in libarchive: "; 182caf54c4fSMartin Matuska size_t s; 183caf54c4fSMartin Matuska 184caf54c4fSMartin Matuska s = write(2, msg1, strlen(msg1)); 185caf54c4fSMartin Matuska (void)s; /* UNUSED */ 186caf54c4fSMartin Matuska s = write(2, msg, strlen(msg)); 187caf54c4fSMartin Matuska (void)s; /* UNUSED */ 188caf54c4fSMartin Matuska s = write(2, "\n", 1); 189caf54c4fSMartin Matuska (void)s; /* UNUSED */ 190caf54c4fSMartin Matuska exit(retvalue); 191caf54c4fSMartin Matuska } 192caf54c4fSMartin Matuska 193caf54c4fSMartin Matuska /* 1946c95142eSMartin Matuska * Create a temporary file 1956c95142eSMartin Matuska */ 1966c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 1976c95142eSMartin Matuska 1986c95142eSMartin Matuska /* 1996c95142eSMartin Matuska * Do not use Windows tmpfile() function. 2006c95142eSMartin Matuska * It will make a temporary file under the root directory 2016c95142eSMartin Matuska * and it'll cause permission error if a user who is 2026c95142eSMartin Matuska * non-Administrator creates temporary files. 2036c95142eSMartin Matuska * Also Windows version of mktemp family including _mktemp_s 2046c95142eSMartin Matuska * are not secure. 205caf54c4fSMartin Matuska */ 206caf54c4fSMartin Matuska int 2076c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 208caf54c4fSMartin Matuska { 2096c95142eSMartin Matuska static const wchar_t num[] = { 2106c95142eSMartin Matuska L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 2116c95142eSMartin Matuska L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 2126c95142eSMartin Matuska L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 2136c95142eSMartin Matuska L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 2146c95142eSMartin Matuska L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 2156c95142eSMartin Matuska L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 2166c95142eSMartin Matuska L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 2176c95142eSMartin Matuska L'u', L'v', L'w', L'x', L'y', L'z' 2186c95142eSMartin Matuska }; 2196c95142eSMartin Matuska HCRYPTPROV hProv; 2206c95142eSMartin Matuska struct archive_wstring temp_name; 2216c95142eSMartin Matuska wchar_t *ws; 2226c95142eSMartin Matuska DWORD attr; 2236c95142eSMartin Matuska wchar_t *xp, *ep; 2246c95142eSMartin Matuska int fd; 225caf54c4fSMartin Matuska 2266c95142eSMartin Matuska hProv = (HCRYPTPROV)NULL; 2276c95142eSMartin Matuska fd = -1; 2286c95142eSMartin Matuska ws = NULL; 2296c95142eSMartin Matuska archive_string_init(&temp_name); 2306c95142eSMartin Matuska 2316c95142eSMartin Matuska /* Get a temporary directory. */ 2326c95142eSMartin Matuska if (tmpdir == NULL) { 2336c95142eSMartin Matuska size_t l; 2346c95142eSMartin Matuska wchar_t *tmp; 2356c95142eSMartin Matuska 2366c95142eSMartin Matuska l = GetTempPathW(0, NULL); 2376c95142eSMartin Matuska if (l == 0) { 2386c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2396c95142eSMartin Matuska goto exit_tmpfile; 2406c95142eSMartin Matuska } 2416c95142eSMartin Matuska tmp = malloc(l*sizeof(wchar_t)); 2426c95142eSMartin Matuska if (tmp == NULL) { 2436c95142eSMartin Matuska errno = ENOMEM; 2446c95142eSMartin Matuska goto exit_tmpfile; 2456c95142eSMartin Matuska } 246*acc60b03SMartin Matuska GetTempPathW((DWORD)l, tmp); 2476c95142eSMartin Matuska archive_wstrcpy(&temp_name, tmp); 2486c95142eSMartin Matuska free(tmp); 249caf54c4fSMartin Matuska } else { 250fd082e96SMartin Matuska if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 251fd082e96SMartin Matuska strlen(tmpdir)) < 0) 252fd082e96SMartin Matuska goto exit_tmpfile; 2536c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != L'/') 2546c95142eSMartin Matuska archive_wstrappend_wchar(&temp_name, L'/'); 255caf54c4fSMartin Matuska } 2566c95142eSMartin Matuska 2576c95142eSMartin Matuska /* Check if temp_name is a directory. */ 2586c95142eSMartin Matuska attr = GetFileAttributesW(temp_name.s); 2596c95142eSMartin Matuska if (attr == (DWORD)-1) { 2606c95142eSMartin Matuska if (GetLastError() != ERROR_FILE_NOT_FOUND) { 2616c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2626c95142eSMartin Matuska goto exit_tmpfile; 2636c95142eSMartin Matuska } 2646c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 2656c95142eSMartin Matuska if (ws == NULL) { 2666c95142eSMartin Matuska errno = EINVAL; 2676c95142eSMartin Matuska goto exit_tmpfile; 2686c95142eSMartin Matuska } 2696c95142eSMartin Matuska attr = GetFileAttributesW(ws); 2706c95142eSMartin Matuska if (attr == (DWORD)-1) { 2716c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2726c95142eSMartin Matuska goto exit_tmpfile; 2736c95142eSMartin Matuska } 2746c95142eSMartin Matuska } 2756c95142eSMartin Matuska if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 2766c95142eSMartin Matuska errno = ENOTDIR; 2776c95142eSMartin Matuska goto exit_tmpfile; 2786c95142eSMartin Matuska } 2796c95142eSMartin Matuska 2806c95142eSMartin Matuska /* 2816c95142eSMartin Matuska * Create a temporary file. 2826c95142eSMartin Matuska */ 2836c95142eSMartin Matuska archive_wstrcat(&temp_name, L"libarchive_"); 2846c95142eSMartin Matuska xp = temp_name.s + archive_strlen(&temp_name); 2856c95142eSMartin Matuska archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 2866c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 2876c95142eSMartin Matuska 2886c95142eSMartin Matuska if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 2896c95142eSMartin Matuska CRYPT_VERIFYCONTEXT)) { 2906c95142eSMartin Matuska la_dosmaperr(GetLastError()); 2916c95142eSMartin Matuska goto exit_tmpfile; 2926c95142eSMartin Matuska } 2936c95142eSMartin Matuska 2946c95142eSMartin Matuska for (;;) { 2956c95142eSMartin Matuska wchar_t *p; 2966c95142eSMartin Matuska HANDLE h; 2976c95142eSMartin Matuska 2986c95142eSMartin Matuska /* Generate a random file name through CryptGenRandom(). */ 2996c95142eSMartin Matuska p = xp; 300*acc60b03SMartin Matuska if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 301*acc60b03SMartin Matuska (BYTE*)p)) { 3026c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3036c95142eSMartin Matuska goto exit_tmpfile; 3046c95142eSMartin Matuska } 3056c95142eSMartin Matuska for (; p < ep; p++) 3066c95142eSMartin Matuska *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 3076c95142eSMartin Matuska 3086c95142eSMartin Matuska free(ws); 3096c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 3106c95142eSMartin Matuska if (ws == NULL) { 3116c95142eSMartin Matuska errno = EINVAL; 3126c95142eSMartin Matuska goto exit_tmpfile; 3136c95142eSMartin Matuska } 3146c95142eSMartin Matuska /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 3156c95142eSMartin Matuska * delete this temporary file immediately when this 3166c95142eSMartin Matuska * file closed. */ 3176c95142eSMartin Matuska h = CreateFileW(ws, 3186c95142eSMartin Matuska GENERIC_READ | GENERIC_WRITE | DELETE, 3196c95142eSMartin Matuska 0,/* Not share */ 3206c95142eSMartin Matuska NULL, 3216c95142eSMartin Matuska CREATE_NEW,/* Create a new file only */ 3226c95142eSMartin Matuska FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 3236c95142eSMartin Matuska NULL); 3246c95142eSMartin Matuska if (h == INVALID_HANDLE_VALUE) { 3256c95142eSMartin Matuska /* The same file already exists. retry with 3266c95142eSMartin Matuska * a new filename. */ 3276c95142eSMartin Matuska if (GetLastError() == ERROR_FILE_EXISTS) 3286c95142eSMartin Matuska continue; 3296c95142eSMartin Matuska /* Otherwise, fail creation temporary file. */ 3306c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3316c95142eSMartin Matuska goto exit_tmpfile; 3326c95142eSMartin Matuska } 3336c95142eSMartin Matuska fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 3346c95142eSMartin Matuska if (fd == -1) { 3356c95142eSMartin Matuska CloseHandle(h); 3366c95142eSMartin Matuska goto exit_tmpfile; 3376c95142eSMartin Matuska } else 3386c95142eSMartin Matuska break;/* success! */ 3396c95142eSMartin Matuska } 3406c95142eSMartin Matuska exit_tmpfile: 3416c95142eSMartin Matuska if (hProv != (HCRYPTPROV)NULL) 3426c95142eSMartin Matuska CryptReleaseContext(hProv, 0); 3436c95142eSMartin Matuska free(ws); 3446c95142eSMartin Matuska archive_wstring_free(&temp_name); 3456c95142eSMartin Matuska return (fd); 3466c95142eSMartin Matuska } 3476c95142eSMartin Matuska 3486c95142eSMartin Matuska #else 3496c95142eSMartin Matuska 3506c95142eSMartin Matuska static int 3516c95142eSMartin Matuska get_tempdir(struct archive_string *temppath) 3526c95142eSMartin Matuska { 3536c95142eSMartin Matuska const char *tmp; 3546c95142eSMartin Matuska 3556c95142eSMartin Matuska tmp = getenv("TMPDIR"); 3566c95142eSMartin Matuska if (tmp == NULL) 3576c95142eSMartin Matuska #ifdef _PATH_TMP 3586c95142eSMartin Matuska tmp = _PATH_TMP; 3596c95142eSMartin Matuska #else 3606c95142eSMartin Matuska tmp = "/tmp"; 3616c95142eSMartin Matuska #endif 3626c95142eSMartin Matuska archive_strcpy(temppath, tmp); 3636c95142eSMartin Matuska if (temppath->s[temppath->length-1] != '/') 3646c95142eSMartin Matuska archive_strappend_char(temppath, '/'); 3656c95142eSMartin Matuska return (ARCHIVE_OK); 3666c95142eSMartin Matuska } 3676c95142eSMartin Matuska 3686c95142eSMartin Matuska #if defined(HAVE_MKSTEMP) 3696c95142eSMartin Matuska 3706c95142eSMartin Matuska /* 3716c95142eSMartin Matuska * We can use mkstemp(). 3726c95142eSMartin Matuska */ 3736c95142eSMartin Matuska 3746c95142eSMartin Matuska int 3756c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 3766c95142eSMartin Matuska { 3776c95142eSMartin Matuska struct archive_string temp_name; 3786c95142eSMartin Matuska int fd = -1; 3796c95142eSMartin Matuska 3806c95142eSMartin Matuska archive_string_init(&temp_name); 3816c95142eSMartin Matuska if (tmpdir == NULL) { 3826c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 3836c95142eSMartin Matuska goto exit_tmpfile; 384caf54c4fSMartin Matuska } else { 3856c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 3866c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != '/') 3876c95142eSMartin Matuska archive_strappend_char(&temp_name, '/'); 388caf54c4fSMartin Matuska } 3896c95142eSMartin Matuska archive_strcat(&temp_name, "libarchive_XXXXXX"); 3906c95142eSMartin Matuska fd = mkstemp(temp_name.s); 3916c95142eSMartin Matuska if (fd < 0) 3926c95142eSMartin Matuska goto exit_tmpfile; 393*acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 3946c95142eSMartin Matuska unlink(temp_name.s); 3956c95142eSMartin Matuska exit_tmpfile: 3966c95142eSMartin Matuska archive_string_free(&temp_name); 3976c95142eSMartin Matuska return (fd); 398caf54c4fSMartin Matuska } 399caf54c4fSMartin Matuska 4006c95142eSMartin Matuska #else 4016c95142eSMartin Matuska 4026c95142eSMartin Matuska /* 4036c95142eSMartin Matuska * We use a private routine. 4046c95142eSMartin Matuska */ 4056c95142eSMartin Matuska 4066c95142eSMartin Matuska int 4076c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 4086c95142eSMartin Matuska { 4096c95142eSMartin Matuska static const char num[] = { 4106c95142eSMartin Matuska '0', '1', '2', '3', '4', '5', '6', '7', 4116c95142eSMartin Matuska '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 4126c95142eSMartin Matuska 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 4136c95142eSMartin Matuska 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 4146c95142eSMartin Matuska 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 4156c95142eSMartin Matuska 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 4166c95142eSMartin Matuska 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 4176c95142eSMartin Matuska 'u', 'v', 'w', 'x', 'y', 'z' 4186c95142eSMartin Matuska }; 4196c95142eSMartin Matuska struct archive_string temp_name; 4206c95142eSMartin Matuska struct stat st; 4216c95142eSMartin Matuska int fd; 4226c95142eSMartin Matuska char *tp, *ep; 4236c95142eSMartin Matuska unsigned seed; 4246c95142eSMartin Matuska 4256c95142eSMartin Matuska fd = -1; 4266c95142eSMartin Matuska archive_string_init(&temp_name); 4276c95142eSMartin Matuska if (tmpdir == NULL) { 4286c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4296c95142eSMartin Matuska goto exit_tmpfile; 4306c95142eSMartin Matuska } else 4316c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4326c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] == '/') { 4336c95142eSMartin Matuska temp_name.s[temp_name.length-1] = '\0'; 4346c95142eSMartin Matuska temp_name.length --; 435caf54c4fSMartin Matuska } 4366c95142eSMartin Matuska if (stat(temp_name.s, &st) < 0) 4376c95142eSMartin Matuska goto exit_tmpfile; 4386c95142eSMartin Matuska if (!S_ISDIR(st.st_mode)) { 4396c95142eSMartin Matuska errno = ENOTDIR; 4406c95142eSMartin Matuska goto exit_tmpfile; 4416c95142eSMartin Matuska } 4426c95142eSMartin Matuska archive_strcat(&temp_name, "/libarchive_"); 4436c95142eSMartin Matuska tp = temp_name.s + archive_strlen(&temp_name); 4446c95142eSMartin Matuska archive_strcat(&temp_name, "XXXXXXXXXX"); 4456c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 4466c95142eSMartin Matuska 447*acc60b03SMartin Matuska fd = open("/dev/random", O_RDONLY | O_CLOEXEC); 448*acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4496c95142eSMartin Matuska if (fd < 0) 4506c95142eSMartin Matuska seed = time(NULL); 4516c95142eSMartin Matuska else { 4526c95142eSMartin Matuska if (read(fd, &seed, sizeof(seed)) < 0) 4536c95142eSMartin Matuska seed = time(NULL); 4546c95142eSMartin Matuska close(fd); 4556c95142eSMartin Matuska } 4566c95142eSMartin Matuska do { 4576c95142eSMartin Matuska char *p; 4586c95142eSMartin Matuska 4596c95142eSMartin Matuska p = tp; 4606c95142eSMartin Matuska while (p < ep) 4616c95142eSMartin Matuska *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 462*acc60b03SMartin Matuska fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 463*acc60b03SMartin Matuska 0600); 4646c95142eSMartin Matuska } while (fd < 0 && errno == EEXIST); 4656c95142eSMartin Matuska if (fd < 0) 4666c95142eSMartin Matuska goto exit_tmpfile; 467*acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4686c95142eSMartin Matuska unlink(temp_name.s); 4696c95142eSMartin Matuska exit_tmpfile: 4706c95142eSMartin Matuska archive_string_free(&temp_name); 4716c95142eSMartin Matuska return (fd); 472caf54c4fSMartin Matuska } 473caf54c4fSMartin Matuska 4746c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */ 4756c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */ 476*acc60b03SMartin Matuska 477*acc60b03SMartin Matuska /* 478*acc60b03SMartin Matuska * Set FD_CLOEXEC flag to a file descriptor if it is not set. 479*acc60b03SMartin Matuska * We have to set the flag if the platform does not provide O_CLOEXEC 480*acc60b03SMartin Matuska * or F_DUPFD_CLOEXEC flags. 481*acc60b03SMartin Matuska * 482*acc60b03SMartin Matuska * Note: This function is absolutely called after creating a new file 483*acc60b03SMartin Matuska * descriptor even if the platform seemingly provides O_CLOEXEC or 484*acc60b03SMartin Matuska * F_DUPFD_CLOEXEC macros because it is possible that the platform 485*acc60b03SMartin Matuska * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 486*acc60b03SMartin Matuska */ 487*acc60b03SMartin Matuska void 488*acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd) 489*acc60b03SMartin Matuska { 490*acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 491*acc60b03SMartin Matuska (void)fd; /* UNSED */ 492*acc60b03SMartin Matuska #else 493*acc60b03SMartin Matuska int flags; 494*acc60b03SMartin Matuska 495*acc60b03SMartin Matuska if (fd >= 0) { 496*acc60b03SMartin Matuska flags = fcntl(fd, F_GETFD); 497*acc60b03SMartin Matuska if (flags != -1 && (flags & FD_CLOEXEC) == 0) 498*acc60b03SMartin Matuska fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 499*acc60b03SMartin Matuska } 500*acc60b03SMartin Matuska #endif 501*acc60b03SMartin Matuska } 502