]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_util.c
MFC r356212,r356366,r356416,r357785
[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 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 }