xref: /freebsd/contrib/libarchive/libarchive/archive_util.c (revision d3d381b2b194b4d24853e92eecef55f262688d1a)
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 int
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 	}
357 exit_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 
367 static int
368 get_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 
391 int
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);
412 exit_tmpfile:
413 	archive_string_free(&temp_name);
414 	return (fd);
415 }
416 
417 #else
418 
419 /*
420  * We use a private routine.
421  */
422 
423 int
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);
479 exit_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  */
497 void
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  */
516 static int
517 archive_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 
578 int
579 archive_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