xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision acc60b03c17eb1e46c3993509dd8383185207183)
1caf54c4fSMartin Matuska /*-
2*acc60b03SMartin Matuska  * Copyright (c) 2009-2012 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
48caf54c4fSMartin Matuska 
49caf54c4fSMartin Matuska #include "archive.h"
50caf54c4fSMartin Matuska #include "archive_private.h"
51caf54c4fSMartin Matuska #include "archive_string.h"
52caf54c4fSMartin Matuska 
53*acc60b03SMartin Matuska #ifndef O_CLOEXEC
54*acc60b03SMartin Matuska #define O_CLOEXEC	0
55*acc60b03SMartin Matuska #endif
56*acc60b03SMartin Matuska 
576c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */
58caf54c4fSMartin Matuska int
596c95142eSMartin Matuska __archive_clean(struct archive *a)
60caf54c4fSMartin Matuska {
616c95142eSMartin Matuska 	archive_string_conversion_free(a);
626c95142eSMartin Matuska 	return (ARCHIVE_OK);
63caf54c4fSMartin Matuska }
64caf54c4fSMartin Matuska 
65caf54c4fSMartin Matuska int
66caf54c4fSMartin Matuska archive_version_number(void)
67caf54c4fSMartin Matuska {
68caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_NUMBER);
69caf54c4fSMartin Matuska }
70caf54c4fSMartin Matuska 
71caf54c4fSMartin Matuska const char *
72caf54c4fSMartin Matuska archive_version_string(void)
73caf54c4fSMartin Matuska {
74caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_STRING);
75caf54c4fSMartin Matuska }
76caf54c4fSMartin Matuska 
77caf54c4fSMartin Matuska int
78caf54c4fSMartin Matuska archive_errno(struct archive *a)
79caf54c4fSMartin Matuska {
80caf54c4fSMartin Matuska 	return (a->archive_error_number);
81caf54c4fSMartin Matuska }
82caf54c4fSMartin Matuska 
83caf54c4fSMartin Matuska const char *
84caf54c4fSMartin Matuska archive_error_string(struct archive *a)
85caf54c4fSMartin Matuska {
86caf54c4fSMartin Matuska 
87caf54c4fSMartin Matuska 	if (a->error != NULL  &&  *a->error != '\0')
88caf54c4fSMartin Matuska 		return (a->error);
89caf54c4fSMartin Matuska 	else
906c95142eSMartin Matuska 		return (NULL);
91caf54c4fSMartin Matuska }
92caf54c4fSMartin Matuska 
93caf54c4fSMartin Matuska int
94caf54c4fSMartin Matuska archive_file_count(struct archive *a)
95caf54c4fSMartin Matuska {
96caf54c4fSMartin Matuska 	return (a->file_count);
97caf54c4fSMartin Matuska }
98caf54c4fSMartin Matuska 
99caf54c4fSMartin Matuska int
100caf54c4fSMartin Matuska archive_format(struct archive *a)
101caf54c4fSMartin Matuska {
102caf54c4fSMartin Matuska 	return (a->archive_format);
103caf54c4fSMartin Matuska }
104caf54c4fSMartin Matuska 
105caf54c4fSMartin Matuska const char *
106caf54c4fSMartin Matuska archive_format_name(struct archive *a)
107caf54c4fSMartin Matuska {
108caf54c4fSMartin Matuska 	return (a->archive_format_name);
109caf54c4fSMartin Matuska }
110caf54c4fSMartin Matuska 
111caf54c4fSMartin Matuska 
112caf54c4fSMartin Matuska int
113caf54c4fSMartin Matuska archive_compression(struct archive *a)
114caf54c4fSMartin Matuska {
1156c95142eSMartin Matuska 	return archive_filter_code(a, 0);
116caf54c4fSMartin Matuska }
117caf54c4fSMartin Matuska 
118caf54c4fSMartin Matuska const char *
119caf54c4fSMartin Matuska archive_compression_name(struct archive *a)
120caf54c4fSMartin Matuska {
1216c95142eSMartin Matuska 	return archive_filter_name(a, 0);
122caf54c4fSMartin Matuska }
123caf54c4fSMartin Matuska 
124caf54c4fSMartin Matuska 
125caf54c4fSMartin Matuska /*
126caf54c4fSMartin Matuska  * Return a count of the number of compressed bytes processed.
127caf54c4fSMartin Matuska  */
128caf54c4fSMartin Matuska int64_t
129caf54c4fSMartin Matuska archive_position_compressed(struct archive *a)
130caf54c4fSMartin Matuska {
1316c95142eSMartin Matuska 	return archive_filter_bytes(a, -1);
132caf54c4fSMartin Matuska }
133caf54c4fSMartin Matuska 
134caf54c4fSMartin Matuska /*
135caf54c4fSMartin Matuska  * Return a count of the number of uncompressed bytes processed.
136caf54c4fSMartin Matuska  */
137caf54c4fSMartin Matuska int64_t
138caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a)
139caf54c4fSMartin Matuska {
1406c95142eSMartin Matuska 	return archive_filter_bytes(a, 0);
141caf54c4fSMartin Matuska }
142caf54c4fSMartin Matuska 
143caf54c4fSMartin Matuska void
144caf54c4fSMartin Matuska archive_clear_error(struct archive *a)
145caf54c4fSMartin Matuska {
146caf54c4fSMartin Matuska 	archive_string_empty(&a->error_string);
147caf54c4fSMartin Matuska 	a->error = NULL;
148caf54c4fSMartin Matuska 	a->archive_error_number = 0;
149caf54c4fSMartin Matuska }
150caf54c4fSMartin Matuska 
151caf54c4fSMartin Matuska void
152caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
153caf54c4fSMartin Matuska {
154caf54c4fSMartin Matuska 	va_list ap;
155caf54c4fSMartin Matuska 
156caf54c4fSMartin Matuska 	a->archive_error_number = error_number;
157caf54c4fSMartin Matuska 	if (fmt == NULL) {
158caf54c4fSMartin Matuska 		a->error = NULL;
159caf54c4fSMartin Matuska 		return;
160caf54c4fSMartin Matuska 	}
161caf54c4fSMartin Matuska 
1626c95142eSMartin Matuska 	archive_string_empty(&(a->error_string));
163caf54c4fSMartin Matuska 	va_start(ap, fmt);
164caf54c4fSMartin Matuska 	archive_string_vsprintf(&(a->error_string), fmt, ap);
165caf54c4fSMartin Matuska 	va_end(ap);
166caf54c4fSMartin Matuska 	a->error = a->error_string.s;
167caf54c4fSMartin Matuska }
168caf54c4fSMartin Matuska 
169caf54c4fSMartin Matuska void
170caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src)
171caf54c4fSMartin Matuska {
172caf54c4fSMartin Matuska 	dest->archive_error_number = src->archive_error_number;
173caf54c4fSMartin Matuska 
174caf54c4fSMartin Matuska 	archive_string_copy(&dest->error_string, &src->error_string);
175caf54c4fSMartin Matuska 	dest->error = dest->error_string.s;
176caf54c4fSMartin Matuska }
177caf54c4fSMartin Matuska 
178caf54c4fSMartin Matuska void
179caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg)
180caf54c4fSMartin Matuska {
181caf54c4fSMartin Matuska 	static const char *msg1 = "Fatal Internal Error in libarchive: ";
182caf54c4fSMartin Matuska 	size_t s;
183caf54c4fSMartin Matuska 
184caf54c4fSMartin Matuska 	s = write(2, msg1, strlen(msg1));
185caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
186caf54c4fSMartin Matuska 	s = write(2, msg, strlen(msg));
187caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
188caf54c4fSMartin Matuska 	s = write(2, "\n", 1);
189caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
190caf54c4fSMartin Matuska 	exit(retvalue);
191caf54c4fSMartin Matuska }
192caf54c4fSMartin Matuska 
193caf54c4fSMartin Matuska /*
1946c95142eSMartin Matuska  * Create a temporary file
1956c95142eSMartin Matuska  */
1966c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
1976c95142eSMartin Matuska 
1986c95142eSMartin Matuska /*
1996c95142eSMartin Matuska  * Do not use Windows tmpfile() function.
2006c95142eSMartin Matuska  * It will make a temporary file under the root directory
2016c95142eSMartin Matuska  * and it'll cause permission error if a user who is
2026c95142eSMartin Matuska  * non-Administrator creates temporary files.
2036c95142eSMartin Matuska  * Also Windows version of mktemp family including _mktemp_s
2046c95142eSMartin Matuska  * are not secure.
205caf54c4fSMartin Matuska  */
206caf54c4fSMartin Matuska int
2076c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
208caf54c4fSMartin Matuska {
2096c95142eSMartin Matuska 	static const wchar_t num[] = {
2106c95142eSMartin Matuska 		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
2116c95142eSMartin Matuska 		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
2126c95142eSMartin Matuska 		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
2136c95142eSMartin Matuska 		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
2146c95142eSMartin Matuska 		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
2156c95142eSMartin Matuska 		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
2166c95142eSMartin Matuska 		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
2176c95142eSMartin Matuska 		L'u', L'v', L'w', L'x', L'y', L'z'
2186c95142eSMartin Matuska 	};
2196c95142eSMartin Matuska 	HCRYPTPROV hProv;
2206c95142eSMartin Matuska 	struct archive_wstring temp_name;
2216c95142eSMartin Matuska 	wchar_t *ws;
2226c95142eSMartin Matuska 	DWORD attr;
2236c95142eSMartin Matuska 	wchar_t *xp, *ep;
2246c95142eSMartin Matuska 	int fd;
225caf54c4fSMartin Matuska 
2266c95142eSMartin Matuska 	hProv = (HCRYPTPROV)NULL;
2276c95142eSMartin Matuska 	fd = -1;
2286c95142eSMartin Matuska 	ws = NULL;
2296c95142eSMartin Matuska 	archive_string_init(&temp_name);
2306c95142eSMartin Matuska 
2316c95142eSMartin Matuska 	/* Get a temporary directory. */
2326c95142eSMartin Matuska 	if (tmpdir == NULL) {
2336c95142eSMartin Matuska 		size_t l;
2346c95142eSMartin Matuska 		wchar_t *tmp;
2356c95142eSMartin Matuska 
2366c95142eSMartin Matuska 		l = GetTempPathW(0, NULL);
2376c95142eSMartin Matuska 		if (l == 0) {
2386c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2396c95142eSMartin Matuska 			goto exit_tmpfile;
2406c95142eSMartin Matuska 		}
2416c95142eSMartin Matuska 		tmp = malloc(l*sizeof(wchar_t));
2426c95142eSMartin Matuska 		if (tmp == NULL) {
2436c95142eSMartin Matuska 			errno = ENOMEM;
2446c95142eSMartin Matuska 			goto exit_tmpfile;
2456c95142eSMartin Matuska 		}
246*acc60b03SMartin Matuska 		GetTempPathW((DWORD)l, tmp);
2476c95142eSMartin Matuska 		archive_wstrcpy(&temp_name, tmp);
2486c95142eSMartin Matuska 		free(tmp);
249caf54c4fSMartin Matuska 	} else {
250fd082e96SMartin Matuska 		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
251fd082e96SMartin Matuska 		    strlen(tmpdir)) < 0)
252fd082e96SMartin Matuska 			goto exit_tmpfile;
2536c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != L'/')
2546c95142eSMartin Matuska 			archive_wstrappend_wchar(&temp_name, L'/');
255caf54c4fSMartin Matuska 	}
2566c95142eSMartin Matuska 
2576c95142eSMartin Matuska 	/* Check if temp_name is a directory. */
2586c95142eSMartin Matuska 	attr = GetFileAttributesW(temp_name.s);
2596c95142eSMartin Matuska 	if (attr == (DWORD)-1) {
2606c95142eSMartin Matuska 		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
2616c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2626c95142eSMartin Matuska 			goto exit_tmpfile;
2636c95142eSMartin Matuska 		}
2646c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
2656c95142eSMartin Matuska 		if (ws == NULL) {
2666c95142eSMartin Matuska 			errno = EINVAL;
2676c95142eSMartin Matuska 			goto exit_tmpfile;
2686c95142eSMartin Matuska 		}
2696c95142eSMartin Matuska 		attr = GetFileAttributesW(ws);
2706c95142eSMartin Matuska 		if (attr == (DWORD)-1) {
2716c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
2726c95142eSMartin Matuska 			goto exit_tmpfile;
2736c95142eSMartin Matuska 		}
2746c95142eSMartin Matuska 	}
2756c95142eSMartin Matuska 	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
2766c95142eSMartin Matuska 		errno = ENOTDIR;
2776c95142eSMartin Matuska 		goto exit_tmpfile;
2786c95142eSMartin Matuska 	}
2796c95142eSMartin Matuska 
2806c95142eSMartin Matuska 	/*
2816c95142eSMartin Matuska 	 * Create a temporary file.
2826c95142eSMartin Matuska 	 */
2836c95142eSMartin Matuska 	archive_wstrcat(&temp_name, L"libarchive_");
2846c95142eSMartin Matuska 	xp = temp_name.s + archive_strlen(&temp_name);
2856c95142eSMartin Matuska 	archive_wstrcat(&temp_name, L"XXXXXXXXXX");
2866c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
2876c95142eSMartin Matuska 
2886c95142eSMartin Matuska 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
2896c95142eSMartin Matuska 		CRYPT_VERIFYCONTEXT)) {
2906c95142eSMartin Matuska 		la_dosmaperr(GetLastError());
2916c95142eSMartin Matuska 		goto exit_tmpfile;
2926c95142eSMartin Matuska 	}
2936c95142eSMartin Matuska 
2946c95142eSMartin Matuska 	for (;;) {
2956c95142eSMartin Matuska 		wchar_t *p;
2966c95142eSMartin Matuska 		HANDLE h;
2976c95142eSMartin Matuska 
2986c95142eSMartin Matuska 		/* Generate a random file name through CryptGenRandom(). */
2996c95142eSMartin Matuska 		p = xp;
300*acc60b03SMartin Matuska 		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
301*acc60b03SMartin Matuska 		    (BYTE*)p)) {
3026c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
3036c95142eSMartin Matuska 			goto exit_tmpfile;
3046c95142eSMartin Matuska 		}
3056c95142eSMartin Matuska 		for (; p < ep; p++)
3066c95142eSMartin Matuska 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
3076c95142eSMartin Matuska 
3086c95142eSMartin Matuska 		free(ws);
3096c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
3106c95142eSMartin Matuska 		if (ws == NULL) {
3116c95142eSMartin Matuska 			errno = EINVAL;
3126c95142eSMartin Matuska 			goto exit_tmpfile;
3136c95142eSMartin Matuska 		}
3146c95142eSMartin Matuska 		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
3156c95142eSMartin Matuska 		 * delete this temporary file immediately when this
3166c95142eSMartin Matuska 		 * file closed. */
3176c95142eSMartin Matuska 		h = CreateFileW(ws,
3186c95142eSMartin Matuska 		    GENERIC_READ | GENERIC_WRITE | DELETE,
3196c95142eSMartin Matuska 		    0,/* Not share */
3206c95142eSMartin Matuska 		    NULL,
3216c95142eSMartin Matuska 		    CREATE_NEW,/* Create a new file only */
3226c95142eSMartin Matuska 		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
3236c95142eSMartin Matuska 		    NULL);
3246c95142eSMartin Matuska 		if (h == INVALID_HANDLE_VALUE) {
3256c95142eSMartin Matuska 			/* The same file already exists. retry with
3266c95142eSMartin Matuska 			 * a new filename. */
3276c95142eSMartin Matuska 			if (GetLastError() == ERROR_FILE_EXISTS)
3286c95142eSMartin Matuska 				continue;
3296c95142eSMartin Matuska 			/* Otherwise, fail creation temporary file. */
3306c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
3316c95142eSMartin Matuska 			goto exit_tmpfile;
3326c95142eSMartin Matuska 		}
3336c95142eSMartin Matuska 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
3346c95142eSMartin Matuska 		if (fd == -1) {
3356c95142eSMartin Matuska 			CloseHandle(h);
3366c95142eSMartin Matuska 			goto exit_tmpfile;
3376c95142eSMartin Matuska 		} else
3386c95142eSMartin Matuska 			break;/* success! */
3396c95142eSMartin Matuska 	}
3406c95142eSMartin Matuska exit_tmpfile:
3416c95142eSMartin Matuska 	if (hProv != (HCRYPTPROV)NULL)
3426c95142eSMartin Matuska 		CryptReleaseContext(hProv, 0);
3436c95142eSMartin Matuska 	free(ws);
3446c95142eSMartin Matuska 	archive_wstring_free(&temp_name);
3456c95142eSMartin Matuska 	return (fd);
3466c95142eSMartin Matuska }
3476c95142eSMartin Matuska 
3486c95142eSMartin Matuska #else
3496c95142eSMartin Matuska 
3506c95142eSMartin Matuska static int
3516c95142eSMartin Matuska get_tempdir(struct archive_string *temppath)
3526c95142eSMartin Matuska {
3536c95142eSMartin Matuska 	const char *tmp;
3546c95142eSMartin Matuska 
3556c95142eSMartin Matuska 	tmp = getenv("TMPDIR");
3566c95142eSMartin Matuska 	if (tmp == NULL)
3576c95142eSMartin Matuska #ifdef _PATH_TMP
3586c95142eSMartin Matuska 		tmp = _PATH_TMP;
3596c95142eSMartin Matuska #else
3606c95142eSMartin Matuska                 tmp = "/tmp";
3616c95142eSMartin Matuska #endif
3626c95142eSMartin Matuska 	archive_strcpy(temppath, tmp);
3636c95142eSMartin Matuska 	if (temppath->s[temppath->length-1] != '/')
3646c95142eSMartin Matuska 		archive_strappend_char(temppath, '/');
3656c95142eSMartin Matuska 	return (ARCHIVE_OK);
3666c95142eSMartin Matuska }
3676c95142eSMartin Matuska 
3686c95142eSMartin Matuska #if defined(HAVE_MKSTEMP)
3696c95142eSMartin Matuska 
3706c95142eSMartin Matuska /*
3716c95142eSMartin Matuska  * We can use mkstemp().
3726c95142eSMartin Matuska  */
3736c95142eSMartin Matuska 
3746c95142eSMartin Matuska int
3756c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
3766c95142eSMartin Matuska {
3776c95142eSMartin Matuska 	struct archive_string temp_name;
3786c95142eSMartin Matuska 	int fd = -1;
3796c95142eSMartin Matuska 
3806c95142eSMartin Matuska 	archive_string_init(&temp_name);
3816c95142eSMartin Matuska 	if (tmpdir == NULL) {
3826c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
3836c95142eSMartin Matuska 			goto exit_tmpfile;
384caf54c4fSMartin Matuska 	} else {
3856c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
3866c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != '/')
3876c95142eSMartin Matuska 			archive_strappend_char(&temp_name, '/');
388caf54c4fSMartin Matuska 	}
3896c95142eSMartin Matuska 	archive_strcat(&temp_name, "libarchive_XXXXXX");
3906c95142eSMartin Matuska 	fd = mkstemp(temp_name.s);
3916c95142eSMartin Matuska 	if (fd < 0)
3926c95142eSMartin Matuska 		goto exit_tmpfile;
393*acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
3946c95142eSMartin Matuska 	unlink(temp_name.s);
3956c95142eSMartin Matuska exit_tmpfile:
3966c95142eSMartin Matuska 	archive_string_free(&temp_name);
3976c95142eSMartin Matuska 	return (fd);
398caf54c4fSMartin Matuska }
399caf54c4fSMartin Matuska 
4006c95142eSMartin Matuska #else
4016c95142eSMartin Matuska 
4026c95142eSMartin Matuska /*
4036c95142eSMartin Matuska  * We use a private routine.
4046c95142eSMartin Matuska  */
4056c95142eSMartin Matuska 
4066c95142eSMartin Matuska int
4076c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
4086c95142eSMartin Matuska {
4096c95142eSMartin Matuska         static const char num[] = {
4106c95142eSMartin Matuska 		'0', '1', '2', '3', '4', '5', '6', '7',
4116c95142eSMartin Matuska 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
4126c95142eSMartin Matuska 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
4136c95142eSMartin Matuska 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
4146c95142eSMartin Matuska 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
4156c95142eSMartin Matuska 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
4166c95142eSMartin Matuska 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
4176c95142eSMartin Matuska 		'u', 'v', 'w', 'x', 'y', 'z'
4186c95142eSMartin Matuska         };
4196c95142eSMartin Matuska 	struct archive_string temp_name;
4206c95142eSMartin Matuska 	struct stat st;
4216c95142eSMartin Matuska 	int fd;
4226c95142eSMartin Matuska 	char *tp, *ep;
4236c95142eSMartin Matuska 	unsigned seed;
4246c95142eSMartin Matuska 
4256c95142eSMartin Matuska 	fd = -1;
4266c95142eSMartin Matuska 	archive_string_init(&temp_name);
4276c95142eSMartin Matuska 	if (tmpdir == NULL) {
4286c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
4296c95142eSMartin Matuska 			goto exit_tmpfile;
4306c95142eSMartin Matuska 	} else
4316c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
4326c95142eSMartin Matuska 	if (temp_name.s[temp_name.length-1] == '/') {
4336c95142eSMartin Matuska 		temp_name.s[temp_name.length-1] = '\0';
4346c95142eSMartin Matuska 		temp_name.length --;
435caf54c4fSMartin Matuska 	}
4366c95142eSMartin Matuska 	if (stat(temp_name.s, &st) < 0)
4376c95142eSMartin Matuska 		goto exit_tmpfile;
4386c95142eSMartin Matuska 	if (!S_ISDIR(st.st_mode)) {
4396c95142eSMartin Matuska 		errno = ENOTDIR;
4406c95142eSMartin Matuska 		goto exit_tmpfile;
4416c95142eSMartin Matuska 	}
4426c95142eSMartin Matuska 	archive_strcat(&temp_name, "/libarchive_");
4436c95142eSMartin Matuska 	tp = temp_name.s + archive_strlen(&temp_name);
4446c95142eSMartin Matuska 	archive_strcat(&temp_name, "XXXXXXXXXX");
4456c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
4466c95142eSMartin Matuska 
447*acc60b03SMartin Matuska 	fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
448*acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
4496c95142eSMartin Matuska 	if (fd < 0)
4506c95142eSMartin Matuska 		seed = time(NULL);
4516c95142eSMartin Matuska 	else {
4526c95142eSMartin Matuska 		if (read(fd, &seed, sizeof(seed)) < 0)
4536c95142eSMartin Matuska 			seed = time(NULL);
4546c95142eSMartin Matuska 		close(fd);
4556c95142eSMartin Matuska 	}
4566c95142eSMartin Matuska 	do {
4576c95142eSMartin Matuska 		char *p;
4586c95142eSMartin Matuska 
4596c95142eSMartin Matuska 		p = tp;
4606c95142eSMartin Matuska 		while (p < ep)
4616c95142eSMartin Matuska 			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
462*acc60b03SMartin Matuska 		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
463*acc60b03SMartin Matuska 			  0600);
4646c95142eSMartin Matuska 	} while (fd < 0 && errno == EEXIST);
4656c95142eSMartin Matuska 	if (fd < 0)
4666c95142eSMartin Matuska 		goto exit_tmpfile;
467*acc60b03SMartin Matuska 	__archive_ensure_cloexec_flag(fd);
4686c95142eSMartin Matuska 	unlink(temp_name.s);
4696c95142eSMartin Matuska exit_tmpfile:
4706c95142eSMartin Matuska 	archive_string_free(&temp_name);
4716c95142eSMartin Matuska 	return (fd);
472caf54c4fSMartin Matuska }
473caf54c4fSMartin Matuska 
4746c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */
4756c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */
476*acc60b03SMartin Matuska 
477*acc60b03SMartin Matuska /*
478*acc60b03SMartin Matuska  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
479*acc60b03SMartin Matuska  * We have to set the flag if the platform does not provide O_CLOEXEC
480*acc60b03SMartin Matuska  * or F_DUPFD_CLOEXEC flags.
481*acc60b03SMartin Matuska  *
482*acc60b03SMartin Matuska  * Note: This function is absolutely called after creating a new file
483*acc60b03SMartin Matuska  * descriptor even if the platform seemingly provides O_CLOEXEC or
484*acc60b03SMartin Matuska  * F_DUPFD_CLOEXEC macros because it is possible that the platform
485*acc60b03SMartin Matuska  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
486*acc60b03SMartin Matuska  */
487*acc60b03SMartin Matuska void
488*acc60b03SMartin Matuska __archive_ensure_cloexec_flag(int fd)
489*acc60b03SMartin Matuska {
490*acc60b03SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
491*acc60b03SMartin Matuska 	(void)fd; /* UNSED */
492*acc60b03SMartin Matuska #else
493*acc60b03SMartin Matuska 	int flags;
494*acc60b03SMartin Matuska 
495*acc60b03SMartin Matuska 	if (fd >= 0) {
496*acc60b03SMartin Matuska 		flags = fcntl(fd, F_GETFD);
497*acc60b03SMartin Matuska 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
498*acc60b03SMartin Matuska 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
499*acc60b03SMartin Matuska 	}
500*acc60b03SMartin Matuska #endif
501*acc60b03SMartin Matuska }
502