archive_util.c revision 238856
1228753Smm/*-
2232153Smm * Copyright (c) 2009,2010 Michihiro NAKAJIMA
3228753Smm * Copyright (c) 2003-2007 Tim Kientzle
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer.
11228753Smm * 2. Redistributions in binary form must reproduce the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer in the
13228753Smm *    documentation and/or other materials provided with the distribution.
14228753Smm *
15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25228753Smm */
26228753Smm
27228753Smm#include "archive_platform.h"
28228763Smm__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_util.c 238856 2012-07-28 06:38:44Z mm $");
29228753Smm
30228753Smm#ifdef HAVE_SYS_TYPES_H
31228753Smm#include <sys/types.h>
32228753Smm#endif
33232153Smm#ifdef HAVE_ERRNO_H
34232153Smm#include <errno.h>
35232153Smm#endif
36232153Smm#ifdef HAVE_FCNTL_H
37232153Smm#include <fcntl.h>
38232153Smm#endif
39228753Smm#ifdef HAVE_STDLIB_H
40228753Smm#include <stdlib.h>
41228753Smm#endif
42228753Smm#ifdef HAVE_STRING_H
43228753Smm#include <string.h>
44228753Smm#endif
45232153Smm#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
46232153Smm#include <wincrypt.h>
47232153Smm#endif
48228753Smm
49228753Smm#include "archive.h"
50228753Smm#include "archive_private.h"
51228753Smm#include "archive_string.h"
52228753Smm
53232153Smm/* Generic initialization of 'struct archive' objects. */
54228753Smmint
55232153Smm__archive_clean(struct archive *a)
56228753Smm{
57232153Smm	archive_string_conversion_free(a);
58232153Smm	return (ARCHIVE_OK);
59228753Smm}
60228753Smm
61228753Smmint
62228753Smmarchive_version_number(void)
63228753Smm{
64228753Smm	return (ARCHIVE_VERSION_NUMBER);
65228753Smm}
66228753Smm
67228753Smmconst char *
68228753Smmarchive_version_string(void)
69228753Smm{
70228753Smm	return (ARCHIVE_VERSION_STRING);
71228753Smm}
72228753Smm
73228753Smmint
74228753Smmarchive_errno(struct archive *a)
75228753Smm{
76228753Smm	return (a->archive_error_number);
77228753Smm}
78228753Smm
79228753Smmconst char *
80228753Smmarchive_error_string(struct archive *a)
81228753Smm{
82228753Smm
83228753Smm	if (a->error != NULL  &&  *a->error != '\0')
84228753Smm		return (a->error);
85228753Smm	else
86232153Smm		return (NULL);
87228753Smm}
88228753Smm
89228753Smmint
90228753Smmarchive_file_count(struct archive *a)
91228753Smm{
92228753Smm	return (a->file_count);
93228753Smm}
94228753Smm
95228753Smmint
96228753Smmarchive_format(struct archive *a)
97228753Smm{
98228753Smm	return (a->archive_format);
99228753Smm}
100228753Smm
101228753Smmconst char *
102228753Smmarchive_format_name(struct archive *a)
103228753Smm{
104228753Smm	return (a->archive_format_name);
105228753Smm}
106228753Smm
107228753Smm
108228753Smmint
109228753Smmarchive_compression(struct archive *a)
110228753Smm{
111232153Smm	return archive_filter_code(a, 0);
112228753Smm}
113228753Smm
114228753Smmconst char *
115228753Smmarchive_compression_name(struct archive *a)
116228753Smm{
117232153Smm	return archive_filter_name(a, 0);
118228753Smm}
119228753Smm
120228753Smm
121228753Smm/*
122228753Smm * Return a count of the number of compressed bytes processed.
123228753Smm */
124228753Smmint64_t
125228753Smmarchive_position_compressed(struct archive *a)
126228753Smm{
127232153Smm	return archive_filter_bytes(a, -1);
128228753Smm}
129228753Smm
130228753Smm/*
131228753Smm * Return a count of the number of uncompressed bytes processed.
132228753Smm */
133228753Smmint64_t
134228753Smmarchive_position_uncompressed(struct archive *a)
135228753Smm{
136232153Smm	return archive_filter_bytes(a, 0);
137228753Smm}
138228753Smm
139228753Smmvoid
140228753Smmarchive_clear_error(struct archive *a)
141228753Smm{
142228753Smm	archive_string_empty(&a->error_string);
143228753Smm	a->error = NULL;
144228753Smm	a->archive_error_number = 0;
145228753Smm}
146228753Smm
147228753Smmvoid
148228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...)
149228753Smm{
150228753Smm	va_list ap;
151228753Smm
152228753Smm	a->archive_error_number = error_number;
153228753Smm	if (fmt == NULL) {
154228753Smm		a->error = NULL;
155228753Smm		return;
156228753Smm	}
157228753Smm
158232153Smm	archive_string_empty(&(a->error_string));
159228753Smm	va_start(ap, fmt);
160228753Smm	archive_string_vsprintf(&(a->error_string), fmt, ap);
161228753Smm	va_end(ap);
162228753Smm	a->error = a->error_string.s;
163228753Smm}
164228753Smm
165228753Smmvoid
166228753Smmarchive_copy_error(struct archive *dest, struct archive *src)
167228753Smm{
168228753Smm	dest->archive_error_number = src->archive_error_number;
169228753Smm
170228753Smm	archive_string_copy(&dest->error_string, &src->error_string);
171228753Smm	dest->error = dest->error_string.s;
172228753Smm}
173228753Smm
174228753Smmvoid
175228753Smm__archive_errx(int retvalue, const char *msg)
176228753Smm{
177228753Smm	static const char *msg1 = "Fatal Internal Error in libarchive: ";
178228753Smm	size_t s;
179228753Smm
180228753Smm	s = write(2, msg1, strlen(msg1));
181228753Smm	(void)s; /* UNUSED */
182228753Smm	s = write(2, msg, strlen(msg));
183228753Smm	(void)s; /* UNUSED */
184228753Smm	s = write(2, "\n", 1);
185228753Smm	(void)s; /* UNUSED */
186228753Smm	exit(retvalue);
187228753Smm}
188228753Smm
189228753Smm/*
190232153Smm * Create a temporary file
191228753Smm */
192232153Smm#if defined(_WIN32) && !defined(__CYGWIN__)
193232153Smm
194232153Smm/*
195232153Smm * Do not use Windows tmpfile() function.
196232153Smm * It will make a temporary file under the root directory
197232153Smm * and it'll cause permission error if a user who is
198232153Smm * non-Administrator creates temporary files.
199232153Smm * Also Windows version of mktemp family including _mktemp_s
200232153Smm * are not secure.
201232153Smm */
202228753Smmint
203232153Smm__archive_mktemp(const char *tmpdir)
204228753Smm{
205232153Smm	static const wchar_t num[] = {
206232153Smm		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
207232153Smm		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
208232153Smm		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
209232153Smm		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
210232153Smm		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
211232153Smm		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
212232153Smm		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
213232153Smm		L'u', L'v', L'w', L'x', L'y', L'z'
214232153Smm	};
215232153Smm	HCRYPTPROV hProv;
216232153Smm	struct archive_wstring temp_name;
217232153Smm	wchar_t *ws;
218232153Smm	DWORD attr;
219232153Smm	wchar_t *xp, *ep;
220232153Smm	int fd;
221228753Smm
222232153Smm	hProv = (HCRYPTPROV)NULL;
223232153Smm	fd = -1;
224232153Smm	ws = NULL;
225232153Smm	archive_string_init(&temp_name);
226232153Smm
227232153Smm	/* Get a temporary directory. */
228232153Smm	if (tmpdir == NULL) {
229232153Smm		size_t l;
230232153Smm		wchar_t *tmp;
231232153Smm
232232153Smm		l = GetTempPathW(0, NULL);
233232153Smm		if (l == 0) {
234232153Smm			la_dosmaperr(GetLastError());
235232153Smm			goto exit_tmpfile;
236232153Smm		}
237232153Smm		tmp = malloc(l*sizeof(wchar_t));
238232153Smm		if (tmp == NULL) {
239232153Smm			errno = ENOMEM;
240232153Smm			goto exit_tmpfile;
241232153Smm		}
242232153Smm		GetTempPathW(l, tmp);
243232153Smm		archive_wstrcpy(&temp_name, tmp);
244232153Smm		free(tmp);
245232153Smm	} else {
246238856Smm		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
247238856Smm		    strlen(tmpdir)) < 0)
248238856Smm			goto exit_tmpfile;
249232153Smm		if (temp_name.s[temp_name.length-1] != L'/')
250232153Smm			archive_wstrappend_wchar(&temp_name, L'/');
251228753Smm	}
252228753Smm
253232153Smm	/* Check if temp_name is a directory. */
254232153Smm	attr = GetFileAttributesW(temp_name.s);
255232153Smm	if (attr == (DWORD)-1) {
256232153Smm		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
257232153Smm			la_dosmaperr(GetLastError());
258232153Smm			goto exit_tmpfile;
259228753Smm		}
260232153Smm		ws = __la_win_permissive_name_w(temp_name.s);
261232153Smm		if (ws == NULL) {
262232153Smm			errno = EINVAL;
263232153Smm			goto exit_tmpfile;
264232153Smm		}
265232153Smm		attr = GetFileAttributesW(ws);
266232153Smm		if (attr == (DWORD)-1) {
267232153Smm			la_dosmaperr(GetLastError());
268232153Smm			goto exit_tmpfile;
269232153Smm		}
270228753Smm	}
271232153Smm	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
272232153Smm		errno = ENOTDIR;
273232153Smm		goto exit_tmpfile;
274232153Smm	}
275228753Smm
276232153Smm	/*
277232153Smm	 * Create a temporary file.
278232153Smm	 */
279232153Smm	archive_wstrcat(&temp_name, L"libarchive_");
280232153Smm	xp = temp_name.s + archive_strlen(&temp_name);
281232153Smm	archive_wstrcat(&temp_name, L"XXXXXXXXXX");
282232153Smm	ep = temp_name.s + archive_strlen(&temp_name);
283228753Smm
284232153Smm	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
285232153Smm		CRYPT_VERIFYCONTEXT)) {
286232153Smm		la_dosmaperr(GetLastError());
287232153Smm		goto exit_tmpfile;
288232153Smm	}
289232153Smm
290232153Smm	for (;;) {
291232153Smm		wchar_t *p;
292232153Smm		HANDLE h;
293232153Smm
294232153Smm		/* Generate a random file name through CryptGenRandom(). */
295232153Smm		p = xp;
296232153Smm		if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) {
297232153Smm			la_dosmaperr(GetLastError());
298232153Smm			goto exit_tmpfile;
299232153Smm		}
300232153Smm		for (; p < ep; p++)
301232153Smm			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
302232153Smm
303232153Smm		free(ws);
304232153Smm		ws = __la_win_permissive_name_w(temp_name.s);
305232153Smm		if (ws == NULL) {
306232153Smm			errno = EINVAL;
307232153Smm			goto exit_tmpfile;
308232153Smm		}
309232153Smm		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
310232153Smm		 * delete this temporary file immediately when this
311232153Smm		 * file closed. */
312232153Smm		h = CreateFileW(ws,
313232153Smm		    GENERIC_READ | GENERIC_WRITE | DELETE,
314232153Smm		    0,/* Not share */
315232153Smm		    NULL,
316232153Smm		    CREATE_NEW,/* Create a new file only */
317232153Smm		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
318232153Smm		    NULL);
319232153Smm		if (h == INVALID_HANDLE_VALUE) {
320232153Smm			/* The same file already exists. retry with
321232153Smm			 * a new filename. */
322232153Smm			if (GetLastError() == ERROR_FILE_EXISTS)
323232153Smm				continue;
324232153Smm			/* Otherwise, fail creation temporary file. */
325232153Smm			la_dosmaperr(GetLastError());
326232153Smm			goto exit_tmpfile;
327232153Smm		}
328232153Smm		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
329232153Smm		if (fd == -1) {
330232153Smm			CloseHandle(h);
331232153Smm			goto exit_tmpfile;
332232153Smm		} else
333232153Smm			break;/* success! */
334232153Smm	}
335232153Smmexit_tmpfile:
336232153Smm	if (hProv != (HCRYPTPROV)NULL)
337232153Smm		CryptReleaseContext(hProv, 0);
338232153Smm	free(ws);
339232153Smm	archive_wstring_free(&temp_name);
340232153Smm	return (fd);
341228753Smm}
342232153Smm
343232153Smm#else
344232153Smm
345232153Smmstatic int
346232153Smmget_tempdir(struct archive_string *temppath)
347232153Smm{
348232153Smm	const char *tmp;
349232153Smm
350232153Smm	tmp = getenv("TMPDIR");
351232153Smm	if (tmp == NULL)
352232153Smm#ifdef _PATH_TMP
353232153Smm		tmp = _PATH_TMP;
354232153Smm#else
355232153Smm                tmp = "/tmp";
356232153Smm#endif
357232153Smm	archive_strcpy(temppath, tmp);
358232153Smm	if (temppath->s[temppath->length-1] != '/')
359232153Smm		archive_strappend_char(temppath, '/');
360232153Smm	return (ARCHIVE_OK);
361232153Smm}
362232153Smm
363232153Smm#if defined(HAVE_MKSTEMP)
364232153Smm
365232153Smm/*
366232153Smm * We can use mkstemp().
367232153Smm */
368232153Smm
369232153Smmint
370232153Smm__archive_mktemp(const char *tmpdir)
371232153Smm{
372232153Smm	struct archive_string temp_name;
373232153Smm	int fd = -1;
374232153Smm
375232153Smm	archive_string_init(&temp_name);
376232153Smm	if (tmpdir == NULL) {
377232153Smm		if (get_tempdir(&temp_name) != ARCHIVE_OK)
378232153Smm			goto exit_tmpfile;
379232153Smm	} else {
380232153Smm		archive_strcpy(&temp_name, tmpdir);
381232153Smm		if (temp_name.s[temp_name.length-1] != '/')
382232153Smm			archive_strappend_char(&temp_name, '/');
383232153Smm	}
384232153Smm	archive_strcat(&temp_name, "libarchive_XXXXXX");
385232153Smm	fd = mkstemp(temp_name.s);
386232153Smm	if (fd < 0)
387232153Smm		goto exit_tmpfile;
388232153Smm	unlink(temp_name.s);
389232153Smmexit_tmpfile:
390232153Smm	archive_string_free(&temp_name);
391232153Smm	return (fd);
392232153Smm}
393232153Smm
394232153Smm#else
395232153Smm
396232153Smm/*
397232153Smm * We use a private routine.
398232153Smm */
399232153Smm
400232153Smmint
401232153Smm__archive_mktemp(const char *tmpdir)
402232153Smm{
403232153Smm        static const char num[] = {
404232153Smm		'0', '1', '2', '3', '4', '5', '6', '7',
405232153Smm		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
406232153Smm		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
407232153Smm		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
408232153Smm		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
409232153Smm		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
410232153Smm		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
411232153Smm		'u', 'v', 'w', 'x', 'y', 'z'
412232153Smm        };
413232153Smm	struct archive_string temp_name;
414232153Smm	struct stat st;
415232153Smm	int fd;
416232153Smm	char *tp, *ep;
417232153Smm	unsigned seed;
418232153Smm
419232153Smm	fd = -1;
420232153Smm	archive_string_init(&temp_name);
421232153Smm	if (tmpdir == NULL) {
422232153Smm		if (get_tempdir(&temp_name) != ARCHIVE_OK)
423232153Smm			goto exit_tmpfile;
424232153Smm	} else
425232153Smm		archive_strcpy(&temp_name, tmpdir);
426232153Smm	if (temp_name.s[temp_name.length-1] == '/') {
427232153Smm		temp_name.s[temp_name.length-1] = '\0';
428232153Smm		temp_name.length --;
429232153Smm	}
430232153Smm	if (stat(temp_name.s, &st) < 0)
431232153Smm		goto exit_tmpfile;
432232153Smm	if (!S_ISDIR(st.st_mode)) {
433232153Smm		errno = ENOTDIR;
434232153Smm		goto exit_tmpfile;
435232153Smm	}
436232153Smm	archive_strcat(&temp_name, "/libarchive_");
437232153Smm	tp = temp_name.s + archive_strlen(&temp_name);
438232153Smm	archive_strcat(&temp_name, "XXXXXXXXXX");
439232153Smm	ep = temp_name.s + archive_strlen(&temp_name);
440232153Smm
441232153Smm	fd = open("/dev/random", O_RDONLY);
442232153Smm	if (fd < 0)
443232153Smm		seed = time(NULL);
444232153Smm	else {
445232153Smm		if (read(fd, &seed, sizeof(seed)) < 0)
446232153Smm			seed = time(NULL);
447232153Smm		close(fd);
448232153Smm	}
449232153Smm	do {
450232153Smm		char *p;
451232153Smm
452232153Smm		p = tp;
453232153Smm		while (p < ep)
454232153Smm			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
455232153Smm		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
456232153Smm	} while (fd < 0 && errno == EEXIST);
457232153Smm	if (fd < 0)
458232153Smm		goto exit_tmpfile;
459232153Smm	unlink(temp_name.s);
460232153Smmexit_tmpfile:
461232153Smm	archive_string_free(&temp_name);
462232153Smm	return (fd);
463232153Smm}
464232153Smm
465232153Smm#endif /* HAVE_MKSTEMP */
466232153Smm#endif /* !_WIN32 || __CYGWIN__ */
467