xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision a7f7e457db5b3f527b4698de613fe094c4ce33c0)
1caf54c4fSMartin Matuska /*-
2cdf63a70SMartin Matuska  * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
3caf54c4fSMartin Matuska  * Copyright (c) 2003-2007 Tim Kientzle
4caf54c4fSMartin Matuska  * All rights reserved.
5caf54c4fSMartin Matuska  *
6caf54c4fSMartin Matuska  * Redistribution and use in source and binary forms, with or without
7caf54c4fSMartin Matuska  * modification, are permitted provided that the following conditions
8caf54c4fSMartin Matuska  * are met:
9caf54c4fSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
10caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
11caf54c4fSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
12caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
13caf54c4fSMartin Matuska  *    documentation and/or other materials provided with the distribution.
14caf54c4fSMartin Matuska  *
15caf54c4fSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16caf54c4fSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17caf54c4fSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18caf54c4fSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19caf54c4fSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20caf54c4fSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21caf54c4fSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22caf54c4fSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23caf54c4fSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24caf54c4fSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25caf54c4fSMartin Matuska  */
26caf54c4fSMartin Matuska 
27caf54c4fSMartin Matuska #include "archive_platform.h"
286c22d9efSMartin Matuska __FBSDID("$FreeBSD$");
29caf54c4fSMartin Matuska 
30caf54c4fSMartin Matuska #ifdef HAVE_SYS_TYPES_H
31caf54c4fSMartin Matuska #include <sys/types.h>
32caf54c4fSMartin Matuska #endif
336c95142eSMartin Matuska #ifdef HAVE_ERRNO_H
346c95142eSMartin Matuska #include <errno.h>
356c95142eSMartin Matuska #endif
366c95142eSMartin Matuska #ifdef HAVE_FCNTL_H
376c95142eSMartin Matuska #include <fcntl.h>
386c95142eSMartin Matuska #endif
39caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H
40caf54c4fSMartin Matuska #include <stdlib.h>
41caf54c4fSMartin Matuska #endif
42caf54c4fSMartin Matuska #ifdef HAVE_STRING_H
43caf54c4fSMartin Matuska #include <string.h>
44caf54c4fSMartin Matuska #endif
456c95142eSMartin Matuska #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
466c95142eSMartin Matuska #include <wincrypt.h>
476c95142eSMartin Matuska #endif
48cdf63a70SMartin Matuska #ifdef HAVE_ZLIB_H
49cdf63a70SMartin Matuska #include <zlib.h>
50cdf63a70SMartin Matuska #endif
51cdf63a70SMartin Matuska #ifdef HAVE_LZMA_H
52cdf63a70SMartin Matuska #include <lzma.h>
53cdf63a70SMartin Matuska #endif
54cdf63a70SMartin Matuska #ifdef HAVE_BZLIB_H
55cdf63a70SMartin Matuska #include <bzlib.h>
56cdf63a70SMartin Matuska #endif
57cdf63a70SMartin Matuska #ifdef HAVE_LZ4_H
58cdf63a70SMartin Matuska #include <lz4.h>
59cdf63a70SMartin Matuska #endif
60caf54c4fSMartin Matuska 
61caf54c4fSMartin Matuska #include "archive.h"
62caf54c4fSMartin Matuska #include "archive_private.h"
63cdf63a70SMartin Matuska #include "archive_random_private.h"
64caf54c4fSMartin Matuska #include "archive_string.h"
65caf54c4fSMartin Matuska 
66acc60b03SMartin Matuska #ifndef O_CLOEXEC
67acc60b03SMartin Matuska #define O_CLOEXEC	0
68acc60b03SMartin Matuska #endif
69acc60b03SMartin Matuska 
70cdf63a70SMartin Matuska static int archive_utility_string_sort_helper(char **, unsigned int);
71cdf63a70SMartin Matuska 
726c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */
73caf54c4fSMartin Matuska int
746c95142eSMartin Matuska __archive_clean(struct archive *a)
75caf54c4fSMartin Matuska {
766c95142eSMartin Matuska 	archive_string_conversion_free(a);
776c95142eSMartin Matuska 	return (ARCHIVE_OK);
78caf54c4fSMartin Matuska }
79caf54c4fSMartin Matuska 
80caf54c4fSMartin Matuska int
81caf54c4fSMartin Matuska archive_version_number(void)
82caf54c4fSMartin Matuska {
83caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_NUMBER);
84caf54c4fSMartin Matuska }
85caf54c4fSMartin Matuska 
86caf54c4fSMartin Matuska const char *
87caf54c4fSMartin Matuska archive_version_string(void)
88caf54c4fSMartin Matuska {
89caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_STRING);
90caf54c4fSMartin Matuska }
91caf54c4fSMartin Matuska 
92caf54c4fSMartin Matuska int
93caf54c4fSMartin Matuska archive_errno(struct archive *a)
94caf54c4fSMartin Matuska {
95caf54c4fSMartin Matuska 	return (a->archive_error_number);
96caf54c4fSMartin Matuska }
97caf54c4fSMartin Matuska 
98caf54c4fSMartin Matuska const char *
99caf54c4fSMartin Matuska archive_error_string(struct archive *a)
100caf54c4fSMartin Matuska {
101caf54c4fSMartin Matuska 
102caf54c4fSMartin Matuska 	if (a->error != NULL  &&  *a->error != '\0')
103caf54c4fSMartin Matuska 		return (a->error);
104caf54c4fSMartin Matuska 	else
1056c95142eSMartin Matuska 		return (NULL);
106caf54c4fSMartin Matuska }
107caf54c4fSMartin Matuska 
108caf54c4fSMartin Matuska int
109caf54c4fSMartin Matuska archive_file_count(struct archive *a)
110caf54c4fSMartin Matuska {
111caf54c4fSMartin Matuska 	return (a->file_count);
112caf54c4fSMartin Matuska }
113caf54c4fSMartin Matuska 
114caf54c4fSMartin Matuska int
115caf54c4fSMartin Matuska archive_format(struct archive *a)
116caf54c4fSMartin Matuska {
117caf54c4fSMartin Matuska 	return (a->archive_format);
118caf54c4fSMartin Matuska }
119caf54c4fSMartin Matuska 
120caf54c4fSMartin Matuska const char *
121caf54c4fSMartin Matuska archive_format_name(struct archive *a)
122caf54c4fSMartin Matuska {
123caf54c4fSMartin Matuska 	return (a->archive_format_name);
124caf54c4fSMartin Matuska }
125caf54c4fSMartin Matuska 
126caf54c4fSMartin Matuska 
127caf54c4fSMartin Matuska int
128caf54c4fSMartin Matuska archive_compression(struct archive *a)
129caf54c4fSMartin Matuska {
1306c95142eSMartin Matuska 	return archive_filter_code(a, 0);
131caf54c4fSMartin Matuska }
132caf54c4fSMartin Matuska 
133caf54c4fSMartin Matuska const char *
134caf54c4fSMartin Matuska archive_compression_name(struct archive *a)
135caf54c4fSMartin Matuska {
1366c95142eSMartin Matuska 	return archive_filter_name(a, 0);
137caf54c4fSMartin Matuska }
138caf54c4fSMartin Matuska 
139caf54c4fSMartin Matuska 
140caf54c4fSMartin Matuska /*
141caf54c4fSMartin Matuska  * Return a count of the number of compressed bytes processed.
142caf54c4fSMartin Matuska  */
143caf54c4fSMartin Matuska int64_t
144caf54c4fSMartin Matuska archive_position_compressed(struct archive *a)
145caf54c4fSMartin Matuska {
1466c95142eSMartin Matuska 	return archive_filter_bytes(a, -1);
147caf54c4fSMartin Matuska }
148caf54c4fSMartin Matuska 
149caf54c4fSMartin Matuska /*
150caf54c4fSMartin Matuska  * Return a count of the number of uncompressed bytes processed.
151caf54c4fSMartin Matuska  */
152caf54c4fSMartin Matuska int64_t
153caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a)
154caf54c4fSMartin Matuska {
1556c95142eSMartin Matuska 	return archive_filter_bytes(a, 0);
156caf54c4fSMartin Matuska }
157caf54c4fSMartin Matuska 
158caf54c4fSMartin Matuska void
159caf54c4fSMartin Matuska archive_clear_error(struct archive *a)
160caf54c4fSMartin Matuska {
161caf54c4fSMartin Matuska 	archive_string_empty(&a->error_string);
162caf54c4fSMartin Matuska 	a->error = NULL;
163caf54c4fSMartin Matuska 	a->archive_error_number = 0;
164caf54c4fSMartin Matuska }
165caf54c4fSMartin Matuska 
166caf54c4fSMartin Matuska void
167caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
168caf54c4fSMartin Matuska {
169caf54c4fSMartin Matuska 	va_list ap;
170caf54c4fSMartin Matuska 
171caf54c4fSMartin Matuska 	a->archive_error_number = error_number;
172caf54c4fSMartin Matuska 	if (fmt == NULL) {
173caf54c4fSMartin Matuska 		a->error = NULL;
174caf54c4fSMartin Matuska 		return;
175caf54c4fSMartin Matuska 	}
176caf54c4fSMartin Matuska 
1776c95142eSMartin Matuska 	archive_string_empty(&(a->error_string));
178caf54c4fSMartin Matuska 	va_start(ap, fmt);
179caf54c4fSMartin Matuska 	archive_string_vsprintf(&(a->error_string), fmt, ap);
180caf54c4fSMartin Matuska 	va_end(ap);
181caf54c4fSMartin Matuska 	a->error = a->error_string.s;
182caf54c4fSMartin Matuska }
183caf54c4fSMartin Matuska 
184caf54c4fSMartin Matuska void
185caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src)
186caf54c4fSMartin Matuska {
187caf54c4fSMartin Matuska 	dest->archive_error_number = src->archive_error_number;
188caf54c4fSMartin Matuska 
189caf54c4fSMartin Matuska 	archive_string_copy(&dest->error_string, &src->error_string);
190caf54c4fSMartin Matuska 	dest->error = dest->error_string.s;
191caf54c4fSMartin Matuska }
192caf54c4fSMartin Matuska 
193caf54c4fSMartin Matuska void
194caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg)
195caf54c4fSMartin Matuska {
196*a7f7e457SMartin Matuska 	static const char msg1[] = "Fatal Internal Error in libarchive: ";
197caf54c4fSMartin Matuska 	size_t s;
198caf54c4fSMartin Matuska 
199caf54c4fSMartin Matuska 	s = write(2, msg1, strlen(msg1));
200caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
201caf54c4fSMartin Matuska 	s = write(2, msg, strlen(msg));
202caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
203caf54c4fSMartin Matuska 	s = write(2, "\n", 1);
204caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
205caf54c4fSMartin Matuska 	exit(retvalue);
206caf54c4fSMartin Matuska }
207caf54c4fSMartin Matuska 
208caf54c4fSMartin Matuska /*
2096c95142eSMartin Matuska  * Create a temporary file
2106c95142eSMartin Matuska  */
2116c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
2126c95142eSMartin Matuska 
2136c95142eSMartin Matuska /*
2146c95142eSMartin Matuska  * Do not use Windows tmpfile() function.
2156c95142eSMartin Matuska  * It will make a temporary file under the root directory
2166c95142eSMartin Matuska  * and it'll cause permission error if a user who is
2176c95142eSMartin Matuska  * non-Administrator creates temporary files.
2186c95142eSMartin Matuska  * Also Windows version of mktemp family including _mktemp_s
2196c95142eSMartin Matuska  * are not secure.
220caf54c4fSMartin Matuska  */
221caf54c4fSMartin Matuska int
2226c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
223caf54c4fSMartin Matuska {
224*a7f7e457SMartin Matuska 	static const wchar_t prefix[] = L"libarchive_";
225*a7f7e457SMartin Matuska 	static const wchar_t suffix[] = L"XXXXXXXXXX";
2266c95142eSMartin Matuska 	static const wchar_t num[] = {
2276c95142eSMartin Matuska 		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
2286c95142eSMartin Matuska 		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
2296c95142eSMartin Matuska 		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
2306c95142eSMartin Matuska 		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
2316c95142eSMartin Matuska 		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
2326c95142eSMartin Matuska 		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
2336c95142eSMartin Matuska 		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
2346c95142eSMartin Matuska 		L'u', L'v', L'w', L'x', L'y', L'z'
2356c95142eSMartin Matuska 	};
2366c95142eSMartin Matuska 	HCRYPTPROV hProv;
2376c95142eSMartin Matuska 	struct archive_wstring temp_name;
2386c95142eSMartin Matuska 	wchar_t *ws;
2396c95142eSMartin Matuska 	DWORD attr;
2406c95142eSMartin Matuska 	wchar_t *xp, *ep;
2416c95142eSMartin Matuska 	int fd;
242caf54c4fSMartin Matuska 
2436c95142eSMartin Matuska 	hProv = (HCRYPTPROV)NULL;
2446c95142eSMartin Matuska 	fd = -1;
2456c95142eSMartin Matuska 	ws = NULL;
2466c95142eSMartin Matuska 	archive_string_init(&temp_name);
2476c95142eSMartin Matuska 
2486c95142eSMartin Matuska 	/* Get a temporary directory. */
2496c95142eSMartin Matuska 	if (tmpdir == NULL) {
2506c95142eSMartin Matuska 		size_t l;
2516c95142eSMartin Matuska 		wchar_t *tmp;
2526c95142eSMartin Matuska 
2536c95142eSMartin Matuska 		l = GetTempPathW(0, NULL);
2546c95142eSMartin Matuska 		if (l == 0) {
2556c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2566c95142eSMartin Matuska 			goto exit_tmpfile;
2576c95142eSMartin Matuska 		}
2586c95142eSMartin Matuska 		tmp = malloc(l*sizeof(wchar_t));
2596c95142eSMartin Matuska 		if (tmp == NULL) {
2606c95142eSMartin Matuska 			errno = ENOMEM;
2616c95142eSMartin Matuska 			goto exit_tmpfile;
2626c95142eSMartin Matuska 		}
263acc60b03SMartin Matuska 		GetTempPathW((DWORD)l, tmp);
2646c95142eSMartin Matuska 		archive_wstrcpy(&temp_name, tmp);
2656c95142eSMartin Matuska 		free(tmp);
266caf54c4fSMartin Matuska 	} else {
267fd082e96SMartin Matuska 		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
268fd082e96SMartin Matuska 		    strlen(tmpdir)) < 0)
269fd082e96SMartin Matuska 			goto exit_tmpfile;
2706c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != L'/')
2716c95142eSMartin Matuska 			archive_wstrappend_wchar(&temp_name, L'/');
272caf54c4fSMartin Matuska 	}
2736c95142eSMartin Matuska 
2746c95142eSMartin Matuska 	/* Check if temp_name is a directory. */
2756c95142eSMartin Matuska 	attr = GetFileAttributesW(temp_name.s);
2766c95142eSMartin Matuska 	if (attr == (DWORD)-1) {
2776c95142eSMartin Matuska 		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
2786c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2796c95142eSMartin Matuska 			goto exit_tmpfile;
2806c95142eSMartin Matuska 		}
2816c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
2826c95142eSMartin Matuska 		if (ws == NULL) {
2836c95142eSMartin Matuska 			errno = EINVAL;
2846c95142eSMartin Matuska 			goto exit_tmpfile;
2856c95142eSMartin Matuska 		}
2866c95142eSMartin Matuska 		attr = GetFileAttributesW(ws);
2876c95142eSMartin Matuska 		if (attr == (DWORD)-1) {
2886c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2896c95142eSMartin Matuska 			goto exit_tmpfile;
2906c95142eSMartin Matuska 		}
2916c95142eSMartin Matuska 	}
2926c95142eSMartin Matuska 	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
2936c95142eSMartin Matuska 		errno = ENOTDIR;
2946c95142eSMartin Matuska 		goto exit_tmpfile;
2956c95142eSMartin Matuska 	}
2966c95142eSMartin Matuska 
2976c95142eSMartin Matuska 	/*
2986c95142eSMartin Matuska 	 * Create a temporary file.
2996c95142eSMartin Matuska 	 */
300cdf63a70SMartin Matuska 	archive_wstrcat(&temp_name, prefix);
301cdf63a70SMartin Matuska 	archive_wstrcat(&temp_name, suffix);
3026c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
303cdf63a70SMartin Matuska 	xp = ep - wcslen(suffix);
3046c95142eSMartin Matuska 
3056c95142eSMartin Matuska 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
3066c95142eSMartin Matuska 		CRYPT_VERIFYCONTEXT)) {
3076c95142eSMartin Matuska 		la_dosmaperr(GetLastError());
3086c95142eSMartin Matuska 		goto exit_tmpfile;
3096c95142eSMartin Matuska 	}
3106c95142eSMartin Matuska 
3116c95142eSMartin Matuska 	for (;;) {
3126c95142eSMartin Matuska 		wchar_t *p;
3136c95142eSMartin Matuska 		HANDLE h;
3146c95142eSMartin Matuska 
3156c95142eSMartin Matuska 		/* Generate a random file name through CryptGenRandom(). */
3166c95142eSMartin Matuska 		p = xp;
317acc60b03SMartin Matuska 		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
318acc60b03SMartin Matuska 		    (BYTE*)p)) {
3196c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
3206c95142eSMartin Matuska 			goto exit_tmpfile;
3216c95142eSMartin Matuska 		}
3226c95142eSMartin Matuska 		for (; p < ep; p++)
3236c95142eSMartin Matuska 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
3246c95142eSMartin Matuska 
3256c95142eSMartin Matuska 		free(ws);
3266c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
3276c95142eSMartin Matuska 		if (ws == NULL) {
3286c95142eSMartin Matuska 			errno = EINVAL;
3296c95142eSMartin Matuska 			goto exit_tmpfile;
3306c95142eSMartin Matuska 		}
3316c95142eSMartin Matuska 		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
3326c95142eSMartin Matuska 		 * delete this temporary file immediately when this
3336c95142eSMartin Matuska 		 * file closed. */
3346c95142eSMartin Matuska 		h = CreateFileW(ws,
3356c95142eSMartin Matuska 		    GENERIC_READ | GENERIC_WRITE | DELETE,
3366c95142eSMartin Matuska 		    0,/* Not share */
3376c95142eSMartin Matuska 		    NULL,
3386c95142eSMartin Matuska 		    CREATE_NEW,/* Create a new file only */
3396c95142eSMartin Matuska 		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
3406c95142eSMartin Matuska 		    NULL);
3416c95142eSMartin Matuska 		if (h == INVALID_HANDLE_VALUE) {
3426c95142eSMartin Matuska 			/* The same file already exists. retry with
3436c95142eSMartin Matuska 			 * a new filename. */
3446c95142eSMartin Matuska 			if (GetLastError() == ERROR_FILE_EXISTS)
3456c95142eSMartin Matuska 				continue;
3466c95142eSMartin Matuska 			/* Otherwise, fail creation temporary file. */
3476c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
3486c95142eSMartin Matuska 			goto exit_tmpfile;
3496c95142eSMartin Matuska 		}
3506c95142eSMartin Matuska 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
3516c95142eSMartin Matuska 		if (fd == -1) {
3526c95142eSMartin Matuska 			CloseHandle(h);
3536c95142eSMartin Matuska 			goto exit_tmpfile;
3546c95142eSMartin Matuska 		} else
3556c95142eSMartin Matuska 			break;/* success! */
3566c95142eSMartin Matuska 	}
3576c95142eSMartin Matuska exit_tmpfile:
3586c95142eSMartin Matuska 	if (hProv != (HCRYPTPROV)NULL)
3596c95142eSMartin Matuska 		CryptReleaseContext(hProv, 0);
3606c95142eSMartin Matuska 	free(ws);
3616c95142eSMartin Matuska 	archive_wstring_free(&temp_name);
3626c95142eSMartin Matuska 	return (fd);
3636c95142eSMartin Matuska }
3646c95142eSMartin Matuska 
3656c95142eSMartin Matuska #else
3666c95142eSMartin Matuska 
3676c95142eSMartin Matuska static int
3686c95142eSMartin Matuska get_tempdir(struct archive_string *temppath)
3696c95142eSMartin Matuska {
3706c95142eSMartin Matuska 	const char *tmp;
3716c95142eSMartin Matuska 
3726c95142eSMartin Matuska 	tmp = getenv("TMPDIR");
3736c95142eSMartin Matuska 	if (tmp == NULL)
3746c95142eSMartin Matuska #ifdef _PATH_TMP
3756c95142eSMartin Matuska 		tmp = _PATH_TMP;
3766c95142eSMartin Matuska #else
3776c95142eSMartin Matuska                 tmp = "/tmp";
3786c95142eSMartin Matuska #endif
3796c95142eSMartin Matuska 	archive_strcpy(temppath, tmp);
3806c95142eSMartin Matuska 	if (temppath->s[temppath->length-1] != '/')
3816c95142eSMartin Matuska 		archive_strappend_char(temppath, '/');
3826c95142eSMartin Matuska 	return (ARCHIVE_OK);
3836c95142eSMartin Matuska }
3846c95142eSMartin Matuska 
3856c95142eSMartin Matuska #if defined(HAVE_MKSTEMP)
3866c95142eSMartin Matuska 
3876c95142eSMartin Matuska /*
3886c95142eSMartin Matuska  * We can use mkstemp().
3896c95142eSMartin Matuska  */
3906c95142eSMartin Matuska 
3916c95142eSMartin Matuska int
3926c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
3936c95142eSMartin Matuska {
3946c95142eSMartin Matuska 	struct archive_string temp_name;
3956c95142eSMartin Matuska 	int fd = -1;
3966c95142eSMartin Matuska 
3976c95142eSMartin Matuska 	archive_string_init(&temp_name);
3986c95142eSMartin Matuska 	if (tmpdir == NULL) {
3996c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
4006c95142eSMartin Matuska 			goto exit_tmpfile;
401caf54c4fSMartin Matuska 	} else {
4026c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
4036c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != '/')
4046c95142eSMartin Matuska 			archive_strappend_char(&temp_name, '/');
405caf54c4fSMartin Matuska 	}
4066c95142eSMartin Matuska 	archive_strcat(&temp_name, "libarchive_XXXXXX");
4076c95142eSMartin Matuska 	fd = mkstemp(temp_name.s);
4086c95142eSMartin Matuska 	if (fd < 0)
4096c95142eSMartin Matuska 		goto exit_tmpfile;
410acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
4116c95142eSMartin Matuska 	unlink(temp_name.s);
4126c95142eSMartin Matuska exit_tmpfile:
4136c95142eSMartin Matuska 	archive_string_free(&temp_name);
4146c95142eSMartin Matuska 	return (fd);
415caf54c4fSMartin Matuska }
416caf54c4fSMartin Matuska 
4176c95142eSMartin Matuska #else
4186c95142eSMartin Matuska 
4196c95142eSMartin Matuska /*
4206c95142eSMartin Matuska  * We use a private routine.
4216c95142eSMartin Matuska  */
4226c95142eSMartin Matuska 
4236c95142eSMartin Matuska int
4246c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
4256c95142eSMartin Matuska {
4266c95142eSMartin Matuska         static const char num[] = {
4276c95142eSMartin Matuska 		'0', '1', '2', '3', '4', '5', '6', '7',
4286c95142eSMartin Matuska 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
4296c95142eSMartin Matuska 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
4306c95142eSMartin Matuska 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
4316c95142eSMartin Matuska 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
4326c95142eSMartin Matuska 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
4336c95142eSMartin Matuska 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
4346c95142eSMartin Matuska 		'u', 'v', 'w', 'x', 'y', 'z'
4356c95142eSMartin Matuska         };
4366c95142eSMartin Matuska 	struct archive_string temp_name;
4376c95142eSMartin Matuska 	struct stat st;
4386c95142eSMartin Matuska 	int fd;
4396c95142eSMartin Matuska 	char *tp, *ep;
4406c95142eSMartin Matuska 
4416c95142eSMartin Matuska 	fd = -1;
4426c95142eSMartin Matuska 	archive_string_init(&temp_name);
4436c95142eSMartin Matuska 	if (tmpdir == NULL) {
4446c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
4456c95142eSMartin Matuska 			goto exit_tmpfile;
4466c95142eSMartin Matuska 	} else
4476c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
4486c95142eSMartin Matuska 	if (temp_name.s[temp_name.length-1] == '/') {
4496c95142eSMartin Matuska 		temp_name.s[temp_name.length-1] = '\0';
4506c95142eSMartin Matuska 		temp_name.length --;
451caf54c4fSMartin Matuska 	}
4526c95142eSMartin Matuska 	if (stat(temp_name.s, &st) < 0)
4536c95142eSMartin Matuska 		goto exit_tmpfile;
4546c95142eSMartin Matuska 	if (!S_ISDIR(st.st_mode)) {
4556c95142eSMartin Matuska 		errno = ENOTDIR;
4566c95142eSMartin Matuska 		goto exit_tmpfile;
4576c95142eSMartin Matuska 	}
4586c95142eSMartin Matuska 	archive_strcat(&temp_name, "/libarchive_");
4596c95142eSMartin Matuska 	tp = temp_name.s + archive_strlen(&temp_name);
4606c95142eSMartin Matuska 	archive_strcat(&temp_name, "XXXXXXXXXX");
4616c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
4626c95142eSMartin Matuska 
4636c95142eSMartin Matuska 	do {
4646c95142eSMartin Matuska 		char *p;
4656c95142eSMartin Matuska 
4666c95142eSMartin Matuska 		p = tp;
467cdf63a70SMartin Matuska 		archive_random(p, ep - p);
468cdf63a70SMartin Matuska 		while (p < ep) {
469cdf63a70SMartin Matuska 			int d = *((unsigned char *)p) % sizeof(num);
470cdf63a70SMartin Matuska 			*p++ = num[d];
471cdf63a70SMartin Matuska 		}
472acc60b03SMartin Matuska 		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
473acc60b03SMartin Matuska 			  0600);
4746c95142eSMartin Matuska 	} while (fd < 0 && errno == EEXIST);
4756c95142eSMartin Matuska 	if (fd < 0)
4766c95142eSMartin Matuska 		goto exit_tmpfile;
477acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
4786c95142eSMartin Matuska 	unlink(temp_name.s);
4796c95142eSMartin Matuska exit_tmpfile:
4806c95142eSMartin Matuska 	archive_string_free(&temp_name);
4816c95142eSMartin Matuska 	return (fd);
482caf54c4fSMartin Matuska }
483caf54c4fSMartin Matuska 
4846c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */
4856c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */
486acc60b03SMartin Matuska 
487acc60b03SMartin Matuska /*
488acc60b03SMartin Matuska  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
489acc60b03SMartin Matuska  * We have to set the flag if the platform does not provide O_CLOEXEC
490acc60b03SMartin Matuska  * or F_DUPFD_CLOEXEC flags.
491acc60b03SMartin Matuska  *
492acc60b03SMartin Matuska  * Note: This function is absolutely called after creating a new file
493acc60b03SMartin Matuska  * descriptor even if the platform seemingly provides O_CLOEXEC or
494acc60b03SMartin Matuska  * F_DUPFD_CLOEXEC macros because it is possible that the platform
495acc60b03SMartin Matuska  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
496acc60b03SMartin Matuska  */
497acc60b03SMartin Matuska void
498acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd)
499acc60b03SMartin Matuska {
500acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
501cfa49a9bSMartin Matuska 	(void)fd; /* UNUSED */
502acc60b03SMartin Matuska #else
503acc60b03SMartin Matuska 	int flags;
504acc60b03SMartin Matuska 
505acc60b03SMartin Matuska 	if (fd >= 0) {
506acc60b03SMartin Matuska 		flags = fcntl(fd, F_GETFD);
507acc60b03SMartin Matuska 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
508acc60b03SMartin Matuska 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
509acc60b03SMartin Matuska 	}
510acc60b03SMartin Matuska #endif
511acc60b03SMartin Matuska }
512cdf63a70SMartin Matuska 
513cdf63a70SMartin Matuska /*
514cdf63a70SMartin Matuska  * Utility function to sort a group of strings using quicksort.
515cdf63a70SMartin Matuska  */
516cdf63a70SMartin Matuska static int
517cdf63a70SMartin Matuska archive_utility_string_sort_helper(char **strings, unsigned int n)
518cdf63a70SMartin Matuska {
519cdf63a70SMartin Matuska 	unsigned int i, lesser_count, greater_count;
520cdf63a70SMartin Matuska 	char **lesser, **greater, **tmp, *pivot;
521cdf63a70SMartin Matuska 	int retval1, retval2;
522cdf63a70SMartin Matuska 
523cdf63a70SMartin Matuska 	/* A list of 0 or 1 elements is already sorted */
524cdf63a70SMartin Matuska 	if (n <= 1)
525cdf63a70SMartin Matuska 		return (ARCHIVE_OK);
526cdf63a70SMartin Matuska 
527cdf63a70SMartin Matuska 	lesser_count = greater_count = 0;
528cdf63a70SMartin Matuska 	lesser = greater = NULL;
529cdf63a70SMartin Matuska 	pivot = strings[0];
530cdf63a70SMartin Matuska 	for (i = 1; i < n; i++)
531cdf63a70SMartin Matuska 	{
532cdf63a70SMartin Matuska 		if (strcmp(strings[i], pivot) < 0)
533cdf63a70SMartin Matuska 		{
534cdf63a70SMartin Matuska 			lesser_count++;
535cdf63a70SMartin Matuska 			tmp = (char **)realloc(lesser,
536cdf63a70SMartin Matuska 				lesser_count * sizeof(char *));
537cdf63a70SMartin Matuska 			if (!tmp) {
538cdf63a70SMartin Matuska 				free(greater);
539cdf63a70SMartin Matuska 				free(lesser);
540cdf63a70SMartin Matuska 				return (ARCHIVE_FATAL);
541cdf63a70SMartin Matuska 			}
542cdf63a70SMartin Matuska 			lesser = tmp;
543cdf63a70SMartin Matuska 			lesser[lesser_count - 1] = strings[i];
544cdf63a70SMartin Matuska 		}
545cdf63a70SMartin Matuska 		else
546cdf63a70SMartin Matuska 		{
547cdf63a70SMartin Matuska 			greater_count++;
548cdf63a70SMartin Matuska 			tmp = (char **)realloc(greater,
549cdf63a70SMartin Matuska 				greater_count * sizeof(char *));
550cdf63a70SMartin Matuska 			if (!tmp) {
551cdf63a70SMartin Matuska 				free(greater);
552cdf63a70SMartin Matuska 				free(lesser);
553cdf63a70SMartin Matuska 				return (ARCHIVE_FATAL);
554cdf63a70SMartin Matuska 			}
555cdf63a70SMartin Matuska 			greater = tmp;
556cdf63a70SMartin Matuska 			greater[greater_count - 1] = strings[i];
557cdf63a70SMartin Matuska 		}
558cdf63a70SMartin Matuska 	}
559cdf63a70SMartin Matuska 
560cdf63a70SMartin Matuska 	/* quicksort(lesser) */
561cdf63a70SMartin Matuska 	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
562cdf63a70SMartin Matuska 	for (i = 0; i < lesser_count; i++)
563cdf63a70SMartin Matuska 		strings[i] = lesser[i];
564cdf63a70SMartin Matuska 	free(lesser);
565cdf63a70SMartin Matuska 
566cdf63a70SMartin Matuska 	/* pivot */
567cdf63a70SMartin Matuska 	strings[lesser_count] = pivot;
568cdf63a70SMartin Matuska 
569cdf63a70SMartin Matuska 	/* quicksort(greater) */
570cdf63a70SMartin Matuska 	retval2 = archive_utility_string_sort_helper(greater, greater_count);
571cdf63a70SMartin Matuska 	for (i = 0; i < greater_count; i++)
572cdf63a70SMartin Matuska 		strings[lesser_count + 1 + i] = greater[i];
573cdf63a70SMartin Matuska 	free(greater);
574cdf63a70SMartin Matuska 
575cdf63a70SMartin Matuska 	return (retval1 < retval2) ? retval1 : retval2;
576cdf63a70SMartin Matuska }
577cdf63a70SMartin Matuska 
578cdf63a70SMartin Matuska int
579cdf63a70SMartin Matuska archive_utility_string_sort(char **strings)
580cdf63a70SMartin Matuska {
581cdf63a70SMartin Matuska 	  unsigned int size = 0;
582cdf63a70SMartin Matuska 	  while (strings[size] != NULL)
583cdf63a70SMartin Matuska 		size++;
584cdf63a70SMartin Matuska 	  return archive_utility_string_sort_helper(strings, size);
585cdf63a70SMartin Matuska }
586