1 /* Copyright (C) 1998,99,2001,2005,2006,2007,2009 Free Software Foundation, Inc.
2 This file is derived from the one in the GNU C Library.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with GU Smalltalk; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 #if !_LIBC
20 # include <config.h>
21 #endif
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <sys/time.h>
30 #include <limits.h>
31 #include <unistd.h>
32
33 #include <errno.h>
34 #ifndef __set_errno
35 # define __set_errno(Val) errno = (Val)
36 #endif
37
38 /* These are the characters used in temporary file names. */
39 static const char letters[] =
40 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
41
42 static int
my_mkdir(name,mode)43 my_mkdir (name, mode)
44 const char* name;
45 mode_t mode;
46 {
47 int retstat;
48 #ifdef _WIN32
49 retstat = mkdir (name);
50 if (retstat == 0)
51 retstat = chmod (name, mode);
52 #else
53 retstat = mkdir (name, mode);
54 #endif
55 return retstat;
56 }
57
58 /* Generate a unique temporary file name from TEMPLATE.
59 The last six characters of TEMPLATE must be "XXXXXX";
60 they are replaced with a string that makes the file name unique.
61 Then open the file and return the template or NULL. */
62 char *
mkdtemp(template)63 mkdtemp (template)
64 char *template;
65 {
66 int len;
67 char *XXXXXX;
68 static long long value;
69 long long random_time_bits;
70 unsigned int count;
71 int save_errno = errno;
72 struct timeval tv;
73
74 /* A lower bound on the number of temporary files to attempt to
75 generate. The maximum total number of temporary file names that
76 can exist for a given template is 62**6. It should never be
77 necessary to try all these combinations. Instead if a reasonable
78 number of names is tried (we define reasonable as 62**3) fail to
79 give the system administrator the chance to remove the problems. */
80 #define ATTEMPTS_MIN (62 * 62 * 62)
81
82 /* The number of times to attempt to generate a temporary file. To
83 conform to POSIX, this must be no smaller than TMP_MAX. */
84 #if defined TMP_MAX
85 unsigned int attempts = ATTEMPTS_MIN < TMP_MAX ? TMP_MAX : ATTEMPTS_MIN;
86 #else
87 unsigned int attempts = ATTEMPTS_MIN;
88 #endif
89
90 len = strlen (template);
91 if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
92 {
93 __set_errno (EINVAL);
94 return NULL;
95 }
96
97 /* This is where the Xs start. */
98 XXXXXX = &template[len - 6];
99
100 /* Get some more or less random data. */
101 gettimeofday (&tv, NULL);
102 random_time_bits = ((long long) tv.tv_usec << 16) ^ tv.tv_sec;
103 value += random_time_bits ^ getpid ();
104
105 for (count = 0; count < attempts; value += 7777, ++count)
106 {
107 long long v = value;
108
109 /* Fill in the random bits. */
110 XXXXXX[0] = letters[v % 62];
111 v /= 62;
112 XXXXXX[1] = letters[v % 62];
113 v /= 62;
114 XXXXXX[2] = letters[v % 62];
115 v /= 62;
116 XXXXXX[3] = letters[v % 62];
117 v /= 62;
118 XXXXXX[4] = letters[v % 62];
119 v /= 62;
120 XXXXXX[5] = letters[v % 62];
121
122 if (my_mkdir(template, 0700) == 0)
123 {
124 __set_errno (save_errno);
125 return template;
126 }
127 else if (errno != EEXIST)
128 return NULL;
129 }
130
131 /* We got out of the loop because we ran out of combinations to try. */
132 __set_errno (EEXIST);
133 return NULL;
134 }
135