Blame libarchive/archive_util.c

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