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