xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision bd66c1b43e33540205dbc1187c2f2a15c58b57ba)
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"
28caf54c4fSMartin Matuska 
29caf54c4fSMartin Matuska #ifdef HAVE_SYS_TYPES_H
30caf54c4fSMartin Matuska #include <sys/types.h>
31caf54c4fSMartin Matuska #endif
326c95142eSMartin Matuska #ifdef HAVE_ERRNO_H
336c95142eSMartin Matuska #include <errno.h>
346c95142eSMartin Matuska #endif
356c95142eSMartin Matuska #ifdef HAVE_FCNTL_H
366c95142eSMartin Matuska #include <fcntl.h>
376c95142eSMartin Matuska #endif
38caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H
39caf54c4fSMartin Matuska #include <stdlib.h>
40caf54c4fSMartin Matuska #endif
41caf54c4fSMartin Matuska #ifdef HAVE_STRING_H
42caf54c4fSMartin Matuska #include <string.h>
43caf54c4fSMartin Matuska #endif
44e64fe029SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
45e64fe029SMartin Matuska #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
46e64fe029SMartin Matuska /* don't use bcrypt when XP needs to be supported */
47e64fe029SMartin Matuska #include <bcrypt.h>
48e64fe029SMartin Matuska 
49e64fe029SMartin Matuska /* Common in other bcrypt implementations, but missing from VS2008. */
50e64fe029SMartin Matuska #ifndef BCRYPT_SUCCESS
51e64fe029SMartin Matuska #define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
52e64fe029SMartin Matuska #endif
53e64fe029SMartin Matuska 
54e64fe029SMartin Matuska #elif defined(HAVE_WINCRYPT_H)
556c95142eSMartin Matuska #include <wincrypt.h>
566c95142eSMartin Matuska #endif
57e64fe029SMartin Matuska #endif
58cdf63a70SMartin Matuska #ifdef HAVE_ZLIB_H
59cdf63a70SMartin Matuska #include <zlib.h>
60cdf63a70SMartin Matuska #endif
61cdf63a70SMartin Matuska #ifdef HAVE_LZMA_H
62cdf63a70SMartin Matuska #include <lzma.h>
63cdf63a70SMartin Matuska #endif
64cdf63a70SMartin Matuska #ifdef HAVE_BZLIB_H
65cdf63a70SMartin Matuska #include <bzlib.h>
66cdf63a70SMartin Matuska #endif
67cdf63a70SMartin Matuska #ifdef HAVE_LZ4_H
68cdf63a70SMartin Matuska #include <lz4.h>
69cdf63a70SMartin Matuska #endif
70caf54c4fSMartin Matuska 
71caf54c4fSMartin Matuska #include "archive.h"
72caf54c4fSMartin Matuska #include "archive_private.h"
73cdf63a70SMartin Matuska #include "archive_random_private.h"
74caf54c4fSMartin Matuska #include "archive_string.h"
75caf54c4fSMartin Matuska 
76acc60b03SMartin Matuska #ifndef O_CLOEXEC
77acc60b03SMartin Matuska #define O_CLOEXEC	0
78acc60b03SMartin Matuska #endif
79acc60b03SMartin Matuska 
80cdf63a70SMartin Matuska static int archive_utility_string_sort_helper(char **, unsigned int);
81cdf63a70SMartin Matuska 
826c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */
83caf54c4fSMartin Matuska int
__archive_clean(struct archive * a)846c95142eSMartin Matuska __archive_clean(struct archive *a)
85caf54c4fSMartin Matuska {
866c95142eSMartin Matuska 	archive_string_conversion_free(a);
876c95142eSMartin Matuska 	return (ARCHIVE_OK);
88caf54c4fSMartin Matuska }
89caf54c4fSMartin Matuska 
90caf54c4fSMartin Matuska int
archive_version_number(void)91caf54c4fSMartin Matuska archive_version_number(void)
92caf54c4fSMartin Matuska {
93caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_NUMBER);
94caf54c4fSMartin Matuska }
95caf54c4fSMartin Matuska 
96caf54c4fSMartin Matuska const char *
archive_version_string(void)97caf54c4fSMartin Matuska archive_version_string(void)
98caf54c4fSMartin Matuska {
99caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_STRING);
100caf54c4fSMartin Matuska }
101caf54c4fSMartin Matuska 
102caf54c4fSMartin Matuska int
archive_errno(struct archive * a)103caf54c4fSMartin Matuska archive_errno(struct archive *a)
104caf54c4fSMartin Matuska {
105caf54c4fSMartin Matuska 	return (a->archive_error_number);
106caf54c4fSMartin Matuska }
107caf54c4fSMartin Matuska 
108caf54c4fSMartin Matuska const char *
archive_error_string(struct archive * a)109caf54c4fSMartin Matuska archive_error_string(struct archive *a)
110caf54c4fSMartin Matuska {
111caf54c4fSMartin Matuska 
112caf54c4fSMartin Matuska 	if (a->error != NULL  &&  *a->error != '\0')
113caf54c4fSMartin Matuska 		return (a->error);
114caf54c4fSMartin Matuska 	else
1156c95142eSMartin Matuska 		return (NULL);
116caf54c4fSMartin Matuska }
117caf54c4fSMartin Matuska 
118caf54c4fSMartin Matuska int
archive_file_count(struct archive * a)119caf54c4fSMartin Matuska archive_file_count(struct archive *a)
120caf54c4fSMartin Matuska {
121caf54c4fSMartin Matuska 	return (a->file_count);
122caf54c4fSMartin Matuska }
123caf54c4fSMartin Matuska 
124caf54c4fSMartin Matuska int
archive_format(struct archive * a)125caf54c4fSMartin Matuska archive_format(struct archive *a)
126caf54c4fSMartin Matuska {
127caf54c4fSMartin Matuska 	return (a->archive_format);
128caf54c4fSMartin Matuska }
129caf54c4fSMartin Matuska 
130caf54c4fSMartin Matuska const char *
archive_format_name(struct archive * a)131caf54c4fSMartin Matuska archive_format_name(struct archive *a)
132caf54c4fSMartin Matuska {
133caf54c4fSMartin Matuska 	return (a->archive_format_name);
134caf54c4fSMartin Matuska }
135caf54c4fSMartin Matuska 
136caf54c4fSMartin Matuska 
137caf54c4fSMartin Matuska int
archive_compression(struct archive * a)138caf54c4fSMartin Matuska archive_compression(struct archive *a)
139caf54c4fSMartin Matuska {
1406c95142eSMartin Matuska 	return archive_filter_code(a, 0);
141caf54c4fSMartin Matuska }
142caf54c4fSMartin Matuska 
143caf54c4fSMartin Matuska const char *
archive_compression_name(struct archive * a)144caf54c4fSMartin Matuska archive_compression_name(struct archive *a)
145caf54c4fSMartin Matuska {
1466c95142eSMartin Matuska 	return archive_filter_name(a, 0);
147caf54c4fSMartin Matuska }
148caf54c4fSMartin Matuska 
149caf54c4fSMartin Matuska 
150caf54c4fSMartin Matuska /*
151caf54c4fSMartin Matuska  * Return a count of the number of compressed bytes processed.
152caf54c4fSMartin Matuska  */
153a2a3407cSMartin Matuska la_int64_t
archive_position_compressed(struct archive * a)154caf54c4fSMartin Matuska archive_position_compressed(struct archive *a)
155caf54c4fSMartin Matuska {
1566c95142eSMartin Matuska 	return archive_filter_bytes(a, -1);
157caf54c4fSMartin Matuska }
158caf54c4fSMartin Matuska 
159caf54c4fSMartin Matuska /*
160caf54c4fSMartin Matuska  * Return a count of the number of uncompressed bytes processed.
161caf54c4fSMartin Matuska  */
162a2a3407cSMartin Matuska la_int64_t
archive_position_uncompressed(struct archive * a)163caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a)
164caf54c4fSMartin Matuska {
1656c95142eSMartin Matuska 	return archive_filter_bytes(a, 0);
166caf54c4fSMartin Matuska }
167caf54c4fSMartin Matuska 
168caf54c4fSMartin Matuska void
archive_clear_error(struct archive * a)169caf54c4fSMartin Matuska archive_clear_error(struct archive *a)
170caf54c4fSMartin Matuska {
171caf54c4fSMartin Matuska 	archive_string_empty(&a->error_string);
172caf54c4fSMartin Matuska 	a->error = NULL;
173caf54c4fSMartin Matuska 	a->archive_error_number = 0;
174caf54c4fSMartin Matuska }
175caf54c4fSMartin Matuska 
176caf54c4fSMartin Matuska void
archive_set_error(struct archive * a,int error_number,const char * fmt,...)177caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
178caf54c4fSMartin Matuska {
179caf54c4fSMartin Matuska 	va_list ap;
180caf54c4fSMartin Matuska 
181caf54c4fSMartin Matuska 	a->archive_error_number = error_number;
182caf54c4fSMartin Matuska 	if (fmt == NULL) {
183caf54c4fSMartin Matuska 		a->error = NULL;
184caf54c4fSMartin Matuska 		return;
185caf54c4fSMartin Matuska 	}
186caf54c4fSMartin Matuska 
1876c95142eSMartin Matuska 	archive_string_empty(&(a->error_string));
188caf54c4fSMartin Matuska 	va_start(ap, fmt);
189caf54c4fSMartin Matuska 	archive_string_vsprintf(&(a->error_string), fmt, ap);
190caf54c4fSMartin Matuska 	va_end(ap);
191caf54c4fSMartin Matuska 	a->error = a->error_string.s;
192caf54c4fSMartin Matuska }
193caf54c4fSMartin Matuska 
194caf54c4fSMartin Matuska void
archive_copy_error(struct archive * dest,struct archive * src)195caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src)
196caf54c4fSMartin Matuska {
197caf54c4fSMartin Matuska 	dest->archive_error_number = src->archive_error_number;
198caf54c4fSMartin Matuska 
199caf54c4fSMartin Matuska 	archive_string_copy(&dest->error_string, &src->error_string);
200caf54c4fSMartin Matuska 	dest->error = dest->error_string.s;
201caf54c4fSMartin Matuska }
202caf54c4fSMartin Matuska 
203caf54c4fSMartin Matuska void
__archive_errx(int retvalue,const char * msg)204caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg)
205caf54c4fSMartin Matuska {
206a7f7e457SMartin Matuska 	static const char msg1[] = "Fatal Internal Error in libarchive: ";
207caf54c4fSMartin Matuska 	size_t s;
208caf54c4fSMartin Matuska 
209caf54c4fSMartin Matuska 	s = write(2, msg1, strlen(msg1));
210caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
211caf54c4fSMartin Matuska 	s = write(2, msg, strlen(msg));
212caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
213caf54c4fSMartin Matuska 	s = write(2, "\n", 1);
214caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
215caf54c4fSMartin Matuska 	exit(retvalue);
216caf54c4fSMartin Matuska }
217caf54c4fSMartin Matuska 
218caf54c4fSMartin Matuska /*
2196c95142eSMartin Matuska  * Create a temporary file
2206c95142eSMartin Matuska  */
2216c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
2226c95142eSMartin Matuska 
2236c95142eSMartin Matuska /*
2246c95142eSMartin Matuska  * Do not use Windows tmpfile() function.
2256c95142eSMartin Matuska  * It will make a temporary file under the root directory
2266c95142eSMartin Matuska  * and it'll cause permission error if a user who is
2276c95142eSMartin Matuska  * non-Administrator creates temporary files.
2286c95142eSMartin Matuska  * Also Windows version of mktemp family including _mktemp_s
2296c95142eSMartin Matuska  * are not secure.
230caf54c4fSMartin Matuska  */
231f9762417SMartin Matuska static int
__archive_mktempx(const char * tmpdir,wchar_t * template)232f9762417SMartin Matuska __archive_mktempx(const char *tmpdir, wchar_t *template)
233caf54c4fSMartin Matuska {
234a7f7e457SMartin Matuska 	static const wchar_t prefix[] = L"libarchive_";
235a7f7e457SMartin Matuska 	static const wchar_t suffix[] = L"XXXXXXXXXX";
2366c95142eSMartin Matuska 	static const wchar_t num[] = {
2376c95142eSMartin Matuska 		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
2386c95142eSMartin Matuska 		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
2396c95142eSMartin Matuska 		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
2406c95142eSMartin Matuska 		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
2416c95142eSMartin Matuska 		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
2426c95142eSMartin Matuska 		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
2436c95142eSMartin Matuska 		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
2446c95142eSMartin Matuska 		L'u', L'v', L'w', L'x', L'y', L'z'
2456c95142eSMartin Matuska 	};
2466c95142eSMartin Matuska 	struct archive_wstring temp_name;
2476c95142eSMartin Matuska 	wchar_t *ws;
2486c95142eSMartin Matuska 	DWORD attr;
2496c95142eSMartin Matuska 	wchar_t *xp, *ep;
2506c95142eSMartin Matuska 	int fd;
251e64fe029SMartin Matuska #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
252e64fe029SMartin Matuska 	BCRYPT_ALG_HANDLE hAlg = NULL;
253e64fe029SMartin Matuska #else
254e64fe029SMartin Matuska 	HCRYPTPROV hProv = (HCRYPTPROV)NULL;
255e64fe029SMartin Matuska #endif
2566c95142eSMartin Matuska 	fd = -1;
2576c95142eSMartin Matuska 	ws = NULL;
2586c95142eSMartin Matuska 	archive_string_init(&temp_name);
2596c95142eSMartin Matuska 
26013d826ffSMartin Matuska 	if (template == NULL) {
2616c95142eSMartin Matuska 		/* Get a temporary directory. */
2626c95142eSMartin Matuska 		if (tmpdir == NULL) {
2636c95142eSMartin Matuska 			size_t l;
2646c95142eSMartin Matuska 			wchar_t *tmp;
2656c95142eSMartin Matuska 
2666c95142eSMartin Matuska 			l = GetTempPathW(0, NULL);
2676c95142eSMartin Matuska 			if (l == 0) {
2686c95142eSMartin Matuska 				la_dosmaperr(GetLastError());
2696c95142eSMartin Matuska 				goto exit_tmpfile;
2706c95142eSMartin Matuska 			}
2716c95142eSMartin Matuska 			tmp = malloc(l*sizeof(wchar_t));
2726c95142eSMartin Matuska 			if (tmp == NULL) {
2736c95142eSMartin Matuska 				errno = ENOMEM;
2746c95142eSMartin Matuska 				goto exit_tmpfile;
2756c95142eSMartin Matuska 			}
276acc60b03SMartin Matuska 			GetTempPathW((DWORD)l, tmp);
2776c95142eSMartin Matuska 			archive_wstrcpy(&temp_name, tmp);
2786c95142eSMartin Matuska 			free(tmp);
279caf54c4fSMartin Matuska 		} else {
280fd082e96SMartin Matuska 			if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
281fd082e96SMartin Matuska 			    strlen(tmpdir)) < 0)
282fd082e96SMartin Matuska 				goto exit_tmpfile;
283*bd66c1b4SMartin Matuska 			if (temp_name.length == 0 ||
284*bd66c1b4SMartin Matuska 			    temp_name.s[temp_name.length-1] != L'/')
2856c95142eSMartin Matuska 				archive_wstrappend_wchar(&temp_name, L'/');
286caf54c4fSMartin Matuska 		}
2876c95142eSMartin Matuska 
2886c95142eSMartin Matuska 		/* Check if temp_name is a directory. */
2896c95142eSMartin Matuska 		attr = GetFileAttributesW(temp_name.s);
2906c95142eSMartin Matuska 		if (attr == (DWORD)-1) {
2916c95142eSMartin Matuska 			if (GetLastError() != ERROR_FILE_NOT_FOUND) {
2926c95142eSMartin Matuska 				la_dosmaperr(GetLastError());
2936c95142eSMartin Matuska 				goto exit_tmpfile;
2946c95142eSMartin Matuska 			}
2956c95142eSMartin Matuska 			ws = __la_win_permissive_name_w(temp_name.s);
2966c95142eSMartin Matuska 			if (ws == NULL) {
2976c95142eSMartin Matuska 				errno = EINVAL;
2986c95142eSMartin Matuska 				goto exit_tmpfile;
2996c95142eSMartin Matuska 			}
3006c95142eSMartin Matuska 			attr = GetFileAttributesW(ws);
3016c95142eSMartin Matuska 			if (attr == (DWORD)-1) {
3026c95142eSMartin Matuska 				la_dosmaperr(GetLastError());
3036c95142eSMartin Matuska 				goto exit_tmpfile;
3046c95142eSMartin Matuska 			}
3056c95142eSMartin Matuska 		}
3066c95142eSMartin Matuska 		if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
3076c95142eSMartin Matuska 			errno = ENOTDIR;
3086c95142eSMartin Matuska 			goto exit_tmpfile;
3096c95142eSMartin Matuska 		}
3106c95142eSMartin Matuska 
3116c95142eSMartin Matuska 		/*
3126c95142eSMartin Matuska 		 * Create a temporary file.
3136c95142eSMartin Matuska 		 */
314cdf63a70SMartin Matuska 		archive_wstrcat(&temp_name, prefix);
315cdf63a70SMartin Matuska 		archive_wstrcat(&temp_name, suffix);
3166c95142eSMartin Matuska 		ep = temp_name.s + archive_strlen(&temp_name);
317cdf63a70SMartin Matuska 		xp = ep - wcslen(suffix);
318f9762417SMartin Matuska 		template = temp_name.s;
319f9762417SMartin Matuska 	} else {
320f9762417SMartin Matuska 		xp = wcschr(template, L'X');
321f9762417SMartin Matuska 		if (xp == NULL)	/* No X, programming error */
322f9762417SMartin Matuska 			abort();
323f9762417SMartin Matuska 		for (ep = xp; *ep == L'X'; ep++)
324f9762417SMartin Matuska 			continue;
325f9762417SMartin Matuska 		if (*ep)	/* X followed by non X, programming error */
326f9762417SMartin Matuska 			abort();
327f9762417SMartin Matuska 	}
3286c95142eSMartin Matuska 
329e64fe029SMartin Matuska #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
330e64fe029SMartin Matuska 	if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
331e64fe029SMartin Matuska 		NULL, 0))) {
332e64fe029SMartin Matuska 		la_dosmaperr(GetLastError());
333e64fe029SMartin Matuska 		goto exit_tmpfile;
334e64fe029SMartin Matuska 	}
335e64fe029SMartin Matuska #else
3366c95142eSMartin Matuska 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
3376c95142eSMartin Matuska 		CRYPT_VERIFYCONTEXT)) {
3386c95142eSMartin Matuska 		la_dosmaperr(GetLastError());
3396c95142eSMartin Matuska 		goto exit_tmpfile;
3406c95142eSMartin Matuska 	}
341e64fe029SMartin Matuska #endif
3426c95142eSMartin Matuska 
3436c95142eSMartin Matuska 	for (;;) {
3446c95142eSMartin Matuska 		wchar_t *p;
3456c95142eSMartin Matuska 		HANDLE h;
346e64fe029SMartin Matuska # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
347e64fe029SMartin Matuska 		CREATEFILE2_EXTENDED_PARAMETERS createExParams;
348e64fe029SMartin Matuska #endif
3496c95142eSMartin Matuska 
3506c95142eSMartin Matuska 		/* Generate a random file name through CryptGenRandom(). */
3516c95142eSMartin Matuska 		p = xp;
352e64fe029SMartin Matuska #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
353e64fe029SMartin Matuska 		if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
354e64fe029SMartin Matuska 		    (DWORD)(ep - p)*sizeof(wchar_t), 0))) {
355e64fe029SMartin Matuska 			la_dosmaperr(GetLastError());
356e64fe029SMartin Matuska 			goto exit_tmpfile;
357e64fe029SMartin Matuska 		}
358e64fe029SMartin Matuska #else
359acc60b03SMartin Matuska 		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
360acc60b03SMartin Matuska 		    (BYTE*)p)) {
3616c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
3626c95142eSMartin Matuska 			goto exit_tmpfile;
3636c95142eSMartin Matuska 		}
364e64fe029SMartin Matuska #endif
3656c95142eSMartin Matuska 		for (; p < ep; p++)
3666c95142eSMartin Matuska 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
3676c95142eSMartin Matuska 
3686c95142eSMartin Matuska 		free(ws);
369f9762417SMartin Matuska 		ws = __la_win_permissive_name_w(template);
3706c95142eSMartin Matuska 		if (ws == NULL) {
3716c95142eSMartin Matuska 			errno = EINVAL;
3726c95142eSMartin Matuska 			goto exit_tmpfile;
3736c95142eSMartin Matuska 		}
374f9762417SMartin Matuska 		if (template == temp_name.s) {
375f9762417SMartin Matuska 			attr = FILE_ATTRIBUTE_TEMPORARY |
376f9762417SMartin Matuska 			       FILE_FLAG_DELETE_ON_CLOSE;
377f9762417SMartin Matuska 		} else {
378f9762417SMartin Matuska 			/* mkstemp */
379f9762417SMartin Matuska 			attr = FILE_ATTRIBUTE_NORMAL;
380f9762417SMartin Matuska 		}
381e64fe029SMartin Matuska # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
382e64fe029SMartin Matuska 		ZeroMemory(&createExParams, sizeof(createExParams));
383e64fe029SMartin Matuska 		createExParams.dwSize = sizeof(createExParams);
384e64fe029SMartin Matuska 		createExParams.dwFileAttributes = attr & 0xFFFF;
385e64fe029SMartin Matuska 		createExParams.dwFileFlags = attr & 0xFFF00000;
386e64fe029SMartin Matuska 		h = CreateFile2(ws,
387e64fe029SMartin Matuska 		    GENERIC_READ | GENERIC_WRITE | DELETE,
388e64fe029SMartin Matuska 		    0,/* Not share */
389e64fe029SMartin Matuska 			CREATE_NEW,
390e64fe029SMartin Matuska 			&createExParams);
391e64fe029SMartin Matuska #else
3926c95142eSMartin Matuska 		h = CreateFileW(ws,
3936c95142eSMartin Matuska 		    GENERIC_READ | GENERIC_WRITE | DELETE,
3946c95142eSMartin Matuska 		    0,/* Not share */
3956c95142eSMartin Matuska 		    NULL,
3966c95142eSMartin Matuska 		    CREATE_NEW,/* Create a new file only */
397f9762417SMartin Matuska 		    attr,
3986c95142eSMartin Matuska 		    NULL);
399e64fe029SMartin Matuska #endif
4006c95142eSMartin Matuska 		if (h == INVALID_HANDLE_VALUE) {
4016c95142eSMartin Matuska 			/* The same file already exists. retry with
4026c95142eSMartin Matuska 			 * a new filename. */
4036c95142eSMartin Matuska 			if (GetLastError() == ERROR_FILE_EXISTS)
4046c95142eSMartin Matuska 				continue;
4056c95142eSMartin Matuska 			/* Otherwise, fail creation temporary file. */
4066c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
4076c95142eSMartin Matuska 			goto exit_tmpfile;
4086c95142eSMartin Matuska 		}
4096c95142eSMartin Matuska 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
4106c95142eSMartin Matuska 		if (fd == -1) {
411f55be4fcSMartin Matuska 			la_dosmaperr(GetLastError());
4126c95142eSMartin Matuska 			CloseHandle(h);
4136c95142eSMartin Matuska 			goto exit_tmpfile;
4146c95142eSMartin Matuska 		} else
4156c95142eSMartin Matuska 			break;/* success! */
4166c95142eSMartin Matuska 	}
4176c95142eSMartin Matuska exit_tmpfile:
418e64fe029SMartin Matuska #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
419e64fe029SMartin Matuska 	if (hAlg != NULL)
420e64fe029SMartin Matuska 		BCryptCloseAlgorithmProvider(hAlg, 0);
421e64fe029SMartin Matuska #else
4226c95142eSMartin Matuska 	if (hProv != (HCRYPTPROV)NULL)
4236c95142eSMartin Matuska 		CryptReleaseContext(hProv, 0);
424e64fe029SMartin Matuska #endif
4256c95142eSMartin Matuska 	free(ws);
426f9762417SMartin Matuska 	if (template == temp_name.s)
4276c95142eSMartin Matuska 		archive_wstring_free(&temp_name);
4286c95142eSMartin Matuska 	return (fd);
4296c95142eSMartin Matuska }
4306c95142eSMartin Matuska 
431f9762417SMartin Matuska int
__archive_mktemp(const char * tmpdir)432f9762417SMartin Matuska __archive_mktemp(const char *tmpdir)
433f9762417SMartin Matuska {
434f9762417SMartin Matuska 	return __archive_mktempx(tmpdir, NULL);
435f9762417SMartin Matuska }
436f9762417SMartin Matuska 
437f9762417SMartin Matuska int
__archive_mkstemp(wchar_t * template)438f9762417SMartin Matuska __archive_mkstemp(wchar_t *template)
439f9762417SMartin Matuska {
440f9762417SMartin Matuska 	return __archive_mktempx(NULL, template);
441f9762417SMartin Matuska }
442f9762417SMartin Matuska 
4436c95142eSMartin Matuska #else
4446c95142eSMartin Matuska 
4456c95142eSMartin Matuska static int
get_tempdir(struct archive_string * temppath)4466c95142eSMartin Matuska get_tempdir(struct archive_string *temppath)
4476c95142eSMartin Matuska {
4486c95142eSMartin Matuska 	const char *tmp;
4496c95142eSMartin Matuska 
4506c95142eSMartin Matuska 	tmp = getenv("TMPDIR");
4516c95142eSMartin Matuska 	if (tmp == NULL)
4526c95142eSMartin Matuska #ifdef _PATH_TMP
4536c95142eSMartin Matuska 		tmp = _PATH_TMP;
4546c95142eSMartin Matuska #else
4556c95142eSMartin Matuska                 tmp = "/tmp";
4566c95142eSMartin Matuska #endif
4576c95142eSMartin Matuska 	archive_strcpy(temppath, tmp);
458*bd66c1b4SMartin Matuska 	if (temppath->length == 0 || temppath->s[temppath->length-1] != '/')
4596c95142eSMartin Matuska 		archive_strappend_char(temppath, '/');
4606c95142eSMartin Matuska 	return (ARCHIVE_OK);
4616c95142eSMartin Matuska }
4626c95142eSMartin Matuska 
4636c95142eSMartin Matuska #if defined(HAVE_MKSTEMP)
4646c95142eSMartin Matuska 
4656c95142eSMartin Matuska /*
4666c95142eSMartin Matuska  * We can use mkstemp().
4676c95142eSMartin Matuska  */
4686c95142eSMartin Matuska 
4696c95142eSMartin Matuska int
__archive_mktemp(const char * tmpdir)4706c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
4716c95142eSMartin Matuska {
4726c95142eSMartin Matuska 	struct archive_string temp_name;
4736c95142eSMartin Matuska 	int fd = -1;
4746c95142eSMartin Matuska 
4756c95142eSMartin Matuska 	archive_string_init(&temp_name);
4766c95142eSMartin Matuska 	if (tmpdir == NULL) {
4776c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
4786c95142eSMartin Matuska 			goto exit_tmpfile;
479caf54c4fSMartin Matuska 	} else {
4806c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
481*bd66c1b4SMartin Matuska 		if (temp_name.length == 0 ||
482*bd66c1b4SMartin Matuska 		    temp_name.s[temp_name.length-1] != '/')
4836c95142eSMartin Matuska 			archive_strappend_char(&temp_name, '/');
484caf54c4fSMartin Matuska 	}
485c3afd20fSMartin Matuska #ifdef O_TMPFILE
486c3afd20fSMartin Matuska 	fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600);
487c3afd20fSMartin Matuska 	if(fd >= 0)
488c3afd20fSMartin Matuska 		goto exit_tmpfile;
489c3afd20fSMartin Matuska #endif
4906c95142eSMartin Matuska 	archive_strcat(&temp_name, "libarchive_XXXXXX");
4916c95142eSMartin Matuska 	fd = mkstemp(temp_name.s);
4926c95142eSMartin Matuska 	if (fd < 0)
4936c95142eSMartin Matuska 		goto exit_tmpfile;
494acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
4956c95142eSMartin Matuska 	unlink(temp_name.s);
4966c95142eSMartin Matuska exit_tmpfile:
4976c95142eSMartin Matuska 	archive_string_free(&temp_name);
4986c95142eSMartin Matuska 	return (fd);
499caf54c4fSMartin Matuska }
500caf54c4fSMartin Matuska 
501f9762417SMartin Matuska int
__archive_mkstemp(char * template)502f9762417SMartin Matuska __archive_mkstemp(char *template)
503f9762417SMartin Matuska {
504f9762417SMartin Matuska 	int fd = -1;
505f9762417SMartin Matuska 	fd = mkstemp(template);
506f9762417SMartin Matuska 	if (fd >= 0)
507f9762417SMartin Matuska 		__archive_ensure_cloexec_flag(fd);
508f9762417SMartin Matuska 	return (fd);
509f9762417SMartin Matuska }
510f9762417SMartin Matuska 
511f9762417SMartin Matuska #else /* !HAVE_MKSTEMP */
5126c95142eSMartin Matuska 
5136c95142eSMartin Matuska /*
5146c95142eSMartin Matuska  * We use a private routine.
5156c95142eSMartin Matuska  */
5166c95142eSMartin Matuska 
517f9762417SMartin Matuska static int
__archive_mktempx(const char * tmpdir,char * template)518f9762417SMartin Matuska __archive_mktempx(const char *tmpdir, char *template)
5196c95142eSMartin Matuska {
5206c95142eSMartin Matuska         static const char num[] = {
5216c95142eSMartin Matuska 		'0', '1', '2', '3', '4', '5', '6', '7',
5226c95142eSMartin Matuska 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
5236c95142eSMartin Matuska 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
5246c95142eSMartin Matuska 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
5256c95142eSMartin Matuska 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
5266c95142eSMartin Matuska 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
5276c95142eSMartin Matuska 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
5286c95142eSMartin Matuska 		'u', 'v', 'w', 'x', 'y', 'z'
5296c95142eSMartin Matuska         };
5306c95142eSMartin Matuska 	struct archive_string temp_name;
5316c95142eSMartin Matuska 	struct stat st;
5326c95142eSMartin Matuska 	int fd;
5336c95142eSMartin Matuska 	char *tp, *ep;
5346c95142eSMartin Matuska 
5356c95142eSMartin Matuska 	fd = -1;
536f9762417SMartin Matuska 	if (template == NULL) {
5376c95142eSMartin Matuska 		archive_string_init(&temp_name);
5386c95142eSMartin Matuska 		if (tmpdir == NULL) {
5396c95142eSMartin Matuska 			if (get_tempdir(&temp_name) != ARCHIVE_OK)
5406c95142eSMartin Matuska 				goto exit_tmpfile;
5416c95142eSMartin Matuska 		} else
5426c95142eSMartin Matuska 			archive_strcpy(&temp_name, tmpdir);
543*bd66c1b4SMartin Matuska 		if (temp_name.length > 0 && temp_name.s[temp_name.length-1] == '/') {
5446c95142eSMartin Matuska 			temp_name.s[temp_name.length-1] = '\0';
5456c95142eSMartin Matuska 			temp_name.length --;
546caf54c4fSMartin Matuska 		}
54752c2bb75SMartin Matuska 		if (la_stat(temp_name.s, &st) < 0)
5486c95142eSMartin Matuska 			goto exit_tmpfile;
5496c95142eSMartin Matuska 		if (!S_ISDIR(st.st_mode)) {
5506c95142eSMartin Matuska 			errno = ENOTDIR;
5516c95142eSMartin Matuska 			goto exit_tmpfile;
5526c95142eSMartin Matuska 		}
5536c95142eSMartin Matuska 		archive_strcat(&temp_name, "/libarchive_");
5546c95142eSMartin Matuska 		tp = temp_name.s + archive_strlen(&temp_name);
5556c95142eSMartin Matuska 		archive_strcat(&temp_name, "XXXXXXXXXX");
5566c95142eSMartin Matuska 		ep = temp_name.s + archive_strlen(&temp_name);
557f9762417SMartin Matuska 		template = temp_name.s;
558f9762417SMartin Matuska 	} else {
559f9762417SMartin Matuska 		tp = strchr(template, 'X');
560f9762417SMartin Matuska 		if (tp == NULL)	/* No X, programming error */
561f9762417SMartin Matuska 			abort();
562f9762417SMartin Matuska 		for (ep = tp; *ep == 'X'; ep++)
563f9762417SMartin Matuska 			continue;
564f9762417SMartin Matuska 		if (*ep)	/* X followed by non X, programming error */
565f9762417SMartin Matuska 			abort();
566f9762417SMartin Matuska 	}
5676c95142eSMartin Matuska 
5686c95142eSMartin Matuska 	do {
5696c95142eSMartin Matuska 		char *p;
5706c95142eSMartin Matuska 
5716c95142eSMartin Matuska 		p = tp;
572cdf63a70SMartin Matuska 		archive_random(p, ep - p);
573cdf63a70SMartin Matuska 		while (p < ep) {
574cdf63a70SMartin Matuska 			int d = *((unsigned char *)p) % sizeof(num);
575cdf63a70SMartin Matuska 			*p++ = num[d];
576cdf63a70SMartin Matuska 		}
577f9762417SMartin Matuska 		fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
578acc60b03SMartin Matuska 			  0600);
5796c95142eSMartin Matuska 	} while (fd < 0 && errno == EEXIST);
5806c95142eSMartin Matuska 	if (fd < 0)
5816c95142eSMartin Matuska 		goto exit_tmpfile;
582acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
583f9762417SMartin Matuska 	if (template == temp_name.s)
5846c95142eSMartin Matuska 		unlink(temp_name.s);
5856c95142eSMartin Matuska exit_tmpfile:
586f9762417SMartin Matuska 	if (template == temp_name.s)
5876c95142eSMartin Matuska 		archive_string_free(&temp_name);
5886c95142eSMartin Matuska 	return (fd);
589caf54c4fSMartin Matuska }
590caf54c4fSMartin Matuska 
591f9762417SMartin Matuska int
__archive_mktemp(const char * tmpdir)592f9762417SMartin Matuska __archive_mktemp(const char *tmpdir)
593f9762417SMartin Matuska {
594f9762417SMartin Matuska 	return __archive_mktempx(tmpdir, NULL);
595f9762417SMartin Matuska }
596f9762417SMartin Matuska 
597f9762417SMartin Matuska int
__archive_mkstemp(char * template)598f9762417SMartin Matuska __archive_mkstemp(char *template)
599f9762417SMartin Matuska {
600f9762417SMartin Matuska 	return __archive_mktempx(NULL, template);
601f9762417SMartin Matuska }
602f9762417SMartin Matuska 
603f9762417SMartin Matuska #endif /* !HAVE_MKSTEMP */
6046c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */
605acc60b03SMartin Matuska 
606acc60b03SMartin Matuska /*
607acc60b03SMartin Matuska  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
608acc60b03SMartin Matuska  * We have to set the flag if the platform does not provide O_CLOEXEC
609acc60b03SMartin Matuska  * or F_DUPFD_CLOEXEC flags.
610acc60b03SMartin Matuska  *
611acc60b03SMartin Matuska  * Note: This function is absolutely called after creating a new file
612acc60b03SMartin Matuska  * descriptor even if the platform seemingly provides O_CLOEXEC or
613acc60b03SMartin Matuska  * F_DUPFD_CLOEXEC macros because it is possible that the platform
614acc60b03SMartin Matuska  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
615acc60b03SMartin Matuska  */
616acc60b03SMartin Matuska void
__archive_ensure_cloexec_flag(int fd)617acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd)
618acc60b03SMartin Matuska {
619acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
620cfa49a9bSMartin Matuska 	(void)fd; /* UNUSED */
621acc60b03SMartin Matuska #else
622acc60b03SMartin Matuska 	int flags;
623acc60b03SMartin Matuska 
624acc60b03SMartin Matuska 	if (fd >= 0) {
625acc60b03SMartin Matuska 		flags = fcntl(fd, F_GETFD);
626acc60b03SMartin Matuska 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
627acc60b03SMartin Matuska 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
628acc60b03SMartin Matuska 	}
629acc60b03SMartin Matuska #endif
630acc60b03SMartin Matuska }
631cdf63a70SMartin Matuska 
632cdf63a70SMartin Matuska /*
633cdf63a70SMartin Matuska  * Utility function to sort a group of strings using quicksort.
634cdf63a70SMartin Matuska  */
635cdf63a70SMartin Matuska static int
archive_utility_string_sort_helper(char ** strings,unsigned int n)636cdf63a70SMartin Matuska archive_utility_string_sort_helper(char **strings, unsigned int n)
637cdf63a70SMartin Matuska {
638cdf63a70SMartin Matuska 	unsigned int i, lesser_count, greater_count;
639cdf63a70SMartin Matuska 	char **lesser, **greater, **tmp, *pivot;
640cdf63a70SMartin Matuska 	int retval1, retval2;
641cdf63a70SMartin Matuska 
642cdf63a70SMartin Matuska 	/* A list of 0 or 1 elements is already sorted */
643cdf63a70SMartin Matuska 	if (n <= 1)
644cdf63a70SMartin Matuska 		return (ARCHIVE_OK);
645cdf63a70SMartin Matuska 
646cdf63a70SMartin Matuska 	lesser_count = greater_count = 0;
647cdf63a70SMartin Matuska 	lesser = greater = NULL;
648cdf63a70SMartin Matuska 	pivot = strings[0];
649cdf63a70SMartin Matuska 	for (i = 1; i < n; i++)
650cdf63a70SMartin Matuska 	{
651cdf63a70SMartin Matuska 		if (strcmp(strings[i], pivot) < 0)
652cdf63a70SMartin Matuska 		{
653cdf63a70SMartin Matuska 			lesser_count++;
654*bd66c1b4SMartin Matuska 			tmp = realloc(lesser, lesser_count * sizeof(*tmp));
655cdf63a70SMartin Matuska 			if (!tmp) {
656cdf63a70SMartin Matuska 				free(greater);
657cdf63a70SMartin Matuska 				free(lesser);
658cdf63a70SMartin Matuska 				return (ARCHIVE_FATAL);
659cdf63a70SMartin Matuska 			}
660cdf63a70SMartin Matuska 			lesser = tmp;
661cdf63a70SMartin Matuska 			lesser[lesser_count - 1] = strings[i];
662cdf63a70SMartin Matuska 		}
663cdf63a70SMartin Matuska 		else
664cdf63a70SMartin Matuska 		{
665cdf63a70SMartin Matuska 			greater_count++;
666*bd66c1b4SMartin Matuska 			tmp = realloc(greater, greater_count * sizeof(*tmp));
667cdf63a70SMartin Matuska 			if (!tmp) {
668cdf63a70SMartin Matuska 				free(greater);
669cdf63a70SMartin Matuska 				free(lesser);
670cdf63a70SMartin Matuska 				return (ARCHIVE_FATAL);
671cdf63a70SMartin Matuska 			}
672cdf63a70SMartin Matuska 			greater = tmp;
673cdf63a70SMartin Matuska 			greater[greater_count - 1] = strings[i];
674cdf63a70SMartin Matuska 		}
675cdf63a70SMartin Matuska 	}
676cdf63a70SMartin Matuska 
677cdf63a70SMartin Matuska 	/* quicksort(lesser) */
678cdf63a70SMartin Matuska 	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
679cdf63a70SMartin Matuska 	for (i = 0; i < lesser_count; i++)
680cdf63a70SMartin Matuska 		strings[i] = lesser[i];
681cdf63a70SMartin Matuska 	free(lesser);
682cdf63a70SMartin Matuska 
683cdf63a70SMartin Matuska 	/* pivot */
684cdf63a70SMartin Matuska 	strings[lesser_count] = pivot;
685cdf63a70SMartin Matuska 
686cdf63a70SMartin Matuska 	/* quicksort(greater) */
687cdf63a70SMartin Matuska 	retval2 = archive_utility_string_sort_helper(greater, greater_count);
688cdf63a70SMartin Matuska 	for (i = 0; i < greater_count; i++)
689cdf63a70SMartin Matuska 		strings[lesser_count + 1 + i] = greater[i];
690cdf63a70SMartin Matuska 	free(greater);
691cdf63a70SMartin Matuska 
692cdf63a70SMartin Matuska 	return (retval1 < retval2) ? retval1 : retval2;
693cdf63a70SMartin Matuska }
694cdf63a70SMartin Matuska 
695cdf63a70SMartin Matuska int
archive_utility_string_sort(char ** strings)696cdf63a70SMartin Matuska archive_utility_string_sort(char **strings)
697cdf63a70SMartin Matuska {
698cdf63a70SMartin Matuska 	  unsigned int size = 0;
699cdf63a70SMartin Matuska 	  while (strings[size] != NULL)
700cdf63a70SMartin Matuska 		size++;
701cdf63a70SMartin Matuska 	  return archive_utility_string_sort_helper(strings, size);
702cdf63a70SMartin Matuska }
703