2 * Copyright (c) 2009-2012 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__)
50 #include "archive_private.h"
51 #include "archive_string.h"
57 /* Generic initialization of 'struct archive' objects. */
59 __archive_clean(struct archive *a)
61 archive_string_conversion_free(a);
66 archive_version_number(void)
68 return (ARCHIVE_VERSION_NUMBER);
72 archive_version_string(void)
74 return (ARCHIVE_VERSION_STRING);
78 archive_errno(struct archive *a)
80 return (a->archive_error_number);
84 archive_error_string(struct archive *a)
87 if (a->error != NULL && *a->error != '\0')
94 archive_file_count(struct archive *a)
96 return (a->file_count);
100 archive_format(struct archive *a)
102 return (a->archive_format);
106 archive_format_name(struct archive *a)
108 return (a->archive_format_name);
113 archive_compression(struct archive *a)
115 return archive_filter_code(a, 0);
119 archive_compression_name(struct archive *a)
121 return archive_filter_name(a, 0);
126 * Return a count of the number of compressed bytes processed.
129 archive_position_compressed(struct archive *a)
131 return archive_filter_bytes(a, -1);
135 * Return a count of the number of uncompressed bytes processed.
138 archive_position_uncompressed(struct archive *a)
140 return archive_filter_bytes(a, 0);
144 archive_clear_error(struct archive *a)
146 archive_string_empty(&a->error_string);
148 a->archive_error_number = 0;
152 archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
156 a->archive_error_number = error_number;
162 archive_string_empty(&(a->error_string));
164 archive_string_vsprintf(&(a->error_string), fmt, ap);
166 a->error = a->error_string.s;
170 archive_copy_error(struct archive *dest, struct archive *src)
172 dest->archive_error_number = src->archive_error_number;
174 archive_string_copy(&dest->error_string, &src->error_string);
175 dest->error = dest->error_string.s;
179 __archive_errx(int retvalue, const char *msg)
181 static const char *msg1 = "Fatal Internal Error in libarchive: ";
184 s = write(2, msg1, strlen(msg1));
185 (void)s; /* UNUSED */
186 s = write(2, msg, strlen(msg));
187 (void)s; /* UNUSED */
188 s = write(2, "\n", 1);
189 (void)s; /* UNUSED */
194 * Create a temporary file
196 #if defined(_WIN32) && !defined(__CYGWIN__)
199 * Do not use Windows tmpfile() function.
200 * It will make a temporary file under the root directory
201 * and it'll cause permission error if a user who is
202 * non-Administrator creates temporary files.
203 * Also Windows version of mktemp family including _mktemp_s
207 __archive_mktemp(const char *tmpdir)
209 static const wchar_t num[] = {
210 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
211 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
212 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
213 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
214 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
215 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
216 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
217 L'u', L'v', L'w', L'x', L'y', L'z'
220 struct archive_wstring temp_name;
226 hProv = (HCRYPTPROV)NULL;
229 archive_string_init(&temp_name);
231 /* Get a temporary directory. */
232 if (tmpdir == NULL) {
236 l = GetTempPathW(0, NULL);
238 la_dosmaperr(GetLastError());
241 tmp = malloc(l*sizeof(wchar_t));
246 GetTempPathW((DWORD)l, tmp);
247 archive_wstrcpy(&temp_name, tmp);
250 if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
253 if (temp_name.s[temp_name.length-1] != L'/')
254 archive_wstrappend_wchar(&temp_name, L'/');
257 /* Check if temp_name is a directory. */
258 attr = GetFileAttributesW(temp_name.s);
259 if (attr == (DWORD)-1) {
260 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
261 la_dosmaperr(GetLastError());
264 ws = __la_win_permissive_name_w(temp_name.s);
269 attr = GetFileAttributesW(ws);
270 if (attr == (DWORD)-1) {
271 la_dosmaperr(GetLastError());
275 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
281 * Create a temporary file.
283 archive_wstrcat(&temp_name, L"libarchive_");
284 xp = temp_name.s + archive_strlen(&temp_name);
285 archive_wstrcat(&temp_name, L"XXXXXXXXXX");
286 ep = temp_name.s + archive_strlen(&temp_name);
288 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
289 CRYPT_VERIFYCONTEXT)) {
290 la_dosmaperr(GetLastError());
298 /* Generate a random file name through CryptGenRandom(). */
300 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
302 la_dosmaperr(GetLastError());
306 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
309 ws = __la_win_permissive_name_w(temp_name.s);
314 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
315 * delete this temporary file immediately when this
318 GENERIC_READ | GENERIC_WRITE | DELETE,
321 CREATE_NEW,/* Create a new file only */
322 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
324 if (h == INVALID_HANDLE_VALUE) {
325 /* The same file already exists. retry with
327 if (GetLastError() == ERROR_FILE_EXISTS)
329 /* Otherwise, fail creation temporary file. */
330 la_dosmaperr(GetLastError());
333 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
341 if (hProv != (HCRYPTPROV)NULL)
342 CryptReleaseContext(hProv, 0);
344 archive_wstring_free(&temp_name);
351 get_tempdir(struct archive_string *temppath)
355 tmp = getenv("TMPDIR");
362 archive_strcpy(temppath, tmp);
363 if (temppath->s[temppath->length-1] != '/')
364 archive_strappend_char(temppath, '/');
368 #if defined(HAVE_MKSTEMP)
371 * We can use mkstemp().
375 __archive_mktemp(const char *tmpdir)
377 struct archive_string temp_name;
380 archive_string_init(&temp_name);
381 if (tmpdir == NULL) {
382 if (get_tempdir(&temp_name) != ARCHIVE_OK)
385 archive_strcpy(&temp_name, tmpdir);
386 if (temp_name.s[temp_name.length-1] != '/')
387 archive_strappend_char(&temp_name, '/');
389 archive_strcat(&temp_name, "libarchive_XXXXXX");
390 fd = mkstemp(temp_name.s);
393 __archive_ensure_cloexec_flag(fd);
396 archive_string_free(&temp_name);
403 * We use a private routine.
407 __archive_mktemp(const char *tmpdir)
409 static const char num[] = {
410 '0', '1', '2', '3', '4', '5', '6', '7',
411 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
412 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
413 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
414 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
415 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
416 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
417 'u', 'v', 'w', 'x', 'y', 'z'
419 struct archive_string temp_name;
426 archive_string_init(&temp_name);
427 if (tmpdir == NULL) {
428 if (get_tempdir(&temp_name) != ARCHIVE_OK)
431 archive_strcpy(&temp_name, tmpdir);
432 if (temp_name.s[temp_name.length-1] == '/') {
433 temp_name.s[temp_name.length-1] = '\0';
436 if (stat(temp_name.s, &st) < 0)
438 if (!S_ISDIR(st.st_mode)) {
442 archive_strcat(&temp_name, "/libarchive_");
443 tp = temp_name.s + archive_strlen(&temp_name);
444 archive_strcat(&temp_name, "XXXXXXXXXX");
445 ep = temp_name.s + archive_strlen(&temp_name);
447 fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
448 __archive_ensure_cloexec_flag(fd);
452 if (read(fd, &seed, sizeof(seed)) < 0)
461 *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
462 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
464 } while (fd < 0 && errno == EEXIST);
467 __archive_ensure_cloexec_flag(fd);
470 archive_string_free(&temp_name);
474 #endif /* HAVE_MKSTEMP */
475 #endif /* !_WIN32 || __CYGWIN__ */
478 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
479 * We have to set the flag if the platform does not provide O_CLOEXEC
480 * or F_DUPFD_CLOEXEC flags.
482 * Note: This function is absolutely called after creating a new file
483 * descriptor even if the platform seemingly provides O_CLOEXEC or
484 * F_DUPFD_CLOEXEC macros because it is possible that the platform
485 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
488 __archive_ensure_cloexec_flag(int fd)
490 #if defined(_WIN32) && !defined(__CYGWIN__)
491 (void)fd; /* UNSED */
496 flags = fcntl(fd, F_GETFD);
497 if (flags != -1 && (flags & FD_CLOEXEC) == 0)
498 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);