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 archive_wstring_append_from_mbs(&temp_name, tmpdir,
248 if (temp_name.s[temp_name.length-1] != L'/')
249 archive_wstrappend_wchar(&temp_name, L'/');
252 /* Check if temp_name is a directory. */
253 attr = GetFileAttributesW(temp_name.s);
254 if (attr == (DWORD)-1) {
255 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
256 la_dosmaperr(GetLastError());
259 ws = __la_win_permissive_name_w(temp_name.s);
264 attr = GetFileAttributesW(ws);
265 if (attr == (DWORD)-1) {
266 la_dosmaperr(GetLastError());
270 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
276 * Create a temporary file.
278 archive_wstrcat(&temp_name, L"libarchive_");
279 xp = temp_name.s + archive_strlen(&temp_name);
280 archive_wstrcat(&temp_name, L"XXXXXXXXXX");
281 ep = temp_name.s + archive_strlen(&temp_name);
283 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
284 CRYPT_VERIFYCONTEXT)) {
285 la_dosmaperr(GetLastError());
293 /* Generate a random file name through CryptGenRandom(). */
295 if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) {
296 la_dosmaperr(GetLastError());
300 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
303 ws = __la_win_permissive_name_w(temp_name.s);
308 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
309 * delete this temporary file immediately when this
312 GENERIC_READ | GENERIC_WRITE | DELETE,
315 CREATE_NEW,/* Create a new file only */
316 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
318 if (h == INVALID_HANDLE_VALUE) {
319 /* The same file already exists. retry with
321 if (GetLastError() == ERROR_FILE_EXISTS)
323 /* Otherwise, fail creation temporary file. */
324 la_dosmaperr(GetLastError());
327 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
335 if (hProv != (HCRYPTPROV)NULL)
336 CryptReleaseContext(hProv, 0);
338 archive_wstring_free(&temp_name);
345 get_tempdir(struct archive_string *temppath)
349 tmp = getenv("TMPDIR");
356 archive_strcpy(temppath, tmp);
357 if (temppath->s[temppath->length-1] != '/')
358 archive_strappend_char(temppath, '/');
362 #if defined(HAVE_MKSTEMP)
365 * We can use mkstemp().
369 __archive_mktemp(const char *tmpdir)
371 struct archive_string temp_name;
374 archive_string_init(&temp_name);
375 if (tmpdir == NULL) {
376 if (get_tempdir(&temp_name) != ARCHIVE_OK)
379 archive_strcpy(&temp_name, tmpdir);
380 if (temp_name.s[temp_name.length-1] != '/')
381 archive_strappend_char(&temp_name, '/');
383 archive_strcat(&temp_name, "libarchive_XXXXXX");
384 fd = mkstemp(temp_name.s);
389 archive_string_free(&temp_name);
396 * We use a private routine.
400 __archive_mktemp(const char *tmpdir)
402 static const char num[] = {
403 '0', '1', '2', '3', '4', '5', '6', '7',
404 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
405 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
406 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
407 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
408 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
409 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
410 'u', 'v', 'w', 'x', 'y', 'z'
412 struct archive_string temp_name;
419 archive_string_init(&temp_name);
420 if (tmpdir == NULL) {
421 if (get_tempdir(&temp_name) != ARCHIVE_OK)
424 archive_strcpy(&temp_name, tmpdir);
425 if (temp_name.s[temp_name.length-1] == '/') {
426 temp_name.s[temp_name.length-1] = '\0';
429 if (stat(temp_name.s, &st) < 0)
431 if (!S_ISDIR(st.st_mode)) {
435 archive_strcat(&temp_name, "/libarchive_");
436 tp = temp_name.s + archive_strlen(&temp_name);
437 archive_strcat(&temp_name, "XXXXXXXXXX");
438 ep = temp_name.s + archive_strlen(&temp_name);
440 fd = open("/dev/random", O_RDONLY);
444 if (read(fd, &seed, sizeof(seed)) < 0)
453 *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
454 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
455 } while (fd < 0 && errno == EEXIST);
460 archive_string_free(&temp_name);
464 #endif /* HAVE_MKSTEMP */
465 #endif /* !_WIN32 || __CYGWIN__ */