archive_util.c revision 305188
1/*-
2 * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
3 * Copyright (c) 2003-2007 Tim Kientzle
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "archive_platform.h"
28__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_util.c 305188 2016-09-01 07:53:59Z mm $");
29
30#ifdef HAVE_SYS_TYPES_H
31#include <sys/types.h>
32#endif
33#ifdef HAVE_ERRNO_H
34#include <errno.h>
35#endif
36#ifdef HAVE_FCNTL_H
37#include <fcntl.h>
38#endif
39#ifdef HAVE_STDLIB_H
40#include <stdlib.h>
41#endif
42#ifdef HAVE_STRING_H
43#include <string.h>
44#endif
45#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
46#include <wincrypt.h>
47#endif
48#ifdef HAVE_ZLIB_H
49#include <zlib.h>
50#endif
51#ifdef HAVE_LZMA_H
52#include <lzma.h>
53#endif
54#ifdef HAVE_BZLIB_H
55#include <bzlib.h>
56#endif
57#ifdef HAVE_LZ4_H
58#include <lz4.h>
59#endif
60
61#include "archive.h"
62#include "archive_private.h"
63#include "archive_random_private.h"
64#include "archive_string.h"
65
66#ifndef O_CLOEXEC
67#define O_CLOEXEC	0
68#endif
69
70static int archive_utility_string_sort_helper(char **, unsigned int);
71
72/* Generic initialization of 'struct archive' objects. */
73int
74__archive_clean(struct archive *a)
75{
76	archive_string_conversion_free(a);
77	return (ARCHIVE_OK);
78}
79
80int
81archive_version_number(void)
82{
83	return (ARCHIVE_VERSION_NUMBER);
84}
85
86const char *
87archive_version_string(void)
88{
89	return (ARCHIVE_VERSION_STRING);
90}
91
92const char *
93archive_version_details(void)
94{
95	static struct archive_string str;
96	static int init = 0;
97	const char *zlib = archive_zlib_version();
98	const char *liblzma = archive_liblzma_version();
99	const char *bzlib = archive_bzlib_version();
100	const char *liblz4 = archive_liblz4_version();
101
102	if (!init) {
103		archive_string_init(&str);
104
105		archive_strcat(&str, ARCHIVE_VERSION_STRING);
106		if (zlib != NULL) {
107			archive_strcat(&str, " zlib/");
108			archive_strcat(&str, zlib);
109		}
110		if (liblzma) {
111			archive_strcat(&str, " liblzma/");
112			archive_strcat(&str, liblzma);
113		}
114		if (bzlib) {
115			const char *p = bzlib;
116			const char *sep = strchr(p, ',');
117			if (sep == NULL)
118				sep = p + strlen(p);
119			archive_strcat(&str, " bz2lib/");
120			archive_strncat(&str, p, sep - p);
121		}
122		if (liblz4) {
123			archive_strcat(&str, " liblz4/");
124			archive_strcat(&str, liblz4);
125		}
126	}
127	return str.s;
128}
129
130const char *
131archive_zlib_version(void)
132{
133#ifdef HAVE_ZLIB_H
134	return ZLIB_VERSION;
135#else
136	return NULL;
137#endif
138}
139
140const char *
141archive_liblzma_version(void)
142{
143#ifdef HAVE_LZMA_H
144	return LZMA_VERSION_STRING;
145#else
146	return NULL;
147#endif
148}
149
150const char *
151archive_bzlib_version(void)
152{
153#ifdef HAVE_BZLIB_H
154	return BZ2_bzlibVersion();
155#else
156	return NULL;
157#endif
158}
159
160const char *
161archive_liblz4_version(void)
162{
163#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
164#define str(s) #s
165#define NUMBER(x) str(x)
166	return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
167#undef NUMBER
168#undef str
169#else
170	return NULL;
171#endif
172}
173
174int
175archive_errno(struct archive *a)
176{
177	return (a->archive_error_number);
178}
179
180const char *
181archive_error_string(struct archive *a)
182{
183
184	if (a->error != NULL  &&  *a->error != '\0')
185		return (a->error);
186	else
187		return (NULL);
188}
189
190int
191archive_file_count(struct archive *a)
192{
193	return (a->file_count);
194}
195
196int
197archive_format(struct archive *a)
198{
199	return (a->archive_format);
200}
201
202const char *
203archive_format_name(struct archive *a)
204{
205	return (a->archive_format_name);
206}
207
208
209int
210archive_compression(struct archive *a)
211{
212	return archive_filter_code(a, 0);
213}
214
215const char *
216archive_compression_name(struct archive *a)
217{
218	return archive_filter_name(a, 0);
219}
220
221
222/*
223 * Return a count of the number of compressed bytes processed.
224 */
225int64_t
226archive_position_compressed(struct archive *a)
227{
228	return archive_filter_bytes(a, -1);
229}
230
231/*
232 * Return a count of the number of uncompressed bytes processed.
233 */
234int64_t
235archive_position_uncompressed(struct archive *a)
236{
237	return archive_filter_bytes(a, 0);
238}
239
240void
241archive_clear_error(struct archive *a)
242{
243	archive_string_empty(&a->error_string);
244	a->error = NULL;
245	a->archive_error_number = 0;
246}
247
248void
249archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
250{
251	va_list ap;
252
253	a->archive_error_number = error_number;
254	if (fmt == NULL) {
255		a->error = NULL;
256		return;
257	}
258
259	archive_string_empty(&(a->error_string));
260	va_start(ap, fmt);
261	archive_string_vsprintf(&(a->error_string), fmt, ap);
262	va_end(ap);
263	a->error = a->error_string.s;
264}
265
266void
267archive_copy_error(struct archive *dest, struct archive *src)
268{
269	dest->archive_error_number = src->archive_error_number;
270
271	archive_string_copy(&dest->error_string, &src->error_string);
272	dest->error = dest->error_string.s;
273}
274
275void
276__archive_errx(int retvalue, const char *msg)
277{
278	static const char *msg1 = "Fatal Internal Error in libarchive: ";
279	size_t s;
280
281	s = write(2, msg1, strlen(msg1));
282	(void)s; /* UNUSED */
283	s = write(2, msg, strlen(msg));
284	(void)s; /* UNUSED */
285	s = write(2, "\n", 1);
286	(void)s; /* UNUSED */
287	exit(retvalue);
288}
289
290/*
291 * Create a temporary file
292 */
293#if defined(_WIN32) && !defined(__CYGWIN__)
294
295/*
296 * Do not use Windows tmpfile() function.
297 * It will make a temporary file under the root directory
298 * and it'll cause permission error if a user who is
299 * non-Administrator creates temporary files.
300 * Also Windows version of mktemp family including _mktemp_s
301 * are not secure.
302 */
303int
304__archive_mktemp(const char *tmpdir)
305{
306	static const wchar_t *prefix = L"libarchive_";
307	static const wchar_t *suffix = L"XXXXXXXXXX";
308	static const wchar_t num[] = {
309		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
310		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
311		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
312		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
313		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
314		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
315		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
316		L'u', L'v', L'w', L'x', L'y', L'z'
317	};
318	HCRYPTPROV hProv;
319	struct archive_wstring temp_name;
320	wchar_t *ws;
321	DWORD attr;
322	wchar_t *xp, *ep;
323	int fd;
324
325	hProv = (HCRYPTPROV)NULL;
326	fd = -1;
327	ws = NULL;
328	archive_string_init(&temp_name);
329
330	/* Get a temporary directory. */
331	if (tmpdir == NULL) {
332		size_t l;
333		wchar_t *tmp;
334
335		l = GetTempPathW(0, NULL);
336		if (l == 0) {
337			la_dosmaperr(GetLastError());
338			goto exit_tmpfile;
339		}
340		tmp = malloc(l*sizeof(wchar_t));
341		if (tmp == NULL) {
342			errno = ENOMEM;
343			goto exit_tmpfile;
344		}
345		GetTempPathW((DWORD)l, tmp);
346		archive_wstrcpy(&temp_name, tmp);
347		free(tmp);
348	} else {
349		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
350		    strlen(tmpdir)) < 0)
351			goto exit_tmpfile;
352		if (temp_name.s[temp_name.length-1] != L'/')
353			archive_wstrappend_wchar(&temp_name, L'/');
354	}
355
356	/* Check if temp_name is a directory. */
357	attr = GetFileAttributesW(temp_name.s);
358	if (attr == (DWORD)-1) {
359		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
360			la_dosmaperr(GetLastError());
361			goto exit_tmpfile;
362		}
363		ws = __la_win_permissive_name_w(temp_name.s);
364		if (ws == NULL) {
365			errno = EINVAL;
366			goto exit_tmpfile;
367		}
368		attr = GetFileAttributesW(ws);
369		if (attr == (DWORD)-1) {
370			la_dosmaperr(GetLastError());
371			goto exit_tmpfile;
372		}
373	}
374	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
375		errno = ENOTDIR;
376		goto exit_tmpfile;
377	}
378
379	/*
380	 * Create a temporary file.
381	 */
382	archive_wstrcat(&temp_name, prefix);
383	archive_wstrcat(&temp_name, suffix);
384	ep = temp_name.s + archive_strlen(&temp_name);
385	xp = ep - wcslen(suffix);
386
387	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
388		CRYPT_VERIFYCONTEXT)) {
389		la_dosmaperr(GetLastError());
390		goto exit_tmpfile;
391	}
392
393	for (;;) {
394		wchar_t *p;
395		HANDLE h;
396
397		/* Generate a random file name through CryptGenRandom(). */
398		p = xp;
399		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
400		    (BYTE*)p)) {
401			la_dosmaperr(GetLastError());
402			goto exit_tmpfile;
403		}
404		for (; p < ep; p++)
405			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
406
407		free(ws);
408		ws = __la_win_permissive_name_w(temp_name.s);
409		if (ws == NULL) {
410			errno = EINVAL;
411			goto exit_tmpfile;
412		}
413		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
414		 * delete this temporary file immediately when this
415		 * file closed. */
416		h = CreateFileW(ws,
417		    GENERIC_READ | GENERIC_WRITE | DELETE,
418		    0,/* Not share */
419		    NULL,
420		    CREATE_NEW,/* Create a new file only */
421		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
422		    NULL);
423		if (h == INVALID_HANDLE_VALUE) {
424			/* The same file already exists. retry with
425			 * a new filename. */
426			if (GetLastError() == ERROR_FILE_EXISTS)
427				continue;
428			/* Otherwise, fail creation temporary file. */
429			la_dosmaperr(GetLastError());
430			goto exit_tmpfile;
431		}
432		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
433		if (fd == -1) {
434			CloseHandle(h);
435			goto exit_tmpfile;
436		} else
437			break;/* success! */
438	}
439exit_tmpfile:
440	if (hProv != (HCRYPTPROV)NULL)
441		CryptReleaseContext(hProv, 0);
442	free(ws);
443	archive_wstring_free(&temp_name);
444	return (fd);
445}
446
447#else
448
449static int
450get_tempdir(struct archive_string *temppath)
451{
452	const char *tmp;
453
454	tmp = getenv("TMPDIR");
455	if (tmp == NULL)
456#ifdef _PATH_TMP
457		tmp = _PATH_TMP;
458#else
459                tmp = "/tmp";
460#endif
461	archive_strcpy(temppath, tmp);
462	if (temppath->s[temppath->length-1] != '/')
463		archive_strappend_char(temppath, '/');
464	return (ARCHIVE_OK);
465}
466
467#if defined(HAVE_MKSTEMP)
468
469/*
470 * We can use mkstemp().
471 */
472
473int
474__archive_mktemp(const char *tmpdir)
475{
476	struct archive_string temp_name;
477	int fd = -1;
478
479	archive_string_init(&temp_name);
480	if (tmpdir == NULL) {
481		if (get_tempdir(&temp_name) != ARCHIVE_OK)
482			goto exit_tmpfile;
483	} else {
484		archive_strcpy(&temp_name, tmpdir);
485		if (temp_name.s[temp_name.length-1] != '/')
486			archive_strappend_char(&temp_name, '/');
487	}
488	archive_strcat(&temp_name, "libarchive_XXXXXX");
489	fd = mkstemp(temp_name.s);
490	if (fd < 0)
491		goto exit_tmpfile;
492	__archive_ensure_cloexec_flag(fd);
493	unlink(temp_name.s);
494exit_tmpfile:
495	archive_string_free(&temp_name);
496	return (fd);
497}
498
499#else
500
501/*
502 * We use a private routine.
503 */
504
505int
506__archive_mktemp(const char *tmpdir)
507{
508        static const char num[] = {
509		'0', '1', '2', '3', '4', '5', '6', '7',
510		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
511		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
512		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
513		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
514		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
515		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
516		'u', 'v', 'w', 'x', 'y', 'z'
517        };
518	struct archive_string temp_name;
519	struct stat st;
520	int fd;
521	char *tp, *ep;
522
523	fd = -1;
524	archive_string_init(&temp_name);
525	if (tmpdir == NULL) {
526		if (get_tempdir(&temp_name) != ARCHIVE_OK)
527			goto exit_tmpfile;
528	} else
529		archive_strcpy(&temp_name, tmpdir);
530	if (temp_name.s[temp_name.length-1] == '/') {
531		temp_name.s[temp_name.length-1] = '\0';
532		temp_name.length --;
533	}
534	if (stat(temp_name.s, &st) < 0)
535		goto exit_tmpfile;
536	if (!S_ISDIR(st.st_mode)) {
537		errno = ENOTDIR;
538		goto exit_tmpfile;
539	}
540	archive_strcat(&temp_name, "/libarchive_");
541	tp = temp_name.s + archive_strlen(&temp_name);
542	archive_strcat(&temp_name, "XXXXXXXXXX");
543	ep = temp_name.s + archive_strlen(&temp_name);
544
545	do {
546		char *p;
547
548		p = tp;
549		archive_random(p, ep - p);
550		while (p < ep) {
551			int d = *((unsigned char *)p) % sizeof(num);
552			*p++ = num[d];
553		}
554		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
555			  0600);
556	} while (fd < 0 && errno == EEXIST);
557	if (fd < 0)
558		goto exit_tmpfile;
559	__archive_ensure_cloexec_flag(fd);
560	unlink(temp_name.s);
561exit_tmpfile:
562	archive_string_free(&temp_name);
563	return (fd);
564}
565
566#endif /* HAVE_MKSTEMP */
567#endif /* !_WIN32 || __CYGWIN__ */
568
569/*
570 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
571 * We have to set the flag if the platform does not provide O_CLOEXEC
572 * or F_DUPFD_CLOEXEC flags.
573 *
574 * Note: This function is absolutely called after creating a new file
575 * descriptor even if the platform seemingly provides O_CLOEXEC or
576 * F_DUPFD_CLOEXEC macros because it is possible that the platform
577 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
578 */
579void
580__archive_ensure_cloexec_flag(int fd)
581{
582#if defined(_WIN32) && !defined(__CYGWIN__)
583	(void)fd; /* UNUSED */
584#else
585	int flags;
586
587	if (fd >= 0) {
588		flags = fcntl(fd, F_GETFD);
589		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
590			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
591	}
592#endif
593}
594
595/*
596 * Utility function to sort a group of strings using quicksort.
597 */
598static int
599archive_utility_string_sort_helper(char **strings, unsigned int n)
600{
601	unsigned int i, lesser_count, greater_count;
602	char **lesser, **greater, **tmp, *pivot;
603	int retval1, retval2;
604
605	/* A list of 0 or 1 elements is already sorted */
606	if (n <= 1)
607		return (ARCHIVE_OK);
608
609	lesser_count = greater_count = 0;
610	lesser = greater = NULL;
611	pivot = strings[0];
612	for (i = 1; i < n; i++)
613	{
614		if (strcmp(strings[i], pivot) < 0)
615		{
616			lesser_count++;
617			tmp = (char **)realloc(lesser,
618				lesser_count * sizeof(char *));
619			if (!tmp) {
620				free(greater);
621				free(lesser);
622				return (ARCHIVE_FATAL);
623			}
624			lesser = tmp;
625			lesser[lesser_count - 1] = strings[i];
626		}
627		else
628		{
629			greater_count++;
630			tmp = (char **)realloc(greater,
631				greater_count * sizeof(char *));
632			if (!tmp) {
633				free(greater);
634				free(lesser);
635				return (ARCHIVE_FATAL);
636			}
637			greater = tmp;
638			greater[greater_count - 1] = strings[i];
639		}
640	}
641
642	/* quicksort(lesser) */
643	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
644	for (i = 0; i < lesser_count; i++)
645		strings[i] = lesser[i];
646	free(lesser);
647
648	/* pivot */
649	strings[lesser_count] = pivot;
650
651	/* quicksort(greater) */
652	retval2 = archive_utility_string_sort_helper(greater, greater_count);
653	for (i = 0; i < greater_count; i++)
654		strings[lesser_count + 1 + i] = greater[i];
655	free(greater);
656
657	return (retval1 < retval2) ? retval1 : retval2;
658}
659
660int
661archive_utility_string_sort(char **strings)
662{
663	  unsigned int size = 0;
664	  while (strings[size] != NULL)
665		size++;
666	  return archive_utility_string_sort_helper(strings, size);
667}
668