xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision f55be4fc57f789f634e9476fa73ba3e7d14d8051)
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