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: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
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_mktempx(const char *tmpdir
, wchar_t *template)
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
;
247 if (template == NULL
) {
248 archive_string_init(&temp_name
);
250 /* Get a temporary directory. */
251 if (tmpdir
== NULL
) {
255 l
= GetTempPathW(0, NULL
);
257 la_dosmaperr(GetLastError());
260 tmp
= malloc(l
*sizeof(wchar_t));
265 GetTempPathW((DWORD
)l
, tmp
);
266 archive_wstrcpy(&temp_name
, tmp
);
269 if (archive_wstring_append_from_mbs(&temp_name
, tmpdir
,
272 if (temp_name
.s
[temp_name
.length
-1] != L
'/')
273 archive_wstrappend_wchar(&temp_name
, L
'/');
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());
283 ws
= __la_win_permissive_name_w(temp_name
.s
);
288 attr
= GetFileAttributesW(ws
);
289 if (attr
== (DWORD
)-1) {
290 la_dosmaperr(GetLastError());
294 if (!(attr
& FILE_ATTRIBUTE_DIRECTORY
)) {
300 * Create a temporary file.
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
;
308 xp
= wcschr(template, L
'X');
309 if (xp
== NULL
) /* No X, programming error */
311 for (ep
= xp
; *ep
== L
'X'; ep
++)
313 if (*ep
) /* X followed by non X, programming error */
317 if (!CryptAcquireContext(&hProv
, NULL
, NULL
, PROV_RSA_FULL
,
318 CRYPT_VERIFYCONTEXT
)) {
319 la_dosmaperr(GetLastError());
326 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
327 CREATEFILE2_EXTENDED_PARAMETERS createExParams
;
330 /* Generate a random file name through CryptGenRandom(). */
332 if (!CryptGenRandom(hProv
, (DWORD
)(ep
- p
)*sizeof(wchar_t),
334 la_dosmaperr(GetLastError());
338 *p
= num
[((DWORD
)*p
) % (sizeof(num
)/sizeof(num
[0]))];
341 ws
= __la_win_permissive_name_w(template);
346 if (template == temp_name
.s
) {
347 attr
= FILE_ATTRIBUTE_TEMPORARY
|
348 FILE_FLAG_DELETE_ON_CLOSE
;
351 attr
= FILE_ATTRIBUTE_NORMAL
;
353 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
354 ZeroMemory(&createExParams
, sizeof(createExParams
));
355 createExParams
.dwSize
= sizeof(createExParams
);
356 createExParams
.dwFileAttributes
= attr
& 0xFFFF;
357 createExParams
.dwFileFlags
= attr
& 0xFFF00000;
359 GENERIC_READ
| GENERIC_WRITE
| DELETE
,
365 GENERIC_READ
| GENERIC_WRITE
| DELETE
,
368 CREATE_NEW
,/* Create a new file only */
372 if (h
== INVALID_HANDLE_VALUE
) {
373 /* The same file already exists. retry with
375 if (GetLastError() == ERROR_FILE_EXISTS
)
377 /* Otherwise, fail creation temporary file. */
378 la_dosmaperr(GetLastError());
381 fd
= _open_osfhandle((intptr_t)h
, _O_BINARY
| _O_RDWR
);
383 la_dosmaperr(GetLastError());
390 if (hProv
!= (HCRYPTPROV
)NULL
)
391 CryptReleaseContext(hProv
, 0);
393 if (template == temp_name
.s
)
394 archive_wstring_free(&temp_name
);
399 __archive_mktemp(const char *tmpdir
)
401 return __archive_mktempx(tmpdir
, NULL
);
405 __archive_mkstemp(wchar_t *template)
407 return __archive_mktempx(NULL
, template);
413 get_tempdir(struct archive_string
*temppath
)
417 tmp
= getenv("TMPDIR");
424 archive_strcpy(temppath
, tmp
);
425 if (temppath
->s
[temppath
->length
-1] != '/')
426 archive_strappend_char(temppath
, '/');
430 #if defined(HAVE_MKSTEMP)
433 * We can use mkstemp().
437 __archive_mktemp(const char *tmpdir
)
439 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 archive_strappend_char(&temp_name
, '/');
452 fd
= open(temp_name
.s
, O_RDWR
|O_CLOEXEC
|O_TMPFILE
|O_EXCL
, 0600);
456 archive_strcat(&temp_name
, "libarchive_XXXXXX");
457 fd
= mkstemp(temp_name
.s
);
460 __archive_ensure_cloexec_flag(fd
);
463 archive_string_free(&temp_name
);
468 __archive_mkstemp(char *template)
471 fd
= mkstemp(template);
473 __archive_ensure_cloexec_flag(fd
);
477 #else /* !HAVE_MKSTEMP */
480 * We use a private routine.
484 __archive_mktempx(const char *tmpdir
, char *template)
486 static const char num
[] = {
487 '0', '1', '2', '3', '4', '5', '6', '7',
488 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
489 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
490 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
491 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
492 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
493 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
494 'u', 'v', 'w', 'x', 'y', 'z'
496 struct archive_string temp_name
;
502 if (template == NULL
) {
503 archive_string_init(&temp_name
);
504 if (tmpdir
== NULL
) {
505 if (get_tempdir(&temp_name
) != ARCHIVE_OK
)
508 archive_strcpy(&temp_name
, tmpdir
);
509 if (temp_name
.s
[temp_name
.length
-1] == '/') {
510 temp_name
.s
[temp_name
.length
-1] = '\0';
513 if (la_stat(temp_name
.s
, &st
) < 0)
515 if (!S_ISDIR(st
.st_mode
)) {
519 archive_strcat(&temp_name
, "/libarchive_");
520 tp
= temp_name
.s
+ archive_strlen(&temp_name
);
521 archive_strcat(&temp_name
, "XXXXXXXXXX");
522 ep
= temp_name
.s
+ archive_strlen(&temp_name
);
523 template = temp_name
.s
;
525 tp
= strchr(template, 'X');
526 if (tp
== NULL
) /* No X, programming error */
528 for (ep
= tp
; *ep
== 'X'; ep
++)
530 if (*ep
) /* X followed by non X, programming error */
538 archive_random(p
, ep
- p
);
540 int d
= *((unsigned char *)p
) % sizeof(num
);
543 fd
= open(template, O_CREAT
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
545 } while (fd
< 0 && errno
== EEXIST
);
548 __archive_ensure_cloexec_flag(fd
);
549 if (template == temp_name
.s
)
552 if (template == temp_name
.s
)
553 archive_string_free(&temp_name
);
558 __archive_mktemp(const char *tmpdir
)
560 return __archive_mktempx(tmpdir
, NULL
);
564 __archive_mkstemp(char *template)
566 return __archive_mktempx(NULL
, template);
569 #endif /* !HAVE_MKSTEMP */
570 #endif /* !_WIN32 || __CYGWIN__ */
573 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
574 * We have to set the flag if the platform does not provide O_CLOEXEC
575 * or F_DUPFD_CLOEXEC flags.
577 * Note: This function is absolutely called after creating a new file
578 * descriptor even if the platform seemingly provides O_CLOEXEC or
579 * F_DUPFD_CLOEXEC macros because it is possible that the platform
580 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
583 __archive_ensure_cloexec_flag(int fd
)
585 #if defined(_WIN32) && !defined(__CYGWIN__)
586 (void)fd
; /* UNUSED */
591 flags
= fcntl(fd
, F_GETFD
);
592 if (flags
!= -1 && (flags
& FD_CLOEXEC
) == 0)
593 fcntl(fd
, F_SETFD
, flags
| FD_CLOEXEC
);
599 * Utility function to sort a group of strings using quicksort.
602 archive_utility_string_sort_helper(char **strings
, unsigned int n
)
604 unsigned int i
, lesser_count
, greater_count
;
605 char **lesser
, **greater
, **tmp
, *pivot
;
606 int retval1
, retval2
;
608 /* A list of 0 or 1 elements is already sorted */
612 lesser_count
= greater_count
= 0;
613 lesser
= greater
= NULL
;
615 for (i
= 1; i
< n
; i
++)
617 if (strcmp(strings
[i
], pivot
) < 0)
620 tmp
= (char **)realloc(lesser
,
621 lesser_count
* sizeof(char *));
625 return (ARCHIVE_FATAL
);
628 lesser
[lesser_count
- 1] = strings
[i
];
633 tmp
= (char **)realloc(greater
,
634 greater_count
* sizeof(char *));
638 return (ARCHIVE_FATAL
);
641 greater
[greater_count
- 1] = strings
[i
];
645 /* quicksort(lesser) */
646 retval1
= archive_utility_string_sort_helper(lesser
, lesser_count
);
647 for (i
= 0; i
< lesser_count
; i
++)
648 strings
[i
] = lesser
[i
];
652 strings
[lesser_count
] = pivot
;
654 /* quicksort(greater) */
655 retval2
= archive_utility_string_sort_helper(greater
, greater_count
);
656 for (i
= 0; i
< greater_count
; i
++)
657 strings
[lesser_count
+ 1 + i
] = greater
[i
];
660 return (retval1
< retval2
) ? retval1
: retval2
;
664 archive_utility_string_sort(char **strings
)
666 unsigned int size
= 0;
667 while (strings
[size
] != NULL
)
669 return archive_utility_string_sort_helper(strings
, size
);