xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision 6c95142e7977d720e7f1c70672b358aa09fa6bfa)
1caf54c4fSMartin Matuska /*-
2*6c95142eSMartin Matuska  * Copyright (c) 2009,2010 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
33*6c95142eSMartin Matuska #ifdef HAVE_ERRNO_H
34*6c95142eSMartin Matuska #include <errno.h>
35*6c95142eSMartin Matuska #endif
36*6c95142eSMartin Matuska #ifdef HAVE_FCNTL_H
37*6c95142eSMartin Matuska #include <fcntl.h>
38*6c95142eSMartin 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
45*6c95142eSMartin Matuska #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
46*6c95142eSMartin Matuska #include <wincrypt.h>
47*6c95142eSMartin Matuska #endif
48caf54c4fSMartin Matuska 
49caf54c4fSMartin Matuska #include "archive.h"
50caf54c4fSMartin Matuska #include "archive_private.h"
51caf54c4fSMartin Matuska #include "archive_string.h"
52caf54c4fSMartin Matuska 
53*6c95142eSMartin Matuska /* Generic initialization of 'struct archive' objects. */
54caf54c4fSMartin Matuska int
55*6c95142eSMartin Matuska __archive_clean(struct archive *a)
56caf54c4fSMartin Matuska {
57*6c95142eSMartin Matuska 	archive_string_conversion_free(a);
58*6c95142eSMartin Matuska 	return (ARCHIVE_OK);
59caf54c4fSMartin Matuska }
60caf54c4fSMartin Matuska 
61caf54c4fSMartin Matuska int
62caf54c4fSMartin Matuska archive_version_number(void)
63caf54c4fSMartin Matuska {
64caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_NUMBER);
65caf54c4fSMartin Matuska }
66caf54c4fSMartin Matuska 
67caf54c4fSMartin Matuska const char *
68caf54c4fSMartin Matuska archive_version_string(void)
69caf54c4fSMartin Matuska {
70caf54c4fSMartin Matuska 	return (ARCHIVE_VERSION_STRING);
71caf54c4fSMartin Matuska }
72caf54c4fSMartin Matuska 
73caf54c4fSMartin Matuska int
74caf54c4fSMartin Matuska archive_errno(struct archive *a)
75caf54c4fSMartin Matuska {
76caf54c4fSMartin Matuska 	return (a->archive_error_number);
77caf54c4fSMartin Matuska }
78caf54c4fSMartin Matuska 
79caf54c4fSMartin Matuska const char *
80caf54c4fSMartin Matuska archive_error_string(struct archive *a)
81caf54c4fSMartin Matuska {
82caf54c4fSMartin Matuska 
83caf54c4fSMartin Matuska 	if (a->error != NULL  &&  *a->error != '\0')
84caf54c4fSMartin Matuska 		return (a->error);
85caf54c4fSMartin Matuska 	else
86*6c95142eSMartin Matuska 		return (NULL);
87caf54c4fSMartin Matuska }
88caf54c4fSMartin Matuska 
89caf54c4fSMartin Matuska int
90caf54c4fSMartin Matuska archive_file_count(struct archive *a)
91caf54c4fSMartin Matuska {
92caf54c4fSMartin Matuska 	return (a->file_count);
93caf54c4fSMartin Matuska }
94caf54c4fSMartin Matuska 
95caf54c4fSMartin Matuska int
96caf54c4fSMartin Matuska archive_format(struct archive *a)
97caf54c4fSMartin Matuska {
98caf54c4fSMartin Matuska 	return (a->archive_format);
99caf54c4fSMartin Matuska }
100caf54c4fSMartin Matuska 
101caf54c4fSMartin Matuska const char *
102caf54c4fSMartin Matuska archive_format_name(struct archive *a)
103caf54c4fSMartin Matuska {
104caf54c4fSMartin Matuska 	return (a->archive_format_name);
105caf54c4fSMartin Matuska }
106caf54c4fSMartin Matuska 
107caf54c4fSMartin Matuska 
108caf54c4fSMartin Matuska int
109caf54c4fSMartin Matuska archive_compression(struct archive *a)
110caf54c4fSMartin Matuska {
111*6c95142eSMartin Matuska 	return archive_filter_code(a, 0);
112caf54c4fSMartin Matuska }
113caf54c4fSMartin Matuska 
114caf54c4fSMartin Matuska const char *
115caf54c4fSMartin Matuska archive_compression_name(struct archive *a)
116caf54c4fSMartin Matuska {
117*6c95142eSMartin Matuska 	return archive_filter_name(a, 0);
118caf54c4fSMartin Matuska }
119caf54c4fSMartin Matuska 
120caf54c4fSMartin Matuska 
121caf54c4fSMartin Matuska /*
122caf54c4fSMartin Matuska  * Return a count of the number of compressed bytes processed.
123caf54c4fSMartin Matuska  */
124caf54c4fSMartin Matuska int64_t
125caf54c4fSMartin Matuska archive_position_compressed(struct archive *a)
126caf54c4fSMartin Matuska {
127*6c95142eSMartin Matuska 	return archive_filter_bytes(a, -1);
128caf54c4fSMartin Matuska }
129caf54c4fSMartin Matuska 
130caf54c4fSMartin Matuska /*
131caf54c4fSMartin Matuska  * Return a count of the number of uncompressed bytes processed.
132caf54c4fSMartin Matuska  */
133caf54c4fSMartin Matuska int64_t
134caf54c4fSMartin Matuska archive_position_uncompressed(struct archive *a)
135caf54c4fSMartin Matuska {
136*6c95142eSMartin Matuska 	return archive_filter_bytes(a, 0);
137caf54c4fSMartin Matuska }
138caf54c4fSMartin Matuska 
139caf54c4fSMartin Matuska void
140caf54c4fSMartin Matuska archive_clear_error(struct archive *a)
141caf54c4fSMartin Matuska {
142caf54c4fSMartin Matuska 	archive_string_empty(&a->error_string);
143caf54c4fSMartin Matuska 	a->error = NULL;
144caf54c4fSMartin Matuska 	a->archive_error_number = 0;
145caf54c4fSMartin Matuska }
146caf54c4fSMartin Matuska 
147caf54c4fSMartin Matuska void
148caf54c4fSMartin Matuska archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
149caf54c4fSMartin Matuska {
150caf54c4fSMartin Matuska 	va_list ap;
151caf54c4fSMartin Matuska 
152caf54c4fSMartin Matuska 	a->archive_error_number = error_number;
153caf54c4fSMartin Matuska 	if (fmt == NULL) {
154caf54c4fSMartin Matuska 		a->error = NULL;
155caf54c4fSMartin Matuska 		return;
156caf54c4fSMartin Matuska 	}
157caf54c4fSMartin Matuska 
158*6c95142eSMartin Matuska 	archive_string_empty(&(a->error_string));
159caf54c4fSMartin Matuska 	va_start(ap, fmt);
160caf54c4fSMartin Matuska 	archive_string_vsprintf(&(a->error_string), fmt, ap);
161caf54c4fSMartin Matuska 	va_end(ap);
162caf54c4fSMartin Matuska 	a->error = a->error_string.s;
163caf54c4fSMartin Matuska }
164caf54c4fSMartin Matuska 
165caf54c4fSMartin Matuska void
166caf54c4fSMartin Matuska archive_copy_error(struct archive *dest, struct archive *src)
167caf54c4fSMartin Matuska {
168caf54c4fSMartin Matuska 	dest->archive_error_number = src->archive_error_number;
169caf54c4fSMartin Matuska 
170caf54c4fSMartin Matuska 	archive_string_copy(&dest->error_string, &src->error_string);
171caf54c4fSMartin Matuska 	dest->error = dest->error_string.s;
172caf54c4fSMartin Matuska }
173caf54c4fSMartin Matuska 
174caf54c4fSMartin Matuska void
175caf54c4fSMartin Matuska __archive_errx(int retvalue, const char *msg)
176caf54c4fSMartin Matuska {
177caf54c4fSMartin Matuska 	static const char *msg1 = "Fatal Internal Error in libarchive: ";
178caf54c4fSMartin Matuska 	size_t s;
179caf54c4fSMartin Matuska 
180caf54c4fSMartin Matuska 	s = write(2, msg1, strlen(msg1));
181caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
182caf54c4fSMartin Matuska 	s = write(2, msg, strlen(msg));
183caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
184caf54c4fSMartin Matuska 	s = write(2, "\n", 1);
185caf54c4fSMartin Matuska 	(void)s; /* UNUSED */
186caf54c4fSMartin Matuska 	exit(retvalue);
187caf54c4fSMartin Matuska }
188caf54c4fSMartin Matuska 
189caf54c4fSMartin Matuska /*
190*6c95142eSMartin Matuska  * Create a temporary file
191*6c95142eSMartin Matuska  */
192*6c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
193*6c95142eSMartin Matuska 
194*6c95142eSMartin Matuska /*
195*6c95142eSMartin Matuska  * Do not use Windows tmpfile() function.
196*6c95142eSMartin Matuska  * It will make a temporary file under the root directory
197*6c95142eSMartin Matuska  * and it'll cause permission error if a user who is
198*6c95142eSMartin Matuska  * non-Administrator creates temporary files.
199*6c95142eSMartin Matuska  * Also Windows version of mktemp family including _mktemp_s
200*6c95142eSMartin Matuska  * are not secure.
201caf54c4fSMartin Matuska  */
202caf54c4fSMartin Matuska int
203*6c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
204caf54c4fSMartin Matuska {
205*6c95142eSMartin Matuska 	static const wchar_t num[] = {
206*6c95142eSMartin Matuska 		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
207*6c95142eSMartin Matuska 		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
208*6c95142eSMartin Matuska 		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
209*6c95142eSMartin Matuska 		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
210*6c95142eSMartin Matuska 		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
211*6c95142eSMartin Matuska 		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
212*6c95142eSMartin Matuska 		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
213*6c95142eSMartin Matuska 		L'u', L'v', L'w', L'x', L'y', L'z'
214*6c95142eSMartin Matuska 	};
215*6c95142eSMartin Matuska 	HCRYPTPROV hProv;
216*6c95142eSMartin Matuska 	struct archive_wstring temp_name;
217*6c95142eSMartin Matuska 	wchar_t *ws;
218*6c95142eSMartin Matuska 	DWORD attr;
219*6c95142eSMartin Matuska 	wchar_t *xp, *ep;
220*6c95142eSMartin Matuska 	int fd;
221caf54c4fSMartin Matuska 
222*6c95142eSMartin Matuska 	hProv = (HCRYPTPROV)NULL;
223*6c95142eSMartin Matuska 	fd = -1;
224*6c95142eSMartin Matuska 	ws = NULL;
225*6c95142eSMartin Matuska 	archive_string_init(&temp_name);
226*6c95142eSMartin Matuska 
227*6c95142eSMartin Matuska 	/* Get a temporary directory. */
228*6c95142eSMartin Matuska 	if (tmpdir == NULL) {
229*6c95142eSMartin Matuska 		size_t l;
230*6c95142eSMartin Matuska 		wchar_t *tmp;
231*6c95142eSMartin Matuska 
232*6c95142eSMartin Matuska 		l = GetTempPathW(0, NULL);
233*6c95142eSMartin Matuska 		if (l == 0) {
234*6c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
235*6c95142eSMartin Matuska 			goto exit_tmpfile;
236*6c95142eSMartin Matuska 		}
237*6c95142eSMartin Matuska 		tmp = malloc(l*sizeof(wchar_t));
238*6c95142eSMartin Matuska 		if (tmp == NULL) {
239*6c95142eSMartin Matuska 			errno = ENOMEM;
240*6c95142eSMartin Matuska 			goto exit_tmpfile;
241*6c95142eSMartin Matuska 		}
242*6c95142eSMartin Matuska 		GetTempPathW(l, tmp);
243*6c95142eSMartin Matuska 		archive_wstrcpy(&temp_name, tmp);
244*6c95142eSMartin Matuska 		free(tmp);
245caf54c4fSMartin Matuska 	} else {
246*6c95142eSMartin Matuska 		archive_wstring_append_from_mbs(&temp_name, tmpdir,
247*6c95142eSMartin Matuska 		    strlen(tmpdir));
248*6c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != L'/')
249*6c95142eSMartin Matuska 			archive_wstrappend_wchar(&temp_name, L'/');
250caf54c4fSMartin Matuska 	}
251*6c95142eSMartin Matuska 
252*6c95142eSMartin Matuska 	/* Check if temp_name is a directory. */
253*6c95142eSMartin Matuska 	attr = GetFileAttributesW(temp_name.s);
254*6c95142eSMartin Matuska 	if (attr == (DWORD)-1) {
255*6c95142eSMartin Matuska 		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
256*6c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
257*6c95142eSMartin Matuska 			goto exit_tmpfile;
258*6c95142eSMartin Matuska 		}
259*6c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
260*6c95142eSMartin Matuska 		if (ws == NULL) {
261*6c95142eSMartin Matuska 			errno = EINVAL;
262*6c95142eSMartin Matuska 			goto exit_tmpfile;
263*6c95142eSMartin Matuska 		}
264*6c95142eSMartin Matuska 		attr = GetFileAttributesW(ws);
265*6c95142eSMartin Matuska 		if (attr == (DWORD)-1) {
266*6c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
267*6c95142eSMartin Matuska 			goto exit_tmpfile;
268*6c95142eSMartin Matuska 		}
269*6c95142eSMartin Matuska 	}
270*6c95142eSMartin Matuska 	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
271*6c95142eSMartin Matuska 		errno = ENOTDIR;
272*6c95142eSMartin Matuska 		goto exit_tmpfile;
273*6c95142eSMartin Matuska 	}
274*6c95142eSMartin Matuska 
275*6c95142eSMartin Matuska 	/*
276*6c95142eSMartin Matuska 	 * Create a temporary file.
277*6c95142eSMartin Matuska 	 */
278*6c95142eSMartin Matuska 	archive_wstrcat(&temp_name, L"libarchive_");
279*6c95142eSMartin Matuska 	xp = temp_name.s + archive_strlen(&temp_name);
280*6c95142eSMartin Matuska 	archive_wstrcat(&temp_name, L"XXXXXXXXXX");
281*6c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
282*6c95142eSMartin Matuska 
283*6c95142eSMartin Matuska 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
284*6c95142eSMartin Matuska 		CRYPT_VERIFYCONTEXT)) {
285*6c95142eSMartin Matuska 		la_dosmaperr(GetLastError());
286*6c95142eSMartin Matuska 		goto exit_tmpfile;
287*6c95142eSMartin Matuska 	}
288*6c95142eSMartin Matuska 
289*6c95142eSMartin Matuska 	for (;;) {
290*6c95142eSMartin Matuska 		wchar_t *p;
291*6c95142eSMartin Matuska 		HANDLE h;
292*6c95142eSMartin Matuska 
293*6c95142eSMartin Matuska 		/* Generate a random file name through CryptGenRandom(). */
294*6c95142eSMartin Matuska 		p = xp;
295*6c95142eSMartin Matuska 		if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) {
296*6c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
297*6c95142eSMartin Matuska 			goto exit_tmpfile;
298*6c95142eSMartin Matuska 		}
299*6c95142eSMartin Matuska 		for (; p < ep; p++)
300*6c95142eSMartin Matuska 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
301*6c95142eSMartin Matuska 
302*6c95142eSMartin Matuska 		free(ws);
303*6c95142eSMartin Matuska 		ws = __la_win_permissive_name_w(temp_name.s);
304*6c95142eSMartin Matuska 		if (ws == NULL) {
305*6c95142eSMartin Matuska 			errno = EINVAL;
306*6c95142eSMartin Matuska 			goto exit_tmpfile;
307*6c95142eSMartin Matuska 		}
308*6c95142eSMartin Matuska 		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
309*6c95142eSMartin Matuska 		 * delete this temporary file immediately when this
310*6c95142eSMartin Matuska 		 * file closed. */
311*6c95142eSMartin Matuska 		h = CreateFileW(ws,
312*6c95142eSMartin Matuska 		    GENERIC_READ | GENERIC_WRITE | DELETE,
313*6c95142eSMartin Matuska 		    0,/* Not share */
314*6c95142eSMartin Matuska 		    NULL,
315*6c95142eSMartin Matuska 		    CREATE_NEW,/* Create a new file only */
316*6c95142eSMartin Matuska 		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
317*6c95142eSMartin Matuska 		    NULL);
318*6c95142eSMartin Matuska 		if (h == INVALID_HANDLE_VALUE) {
319*6c95142eSMartin Matuska 			/* The same file already exists. retry with
320*6c95142eSMartin Matuska 			 * a new filename. */
321*6c95142eSMartin Matuska 			if (GetLastError() == ERROR_FILE_EXISTS)
322*6c95142eSMartin Matuska 				continue;
323*6c95142eSMartin Matuska 			/* Otherwise, fail creation temporary file. */
324*6c95142eSMartin Matuska 			la_dosmaperr(GetLastError());
325*6c95142eSMartin Matuska 			goto exit_tmpfile;
326*6c95142eSMartin Matuska 		}
327*6c95142eSMartin Matuska 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
328*6c95142eSMartin Matuska 		if (fd == -1) {
329*6c95142eSMartin Matuska 			CloseHandle(h);
330*6c95142eSMartin Matuska 			goto exit_tmpfile;
331*6c95142eSMartin Matuska 		} else
332*6c95142eSMartin Matuska 			break;/* success! */
333*6c95142eSMartin Matuska 	}
334*6c95142eSMartin Matuska exit_tmpfile:
335*6c95142eSMartin Matuska 	if (hProv != (HCRYPTPROV)NULL)
336*6c95142eSMartin Matuska 		CryptReleaseContext(hProv, 0);
337*6c95142eSMartin Matuska 	free(ws);
338*6c95142eSMartin Matuska 	archive_wstring_free(&temp_name);
339*6c95142eSMartin Matuska 	return (fd);
340*6c95142eSMartin Matuska }
341*6c95142eSMartin Matuska 
342*6c95142eSMartin Matuska #else
343*6c95142eSMartin Matuska 
344*6c95142eSMartin Matuska static int
345*6c95142eSMartin Matuska get_tempdir(struct archive_string *temppath)
346*6c95142eSMartin Matuska {
347*6c95142eSMartin Matuska 	const char *tmp;
348*6c95142eSMartin Matuska 
349*6c95142eSMartin Matuska 	tmp = getenv("TMPDIR");
350*6c95142eSMartin Matuska 	if (tmp == NULL)
351*6c95142eSMartin Matuska #ifdef _PATH_TMP
352*6c95142eSMartin Matuska 		tmp = _PATH_TMP;
353*6c95142eSMartin Matuska #else
354*6c95142eSMartin Matuska                 tmp = "/tmp";
355*6c95142eSMartin Matuska #endif
356*6c95142eSMartin Matuska 	archive_strcpy(temppath, tmp);
357*6c95142eSMartin Matuska 	if (temppath->s[temppath->length-1] != '/')
358*6c95142eSMartin Matuska 		archive_strappend_char(temppath, '/');
359*6c95142eSMartin Matuska 	return (ARCHIVE_OK);
360*6c95142eSMartin Matuska }
361*6c95142eSMartin Matuska 
362*6c95142eSMartin Matuska #if defined(HAVE_MKSTEMP)
363*6c95142eSMartin Matuska 
364*6c95142eSMartin Matuska /*
365*6c95142eSMartin Matuska  * We can use mkstemp().
366*6c95142eSMartin Matuska  */
367*6c95142eSMartin Matuska 
368*6c95142eSMartin Matuska int
369*6c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
370*6c95142eSMartin Matuska {
371*6c95142eSMartin Matuska 	struct archive_string temp_name;
372*6c95142eSMartin Matuska 	int fd = -1;
373*6c95142eSMartin Matuska 
374*6c95142eSMartin Matuska 	archive_string_init(&temp_name);
375*6c95142eSMartin Matuska 	if (tmpdir == NULL) {
376*6c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
377*6c95142eSMartin Matuska 			goto exit_tmpfile;
378caf54c4fSMartin Matuska 	} else {
379*6c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
380*6c95142eSMartin Matuska 		if (temp_name.s[temp_name.length-1] != '/')
381*6c95142eSMartin Matuska 			archive_strappend_char(&temp_name, '/');
382caf54c4fSMartin Matuska 	}
383*6c95142eSMartin Matuska 	archive_strcat(&temp_name, "libarchive_XXXXXX");
384*6c95142eSMartin Matuska 	fd = mkstemp(temp_name.s);
385*6c95142eSMartin Matuska 	if (fd < 0)
386*6c95142eSMartin Matuska 		goto exit_tmpfile;
387*6c95142eSMartin Matuska 	unlink(temp_name.s);
388*6c95142eSMartin Matuska exit_tmpfile:
389*6c95142eSMartin Matuska 	archive_string_free(&temp_name);
390*6c95142eSMartin Matuska 	return (fd);
391caf54c4fSMartin Matuska }
392caf54c4fSMartin Matuska 
393*6c95142eSMartin Matuska #else
394*6c95142eSMartin Matuska 
395*6c95142eSMartin Matuska /*
396*6c95142eSMartin Matuska  * We use a private routine.
397*6c95142eSMartin Matuska  */
398*6c95142eSMartin Matuska 
399*6c95142eSMartin Matuska int
400*6c95142eSMartin Matuska __archive_mktemp(const char *tmpdir)
401*6c95142eSMartin Matuska {
402*6c95142eSMartin Matuska         static const char num[] = {
403*6c95142eSMartin Matuska 		'0', '1', '2', '3', '4', '5', '6', '7',
404*6c95142eSMartin Matuska 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
405*6c95142eSMartin Matuska 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
406*6c95142eSMartin Matuska 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
407*6c95142eSMartin Matuska 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
408*6c95142eSMartin Matuska 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
409*6c95142eSMartin Matuska 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
410*6c95142eSMartin Matuska 		'u', 'v', 'w', 'x', 'y', 'z'
411*6c95142eSMartin Matuska         };
412*6c95142eSMartin Matuska 	struct archive_string temp_name;
413*6c95142eSMartin Matuska 	struct stat st;
414*6c95142eSMartin Matuska 	int fd;
415*6c95142eSMartin Matuska 	char *tp, *ep;
416*6c95142eSMartin Matuska 	unsigned seed;
417*6c95142eSMartin Matuska 
418*6c95142eSMartin Matuska 	fd = -1;
419*6c95142eSMartin Matuska 	archive_string_init(&temp_name);
420*6c95142eSMartin Matuska 	if (tmpdir == NULL) {
421*6c95142eSMartin Matuska 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
422*6c95142eSMartin Matuska 			goto exit_tmpfile;
423*6c95142eSMartin Matuska 	} else
424*6c95142eSMartin Matuska 		archive_strcpy(&temp_name, tmpdir);
425*6c95142eSMartin Matuska 	if (temp_name.s[temp_name.length-1] == '/') {
426*6c95142eSMartin Matuska 		temp_name.s[temp_name.length-1] = '\0';
427*6c95142eSMartin Matuska 		temp_name.length --;
428caf54c4fSMartin Matuska 	}
429*6c95142eSMartin Matuska 	if (stat(temp_name.s, &st) < 0)
430*6c95142eSMartin Matuska 		goto exit_tmpfile;
431*6c95142eSMartin Matuska 	if (!S_ISDIR(st.st_mode)) {
432*6c95142eSMartin Matuska 		errno = ENOTDIR;
433*6c95142eSMartin Matuska 		goto exit_tmpfile;
434*6c95142eSMartin Matuska 	}
435*6c95142eSMartin Matuska 	archive_strcat(&temp_name, "/libarchive_");
436*6c95142eSMartin Matuska 	tp = temp_name.s + archive_strlen(&temp_name);
437*6c95142eSMartin Matuska 	archive_strcat(&temp_name, "XXXXXXXXXX");
438*6c95142eSMartin Matuska 	ep = temp_name.s + archive_strlen(&temp_name);
439*6c95142eSMartin Matuska 
440*6c95142eSMartin Matuska 	fd = open("/dev/random", O_RDONLY);
441*6c95142eSMartin Matuska 	if (fd < 0)
442*6c95142eSMartin Matuska 		seed = time(NULL);
443*6c95142eSMartin Matuska 	else {
444*6c95142eSMartin Matuska 		if (read(fd, &seed, sizeof(seed)) < 0)
445*6c95142eSMartin Matuska 			seed = time(NULL);
446*6c95142eSMartin Matuska 		close(fd);
447*6c95142eSMartin Matuska 	}
448*6c95142eSMartin Matuska 	do {
449*6c95142eSMartin Matuska 		char *p;
450*6c95142eSMartin Matuska 
451*6c95142eSMartin Matuska 		p = tp;
452*6c95142eSMartin Matuska 		while (p < ep)
453*6c95142eSMartin Matuska 			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
454*6c95142eSMartin Matuska 		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
455*6c95142eSMartin Matuska 	} while (fd < 0 && errno == EEXIST);
456*6c95142eSMartin Matuska 	if (fd < 0)
457*6c95142eSMartin Matuska 		goto exit_tmpfile;
458*6c95142eSMartin Matuska 	unlink(temp_name.s);
459*6c95142eSMartin Matuska exit_tmpfile:
460*6c95142eSMartin Matuska 	archive_string_free(&temp_name);
461*6c95142eSMartin Matuska 	return (fd);
462caf54c4fSMartin Matuska }
463caf54c4fSMartin Matuska 
464*6c95142eSMartin Matuska #endif /* HAVE_MKSTEMP */
465*6c95142eSMartin Matuska #endif /* !_WIN32 || __CYGWIN__ */
466