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