xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision 2f513db72b034fd5ef7f080b11be5c711c15186a)
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 			CloseHandle(h);
369 			goto exit_tmpfile;
370 		} else
371 			break;/* success! */
372 	}
373 exit_tmpfile:
374 	if (hProv != (HCRYPTPROV)NULL)
375 		CryptReleaseContext(hProv, 0);
376 	free(ws);
377 	if (template == temp_name.s)
378 		archive_wstring_free(&temp_name);
379 	return (fd);
380 }
381 
382 int
383 __archive_mktemp(const char *tmpdir)
384 {
385 	return __archive_mktempx(tmpdir, NULL);
386 }
387 
388 int
389 __archive_mkstemp(wchar_t *template)
390 {
391 	return __archive_mktempx(NULL, template);
392 }
393 
394 #else
395 
396 static int
397 get_tempdir(struct archive_string *temppath)
398 {
399 	const char *tmp;
400 
401 	tmp = getenv("TMPDIR");
402 	if (tmp == NULL)
403 #ifdef _PATH_TMP
404 		tmp = _PATH_TMP;
405 #else
406                 tmp = "/tmp";
407 #endif
408 	archive_strcpy(temppath, tmp);
409 	if (temppath->s[temppath->length-1] != '/')
410 		archive_strappend_char(temppath, '/');
411 	return (ARCHIVE_OK);
412 }
413 
414 #if defined(HAVE_MKSTEMP)
415 
416 /*
417  * We can use mkstemp().
418  */
419 
420 int
421 __archive_mktemp(const char *tmpdir)
422 {
423 	struct archive_string temp_name;
424 	int fd = -1;
425 
426 	archive_string_init(&temp_name);
427 	if (tmpdir == NULL) {
428 		if (get_tempdir(&temp_name) != ARCHIVE_OK)
429 			goto exit_tmpfile;
430 	} else {
431 		archive_strcpy(&temp_name, tmpdir);
432 		if (temp_name.s[temp_name.length-1] != '/')
433 			archive_strappend_char(&temp_name, '/');
434 	}
435 	archive_strcat(&temp_name, "libarchive_XXXXXX");
436 	fd = mkstemp(temp_name.s);
437 	if (fd < 0)
438 		goto exit_tmpfile;
439 	__archive_ensure_cloexec_flag(fd);
440 	unlink(temp_name.s);
441 exit_tmpfile:
442 	archive_string_free(&temp_name);
443 	return (fd);
444 }
445 
446 int
447 __archive_mkstemp(char *template)
448 {
449 	int fd = -1;
450 	fd = mkstemp(template);
451 	if (fd >= 0)
452 		__archive_ensure_cloexec_flag(fd);
453 	return (fd);
454 }
455 
456 #else /* !HAVE_MKSTEMP */
457 
458 /*
459  * We use a private routine.
460  */
461 
462 static int
463 __archive_mktempx(const char *tmpdir, char *template)
464 {
465         static const char num[] = {
466 		'0', '1', '2', '3', '4', '5', '6', '7',
467 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
468 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
469 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
470 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
471 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
472 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
473 		'u', 'v', 'w', 'x', 'y', 'z'
474         };
475 	struct archive_string temp_name;
476 	struct stat st;
477 	int fd;
478 	char *tp, *ep;
479 
480 	fd = -1;
481 	if (template == NULL) {
482 		archive_string_init(&temp_name);
483 		if (tmpdir == NULL) {
484 			if (get_tempdir(&temp_name) != ARCHIVE_OK)
485 				goto exit_tmpfile;
486 		} else
487 			archive_strcpy(&temp_name, tmpdir);
488 		if (temp_name.s[temp_name.length-1] == '/') {
489 			temp_name.s[temp_name.length-1] = '\0';
490 			temp_name.length --;
491 		}
492 		if (la_stat(temp_name.s, &st) < 0)
493 			goto exit_tmpfile;
494 		if (!S_ISDIR(st.st_mode)) {
495 			errno = ENOTDIR;
496 			goto exit_tmpfile;
497 		}
498 		archive_strcat(&temp_name, "/libarchive_");
499 		tp = temp_name.s + archive_strlen(&temp_name);
500 		archive_strcat(&temp_name, "XXXXXXXXXX");
501 		ep = temp_name.s + archive_strlen(&temp_name);
502 		template = temp_name.s;
503 	} else {
504 		tp = strchr(template, 'X');
505 		if (tp == NULL)	/* No X, programming error */
506 			abort();
507 		for (ep = tp; *ep == 'X'; ep++)
508 			continue;
509 		if (*ep)	/* X followed by non X, programming error */
510 			abort();
511 	}
512 
513 	do {
514 		char *p;
515 
516 		p = tp;
517 		archive_random(p, ep - p);
518 		while (p < ep) {
519 			int d = *((unsigned char *)p) % sizeof(num);
520 			*p++ = num[d];
521 		}
522 		fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
523 			  0600);
524 	} while (fd < 0 && errno == EEXIST);
525 	if (fd < 0)
526 		goto exit_tmpfile;
527 	__archive_ensure_cloexec_flag(fd);
528 	if (template == temp_name.s)
529 		unlink(temp_name.s);
530 exit_tmpfile:
531 	if (template == temp_name.s)
532 		archive_string_free(&temp_name);
533 	return (fd);
534 }
535 
536 int
537 __archive_mktemp(const char *tmpdir)
538 {
539 	return __archive_mktempx(tmpdir, NULL);
540 }
541 
542 int
543 __archive_mkstemp(char *template)
544 {
545 	return __archive_mktempx(NULL, template);
546 }
547 
548 #endif /* !HAVE_MKSTEMP */
549 #endif /* !_WIN32 || __CYGWIN__ */
550 
551 /*
552  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
553  * We have to set the flag if the platform does not provide O_CLOEXEC
554  * or F_DUPFD_CLOEXEC flags.
555  *
556  * Note: This function is absolutely called after creating a new file
557  * descriptor even if the platform seemingly provides O_CLOEXEC or
558  * F_DUPFD_CLOEXEC macros because it is possible that the platform
559  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
560  */
561 void
562 __archive_ensure_cloexec_flag(int fd)
563 {
564 #if defined(_WIN32) && !defined(__CYGWIN__)
565 	(void)fd; /* UNUSED */
566 #else
567 	int flags;
568 
569 	if (fd >= 0) {
570 		flags = fcntl(fd, F_GETFD);
571 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
572 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
573 	}
574 #endif
575 }
576 
577 /*
578  * Utility function to sort a group of strings using quicksort.
579  */
580 static int
581 archive_utility_string_sort_helper(char **strings, unsigned int n)
582 {
583 	unsigned int i, lesser_count, greater_count;
584 	char **lesser, **greater, **tmp, *pivot;
585 	int retval1, retval2;
586 
587 	/* A list of 0 or 1 elements is already sorted */
588 	if (n <= 1)
589 		return (ARCHIVE_OK);
590 
591 	lesser_count = greater_count = 0;
592 	lesser = greater = NULL;
593 	pivot = strings[0];
594 	for (i = 1; i < n; i++)
595 	{
596 		if (strcmp(strings[i], pivot) < 0)
597 		{
598 			lesser_count++;
599 			tmp = (char **)realloc(lesser,
600 				lesser_count * sizeof(char *));
601 			if (!tmp) {
602 				free(greater);
603 				free(lesser);
604 				return (ARCHIVE_FATAL);
605 			}
606 			lesser = tmp;
607 			lesser[lesser_count - 1] = strings[i];
608 		}
609 		else
610 		{
611 			greater_count++;
612 			tmp = (char **)realloc(greater,
613 				greater_count * sizeof(char *));
614 			if (!tmp) {
615 				free(greater);
616 				free(lesser);
617 				return (ARCHIVE_FATAL);
618 			}
619 			greater = tmp;
620 			greater[greater_count - 1] = strings[i];
621 		}
622 	}
623 
624 	/* quicksort(lesser) */
625 	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
626 	for (i = 0; i < lesser_count; i++)
627 		strings[i] = lesser[i];
628 	free(lesser);
629 
630 	/* pivot */
631 	strings[lesser_count] = pivot;
632 
633 	/* quicksort(greater) */
634 	retval2 = archive_utility_string_sort_helper(greater, greater_count);
635 	for (i = 0; i < greater_count; i++)
636 		strings[lesser_count + 1 + i] = greater[i];
637 	free(greater);
638 
639 	return (retval1 < retval2) ? retval1 : retval2;
640 }
641 
642 int
643 archive_utility_string_sort(char **strings)
644 {
645 	  unsigned int size = 0;
646 	  while (strings[size] != NULL)
647 		size++;
648 	  return archive_utility_string_sort_helper(strings, size);
649 }
650