xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision 74d9553e43cfafc29448d0bb836916aa21dea0de)
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$");
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 
70 static int archive_utility_string_sort_helper(char **, unsigned int);
71 
72 /* Generic initialization of 'struct archive' objects. */
73 int
74 __archive_clean(struct archive *a)
75 {
76 	archive_string_conversion_free(a);
77 	return (ARCHIVE_OK);
78 }
79 
80 int
81 archive_version_number(void)
82 {
83 	return (ARCHIVE_VERSION_NUMBER);
84 }
85 
86 const char *
87 archive_version_string(void)
88 {
89 	return (ARCHIVE_VERSION_STRING);
90 }
91 
92 const char *
93 archive_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 
130 const char *
131 archive_zlib_version(void)
132 {
133 #ifdef HAVE_ZLIB_H
134 	return ZLIB_VERSION;
135 #else
136 	return NULL;
137 #endif
138 }
139 
140 const char *
141 archive_liblzma_version(void)
142 {
143 #ifdef HAVE_LZMA_H
144 	return LZMA_VERSION_STRING;
145 #else
146 	return NULL;
147 #endif
148 }
149 
150 const char *
151 archive_bzlib_version(void)
152 {
153 #ifdef HAVE_BZLIB_H
154 	return BZ2_bzlibVersion();
155 #else
156 	return NULL;
157 #endif
158 }
159 
160 const char *
161 archive_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 
174 int
175 archive_errno(struct archive *a)
176 {
177 	return (a->archive_error_number);
178 }
179 
180 const char *
181 archive_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 
190 int
191 archive_file_count(struct archive *a)
192 {
193 	return (a->file_count);
194 }
195 
196 int
197 archive_format(struct archive *a)
198 {
199 	return (a->archive_format);
200 }
201 
202 const char *
203 archive_format_name(struct archive *a)
204 {
205 	return (a->archive_format_name);
206 }
207 
208 
209 int
210 archive_compression(struct archive *a)
211 {
212 	return archive_filter_code(a, 0);
213 }
214 
215 const char *
216 archive_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  */
225 int64_t
226 archive_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  */
234 int64_t
235 archive_position_uncompressed(struct archive *a)
236 {
237 	return archive_filter_bytes(a, 0);
238 }
239 
240 void
241 archive_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 
248 void
249 archive_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 
266 void
267 archive_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 
275 void
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  */
303 int
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 	}
439 exit_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 
449 static int
450 get_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 
473 int
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);
494 exit_tmpfile:
495 	archive_string_free(&temp_name);
496 	return (fd);
497 }
498 
499 #else
500 
501 /*
502  * We use a private routine.
503  */
504 
505 int
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);
561 exit_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  */
579 void
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  */
598 static int
599 archive_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 
660 int
661 archive_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