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 92cdf63a70SMartin Matuska const char * 93cdf63a70SMartin Matuska archive_version_details(void) 94cdf63a70SMartin Matuska { 95cdf63a70SMartin Matuska static struct archive_string str; 96cdf63a70SMartin Matuska static int init = 0; 97cdf63a70SMartin Matuska const char *zlib = archive_zlib_version(); 98cdf63a70SMartin Matuska const char *liblzma = archive_liblzma_version(); 99cdf63a70SMartin Matuska const char *bzlib = archive_bzlib_version(); 100cdf63a70SMartin Matuska const char *liblz4 = archive_liblz4_version(); 101cdf63a70SMartin Matuska 102cdf63a70SMartin Matuska if (!init) { 103cdf63a70SMartin Matuska archive_string_init(&str); 104cdf63a70SMartin Matuska 105cdf63a70SMartin Matuska archive_strcat(&str, ARCHIVE_VERSION_STRING); 106cdf63a70SMartin Matuska if (zlib != NULL) { 107cdf63a70SMartin Matuska archive_strcat(&str, " zlib/"); 108cdf63a70SMartin Matuska archive_strcat(&str, zlib); 109cdf63a70SMartin Matuska } 110cdf63a70SMartin Matuska if (liblzma) { 111cdf63a70SMartin Matuska archive_strcat(&str, " liblzma/"); 112cdf63a70SMartin Matuska archive_strcat(&str, liblzma); 113cdf63a70SMartin Matuska } 114cdf63a70SMartin Matuska if (bzlib) { 115cdf63a70SMartin Matuska const char *p = bzlib; 116cdf63a70SMartin Matuska const char *sep = strchr(p, ','); 117cdf63a70SMartin Matuska if (sep == NULL) 118cdf63a70SMartin Matuska sep = p + strlen(p); 119cdf63a70SMartin Matuska archive_strcat(&str, " bz2lib/"); 120cdf63a70SMartin Matuska archive_strncat(&str, p, sep - p); 121cdf63a70SMartin Matuska } 122cdf63a70SMartin Matuska if (liblz4) { 123cdf63a70SMartin Matuska archive_strcat(&str, " liblz4/"); 124cdf63a70SMartin Matuska archive_strcat(&str, liblz4); 125cdf63a70SMartin Matuska } 126cdf63a70SMartin Matuska } 127cdf63a70SMartin Matuska return str.s; 128cdf63a70SMartin Matuska } 129cdf63a70SMartin Matuska 130cdf63a70SMartin Matuska const char * 131cdf63a70SMartin Matuska archive_zlib_version(void) 132cdf63a70SMartin Matuska { 133cdf63a70SMartin Matuska #ifdef HAVE_ZLIB_H 134cdf63a70SMartin Matuska return ZLIB_VERSION; 135cdf63a70SMartin Matuska #else 136cdf63a70SMartin Matuska return NULL; 137cdf63a70SMartin Matuska #endif 138cdf63a70SMartin Matuska } 139cdf63a70SMartin Matuska 140cdf63a70SMartin Matuska const char * 141cdf63a70SMartin Matuska archive_liblzma_version(void) 142cdf63a70SMartin Matuska { 143cdf63a70SMartin Matuska #ifdef HAVE_LZMA_H 144cdf63a70SMartin Matuska return LZMA_VERSION_STRING; 145cdf63a70SMartin Matuska #else 146cdf63a70SMartin Matuska return NULL; 147cdf63a70SMartin Matuska #endif 148cdf63a70SMartin Matuska } 149cdf63a70SMartin Matuska 150cdf63a70SMartin Matuska const char * 151cdf63a70SMartin Matuska archive_bzlib_version(void) 152cdf63a70SMartin Matuska { 153cdf63a70SMartin Matuska #ifdef HAVE_BZLIB_H 154cdf63a70SMartin Matuska return BZ2_bzlibVersion(); 155cdf63a70SMartin Matuska #else 156cdf63a70SMartin Matuska return NULL; 157cdf63a70SMartin Matuska #endif 158cdf63a70SMartin Matuska } 159cdf63a70SMartin Matuska 160cdf63a70SMartin Matuska const char * 161cdf63a70SMartin Matuska archive_liblz4_version(void) 162cdf63a70SMartin Matuska { 163cdf63a70SMartin Matuska #if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) 164cdf63a70SMartin Matuska #define str(s) #s 165cdf63a70SMartin Matuska #define NUMBER(x) str(x) 166cdf63a70SMartin Matuska return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE); 167cdf63a70SMartin Matuska #undef NUMBER 168cdf63a70SMartin Matuska #undef str 169cdf63a70SMartin Matuska #else 170cdf63a70SMartin Matuska return NULL; 171cdf63a70SMartin Matuska #endif 172cdf63a70SMartin Matuska } 173cdf63a70SMartin Matuska 174caf54c4fSMartin Matuska int 175caf54c4fSMartin Matuska archive_errno(struct archive *a) 176caf54c4fSMartin Matuska { 177caf54c4fSMartin Matuska return (a->archive_error_number); 178caf54c4fSMartin Matuska } 179caf54c4fSMartin Matuska 180caf54c4fSMartin Matuska const char * 181caf54c4fSMartin Matuska archive_error_string(struct archive *a) 182caf54c4fSMartin Matuska { 183caf54c4fSMartin Matuska 184caf54c4fSMartin Matuska if (a->error != NULL && *a->error != '\0') 185caf54c4fSMartin Matuska return (a->error); 186caf54c4fSMartin Matuska else 1876c95142eSMartin Matuska return (NULL); 188caf54c4fSMartin Matuska } 189caf54c4fSMartin Matuska 190caf54c4fSMartin Matuska int 191caf54c4fSMartin Matuska archive_file_count(struct archive *a) 192caf54c4fSMartin Matuska { 193caf54c4fSMartin Matuska return (a->file_count); 194caf54c4fSMartin Matuska } 195caf54c4fSMartin Matuska 196caf54c4fSMartin Matuska int 197caf54c4fSMartin Matuska archive_format(struct archive *a) 198caf54c4fSMartin Matuska { 199caf54c4fSMartin Matuska return (a->archive_format); 200caf54c4fSMartin Matuska } 201caf54c4fSMartin Matuska 202caf54c4fSMartin Matuska const char * 203caf54c4fSMartin Matuska archive_format_name(struct archive *a) 204caf54c4fSMartin Matuska { 205caf54c4fSMartin Matuska return (a->archive_format_name); 206caf54c4fSMartin Matuska } 207caf54c4fSMartin Matuska 208caf54c4fSMartin Matuska 209caf54c4fSMartin Matuska int 210caf54c4fSMartin Matuska archive_compression(struct archive *a) 211caf54c4fSMartin Matuska { 2126c95142eSMartin Matuska return archive_filter_code(a, 0); 213caf54c4fSMartin Matuska } 214caf54c4fSMartin Matuska 215caf54c4fSMartin Matuska const char * 216caf54c4fSMartin Matuska archive_compression_name(struct archive *a) 217caf54c4fSMartin Matuska { 2186c95142eSMartin Matuska return archive_filter_name(a, 0); 219caf54c4fSMartin Matuska } 220caf54c4fSMartin Matuska 221caf54c4fSMartin Matuska 222caf54c4fSMartin Matuska /* 223caf54c4fSMartin Matuska * Return a count of the number of compressed bytes processed. 224caf54c4fSMartin Matuska */ 225caf54c4fSMartin Matuska int64_t 226caf54c4fSMartin Matuska archive_position_compressed(struct archive *a) 227caf54c4fSMartin Matuska { 2286c95142eSMartin Matuska return archive_filter_bytes(a, -1); 229caf54c4fSMartin Matuska } 230caf54c4fSMartin Matuska 231caf54c4fSMartin Matuska /* 232caf54c4fSMartin Matuska * Return a count of the number of uncompressed bytes processed. 233caf54c4fSMartin Matuska */ 234caf54c4fSMartin Matuska int64_t 235caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a) 236caf54c4fSMartin Matuska { 2376c95142eSMartin Matuska return archive_filter_bytes(a, 0); 238caf54c4fSMartin Matuska } 239caf54c4fSMartin Matuska 240caf54c4fSMartin Matuska void 241caf54c4fSMartin Matuska archive_clear_error(struct archive *a) 242caf54c4fSMartin Matuska { 243caf54c4fSMartin Matuska archive_string_empty(&a->error_string); 244caf54c4fSMartin Matuska a->error = NULL; 245caf54c4fSMartin Matuska a->archive_error_number = 0; 246caf54c4fSMartin Matuska } 247caf54c4fSMartin Matuska 248caf54c4fSMartin Matuska void 249caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 250caf54c4fSMartin Matuska { 251caf54c4fSMartin Matuska va_list ap; 252caf54c4fSMartin Matuska 253caf54c4fSMartin Matuska a->archive_error_number = error_number; 254caf54c4fSMartin Matuska if (fmt == NULL) { 255caf54c4fSMartin Matuska a->error = NULL; 256caf54c4fSMartin Matuska return; 257caf54c4fSMartin Matuska } 258caf54c4fSMartin Matuska 2596c95142eSMartin Matuska archive_string_empty(&(a->error_string)); 260caf54c4fSMartin Matuska va_start(ap, fmt); 261caf54c4fSMartin Matuska archive_string_vsprintf(&(a->error_string), fmt, ap); 262caf54c4fSMartin Matuska va_end(ap); 263caf54c4fSMartin Matuska a->error = a->error_string.s; 264caf54c4fSMartin Matuska } 265caf54c4fSMartin Matuska 266caf54c4fSMartin Matuska void 267caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src) 268caf54c4fSMartin Matuska { 269caf54c4fSMartin Matuska dest->archive_error_number = src->archive_error_number; 270caf54c4fSMartin Matuska 271caf54c4fSMartin Matuska archive_string_copy(&dest->error_string, &src->error_string); 272caf54c4fSMartin Matuska dest->error = dest->error_string.s; 273caf54c4fSMartin Matuska } 274caf54c4fSMartin Matuska 275caf54c4fSMartin Matuska void 276caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg) 277caf54c4fSMartin Matuska { 278caf54c4fSMartin Matuska static const char *msg1 = "Fatal Internal Error in libarchive: "; 279caf54c4fSMartin Matuska size_t s; 280caf54c4fSMartin Matuska 281caf54c4fSMartin Matuska s = write(2, msg1, strlen(msg1)); 282caf54c4fSMartin Matuska (void)s; /* UNUSED */ 283caf54c4fSMartin Matuska s = write(2, msg, strlen(msg)); 284caf54c4fSMartin Matuska (void)s; /* UNUSED */ 285caf54c4fSMartin Matuska s = write(2, "\n", 1); 286caf54c4fSMartin Matuska (void)s; /* UNUSED */ 287caf54c4fSMartin Matuska exit(retvalue); 288caf54c4fSMartin Matuska } 289caf54c4fSMartin Matuska 290caf54c4fSMartin Matuska /* 2916c95142eSMartin Matuska * Create a temporary file 2926c95142eSMartin Matuska */ 2936c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 2946c95142eSMartin Matuska 2956c95142eSMartin Matuska /* 2966c95142eSMartin Matuska * Do not use Windows tmpfile() function. 2976c95142eSMartin Matuska * It will make a temporary file under the root directory 2986c95142eSMartin Matuska * and it'll cause permission error if a user who is 2996c95142eSMartin Matuska * non-Administrator creates temporary files. 3006c95142eSMartin Matuska * Also Windows version of mktemp family including _mktemp_s 3016c95142eSMartin Matuska * are not secure. 302caf54c4fSMartin Matuska */ 303caf54c4fSMartin Matuska int 3046c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 305caf54c4fSMartin Matuska { 306cdf63a70SMartin Matuska static const wchar_t *prefix = L"libarchive_"; 307cdf63a70SMartin Matuska static const wchar_t *suffix = L"XXXXXXXXXX"; 3086c95142eSMartin Matuska static const wchar_t num[] = { 3096c95142eSMartin Matuska L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 3106c95142eSMartin Matuska L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 3116c95142eSMartin Matuska L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 3126c95142eSMartin Matuska L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 3136c95142eSMartin Matuska L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 3146c95142eSMartin Matuska L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 3156c95142eSMartin Matuska L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 3166c95142eSMartin Matuska L'u', L'v', L'w', L'x', L'y', L'z' 3176c95142eSMartin Matuska }; 3186c95142eSMartin Matuska HCRYPTPROV hProv; 3196c95142eSMartin Matuska struct archive_wstring temp_name; 3206c95142eSMartin Matuska wchar_t *ws; 3216c95142eSMartin Matuska DWORD attr; 3226c95142eSMartin Matuska wchar_t *xp, *ep; 3236c95142eSMartin Matuska int fd; 324caf54c4fSMartin Matuska 3256c95142eSMartin Matuska hProv = (HCRYPTPROV)NULL; 3266c95142eSMartin Matuska fd = -1; 3276c95142eSMartin Matuska ws = NULL; 3286c95142eSMartin Matuska archive_string_init(&temp_name); 3296c95142eSMartin Matuska 3306c95142eSMartin Matuska /* Get a temporary directory. */ 3316c95142eSMartin Matuska if (tmpdir == NULL) { 3326c95142eSMartin Matuska size_t l; 3336c95142eSMartin Matuska wchar_t *tmp; 3346c95142eSMartin Matuska 3356c95142eSMartin Matuska l = GetTempPathW(0, NULL); 3366c95142eSMartin Matuska if (l == 0) { 3376c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3386c95142eSMartin Matuska goto exit_tmpfile; 3396c95142eSMartin Matuska } 3406c95142eSMartin Matuska tmp = malloc(l*sizeof(wchar_t)); 3416c95142eSMartin Matuska if (tmp == NULL) { 3426c95142eSMartin Matuska errno = ENOMEM; 3436c95142eSMartin Matuska goto exit_tmpfile; 3446c95142eSMartin Matuska } 345acc60b03SMartin Matuska GetTempPathW((DWORD)l, tmp); 3466c95142eSMartin Matuska archive_wstrcpy(&temp_name, tmp); 3476c95142eSMartin Matuska free(tmp); 348caf54c4fSMartin Matuska } else { 349fd082e96SMartin Matuska if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 350fd082e96SMartin Matuska strlen(tmpdir)) < 0) 351fd082e96SMartin Matuska goto exit_tmpfile; 3526c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != L'/') 3536c95142eSMartin Matuska archive_wstrappend_wchar(&temp_name, L'/'); 354caf54c4fSMartin Matuska } 3556c95142eSMartin Matuska 3566c95142eSMartin Matuska /* Check if temp_name is a directory. */ 3576c95142eSMartin Matuska attr = GetFileAttributesW(temp_name.s); 3586c95142eSMartin Matuska if (attr == (DWORD)-1) { 3596c95142eSMartin Matuska if (GetLastError() != ERROR_FILE_NOT_FOUND) { 3606c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3616c95142eSMartin Matuska goto exit_tmpfile; 3626c95142eSMartin Matuska } 3636c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 3646c95142eSMartin Matuska if (ws == NULL) { 3656c95142eSMartin Matuska errno = EINVAL; 3666c95142eSMartin Matuska goto exit_tmpfile; 3676c95142eSMartin Matuska } 3686c95142eSMartin Matuska attr = GetFileAttributesW(ws); 3696c95142eSMartin Matuska if (attr == (DWORD)-1) { 3706c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3716c95142eSMartin Matuska goto exit_tmpfile; 3726c95142eSMartin Matuska } 3736c95142eSMartin Matuska } 3746c95142eSMartin Matuska if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 3756c95142eSMartin Matuska errno = ENOTDIR; 3766c95142eSMartin Matuska goto exit_tmpfile; 3776c95142eSMartin Matuska } 3786c95142eSMartin Matuska 3796c95142eSMartin Matuska /* 3806c95142eSMartin Matuska * Create a temporary file. 3816c95142eSMartin Matuska */ 382cdf63a70SMartin Matuska archive_wstrcat(&temp_name, prefix); 383cdf63a70SMartin Matuska archive_wstrcat(&temp_name, suffix); 3846c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 385cdf63a70SMartin Matuska xp = ep - wcslen(suffix); 3866c95142eSMartin Matuska 3876c95142eSMartin Matuska if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 3886c95142eSMartin Matuska CRYPT_VERIFYCONTEXT)) { 3896c95142eSMartin Matuska la_dosmaperr(GetLastError()); 3906c95142eSMartin Matuska goto exit_tmpfile; 3916c95142eSMartin Matuska } 3926c95142eSMartin Matuska 3936c95142eSMartin Matuska for (;;) { 3946c95142eSMartin Matuska wchar_t *p; 3956c95142eSMartin Matuska HANDLE h; 3966c95142eSMartin Matuska 3976c95142eSMartin Matuska /* Generate a random file name through CryptGenRandom(). */ 3986c95142eSMartin Matuska p = xp; 399acc60b03SMartin Matuska if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 400acc60b03SMartin Matuska (BYTE*)p)) { 4016c95142eSMartin Matuska la_dosmaperr(GetLastError()); 4026c95142eSMartin Matuska goto exit_tmpfile; 4036c95142eSMartin Matuska } 4046c95142eSMartin Matuska for (; p < ep; p++) 4056c95142eSMartin Matuska *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 4066c95142eSMartin Matuska 4076c95142eSMartin Matuska free(ws); 4086c95142eSMartin Matuska ws = __la_win_permissive_name_w(temp_name.s); 4096c95142eSMartin Matuska if (ws == NULL) { 4106c95142eSMartin Matuska errno = EINVAL; 4116c95142eSMartin Matuska goto exit_tmpfile; 4126c95142eSMartin Matuska } 4136c95142eSMartin Matuska /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 4146c95142eSMartin Matuska * delete this temporary file immediately when this 4156c95142eSMartin Matuska * file closed. */ 4166c95142eSMartin Matuska h = CreateFileW(ws, 4176c95142eSMartin Matuska GENERIC_READ | GENERIC_WRITE | DELETE, 4186c95142eSMartin Matuska 0,/* Not share */ 4196c95142eSMartin Matuska NULL, 4206c95142eSMartin Matuska CREATE_NEW,/* Create a new file only */ 4216c95142eSMartin Matuska FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 4226c95142eSMartin Matuska NULL); 4236c95142eSMartin Matuska if (h == INVALID_HANDLE_VALUE) { 4246c95142eSMartin Matuska /* The same file already exists. retry with 4256c95142eSMartin Matuska * a new filename. */ 4266c95142eSMartin Matuska if (GetLastError() == ERROR_FILE_EXISTS) 4276c95142eSMartin Matuska continue; 4286c95142eSMartin Matuska /* Otherwise, fail creation temporary file. */ 4296c95142eSMartin Matuska la_dosmaperr(GetLastError()); 4306c95142eSMartin Matuska goto exit_tmpfile; 4316c95142eSMartin Matuska } 4326c95142eSMartin Matuska fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 4336c95142eSMartin Matuska if (fd == -1) { 4346c95142eSMartin Matuska CloseHandle(h); 4356c95142eSMartin Matuska goto exit_tmpfile; 4366c95142eSMartin Matuska } else 4376c95142eSMartin Matuska break;/* success! */ 4386c95142eSMartin Matuska } 4396c95142eSMartin Matuska exit_tmpfile: 4406c95142eSMartin Matuska if (hProv != (HCRYPTPROV)NULL) 4416c95142eSMartin Matuska CryptReleaseContext(hProv, 0); 4426c95142eSMartin Matuska free(ws); 4436c95142eSMartin Matuska archive_wstring_free(&temp_name); 4446c95142eSMartin Matuska return (fd); 4456c95142eSMartin Matuska } 4466c95142eSMartin Matuska 4476c95142eSMartin Matuska #else 4486c95142eSMartin Matuska 4496c95142eSMartin Matuska static int 4506c95142eSMartin Matuska get_tempdir(struct archive_string *temppath) 4516c95142eSMartin Matuska { 4526c95142eSMartin Matuska const char *tmp; 4536c95142eSMartin Matuska 4546c95142eSMartin Matuska tmp = getenv("TMPDIR"); 4556c95142eSMartin Matuska if (tmp == NULL) 4566c95142eSMartin Matuska #ifdef _PATH_TMP 4576c95142eSMartin Matuska tmp = _PATH_TMP; 4586c95142eSMartin Matuska #else 4596c95142eSMartin Matuska tmp = "/tmp"; 4606c95142eSMartin Matuska #endif 4616c95142eSMartin Matuska archive_strcpy(temppath, tmp); 4626c95142eSMartin Matuska if (temppath->s[temppath->length-1] != '/') 4636c95142eSMartin Matuska archive_strappend_char(temppath, '/'); 4646c95142eSMartin Matuska return (ARCHIVE_OK); 4656c95142eSMartin Matuska } 4666c95142eSMartin Matuska 4676c95142eSMartin Matuska #if defined(HAVE_MKSTEMP) 4686c95142eSMartin Matuska 4696c95142eSMartin Matuska /* 4706c95142eSMartin Matuska * We can use mkstemp(). 4716c95142eSMartin Matuska */ 4726c95142eSMartin Matuska 4736c95142eSMartin Matuska int 4746c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 4756c95142eSMartin Matuska { 4766c95142eSMartin Matuska struct archive_string temp_name; 4776c95142eSMartin Matuska int fd = -1; 4786c95142eSMartin Matuska 4796c95142eSMartin Matuska archive_string_init(&temp_name); 4806c95142eSMartin Matuska if (tmpdir == NULL) { 4816c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 4826c95142eSMartin Matuska goto exit_tmpfile; 483caf54c4fSMartin Matuska } else { 4846c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 4856c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] != '/') 4866c95142eSMartin Matuska archive_strappend_char(&temp_name, '/'); 487caf54c4fSMartin Matuska } 4886c95142eSMartin Matuska archive_strcat(&temp_name, "libarchive_XXXXXX"); 4896c95142eSMartin Matuska fd = mkstemp(temp_name.s); 4906c95142eSMartin Matuska if (fd < 0) 4916c95142eSMartin Matuska goto exit_tmpfile; 492acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 4936c95142eSMartin Matuska unlink(temp_name.s); 4946c95142eSMartin Matuska exit_tmpfile: 4956c95142eSMartin Matuska archive_string_free(&temp_name); 4966c95142eSMartin Matuska return (fd); 497caf54c4fSMartin Matuska } 498caf54c4fSMartin Matuska 4996c95142eSMartin Matuska #else 5006c95142eSMartin Matuska 5016c95142eSMartin Matuska /* 5026c95142eSMartin Matuska * We use a private routine. 5036c95142eSMartin Matuska */ 5046c95142eSMartin Matuska 5056c95142eSMartin Matuska int 5066c95142eSMartin Matuska __archive_mktemp(const char *tmpdir) 5076c95142eSMartin Matuska { 5086c95142eSMartin Matuska static const char num[] = { 5096c95142eSMartin Matuska '0', '1', '2', '3', '4', '5', '6', '7', 5106c95142eSMartin Matuska '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 5116c95142eSMartin Matuska 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 5126c95142eSMartin Matuska 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 5136c95142eSMartin Matuska 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 5146c95142eSMartin Matuska 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 5156c95142eSMartin Matuska 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 5166c95142eSMartin Matuska 'u', 'v', 'w', 'x', 'y', 'z' 5176c95142eSMartin Matuska }; 5186c95142eSMartin Matuska struct archive_string temp_name; 5196c95142eSMartin Matuska struct stat st; 5206c95142eSMartin Matuska int fd; 5216c95142eSMartin Matuska char *tp, *ep; 5226c95142eSMartin Matuska 5236c95142eSMartin Matuska fd = -1; 5246c95142eSMartin Matuska archive_string_init(&temp_name); 5256c95142eSMartin Matuska if (tmpdir == NULL) { 5266c95142eSMartin Matuska if (get_tempdir(&temp_name) != ARCHIVE_OK) 5276c95142eSMartin Matuska goto exit_tmpfile; 5286c95142eSMartin Matuska } else 5296c95142eSMartin Matuska archive_strcpy(&temp_name, tmpdir); 5306c95142eSMartin Matuska if (temp_name.s[temp_name.length-1] == '/') { 5316c95142eSMartin Matuska temp_name.s[temp_name.length-1] = '\0'; 5326c95142eSMartin Matuska temp_name.length --; 533caf54c4fSMartin Matuska } 5346c95142eSMartin Matuska if (stat(temp_name.s, &st) < 0) 5356c95142eSMartin Matuska goto exit_tmpfile; 5366c95142eSMartin Matuska if (!S_ISDIR(st.st_mode)) { 5376c95142eSMartin Matuska errno = ENOTDIR; 5386c95142eSMartin Matuska goto exit_tmpfile; 5396c95142eSMartin Matuska } 5406c95142eSMartin Matuska archive_strcat(&temp_name, "/libarchive_"); 5416c95142eSMartin Matuska tp = temp_name.s + archive_strlen(&temp_name); 5426c95142eSMartin Matuska archive_strcat(&temp_name, "XXXXXXXXXX"); 5436c95142eSMartin Matuska ep = temp_name.s + archive_strlen(&temp_name); 5446c95142eSMartin Matuska 5456c95142eSMartin Matuska do { 5466c95142eSMartin Matuska char *p; 5476c95142eSMartin Matuska 5486c95142eSMartin Matuska p = tp; 549cdf63a70SMartin Matuska archive_random(p, ep - p); 550cdf63a70SMartin Matuska while (p < ep) { 551cdf63a70SMartin Matuska int d = *((unsigned char *)p) % sizeof(num); 552cdf63a70SMartin Matuska *p++ = num[d]; 553cdf63a70SMartin Matuska } 554acc60b03SMartin Matuska fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 555acc60b03SMartin Matuska 0600); 5566c95142eSMartin Matuska } while (fd < 0 && errno == EEXIST); 5576c95142eSMartin Matuska if (fd < 0) 5586c95142eSMartin Matuska goto exit_tmpfile; 559acc60b03SMartin Matuska __archive_ensure_cloexec_flag(fd); 5606c95142eSMartin Matuska unlink(temp_name.s); 5616c95142eSMartin Matuska exit_tmpfile: 5626c95142eSMartin Matuska archive_string_free(&temp_name); 5636c95142eSMartin Matuska return (fd); 564caf54c4fSMartin Matuska } 565caf54c4fSMartin Matuska 5666c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */ 5676c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */ 568acc60b03SMartin Matuska 569acc60b03SMartin Matuska /* 570acc60b03SMartin Matuska * Set FD_CLOEXEC flag to a file descriptor if it is not set. 571acc60b03SMartin Matuska * We have to set the flag if the platform does not provide O_CLOEXEC 572acc60b03SMartin Matuska * or F_DUPFD_CLOEXEC flags. 573acc60b03SMartin Matuska * 574acc60b03SMartin Matuska * Note: This function is absolutely called after creating a new file 575acc60b03SMartin Matuska * descriptor even if the platform seemingly provides O_CLOEXEC or 576acc60b03SMartin Matuska * F_DUPFD_CLOEXEC macros because it is possible that the platform 577acc60b03SMartin Matuska * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 578acc60b03SMartin Matuska */ 579acc60b03SMartin Matuska void 580acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd) 581acc60b03SMartin Matuska { 582acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 583*cfa49a9bSMartin Matuska (void)fd; /* UNUSED */ 584acc60b03SMartin Matuska #else 585acc60b03SMartin Matuska int flags; 586acc60b03SMartin Matuska 587acc60b03SMartin Matuska if (fd >= 0) { 588acc60b03SMartin Matuska flags = fcntl(fd, F_GETFD); 589acc60b03SMartin Matuska if (flags != -1 && (flags & FD_CLOEXEC) == 0) 590acc60b03SMartin Matuska fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 591acc60b03SMartin Matuska } 592acc60b03SMartin Matuska #endif 593acc60b03SMartin Matuska } 594cdf63a70SMartin Matuska 595cdf63a70SMartin Matuska /* 596cdf63a70SMartin Matuska * Utility function to sort a group of strings using quicksort. 597cdf63a70SMartin Matuska */ 598cdf63a70SMartin Matuska static int 599cdf63a70SMartin Matuska archive_utility_string_sort_helper(char **strings, unsigned int n) 600cdf63a70SMartin Matuska { 601cdf63a70SMartin Matuska unsigned int i, lesser_count, greater_count; 602cdf63a70SMartin Matuska char **lesser, **greater, **tmp, *pivot; 603cdf63a70SMartin Matuska int retval1, retval2; 604cdf63a70SMartin Matuska 605cdf63a70SMartin Matuska /* A list of 0 or 1 elements is already sorted */ 606cdf63a70SMartin Matuska if (n <= 1) 607cdf63a70SMartin Matuska return (ARCHIVE_OK); 608cdf63a70SMartin Matuska 609cdf63a70SMartin Matuska lesser_count = greater_count = 0; 610cdf63a70SMartin Matuska lesser = greater = NULL; 611cdf63a70SMartin Matuska pivot = strings[0]; 612cdf63a70SMartin Matuska for (i = 1; i < n; i++) 613cdf63a70SMartin Matuska { 614cdf63a70SMartin Matuska if (strcmp(strings[i], pivot) < 0) 615cdf63a70SMartin Matuska { 616cdf63a70SMartin Matuska lesser_count++; 617cdf63a70SMartin Matuska tmp = (char **)realloc(lesser, 618cdf63a70SMartin Matuska lesser_count * sizeof(char *)); 619cdf63a70SMartin Matuska if (!tmp) { 620cdf63a70SMartin Matuska free(greater); 621cdf63a70SMartin Matuska free(lesser); 622cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 623cdf63a70SMartin Matuska } 624cdf63a70SMartin Matuska lesser = tmp; 625cdf63a70SMartin Matuska lesser[lesser_count - 1] = strings[i]; 626cdf63a70SMartin Matuska } 627cdf63a70SMartin Matuska else 628cdf63a70SMartin Matuska { 629cdf63a70SMartin Matuska greater_count++; 630cdf63a70SMartin Matuska tmp = (char **)realloc(greater, 631cdf63a70SMartin Matuska greater_count * sizeof(char *)); 632cdf63a70SMartin Matuska if (!tmp) { 633cdf63a70SMartin Matuska free(greater); 634cdf63a70SMartin Matuska free(lesser); 635cdf63a70SMartin Matuska return (ARCHIVE_FATAL); 636cdf63a70SMartin Matuska } 637cdf63a70SMartin Matuska greater = tmp; 638cdf63a70SMartin Matuska greater[greater_count - 1] = strings[i]; 639cdf63a70SMartin Matuska } 640cdf63a70SMartin Matuska } 641cdf63a70SMartin Matuska 642cdf63a70SMartin Matuska /* quicksort(lesser) */ 643cdf63a70SMartin Matuska retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 644cdf63a70SMartin Matuska for (i = 0; i < lesser_count; i++) 645cdf63a70SMartin Matuska strings[i] = lesser[i]; 646cdf63a70SMartin Matuska free(lesser); 647cdf63a70SMartin Matuska 648cdf63a70SMartin Matuska /* pivot */ 649cdf63a70SMartin Matuska strings[lesser_count] = pivot; 650cdf63a70SMartin Matuska 651cdf63a70SMartin Matuska /* quicksort(greater) */ 652cdf63a70SMartin Matuska retval2 = archive_utility_string_sort_helper(greater, greater_count); 653cdf63a70SMartin Matuska for (i = 0; i < greater_count; i++) 654cdf63a70SMartin Matuska strings[lesser_count + 1 + i] = greater[i]; 655cdf63a70SMartin Matuska free(greater); 656cdf63a70SMartin Matuska 657cdf63a70SMartin Matuska return (retval1 < retval2) ? retval1 : retval2; 658cdf63a70SMartin Matuska } 659cdf63a70SMartin Matuska 660cdf63a70SMartin Matuska int 661cdf63a70SMartin Matuska archive_utility_string_sort(char **strings) 662cdf63a70SMartin Matuska { 663cdf63a70SMartin Matuska unsigned int size = 0; 664cdf63a70SMartin Matuska while (strings[size] != NULL) 665cdf63a70SMartin Matuska size++; 666cdf63a70SMartin Matuska return archive_utility_string_sort_helper(strings, size); 667cdf63a70SMartin Matuska } 668