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: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
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 <cm3p/zlib.h>
50 #endif
51 #ifdef HAVE_LZMA_H
52 #include <cm3p/lzma.h>
53 #endif
54 #ifdef HAVE_BZLIB_H
55 #include <cm3p/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
__archive_clean(struct archive * a)74 __archive_clean(struct archive *a)
75 {
76 archive_string_conversion_free(a);
77 return (ARCHIVE_OK);
78 }
79
80 int
archive_version_number(void)81 archive_version_number(void)
82 {
83 return (ARCHIVE_VERSION_NUMBER);
84 }
85
86 const char *
archive_version_string(void)87 archive_version_string(void)
88 {
89 return (ARCHIVE_VERSION_STRING);
90 }
91
92 int
archive_errno(struct archive * a)93 archive_errno(struct archive *a)
94 {
95 return (a->archive_error_number);
96 }
97
98 const char *
archive_error_string(struct archive * a)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
archive_file_count(struct archive * a)109 archive_file_count(struct archive *a)
110 {
111 return (a->file_count);
112 }
113
114 int
archive_format(struct archive * a)115 archive_format(struct archive *a)
116 {
117 return (a->archive_format);
118 }
119
120 const char *
archive_format_name(struct archive * a)121 archive_format_name(struct archive *a)
122 {
123 return (a->archive_format_name);
124 }
125
126
127 int
archive_compression(struct archive * a)128 archive_compression(struct archive *a)
129 {
130 return archive_filter_code(a, 0);
131 }
132
133 const char *
archive_compression_name(struct archive * a)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
archive_position_compressed(struct archive * a)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
archive_position_uncompressed(struct archive * a)153 archive_position_uncompressed(struct archive *a)
154 {
155 return archive_filter_bytes(a, 0);
156 }
157
158 void
archive_clear_error(struct archive * a)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
archive_set_error(struct archive * a,int error_number,const char * fmt,...)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
archive_copy_error(struct archive * dest,struct archive * src)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
__archive_errx(int retvalue,const char * msg)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
__archive_mktempx(const char * tmpdir,wchar_t * template)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
__archive_mktemp(const char * tmpdir)384 __archive_mktemp(const char *tmpdir)
385 {
386 return __archive_mktempx(tmpdir, NULL);
387 }
388
389 int
__archive_mkstemp(wchar_t * template)390 __archive_mkstemp(wchar_t *template)
391 {
392 return __archive_mktempx(NULL, template);
393 }
394
395 #else
396
397 static int
get_tempdir(struct archive_string * temppath)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
__archive_mktemp(const char * tmpdir)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 #ifdef O_TMPFILE
437 fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600);
438 if(fd >= 0)
439 goto exit_tmpfile;
440 #endif
441 archive_strcat(&temp_name, "libarchive_XXXXXX");
442 fd = mkstemp(temp_name.s);
443 if (fd < 0)
444 goto exit_tmpfile;
445 __archive_ensure_cloexec_flag(fd);
446 unlink(temp_name.s);
447 exit_tmpfile:
448 archive_string_free(&temp_name);
449 return (fd);
450 }
451
452 int
__archive_mkstemp(char * template)453 __archive_mkstemp(char *template)
454 {
455 int fd = -1;
456 fd = mkstemp(template);
457 if (fd >= 0)
458 __archive_ensure_cloexec_flag(fd);
459 return (fd);
460 }
461
462 #else /* !HAVE_MKSTEMP */
463
464 /*
465 * We use a private routine.
466 */
467
468 static int
__archive_mktempx(const char * tmpdir,char * template)469 __archive_mktempx(const char *tmpdir, char *template)
470 {
471 static const char num[] = {
472 '0', '1', '2', '3', '4', '5', '6', '7',
473 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
474 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
475 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
476 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
477 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
478 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
479 'u', 'v', 'w', 'x', 'y', 'z'
480 };
481 struct archive_string temp_name;
482 struct stat st;
483 int fd;
484 char *tp, *ep;
485
486 fd = -1;
487 if (template == NULL) {
488 archive_string_init(&temp_name);
489 if (tmpdir == NULL) {
490 if (get_tempdir(&temp_name) != ARCHIVE_OK)
491 goto exit_tmpfile;
492 } else
493 archive_strcpy(&temp_name, tmpdir);
494 if (temp_name.s[temp_name.length-1] == '/') {
495 temp_name.s[temp_name.length-1] = '\0';
496 temp_name.length --;
497 }
498 if (la_stat(temp_name.s, &st) < 0)
499 goto exit_tmpfile;
500 if (!S_ISDIR(st.st_mode)) {
501 errno = ENOTDIR;
502 goto exit_tmpfile;
503 }
504 archive_strcat(&temp_name, "/libarchive_");
505 tp = temp_name.s + archive_strlen(&temp_name);
506 archive_strcat(&temp_name, "XXXXXXXXXX");
507 ep = temp_name.s + archive_strlen(&temp_name);
508 template = temp_name.s;
509 } else {
510 tp = strchr(template, 'X');
511 if (tp == NULL) /* No X, programming error */
512 abort();
513 for (ep = tp; *ep == 'X'; ep++)
514 continue;
515 if (*ep) /* X followed by non X, programming error */
516 abort();
517 }
518
519 do {
520 char *p;
521
522 p = tp;
523 archive_random(p, ep - p);
524 while (p < ep) {
525 int d = *((unsigned char *)p) % sizeof(num);
526 *p++ = num[d];
527 }
528 fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
529 0600);
530 } while (fd < 0 && errno == EEXIST);
531 if (fd < 0)
532 goto exit_tmpfile;
533 __archive_ensure_cloexec_flag(fd);
534 if (template == temp_name.s)
535 unlink(temp_name.s);
536 exit_tmpfile:
537 if (template == temp_name.s)
538 archive_string_free(&temp_name);
539 return (fd);
540 }
541
542 int
__archive_mktemp(const char * tmpdir)543 __archive_mktemp(const char *tmpdir)
544 {
545 return __archive_mktempx(tmpdir, NULL);
546 }
547
548 int
__archive_mkstemp(char * template)549 __archive_mkstemp(char *template)
550 {
551 return __archive_mktempx(NULL, template);
552 }
553
554 #endif /* !HAVE_MKSTEMP */
555 #endif /* !_WIN32 || __CYGWIN__ */
556
557 /*
558 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
559 * We have to set the flag if the platform does not provide O_CLOEXEC
560 * or F_DUPFD_CLOEXEC flags.
561 *
562 * Note: This function is absolutely called after creating a new file
563 * descriptor even if the platform seemingly provides O_CLOEXEC or
564 * F_DUPFD_CLOEXEC macros because it is possible that the platform
565 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
566 */
567 void
__archive_ensure_cloexec_flag(int fd)568 __archive_ensure_cloexec_flag(int fd)
569 {
570 #if defined(_WIN32) && !defined(__CYGWIN__)
571 (void)fd; /* UNUSED */
572 #else
573 int flags;
574
575 if (fd >= 0) {
576 flags = fcntl(fd, F_GETFD);
577 if (flags != -1 && (flags & FD_CLOEXEC) == 0)
578 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
579 }
580 #endif
581 }
582
583 /*
584 * Utility function to sort a group of strings using quicksort.
585 */
586 static int
archive_utility_string_sort_helper(char ** strings,unsigned int n)587 archive_utility_string_sort_helper(char **strings, unsigned int n)
588 {
589 unsigned int i, lesser_count, greater_count;
590 char **lesser, **greater, **tmp, *pivot;
591 int retval1, retval2;
592
593 /* A list of 0 or 1 elements is already sorted */
594 if (n <= 1)
595 return (ARCHIVE_OK);
596
597 lesser_count = greater_count = 0;
598 lesser = greater = NULL;
599 pivot = strings[0];
600 for (i = 1; i < n; i++)
601 {
602 if (strcmp(strings[i], pivot) < 0)
603 {
604 lesser_count++;
605 tmp = (char **)realloc(lesser,
606 lesser_count * sizeof(char *));
607 if (!tmp) {
608 free(greater);
609 free(lesser);
610 return (ARCHIVE_FATAL);
611 }
612 lesser = tmp;
613 lesser[lesser_count - 1] = strings[i];
614 }
615 else
616 {
617 greater_count++;
618 tmp = (char **)realloc(greater,
619 greater_count * sizeof(char *));
620 if (!tmp) {
621 free(greater);
622 free(lesser);
623 return (ARCHIVE_FATAL);
624 }
625 greater = tmp;
626 greater[greater_count - 1] = strings[i];
627 }
628 }
629
630 /* quicksort(lesser) */
631 retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
632 for (i = 0; i < lesser_count; i++)
633 strings[i] = lesser[i];
634 free(lesser);
635
636 /* pivot */
637 strings[lesser_count] = pivot;
638
639 /* quicksort(greater) */
640 retval2 = archive_utility_string_sort_helper(greater, greater_count);
641 for (i = 0; i < greater_count; i++)
642 strings[lesser_count + 1 + i] = greater[i];
643 free(greater);
644
645 return (retval1 < retval2) ? retval1 : retval2;
646 }
647
648 int
archive_utility_string_sort(char ** strings)649 archive_utility_string_sort(char **strings)
650 {
651 unsigned int size = 0;
652 while (strings[size] != NULL)
653 size++;
654 return archive_utility_string_sort_helper(strings, size);
655 }
656