2 * Copyright (c) 2009,2010 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__)
50 #include "archive_private.h"
51 #include "archive_string.h"
53 /* Generic initialization of 'struct archive' objects. */
55 __archive_clean(struct archive *a)
57 archive_string_conversion_free(a);
62 archive_version_number(void)
64 return (ARCHIVE_VERSION_NUMBER);
68 archive_version_string(void)
70 return (ARCHIVE_VERSION_STRING);
74 archive_errno(struct archive *a)
76 return (a->archive_error_number);
80 archive_error_string(struct archive *a)
83 if (a->error != NULL && *a->error != '\0')
90 archive_file_count(struct archive *a)
92 return (a->file_count);
96 archive_format(struct archive *a)
98 return (a->archive_format);
102 archive_format_name(struct archive *a)
104 return (a->archive_format_name);
109 archive_compression(struct archive *a)
111 return archive_filter_code(a, 0);
115 archive_compression_name(struct archive *a)
117 return archive_filter_name(a, 0);
122 * Return a count of the number of compressed bytes processed.
125 archive_position_compressed(struct archive *a)
127 return archive_filter_bytes(a, -1);
131 * Return a count of the number of uncompressed bytes processed.
134 archive_position_uncompressed(struct archive *a)
136 return archive_filter_bytes(a, 0);
140 archive_clear_error(struct archive *a)
142 archive_string_empty(&a->error_string);
144 a->archive_error_number = 0;
148 archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
152 a->archive_error_number = error_number;
158 archive_string_empty(&(a->error_string));
160 archive_string_vsprintf(&(a->error_string), fmt, ap);
162 a->error = a->error_string.s;
166 archive_copy_error(struct archive *dest, struct archive *src)
168 dest->archive_error_number = src->archive_error_number;
170 archive_string_copy(&dest->error_string, &src->error_string);
171 dest->error = dest->error_string.s;
175 __archive_errx(int retvalue, const char *msg)
177 static const char *msg1 = "Fatal Internal Error in libarchive: ";
180 s = write(2, msg1, strlen(msg1));
181 (void)s; /* UNUSED */
182 s = write(2, msg, strlen(msg));
183 (void)s; /* UNUSED */
184 s = write(2, "\n", 1);
185 (void)s; /* UNUSED */
190 * Create a temporary file
192 #if defined(_WIN32) && !defined(__CYGWIN__)
195 * Do not use Windows tmpfile() function.
196 * It will make a temporary file under the root directory
197 * and it'll cause permission error if a user who is
198 * non-Administrator creates temporary files.
199 * Also Windows version of mktemp family including _mktemp_s
203 __archive_mktemp(const char *tmpdir)
205 static const wchar_t num[] = {
206 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
207 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
208 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
209 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
210 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
211 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
212 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
213 L'u', L'v', L'w', L'x', L'y', L'z'
216 struct archive_wstring temp_name;
222 hProv = (HCRYPTPROV)NULL;
225 archive_string_init(&temp_name);
227 /* Get a temporary directory. */
228 if (tmpdir == NULL) {
232 l = GetTempPathW(0, NULL);
234 la_dosmaperr(GetLastError());
237 tmp = malloc(l*sizeof(wchar_t));
242 GetTempPathW(l, tmp);
243 archive_wstrcpy(&temp_name, tmp);
246 if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
249 if (temp_name.s[temp_name.length-1] != L'/')
250 archive_wstrappend_wchar(&temp_name, L'/');
253 /* Check if temp_name is a directory. */
254 attr = GetFileAttributesW(temp_name.s);
255 if (attr == (DWORD)-1) {
256 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
257 la_dosmaperr(GetLastError());
260 ws = __la_win_permissive_name_w(temp_name.s);
265 attr = GetFileAttributesW(ws);
266 if (attr == (DWORD)-1) {
267 la_dosmaperr(GetLastError());
271 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
277 * Create a temporary file.
279 archive_wstrcat(&temp_name, L"libarchive_");
280 xp = temp_name.s + archive_strlen(&temp_name);
281 archive_wstrcat(&temp_name, L"XXXXXXXXXX");
282 ep = temp_name.s + archive_strlen(&temp_name);
284 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
285 CRYPT_VERIFYCONTEXT)) {
286 la_dosmaperr(GetLastError());
294 /* Generate a random file name through CryptGenRandom(). */
296 if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) {
297 la_dosmaperr(GetLastError());
301 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
304 ws = __la_win_permissive_name_w(temp_name.s);
309 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
310 * delete this temporary file immediately when this
313 GENERIC_READ | GENERIC_WRITE | DELETE,
316 CREATE_NEW,/* Create a new file only */
317 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
319 if (h == INVALID_HANDLE_VALUE) {
320 /* The same file already exists. retry with
322 if (GetLastError() == ERROR_FILE_EXISTS)
324 /* Otherwise, fail creation temporary file. */
325 la_dosmaperr(GetLastError());
328 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
336 if (hProv != (HCRYPTPROV)NULL)
337 CryptReleaseContext(hProv, 0);
339 archive_wstring_free(&temp_name);
346 get_tempdir(struct archive_string *temppath)
350 tmp = getenv("TMPDIR");
357 archive_strcpy(temppath, tmp);
358 if (temppath->s[temppath->length-1] != '/')
359 archive_strappend_char(temppath, '/');
363 #if defined(HAVE_MKSTEMP)
366 * We can use mkstemp().
370 __archive_mktemp(const char *tmpdir)
372 struct archive_string temp_name;
375 archive_string_init(&temp_name);
376 if (tmpdir == NULL) {
377 if (get_tempdir(&temp_name) != ARCHIVE_OK)
380 archive_strcpy(&temp_name, tmpdir);
381 if (temp_name.s[temp_name.length-1] != '/')
382 archive_strappend_char(&temp_name, '/');
384 archive_strcat(&temp_name, "libarchive_XXXXXX");
385 fd = mkstemp(temp_name.s);
390 archive_string_free(&temp_name);
397 * We use a private routine.
401 __archive_mktemp(const char *tmpdir)
403 static const char num[] = {
404 '0', '1', '2', '3', '4', '5', '6', '7',
405 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
406 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
407 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
408 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
409 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
410 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
411 'u', 'v', 'w', 'x', 'y', 'z'
413 struct archive_string temp_name;
420 archive_string_init(&temp_name);
421 if (tmpdir == NULL) {
422 if (get_tempdir(&temp_name) != ARCHIVE_OK)
425 archive_strcpy(&temp_name, tmpdir);
426 if (temp_name.s[temp_name.length-1] == '/') {
427 temp_name.s[temp_name.length-1] = '\0';
430 if (stat(temp_name.s, &st) < 0)
432 if (!S_ISDIR(st.st_mode)) {
436 archive_strcat(&temp_name, "/libarchive_");
437 tp = temp_name.s + archive_strlen(&temp_name);
438 archive_strcat(&temp_name, "XXXXXXXXXX");
439 ep = temp_name.s + archive_strlen(&temp_name);
441 fd = open("/dev/random", O_RDONLY);
445 if (read(fd, &seed, sizeof(seed)) < 0)
454 *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
455 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
456 } while (fd < 0 && errno == EEXIST);
461 archive_string_free(&temp_name);
465 #endif /* HAVE_MKSTEMP */
466 #endif /* !_WIN32 || __CYGWIN__ */