2 * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
3 * Copyright (c) 2003-2007 Tim Kientzle
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
45 #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
62 #include "archive_private.h"
63 #include "archive_random_private.h"
64 #include "archive_string.h"
70 static int archive_utility_string_sort_helper(char **, unsigned int);
72 /* Generic initialization of 'struct archive' objects. */
74 __archive_clean(struct archive *a)
76 archive_string_conversion_free(a);
81 archive_version_number(void)
83 return (ARCHIVE_VERSION_NUMBER);
87 archive_version_string(void)
89 return (ARCHIVE_VERSION_STRING);
93 archive_errno(struct archive *a)
95 return (a->archive_error_number);
99 archive_error_string(struct archive *a)
102 if (a->error != NULL && *a->error != '\0')
109 archive_file_count(struct archive *a)
111 return (a->file_count);
115 archive_format(struct archive *a)
117 return (a->archive_format);
121 archive_format_name(struct archive *a)
123 return (a->archive_format_name);
128 archive_compression(struct archive *a)
130 return archive_filter_code(a, 0);
134 archive_compression_name(struct archive *a)
136 return archive_filter_name(a, 0);
141 * Return a count of the number of compressed bytes processed.
144 archive_position_compressed(struct archive *a)
146 return archive_filter_bytes(a, -1);
150 * Return a count of the number of uncompressed bytes processed.
153 archive_position_uncompressed(struct archive *a)
155 return archive_filter_bytes(a, 0);
159 archive_clear_error(struct archive *a)
161 archive_string_empty(&a->error_string);
163 a->archive_error_number = 0;
167 archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
171 a->archive_error_number = error_number;
177 archive_string_empty(&(a->error_string));
179 archive_string_vsprintf(&(a->error_string), fmt, ap);
181 a->error = a->error_string.s;
185 archive_copy_error(struct archive *dest, struct archive *src)
187 dest->archive_error_number = src->archive_error_number;
189 archive_string_copy(&dest->error_string, &src->error_string);
190 dest->error = dest->error_string.s;
194 __archive_errx(int retvalue, const char *msg)
196 static const char msg1[] = "Fatal Internal Error in libarchive: ";
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 */
209 * Create a temporary file
211 #if defined(_WIN32) && !defined(__CYGWIN__)
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
222 __archive_mktemp(const char *tmpdir)
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'
237 struct archive_wstring temp_name;
243 hProv = (HCRYPTPROV)NULL;
246 archive_string_init(&temp_name);
248 /* Get a temporary directory. */
249 if (tmpdir == NULL) {
253 l = GetTempPathW(0, NULL);
255 la_dosmaperr(GetLastError());
258 tmp = malloc(l*sizeof(wchar_t));
263 GetTempPathW((DWORD)l, tmp);
264 archive_wstrcpy(&temp_name, tmp);
267 if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
270 if (temp_name.s[temp_name.length-1] != L'/')
271 archive_wstrappend_wchar(&temp_name, L'/');
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());
281 ws = __la_win_permissive_name_w(temp_name.s);
286 attr = GetFileAttributesW(ws);
287 if (attr == (DWORD)-1) {
288 la_dosmaperr(GetLastError());
292 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
298 * Create a temporary file.
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);
305 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
306 CRYPT_VERIFYCONTEXT)) {
307 la_dosmaperr(GetLastError());
315 /* Generate a random file name through CryptGenRandom(). */
317 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
319 la_dosmaperr(GetLastError());
323 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
326 ws = __la_win_permissive_name_w(temp_name.s);
331 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
332 * delete this temporary file immediately when this
335 GENERIC_READ | GENERIC_WRITE | DELETE,
338 CREATE_NEW,/* Create a new file only */
339 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
341 if (h == INVALID_HANDLE_VALUE) {
342 /* The same file already exists. retry with
344 if (GetLastError() == ERROR_FILE_EXISTS)
346 /* Otherwise, fail creation temporary file. */
347 la_dosmaperr(GetLastError());
350 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
358 if (hProv != (HCRYPTPROV)NULL)
359 CryptReleaseContext(hProv, 0);
361 archive_wstring_free(&temp_name);
368 get_tempdir(struct archive_string *temppath)
372 tmp = getenv("TMPDIR");
379 archive_strcpy(temppath, tmp);
380 if (temppath->s[temppath->length-1] != '/')
381 archive_strappend_char(temppath, '/');
385 #if defined(HAVE_MKSTEMP)
388 * We can use mkstemp().
392 __archive_mktemp(const char *tmpdir)
394 struct archive_string temp_name;
397 archive_string_init(&temp_name);
398 if (tmpdir == NULL) {
399 if (get_tempdir(&temp_name) != ARCHIVE_OK)
402 archive_strcpy(&temp_name, tmpdir);
403 if (temp_name.s[temp_name.length-1] != '/')
404 archive_strappend_char(&temp_name, '/');
406 archive_strcat(&temp_name, "libarchive_XXXXXX");
407 fd = mkstemp(temp_name.s);
410 __archive_ensure_cloexec_flag(fd);
413 archive_string_free(&temp_name);
420 * We use a private routine.
424 __archive_mktemp(const char *tmpdir)
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'
436 struct archive_string temp_name;
442 archive_string_init(&temp_name);
443 if (tmpdir == NULL) {
444 if (get_tempdir(&temp_name) != ARCHIVE_OK)
447 archive_strcpy(&temp_name, tmpdir);
448 if (temp_name.s[temp_name.length-1] == '/') {
449 temp_name.s[temp_name.length-1] = '\0';
452 if (stat(temp_name.s, &st) < 0)
454 if (!S_ISDIR(st.st_mode)) {
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);
467 archive_random(p, ep - p);
469 int d = *((unsigned char *)p) % sizeof(num);
472 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
474 } while (fd < 0 && errno == EEXIST);
477 __archive_ensure_cloexec_flag(fd);
480 archive_string_free(&temp_name);
484 #endif /* HAVE_MKSTEMP */
485 #endif /* !_WIN32 || __CYGWIN__ */
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.
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.
498 __archive_ensure_cloexec_flag(int fd)
500 #if defined(_WIN32) && !defined(__CYGWIN__)
501 (void)fd; /* UNUSED */
506 flags = fcntl(fd, F_GETFD);
507 if (flags != -1 && (flags & FD_CLOEXEC) == 0)
508 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
514 * Utility function to sort a group of strings using quicksort.
517 archive_utility_string_sort_helper(char **strings, unsigned int n)
519 unsigned int i, lesser_count, greater_count;
520 char **lesser, **greater, **tmp, *pivot;
521 int retval1, retval2;
523 /* A list of 0 or 1 elements is already sorted */
527 lesser_count = greater_count = 0;
528 lesser = greater = NULL;
530 for (i = 1; i < n; i++)
532 if (strcmp(strings[i], pivot) < 0)
535 tmp = (char **)realloc(lesser,
536 lesser_count * sizeof(char *));
540 return (ARCHIVE_FATAL);
543 lesser[lesser_count - 1] = strings[i];
548 tmp = (char **)realloc(greater,
549 greater_count * sizeof(char *));
553 return (ARCHIVE_FATAL);
556 greater[greater_count - 1] = strings[i];
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];
567 strings[lesser_count] = pivot;
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];
575 return (retval1 < retval2) ? retval1 : retval2;
579 archive_utility_string_sort(char **strings)
581 unsigned int size = 0;
582 while (strings[size] != NULL)
584 return archive_utility_string_sort_helper(strings, size);