Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/lib/tempname.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* tempname.c - generate the name of a temporary file. | - | ||||||||||||
2 | - | |||||||||||||
3 | Copyright (C) 1991-2003, 2005-2007, 2009-2018 Free Software Foundation, Inc. | - | ||||||||||||
4 | - | |||||||||||||
5 | This program is free software: you can redistribute it and/or modify | - | ||||||||||||
6 | it under the terms of the GNU General Public License as published by | - | ||||||||||||
7 | the Free Software Foundation; either version 3 of the License, or | - | ||||||||||||
8 | (at your option) any later version. | - | ||||||||||||
9 | - | |||||||||||||
10 | This program is distributed in the hope that it will be useful, | - | ||||||||||||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | ||||||||||||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | ||||||||||||
13 | GNU General Public License for more details. | - | ||||||||||||
14 | - | |||||||||||||
15 | You should have received a copy of the GNU General Public License | - | ||||||||||||
16 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ | - | ||||||||||||
17 | - | |||||||||||||
18 | /* Extracted from glibc sysdeps/posix/tempname.c. See also tmpdir.c. */ | - | ||||||||||||
19 | - | |||||||||||||
20 | #if !_LIBC | - | ||||||||||||
21 | # include <config.h> | - | ||||||||||||
22 | # include "tempname.h" | - | ||||||||||||
23 | # include "randint.h" | - | ||||||||||||
24 | #endif | - | ||||||||||||
25 | - | |||||||||||||
26 | #include <sys/types.h> | - | ||||||||||||
27 | #include <assert.h> | - | ||||||||||||
28 | - | |||||||||||||
29 | #include <errno.h> | - | ||||||||||||
30 | #ifndef __set_errno | - | ||||||||||||
31 | # define __set_errno(Val) errno = (Val) | - | ||||||||||||
32 | #endif | - | ||||||||||||
33 | - | |||||||||||||
34 | #include <stdio.h> | - | ||||||||||||
35 | #ifndef P_tmpdir | - | ||||||||||||
36 | # define P_tmpdir "/tmp" | - | ||||||||||||
37 | #endif | - | ||||||||||||
38 | #ifndef TMP_MAX | - | ||||||||||||
39 | # define TMP_MAX 238328 | - | ||||||||||||
40 | #endif | - | ||||||||||||
41 | #ifndef __GT_FILE | - | ||||||||||||
42 | # define __GT_FILE 0 | - | ||||||||||||
43 | # define __GT_DIR 1 | - | ||||||||||||
44 | # define __GT_NOCREATE 2 | - | ||||||||||||
45 | #endif | - | ||||||||||||
46 | #if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ | - | ||||||||||||
47 | || GT_NOCREATE != __GT_NOCREATE) | - | ||||||||||||
48 | # error report this to bug-gnulib@gnu.org | - | ||||||||||||
49 | #endif | - | ||||||||||||
50 | - | |||||||||||||
51 | #include <stdbool.h> | - | ||||||||||||
52 | #include <stddef.h> | - | ||||||||||||
53 | #include <stdlib.h> | - | ||||||||||||
54 | #include <string.h> | - | ||||||||||||
55 | - | |||||||||||||
56 | #include <fcntl.h> | - | ||||||||||||
57 | #include <sys/time.h> | - | ||||||||||||
58 | #include <stdint.h> | - | ||||||||||||
59 | #include <unistd.h> | - | ||||||||||||
60 | - | |||||||||||||
61 | #include <sys/stat.h> | - | ||||||||||||
62 | - | |||||||||||||
63 | #if _LIBC | - | ||||||||||||
64 | # define struct_stat64 struct stat64 | - | ||||||||||||
65 | #else | - | ||||||||||||
66 | # define struct_stat64 struct stat | - | ||||||||||||
67 | # define __try_tempname try_tempname | - | ||||||||||||
68 | # define __gen_tempname gen_tempname | - | ||||||||||||
69 | # define __getpid getpid | - | ||||||||||||
70 | # define __gettimeofday gettimeofday | - | ||||||||||||
71 | # define __mkdir mkdir | - | ||||||||||||
72 | # define __open open | - | ||||||||||||
73 | # define __lxstat64(version, file, buf) lstat (file, buf) | - | ||||||||||||
74 | #endif | - | ||||||||||||
75 | - | |||||||||||||
76 | #ifdef _LIBC | - | ||||||||||||
77 | # include <hp-timing.h> | - | ||||||||||||
78 | # if HP_TIMING_AVAIL | - | ||||||||||||
79 | # define RANDOM_BITS(Var) \ | - | ||||||||||||
80 | if (__builtin_expect (value == UINT64_C (0), 0)) \ | - | ||||||||||||
81 | { \ | - | ||||||||||||
82 | /* If this is the first time this function is used initialize \ | - | ||||||||||||
83 | the variable we accumulate the value in to some somewhat \ | - | ||||||||||||
84 | random value. If we'd not do this programs at startup time \ | - | ||||||||||||
85 | might have a reduced set of possible names, at least on slow \ | - | ||||||||||||
86 | machines. */ \ | - | ||||||||||||
87 | struct timeval tv; \ | - | ||||||||||||
88 | __gettimeofday (&tv, NULL); \ | - | ||||||||||||
89 | value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ | - | ||||||||||||
90 | } \ | - | ||||||||||||
91 | HP_TIMING_NOW (Var) | - | ||||||||||||
92 | # endif | - | ||||||||||||
93 | #endif | - | ||||||||||||
94 | - | |||||||||||||
95 | /* Use the widest available unsigned type if uint64_t is not | - | ||||||||||||
96 | available. The algorithm below extracts a number less than 62**6 | - | ||||||||||||
97 | (approximately 2**35.725) from uint64_t, so ancient hosts where | - | ||||||||||||
98 | uintmax_t is only 32 bits lose about 3.725 bits of randomness, | - | ||||||||||||
99 | which is better than not having mkstemp at all. */ | - | ||||||||||||
100 | #if !defined UINT64_MAX && !defined uint64_t | - | ||||||||||||
101 | # define uint64_t uintmax_t | - | ||||||||||||
102 | #endif | - | ||||||||||||
103 | - | |||||||||||||
104 | #if _LIBC | - | ||||||||||||
105 | /* Return nonzero if DIR is an existent directory. */ | - | ||||||||||||
106 | static int | - | ||||||||||||
107 | direxists (const char *dir) | - | ||||||||||||
108 | { | - | ||||||||||||
109 | struct_stat64 buf; | - | ||||||||||||
110 | return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); | - | ||||||||||||
111 | } | - | ||||||||||||
112 | - | |||||||||||||
113 | /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is | - | ||||||||||||
114 | non-null and exists, uses it; otherwise uses the first of $TMPDIR, | - | ||||||||||||
115 | P_tmpdir, /tmp that exists. Copies into TMPL a template suitable | - | ||||||||||||
116 | for use with mk[s]temp. Will fail (-1) if DIR is non-null and | - | ||||||||||||
117 | doesn't exist, none of the searched dirs exists, or there's not | - | ||||||||||||
118 | enough space in TMPL. */ | - | ||||||||||||
119 | int | - | ||||||||||||
120 | __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, | - | ||||||||||||
121 | int try_tmpdir) | - | ||||||||||||
122 | { | - | ||||||||||||
123 | const char *d; | - | ||||||||||||
124 | size_t dlen, plen; | - | ||||||||||||
125 | - | |||||||||||||
126 | if (!pfx || !pfx[0]) | - | ||||||||||||
127 | { | - | ||||||||||||
128 | pfx = "file"; | - | ||||||||||||
129 | plen = 4; | - | ||||||||||||
130 | } | - | ||||||||||||
131 | else | - | ||||||||||||
132 | { | - | ||||||||||||
133 | plen = strlen (pfx); | - | ||||||||||||
134 | if (plen > 5) | - | ||||||||||||
135 | plen = 5; | - | ||||||||||||
136 | } | - | ||||||||||||
137 | - | |||||||||||||
138 | if (try_tmpdir) | - | ||||||||||||
139 | { | - | ||||||||||||
140 | d = __secure_getenv ("TMPDIR"); | - | ||||||||||||
141 | if (d != NULL && direxists (d)) | - | ||||||||||||
142 | dir = d; | - | ||||||||||||
143 | else if (dir != NULL && direxists (dir)) | - | ||||||||||||
144 | /* nothing */ ; | - | ||||||||||||
145 | else | - | ||||||||||||
146 | dir = NULL; | - | ||||||||||||
147 | } | - | ||||||||||||
148 | if (dir == NULL) | - | ||||||||||||
149 | { | - | ||||||||||||
150 | if (direxists (P_tmpdir)) | - | ||||||||||||
151 | dir = P_tmpdir; | - | ||||||||||||
152 | else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) | - | ||||||||||||
153 | dir = "/tmp"; | - | ||||||||||||
154 | else | - | ||||||||||||
155 | { | - | ||||||||||||
156 | __set_errno (ENOENT); | - | ||||||||||||
157 | return -1; | - | ||||||||||||
158 | } | - | ||||||||||||
159 | } | - | ||||||||||||
160 | - | |||||||||||||
161 | dlen = strlen (dir); | - | ||||||||||||
162 | while (dlen > 1 && dir[dlen - 1] == '/') | - | ||||||||||||
163 | dlen--; /* remove trailing slashes */ | - | ||||||||||||
164 | - | |||||||||||||
165 | /* check we have room for "${dir}/${pfx}XXXXXX\0" */ | - | ||||||||||||
166 | if (tmpl_len < dlen + 1 + plen + 6 + 1) | - | ||||||||||||
167 | { | - | ||||||||||||
168 | __set_errno (EINVAL); | - | ||||||||||||
169 | return -1; | - | ||||||||||||
170 | } | - | ||||||||||||
171 | - | |||||||||||||
172 | sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); | - | ||||||||||||
173 | return 0; | - | ||||||||||||
174 | } | - | ||||||||||||
175 | #endif /* _LIBC */ | - | ||||||||||||
176 | - | |||||||||||||
177 | static inline bool _GL_ATTRIBUTE_PURE | - | ||||||||||||
178 | check_x_suffix (char const *s, size_t len) | - | ||||||||||||
179 | { | - | ||||||||||||
180 | return len <= strspn (s, "X"); executed 596 times by 4 tests: return len <= __builtin_strspn ( s , "X" ) ; Executed by:
| 596 | ||||||||||||
181 | } | - | ||||||||||||
182 | - | |||||||||||||
183 | /* These are the characters used in temporary file names. */ | - | ||||||||||||
184 | static const char letters[] = | - | ||||||||||||
185 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | - | ||||||||||||
186 | - | |||||||||||||
187 | int | - | ||||||||||||
188 | try_tempname_len (char *tmpl, int suffixlen, void *args, | - | ||||||||||||
189 | int (*tryfunc) (char *, void *), size_t x_suffix_len) | - | ||||||||||||
190 | { | - | ||||||||||||
191 | size_t len; | - | ||||||||||||
192 | char *XXXXXX; | - | ||||||||||||
193 | unsigned int count; | - | ||||||||||||
194 | int fd = -1; | - | ||||||||||||
195 | int save_errno = errno; | - | ||||||||||||
196 | struct randint_source *rand_src; | - | ||||||||||||
197 | - | |||||||||||||
198 | /* A lower bound on the number of temporary files to attempt to | - | ||||||||||||
199 | generate. The maximum total number of temporary file names that | - | ||||||||||||
200 | can exist for a given template is 62**6. It should never be | - | ||||||||||||
201 | necessary to try all of these combinations. Instead if a reasonable | - | ||||||||||||
202 | number of names is tried (we define reasonable as 62**3) fail to | - | ||||||||||||
203 | give the system administrator the chance to remove the problems. | - | ||||||||||||
204 | This value requires that X_SUFFIX_LEN be at least 3. */ | - | ||||||||||||
205 | #define ATTEMPTS_MIN (62 * 62 * 62) | - | ||||||||||||
206 | - | |||||||||||||
207 | /* The number of times to attempt to generate a temporary file. To | - | ||||||||||||
208 | conform to POSIX, this must be no smaller than TMP_MAX. */ | - | ||||||||||||
209 | #if ATTEMPTS_MIN < TMP_MAX | - | ||||||||||||
210 | unsigned int attempts = TMP_MAX; | - | ||||||||||||
211 | #else | - | ||||||||||||
212 | unsigned int attempts = ATTEMPTS_MIN; | - | ||||||||||||
213 | #endif | - | ||||||||||||
214 | - | |||||||||||||
215 | len = strlen (tmpl); | - | ||||||||||||
216 | if (len < x_suffix_len + suffixlen
| 0-596 | ||||||||||||
217 | || ! check_x_suffix (&tmpl[len - x_suffix_len - suffixlen],
| 0-596 | ||||||||||||
218 | x_suffix_len))
| 0-596 | ||||||||||||
219 | { | - | ||||||||||||
220 | __set_errno (EINVAL); | - | ||||||||||||
221 | return -1; never executed: return -1; | 0 | ||||||||||||
222 | } | - | ||||||||||||
223 | - | |||||||||||||
224 | /* This is where the Xs start. */ | - | ||||||||||||
225 | XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; | - | ||||||||||||
226 | - | |||||||||||||
227 | /* Get some more or less random data. */ | - | ||||||||||||
228 | rand_src = randint_all_new (NULL, x_suffix_len); | - | ||||||||||||
229 | if (! rand_src)
| 0-596 | ||||||||||||
230 | return -1; never executed: return -1; | 0 | ||||||||||||
231 | - | |||||||||||||
232 | for (count = 0; count < attempts; ++count)
| 0-596 | ||||||||||||
233 | { | - | ||||||||||||
234 | size_t i; | - | ||||||||||||
235 | - | |||||||||||||
236 | for (i = 0; i < x_suffix_len; i++)
| 596-2470 | ||||||||||||
237 | XXXXXX[i] = letters[randint_genmax (rand_src, sizeof letters - 2)]; executed 2470 times by 4 tests: XXXXXX[i] = letters[randint_genmax (rand_src, sizeof letters - 2)]; Executed by:
| 2470 | ||||||||||||
238 | - | |||||||||||||
239 | fd = tryfunc (tmpl, args); | - | ||||||||||||
240 | if (fd >= 0)
| 2-594 | ||||||||||||
241 | { | - | ||||||||||||
242 | __set_errno (save_errno); | - | ||||||||||||
243 | goto done; executed 594 times by 4 tests: goto done; Executed by:
| 594 | ||||||||||||
244 | } | - | ||||||||||||
245 | else if (errno != EEXIST)
| 0-2 | ||||||||||||
246 | { | - | ||||||||||||
247 | fd = -1; | - | ||||||||||||
248 | goto done; executed 2 times by 2 tests: goto done; Executed by:
| 2 | ||||||||||||
249 | } | - | ||||||||||||
250 | } never executed: end of block | 0 | ||||||||||||
251 | - | |||||||||||||
252 | randint_all_free (rand_src); | - | ||||||||||||
253 | - | |||||||||||||
254 | /* We got out of the loop because we ran out of combinations to try. */ | - | ||||||||||||
255 | __set_errno (EEXIST); | - | ||||||||||||
256 | return -1; never executed: return -1; | 0 | ||||||||||||
257 | - | |||||||||||||
258 | done: | - | ||||||||||||
259 | { | - | ||||||||||||
260 | int saved_errno = errno; | - | ||||||||||||
261 | randint_all_free (rand_src); | - | ||||||||||||
262 | __set_errno (saved_errno); | - | ||||||||||||
263 | } | - | ||||||||||||
264 | return fd; executed 596 times by 4 tests: return fd; Executed by:
| 596 | ||||||||||||
265 | } | - | ||||||||||||
266 | - | |||||||||||||
267 | static int | - | ||||||||||||
268 | try_file (char *tmpl, void *flags) | - | ||||||||||||
269 | { | - | ||||||||||||
270 | int *openflags = flags; | - | ||||||||||||
271 | return __open (tmpl, executed 13 times by 1 test: return open (tmpl, (*openflags & ~ 0003 ) | 02 | 0100 | 0200 , 0400 | 0200 ); Executed by:
| 13 | ||||||||||||
272 | (*openflags & ~O_ACCMODE) executed 13 times by 1 test: return open (tmpl, (*openflags & ~ 0003 ) | 02 | 0100 | 0200 , 0400 | 0200 ); Executed by:
| 13 | ||||||||||||
273 | | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); executed 13 times by 1 test: return open (tmpl, (*openflags & ~ 0003 ) | 02 | 0100 | 0200 , 0400 | 0200 ); Executed by:
| 13 | ||||||||||||
274 | } | - | ||||||||||||
275 | - | |||||||||||||
276 | static int | - | ||||||||||||
277 | try_dir (char *tmpl, void *flags _GL_UNUSED) | - | ||||||||||||
278 | { | - | ||||||||||||
279 | return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); executed 549 times by 1 test: return mkdir (tmpl, 0400 | 0200 | 0100 ); Executed by:
| 549 | ||||||||||||
280 | } | - | ||||||||||||
281 | - | |||||||||||||
282 | static int | - | ||||||||||||
283 | try_nocreate (char *tmpl, void *flags _GL_UNUSED) | - | ||||||||||||
284 | { | - | ||||||||||||
285 | struct_stat64 st; | - | ||||||||||||
286 | - | |||||||||||||
287 | if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW)
| 0-4 | ||||||||||||
288 | __set_errno (EEXIST); never executed: (*__errno_location ()) = ( 17 ); | 0 | ||||||||||||
289 | return errno == ENOENT ? 0 : -1; executed 4 times by 1 test: return (*__errno_location ()) == 2 ? 0 : -1; Executed by:
| 4 | ||||||||||||
290 | } | - | ||||||||||||
291 | - | |||||||||||||
292 | /* Generate a temporary file name based on TMPL. TMPL must match the | - | ||||||||||||
293 | rules for mk[s]temp (i.e., end in at least X_SUFFIX_LEN "X"s, | - | ||||||||||||
294 | possibly with a suffix). | - | ||||||||||||
295 | The name constructed does not exist at the time of the call to | - | ||||||||||||
296 | this function. TMPL is overwritten with the result. | - | ||||||||||||
297 | - | |||||||||||||
298 | KIND may be one of: | - | ||||||||||||
299 | __GT_NOCREATE: simply verify that the name does not exist | - | ||||||||||||
300 | at the time of the call. | - | ||||||||||||
301 | __GT_FILE: create the file using open(O_CREAT|O_EXCL) | - | ||||||||||||
302 | and return a read-write fd. The file is mode 0600. | - | ||||||||||||
303 | __GT_DIR: create a directory, which will be mode 0700. | - | ||||||||||||
304 | - | |||||||||||||
305 | We use a clever algorithm to get hard-to-predict names. */ | - | ||||||||||||
306 | int | - | ||||||||||||
307 | gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, | - | ||||||||||||
308 | size_t x_suffix_len) | - | ||||||||||||
309 | { | - | ||||||||||||
310 | int (*tryfunc) (char *, void *); | - | ||||||||||||
311 | - | |||||||||||||
312 | switch (kind) | - | ||||||||||||
313 | { | - | ||||||||||||
314 | case __GT_FILE: executed 13 times by 1 test: case 0: Executed by:
| 13 | ||||||||||||
315 | tryfunc = try_file; | - | ||||||||||||
316 | break; executed 13 times by 1 test: break; Executed by:
| 13 | ||||||||||||
317 | - | |||||||||||||
318 | case __GT_DIR: executed 549 times by 1 test: case 1: Executed by:
| 549 | ||||||||||||
319 | tryfunc = try_dir; | - | ||||||||||||
320 | break; executed 549 times by 1 test: break; Executed by:
| 549 | ||||||||||||
321 | - | |||||||||||||
322 | case __GT_NOCREATE: executed 4 times by 1 test: case 2: Executed by:
| 4 | ||||||||||||
323 | tryfunc = try_nocreate; | - | ||||||||||||
324 | break; executed 4 times by 1 test: break; Executed by:
| 4 | ||||||||||||
325 | - | |||||||||||||
326 | default: never executed: default: | 0 | ||||||||||||
327 | assert (! "invalid KIND in __gen_tempname"); | - | ||||||||||||
328 | abort (); never executed: abort (); | 0 | ||||||||||||
329 | } | - | ||||||||||||
330 | return try_tempname_len (tmpl, suffixlen, &flags, tryfunc, x_suffix_len); executed 566 times by 1 test: return try_tempname_len (tmpl, suffixlen, &flags, tryfunc, x_suffix_len); Executed by:
| 566 | ||||||||||||
331 | } | - | ||||||||||||
332 | - | |||||||||||||
333 | int | - | ||||||||||||
334 | __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) | - | ||||||||||||
335 | { | - | ||||||||||||
336 | return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); never executed: return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); | 0 | ||||||||||||
337 | } | - | ||||||||||||
338 | - | |||||||||||||
339 | int | - | ||||||||||||
340 | __try_tempname (char *tmpl, int suffixlen, void *args, | - | ||||||||||||
341 | int (*tryfunc) (char *, void *)) | - | ||||||||||||
342 | { | - | ||||||||||||
343 | return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); never executed: return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); | 0 | ||||||||||||
344 | } | - | ||||||||||||
Source code | Switch to Preprocessed file |