1228753Smm/*-
2302001Smm * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
3228753Smm * Copyright (c) 2003-2007 Tim Kientzle
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer.
11228753Smm * 2. Redistributions in binary form must reproduce the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer in the
13228753Smm *    documentation and/or other materials provided with the distribution.
14228753Smm *
15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25228753Smm */
26228753Smm
27228753Smm#include "archive_platform.h"
28228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_util.c 368708 2020-12-16 22:25:40Z mm $");
29228753Smm
30228753Smm#ifdef HAVE_SYS_TYPES_H
31228753Smm#include <sys/types.h>
32228753Smm#endif
33232153Smm#ifdef HAVE_ERRNO_H
34232153Smm#include <errno.h>
35232153Smm#endif
36232153Smm#ifdef HAVE_FCNTL_H
37232153Smm#include <fcntl.h>
38232153Smm#endif
39228753Smm#ifdef HAVE_STDLIB_H
40228753Smm#include <stdlib.h>
41228753Smm#endif
42228753Smm#ifdef HAVE_STRING_H
43228753Smm#include <string.h>
44228753Smm#endif
45232153Smm#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
46232153Smm#include <wincrypt.h>
47232153Smm#endif
48302001Smm#ifdef HAVE_ZLIB_H
49302001Smm#include <zlib.h>
50302001Smm#endif
51302001Smm#ifdef HAVE_LZMA_H
52302001Smm#include <lzma.h>
53302001Smm#endif
54302001Smm#ifdef HAVE_BZLIB_H
55302001Smm#include <bzlib.h>
56302001Smm#endif
57302001Smm#ifdef HAVE_LZ4_H
58302001Smm#include <lz4.h>
59302001Smm#endif
60228753Smm
61228753Smm#include "archive.h"
62228753Smm#include "archive_private.h"
63302001Smm#include "archive_random_private.h"
64228753Smm#include "archive_string.h"
65228753Smm
66248616Smm#ifndef O_CLOEXEC
67248616Smm#define O_CLOEXEC	0
68248616Smm#endif
69248616Smm
70302001Smmstatic int archive_utility_string_sort_helper(char **, unsigned int);
71302001Smm
72232153Smm/* Generic initialization of 'struct archive' objects. */
73228753Smmint
74232153Smm__archive_clean(struct archive *a)
75228753Smm{
76232153Smm	archive_string_conversion_free(a);
77232153Smm	return (ARCHIVE_OK);
78228753Smm}
79228753Smm
80228753Smmint
81228753Smmarchive_version_number(void)
82228753Smm{
83228753Smm	return (ARCHIVE_VERSION_NUMBER);
84228753Smm}
85228753Smm
86228753Smmconst char *
87228753Smmarchive_version_string(void)
88228753Smm{
89228753Smm	return (ARCHIVE_VERSION_STRING);
90228753Smm}
91228753Smm
92228753Smmint
93228753Smmarchive_errno(struct archive *a)
94228753Smm{
95228753Smm	return (a->archive_error_number);
96228753Smm}
97228753Smm
98228753Smmconst char *
99228753Smmarchive_error_string(struct archive *a)
100228753Smm{
101228753Smm
102228753Smm	if (a->error != NULL  &&  *a->error != '\0')
103228753Smm		return (a->error);
104228753Smm	else
105232153Smm		return (NULL);
106228753Smm}
107228753Smm
108228753Smmint
109228753Smmarchive_file_count(struct archive *a)
110228753Smm{
111228753Smm	return (a->file_count);
112228753Smm}
113228753Smm
114228753Smmint
115228753Smmarchive_format(struct archive *a)
116228753Smm{
117228753Smm	return (a->archive_format);
118228753Smm}
119228753Smm
120228753Smmconst char *
121228753Smmarchive_format_name(struct archive *a)
122228753Smm{
123228753Smm	return (a->archive_format_name);
124228753Smm}
125228753Smm
126228753Smm
127228753Smmint
128228753Smmarchive_compression(struct archive *a)
129228753Smm{
130232153Smm	return archive_filter_code(a, 0);
131228753Smm}
132228753Smm
133228753Smmconst char *
134228753Smmarchive_compression_name(struct archive *a)
135228753Smm{
136232153Smm	return archive_filter_name(a, 0);
137228753Smm}
138228753Smm
139228753Smm
140228753Smm/*
141228753Smm * Return a count of the number of compressed bytes processed.
142228753Smm */
143328828Smmla_int64_t
144228753Smmarchive_position_compressed(struct archive *a)
145228753Smm{
146232153Smm	return archive_filter_bytes(a, -1);
147228753Smm}
148228753Smm
149228753Smm/*
150228753Smm * Return a count of the number of uncompressed bytes processed.
151228753Smm */
152328828Smmla_int64_t
153228753Smmarchive_position_uncompressed(struct archive *a)
154228753Smm{
155232153Smm	return archive_filter_bytes(a, 0);
156228753Smm}
157228753Smm
158228753Smmvoid
159228753Smmarchive_clear_error(struct archive *a)
160228753Smm{
161228753Smm	archive_string_empty(&a->error_string);
162228753Smm	a->error = NULL;
163228753Smm	a->archive_error_number = 0;
164228753Smm}
165228753Smm
166228753Smmvoid
167228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...)
168228753Smm{
169228753Smm	va_list ap;
170228753Smm
171228753Smm	a->archive_error_number = error_number;
172228753Smm	if (fmt == NULL) {
173228753Smm		a->error = NULL;
174228753Smm		return;
175228753Smm	}
176228753Smm
177232153Smm	archive_string_empty(&(a->error_string));
178228753Smm	va_start(ap, fmt);
179228753Smm	archive_string_vsprintf(&(a->error_string), fmt, ap);
180228753Smm	va_end(ap);
181228753Smm	a->error = a->error_string.s;
182228753Smm}
183228753Smm
184228753Smmvoid
185228753Smmarchive_copy_error(struct archive *dest, struct archive *src)
186228753Smm{
187228753Smm	dest->archive_error_number = src->archive_error_number;
188228753Smm
189228753Smm	archive_string_copy(&dest->error_string, &src->error_string);
190228753Smm	dest->error = dest->error_string.s;
191228753Smm}
192228753Smm
193228753Smmvoid
194228753Smm__archive_errx(int retvalue, const char *msg)
195228753Smm{
196316338Smm	static const char msg1[] = "Fatal Internal Error in libarchive: ";
197228753Smm	size_t s;
198228753Smm
199228753Smm	s = write(2, msg1, strlen(msg1));
200228753Smm	(void)s; /* UNUSED */
201228753Smm	s = write(2, msg, strlen(msg));
202228753Smm	(void)s; /* UNUSED */
203228753Smm	s = write(2, "\n", 1);
204228753Smm	(void)s; /* UNUSED */
205228753Smm	exit(retvalue);
206228753Smm}
207228753Smm
208228753Smm/*
209232153Smm * Create a temporary file
210228753Smm */
211232153Smm#if defined(_WIN32) && !defined(__CYGWIN__)
212232153Smm
213232153Smm/*
214232153Smm * Do not use Windows tmpfile() function.
215232153Smm * It will make a temporary file under the root directory
216232153Smm * and it'll cause permission error if a user who is
217232153Smm * non-Administrator creates temporary files.
218232153Smm * Also Windows version of mktemp family including _mktemp_s
219232153Smm * are not secure.
220232153Smm */
221358090Smmstatic int
222358090Smm__archive_mktempx(const char *tmpdir, wchar_t *template)
223228753Smm{
224316338Smm	static const wchar_t prefix[] = L"libarchive_";
225316338Smm	static const wchar_t suffix[] = L"XXXXXXXXXX";
226232153Smm	static const wchar_t num[] = {
227232153Smm		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
228232153Smm		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
229232153Smm		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
230232153Smm		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
231232153Smm		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
232232153Smm		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
233232153Smm		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
234232153Smm		L'u', L'v', L'w', L'x', L'y', L'z'
235232153Smm	};
236232153Smm	HCRYPTPROV hProv;
237232153Smm	struct archive_wstring temp_name;
238232153Smm	wchar_t *ws;
239232153Smm	DWORD attr;
240232153Smm	wchar_t *xp, *ep;
241232153Smm	int fd;
242228753Smm
243232153Smm	hProv = (HCRYPTPROV)NULL;
244232153Smm	fd = -1;
245232153Smm	ws = NULL;
246232153Smm
247358090Smm	if (template == NULL) {
248358090Smm		archive_string_init(&temp_name);
249232153Smm
250358090Smm		/* Get a temporary directory. */
251358090Smm		if (tmpdir == NULL) {
252358090Smm			size_t l;
253358090Smm			wchar_t *tmp;
254358090Smm
255358090Smm			l = GetTempPathW(0, NULL);
256358090Smm			if (l == 0) {
257358090Smm				la_dosmaperr(GetLastError());
258358090Smm				goto exit_tmpfile;
259358090Smm			}
260358090Smm			tmp = malloc(l*sizeof(wchar_t));
261358090Smm			if (tmp == NULL) {
262358090Smm				errno = ENOMEM;
263358090Smm				goto exit_tmpfile;
264358090Smm			}
265358090Smm			GetTempPathW((DWORD)l, tmp);
266358090Smm			archive_wstrcpy(&temp_name, tmp);
267358090Smm			free(tmp);
268358090Smm		} else {
269358090Smm			if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
270358090Smm			    strlen(tmpdir)) < 0)
271358090Smm				goto exit_tmpfile;
272358090Smm			if (temp_name.s[temp_name.length-1] != L'/')
273358090Smm				archive_wstrappend_wchar(&temp_name, L'/');
274232153Smm		}
275228753Smm
276358090Smm		/* Check if temp_name is a directory. */
277358090Smm		attr = GetFileAttributesW(temp_name.s);
278358090Smm		if (attr == (DWORD)-1) {
279358090Smm			if (GetLastError() != ERROR_FILE_NOT_FOUND) {
280358090Smm				la_dosmaperr(GetLastError());
281358090Smm				goto exit_tmpfile;
282358090Smm			}
283358090Smm			ws = __la_win_permissive_name_w(temp_name.s);
284358090Smm			if (ws == NULL) {
285358090Smm				errno = EINVAL;
286358090Smm				goto exit_tmpfile;
287358090Smm			}
288358090Smm			attr = GetFileAttributesW(ws);
289358090Smm			if (attr == (DWORD)-1) {
290358090Smm				la_dosmaperr(GetLastError());
291358090Smm				goto exit_tmpfile;
292358090Smm			}
293228753Smm		}
294358090Smm		if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
295358090Smm			errno = ENOTDIR;
296232153Smm			goto exit_tmpfile;
297232153Smm		}
298358090Smm
299358090Smm		/*
300358090Smm		 * Create a temporary file.
301358090Smm		 */
302358090Smm		archive_wstrcat(&temp_name, prefix);
303358090Smm		archive_wstrcat(&temp_name, suffix);
304358090Smm		ep = temp_name.s + archive_strlen(&temp_name);
305358090Smm		xp = ep - wcslen(suffix);
306358090Smm		template = temp_name.s;
307358090Smm	} else {
308358090Smm		xp = wcschr(template, L'X');
309358090Smm		if (xp == NULL)	/* No X, programming error */
310358090Smm			abort();
311358090Smm		for (ep = xp; *ep == L'X'; ep++)
312358090Smm			continue;
313358090Smm		if (*ep)	/* X followed by non X, programming error */
314358090Smm			abort();
315228753Smm	}
316228753Smm
317232153Smm	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
318232153Smm		CRYPT_VERIFYCONTEXT)) {
319232153Smm		la_dosmaperr(GetLastError());
320232153Smm		goto exit_tmpfile;
321232153Smm	}
322232153Smm
323232153Smm	for (;;) {
324232153Smm		wchar_t *p;
325232153Smm		HANDLE h;
326232153Smm
327232153Smm		/* Generate a random file name through CryptGenRandom(). */
328232153Smm		p = xp;
329248616Smm		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
330248616Smm		    (BYTE*)p)) {
331232153Smm			la_dosmaperr(GetLastError());
332232153Smm			goto exit_tmpfile;
333232153Smm		}
334232153Smm		for (; p < ep; p++)
335232153Smm			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
336232153Smm
337232153Smm		free(ws);
338358090Smm		ws = __la_win_permissive_name_w(template);
339232153Smm		if (ws == NULL) {
340232153Smm			errno = EINVAL;
341232153Smm			goto exit_tmpfile;
342232153Smm		}
343358090Smm		if (template == temp_name.s) {
344358090Smm			attr = FILE_ATTRIBUTE_TEMPORARY |
345358090Smm			       FILE_FLAG_DELETE_ON_CLOSE;
346358090Smm		} else {
347358090Smm			/* mkstemp */
348358090Smm			attr = FILE_ATTRIBUTE_NORMAL;
349358090Smm		}
350232153Smm		h = CreateFileW(ws,
351232153Smm		    GENERIC_READ | GENERIC_WRITE | DELETE,
352232153Smm		    0,/* Not share */
353232153Smm		    NULL,
354232153Smm		    CREATE_NEW,/* Create a new file only */
355358090Smm		    attr,
356232153Smm		    NULL);
357232153Smm		if (h == INVALID_HANDLE_VALUE) {
358232153Smm			/* The same file already exists. retry with
359232153Smm			 * a new filename. */
360232153Smm			if (GetLastError() == ERROR_FILE_EXISTS)
361232153Smm				continue;
362232153Smm			/* Otherwise, fail creation temporary file. */
363232153Smm			la_dosmaperr(GetLastError());
364232153Smm			goto exit_tmpfile;
365232153Smm		}
366232153Smm		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
367232153Smm		if (fd == -1) {
368358927Smm			la_dosmaperr(GetLastError());
369232153Smm			CloseHandle(h);
370232153Smm			goto exit_tmpfile;
371232153Smm		} else
372232153Smm			break;/* success! */
373232153Smm	}
374232153Smmexit_tmpfile:
375232153Smm	if (hProv != (HCRYPTPROV)NULL)
376232153Smm		CryptReleaseContext(hProv, 0);
377232153Smm	free(ws);
378358090Smm	if (template == temp_name.s)
379358090Smm		archive_wstring_free(&temp_name);
380232153Smm	return (fd);
381228753Smm}
382232153Smm
383358090Smmint
384358090Smm__archive_mktemp(const char *tmpdir)
385358090Smm{
386358090Smm	return __archive_mktempx(tmpdir, NULL);
387358090Smm}
388358090Smm
389358090Smmint
390358090Smm__archive_mkstemp(wchar_t *template)
391358090Smm{
392358090Smm	return __archive_mktempx(NULL, template);
393358090Smm}
394358090Smm
395232153Smm#else
396232153Smm
397232153Smmstatic int
398232153Smmget_tempdir(struct archive_string *temppath)
399232153Smm{
400232153Smm	const char *tmp;
401232153Smm
402232153Smm	tmp = getenv("TMPDIR");
403232153Smm	if (tmp == NULL)
404232153Smm#ifdef _PATH_TMP
405232153Smm		tmp = _PATH_TMP;
406232153Smm#else
407232153Smm                tmp = "/tmp";
408232153Smm#endif
409232153Smm	archive_strcpy(temppath, tmp);
410232153Smm	if (temppath->s[temppath->length-1] != '/')
411232153Smm		archive_strappend_char(temppath, '/');
412232153Smm	return (ARCHIVE_OK);
413232153Smm}
414232153Smm
415232153Smm#if defined(HAVE_MKSTEMP)
416232153Smm
417232153Smm/*
418232153Smm * We can use mkstemp().
419232153Smm */
420232153Smm
421232153Smmint
422232153Smm__archive_mktemp(const char *tmpdir)
423232153Smm{
424232153Smm	struct archive_string temp_name;
425232153Smm	int fd = -1;
426232153Smm
427232153Smm	archive_string_init(&temp_name);
428232153Smm	if (tmpdir == NULL) {
429232153Smm		if (get_tempdir(&temp_name) != ARCHIVE_OK)
430232153Smm			goto exit_tmpfile;
431232153Smm	} else {
432232153Smm		archive_strcpy(&temp_name, tmpdir);
433232153Smm		if (temp_name.s[temp_name.length-1] != '/')
434232153Smm			archive_strappend_char(&temp_name, '/');
435232153Smm	}
436368708Smm#ifdef O_TMPFILE
437368708Smm	fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600);
438368708Smm	if(fd >= 0)
439368708Smm		goto exit_tmpfile;
440368708Smm#endif
441232153Smm	archive_strcat(&temp_name, "libarchive_XXXXXX");
442232153Smm	fd = mkstemp(temp_name.s);
443232153Smm	if (fd < 0)
444232153Smm		goto exit_tmpfile;
445248616Smm	__archive_ensure_cloexec_flag(fd);
446232153Smm	unlink(temp_name.s);
447232153Smmexit_tmpfile:
448232153Smm	archive_string_free(&temp_name);
449232153Smm	return (fd);
450232153Smm}
451232153Smm
452358090Smmint
453358090Smm__archive_mkstemp(char *template)
454358090Smm{
455358090Smm	int fd = -1;
456358090Smm	fd = mkstemp(template);
457358090Smm	if (fd >= 0)
458358090Smm		__archive_ensure_cloexec_flag(fd);
459358090Smm	return (fd);
460358090Smm}
461232153Smm
462358090Smm#else /* !HAVE_MKSTEMP */
463358090Smm
464232153Smm/*
465232153Smm * We use a private routine.
466232153Smm */
467232153Smm
468358090Smmstatic int
469358090Smm__archive_mktempx(const char *tmpdir, char *template)
470232153Smm{
471232153Smm        static const char num[] = {
472232153Smm		'0', '1', '2', '3', '4', '5', '6', '7',
473232153Smm		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
474232153Smm		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
475232153Smm		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
476232153Smm		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
477232153Smm		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
478232153Smm		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
479232153Smm		'u', 'v', 'w', 'x', 'y', 'z'
480232153Smm        };
481232153Smm	struct archive_string temp_name;
482232153Smm	struct stat st;
483232153Smm	int fd;
484232153Smm	char *tp, *ep;
485232153Smm
486232153Smm	fd = -1;
487358090Smm	if (template == NULL) {
488358090Smm		archive_string_init(&temp_name);
489358090Smm		if (tmpdir == NULL) {
490358090Smm			if (get_tempdir(&temp_name) != ARCHIVE_OK)
491358090Smm				goto exit_tmpfile;
492358090Smm		} else
493358090Smm			archive_strcpy(&temp_name, tmpdir);
494358090Smm		if (temp_name.s[temp_name.length-1] == '/') {
495358090Smm			temp_name.s[temp_name.length-1] = '\0';
496358090Smm			temp_name.length --;
497358090Smm		}
498358090Smm		if (la_stat(temp_name.s, &st) < 0)
499232153Smm			goto exit_tmpfile;
500358090Smm		if (!S_ISDIR(st.st_mode)) {
501358090Smm			errno = ENOTDIR;
502358090Smm			goto exit_tmpfile;
503358090Smm		}
504358090Smm		archive_strcat(&temp_name, "/libarchive_");
505358090Smm		tp = temp_name.s + archive_strlen(&temp_name);
506358090Smm		archive_strcat(&temp_name, "XXXXXXXXXX");
507358090Smm		ep = temp_name.s + archive_strlen(&temp_name);
508358090Smm		template = temp_name.s;
509358090Smm	} else {
510358090Smm		tp = strchr(template, 'X');
511358090Smm		if (tp == NULL)	/* No X, programming error */
512358090Smm			abort();
513358090Smm		for (ep = tp; *ep == 'X'; ep++)
514358090Smm			continue;
515358090Smm		if (*ep)	/* X followed by non X, programming error */
516358090Smm			abort();
517232153Smm	}
518232153Smm
519232153Smm	do {
520232153Smm		char *p;
521232153Smm
522232153Smm		p = tp;
523302001Smm		archive_random(p, ep - p);
524302001Smm		while (p < ep) {
525302001Smm			int d = *((unsigned char *)p) % sizeof(num);
526302001Smm			*p++ = num[d];
527302001Smm		}
528358090Smm		fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
529248616Smm			  0600);
530232153Smm	} while (fd < 0 && errno == EEXIST);
531232153Smm	if (fd < 0)
532232153Smm		goto exit_tmpfile;
533248616Smm	__archive_ensure_cloexec_flag(fd);
534358090Smm	if (template == temp_name.s)
535358090Smm		unlink(temp_name.s);
536232153Smmexit_tmpfile:
537358090Smm	if (template == temp_name.s)
538358090Smm		archive_string_free(&temp_name);
539232153Smm	return (fd);
540232153Smm}
541232153Smm
542358090Smmint
543358090Smm__archive_mktemp(const char *tmpdir)
544358090Smm{
545358090Smm	return __archive_mktempx(tmpdir, NULL);
546358090Smm}
547358090Smm
548358090Smmint
549358090Smm__archive_mkstemp(char *template)
550358090Smm{
551358090Smm	return __archive_mktempx(NULL, template);
552358090Smm}
553358090Smm
554358090Smm#endif /* !HAVE_MKSTEMP */
555232153Smm#endif /* !_WIN32 || __CYGWIN__ */
556248616Smm
557248616Smm/*
558248616Smm * Set FD_CLOEXEC flag to a file descriptor if it is not set.
559248616Smm * We have to set the flag if the platform does not provide O_CLOEXEC
560248616Smm * or F_DUPFD_CLOEXEC flags.
561248616Smm *
562248616Smm * Note: This function is absolutely called after creating a new file
563248616Smm * descriptor even if the platform seemingly provides O_CLOEXEC or
564248616Smm * F_DUPFD_CLOEXEC macros because it is possible that the platform
565248616Smm * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
566248616Smm */
567248616Smmvoid
568248616Smm__archive_ensure_cloexec_flag(int fd)
569248616Smm{
570248616Smm#if defined(_WIN32) && !defined(__CYGWIN__)
571305192Smm	(void)fd; /* UNUSED */
572248616Smm#else
573248616Smm	int flags;
574248616Smm
575248616Smm	if (fd >= 0) {
576248616Smm		flags = fcntl(fd, F_GETFD);
577248616Smm		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
578248616Smm			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
579248616Smm	}
580248616Smm#endif
581248616Smm}
582302001Smm
583302001Smm/*
584302001Smm * Utility function to sort a group of strings using quicksort.
585302001Smm */
586302001Smmstatic int
587302001Smmarchive_utility_string_sort_helper(char **strings, unsigned int n)
588302001Smm{
589302001Smm	unsigned int i, lesser_count, greater_count;
590302001Smm	char **lesser, **greater, **tmp, *pivot;
591302001Smm	int retval1, retval2;
592302001Smm
593302001Smm	/* A list of 0 or 1 elements is already sorted */
594302001Smm	if (n <= 1)
595302001Smm		return (ARCHIVE_OK);
596302001Smm
597302001Smm	lesser_count = greater_count = 0;
598302001Smm	lesser = greater = NULL;
599302001Smm	pivot = strings[0];
600302001Smm	for (i = 1; i < n; i++)
601302001Smm	{
602302001Smm		if (strcmp(strings[i], pivot) < 0)
603302001Smm		{
604302001Smm			lesser_count++;
605302001Smm			tmp = (char **)realloc(lesser,
606302001Smm				lesser_count * sizeof(char *));
607302001Smm			if (!tmp) {
608302001Smm				free(greater);
609302001Smm				free(lesser);
610302001Smm				return (ARCHIVE_FATAL);
611302001Smm			}
612302001Smm			lesser = tmp;
613302001Smm			lesser[lesser_count - 1] = strings[i];
614302001Smm		}
615302001Smm		else
616302001Smm		{
617302001Smm			greater_count++;
618302001Smm			tmp = (char **)realloc(greater,
619302001Smm				greater_count * sizeof(char *));
620302001Smm			if (!tmp) {
621302001Smm				free(greater);
622302001Smm				free(lesser);
623302001Smm				return (ARCHIVE_FATAL);
624302001Smm			}
625302001Smm			greater = tmp;
626302001Smm			greater[greater_count - 1] = strings[i];
627302001Smm		}
628302001Smm	}
629302001Smm
630302001Smm	/* quicksort(lesser) */
631302001Smm	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
632302001Smm	for (i = 0; i < lesser_count; i++)
633302001Smm		strings[i] = lesser[i];
634302001Smm	free(lesser);
635302001Smm
636302001Smm	/* pivot */
637302001Smm	strings[lesser_count] = pivot;
638302001Smm
639302001Smm	/* quicksort(greater) */
640302001Smm	retval2 = archive_utility_string_sort_helper(greater, greater_count);
641302001Smm	for (i = 0; i < greater_count; i++)
642302001Smm		strings[lesser_count + 1 + i] = greater[i];
643302001Smm	free(greater);
644302001Smm
645302001Smm	return (retval1 < retval2) ? retval1 : retval2;
646302001Smm}
647302001Smm
648302001Smmint
649302001Smmarchive_utility_string_sort(char **strings)
650302001Smm{
651302001Smm	  unsigned int size = 0;
652302001Smm	  while (strings[size] != NULL)
653302001Smm		size++;
654302001Smm	  return archive_utility_string_sort_helper(strings, size);
655302001Smm}
656