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