]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_util.c
MFC r368207,368607:
[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                         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
384 __archive_mktemp(const char *tmpdir)
385 {
386         return __archive_mktempx(tmpdir, NULL);
387 }
388
389 int
390 __archive_mkstemp(wchar_t *template)
391 {
392         return __archive_mktempx(NULL, template);
393 }
394
395 #else
396
397 static int
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
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
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
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
543 __archive_mktemp(const char *tmpdir)
544 {
545         return __archive_mktempx(tmpdir, NULL);
546 }
547
548 int
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
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
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
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 }