This source file includes following definitions.
- hash32s
- utfile_mkstemps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #include <ctype.h>
17 #include <signal.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #if defined(__sunos) && defined(SYSV)
24 # include <sys/param.h>
25 #endif
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <time.h>
29 #include <sys/time.h>
30 #include <stdint.h>
31 #include <unistd.h>
32
33 #define MAX_MKSTEMPS_TRIES 10000
34
35 #if defined(__MINGW64__) || defined(__MINGW32__)
36 # include "bsd_random.h"
37 # define random bsd_random
38 # define srandom bsd_srandom
39 #endif
40
41 #if defined(FREE)
42 # undef FREE
43 #endif
44 #define FREE(p) do \
45 { \
46 free((p)); \
47 (p) = NULL; \
48 } while(0)
49
50 static char valid_file_name_chars[]
51 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
52
53 static inline uint32_t
54 hash32s(const void *buf, size_t len, uint32_t h)
55 {
56 const unsigned char *p = buf;
57
58 for (size_t i = 0; i < len; i++)
59 h = h * 31 + p[i];
60
61 h ^= h >> 17;
62 h *= UINT32_C(0xed5ad4bb);
63 h ^= h >> 11;
64 h *= UINT32_C(0xac4c1b51);
65 h ^= h >> 15;
66 h *= UINT32_C(0x31848bab);
67 h ^= h >> 14;
68
69 return h;
70 }
71
72
73
74
75
76
77 int
78 utfile_mkstemps(char *request_pattern, int suffix_length)
79 {
80 long pattern_length;
81 int st1ret;
82 char *mask_pointer;
83 struct timespec st1;
84
85 char *pattern = strdup(request_pattern);
86 if (!pattern)
87 {
88 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
89 __func__, __FILE__, __LINE__);
90 #if defined(USE_BACKTRACE)
91 # if defined(SIGUSR2)
92 (void)raise(SIGUSR2);
93
94 # endif
95 #endif
96 abort();
97 }
98
99 pattern_length = (long) strlen(pattern);
100
101 #if defined(USE_MONOTONIC)
102 st1ret = clock_gettime(CLOCK_MONOTONIC, &st1);
103 #else
104 st1ret = clock_gettime(CLOCK_REALTIME, &st1);
105 #endif
106 if (st1ret != 0)
107 {
108 (void)fprintf (stderr, "\rFATAL: clock_gettime failure! Aborting at %s[%s:%d]\r\n",
109 __func__, __FILE__, __LINE__);
110 #if defined(USE_BACKTRACE)
111 # if defined(SIGUSR2)
112 (void)raise(SIGUSR2);
113
114 # endif
115 #endif
116 abort();
117 }
118
119 uint32_t h = 0;
120 #if __STDC_VERSION__ < 201112L
121
122 void *(*mallocptr)() = malloc;
123 h = hash32s(&mallocptr, sizeof(mallocptr), h);
124 #endif
125 void *small = malloc(1);
126 h = hash32s(&small, sizeof(small), h);
127 FREE(small);
128 void *big = malloc(1UL << 20);
129 h = hash32s(&big, sizeof(big), h);
130 FREE(big);
131 void *ptr = &ptr;
132 h = hash32s(&ptr, sizeof(ptr), h);
133 time_t t = time(0);
134 h = hash32s(&t, sizeof(t), h);
135 #if !defined(_AIX)
136 for (int i = 0; i < 1000; i++)
137 {
138 unsigned long counter = 0;
139 clock_t start = clock();
140 while (clock() == start)
141 {
142 counter++;
143 }
144 h = hash32s(&start, sizeof(start), h);
145 h = hash32s(&counter, sizeof(counter), h);
146 }
147 #endif
148 int mypid = (int)getpid();
149 h = hash32s(&mypid, sizeof(mypid), h);
150 char rnd[4];
151 FILE *f = fopen("/dev/urandom", "rb");
152 if (f)
153 {
154 if (fread(rnd, sizeof(rnd), 1, f))
155 {
156 h = hash32s(rnd, sizeof(rnd), h);
157 }
158 fclose(f);
159 }
160 srandom(h);
161
162 if (( (long) pattern_length - 6 ) < (long) suffix_length)
163 {
164 FREE(pattern);
165 return ( -1 );
166 }
167
168 long mask_offset = (long) pattern_length - ( 6 + (long) suffix_length );
169
170 if (strncmp(&pattern[mask_offset], "XXXXXX", 6))
171 {
172 FREE(pattern);
173 return ( -1 );
174 }
175
176 mask_pointer = &pattern[mask_offset];
177
178 long valid_char_count = (long) strlen(valid_file_name_chars);
179
180 if (valid_char_count < 1)
181 {
182 FREE(pattern);
183 return ( -1 );
184 }
185
186 for (int count = 0; count < MAX_MKSTEMPS_TRIES; count++)
187 {
188 for (int mask_index = 0; mask_index < 6; mask_index++)
189 {
190 mask_pointer[mask_index]
191 = valid_file_name_chars[random() % valid_char_count];
192 }
193
194 int fd = open(pattern, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
195
196 if (fd >= 0)
197 {
198 FREE(pattern);
199 return ( fd );
200 }
201
202
203
204
205
206
207 if (( errno != EEXIST ) && ( errno != EISDIR ))
208 {
209 break;
210 }
211 }
212
213
214
215
216
217
218 FREE(pattern);
219 return ( -1 );
220 }