]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Introduce a function __archive_mktemp() to create a temporary file,
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 11 Feb 2010 08:28:04 +0000 (03:28 -0500)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 11 Feb 2010 08:28:04 +0000 (03:28 -0500)
which will be used by ISO writer and xar writer.

SVN-Revision: 1895

CMakeLists.txt
build/cmake/config.h.in
configure.ac
libarchive/archive_private.h
libarchive/archive_util.c
libarchive/archive_windows.c
libarchive/archive_windows.h

index ea1272cd2f97ce555fe28ac30935348fb051172c..9f0e0cf88eee50bcb5d7c2f8aca4d58dc6d98b4e 100644 (file)
@@ -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)
index b9ff03fa7ae16a2aa307e19ffa516cc1ba84135e..ac9680ada67e239d7eb0be1824dd75da55c2eede 100644 (file)
 /* 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 <ndir.h> header file, and it defines `DIR'. */
 #cmakedefine HAVE_NDIR_H 1
 
index 513c46aaf3754fca0660e6a127a17e0ee6f986ac..45960ad57e20f672aafb0831150f01fc3e3be1c6 100644 (file)
@@ -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])
index fba3d62a20afb636aca09090b812343fa8e7ec48..dc8857a3b8eadd3364af2b3505b343e4b419ca5e 100644 (file)
@@ -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)
index c945d5fa71a36a3e458ecbcf7219c8c0febe59e5..300690602069bde8cc254d4d24670a40f1eece08 100644 (file)
@@ -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 <sys/types.h>
 #endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #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
index 03a459e7c492beee1c8ff5494287ed586a5b836e..eb7f7a52c058614660aa9542d31436ac677703a1 100644 (file)
@@ -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 <stdlib.h>
 #include <wchar.h>
 #include <windows.h>
+#include <share.h>
 
 #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.
index b68e72e9870fbbd01e1159b9568965e74bc63ee4..df8092c0b9c8092012850aaca95b73cdc58c0237 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
+ * Copyright (c) 2009,2010 Michihiro NAKAJIMA
  * Copyright (c) 2003-2006 Tim Kientzle
  * All rights reserved.
  *
 #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);