]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_util.c
MFC r299529,r299540,r299576,r299896:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_util.c
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 const char *
93 archive_version_details(void)
94 {
95         static struct archive_string str;
96         static int init = 0;
97         const char *zlib = archive_zlib_version();
98         const char *liblzma = archive_liblzma_version();
99         const char *bzlib = archive_bzlib_version();
100         const char *liblz4 = archive_liblz4_version();
101
102         if (!init) {
103                 archive_string_init(&str);
104
105                 archive_strcat(&str, ARCHIVE_VERSION_STRING);
106                 if (zlib != NULL) {
107                         archive_strcat(&str, " zlib/");
108                         archive_strcat(&str, zlib);
109                 }
110                 if (liblzma) {
111                         archive_strcat(&str, " liblzma/");
112                         archive_strcat(&str, liblzma);
113                 }
114                 if (bzlib) {
115                         const char *p = bzlib;
116                         const char *sep = strchr(p, ',');
117                         if (sep == NULL)
118                                 sep = p + strlen(p);
119                         archive_strcat(&str, " bz2lib/");
120                         archive_strncat(&str, p, sep - p);
121                 }
122                 if (liblz4) {
123                         archive_strcat(&str, " liblz4/");
124                         archive_strcat(&str, liblz4);
125                 }
126         }
127         return str.s;
128 }
129
130 const char *
131 archive_zlib_version(void)
132 {
133 #ifdef HAVE_ZLIB_H
134         return ZLIB_VERSION;
135 #else
136         return NULL;
137 #endif
138 }
139
140 const char *
141 archive_liblzma_version(void)
142 {
143 #ifdef HAVE_LZMA_H
144         return LZMA_VERSION_STRING;
145 #else
146         return NULL;
147 #endif
148 }
149
150 const char *
151 archive_bzlib_version(void)
152 {
153 #ifdef HAVE_BZLIB_H
154         return BZ2_bzlibVersion();
155 #else
156         return NULL;
157 #endif
158 }
159
160 const char *
161 archive_liblz4_version(void)
162 {
163 #if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
164 #define str(s) #s
165 #define NUMBER(x) str(x)
166         return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
167 #undef NUMBER
168 #undef str
169 #else
170         return NULL;
171 #endif
172 }
173
174 int
175 archive_errno(struct archive *a)
176 {
177         return (a->archive_error_number);
178 }
179
180 const char *
181 archive_error_string(struct archive *a)
182 {
183
184         if (a->error != NULL  &&  *a->error != '\0')
185                 return (a->error);
186         else
187                 return (NULL);
188 }
189
190 int
191 archive_file_count(struct archive *a)
192 {
193         return (a->file_count);
194 }
195
196 int
197 archive_format(struct archive *a)
198 {
199         return (a->archive_format);
200 }
201
202 const char *
203 archive_format_name(struct archive *a)
204 {
205         return (a->archive_format_name);
206 }
207
208
209 int
210 archive_compression(struct archive *a)
211 {
212         return archive_filter_code(a, 0);
213 }
214
215 const char *
216 archive_compression_name(struct archive *a)
217 {
218         return archive_filter_name(a, 0);
219 }
220
221
222 /*
223  * Return a count of the number of compressed bytes processed.
224  */
225 int64_t
226 archive_position_compressed(struct archive *a)
227 {
228         return archive_filter_bytes(a, -1);
229 }
230
231 /*
232  * Return a count of the number of uncompressed bytes processed.
233  */
234 int64_t
235 archive_position_uncompressed(struct archive *a)
236 {
237         return archive_filter_bytes(a, 0);
238 }
239
240 void
241 archive_clear_error(struct archive *a)
242 {
243         archive_string_empty(&a->error_string);
244         a->error = NULL;
245         a->archive_error_number = 0;
246 }
247
248 void
249 archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
250 {
251         va_list ap;
252
253         a->archive_error_number = error_number;
254         if (fmt == NULL) {
255                 a->error = NULL;
256                 return;
257         }
258
259         archive_string_empty(&(a->error_string));
260         va_start(ap, fmt);
261         archive_string_vsprintf(&(a->error_string), fmt, ap);
262         va_end(ap);
263         a->error = a->error_string.s;
264 }
265
266 void
267 archive_copy_error(struct archive *dest, struct archive *src)
268 {
269         dest->archive_error_number = src->archive_error_number;
270
271         archive_string_copy(&dest->error_string, &src->error_string);
272         dest->error = dest->error_string.s;
273 }
274
275 void
276 __archive_errx(int retvalue, const char *msg)
277 {
278         static const char *msg1 = "Fatal Internal Error in libarchive: ";
279         size_t s;
280
281         s = write(2, msg1, strlen(msg1));
282         (void)s; /* UNUSED */
283         s = write(2, msg, strlen(msg));
284         (void)s; /* UNUSED */
285         s = write(2, "\n", 1);
286         (void)s; /* UNUSED */
287         exit(retvalue);
288 }
289
290 /*
291  * Create a temporary file
292  */
293 #if defined(_WIN32) && !defined(__CYGWIN__)
294
295 /*
296  * Do not use Windows tmpfile() function.
297  * It will make a temporary file under the root directory
298  * and it'll cause permission error if a user who is
299  * non-Administrator creates temporary files.
300  * Also Windows version of mktemp family including _mktemp_s
301  * are not secure.
302  */
303 int
304 __archive_mktemp(const char *tmpdir)
305 {
306         static const wchar_t *prefix = L"libarchive_";
307         static const wchar_t *suffix = L"XXXXXXXXXX";
308         static const wchar_t num[] = {
309                 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
310                 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
311                 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
312                 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
313                 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
314                 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
315                 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
316                 L'u', L'v', L'w', L'x', L'y', L'z'
317         };
318         HCRYPTPROV hProv;
319         struct archive_wstring temp_name;
320         wchar_t *ws;
321         DWORD attr;
322         wchar_t *xp, *ep;
323         int fd;
324
325         hProv = (HCRYPTPROV)NULL;
326         fd = -1;
327         ws = NULL;
328         archive_string_init(&temp_name);
329
330         /* Get a temporary directory. */
331         if (tmpdir == NULL) {
332                 size_t l;
333                 wchar_t *tmp;
334
335                 l = GetTempPathW(0, NULL);
336                 if (l == 0) {
337                         la_dosmaperr(GetLastError());
338                         goto exit_tmpfile;
339                 }
340                 tmp = malloc(l*sizeof(wchar_t));
341                 if (tmp == NULL) {
342                         errno = ENOMEM;
343                         goto exit_tmpfile;
344                 }
345                 GetTempPathW((DWORD)l, tmp);
346                 archive_wstrcpy(&temp_name, tmp);
347                 free(tmp);
348         } else {
349                 if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
350                     strlen(tmpdir)) < 0)
351                         goto exit_tmpfile;
352                 if (temp_name.s[temp_name.length-1] != L'/')
353                         archive_wstrappend_wchar(&temp_name, L'/');
354         }
355
356         /* Check if temp_name is a directory. */
357         attr = GetFileAttributesW(temp_name.s);
358         if (attr == (DWORD)-1) {
359                 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
360                         la_dosmaperr(GetLastError());
361                         goto exit_tmpfile;
362                 }
363                 ws = __la_win_permissive_name_w(temp_name.s);
364                 if (ws == NULL) {
365                         errno = EINVAL;
366                         goto exit_tmpfile;
367                 }
368                 attr = GetFileAttributesW(ws);
369                 if (attr == (DWORD)-1) {
370                         la_dosmaperr(GetLastError());
371                         goto exit_tmpfile;
372                 }
373         }
374         if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
375                 errno = ENOTDIR;
376                 goto exit_tmpfile;
377         }
378
379         /*
380          * Create a temporary file.
381          */
382         archive_wstrcat(&temp_name, prefix);
383         archive_wstrcat(&temp_name, suffix);
384         ep = temp_name.s + archive_strlen(&temp_name);
385         xp = ep - wcslen(suffix);
386
387         if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
388                 CRYPT_VERIFYCONTEXT)) {
389                 la_dosmaperr(GetLastError());
390                 goto exit_tmpfile;
391         }
392
393         for (;;) {
394                 wchar_t *p;
395                 HANDLE h;
396
397                 /* Generate a random file name through CryptGenRandom(). */
398                 p = xp;
399                 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
400                     (BYTE*)p)) {
401                         la_dosmaperr(GetLastError());
402                         goto exit_tmpfile;
403                 }
404                 for (; p < ep; p++)
405                         *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
406
407                 free(ws);
408                 ws = __la_win_permissive_name_w(temp_name.s);
409                 if (ws == NULL) {
410                         errno = EINVAL;
411                         goto exit_tmpfile;
412                 }
413                 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
414                  * delete this temporary file immediately when this
415                  * file closed. */
416                 h = CreateFileW(ws,
417                     GENERIC_READ | GENERIC_WRITE | DELETE,
418                     0,/* Not share */
419                     NULL,
420                     CREATE_NEW,/* Create a new file only */
421                     FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
422                     NULL);
423                 if (h == INVALID_HANDLE_VALUE) {
424                         /* The same file already exists. retry with
425                          * a new filename. */
426                         if (GetLastError() == ERROR_FILE_EXISTS)
427                                 continue;
428                         /* Otherwise, fail creation temporary file. */
429                         la_dosmaperr(GetLastError());
430                         goto exit_tmpfile;
431                 }
432                 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
433                 if (fd == -1) {
434                         CloseHandle(h);
435                         goto exit_tmpfile;
436                 } else
437                         break;/* success! */
438         }
439 exit_tmpfile:
440         if (hProv != (HCRYPTPROV)NULL)
441                 CryptReleaseContext(hProv, 0);
442         free(ws);
443         archive_wstring_free(&temp_name);
444         return (fd);
445 }
446
447 #else
448
449 static int
450 get_tempdir(struct archive_string *temppath)
451 {
452         const char *tmp;
453
454         tmp = getenv("TMPDIR");
455         if (tmp == NULL)
456 #ifdef _PATH_TMP
457                 tmp = _PATH_TMP;
458 #else
459                 tmp = "/tmp";
460 #endif
461         archive_strcpy(temppath, tmp);
462         if (temppath->s[temppath->length-1] != '/')
463                 archive_strappend_char(temppath, '/');
464         return (ARCHIVE_OK);
465 }
466
467 #if defined(HAVE_MKSTEMP)
468
469 /*
470  * We can use mkstemp().
471  */
472
473 int
474 __archive_mktemp(const char *tmpdir)
475 {
476         struct archive_string temp_name;
477         int fd = -1;
478
479         archive_string_init(&temp_name);
480         if (tmpdir == NULL) {
481                 if (get_tempdir(&temp_name) != ARCHIVE_OK)
482                         goto exit_tmpfile;
483         } else {
484                 archive_strcpy(&temp_name, tmpdir);
485                 if (temp_name.s[temp_name.length-1] != '/')
486                         archive_strappend_char(&temp_name, '/');
487         }
488         archive_strcat(&temp_name, "libarchive_XXXXXX");
489         fd = mkstemp(temp_name.s);
490         if (fd < 0)
491                 goto exit_tmpfile;
492         __archive_ensure_cloexec_flag(fd);
493         unlink(temp_name.s);
494 exit_tmpfile:
495         archive_string_free(&temp_name);
496         return (fd);
497 }
498
499 #else
500
501 /*
502  * We use a private routine.
503  */
504
505 int
506 __archive_mktemp(const char *tmpdir)
507 {
508         static const char num[] = {
509                 '0', '1', '2', '3', '4', '5', '6', '7',
510                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
511                 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
512                 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
513                 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
514                 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
515                 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
516                 'u', 'v', 'w', 'x', 'y', 'z'
517         };
518         struct archive_string temp_name;
519         struct stat st;
520         int fd;
521         char *tp, *ep;
522
523         fd = -1;
524         archive_string_init(&temp_name);
525         if (tmpdir == NULL) {
526                 if (get_tempdir(&temp_name) != ARCHIVE_OK)
527                         goto exit_tmpfile;
528         } else
529                 archive_strcpy(&temp_name, tmpdir);
530         if (temp_name.s[temp_name.length-1] == '/') {
531                 temp_name.s[temp_name.length-1] = '\0';
532                 temp_name.length --;
533         }
534         if (stat(temp_name.s, &st) < 0)
535                 goto exit_tmpfile;
536         if (!S_ISDIR(st.st_mode)) {
537                 errno = ENOTDIR;
538                 goto exit_tmpfile;
539         }
540         archive_strcat(&temp_name, "/libarchive_");
541         tp = temp_name.s + archive_strlen(&temp_name);
542         archive_strcat(&temp_name, "XXXXXXXXXX");
543         ep = temp_name.s + archive_strlen(&temp_name);
544
545         do {
546                 char *p;
547
548                 p = tp;
549                 archive_random(p, ep - p);
550                 while (p < ep) {
551                         int d = *((unsigned char *)p) % sizeof(num);
552                         *p++ = num[d];
553                 }
554                 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
555                           0600);
556         } while (fd < 0 && errno == EEXIST);
557         if (fd < 0)
558                 goto exit_tmpfile;
559         __archive_ensure_cloexec_flag(fd);
560         unlink(temp_name.s);
561 exit_tmpfile:
562         archive_string_free(&temp_name);
563         return (fd);
564 }
565
566 #endif /* HAVE_MKSTEMP */
567 #endif /* !_WIN32 || __CYGWIN__ */
568
569 /*
570  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
571  * We have to set the flag if the platform does not provide O_CLOEXEC
572  * or F_DUPFD_CLOEXEC flags.
573  *
574  * Note: This function is absolutely called after creating a new file
575  * descriptor even if the platform seemingly provides O_CLOEXEC or
576  * F_DUPFD_CLOEXEC macros because it is possible that the platform
577  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
578  */
579 void
580 __archive_ensure_cloexec_flag(int fd)
581 {
582 #if defined(_WIN32) && !defined(__CYGWIN__)
583         (void)fd; /* UNSED */
584 #else
585         int flags;
586
587         if (fd >= 0) {
588                 flags = fcntl(fd, F_GETFD);
589                 if (flags != -1 && (flags & FD_CLOEXEC) == 0)
590                         fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
591         }
592 #endif
593 }
594
595 /*
596  * Utility function to sort a group of strings using quicksort.
597  */
598 static int
599 archive_utility_string_sort_helper(char **strings, unsigned int n)
600 {
601         unsigned int i, lesser_count, greater_count;
602         char **lesser, **greater, **tmp, *pivot;
603         int retval1, retval2;
604
605         /* A list of 0 or 1 elements is already sorted */
606         if (n <= 1)
607                 return (ARCHIVE_OK);
608
609         lesser_count = greater_count = 0;
610         lesser = greater = NULL;
611         pivot = strings[0];
612         for (i = 1; i < n; i++)
613         {
614                 if (strcmp(strings[i], pivot) < 0)
615                 {
616                         lesser_count++;
617                         tmp = (char **)realloc(lesser,
618                                 lesser_count * sizeof(char *));
619                         if (!tmp) {
620                                 free(greater);
621                                 free(lesser);
622                                 return (ARCHIVE_FATAL);
623                         }
624                         lesser = tmp;
625                         lesser[lesser_count - 1] = strings[i];
626                 }
627                 else
628                 {
629                         greater_count++;
630                         tmp = (char **)realloc(greater,
631                                 greater_count * sizeof(char *));
632                         if (!tmp) {
633                                 free(greater);
634                                 free(lesser);
635                                 return (ARCHIVE_FATAL);
636                         }
637                         greater = tmp;
638                         greater[greater_count - 1] = strings[i];
639                 }
640         }
641
642         /* quicksort(lesser) */
643         retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
644         for (i = 0; i < lesser_count; i++)
645                 strings[i] = lesser[i];
646         free(lesser);
647
648         /* pivot */
649         strings[lesser_count] = pivot;
650
651         /* quicksort(greater) */
652         retval2 = archive_utility_string_sort_helper(greater, greater_count);
653         for (i = 0; i < greater_count; i++)
654                 strings[lesser_count + 1 + i] = greater[i];
655         free(greater);
656
657         return (retval1 < retval2) ? retval1 : retval2;
658 }
659
660 int
661 archive_utility_string_sort(char **strings)
662 {
663           unsigned int size = 0;
664           while (strings[size] != NULL)
665                 size++;
666           return archive_utility_string_sort_helper(strings, size);
667 }