]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_util.c
MFC r358533:
[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         archive_strcat(&temp_name, "libarchive_XXXXXX");
437         fd = mkstemp(temp_name.s);
438         if (fd < 0)
439                 goto exit_tmpfile;
440         __archive_ensure_cloexec_flag(fd);
441         unlink(temp_name.s);
442 exit_tmpfile:
443         archive_string_free(&temp_name);
444         return (fd);
445 }
446
447 int
448 __archive_mkstemp(char *template)
449 {
450         int fd = -1;
451         fd = mkstemp(template);
452         if (fd >= 0)
453                 __archive_ensure_cloexec_flag(fd);
454         return (fd);
455 }
456
457 #else /* !HAVE_MKSTEMP */
458
459 /*
460  * We use a private routine.
461  */
462
463 static int
464 __archive_mktempx(const char *tmpdir, char *template)
465 {
466         static const char num[] = {
467                 '0', '1', '2', '3', '4', '5', '6', '7',
468                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
469                 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
470                 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
471                 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
472                 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
473                 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
474                 'u', 'v', 'w', 'x', 'y', 'z'
475         };
476         struct archive_string temp_name;
477         struct stat st;
478         int fd;
479         char *tp, *ep;
480
481         fd = -1;
482         if (template == NULL) {
483                 archive_string_init(&temp_name);
484                 if (tmpdir == NULL) {
485                         if (get_tempdir(&temp_name) != ARCHIVE_OK)
486                                 goto exit_tmpfile;
487                 } else
488                         archive_strcpy(&temp_name, tmpdir);
489                 if (temp_name.s[temp_name.length-1] == '/') {
490                         temp_name.s[temp_name.length-1] = '\0';
491                         temp_name.length --;
492                 }
493                 if (la_stat(temp_name.s, &st) < 0)
494                         goto exit_tmpfile;
495                 if (!S_ISDIR(st.st_mode)) {
496                         errno = ENOTDIR;
497                         goto exit_tmpfile;
498                 }
499                 archive_strcat(&temp_name, "/libarchive_");
500                 tp = temp_name.s + archive_strlen(&temp_name);
501                 archive_strcat(&temp_name, "XXXXXXXXXX");
502                 ep = temp_name.s + archive_strlen(&temp_name);
503                 template = temp_name.s;
504         } else {
505                 tp = strchr(template, 'X');
506                 if (tp == NULL) /* No X, programming error */
507                         abort();
508                 for (ep = tp; *ep == 'X'; ep++)
509                         continue;
510                 if (*ep)        /* X followed by non X, programming error */
511                         abort();
512         }
513
514         do {
515                 char *p;
516
517                 p = tp;
518                 archive_random(p, ep - p);
519                 while (p < ep) {
520                         int d = *((unsigned char *)p) % sizeof(num);
521                         *p++ = num[d];
522                 }
523                 fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
524                           0600);
525         } while (fd < 0 && errno == EEXIST);
526         if (fd < 0)
527                 goto exit_tmpfile;
528         __archive_ensure_cloexec_flag(fd);
529         if (template == temp_name.s)
530                 unlink(temp_name.s);
531 exit_tmpfile:
532         if (template == temp_name.s)
533                 archive_string_free(&temp_name);
534         return (fd);
535 }
536
537 int
538 __archive_mktemp(const char *tmpdir)
539 {
540         return __archive_mktempx(tmpdir, NULL);
541 }
542
543 int
544 __archive_mkstemp(char *template)
545 {
546         return __archive_mktempx(NULL, template);
547 }
548
549 #endif /* !HAVE_MKSTEMP */
550 #endif /* !_WIN32 || __CYGWIN__ */
551
552 /*
553  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
554  * We have to set the flag if the platform does not provide O_CLOEXEC
555  * or F_DUPFD_CLOEXEC flags.
556  *
557  * Note: This function is absolutely called after creating a new file
558  * descriptor even if the platform seemingly provides O_CLOEXEC or
559  * F_DUPFD_CLOEXEC macros because it is possible that the platform
560  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
561  */
562 void
563 __archive_ensure_cloexec_flag(int fd)
564 {
565 #if defined(_WIN32) && !defined(__CYGWIN__)
566         (void)fd; /* UNUSED */
567 #else
568         int flags;
569
570         if (fd >= 0) {
571                 flags = fcntl(fd, F_GETFD);
572                 if (flags != -1 && (flags & FD_CLOEXEC) == 0)
573                         fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
574         }
575 #endif
576 }
577
578 /*
579  * Utility function to sort a group of strings using quicksort.
580  */
581 static int
582 archive_utility_string_sort_helper(char **strings, unsigned int n)
583 {
584         unsigned int i, lesser_count, greater_count;
585         char **lesser, **greater, **tmp, *pivot;
586         int retval1, retval2;
587
588         /* A list of 0 or 1 elements is already sorted */
589         if (n <= 1)
590                 return (ARCHIVE_OK);
591
592         lesser_count = greater_count = 0;
593         lesser = greater = NULL;
594         pivot = strings[0];
595         for (i = 1; i < n; i++)
596         {
597                 if (strcmp(strings[i], pivot) < 0)
598                 {
599                         lesser_count++;
600                         tmp = (char **)realloc(lesser,
601                                 lesser_count * sizeof(char *));
602                         if (!tmp) {
603                                 free(greater);
604                                 free(lesser);
605                                 return (ARCHIVE_FATAL);
606                         }
607                         lesser = tmp;
608                         lesser[lesser_count - 1] = strings[i];
609                 }
610                 else
611                 {
612                         greater_count++;
613                         tmp = (char **)realloc(greater,
614                                 greater_count * sizeof(char *));
615                         if (!tmp) {
616                                 free(greater);
617                                 free(lesser);
618                                 return (ARCHIVE_FATAL);
619                         }
620                         greater = tmp;
621                         greater[greater_count - 1] = strings[i];
622                 }
623         }
624
625         /* quicksort(lesser) */
626         retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
627         for (i = 0; i < lesser_count; i++)
628                 strings[i] = lesser[i];
629         free(lesser);
630
631         /* pivot */
632         strings[lesser_count] = pivot;
633
634         /* quicksort(greater) */
635         retval2 = archive_utility_string_sort_helper(greater, greater_count);
636         for (i = 0; i < greater_count; i++)
637                 strings[lesser_count + 1 + i] = greater[i];
638         free(greater);
639
640         return (retval1 < retval2) ? retval1 : retval2;
641 }
642
643 int
644 archive_utility_string_sort(char **strings)
645 {
646           unsigned int size = 0;
647           while (strings[size] != NULL)
648                 size++;
649           return archive_utility_string_sort_helper(strings, size);
650 }