From: Michihiro NAKAJIMA Date: Thu, 11 Feb 2010 08:28:04 +0000 (-0500) Subject: Introduce a function __archive_mktemp() to create a temporary file, X-Git-Tag: v3.0.0a~1265 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68fb45a134339ca8221f060c21b536993136adf0;p=thirdparty%2Flibarchive.git Introduce a function __archive_mktemp() to create a temporary file, which will be used by ISO writer and xar writer. SVN-Revision: 1895 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1272cd2..9f0e0cf88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -396,6 +396,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(memmove HAVE_MEMMOVE) CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR) CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO) CHECK_FUNCTION_EXISTS_GLIBC(mknod HAVE_MKNOD) +CHECK_FUNCTION_EXISTS_GLIBC(mkstemp HAVE_MKSTEMP) CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO) CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE) CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL) diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index b9ff03fa7..ac9680ada 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -323,6 +323,9 @@ /* Define to 1 if you have the `mknod' function. */ #cmakedefine HAVE_MKNOD 1 +/* Define to 1 if you have the `mkstemp' function. */ +#cmakedefine HAVE_MKSTEMP 1 + /* Define to 1 if you have the header file, and it defines `DIR'. */ #cmakedefine HAVE_NDIR_H 1 diff --git a/configure.ac b/configure.ac index 513c46aaf..45960ad57 100644 --- a/configure.ac +++ b/configure.ac @@ -391,7 +391,7 @@ AC_CHECK_FUNCS([chflags chown chroot]) AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fork]) AC_CHECK_FUNCS([fstat ftruncate futimens futimes geteuid getpid]) AC_CHECK_FUNCS([lchflags lchmod lchown link lstat]) -AC_CHECK_FUNCS([lutimes memmove memset mkdir mkfifo mknod]) +AC_CHECK_FUNCS([lutimes memmove memset mkdir mkfifo mknod mkstemp]) AC_CHECK_FUNCS([nl_langinfo pipe poll readlink]) AC_CHECK_FUNCS([select setenv setlocale sigaction]) AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strrchr symlink timegm]) diff --git a/libarchive/archive_private.h b/libarchive/archive_private.h index fba3d62a2..dc8857a3b 100644 --- a/libarchive/archive_private.h +++ b/libarchive/archive_private.h @@ -111,6 +111,9 @@ void __archive_errx(int retvalue, const char *msg) __LA_DEAD; int __archive_parse_options(const char *p, const char *fn, int keysize, char *key, int valsize, char *val); +int __archive_mktemp(const char *tmpdir); + + #define err_combine(a,b) ((a) < (b) ? (a) : (b)) #if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300) diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c index c945d5fa7..300690602 100644 --- a/libarchive/archive_util.c +++ b/libarchive/archive_util.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Michihiro NAKAJIMA + * Copyright (c) 2009,2010 Michihiro NAKAJIMA * Copyright (c) 2003-2007 Tim Kientzle * All rights reserved. * @@ -30,6 +30,12 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1 #ifdef HAVE_SYS_TYPES_H #include #endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif #ifdef HAVE_STDLIB_H #include #endif @@ -389,3 +395,160 @@ complete: /* Return a size which we've consumed for detecting option */ return ((int)(p - p_org)); } + +/* + * Create a temporary file + */ + +#if defined(HAVE_MKSTEMP) || !defined(HAVE_TMPFILE) + +#if defined(_WIN32) && !defined(__CYGWIN__) + +static int +get_tempdir(struct archive_string *temppath) +{ + size_t l; + char *tmp; + + l = GetTempPathA(0, NULL); + if (l == 0) + return (ARCHIVE_FATAL); + tmp = malloc(l); + if (tmp == NULL) + return (ARCHIVE_FATAL); + GetTempPathA(l, tmp); + archive_strcpy(temppath, tmp); + free(tmp); + return (ARCHIVE_OK); +} + +#else /* _WIN32 && !__CYGWIN__ */ + +static int +get_tempdir(struct archive_string *temppath) +{ + const char *tmp; + + tmp = getenv("TMPDIR"); + if (tmp == NULL) +#ifdef _PATH_TMP + tmp = _PATH_TMP; +#else + tmp = "/tmp"; +#endif + archive_strcpy(temppath, tmp); + if (temppath->s[temppath->length-1] != '/') + archive_strappend_char(temppath, '/'); + return (ARCHIVE_OK); +} + +#endif /* _WIN32 && !__CYGWIN__ */ +#endif /* HAVE_MKSTEMP || !HAVE_TMPFILE */ + +#if defined(HAVE_MKSTEMP) + +/* + * We can use mkstemp(). + */ + +int +__archive_mktemp(const char *tmpdir) +{ + struct archive_string temp_name; + int fd; + + archive_string_init(&temp_name); + if (tmpdir == NULL) { + if (get_tempdir(&temp_name) != ARCHIVE_OK) + goto exit_tmpfile; + } else { + archive_strcpy(&temp_name, tmpdir); + if (temp_name.s[temp_name.length-1] != '/') + archive_strappend_char(&temp_name, '/'); + } + archive_strcat(&temp_name, "libarchive_XXXXXX"); + fd = mkstemp(temp_name.s); + if (fd < 0) + goto exit_tmpfile; +#if !defined(_WIN32) || defined(__CYGWIN__) + /* On Windows, the temporary file will be automatically removed + * when the file is closed */ + unlink(temp_name.s); +#endif +exit_tmpfile: + archive_string_free(&temp_name); + return (fd); +} + +#else + +/* + * We use a private routine. + */ + +int +__archive_mktemp(const char *tmpdir) +{ + static const char num[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z' + }; + struct archive_string temp_name; + struct stat st; + int fd; + char *tp, *ep; + unsigned seed; + + fd = -1; + archive_string_init(&temp_name); + if (tmpdir == NULL) { + if (get_tempdir(&temp_name) != ARCHIVE_OK) + goto exit_tmpfile; + } else + archive_strcpy(&temp_name, tmpdir); + if (temp_name.s[temp_name.length-1] == '/') { + temp_name.s[temp_name.length-1] = '\0'; + temp_name.length --; + } + if (stat(temp_name.s, &st) < 0) + goto exit_tmpfile; + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + goto exit_tmpfile; + } + archive_strcat(&temp_name, "/libarchive_"); + tp = temp_name.s + archive_strlen(&temp_name); + archive_strcat(&temp_name, "XXXXXXXXXX"); + ep = temp_name.s + archive_strlen(&temp_name); + + fd = open("/dev/random", O_RDONLY); + if (fd < 0) + seed = time(NULL); + else { + if (read(fd, &seed, sizeof(seed)) < 0) + seed = time(NULL); + close(fd); + } + do { + char *p; + + p = tp; + while (p < ep) + *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; + fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600); + } while (fd < 0 && errno == EEXIST); + if (fd < 0) + goto exit_tmpfile; + unlink(temp_name.s); +exit_tmpfile: + archive_string_free(&temp_name); + return (fd); +} + +#endif diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 03a459e7c..eb7f7a52c 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Michihiro NAKAJIMA + * Copyright (c) 2009,2010 Michihiro NAKAJIMA * Copyright (c) 2003-2007 Kees Zeelenberg * All rights reserved. * @@ -59,6 +59,7 @@ #include #include #include +#include #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) @@ -594,6 +595,83 @@ __la_mkdir(const char *path, mode_t mode) return (0); } +/* + * Do not use Windows tmpfile function. + * It will make a temporary file under the root directory + * and it'll cause permission error if a user who is + * non-Administrator creates temporary files. + */ +int +__la_mkstemp(char *template) +{ + static const char num[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z' + }; + HCRYPTPROV hProv; + wchar_t *ws; + int fd; + size_t l, tmpsize; + errno_t err; + int i, xcnt; + + fd = -1; + hProv = (HCRYPTPROV)NULL; + tmpsize = l = strlen(template); + xcnt = 0; + while (l > 0 && template[--l] == 'X') + xcnt++; + if (xcnt < 6) { + errno = EINVAL; + goto exit_tmpfile; + } + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + + ws = NULL; + do { + BYTE *p; + + /* Make a random file name. */ + p = (BYTE *)template + tmpsize - xcnt; + if (!CryptGenRandom(hProv, xcnt, p)) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } + for (i = 0; i < xcnt; i++, p++) + *p = num[*p % sizeof(num)]; + + free(ws); + ws = permissive_name(template); + if (ws == NULL) { + errno = EINVAL; + goto exit_tmpfile; + } + err = _wsopen_s(&fd, ws, + _O_CREAT | _O_EXCL | _O_BINARY | _O_RDWR | _O_TEMPORARY, + _SH_DENYRW, + _S_IREAD | _S_IWRITE); + } while (err == EEXIST); + + if (err != 0) + fd = -1; +exit_tmpfile: + free(ws); + if (hProv != (HCRYPTPROV)NULL) + CryptReleaseContext(hProv, 0); + return (fd); +} + /* Windows' mbstowcs is differrent error handling from other unix mbstowcs. * That one is using MultiByteToWideChar function with MB_PRECOMPOSED and * MB_ERR_INVALID_CHARS flags. diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index b68e72e98..df8092c0b 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Michihiro NAKAJIMA + * Copyright (c) 2009,2010 Michihiro NAKAJIMA * Copyright (c) 2003-2006 Tim Kientzle * All rights reserved. * @@ -114,6 +114,7 @@ #define lstat __la_stat #define mbstowcs __la_mbstowcs #define mkdir(d,m) __la_mkdir(d, m) +#define mkstemp __la_mkstemp #define mktemp _mktemp #define open __la_open #define read __la_read @@ -358,6 +359,9 @@ typedef struct { #ifndef HAVE_LINK #define HAVE_LINK 1 #endif +#ifndef HAVE_MKSTEMP +#define HAVE_MKSTEMP 1 +#endif /* Replacement POSIX function */ extern int __la_chdir(const char *path); @@ -370,6 +374,7 @@ extern int __la_link(const char *src, const char *dst); extern __int64 __la_lseek(int fd, __int64 offset, int whence); extern size_t __la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars); extern int __la_mkdir(const char *path, mode_t mode); +extern int __la_mkstemp(char *template); extern int __la_open(const char *path, int flags, ...); extern ssize_t __la_read(int fd, void *buf, size_t nbytes); extern int __la_rmdir(const char *path);