Blame libarchive/archive_util.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
Packit 08bd4c
 * Copyright (c) 2003-2007 Tim Kientzle
Packit 08bd4c
 * All rights reserved.
Packit 08bd4c
 *
Packit 08bd4c
 * Redistribution and use in source and binary forms, with or without
Packit 08bd4c
 * modification, are permitted provided that the following conditions
Packit 08bd4c
 * are met:
Packit 08bd4c
 * 1. Redistributions of source code must retain the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer.
Packit 08bd4c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer in the
Packit 08bd4c
 *    documentation and/or other materials provided with the distribution.
Packit 08bd4c
 *
Packit 08bd4c
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit 08bd4c
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 08bd4c
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 08bd4c
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 08bd4c
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 08bd4c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 08bd4c
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 08bd4c
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 08bd4c
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 08bd4c
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#include "archive_platform.h"
Packit 08bd4c
__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_SYS_TYPES_H
Packit 08bd4c
#include <sys/types.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_ERRNO_H
Packit 08bd4c
#include <errno.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_FCNTL_H
Packit 08bd4c
#include <fcntl.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STDLIB_H
Packit 08bd4c
#include <stdlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STRING_H
Packit 08bd4c
#include <string.h>
Packit 08bd4c
#endif
Packit 08bd4c
#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
Packit 08bd4c
#include <wincrypt.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
#include <zlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_LZMA_H
Packit 08bd4c
#include <lzma.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_BZLIB_H
Packit 08bd4c
#include <bzlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_LZ4_H
Packit 08bd4c
#include <lz4.h>
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
#include "archive.h"
Packit 08bd4c
#include "archive_private.h"
Packit 08bd4c
#include "archive_random_private.h"
Packit 08bd4c
#include "archive_string.h"
Packit 08bd4c
Packit 08bd4c
#ifndef O_CLOEXEC
Packit 08bd4c
#define O_CLOEXEC	0
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
static int archive_utility_string_sort_helper(char **, unsigned int);
Packit 08bd4c
Packit 08bd4c
/* Generic initialization of 'struct archive' objects. */
Packit 08bd4c
int
Packit 08bd4c
__archive_clean(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	archive_string_conversion_free(a);
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_version_number(void)
Packit 08bd4c
{
Packit 08bd4c
	return (ARCHIVE_VERSION_NUMBER);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
const char *
Packit 08bd4c
archive_version_string(void)
Packit 08bd4c
{
Packit 08bd4c
	return (ARCHIVE_VERSION_STRING);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_errno(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return (a->archive_error_number);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
const char *
Packit 08bd4c
archive_error_string(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
Packit 08bd4c
	if (a->error != NULL  &&  *a->error != '\0')
Packit 08bd4c
		return (a->error);
Packit 08bd4c
	else
Packit 08bd4c
		return (NULL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_file_count(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return (a->file_count);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_format(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return (a->archive_format);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
const char *
Packit 08bd4c
archive_format_name(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return (a->archive_format_name);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_compression(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return archive_filter_code(a, 0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
const char *
Packit 08bd4c
archive_compression_name(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return archive_filter_name(a, 0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Return a count of the number of compressed bytes processed.
Packit 08bd4c
 */
Packit 08bd4c
int64_t
Packit 08bd4c
archive_position_compressed(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return archive_filter_bytes(a, -1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Return a count of the number of uncompressed bytes processed.
Packit 08bd4c
 */
Packit 08bd4c
int64_t
Packit 08bd4c
archive_position_uncompressed(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	return archive_filter_bytes(a, 0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
archive_clear_error(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	archive_string_empty(&a->error_string);
Packit 08bd4c
	a->error = NULL;
Packit 08bd4c
	a->archive_error_number = 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
Packit 08bd4c
{
Packit 08bd4c
	va_list ap;
Packit 08bd4c
Packit 08bd4c
	a->archive_error_number = error_number;
Packit 08bd4c
	if (fmt == NULL) {
Packit 08bd4c
		a->error = NULL;
Packit 08bd4c
		return;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	archive_string_empty(&(a->error_string));
Packit 08bd4c
	va_start(ap, fmt);
Packit 08bd4c
	archive_string_vsprintf(&(a->error_string), fmt, ap);
Packit 08bd4c
	va_end(ap);
Packit 08bd4c
	a->error = a->error_string.s;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
archive_copy_error(struct archive *dest, struct archive *src)
Packit 08bd4c
{
Packit 08bd4c
	dest->archive_error_number = src->archive_error_number;
Packit 08bd4c
Packit 08bd4c
	archive_string_copy(&dest->error_string, &src->error_string);
Packit 08bd4c
	dest->error = dest->error_string.s;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
__archive_errx(int retvalue, const char *msg)
Packit 08bd4c
{
Packit 08bd4c
	static const char msg1[] = "Fatal Internal Error in libarchive: ";
Packit 08bd4c
	size_t s;
Packit 08bd4c
Packit 08bd4c
	s = write(2, msg1, strlen(msg1));
Packit 08bd4c
	(void)s; /* UNUSED */
Packit 08bd4c
	s = write(2, msg, strlen(msg));
Packit 08bd4c
	(void)s; /* UNUSED */
Packit 08bd4c
	s = write(2, "\n", 1);
Packit 08bd4c
	(void)s; /* UNUSED */
Packit 08bd4c
	exit(retvalue);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Create a temporary file
Packit 08bd4c
 */
Packit 08bd4c
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Do not use Windows tmpfile() function.
Packit 08bd4c
 * It will make a temporary file under the root directory
Packit 08bd4c
 * and it'll cause permission error if a user who is
Packit 08bd4c
 * non-Administrator creates temporary files.
Packit 08bd4c
 * Also Windows version of mktemp family including _mktemp_s
Packit 08bd4c
 * are not secure.
Packit 08bd4c
 */
Packit 08bd4c
int
Packit 08bd4c
__archive_mktemp(const char *tmpdir)
Packit 08bd4c
{
Packit 08bd4c
	static const wchar_t prefix[] = L"libarchive_";
Packit 08bd4c
	static const wchar_t suffix[] = L"XXXXXXXXXX";
Packit 08bd4c
	static const wchar_t num[] = {
Packit 08bd4c
		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
Packit 08bd4c
		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
Packit 08bd4c
		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
Packit 08bd4c
		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
Packit 08bd4c
		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
Packit 08bd4c
		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
Packit 08bd4c
		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
Packit 08bd4c
		L'u', L'v', L'w', L'x', L'y', L'z'
Packit 08bd4c
	};
Packit 08bd4c
	HCRYPTPROV hProv;
Packit 08bd4c
	struct archive_wstring temp_name;
Packit 08bd4c
	wchar_t *ws;
Packit 08bd4c
	DWORD attr;
Packit 08bd4c
	wchar_t *xp, *ep;
Packit 08bd4c
	int fd;
Packit 08bd4c
Packit 08bd4c
	hProv = (HCRYPTPROV)NULL;
Packit 08bd4c
	fd = -1;
Packit 08bd4c
	ws = NULL;
Packit 08bd4c
	archive_string_init(&temp_name);
Packit 08bd4c
Packit 08bd4c
	/* Get a temporary directory. */
Packit 08bd4c
	if (tmpdir == NULL) {
Packit 08bd4c
		size_t l;
Packit 08bd4c
		wchar_t *tmp;
Packit 08bd4c
Packit 08bd4c
		l = GetTempPathW(0, NULL);
Packit 08bd4c
		if (l == 0) {
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		tmp = malloc(l*sizeof(wchar_t));
Packit 08bd4c
		if (tmp == NULL) {
Packit 08bd4c
			errno = ENOMEM;
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		GetTempPathW((DWORD)l, tmp);
Packit 08bd4c
		archive_wstrcpy(&temp_name, tmp);
Packit 08bd4c
		free(tmp);
Packit 08bd4c
	} else {
Packit 08bd4c
		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
Packit 08bd4c
		    strlen(tmpdir)) < 0)
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		if (temp_name.s[temp_name.length-1] != L'/')
Packit 08bd4c
			archive_wstrappend_wchar(&temp_name, L'/');
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Check if temp_name is a directory. */
Packit 08bd4c
	attr = GetFileAttributesW(temp_name.s);
Packit 08bd4c
	if (attr == (DWORD)-1) {
Packit 08bd4c
		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		ws = __la_win_permissive_name_w(temp_name.s);
Packit 08bd4c
		if (ws == NULL) {
Packit 08bd4c
			errno = EINVAL;
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		attr = GetFileAttributesW(ws);
Packit 08bd4c
		if (attr == (DWORD)-1) {
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
Packit 08bd4c
		errno = ENOTDIR;
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Create a temporary file.
Packit 08bd4c
	 */
Packit 08bd4c
	archive_wstrcat(&temp_name, prefix);
Packit 08bd4c
	archive_wstrcat(&temp_name, suffix);
Packit 08bd4c
	ep = temp_name.s + archive_strlen(&temp_name);
Packit 08bd4c
	xp = ep - wcslen(suffix);
Packit 08bd4c
Packit 08bd4c
	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
Packit 08bd4c
		CRYPT_VERIFYCONTEXT)) {
Packit 08bd4c
		la_dosmaperr(GetLastError());
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		wchar_t *p;
Packit 08bd4c
		HANDLE h;
Packit 08bd4c
Packit 08bd4c
		/* Generate a random file name through CryptGenRandom(). */
Packit 08bd4c
		p = xp;
Packit 08bd4c
		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
Packit 08bd4c
		    (BYTE*)p)) {
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		for (; p < ep; p++)
Packit 08bd4c
			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
Packit 08bd4c
Packit 08bd4c
		free(ws);
Packit 08bd4c
		ws = __la_win_permissive_name_w(temp_name.s);
Packit 08bd4c
		if (ws == NULL) {
Packit 08bd4c
			errno = EINVAL;
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
Packit 08bd4c
		 * delete this temporary file immediately when this
Packit 08bd4c
		 * file closed. */
Packit 08bd4c
		h = CreateFileW(ws,
Packit 08bd4c
		    GENERIC_READ | GENERIC_WRITE | DELETE,
Packit 08bd4c
		    0,/* Not share */
Packit 08bd4c
		    NULL,
Packit 08bd4c
		    CREATE_NEW,/* Create a new file only */
Packit 08bd4c
		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
Packit 08bd4c
		    NULL);
Packit 08bd4c
		if (h == INVALID_HANDLE_VALUE) {
Packit 08bd4c
			/* The same file already exists. retry with
Packit 08bd4c
			 * a new filename. */
Packit 08bd4c
			if (GetLastError() == ERROR_FILE_EXISTS)
Packit 08bd4c
				continue;
Packit 08bd4c
			/* Otherwise, fail creation temporary file. */
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		}
Packit 08bd4c
		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
Packit 08bd4c
		if (fd == -1) {
Packit 08bd4c
			CloseHandle(h);
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
		} else
Packit 08bd4c
			break;/* success! */
Packit 08bd4c
	}
Packit 08bd4c
exit_tmpfile:
Packit 08bd4c
	if (hProv != (HCRYPTPROV)NULL)
Packit 08bd4c
		CryptReleaseContext(hProv, 0);
Packit 08bd4c
	free(ws);
Packit 08bd4c
	archive_wstring_free(&temp_name);
Packit 08bd4c
	return (fd);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#else
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
get_tempdir(struct archive_string *temppath)
Packit 08bd4c
{
Packit 08bd4c
	const char *tmp;
Packit 08bd4c
Packit 08bd4c
	tmp = getenv("TMPDIR");
Packit 08bd4c
	if (tmp == NULL)
Packit 08bd4c
#ifdef _PATH_TMP
Packit 08bd4c
		tmp = _PATH_TMP;
Packit 08bd4c
#else
Packit 08bd4c
                tmp = "/tmp";
Packit 08bd4c
#endif
Packit 08bd4c
	archive_strcpy(temppath, tmp);
Packit 08bd4c
	if (temppath->s[temppath->length-1] != '/')
Packit 08bd4c
		archive_strappend_char(temppath, '/');
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#if defined(HAVE_MKSTEMP)
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * We can use mkstemp().
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
__archive_mktemp(const char *tmpdir)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_string temp_name;
Packit 08bd4c
	int fd = -1;
Packit 08bd4c
Packit 08bd4c
	archive_string_init(&temp_name);
Packit 08bd4c
	if (tmpdir == NULL) {
Packit 08bd4c
		if (get_tempdir(&temp_name) != ARCHIVE_OK)
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
	} else {
Packit 08bd4c
		archive_strcpy(&temp_name, tmpdir);
Packit 08bd4c
		if (temp_name.s[temp_name.length-1] != '/')
Packit 08bd4c
			archive_strappend_char(&temp_name, '/');
Packit 08bd4c
	}
Packit 08bd4c
	archive_strcat(&temp_name, "libarchive_XXXXXX");
Packit 08bd4c
	fd = mkstemp(temp_name.s);
Packit 08bd4c
	if (fd < 0)
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	__archive_ensure_cloexec_flag(fd);
Packit 08bd4c
	unlink(temp_name.s);
Packit 08bd4c
exit_tmpfile:
Packit 08bd4c
	archive_string_free(&temp_name);
Packit 08bd4c
	return (fd);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#else
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * We use a private routine.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
__archive_mktemp(const char *tmpdir)
Packit 08bd4c
{
Packit 08bd4c
        static const char num[] = {
Packit 08bd4c
		'0', '1', '2', '3', '4', '5', '6', '7',
Packit 08bd4c
		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
Packit 08bd4c
		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
Packit 08bd4c
		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
Packit 08bd4c
		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
Packit 08bd4c
		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
Packit 08bd4c
		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
Packit 08bd4c
		'u', 'v', 'w', 'x', 'y', 'z'
Packit 08bd4c
        };
Packit 08bd4c
	struct archive_string temp_name;
Packit 08bd4c
	struct stat st;
Packit 08bd4c
	int fd;
Packit 08bd4c
	char *tp, *ep;
Packit 08bd4c
Packit 08bd4c
	fd = -1;
Packit 08bd4c
	archive_string_init(&temp_name);
Packit 08bd4c
	if (tmpdir == NULL) {
Packit 08bd4c
		if (get_tempdir(&temp_name) != ARCHIVE_OK)
Packit 08bd4c
			goto exit_tmpfile;
Packit 08bd4c
	} else
Packit 08bd4c
		archive_strcpy(&temp_name, tmpdir);
Packit 08bd4c
	if (temp_name.s[temp_name.length-1] == '/') {
Packit 08bd4c
		temp_name.s[temp_name.length-1] = '\0';
Packit 08bd4c
		temp_name.length --;
Packit 08bd4c
	}
Packit 08bd4c
	if (stat(temp_name.s, &st) < 0)
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	if (!S_ISDIR(st.st_mode)) {
Packit 08bd4c
		errno = ENOTDIR;
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	}
Packit 08bd4c
	archive_strcat(&temp_name, "/libarchive_");
Packit 08bd4c
	tp = temp_name.s + archive_strlen(&temp_name);
Packit 08bd4c
	archive_strcat(&temp_name, "XXXXXXXXXX");
Packit 08bd4c
	ep = temp_name.s + archive_strlen(&temp_name);
Packit 08bd4c
Packit 08bd4c
	do {
Packit 08bd4c
		char *p;
Packit 08bd4c
Packit 08bd4c
		p = tp;
Packit 08bd4c
		archive_random(p, ep - p);
Packit 08bd4c
		while (p < ep) {
Packit 08bd4c
			int d = *((unsigned char *)p) % sizeof(num);
Packit 08bd4c
			*p++ = num[d];
Packit 08bd4c
		}
Packit 08bd4c
		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
Packit 08bd4c
			  0600);
Packit 08bd4c
	} while (fd < 0 && errno == EEXIST);
Packit 08bd4c
	if (fd < 0)
Packit 08bd4c
		goto exit_tmpfile;
Packit 08bd4c
	__archive_ensure_cloexec_flag(fd);
Packit 08bd4c
	unlink(temp_name.s);
Packit 08bd4c
exit_tmpfile:
Packit 08bd4c
	archive_string_free(&temp_name);
Packit 08bd4c
	return (fd);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#endif /* HAVE_MKSTEMP */
Packit 08bd4c
#endif /* !_WIN32 || __CYGWIN__ */
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
Packit 08bd4c
 * We have to set the flag if the platform does not provide O_CLOEXEC
Packit 08bd4c
 * or F_DUPFD_CLOEXEC flags.
Packit 08bd4c
 *
Packit 08bd4c
 * Note: This function is absolutely called after creating a new file
Packit 08bd4c
 * descriptor even if the platform seemingly provides O_CLOEXEC or
Packit 08bd4c
 * F_DUPFD_CLOEXEC macros because it is possible that the platform
Packit 08bd4c
 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
Packit 08bd4c
 */
Packit 08bd4c
void
Packit 08bd4c
__archive_ensure_cloexec_flag(int fd)
Packit 08bd4c
{
Packit 08bd4c
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 08bd4c
	(void)fd; /* UNUSED */
Packit 08bd4c
#else
Packit 08bd4c
	int flags;
Packit 08bd4c
Packit 08bd4c
	if (fd >= 0) {
Packit 08bd4c
		flags = fcntl(fd, F_GETFD);
Packit 08bd4c
		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
Packit 08bd4c
			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
Packit 08bd4c
	}
Packit 08bd4c
#endif
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Utility function to sort a group of strings using quicksort.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
archive_utility_string_sort_helper(char **strings, unsigned int n)
Packit 08bd4c
{
Packit 08bd4c
	unsigned int i, lesser_count, greater_count;
Packit 08bd4c
	char **lesser, **greater, **tmp, *pivot;
Packit 08bd4c
	int retval1, retval2;
Packit 08bd4c
Packit 08bd4c
	/* A list of 0 or 1 elements is already sorted */
Packit 08bd4c
	if (n <= 1)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	lesser_count = greater_count = 0;
Packit 08bd4c
	lesser = greater = NULL;
Packit 08bd4c
	pivot = strings[0];
Packit 08bd4c
	for (i = 1; i < n; i++)
Packit 08bd4c
	{
Packit 08bd4c
		if (strcmp(strings[i], pivot) < 0)
Packit 08bd4c
		{
Packit 08bd4c
			lesser_count++;
Packit 08bd4c
			tmp = (char **)realloc(lesser,
Packit 08bd4c
				lesser_count * sizeof(char *));
Packit 08bd4c
			if (!tmp) {
Packit 08bd4c
				free(greater);
Packit 08bd4c
				free(lesser);
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			lesser = tmp;
Packit 08bd4c
			lesser[lesser_count - 1] = strings[i];
Packit 08bd4c
		}
Packit 08bd4c
		else
Packit 08bd4c
		{
Packit 08bd4c
			greater_count++;
Packit 08bd4c
			tmp = (char **)realloc(greater,
Packit 08bd4c
				greater_count * sizeof(char *));
Packit 08bd4c
			if (!tmp) {
Packit 08bd4c
				free(greater);
Packit 08bd4c
				free(lesser);
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			greater = tmp;
Packit 08bd4c
			greater[greater_count - 1] = strings[i];
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* quicksort(lesser) */
Packit 08bd4c
	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
Packit 08bd4c
	for (i = 0; i < lesser_count; i++)
Packit 08bd4c
		strings[i] = lesser[i];
Packit 08bd4c
	free(lesser);
Packit 08bd4c
Packit 08bd4c
	/* pivot */
Packit 08bd4c
	strings[lesser_count] = pivot;
Packit 08bd4c
Packit 08bd4c
	/* quicksort(greater) */
Packit 08bd4c
	retval2 = archive_utility_string_sort_helper(greater, greater_count);
Packit 08bd4c
	for (i = 0; i < greater_count; i++)
Packit 08bd4c
		strings[lesser_count + 1 + i] = greater[i];
Packit 08bd4c
	free(greater);
Packit 08bd4c
Packit 08bd4c
	return (retval1 < retval2) ? retval1 : retval2;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_utility_string_sort(char **strings)
Packit 08bd4c
{
Packit 08bd4c
	  unsigned int size = 0;
Packit 08bd4c
	  while (strings[size] != NULL)
Packit 08bd4c
		size++;
Packit 08bd4c
	  return archive_utility_string_sort_helper(strings, size);
Packit 08bd4c
}