archive_util.c revision 328827
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 328827 2018-02-03 02:17:04Z 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
92int
93archive_errno(struct archive *a)
94{
95	return (a->archive_error_number);
96}
97
98const char *
99archive_error_string(struct archive *a)
100{
101
102	if (a->error != NULL  &&  *a->error != '\0')
103		return (a->error);
104	else
105		return (NULL);
106}
107
108int
109archive_file_count(struct archive *a)
110{
111	return (a->file_count);
112}
113
114int
115archive_format(struct archive *a)
116{
117	return (a->archive_format);
118}
119
120const char *
121archive_format_name(struct archive *a)
122{
123	return (a->archive_format_name);
124}
125
126
127int
128archive_compression(struct archive *a)
129{
130	return archive_filter_code(a, 0);
131}
132
133const char *
134archive_compression_name(struct archive *a)
135{
136	return archive_filter_name(a, 0);
137}
138
139
140/*
141 * Return a count of the number of compressed bytes processed.
142 */
143la_int64_t
144archive_position_compressed(struct archive *a)
145{
146	return archive_filter_bytes(a, -1);
147}
148
149/*
150 * Return a count of the number of uncompressed bytes processed.
151 */
152la_int64_t
153archive_position_uncompressed(struct archive *a)
154{
155	return archive_filter_bytes(a, 0);
156}
157
158void
159archive_clear_error(struct archive *a)
160{
161	archive_string_empty(&a->error_string);
162	a->error = NULL;
163	a->archive_error_number = 0;
164}
165
166void
167archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
168{
169	va_list ap;
170
171	a->archive_error_number = error_number;
172	if (fmt == NULL) {
173		a->error = NULL;
174		return;
175	}
176
177	archive_string_empty(&(a->error_string));
178	va_start(ap, fmt);
179	archive_string_vsprintf(&(a->error_string), fmt, ap);
180	va_end(ap);
181	a->error = a->error_string.s;
182}
183
184void
185archive_copy_error(struct archive *dest, struct archive *src)
186{
187	dest->archive_error_number = src->archive_error_number;
188
189	archive_string_copy(&dest->error_string, &src->error_string);
190	dest->error = dest->error_string.s;
191}
192
193void
194__archive_errx(int retvalue, const char *msg)
195{
196	static const char msg1[] = "Fatal Internal Error in libarchive: ";
197	size_t s;
198
199	s = write(2, msg1, strlen(msg1));
200	(void)s; /* UNUSED */
201	s = write(2, msg, strlen(msg));
202	(void)s; /* UNUSED */
203	s = write(2, "\n", 1);
204	(void)s; /* UNUSED */
205	exit(retvalue);
206}
207
208/*
209 * Create a temporary file
210 */
211#if defined(_WIN32) && !defined(__CYGWIN__)
212
213/*
214 * Do not use Windows tmpfile() function.
215 * It will make a temporary file under the root directory
216 * and it'll cause permission error if a user who is
217 * non-Administrator creates temporary files.
218 * Also Windows version of mktemp family including _mktemp_s
219 * are not secure.
220 */
221int
222__archive_mktemp(const char *tmpdir)
223{
224	static const wchar_t prefix[] = L"libarchive_";
225	static const wchar_t suffix[] = L"XXXXXXXXXX";
226	static const wchar_t num[] = {
227		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
228		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
229		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
230		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
231		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
232		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
233		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
234		L'u', L'v', L'w', L'x', L'y', L'z'
235	};
236	HCRYPTPROV hProv;
237	struct archive_wstring temp_name;
238	wchar_t *ws;
239	DWORD attr;
240	wchar_t *xp, *ep;
241	int fd;
242
243	hProv = (HCRYPTPROV)NULL;
244	fd = -1;
245	ws = NULL;
246	archive_string_init(&temp_name);
247
248	/* Get a temporary directory. */
249	if (tmpdir == NULL) {
250		size_t l;
251		wchar_t *tmp;
252
253		l = GetTempPathW(0, NULL);
254		if (l == 0) {
255			la_dosmaperr(GetLastError());
256			goto exit_tmpfile;
257		}
258		tmp = malloc(l*sizeof(wchar_t));
259		if (tmp == NULL) {
260			errno = ENOMEM;
261			goto exit_tmpfile;
262		}
263		GetTempPathW((DWORD)l, tmp);
264		archive_wstrcpy(&temp_name, tmp);
265		free(tmp);
266	} else {
267		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
268		    strlen(tmpdir)) < 0)
269			goto exit_tmpfile;
270		if (temp_name.s[temp_name.length-1] != L'/')
271			archive_wstrappend_wchar(&temp_name, L'/');
272	}
273
274	/* Check if temp_name is a directory. */
275	attr = GetFileAttributesW(temp_name.s);
276	if (attr == (DWORD)-1) {
277		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
278			la_dosmaperr(GetLastError());
279			goto exit_tmpfile;
280		}
281		ws = __la_win_permissive_name_w(temp_name.s);
282		if (ws == NULL) {
283			errno = EINVAL;
284			goto exit_tmpfile;
285		}
286		attr = GetFileAttributesW(ws);
287		if (attr == (DWORD)-1) {
288			la_dosmaperr(GetLastError());
289			goto exit_tmpfile;
290		}
291	}
292	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
293		errno = ENOTDIR;
294		goto exit_tmpfile;
295	}
296
297	/*
298	 * Create a temporary file.
299	 */
300	archive_wstrcat(&temp_name, prefix);
301	archive_wstrcat(&temp_name, suffix);
302	ep = temp_name.s + archive_strlen(&temp_name);
303	xp = ep - wcslen(suffix);
304
305	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
306		CRYPT_VERIFYCONTEXT)) {
307		la_dosmaperr(GetLastError());
308		goto exit_tmpfile;
309	}
310
311	for (;;) {
312		wchar_t *p;
313		HANDLE h;
314
315		/* Generate a random file name through CryptGenRandom(). */
316		p = xp;
317		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
318		    (BYTE*)p)) {
319			la_dosmaperr(GetLastError());
320			goto exit_tmpfile;
321		}
322		for (; p < ep; p++)
323			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
324
325		free(ws);
326		ws = __la_win_permissive_name_w(temp_name.s);
327		if (ws == NULL) {
328			errno = EINVAL;
329			goto exit_tmpfile;
330		}
331		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
332		 * delete this temporary file immediately when this
333		 * file closed. */
334		h = CreateFileW(ws,
335		    GENERIC_READ | GENERIC_WRITE | DELETE,
336		    0,/* Not share */
337		    NULL,
338		    CREATE_NEW,/* Create a new file only */
339		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
340		    NULL);
341		if (h == INVALID_HANDLE_VALUE) {
342			/* The same file already exists. retry with
343			 * a new filename. */
344			if (GetLastError() == ERROR_FILE_EXISTS)
345				continue;
346			/* Otherwise, fail creation temporary file. */
347			la_dosmaperr(GetLastError());
348			goto exit_tmpfile;
349		}
350		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
351		if (fd == -1) {
352			CloseHandle(h);
353			goto exit_tmpfile;
354		} else
355			break;/* success! */
356	}
357exit_tmpfile:
358	if (hProv != (HCRYPTPROV)NULL)
359		CryptReleaseContext(hProv, 0);
360	free(ws);
361	archive_wstring_free(&temp_name);
362	return (fd);
363}
364
365#else
366
367static int
368get_tempdir(struct archive_string *temppath)
369{
370	const char *tmp;
371
372	tmp = getenv("TMPDIR");
373	if (tmp == NULL)
374#ifdef _PATH_TMP
375		tmp = _PATH_TMP;
376#else
377                tmp = "/tmp";
378#endif
379	archive_strcpy(temppath, tmp);
380	if (temppath->s[temppath->length-1] != '/')
381		archive_strappend_char(temppath, '/');
382	return (ARCHIVE_OK);
383}
384
385#if defined(HAVE_MKSTEMP)
386
387/*
388 * We can use mkstemp().
389 */
390
391int
392__archive_mktemp(const char *tmpdir)
393{
394	struct archive_string temp_name;
395	int fd = -1;
396
397	archive_string_init(&temp_name);
398	if (tmpdir == NULL) {
399		if (get_tempdir(&temp_name) != ARCHIVE_OK)
400			goto exit_tmpfile;
401	} else {
402		archive_strcpy(&temp_name, tmpdir);
403		if (temp_name.s[temp_name.length-1] != '/')
404			archive_strappend_char(&temp_name, '/');
405	}
406	archive_strcat(&temp_name, "libarchive_XXXXXX");
407	fd = mkstemp(temp_name.s);
408	if (fd < 0)
409		goto exit_tmpfile;
410	__archive_ensure_cloexec_flag(fd);
411	unlink(temp_name.s);
412exit_tmpfile:
413	archive_string_free(&temp_name);
414	return (fd);
415}
416
417#else
418
419/*
420 * We use a private routine.
421 */
422
423int
424__archive_mktemp(const char *tmpdir)
425{
426        static const char num[] = {
427		'0', '1', '2', '3', '4', '5', '6', '7',
428		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
429		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
430		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
431		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
432		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
433		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
434		'u', 'v', 'w', 'x', 'y', 'z'
435        };
436	struct archive_string temp_name;
437	struct stat st;
438	int fd;
439	char *tp, *ep;
440
441	fd = -1;
442	archive_string_init(&temp_name);
443	if (tmpdir == NULL) {
444		if (get_tempdir(&temp_name) != ARCHIVE_OK)
445			goto exit_tmpfile;
446	} else
447		archive_strcpy(&temp_name, tmpdir);
448	if (temp_name.s[temp_name.length-1] == '/') {
449		temp_name.s[temp_name.length-1] = '\0';
450		temp_name.length --;
451	}
452	if (stat(temp_name.s, &st) < 0)
453		goto exit_tmpfile;
454	if (!S_ISDIR(st.st_mode)) {
455		errno = ENOTDIR;
456		goto exit_tmpfile;
457	}
458	archive_strcat(&temp_name, "/libarchive_");
459	tp = temp_name.s + archive_strlen(&temp_name);
460	archive_strcat(&temp_name, "XXXXXXXXXX");
461	ep = temp_name.s + archive_strlen(&temp_name);
462
463	do {
464		char *p;
465
466		p = tp;
467		archive_random(p, ep - p);
468		while (p < ep) {
469			int d = *((unsigned char *)p) % sizeof(num);
470			*p++ = num[d];
471		}
472		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
473			  0600);
474	} while (fd < 0 && errno == EEXIST);
475	if (fd < 0)
476		goto exit_tmpfile;
477	__archive_ensure_cloexec_flag(fd);
478	unlink(temp_name.s);
479exit_tmpfile:
480	archive_string_free(&temp_name);
481	return (fd);
482}
483
484#endif /* HAVE_MKSTEMP */
485#endif /* !_WIN32 || __CYGWIN__ */
486
487/*
488 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
489 * We have to set the flag if the platform does not provide O_CLOEXEC
490 * or F_DUPFD_CLOEXEC flags.
491 *
492 * Note: This function is absolutely called after creating a new file
493 * descriptor even if the platform seemingly provides O_CLOEXEC or
494 * F_DUPFD_CLOEXEC macros because it is possible that the platform
495 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
496 */
497void
498__archive_ensure_cloexec_flag(int fd)
499{
500#if defined(_WIN32) && !defined(__CYGWIN__)
501	(void)fd; /* UNUSED */
502#else
503	int flags;
504
505	if (fd >= 0) {
506		flags = fcntl(fd, F_GETFD);
507		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
508			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
509	}
510#endif
511}
512
513/*
514 * Utility function to sort a group of strings using quicksort.
515 */
516static int
517archive_utility_string_sort_helper(char **strings, unsigned int n)
518{
519	unsigned int i, lesser_count, greater_count;
520	char **lesser, **greater, **tmp, *pivot;
521	int retval1, retval2;
522
523	/* A list of 0 or 1 elements is already sorted */
524	if (n <= 1)
525		return (ARCHIVE_OK);
526
527	lesser_count = greater_count = 0;
528	lesser = greater = NULL;
529	pivot = strings[0];
530	for (i = 1; i < n; i++)
531	{
532		if (strcmp(strings[i], pivot) < 0)
533		{
534			lesser_count++;
535			tmp = (char **)realloc(lesser,
536				lesser_count * sizeof(char *));
537			if (!tmp) {
538				free(greater);
539				free(lesser);
540				return (ARCHIVE_FATAL);
541			}
542			lesser = tmp;
543			lesser[lesser_count - 1] = strings[i];
544		}
545		else
546		{
547			greater_count++;
548			tmp = (char **)realloc(greater,
549				greater_count * sizeof(char *));
550			if (!tmp) {
551				free(greater);
552				free(lesser);
553				return (ARCHIVE_FATAL);
554			}
555			greater = tmp;
556			greater[greater_count - 1] = strings[i];
557		}
558	}
559
560	/* quicksort(lesser) */
561	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
562	for (i = 0; i < lesser_count; i++)
563		strings[i] = lesser[i];
564	free(lesser);
565
566	/* pivot */
567	strings[lesser_count] = pivot;
568
569	/* quicksort(greater) */
570	retval2 = archive_utility_string_sort_helper(greater, greater_count);
571	for (i = 0; i < greater_count; i++)
572		strings[lesser_count + 1 + i] = greater[i];
573	free(greater);
574
575	return (retval1 < retval2) ? retval1 : retval2;
576}
577
578int
579archive_utility_string_sort(char **strings)
580{
581	  unsigned int size = 0;
582	  while (strings[size] != NULL)
583		size++;
584	  return archive_utility_string_sort_helper(strings, size);
585}
586