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