summaryrefslogtreecommitdiffstats
path: root/src/common.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2019-01-23 01:19:46 +0100
committerGravatar Nikias Bassen2019-01-23 01:19:46 +0100
commita808accd1e748184933f0e4d97d499d79f34f889 (patch)
tree6635f67416e121c0ca9bb1b1feef3758c47b8a8a /src/common.c
parente0b44cfb99c7e400c0fc51474f240dba3facd412 (diff)
downloadidevicerestore-a808accd1e748184933f0e4d97d499d79f34f889.tar.gz
idevicerestore-a808accd1e748184933f0e4d97d499d79f34f889.tar.bz2
Replace tempnam() with mkstemp() and provide reference implementation for systems lacking it
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/common.c b/src/common.c
index c3d835f..59e37a5 100644
--- a/src/common.c
+++ b/src/common.c
@@ -28,10 +28,25 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <errno.h>
#include <libgen.h>
#include <time.h>
#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <windows.h>
+#ifndef _O_EXCL
+#define _O_EXCL 0x0400
+#endif
+#ifndef O_EXCL
+#define O_EXCL _O_EXCL
+#endif
+#else
+#include <sys/time.h>
+#include <pthread.h>
+#endif
#include "common.h"
@@ -280,6 +295,168 @@ int mkdir_with_parents(const char *dir, int mode)
return res;
}
+#ifndef HAVE_MKSTEMP
+/* Based on libc's __gen_tempname() from sysdeps/posix/tempname.c
+ Copyright (C) 1991-2018 Free Software Foundation, Inc.
+ With changes from https://stackoverflow.com/a/6036308 and some
+ additional changes. */
+int mkstemp(char *tmpl)
+{
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ int len;
+ char *XXXXXX;
+ static unsigned long long value;
+ unsigned long long random_time_bits;
+ unsigned int count;
+ int fd = -1;
+ int save_errno = errno;
+
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6. It should never be
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+#if ATTEMPTS_MIN < TMP_MAX
+ unsigned int attempts = TMP_MAX;
+#else
+ unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get some more or less random data. */
+#ifdef WIN32
+ {
+ SYSTEMTIME stNow;
+ FILETIME ftNow;
+
+ // get system time
+ GetSystemTime(&stNow);
+ if (!SystemTimeToFileTime(&stNow, &ftNow))
+ {
+ errno = -1;
+ return -1;
+ }
+
+ random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32)
+ | (unsigned long long)ftNow.dwLowDateTime);
+ }
+ value += random_time_bits ^ ((unsigned long long)GetCurrentProcessId() << 32 | (unsigned long long)GetCurrentThreadId());
+#else
+ {
+ struct timeval tvNow = {0, 0};
+ gettimeofday(&tvNow, NULL);
+ random_time_bits = (((unsigned long long)tvNow.tv_sec << 32)
+ | (unsigned long long)tvNow.tv_usec);
+ }
+ value += random_time_bits ^ ((unsigned long long)getpid() << 32 | (unsigned long long)(uintptr_t)pthread_self());
+#endif
+
+ for (count = 0; count < attempts; value += 7777, ++count)
+ {
+ unsigned long long v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+#ifdef WIN32
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
+#else
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+#endif
+ if (fd >= 0)
+ {
+ errno = save_errno;
+ return fd;
+ }
+ else if (errno != EEXIST)
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ errno = EEXIST;
+ return -1;
+}
+#endif
+
+char *get_temp_filename(const char *prefix)
+{
+ char *result = NULL;
+ char *tmpdir;
+ size_t lt;
+ size_t lp;
+ const char *TMPVARS[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", NULL };
+ int i = 0;
+ int fd;
+
+ /* check the prefix parameter */
+ if (!prefix) {
+ prefix = "tmp_";
+ }
+#ifdef WIN32
+ if (strchr(prefix, '/') || strchr(prefix, '\\')) return NULL;
+#else
+ if (strchr(prefix, '/')) return NULL;
+#endif
+
+ while (TMPVARS[i] && ((tmpdir = getenv(TMPVARS[i])) == NULL)) i++;
+ if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
+#ifdef WIN32
+ tmpdir = "C:\\WINDOWS\\TEMP";
+#else
+ tmpdir = P_tmpdir;
+#endif
+ }
+ if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
+ return NULL;
+ }
+
+ lt = strlen(tmpdir);
+ if (lt < 1) {
+ return NULL;
+ }
+ lp = strlen(prefix);
+ result = malloc(lt + lp + 8);
+ strncpy(result, tmpdir, lt);
+#ifdef WIN32
+ if (tmpdir[lt-1] != '/' && tmpdir[lt-1] != '\\') result[lt++] = '\\';
+#else
+ if (tmpdir[lt-1] != '/') result[lt++] = '/';
+#endif
+ strncpy(result + lt, prefix, lp);
+ strcpy(result + lt + lp, "XXXXXX");
+ fd = mkstemp(result);
+ if (fd < 0) {
+ free(result);
+ result = NULL;
+ }
+ close(fd);
+ return result;
+}
+
void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress)
{
if(client && client->progress_cb) {