Merge pull request #112 from randy408/fuzz

Add fuzz target for OSS-Fuzz integration
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..86c1078
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,32 @@
+---
+name: Bug Report
+about: Report where libzip didn't behave like you expected.
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the Bug**
+A clear and concise description of what the bug is.
+
+**Expected Behavior**
+A clear and concise description of what you expected to happen.
+
+**Observed Behavior**
+A clear and concise description of what actually happened.
+
+**To Reproduce**
+Short program or code snippet that reproduces the problem.
+
+**libzip Version**
+Version of libzip or revision repository used.
+
+**Operating System**
+Operating system and version, used compiler.
+
+**Test Files**
+If applicable, attach and describe zip archives that trigger the problem.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/compile-error.md b/.github/ISSUE_TEMPLATE/compile-error.md
new file mode 100644
index 0000000..45c8a7a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/compile-error.md
@@ -0,0 +1,25 @@
+---
+name: Compile Error
+about: Report when libzip does not compile.
+title: ''
+labels: compile
+assignees: ''
+
+---
+
+**Compiler Error**
+Output from the compiler, including exact and complete error message, file name and line number.
+
+**libzip Version**
+Version of libzip or revision repository used.
+
+**Operating System and Compiler**
+The operating system and compiler used, including version number.
+
+Also, any flags passed to `cmake`.
+
+**Autodetected Configuration**
+Attach `CmakeCache.txt` from your build directory. This list everything `cmake` detected on your system.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000..98bead5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,22 @@
+---
+name: Feature Request
+about: Suggest an idea for this project.
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Description**
+A clear and concise description of what you want to achieve, why the current features are insufficient, and why you think it is generally useful.
+
+Also, have you checked wether the feature is already mentioned in TODO.md? If so, only submit a new issue if you expand on it. 
+
+**Solution**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context about the feature request here.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8eb16e..e64684b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -140,8 +140,8 @@
 CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
 CHECK_FUNCTION_EXISTS(_strtoi64 HAVE__STRTOI64)
 CHECK_FUNCTION_EXISTS(_strtoui64 HAVE__STRTOUI64)
-CHECK_FUNCTION_EXISTS(_umask HAVE__UMASK)
 CHECK_FUNCTION_EXISTS(_unlink HAVE__UNLINK)
+CHECK_FUNCTION_EXISTS(arc4random HAVE_ARC4RANDOM)
 CHECK_FUNCTION_EXISTS(clonefile HAVE_CLONEFILE)
 CHECK_FUNCTION_EXISTS(explicit_bzero HAVE_EXPLICIT_BZERO)
 CHECK_FUNCTION_EXISTS(explicit_memset HAVE_EXPLICIT_MEMSET)
@@ -150,7 +150,6 @@
 CHECK_FUNCTION_EXISTS(ftello HAVE_FTELLO)
 CHECK_FUNCTION_EXISTS(getprogname HAVE_GETPROGNAME)
 CHECK_FUNCTION_EXISTS(open HAVE_OPEN)
-CHECK_FUNCTION_EXISTS(mkstemp HAVE_MKSTEMP)
 CHECK_FUNCTION_EXISTS(setmode HAVE_SETMODE)
 CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF)
 CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
@@ -301,22 +300,27 @@
 SET(bindir \${exec_prefix}/${CMAKE_INSTALL_BINDIR})
 SET(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR})
 SET(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR})
-IF(BZIP2_FOUND)
-  SET(LIBS "${LIBS} -lbz2")
-ENDIF()
-SET(LIBS "${LIBS} -lz")
 IF(CMAKE_SYSTEM_NAME MATCHES BSD)
   SET(PKG_CONFIG_RPATH "-Wl,-R\${libdir}")
 ENDIF(CMAKE_SYSTEM_NAME MATCHES BSD)
+get_target_property(LIBS_PRIVATE zip LINK_LIBRARIES)
+foreach(LIB ${LIBS_PRIVATE})
+  if(LIB MATCHES "^/")
+    get_filename_component(LIB ${LIB} NAME_WE)
+    string(REGEX REPLACE "^lib" "" LIB ${LIB})
+  endif()
+  set(LIBS "${LIBS} -l${LIB}")
+endforeach()
 CONFIGURE_FILE(libzip.pc.in libzip.pc @ONLY)
 INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libzip.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
 
 # fixed size integral types
 
-IF(HAVE_STDINT_H_LIBZIP)
+IF(HAVE_INTTYPES_H_LIBZIP)
+  SET(LIBZIP_TYPES_INCLUDE "#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>")
+ELSEIF(HAVE_STDINT_H_LIBZIP)
   SET(LIBZIP_TYPES_INCLUDE "#include <stdint.h>")
-ELSEIF(HAVE_INTTYPES_H_LIBZIP)
-  SET(LIBZIP_TYPES_INCLUDE "#include <inttypes.h>")
 ELSEIF(HAVE_SYS_TYPES_H_LIBZIP)
   SET(LIBZIP_TYPES_INCLUDE "#include <sys/types.h>")
 ENDIF()
diff --git a/NEWS.md b/NEWS.md
index 9d8d2a3..42ef46b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,9 @@
+1.X.X [20XX-XX-XX]
+==================
+
+* Avoid using umask() since it's not thread-safe.
+* Set close-on-exec flag when opening files.
+
 1.5.2 [2019-03-12]
 ==================
 * Fix bug in AES encryption affecting certain file sizes
diff --git a/THANKS b/THANKS
index 5e4ae73..c9e2176 100644
--- a/THANKS
+++ b/THANKS
@@ -12,6 +12,7 @@
 Ankur Kothari <ankz.kothari@gmail.com>
 BALATON Zoltan <balaton@eik.bme.hu>
 Benjamin Gilbert <bgilbert@backtick.net>
+Beuc <beuc@beuc.net>
 Boaz Stolk <bstolk@aweta.nl>
 Bogdan <bogiebog@gmail.com>
 Brian 'geeknik' Carpenter <geeknik@protonmail.ch>
@@ -21,6 +22,7 @@
 Coverity <info@coverity.com>
 Dane Springmeyer <dane.springmeyer@gmail.com>
 David Demelier <demelier.david@gmail.com>
+Declan Moran
 Del Merritt <del@alum.mit.edu>
 Dmytro Rybachenko <atmoliton@gmail.com>
 Elvis Angelaccio
@@ -37,6 +39,7 @@
 Info-ZIP group
 Jan Weiß <jan@geheimwerk.de>
 Jay Freeman (saurik) <saurik@saurik.com>
+Joachim Reichel <joachim.reichel@gmx.de>
 João Custódio <joao_custodio@symantec.com>
 Joel Ebrahimi <joel.ebrahimi@gmail.com>
 Jono Spiro <jono.spiro@gmail.com>
@@ -48,7 +51,7 @@
 Lubomir I. Ivanov <neolit123@gmail.com>
 Maël Nison
 Martin Buchholz <martinrb@google.com>
-Martin Herkt
+Martin Herkt <lachs0r@srsfckn.biz>
 Martin Szulecki <m.szulecki@libimobiledevice.org>
 Michael Balzer
 Michael Beck <mm.beck@gmx.net>
diff --git a/android/do.sh b/android/do.sh
new file mode 100755
index 0000000..c4641c9
--- /dev/null
+++ b/android/do.sh
@@ -0,0 +1,63 @@
+
+# Author: Declan Moran
+# www.silverglint.com 
+# Thanks to damaex (https://github.com/damaex), for significant contributions
+
+ANDROID_NDK_ROOT=/home/android/android-ndk-r19c
+
+INSTALL_DIR=install
+BUILD_DIR=build
+START_DIR=$(pwd)
+
+rm -rf $INSTALL_DIR
+rm -rf $BUILD_DIR
+mkdir -p $BUILD_DIR #"${ANDROID_TARGET_PLATFORM}"
+
+#--------------------------------------------------------------------
+build_it()
+{
+    # builds either a static or shared lib depending on parm passed (ON or OFF)
+    want_shared=$1
+
+	cmake -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \
+		-DCMAKE_INSTALL_PREFIX:PATH=../../${INSTALL_DIR}/${ANDROID_TARGET_PLATFORM} \
+		-DANDROID_ABI=${ANDROID_TARGET_PLATFORM} \
+		-DENABLE_OPENSSL:BOOL=OFF \
+		-DENABLE_COMMONCRYPTO:BOOL=OFF \
+		-DENABLE_GNUTLS:BOOL=OFF \
+		-DENABLE_MBEDTLS:BOOL=OFF \
+		-DENABLE_OPENSSL:BOOL=OFF \
+		-DENABLE_WINDOWS_CRYPTO:BOOL=OFF \
+		-DBUILD_TOOLS:BOOL=OFF \
+		-DBUILD_REGRESS:BOOL=OFF \
+		-DBUILD_EXAMPLES:BOOL=OFF \
+		-DBUILD_SHARED_LIBS:BOOL=$want_shared \
+		-DBUILD_DOC:BOOL=OFF \
+		-DANDROID_TOOLCHAIN=clang  cmake -H.. -B$BUILD_DIR/${ANDROID_TARGET_PLATFORM}
+		   	
+        #run make with all system threads and install
+        cd $BUILD_DIR/${ANDROID_TARGET_PLATFORM}
+        make install -j$(nproc --all)
+        cd $START_DIR
+    }
+
+#--------------------------------------------------------------------
+for ANDROID_TARGET_PLATFORM in armeabi-v7a arm64-v8a x86 x86_64
+do
+	echo "Building libzip for ${ANDROID_TARGET_PLATFORM}" 
+	
+	build_it ON
+	build_it OFF
+	
+	if [ $? -ne 0 ]; then
+		echo "Error executing: cmake"
+		exit 1
+	fi
+
+	
+	if [ $? -ne 0 ]; then
+		echo "Error executing make install for platform: ${ANDROID_TARGET_PLATFORM}"
+		exit 1
+    fi
+    
+done    
diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile
new file mode 100644
index 0000000..2e726e4
--- /dev/null
+++ b/android/docker/Dockerfile
@@ -0,0 +1,122 @@
+# Version: 1.0
+
+# Dockerfile for building libzip for android
+# https://github.com/dec1/libzip.git
+# creates docker container with all tools, libraries and sources required to build libzip for android.
+
+# Author: Declan Moran
+# www.silverglint.com
+
+
+# Usage: 
+#---------
+# download the libzip repository
+# > git clone https://github.com/dec1/libzip.git
+# > cd libzip
+#
+# build docker image "my_img_zip" from the dockerfile in "docker" dir
+# > docker build -t my_img_zip ./android/docker
+#
+# run docker container "my_ctr_zip" from this image, mounting the current dir. (Need to pass absolute host paths to mount volume- hence "pwd")
+# > docker run  -v $(pwd):/home/docker-share/libzip -it --entrypoint=/bin/bash --name my_ctr_zip my_img_zip
+#
+# Now inside docker container
+# $ cd /home/docker-share/libzip/android
+#
+# Modify ./do.sh (on host), to match the boost and android ndk versions/paths in the "Configure here" section below
+# Build from running docker container. 
+# $./do.sh
+#
+# "./build" dir contains required build, but owned by root. chown to your username/group
+# > sudo chown -R <userid>:<groupid> ./build
+# > sudo chown -R <userid>:<groupid> ./install
+#
+# Exit container, when build is finsihed.
+# $ exit
+# 
+
+
+
+
+FROM ubuntu:18.04
+ 
+ 
+## --------------------------------------------------------------------
+##              Configure here
+# ---------------------------------------------------------------------
+# ---------------------------------------------------------------------
+# Here you can speciofy exactly what android ndk (and sdk) version you want to use.
+
+
+
+# (2) Android SDK
+# https://developer.android.com/studio#downloads
+ARG SDK_URL_BASE=https://dl.google.com/android/repository
+ARG SDK_FILE=sdk-tools-linux-4333796.zip
+
+# the sdk plaform to use 
+# https://developer.android.com/guide/topics/manifest/uses-sdk-element
+ARG ANDROID_SDK_PLATFORM_VERS="platforms;android-28"
+
+
+
+# (3) Android NDK
+# https://developer.android.com/ndk/downloads
+ARG NDK_URL_BASE=https://dl.google.com/android/repository
+ARG NDK_FILE=android-ndk-r19c-linux-x86_64.zip
+# ---------------------------------------------------------------------
+## --------------------------------------------------------------------
+
+RUN apt-get update
+RUN apt-get -y dist-upgrade
+
+
+# for downloading archives
+RUN apt-get -y install wget
+
+# for unzipping downloaded android archives
+RUN apt-get -y install zip 
+RUN apt-get -y install cmake
+
+RUN apt-get -y install lib32z1
+
+
+# need this this to install some (32 bit) prerequisites for android builds 
+RUN dpkg --add-architecture i386
+RUN apt-get update
+RUN apt-get -y dist-upgrade
+RUN apt-get install -y  libc6:i386 libncurses5:i386 libstdc++6:i386 libbz2-1.0:i386
+
+
+# need c compiler to set up create boost build system (before building boost with it and android toolchain)
+RUN apt-get -y install build-essential 
+RUN apt-get -y install libc6-dev-i386
+RUN apt-get -y install clang
+
+RUN apt-get -y install openjdk-8-jdk
+#--------------------------------------
+
+ARG ANDROID_HOME=/home/android
+WORKDIR ${ANDROID_HOME}
+
+
+# SDK
+# ----
+# download android sdk command line tools
+RUN wget ${SDK_URL_BASE}/$SDK_FILE
+RUN unzip $SDK_FILE 
+
+ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools
+
+
+RUN yes | sdkmanager --licenses
+
+RUN sdkmanager "platform-tools" $ANDROID_SDK_PLATFORM_VERS
+#RUN sdkmanager "platform-tools" "platforms;android-28" 
+
+
+# NDK
+# ----
+RUN wget ${NDK_URL_BASE}/$NDK_FILE
+RUN unzip $NDK_FILE 
+
diff --git a/android/readme.txt b/android/readme.txt
new file mode 100644
index 0000000..aa69fbd
--- /dev/null
+++ b/android/readme.txt
@@ -0,0 +1,10 @@
+
+Cross compile libzip for android.
+--------------------------------
+Modify "do.sh" as appropriate if you need to specify a different ndk dir or wish to specify different build parameters
+
+Prerequisites for the development machine - see docker/Dockerfile
+
+You can either set you host machine up with these prerequisites or simply use docker (in which case you need not install anything on your host machine except docker itself).
+
+See "Usage" in docker/Dockerfile for detailed instructions.
diff --git a/cmake-config.h.in b/cmake-config.h.in
index 51efe61..8dde4bd 100644
--- a/cmake-config.h.in
+++ b/cmake-config.h.in
@@ -19,6 +19,7 @@
 #cmakedefine HAVE__STRTOUI64
 #cmakedefine HAVE__UMASK
 #cmakedefine HAVE__UNLINK
+#cmakedefine HAVE_ARC4RANDOM
 #cmakedefine HAVE_CLONEFILE
 #cmakedefine HAVE_COMMONCRYPTO
 #cmakedefine HAVE_CRYPTO
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 8be48a0..1f7ee12 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -175,7 +175,9 @@
   ENDIF()
 ELSE(WIN32)
   SET(LIBZIP_OPSYS_FILES
+    zip_mkstempm.c
     zip_source_file.c
+    zip_random_unix.c
   )
 ENDIF(WIN32)
 
@@ -185,17 +187,13 @@
   COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/make_zip_err_str.sh ${CMAKE_CURRENT_SOURCE_DIR}/zip.h ${CMAKE_CURRENT_SOURCE_DIR}/zip_err_str.c
   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/zip.h ${CMAKE_CURRENT_SOURCE_DIR}/make_zip_err_str.sh
 )
-CHECK_FUNCTION_EXISTS(mkstemp HAVE_MKSTEMP)
-IF(NOT HAVE_MKSTEMP)
-  SET(LIBZIP_EXTRA_FILES mkstemp.c)
-ENDIF(NOT HAVE_MKSTEMP)
 IF(HAVE_LIBBZ2)
   SET(LIBZIP_OPTIONAL_FILES zip_algorithm_bzip2.c)
 ENDIF()
 
 IF(HAVE_COMMONCRYPTO)
   SET(LIBZIP_OPTIONAL_FILES ${LIBZIP_OPTIONAL_FILES} zip_crypto_commoncrypto.c
-)  
+)
 ELSEIF(HAVE_WINDOWS_CRYPTO)
   SET(LIBZIP_OPTIONAL_FILES ${LIBZIP_OPTIONAL_FILES} zip_crypto_win.c
 )
diff --git a/lib/compat.h b/lib/compat.h
index 79f94db..41b7ddb 100644
--- a/lib/compat.h
+++ b/lib/compat.h
@@ -116,9 +116,6 @@
 #if !defined(HAVE_STRTOULL) && defined(HAVE__STRTOUI64)
 #define strtoull _strtoui64
 #endif
-#if defined(HAVE__UMASK)
-#define umask _umask
-#endif
 #if defined(HAVE__UNLINK)
 #define unlink _unlink
 #endif
@@ -132,11 +129,6 @@
 #define ftello(s) ((long)ftell((s)))
 #endif
 
-#ifndef HAVE_MKSTEMP
-int _zip_mkstemp(char *);
-#define mkstemp _zip_mkstemp
-#endif
-
 #if !defined(HAVE_STRCASECMP)
 #if defined(HAVE__STRICMP)
 #define strcasecmp _stricmp
diff --git a/lib/mkstemp.c b/lib/mkstemp.c
deleted file mode 100644
index f18f10b..0000000
--- a/lib/mkstemp.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Adapted from NetBSB libc by Dieter Baron */
-
-/*	NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp 	*/
-
-/*
- * Copyright (c) 1987, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef _WIN32
-#include <io.h>
-#include <process.h>
-#else
-#include <unistd.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-
-int
-_zip_mkstemp(char *path) {
-#ifdef _WIN32
-    int ret;
-    ret = _creat(_mktemp(path), _S_IREAD | _S_IWRITE);
-    if (ret == -1) {
-	return 0;
-    }
-    else {
-	return ret;
-    }
-#else
-    int fd;
-    char *start, *trv;
-    struct stat sbuf;
-    pid_t pid;
-
-    /* To guarantee multiple calls generate unique names even if
-       the file is not created. 676 different possibilities with 7
-       or more X's, 26 with 6 or less. */
-    static char xtra[2] = "aa";
-    int xcnt = 0;
-
-    pid = getpid();
-
-    /* Move to end of path and count trailing X's. */
-    for (trv = path; *trv; ++trv)
-	if (*trv == 'X')
-	    xcnt++;
-	else
-	    xcnt = 0;
-
-    /* Use at least one from xtra.  Use 2 if more than 6 X's. */
-    if (*(trv - 1) == 'X')
-	*--trv = xtra[0];
-    if (xcnt > 6 && *(trv - 1) == 'X')
-	*--trv = xtra[1];
-
-    /* Set remaining X's to pid digits with 0's to the left. */
-    while (*--trv == 'X') {
-	*trv = (pid % 10) + '0';
-	pid /= 10;
-    }
-
-    /* update xtra for next call. */
-    if (xtra[0] != 'z')
-	xtra[0]++;
-    else {
-	xtra[0] = 'a';
-	if (xtra[1] != 'z')
-	    xtra[1]++;
-	else
-	    xtra[1] = 'a';
-    }
-
-    /*
-     * check the target directory; if you have six X's and it
-     * doesn't exist this runs for a *very* long time.
-     */
-    for (start = trv + 1;; --trv) {
-	if (trv <= path)
-	    break;
-	if (*trv == '/') {
-	    *trv = '\0';
-	    if (stat(path, &sbuf))
-		return (0);
-	    if (!S_ISDIR(sbuf.st_mode)) {
-		errno = ENOTDIR;
-		return (0);
-	    }
-	    *trv = '/';
-	    break;
-	}
-    }
-
-    for (;;) {
-	if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_BINARY, 0600)) >= 0)
-	    return (fd);
-	if (errno != EEXIST)
-	    return (0);
-
-	/* tricky little algorithm for backward compatibility */
-	for (trv = start;;) {
-	    if (!*trv)
-		return (0);
-	    if (*trv == 'z')
-		*trv++ = 'a';
-	    else {
-		if (isdigit((unsigned char)*trv))
-		    *trv = 'a';
-		else
-		    ++*trv;
-		break;
-	    }
-	}
-    }
-    /*NOTREACHED*/
-#endif
-}
diff --git a/lib/zip_crypto_commoncrypto.c b/lib/zip_crypto_commoncrypto.c
index 10f7700..da223a9 100644
--- a/lib/zip_crypto_commoncrypto.c
+++ b/lib/zip_crypto_commoncrypto.c
@@ -108,21 +108,3 @@
 
     return hmac;
 }
-
-
-ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
-    int fd;
-
-    if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
-	return false;
-    }
-
-    if (read(fd, buffer, length) != length) {
-	close(fd);
-	return false;
-    }
-
-    close(fd);
-    return true;
-}
diff --git a/lib/zip_crypto_gnutls.c b/lib/zip_crypto_gnutls.c
index 9184867..88eb6ff 100644
--- a/lib/zip_crypto_gnutls.c
+++ b/lib/zip_crypto_gnutls.c
@@ -130,6 +130,6 @@
 
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     return gnutls_rnd(GNUTLS_RND_KEY, buffer, length) == 0;
 }
diff --git a/lib/zip_crypto_gnutls.h b/lib/zip_crypto_gnutls.h
index 40d34a5..a574466 100644
--- a/lib/zip_crypto_gnutls.h
+++ b/lib/zip_crypto_gnutls.h
@@ -34,6 +34,8 @@
 #ifndef HAD_ZIP_CRYPTO_GNUTLS_H
 #define HAD_ZIP_CRYPTO_GNUTLS_H
 
+#define HAVE_SECURE_RANDOM
+
 #include <nettle/aes.h>
 #include <nettle/pbkdf2.h>
 
diff --git a/lib/zip_crypto_mbedtls.c b/lib/zip_crypto_mbedtls.c
index 8e74fbc..c85943b 100644
--- a/lib/zip_crypto_mbedtls.c
+++ b/lib/zip_crypto_mbedtls.c
@@ -136,7 +136,7 @@
 } zip_random_context_t;
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     static zip_random_context_t *ctx = NULL;
     const unsigned char *pers = "zip_crypto_mbedtls";
 
diff --git a/lib/zip_crypto_mbedtls.h b/lib/zip_crypto_mbedtls.h
index af22d5b..edfef76 100644
--- a/lib/zip_crypto_mbedtls.h
+++ b/lib/zip_crypto_mbedtls.h
@@ -34,6 +34,8 @@
 #ifndef HAD_ZIP_CRYPTO_MBEDTLS_H
 #define HAD_ZIP_CRYPTO_MBEDTLS_H
 
+#define HAVE_SECURE_RANDOM
+
 #include <mbedtls/aes.h>
 #include <mbedtls/md.h>
 
diff --git a/lib/zip_crypto_openssl.c b/lib/zip_crypto_openssl.c
index a1766bf..4760592 100644
--- a/lib/zip_crypto_openssl.c
+++ b/lib/zip_crypto_openssl.c
@@ -131,6 +131,6 @@
 
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     return RAND_bytes(buffer, length) == 1;
 }
diff --git a/lib/zip_crypto_openssl.h b/lib/zip_crypto_openssl.h
index 906890e..991884f 100644
--- a/lib/zip_crypto_openssl.h
+++ b/lib/zip_crypto_openssl.h
@@ -34,6 +34,8 @@
 #ifndef HAD_ZIP_CRYPTO_OPENSSL_H
 #define HAD_ZIP_CRYPTO_OPENSSL_H
 
+#define HAVE_SECURE_RANDOM
+
 #include <openssl/aes.h>
 #include <openssl/hmac.h>
 
diff --git a/lib/zip_crypto_win.c b/lib/zip_crypto_win.c
index a596540..3a19f52 100644
--- a/lib/zip_crypto_win.c
+++ b/lib/zip_crypto_win.c
@@ -39,7 +39,7 @@
 #define WIN32_LEAN_AND_MEAN
 #define NOCRYPT
 
-#include <Windows.h>
+#include <windows.h>
 #include <bcrypt.h>
 
 #pragma comment(lib, "bcrypt.lib")
@@ -460,6 +460,6 @@
 }
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     return BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, length, BCRYPT_USE_SYSTEM_PREFERRED_RNG));
 }
diff --git a/lib/zip_crypto_win.h b/lib/zip_crypto_win.h
index 9a239af..2b13c07 100644
--- a/lib/zip_crypto_win.h
+++ b/lib/zip_crypto_win.h
@@ -34,6 +34,8 @@
 #ifndef HAD_ZIP_CRYPTO_WIN_H
 #define HAD_ZIP_CRYPTO_WIN_H
 
+#define HAVE_SECURE_RANDOM
+
 typedef struct _zip_crypto_aes_s _zip_crypto_aes_t;
 typedef struct _zip_crypto_hmac_s _zip_crypto_hmac_t;
 
diff --git a/lib/zip_mkstempm.c b/lib/zip_mkstempm.c
new file mode 100644
index 0000000..a38ba61
--- /dev/null
+++ b/lib/zip_mkstempm.c
@@ -0,0 +1,94 @@
+/*
+  zip_mkstempm.c -- mkstemp replacement that accepts a mode argument
+  Copyright (C) 2019 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zipint.h"
+
+/*
+ * create temporary file with same permissions as previous one;
+ * or default permissions if there is no previous file
+ */
+int
+_zip_mkstempm(char *path, int mode) {
+    int fd;
+    char *start, *end, *xs;
+
+    int xcnt = 0;
+
+    end = path + strlen(path);
+    start = end - 1;
+    while (start >= path && *start == 'X') {
+	xcnt++;
+	start--;
+    }
+
+    if (xcnt == 0) {
+	errno = EINVAL;
+	return -1;
+    }
+
+    start++;
+
+    for (;;) {
+        zip_uint32_t value = zip_random_uint32();
+
+	xs = start;
+
+	while (xs < end) {
+            char digit = value % 36;
+            if (digit < 10) {
+                *(xs++) = digit + '0';
+            }
+            else {
+                *(xs++) = digit - 10 + 'a';
+            }
+	    value /= 36;
+	}
+
+	if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {
+	    if (mode != -1) {
+		/* open() honors umask(), which we don't want in this case */
+		(void)chmod(path, (mode_t)mode);
+	    }
+	    return fd;
+	}
+	if (errno != EEXIST) {
+	    return -1;
+	}
+    }
+}
diff --git a/lib/zip_random_unix.c b/lib/zip_random_unix.c
index 8e289df..17cd46e 100644
--- a/lib/zip_random_unix.c
+++ b/lib/zip_random_unix.c
@@ -33,11 +33,38 @@
 
 #include "zipint.h"
 
+#ifdef HAVE_CRYPTO
+#include "zip_crypto.h"
+#endif
+
+
+#ifdef HAVE_ARC4RANDOM
+
+#include <stdlib.h>
+
+#ifndef HAVE_SECURE_RANDOM
+ZIP_EXTERN bool
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
+    arc4random_buf(buffer, length);
+    return true;
+}
+#endif
+
+#ifndef HAVE_RANDOM_UINT32
+zip_uint32_t
+zip_random_uint32(void) {
+    return arc4random();
+}
+#endif
+
+#else /* HAVE_ARC4RANDOM */
+
+#ifndef HAVE_SECURE_RANDOM
 #include <fcntl.h>
 #include <unistd.h>
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     int fd;
 
     if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
@@ -52,3 +79,27 @@
     close(fd);
     return true;
 }
+#endif
+
+#ifndef HAVE_RANDOM_UINT32
+#include <stdlib.h>
+
+zip_uint32_t
+zip_random_uint32(void) {
+    static bool seeded = false;
+    
+    zip_uint32_t value;
+    
+    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
+        return value;
+    }
+    
+    if (!seeded) {
+        srandom((unsigned int)time(NULL));
+    }
+    
+    return (zip_uint32_t)random();
+}
+#endif
+
+#endif /* HAVE_ARC4RANDOM */
diff --git a/lib/zip_random_uwp.c b/lib/zip_random_uwp.c
index 42b96a0..465d532 100644
--- a/lib/zip_random_uwp.c
+++ b/lib/zip_random_uwp.c
@@ -31,15 +31,22 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#include "zipint.h"
+
+#ifdef HAVE_CRYPTO
+#include "zip_crypto.h"
+#endif
+
+#ifndef HAVE_SECURE_RANDOM
+
 #include <bcrypt.h>
 #include <ntstatus.h>
 #include <windows.h>
 
-#include "zipint.h"
 #include "zipwin32.h"
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     BCRYPT_ALG_HANDLE hAlg = NULL;
     NTSTATUS hr = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
     if (hr != STATUS_SUCCESS || hAlg == NULL) {
@@ -52,3 +59,26 @@
     }
     return true;
 }
+
+#endif
+
+#ifndef HAVE_RANDOM_UINT32
+#include <stdlib.h>
+
+zip_uint32_t
+zip_random_uint32(void) {
+    static bool seeded = false;
+    
+    zip_uint32_t value;
+    
+    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
+        return value;
+    }
+    
+    if (!seeded) {
+        srandom((unsigned int)time(NULL));
+    }
+    
+    return (zip_uint32_t)random();
+}
+#endif
diff --git a/lib/zip_random_win32.c b/lib/zip_random_win32.c
index 3b92978..1f1dc55 100644
--- a/lib/zip_random_win32.c
+++ b/lib/zip_random_win32.c
@@ -34,10 +34,16 @@
 #include "zipint.h"
 #include "zipwin32.h"
 
+#ifdef HAVE_CRYPTO
+#include "zip_crypto.h"
+#endif
+
+#ifndef HAVE_SECURE_RANDOM
+
 #include <wincrypt.h>
 
 ZIP_EXTERN bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     HCRYPTPROV hprov;
     if (!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
 	return false;
@@ -50,3 +56,25 @@
     }
     return true;
 }
+#endif
+
+#ifndef HAVE_RANDOM_UINT32
+#include <stdlib.h>
+
+zip_uint32_t
+zip_random_uint32(void) {
+    static bool seeded = false;
+    
+    zip_uint32_t value;
+    
+    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
+        return value;
+    }
+    
+    if (!seeded) {
+        srandom((unsigned int)time(NULL));
+    }
+    
+    return (zip_uint32_t)random();
+}
+#endif
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index cb3d151..b2fc4b7 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -31,6 +31,7 @@
   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -54,28 +55,6 @@
 #define CAN_CLONE
 #endif
 
-#ifdef _WIN32
-/* WIN32 needs <fcntl.h> for _O_BINARY */
-#include <fcntl.h>
-#endif
-
-/* Windows sys/types.h does not provide these */
-#ifndef S_ISREG
-#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
-#endif
-#if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
-#define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
-#elif defined(_S_IWRITE)
-#define _SAFE_MASK (_S_IWRITE)
-#else
-#error do not know safe values for umask, please report this
-#endif
-
-#ifdef _MSC_VER
-/* MSVC doesn't have mode_t */
-typedef int mode_t;
-#endif
-
 struct read_file {
     zip_error_t error; /* last error information */
     zip_int64_t supports;
@@ -99,6 +78,7 @@
 #ifdef CAN_CLONE
 static zip_int64_t create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset);
 #endif
+static FILE *_zip_fopen(const char *name, bool writeable);
 static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
 static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
 
@@ -245,23 +225,29 @@
 create_temp_output(struct read_file *ctx) {
     char *temp;
     int tfd;
-    mode_t mask;
+    int mode;
     FILE *tfp;
+    struct stat st;
 
     if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
 	zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
 	return -1;
     }
+
+    if (stat(ctx->fname, &st) == 0) {
+	mode = st.st_mode;
+    }
+    else {
+	mode = -1;
+    }
+
     sprintf(temp, "%s.XXXXXX", ctx->fname);
 
-    mask = umask(_SAFE_MASK);
-    if ((tfd = mkstemp(temp)) == -1) {
+    if ((tfd = _zip_mkstempm(temp, mode)) == -1) {
 	zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
-	umask(mask);
 	free(temp);
 	return -1;
     }
-    umask(mask);
 
     if ((tfp = fdopen(tfd, "r+b")) == NULL) {
 	zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
@@ -271,14 +257,6 @@
 	return -1;
     }
 
-#ifdef _WIN32
-    /*
-     According to Pierre Joye, Windows in some environments per
-     default creates text files, so force binary mode.
-     */
-    _setmode(_fileno(tfp), _O_BINARY);
-#endif
-
     ctx->fout = tfp;
     ctx->tmpname = temp;
 
@@ -316,7 +294,7 @@
 	free(temp);
 	return -1;
     }
-    if ((tfp = fopen(temp, "r+b")) == NULL) {
+    if ((tfp = _zip_fopen(temp, true)) == NULL) {
 	zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
 	(void)remove(temp);
 	free(temp);
@@ -413,27 +391,15 @@
 #endif
 
     case ZIP_SOURCE_COMMIT_WRITE: {
-	mode_t mode;
-	struct stat st;
-
 	if (fclose(ctx->fout) < 0) {
 	    ctx->fout = NULL;
 	    zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
 	}
 	ctx->fout = NULL;
-	if (stat(ctx->fname, &st) == 0) {
-	    mode = st.st_mode;
-	} else {
-	    mode_t mask = umask(022);
-	    umask(mask);
-	    mode = 0666 & ~mask;
-	}
 	if (rename(ctx->tmpname, ctx->fname) < 0) {
 	    zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
 	    return -1;
 	}
-	/* not much we can do if chmod fails except make the whole commit fail */
-	(void)chmod(ctx->fname, mode);
 	free(ctx->tmpname);
 	ctx->tmpname = NULL;
 	return 0;
@@ -459,7 +425,7 @@
 
     case ZIP_SOURCE_OPEN:
 	if (ctx->fname) {
-	    if ((ctx->f = fopen(ctx->fname, "rb")) == NULL) {
+	    if ((ctx->f = _zip_fopen(ctx->fname, false)) == NULL) {
 		zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
 		return -1;
 	    }
@@ -656,3 +622,33 @@
     }
     return 0;
 }
+
+
+/*
+ * fopen replacement that sets the close-on-exec flag
+ * some implementations support an fopen 'e' flag for that,
+ * but e.g. macOS doesn't.
+ */
+static FILE *
+_zip_fopen(const char *name, bool writeable)
+{
+    int fd;
+    int flags;
+    FILE *fp;
+
+    flags = O_CLOEXEC;
+    if (writeable) {
+	flags |= O_RDWR;
+    }
+    else {
+	flags |= O_RDONLY;
+    }
+
+    if ((fd = open(name, flags)) < 0) {
+	return NULL;
+    }
+    if ((fp = fdopen(fd, writeable ? "r+b" : "rb")) == NULL) {
+	return NULL;
+    }
+    return fp;
+}
diff --git a/lib/zip_source_winzip_aes_encode.c b/lib/zip_source_winzip_aes_encode.c
index 4e5f753..7df5faf 100644
--- a/lib/zip_source_winzip_aes_encode.c
+++ b/lib/zip_source_winzip_aes_encode.c
@@ -83,7 +83,7 @@
 static int
 encrypt_header(zip_source_t *src, struct winzip_aes *ctx) {
     zip_uint16_t salt_length = SALT_LENGTH(ctx->encryption_method);
-    if (!zip_random(ctx->data, salt_length)) {
+    if (!zip_secure_random(ctx->data, salt_length)) {
 	zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
 	return -1;
     }
diff --git a/lib/zipint.h b/lib/zipint.h
index 093a1b2..76e8709 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -523,6 +523,8 @@
 bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error);
 bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error);
 
+int _zip_mkstempm(char *path, int mode);
+
 zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);
 
 void _zip_progress_end(zip_progress_t *progress);
@@ -532,7 +534,9 @@
 void _zip_progress_subrange(zip_progress_t *progress, double start, double end);
 void _zip_progress_update(zip_progress_t *progress, double value);
 
-ZIP_EXTERN bool zip_random(zip_uint8_t *buffer, zip_uint16_t length);
+/* this symbol is extern so it can be overridden for regression testing */
+ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length);
+zip_uint32_t zip_random_uint32(void);
 
 int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
 int _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error);
diff --git a/man/zip_source_stat.mdoc b/man/zip_source_stat.mdoc
index 69f4516..37b43a9 100644
--- a/man/zip_source_stat.mdoc
+++ b/man/zip_source_stat.mdoc
@@ -79,24 +79,24 @@
 Check if the flag defined by the following defines are in
 .Ar valid
 before accessing the fields:
-.Bl -tag -width ZIP_SOURCE_STAT_ENCRYPTION_METHODXX -compact -offset indent
-.It Dv ZIP_SOURCE_STAT_NAME
+.Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent
+.It Dv ZIP_STAT_NAME
 .Ar name
-.It Dv ZIP_SOURCE_STAT_INDEX
+.It Dv ZIP_STAT_INDEX
 .Ar index
-.It Dv ZIP_SOURCE_STAT_SIZE
+.It Dv ZIP_STAT_SIZE
 .Ar size
-.It Dv ZIP_SOURCE_STAT_COMP_SIZE
+.It Dv ZIP_STAT_COMP_SIZE
 .Ar comp_size
-.It Dv ZIP_SOURCE_STAT_MTIME
+.It Dv ZIP_STAT_MTIME
 .Ar mtime
-.It Dv ZIP_SOURCE_STAT_CRC
+.It Dv ZIP_STAT_CRC
 .Ar crc
-.It Dv ZIP_SOURCE_STAT_COMP_METHOD
+.It Dv ZIP_STAT_COMP_METHOD
 .Ar comp_method
-.It Dv ZIP_SOURCE_STAT_ENCRYPTION_METHOD
+.It Dv ZIP_STAT_ENCRYPTION_METHOD
 .Ar encryption_method
-.It Dv ZIP_SOURCE_STAT_FLAGS
+.It Dv ZIP_STAT_FLAGS
 .Ar flags
 .El
 .Pp
diff --git a/regress/nonrandomopen.c b/regress/nonrandomopen.c
index c9833e0..ec8c5f8 100644
--- a/regress/nonrandomopen.c
+++ b/regress/nonrandomopen.c
@@ -1,5 +1,5 @@
 /*
-  nonrandomopen.c -- override zip_random
+  nonrandomopen.c -- override zip_secure_random
 
   Copyright (C) 2017-2018 Dieter Baron and Thomas Klausner
 
@@ -43,7 +43,7 @@
 #include "zipint.h"
 
 bool
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
     memset(buffer, 0, length);
 
     return true;
diff --git a/regress/nonrandomopentest.c b/regress/nonrandomopentest.c
index 1ed6249..0b5bf9f 100644
--- a/regress/nonrandomopentest.c
+++ b/regress/nonrandomopentest.c
@@ -42,8 +42,8 @@
     int i;
 
 #ifdef HAVE_CRYPTO
-    if (!zip_random(buf, sizeof(buf))) {
-	fprintf(stderr, "zip_random returned false\n");
+    if (!zip_secure_random(buf, sizeof(buf))) {
+	fprintf(stderr, "zip_secure_random returned false\n");
 	exit(1);
     }
     for (i = 0; i < sizeof(buf); i++) {
diff --git a/xcode/libzip.xcodeproj/project.pbxproj b/xcode/libzip.xcodeproj/project.pbxproj
index 26ef3e4..b7885b8 100644
--- a/xcode/libzip.xcodeproj/project.pbxproj
+++ b/xcode/libzip.xcodeproj/project.pbxproj
@@ -183,11 +183,13 @@
 		4B3A5F531DF96EB4005A53A1 /* zip_ftell.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4E1DF96D83005A53A1 /* zip_ftell.c */; };
 		4B3A5F541DF96EB5005A53A1 /* zip_fseek.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4D1DF96D83005A53A1 /* zip_fseek.c */; };
 		4B3A5F551DF96EB5005A53A1 /* zip_ftell.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4E1DF96D83005A53A1 /* zip_ftell.c */; };
+		4B5169A822A7993E00AA4340 /* zip_mkstempm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B5169A722A7993D00AA4340 /* zip_mkstempm.c */; };
 		4B51DDBA1FDAE20A00C5CA85 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
 		4B51DDBB1FDAE20A00C5CA85 /* libzip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D68B15B2F3F1002D5007 /* libzip.framework */; };
 		4B51DDC11FDAE25B00C5CA85 /* ziptool.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BACD57C15BC2AEF00920691 /* ziptool.c */; };
 		4B51DDC21FDAE25F00C5CA85 /* ziptool_regress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B51DDB31FDAE1DB00C5CA85 /* ziptool_regress.c */; };
 		4B51DDC31FDAE26600C5CA85 /* source_hole.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD6CB5C19E6A5D900710654 /* source_hole.c */; };
+		4B542C2C22B12E3900960B38 /* zip_random_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 736ED9B81E3D688C00C36873 /* zip_random_unix.c */; };
 		4B69E6EE2032F18B0001EEE7 /* zip_winzip_aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B69E6ED2032F1870001EEE7 /* zip_winzip_aes.c */; };
 		4B69E6EF2032F18E0001EEE7 /* zip_winzip_aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B69E6ED2032F1870001EEE7 /* zip_winzip_aes.c */; };
 		4B82CED419915F360097BC18 /* zip_file_set_mtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B82CED319915F360097BC18 /* zip_file_set_mtime.c */; };
@@ -710,6 +712,7 @@
 		4B41A2651FE15E99005D8C91 /* clone-fs-add.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "clone-fs-add.test"; sourceTree = "<group>"; };
 		4B41A2661FE15FCE005D8C91 /* clone-fs-delete.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "clone-fs-delete.test"; sourceTree = "<group>"; };
 		4B41A2671FE1604E005D8C91 /* clone-fs-replace.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "clone-fs-replace.test"; sourceTree = "<group>"; };
+		4B5169A722A7993D00AA4340 /* zip_mkstempm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_mkstempm.c; sourceTree = "<group>"; };
 		4B51DDB21FDADEDF00C5CA85 /* INSTALL.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
 		4B51DDB31FDAE1DB00C5CA85 /* ziptool_regress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ziptool_regress.c; sourceTree = "<group>"; };
 		4B51DDC01FDAE20A00C5CA85 /* ziptool_regress */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ziptool_regress; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1490,12 +1493,8 @@
 			isa = PBXGroup;
 			children = (
 				4B77E61A1FDDCD3A006786BA /* CMakeLists.txt */,
-				4BDC72A015B1B56400236D3C /* config.h */,
 				4BD25DA51CF58790005A9EC4 /* compat.h */,
-				4BDC729E15B1B4E900236D3C /* zipconf.h */,
-				4BDC729815B1B2A600236D3C /* zip.h */,
-				4BDC729915B1B2A600236D3C /* zipint.h */,
-				4BCD54C81AB05AA90003D379 /* zipwin32.h */,
+				4BDC72A015B1B56400236D3C /* config.h */,
 				4BDC71F115B1B25E00236D3C /* zip_add_dir.c */,
 				4BDC71F215B1B25E00236D3C /* zip_add_entry.c */,
 				4BDC71F315B1B25E00236D3C /* zip_add.c */,
@@ -1503,13 +1502,13 @@
 				4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */,
 				4BCB434119E9347E0067FAA3 /* zip_buffer.c */,
 				4BDC71F415B1B25E00236D3C /* zip_close.c */,
-				4B69E6F3203342E30001EEE7 /* zip_crypto.h */,
-				4BE92AB0203597D700509BC8 /* zip_crypto_commoncrypto.h */,
 				4BE92AB1203597D700509BC8 /* zip_crypto_commoncrypto.c */,
+				4BE92AB0203597D700509BC8 /* zip_crypto_commoncrypto.h */,
 				4B69E6F020330D460001EEE7 /* zip_crypto_gnutls.c */,
 				4B69E6F2203341D50001EEE7 /* zip_crypto_gnutls.h */,
 				4BE92AAB20346B1900509BC8 /* zip_crypto_openssl.c */,
 				4BE92AAA20346B1900509BC8 /* zip_crypto_openssl.h */,
+				4B69E6F3203342E30001EEE7 /* zip_crypto.h */,
 				4BDC71F515B1B25E00236D3C /* zip_delete.c */,
 				4BDC71F615B1B25E00236D3C /* zip_dir_add.c */,
 				4BDC71F715B1B25E00236D3C /* zip_dirent.c */,
@@ -1557,6 +1556,7 @@
 				3D9284801C309510001EABA7 /* zip_hash.c */,
 				4BCF3019199A2F820064207B /* zip_io_util.c */,
 				4BDC721C15B1B25E00236D3C /* zip_memdup.c */,
+				4B5169A722A7993D00AA4340 /* zip_mkstempm.c */,
 				4BDC721D15B1B25E00236D3C /* zip_name_locate.c */,
 				4BDC721E15B1B25E00236D3C /* zip_new.c */,
 				4BDC721F15B1B25E00236D3C /* zip_open.c */,
@@ -1570,8 +1570,8 @@
 				4BDC722515B1B25E00236D3C /* zip_set_file_comment.c */,
 				4BDC722615B1B25E00236D3C /* zip_set_file_compression.c */,
 				4BDC722715B1B25E00236D3C /* zip_set_name.c */,
-				4BCF301A199A2F820064207B /* zip_source_begin_write.c */,
 				4BC03FA21FDD6B6F003C7B62 /* zip_source_begin_write_cloning.c */,
+				4BCF301A199A2F820064207B /* zip_source_begin_write.c */,
 				4BDC722815B1B25E00236D3C /* zip_source_buffer.c */,
 				4BD5053219A0116D007DD28A /* zip_source_call.c */,
 				4BDC722915B1B25E00236D3C /* zip_source_close.c */,
@@ -1591,12 +1591,16 @@
 				4BDC723515B1B25E00236D3C /* zip_source_read.c */,
 				4BCF3031199ABD3A0064207B /* zip_source_remove.c */,
 				4BCF301C199A2F820064207B /* zip_source_rollback_write.c */,
-				4BCF301D199A2F820064207B /* zip_source_seek.c */,
 				4BCF3034199ABDDA0064207B /* zip_source_seek_write.c */,
+				4BCF301D199A2F820064207B /* zip_source_seek.c */,
 				4BDC723615B1B25E00236D3C /* zip_source_stat.c */,
 				4BCF301E199A2F820064207B /* zip_source_supports.c */,
-				4BCF301F199A2F820064207B /* zip_source_tell.c */,
 				4BCF3035199ABDDA0064207B /* zip_source_tell_write.c */,
+				4BCF301F199A2F820064207B /* zip_source_tell.c */,
+				4BCD54C41AB05AA90003D379 /* zip_source_win32a.c */,
+				4BEF35C31AF4D92D00974F28 /* zip_source_win32handle.c */,
+				4BCD54C61AB05AA90003D379 /* zip_source_win32utf8.c */,
+				4BCD54C71AB05AA90003D379 /* zip_source_win32w.c */,
 				4BDC723715B1B25E00236D3C /* zip_source_window.c */,
 				736ED9B91E3D688C00C36873 /* zip_source_winzip_aes_decode.c */,
 				736ED9BA1E3D688C00C36873 /* zip_source_winzip_aes_encode.c */,
@@ -1609,15 +1613,15 @@
 				4BDC723D15B1B25E00236D3C /* zip_strerror.c */,
 				4BDC723E15B1B25E00236D3C /* zip_string.c */,
 				4BDC723F15B1B25E00236D3C /* zip_unchange_all.c */,
-				4BCD54C41AB05AA90003D379 /* zip_source_win32a.c */,
-				4BEF35C31AF4D92D00974F28 /* zip_source_win32handle.c */,
-				4BCD54C61AB05AA90003D379 /* zip_source_win32utf8.c */,
-				4BCD54C71AB05AA90003D379 /* zip_source_win32w.c */,
 				4BDC724015B1B25E00236D3C /* zip_unchange_archive.c */,
 				4BDC724115B1B25E00236D3C /* zip_unchange_data.c */,
 				4BDC724215B1B25E00236D3C /* zip_unchange.c */,
 				4BDC724315B1B25E00236D3C /* zip_utf-8.c */,
 				4B69E6ED2032F1870001EEE7 /* zip_winzip_aes.c */,
+				4BDC729815B1B2A600236D3C /* zip.h */,
+				4BDC729E15B1B4E900236D3C /* zipconf.h */,
+				4BDC729915B1B2A600236D3C /* zipint.h */,
+				4BCD54C81AB05AA90003D379 /* zipwin32.h */,
 			);
 			name = libzip;
 			path = ../lib;
@@ -1915,6 +1919,7 @@
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
 			knownRegions = (
+				English,
 				en,
 			);
 			mainGroup = 4BDC71BD15B181DA00236D3C;
@@ -2065,6 +2070,7 @@
 				4BCF302A199A2F820064207B /* zip_source_seek.c in Sources */,
 				4B01D6C515B2F46B002D5007 /* zip_fopen_index_encrypted.c in Sources */,
 				4B01D6C615B2F46B002D5007 /* zip_fopen_index.c in Sources */,
+				4B5169A822A7993E00AA4340 /* zip_mkstempm.c in Sources */,
 				4B69E6EE2032F18B0001EEE7 /* zip_winzip_aes.c in Sources */,
 				4B01D6C715B2F46B002D5007 /* zip_fopen.c in Sources */,
 				3D9284821C309510001EABA7 /* zip_hash.c in Sources */,
@@ -2088,6 +2094,7 @@
 				4B01D6D415B2F46B002D5007 /* zip_open.c in Sources */,
 				4B01D6D515B2F46B002D5007 /* zip_rename.c in Sources */,
 				4BCF302E199A2F820064207B /* zip_source_tell.c in Sources */,
+				4B542C2C22B12E3900960B38 /* zip_random_unix.c in Sources */,
 				4B972050188EBE85002FAFAD /* zip_file_get_external_attributes.c in Sources */,
 				4B01D6D615B2F46B002D5007 /* zip_replace.c in Sources */,
 				4B01D6D715B2F46B002D5007 /* zip_set_archive_comment.c in Sources */,