1228753Smm/*-
2248616Smm * Copyright (c) 2009-2012 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$");
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
53248616Smm#ifndef O_CLOEXEC
54248616Smm#define O_CLOEXEC	0
55248616Smm#endif
56248616Smm
57232153Smm/* Generic initialization of 'struct archive' objects. */
58228753Smmint
59232153Smm__archive_clean(struct archive *a)
60228753Smm{
61232153Smm	archive_string_conversion_free(a);
62232153Smm	return (ARCHIVE_OK);
63228753Smm}
64228753Smm
65228753Smmint
66228753Smmarchive_version_number(void)
67228753Smm{
68228753Smm	return (ARCHIVE_VERSION_NUMBER);
69228753Smm}
70228753Smm
71228753Smmconst char *
72228753Smmarchive_version_string(void)
73228753Smm{
74228753Smm	return (ARCHIVE_VERSION_STRING);
75228753Smm}
76228753Smm
77228753Smmint
78228753Smmarchive_errno(struct archive *a)
79228753Smm{
80228753Smm	return (a->archive_error_number);
81228753Smm}
82228753Smm
83228753Smmconst char *
84228753Smmarchive_error_string(struct archive *a)
85228753Smm{
86228753Smm
87228753Smm	if (a->error != NULL  &&  *a->error != '\0')
88228753Smm		return (a->error);
89228753Smm	else
90232153Smm		return (NULL);
91228753Smm}
92228753Smm
93228753Smmint
94228753Smmarchive_file_count(struct archive *a)
95228753Smm{
96228753Smm	return (a->file_count);
97228753Smm}
98228753Smm
99228753Smmint
100228753Smmarchive_format(struct archive *a)
101228753Smm{
102228753Smm	return (a->archive_format);
103228753Smm}
104228753Smm
105228753Smmconst char *
106228753Smmarchive_format_name(struct archive *a)
107228753Smm{
108228753Smm	return (a->archive_format_name);
109228753Smm}
110228753Smm
111228753Smm
112228753Smmint
113228753Smmarchive_compression(struct archive *a)
114228753Smm{
115232153Smm	return archive_filter_code(a, 0);
116228753Smm}
117228753Smm
118228753Smmconst char *
119228753Smmarchive_compression_name(struct archive *a)
120228753Smm{
121232153Smm	return archive_filter_name(a, 0);
122228753Smm}
123228753Smm
124228753Smm
125228753Smm/*
126228753Smm * Return a count of the number of compressed bytes processed.
127228753Smm */
128228753Smmint64_t
129228753Smmarchive_position_compressed(struct archive *a)
130228753Smm{
131232153Smm	return archive_filter_bytes(a, -1);
132228753Smm}
133228753Smm
134228753Smm/*
135228753Smm * Return a count of the number of uncompressed bytes processed.
136228753Smm */
137228753Smmint64_t
138228753Smmarchive_position_uncompressed(struct archive *a)
139228753Smm{
140232153Smm	return archive_filter_bytes(a, 0);
141228753Smm}
142228753Smm
143228753Smmvoid
144228753Smmarchive_clear_error(struct archive *a)
145228753Smm{
146228753Smm	archive_string_empty(&a->error_string);
147228753Smm	a->error = NULL;
148228753Smm	a->archive_error_number = 0;
149228753Smm}
150228753Smm
151228753Smmvoid
152228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...)
153228753Smm{
154228753Smm	va_list ap;
155228753Smm
156228753Smm	a->archive_error_number = error_number;
157228753Smm	if (fmt == NULL) {
158228753Smm		a->error = NULL;
159228753Smm		return;
160228753Smm	}
161228753Smm
162232153Smm	archive_string_empty(&(a->error_string));
163228753Smm	va_start(ap, fmt);
164228753Smm	archive_string_vsprintf(&(a->error_string), fmt, ap);
165228753Smm	va_end(ap);
166228753Smm	a->error = a->error_string.s;
167228753Smm}
168228753Smm
169228753Smmvoid
170228753Smmarchive_copy_error(struct archive *dest, struct archive *src)
171228753Smm{
172228753Smm	dest->archive_error_number = src->archive_error_number;
173228753Smm
174228753Smm	archive_string_copy(&dest->error_string, &src->error_string);
175228753Smm	dest->error = dest->error_string.s;
176228753Smm}
177228753Smm
178228753Smmvoid
179228753Smm__archive_errx(int retvalue, const char *msg)
180228753Smm{
181228753Smm	static const char *msg1 = "Fatal Internal Error in libarchive: ";
182228753Smm	size_t s;
183228753Smm
184228753Smm	s = write(2, msg1, strlen(msg1));
185228753Smm	(void)s; /* UNUSED */
186228753Smm	s = write(2, msg, strlen(msg));
187228753Smm	(void)s; /* UNUSED */
188228753Smm	s = write(2, "\n", 1);
189228753Smm	(void)s; /* UNUSED */
190228753Smm	exit(retvalue);
191228753Smm}
192228753Smm
193228753Smm/*
194232153Smm * Create a temporary file
195228753Smm */
196232153Smm#if defined(_WIN32) && !defined(__CYGWIN__)
197232153Smm
198232153Smm/*
199232153Smm * Do not use Windows tmpfile() function.
200232153Smm * It will make a temporary file under the root directory
201232153Smm * and it'll cause permission error if a user who is
202232153Smm * non-Administrator creates temporary files.
203232153Smm * Also Windows version of mktemp family including _mktemp_s
204232153Smm * are not secure.
205232153Smm */
206228753Smmint
207232153Smm__archive_mktemp(const char *tmpdir)
208228753Smm{
209232153Smm	static const wchar_t num[] = {
210232153Smm		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
211232153Smm		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
212232153Smm		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
213232153Smm		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
214232153Smm		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
215232153Smm		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
216232153Smm		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
217232153Smm		L'u', L'v', L'w', L'x', L'y', L'z'
218232153Smm	};
219232153Smm	HCRYPTPROV hProv;
220232153Smm	struct archive_wstring temp_name;
221232153Smm	wchar_t *ws;
222232153Smm	DWORD attr;
223232153Smm	wchar_t *xp, *ep;
224232153Smm	int fd;
225228753Smm
226232153Smm	hProv = (HCRYPTPROV)NULL;
227232153Smm	fd = -1;
228232153Smm	ws = NULL;
229232153Smm	archive_string_init(&temp_name);
230232153Smm
231232153Smm	/* Get a temporary directory. */
232232153Smm	if (tmpdir == NULL) {
233232153Smm		size_t l;
234232153Smm		wchar_t *tmp;
235232153Smm
236232153Smm		l = GetTempPathW(0, NULL);
237232153Smm		if (l == 0) {
238232153Smm			la_dosmaperr(GetLastError());
239232153Smm			goto exit_tmpfile;
240232153Smm		}
241232153Smm		tmp = malloc(l*sizeof(wchar_t));
242232153Smm		if (tmp == NULL) {
243232153Smm			errno = ENOMEM;
244232153Smm			goto exit_tmpfile;
245232153Smm		}
246248616Smm		GetTempPathW((DWORD)l, tmp);
247232153Smm		archive_wstrcpy(&temp_name, tmp);
248232153Smm		free(tmp);
249232153Smm	} else {
250238856Smm		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
251238856Smm		    strlen(tmpdir)) < 0)
252238856Smm			goto exit_tmpfile;
253232153Smm		if (temp_name.s[temp_name.length-1] != L'/')
254232153Smm			archive_wstrappend_wchar(&temp_name, L'/');
255228753Smm	}
256228753Smm
257232153Smm	/* Check if temp_name is a directory. */
258232153Smm	attr = GetFileAttributesW(temp_name.s);
259232153Smm	if (attr == (DWORD)-1) {
260232153Smm		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
261232153Smm			la_dosmaperr(GetLastError());
262232153Smm			goto exit_tmpfile;
263228753Smm		}
264232153Smm		ws = __la_win_permissive_name_w(temp_name.s);
265232153Smm		if (ws == NULL) {
266232153Smm			errno = EINVAL;
267232153Smm			goto exit_tmpfile;
268232153Smm		}
269232153Smm		attr = GetFileAttributesW(ws);
270232153Smm		if (attr == (DWORD)-1) {
271232153Smm			la_dosmaperr(GetLastError());
272232153Smm			goto exit_tmpfile;
273232153Smm		}
274228753Smm	}
275232153Smm	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
276232153Smm		errno = ENOTDIR;
277232153Smm		goto exit_tmpfile;
278232153Smm	}
279228753Smm
280232153Smm	/*
281232153Smm	 * Create a temporary file.
282232153Smm	 */
283232153Smm	archive_wstrcat(&temp_name, L"libarchive_");
284232153Smm	xp = temp_name.s + archive_strlen(&temp_name);
285232153Smm	archive_wstrcat(&temp_name, L"XXXXXXXXXX");
286232153Smm	ep = temp_name.s + archive_strlen(&temp_name);
287228753Smm
288232153Smm	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
289232153Smm		CRYPT_VERIFYCONTEXT)) {
290232153Smm		la_dosmaperr(GetLastError());
291232153Smm		goto exit_tmpfile;
292232153Smm	}
293232153Smm
294232153Smm	for (;;) {
295232153Smm		wchar_t *p;
296232153Smm		HANDLE h;
297232153Smm
298232153Smm		/* Generate a random file name through CryptGenRandom(). */
299232153Smm		p = xp;
300248616Smm		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
301248616Smm		    (BYTE*)p)) {
302232153Smm			la_dosmaperr(GetLastError());
303232153Smm			goto exit_tmpfile;
304232153Smm		}
305232153Smm		for (; p < ep; p++)
306232153Smm			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
307232153Smm
308232153Smm		free(ws);
309232153Smm		ws = __la_win_permissive_name_w(temp_name.s);
310232153Smm		if (ws == NULL) {
311232153Smm			errno = EINVAL;
312232153Smm			goto exit_tmpfile;
313232153Smm		}
314232153Smm		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
315232153Smm		 * delete this temporary file immediately when this
316232153Smm		 * file closed. */
317232153Smm		h = CreateFileW(ws,
318232153Smm		    GENERIC_READ | GENERIC_WRITE | DELETE,
319232153Smm		    0,/* Not share */
320232153Smm		    NULL,
321232153Smm		    CREATE_NEW,/* Create a new file only */
322232153Smm		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
323232153Smm		    NULL);
324232153Smm		if (h == INVALID_HANDLE_VALUE) {
325232153Smm			/* The same file already exists. retry with
326232153Smm			 * a new filename. */
327232153Smm			if (GetLastError() == ERROR_FILE_EXISTS)
328232153Smm				continue;
329232153Smm			/* Otherwise, fail creation temporary file. */
330232153Smm			la_dosmaperr(GetLastError());
331232153Smm			goto exit_tmpfile;
332232153Smm		}
333232153Smm		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
334232153Smm		if (fd == -1) {
335232153Smm			CloseHandle(h);
336232153Smm			goto exit_tmpfile;
337232153Smm		} else
338232153Smm			break;/* success! */
339232153Smm	}
340232153Smmexit_tmpfile:
341232153Smm	if (hProv != (HCRYPTPROV)NULL)
342232153Smm		CryptReleaseContext(hProv, 0);
343232153Smm	free(ws);
344232153Smm	archive_wstring_free(&temp_name);
345232153Smm	return (fd);
346228753Smm}
347232153Smm
348232153Smm#else
349232153Smm
350232153Smmstatic int
351232153Smmget_tempdir(struct archive_string *temppath)
352232153Smm{
353232153Smm	const char *tmp;
354232153Smm
355232153Smm	tmp = getenv("TMPDIR");
356232153Smm	if (tmp == NULL)
357232153Smm#ifdef _PATH_TMP
358232153Smm		tmp = _PATH_TMP;
359232153Smm#else
360232153Smm                tmp = "/tmp";
361232153Smm#endif
362232153Smm	archive_strcpy(temppath, tmp);
363232153Smm	if (temppath->s[temppath->length-1] != '/')
364232153Smm		archive_strappend_char(temppath, '/');
365232153Smm	return (ARCHIVE_OK);
366232153Smm}
367232153Smm
368232153Smm#if defined(HAVE_MKSTEMP)
369232153Smm
370232153Smm/*
371232153Smm * We can use mkstemp().
372232153Smm */
373232153Smm
374232153Smmint
375232153Smm__archive_mktemp(const char *tmpdir)
376232153Smm{
377232153Smm	struct archive_string temp_name;
378232153Smm	int fd = -1;
379232153Smm
380232153Smm	archive_string_init(&temp_name);
381232153Smm	if (tmpdir == NULL) {
382232153Smm		if (get_tempdir(&temp_name) != ARCHIVE_OK)
383232153Smm			goto exit_tmpfile;
384232153Smm	} else {
385232153Smm		archive_strcpy(&temp_name, tmpdir);
386232153Smm		if (temp_name.s[temp_name.length-1] != '/')
387232153Smm			archive_strappend_char(&temp_name, '/');
388232153Smm	}
389232153Smm	archive_strcat(&temp_name, "libarchive_XXXXXX");
390232153Smm	fd = mkstemp(temp_name.s);
391232153Smm	if (fd < 0)
392232153Smm		goto exit_tmpfile;
393248616Smm	__archive_ensure_cloexec_flag(fd);
394232153Smm	unlink(temp_name.s);
395232153Smmexit_tmpfile:
396232153Smm	archive_string_free(&temp_name);
397232153Smm	return (fd);
398232153Smm}
399232153Smm
400232153Smm#else
401232153Smm
402232153Smm/*
403232153Smm * We use a private routine.
404232153Smm */
405232153Smm
406232153Smmint
407232153Smm__archive_mktemp(const char *tmpdir)
408232153Smm{
409232153Smm        static const char num[] = {
410232153Smm		'0', '1', '2', '3', '4', '5', '6', '7',
411232153Smm		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
412232153Smm		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
413232153Smm		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
414232153Smm		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
415232153Smm		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
416232153Smm		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
417232153Smm		'u', 'v', 'w', 'x', 'y', 'z'
418232153Smm        };
419232153Smm	struct archive_string temp_name;
420232153Smm	struct stat st;
421232153Smm	int fd;
422232153Smm	char *tp, *ep;
423232153Smm	unsigned seed;
424232153Smm
425232153Smm	fd = -1;
426232153Smm	archive_string_init(&temp_name);
427232153Smm	if (tmpdir == NULL) {
428232153Smm		if (get_tempdir(&temp_name) != ARCHIVE_OK)
429232153Smm			goto exit_tmpfile;
430232153Smm	} else
431232153Smm		archive_strcpy(&temp_name, tmpdir);
432232153Smm	if (temp_name.s[temp_name.length-1] == '/') {
433232153Smm		temp_name.s[temp_name.length-1] = '\0';
434232153Smm		temp_name.length --;
435232153Smm	}
436232153Smm	if (stat(temp_name.s, &st) < 0)
437232153Smm		goto exit_tmpfile;
438232153Smm	if (!S_ISDIR(st.st_mode)) {
439232153Smm		errno = ENOTDIR;
440232153Smm		goto exit_tmpfile;
441232153Smm	}
442232153Smm	archive_strcat(&temp_name, "/libarchive_");
443232153Smm	tp = temp_name.s + archive_strlen(&temp_name);
444232153Smm	archive_strcat(&temp_name, "XXXXXXXXXX");
445232153Smm	ep = temp_name.s + archive_strlen(&temp_name);
446232153Smm
447248616Smm	fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
448248616Smm	__archive_ensure_cloexec_flag(fd);
449232153Smm	if (fd < 0)
450232153Smm		seed = time(NULL);
451232153Smm	else {
452232153Smm		if (read(fd, &seed, sizeof(seed)) < 0)
453232153Smm			seed = time(NULL);
454232153Smm		close(fd);
455232153Smm	}
456232153Smm	do {
457232153Smm		char *p;
458232153Smm
459232153Smm		p = tp;
460232153Smm		while (p < ep)
461232153Smm			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
462248616Smm		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
463248616Smm			  0600);
464232153Smm	} while (fd < 0 && errno == EEXIST);
465232153Smm	if (fd < 0)
466232153Smm		goto exit_tmpfile;
467248616Smm	__archive_ensure_cloexec_flag(fd);
468232153Smm	unlink(temp_name.s);
469232153Smmexit_tmpfile:
470232153Smm	archive_string_free(&temp_name);
471232153Smm	return (fd);
472232153Smm}
473232153Smm
474232153Smm#endif /* HAVE_MKSTEMP */
475232153Smm#endif /* !_WIN32 || __CYGWIN__ */
476248616Smm
477248616Smm/*
478248616Smm * Set FD_CLOEXEC flag to a file descriptor if it is not set.
479248616Smm * We have to set the flag if the platform does not provide O_CLOEXEC
480248616Smm * or F_DUPFD_CLOEXEC flags.
481248616Smm *
482248616Smm * Note: This function is absolutely called after creating a new file
483248616Smm * descriptor even if the platform seemingly provides O_CLOEXEC or
484248616Smm * F_DUPFD_CLOEXEC macros because it is possible that the platform
485248616Smm * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
486248616Smm */
487248616Smmvoid
488248616Smm__archive_ensure_cloexec_flag(int fd)
489248616Smm{
490248616Smm#if defined(_WIN32) && !defined(__CYGWIN__)
491248616Smm	(void)fd; /* UNSED */
492248616Smm#else
493248616Smm	int flags;
494248616Smm
495248616Smm	if (fd >= 0) {
496248616Smm		flags = fcntl(fd, F_GETFD);
497248616Smm		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
498248616Smm			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
499248616Smm	}
500248616Smm#endif
501248616Smm}
502