xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision a521f2116473fbd8c09db395518f060a27d02334)
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 int
93 archive_errno(struct archive *a)
94 {
95 	return (a->archive_error_number);
96 }
97 
98 const char *
99 archive_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 
108 int
109 archive_file_count(struct archive *a)
110 {
111 	return (a->file_count);
112 }
113 
114 int
115 archive_format(struct archive *a)
116 {
117 	return (a->archive_format);
118 }
119 
120 const char *
121 archive_format_name(struct archive *a)
122 {
123 	return (a->archive_format_name);
124 }
125 
126 
127 int
128 archive_compression(struct archive *a)
129 {
130 	return archive_filter_code(a, 0);
131 }
132 
133 const char *
134 archive_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  */
143 la_int64_t
144 archive_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  */
152 la_int64_t
153 archive_position_uncompressed(struct archive *a)
154 {
155 	return archive_filter_bytes(a, 0);
156 }
157 
158 void
159 archive_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 
166 void
167 archive_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 
184 void
185 archive_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 
193 void
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  */
221 static int
222 __archive_mktempx(const char *tmpdir, wchar_t *template)
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 
247 	if (template == NULL) {
248 		archive_string_init(&temp_name);
249 
250 		/* Get a temporary directory. */
251 		if (tmpdir == NULL) {
252 			size_t l;
253 			wchar_t *tmp;
254 
255 			l = GetTempPathW(0, NULL);
256 			if (l == 0) {
257 				la_dosmaperr(GetLastError());
258 				goto exit_tmpfile;
259 			}
260 			tmp = malloc(l*sizeof(wchar_t));
261 			if (tmp == NULL) {
262 				errno = ENOMEM;
263 				goto exit_tmpfile;
264 			}
265 			GetTempPathW((DWORD)l, tmp);
266 			archive_wstrcpy(&temp_name, tmp);
267 			free(tmp);
268 		} else {
269 			if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
270 			    strlen(tmpdir)) < 0)
271 				goto exit_tmpfile;
272 			if (temp_name.s[temp_name.length-1] != L'/')
273 				archive_wstrappend_wchar(&temp_name, L'/');
274 		}
275 
276 		/* Check if temp_name is a directory. */
277 		attr = GetFileAttributesW(temp_name.s);
278 		if (attr == (DWORD)-1) {
279 			if (GetLastError() != ERROR_FILE_NOT_FOUND) {
280 				la_dosmaperr(GetLastError());
281 				goto exit_tmpfile;
282 			}
283 			ws = __la_win_permissive_name_w(temp_name.s);
284 			if (ws == NULL) {
285 				errno = EINVAL;
286 				goto exit_tmpfile;
287 			}
288 			attr = GetFileAttributesW(ws);
289 			if (attr == (DWORD)-1) {
290 				la_dosmaperr(GetLastError());
291 				goto exit_tmpfile;
292 			}
293 		}
294 		if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
295 			errno = ENOTDIR;
296 			goto exit_tmpfile;
297 		}
298 
299 		/*
300 		 * Create a temporary file.
301 		 */
302 		archive_wstrcat(&temp_name, prefix);
303 		archive_wstrcat(&temp_name, suffix);
304 		ep = temp_name.s + archive_strlen(&temp_name);
305 		xp = ep - wcslen(suffix);
306 		template = temp_name.s;
307 	} else {
308 		xp = wcschr(template, L'X');
309 		if (xp == NULL)	/* No X, programming error */
310 			abort();
311 		for (ep = xp; *ep == L'X'; ep++)
312 			continue;
313 		if (*ep)	/* X followed by non X, programming error */
314 			abort();
315 	}
316 
317 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
318 		CRYPT_VERIFYCONTEXT)) {
319 		la_dosmaperr(GetLastError());
320 		goto exit_tmpfile;
321 	}
322 
323 	for (;;) {
324 		wchar_t *p;
325 		HANDLE h;
326 
327 		/* Generate a random file name through CryptGenRandom(). */
328 		p = xp;
329 		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
330 		    (BYTE*)p)) {
331 			la_dosmaperr(GetLastError());
332 			goto exit_tmpfile;
333 		}
334 		for (; p < ep; p++)
335 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
336 
337 		free(ws);
338 		ws = __la_win_permissive_name_w(template);
339 		if (ws == NULL) {
340 			errno = EINVAL;
341 			goto exit_tmpfile;
342 		}
343 		if (template == temp_name.s) {
344 			attr = FILE_ATTRIBUTE_TEMPORARY |
345 			       FILE_FLAG_DELETE_ON_CLOSE;
346 		} else {
347 			/* mkstemp */
348 			attr = FILE_ATTRIBUTE_NORMAL;
349 		}
350 		h = CreateFileW(ws,
351 		    GENERIC_READ | GENERIC_WRITE | DELETE,
352 		    0,/* Not share */
353 		    NULL,
354 		    CREATE_NEW,/* Create a new file only */
355 		    attr,
356 		    NULL);
357 		if (h == INVALID_HANDLE_VALUE) {
358 			/* The same file already exists. retry with
359 			 * a new filename. */
360 			if (GetLastError() == ERROR_FILE_EXISTS)
361 				continue;
362 			/* Otherwise, fail creation temporary file. */
363 			la_dosmaperr(GetLastError());
364 			goto exit_tmpfile;
365 		}
366 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
367 		if (fd == -1) {
368 			la_dosmaperr(GetLastError());
369 			CloseHandle(h);
370 			goto exit_tmpfile;
371 		} else
372 			break;/* success! */
373 	}
374 exit_tmpfile:
375 	if (hProv != (HCRYPTPROV)NULL)
376 		CryptReleaseContext(hProv, 0);
377 	free(ws);
378 	if (template == temp_name.s)
379 		archive_wstring_free(&temp_name);
380 	return (fd);
381 }
382 
383 int
384 __archive_mktemp(const char *tmpdir)
385 {
386 	return __archive_mktempx(tmpdir, NULL);
387 }
388 
389 int
390 __archive_mkstemp(wchar_t *template)
391 {
392 	return __archive_mktempx(NULL, template);
393 }
394 
395 #else
396 
397 static int
398 get_tempdir(struct archive_string *temppath)
399 {
400 	const char *tmp;
401 
402 	tmp = getenv("TMPDIR");
403 	if (tmp == NULL)
404 #ifdef _PATH_TMP
405 		tmp = _PATH_TMP;
406 #else
407                 tmp = "/tmp";
408 #endif
409 	archive_strcpy(temppath, tmp);
410 	if (temppath->s[temppath->length-1] != '/')
411 		archive_strappend_char(temppath, '/');
412 	return (ARCHIVE_OK);
413 }
414 
415 #if defined(HAVE_MKSTEMP)
416 
417 /*
418  * We can use mkstemp().
419  */
420 
421 int
422 __archive_mktemp(const char *tmpdir)
423 {
424 	struct archive_string temp_name;
425 	int fd = -1;
426 
427 	archive_string_init(&temp_name);
428 	if (tmpdir == NULL) {
429 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
430 			goto exit_tmpfile;
431 	} else {
432 		archive_strcpy(&temp_name, tmpdir);
433 		if (temp_name.s[temp_name.length-1] != '/')
434 			archive_strappend_char(&temp_name, '/');
435 	}
436 	archive_strcat(&temp_name, "libarchive_XXXXXX");
437 	fd = mkstemp(temp_name.s);
438 	if (fd < 0)
439 		goto exit_tmpfile;
440 	__archive_ensure_cloexec_flag(fd);
441 	unlink(temp_name.s);
442 exit_tmpfile:
443 	archive_string_free(&temp_name);
444 	return (fd);
445 }
446 
447 int
448 __archive_mkstemp(char *template)
449 {
450 	int fd = -1;
451 	fd = mkstemp(template);
452 	if (fd >= 0)
453 		__archive_ensure_cloexec_flag(fd);
454 	return (fd);
455 }
456 
457 #else /* !HAVE_MKSTEMP */
458 
459 /*
460  * We use a private routine.
461  */
462 
463 static int
464 __archive_mktempx(const char *tmpdir, char *template)
465 {
466         static const char num[] = {
467 		'0', '1', '2', '3', '4', '5', '6', '7',
468 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
469 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
470 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
471 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
472 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
473 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
474 		'u', 'v', 'w', 'x', 'y', 'z'
475         };
476 	struct archive_string temp_name;
477 	struct stat st;
478 	int fd;
479 	char *tp, *ep;
480 
481 	fd = -1;
482 	if (template == NULL) {
483 		archive_string_init(&temp_name);
484 		if (tmpdir == NULL) {
485 			if (get_tempdir(&temp_name) != ARCHIVE_OK)
486 				goto exit_tmpfile;
487 		} else
488 			archive_strcpy(&temp_name, tmpdir);
489 		if (temp_name.s[temp_name.length-1] == '/') {
490 			temp_name.s[temp_name.length-1] = '\0';
491 			temp_name.length --;
492 		}
493 		if (la_stat(temp_name.s, &st) < 0)
494 			goto exit_tmpfile;
495 		if (!S_ISDIR(st.st_mode)) {
496 			errno = ENOTDIR;
497 			goto exit_tmpfile;
498 		}
499 		archive_strcat(&temp_name, "/libarchive_");
500 		tp = temp_name.s + archive_strlen(&temp_name);
501 		archive_strcat(&temp_name, "XXXXXXXXXX");
502 		ep = temp_name.s + archive_strlen(&temp_name);
503 		template = temp_name.s;
504 	} else {
505 		tp = strchr(template, 'X');
506 		if (tp == NULL)	/* No X, programming error */
507 			abort();
508 		for (ep = tp; *ep == 'X'; ep++)
509 			continue;
510 		if (*ep)	/* X followed by non X, programming error */
511 			abort();
512 	}
513 
514 	do {
515 		char *p;
516 
517 		p = tp;
518 		archive_random(p, ep - p);
519 		while (p < ep) {
520 			int d = *((unsigned char *)p) % sizeof(num);
521 			*p++ = num[d];
522 		}
523 		fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
524 			  0600);
525 	} while (fd < 0 && errno == EEXIST);
526 	if (fd < 0)
527 		goto exit_tmpfile;
528 	__archive_ensure_cloexec_flag(fd);
529 	if (template == temp_name.s)
530 		unlink(temp_name.s);
531 exit_tmpfile:
532 	if (template == temp_name.s)
533 		archive_string_free(&temp_name);
534 	return (fd);
535 }
536 
537 int
538 __archive_mktemp(const char *tmpdir)
539 {
540 	return __archive_mktempx(tmpdir, NULL);
541 }
542 
543 int
544 __archive_mkstemp(char *template)
545 {
546 	return __archive_mktempx(NULL, template);
547 }
548 
549 #endif /* !HAVE_MKSTEMP */
550 #endif /* !_WIN32 || __CYGWIN__ */
551 
552 /*
553  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
554  * We have to set the flag if the platform does not provide O_CLOEXEC
555  * or F_DUPFD_CLOEXEC flags.
556  *
557  * Note: This function is absolutely called after creating a new file
558  * descriptor even if the platform seemingly provides O_CLOEXEC or
559  * F_DUPFD_CLOEXEC macros because it is possible that the platform
560  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
561  */
562 void
563 __archive_ensure_cloexec_flag(int fd)
564 {
565 #if defined(_WIN32) && !defined(__CYGWIN__)
566 	(void)fd; /* UNUSED */
567 #else
568 	int flags;
569 
570 	if (fd >= 0) {
571 		flags = fcntl(fd, F_GETFD);
572 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
573 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
574 	}
575 #endif
576 }
577 
578 /*
579  * Utility function to sort a group of strings using quicksort.
580  */
581 static int
582 archive_utility_string_sort_helper(char **strings, unsigned int n)
583 {
584 	unsigned int i, lesser_count, greater_count;
585 	char **lesser, **greater, **tmp, *pivot;
586 	int retval1, retval2;
587 
588 	/* A list of 0 or 1 elements is already sorted */
589 	if (n <= 1)
590 		return (ARCHIVE_OK);
591 
592 	lesser_count = greater_count = 0;
593 	lesser = greater = NULL;
594 	pivot = strings[0];
595 	for (i = 1; i < n; i++)
596 	{
597 		if (strcmp(strings[i], pivot) < 0)
598 		{
599 			lesser_count++;
600 			tmp = (char **)realloc(lesser,
601 				lesser_count * sizeof(char *));
602 			if (!tmp) {
603 				free(greater);
604 				free(lesser);
605 				return (ARCHIVE_FATAL);
606 			}
607 			lesser = tmp;
608 			lesser[lesser_count - 1] = strings[i];
609 		}
610 		else
611 		{
612 			greater_count++;
613 			tmp = (char **)realloc(greater,
614 				greater_count * sizeof(char *));
615 			if (!tmp) {
616 				free(greater);
617 				free(lesser);
618 				return (ARCHIVE_FATAL);
619 			}
620 			greater = tmp;
621 			greater[greater_count - 1] = strings[i];
622 		}
623 	}
624 
625 	/* quicksort(lesser) */
626 	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
627 	for (i = 0; i < lesser_count; i++)
628 		strings[i] = lesser[i];
629 	free(lesser);
630 
631 	/* pivot */
632 	strings[lesser_count] = pivot;
633 
634 	/* quicksort(greater) */
635 	retval2 = archive_utility_string_sort_helper(greater, greater_count);
636 	for (i = 0; i < greater_count; i++)
637 		strings[lesser_count + 1 + i] = greater[i];
638 	free(greater);
639 
640 	return (retval1 < retval2) ? retval1 : retval2;
641 }
642 
643 int
644 archive_utility_string_sort(char **strings)
645 {
646 	  unsigned int size = 0;
647 	  while (strings[size] != NULL)
648 		size++;
649 	  return archive_utility_string_sort_helper(strings, size);
650 }
651