Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/tempname.c @ 9928:9a02133ad731
Add tentative support for Linux libc5.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Thu, 17 Apr 2008 02:01:23 +0200 |
parents | bbbbbf4cd1c5 |
children | 52791eb62094 |
rev | line source |
---|---|
4020 | 1 /* tempname.c - generate the name of a temporary file. |
3192 | 2 |
4020 | 3 Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
7897
b7a83a69ac23
* MODULES.html.sh (Support for systems lacking POSIX:2001): New
Paul Eggert <eggert@cs.ucla.edu>
parents:
7630
diff
changeset
|
4 2000, 2001, 2002, 2003, 2005, 2006, 2007 Free Software Foundation, |
b7a83a69ac23
* MODULES.html.sh (Support for systems lacking POSIX:2001): New
Paul Eggert <eggert@cs.ucla.edu>
parents:
7630
diff
changeset
|
5 Inc. |
3192 | 6 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7897
diff
changeset
|
7 This program is free software: you can redistribute it and/or modify |
4020 | 8 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7897
diff
changeset
|
9 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7897
diff
changeset
|
10 (at your option) any later version. |
3192 | 11 |
4020 | 12 This program is distributed in the hope that it will be useful, |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7897
diff
changeset
|
17 You should have received a copy of the GNU General Public License |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7897
diff
changeset
|
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
3192 | 19 |
7575
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
20 /* Extracted from glibc sysdeps/posix/tempname.c. See also tmpdir.c. */ |
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
21 |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
7162
diff
changeset
|
22 #if !_LIBC |
3192 | 23 # include <config.h> |
7575
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
24 # include "tempname.h" |
3192 | 25 #endif |
26 | |
27 #include <sys/types.h> | |
28 #include <assert.h> | |
29 | |
30 #include <errno.h> | |
31 #ifndef __set_errno | |
32 # define __set_errno(Val) errno = (Val) | |
33 #endif | |
34 | |
35 #include <stdio.h> | |
36 #ifndef P_tmpdir | |
37 # define P_tmpdir "/tmp" | |
38 #endif | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
39 #ifndef TMP_MAX |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
40 # define TMP_MAX 238328 |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
41 #endif |
3192 | 42 #ifndef __GT_FILE |
43 # define __GT_FILE 0 | |
44 # define __GT_BIGFILE 1 | |
45 # define __GT_DIR 2 | |
46 # define __GT_NOCREATE 3 | |
47 #endif | |
48 | |
4333 | 49 #include <stddef.h> |
3654
60143dd95a31
Include stdlib.h unconditionally. On some old systems for which
Jim Meyering <jim@meyering.net>
parents:
3653
diff
changeset
|
50 #include <stdlib.h> |
4691 | 51 #include <string.h> |
3654
60143dd95a31
Include stdlib.h unconditionally. On some old systems for which
Jim Meyering <jim@meyering.net>
parents:
3653
diff
changeset
|
52 |
5955
ace6ea191424
Assume HAVE_FCNTL_H (i.e., include <fcntl.h> unconditionally,
Jim Meyering <jim@meyering.net>
parents:
5907
diff
changeset
|
53 #include <fcntl.h> |
7897
b7a83a69ac23
* MODULES.html.sh (Support for systems lacking POSIX:2001): New
Paul Eggert <eggert@cs.ucla.edu>
parents:
7630
diff
changeset
|
54 #include <sys/time.h> |
7162
19c2e5121b2f
Add and change modules to make it easier for coreutils to use
Paul Eggert <eggert@cs.ucla.edu>
parents:
6806
diff
changeset
|
55 #include <stdint.h> |
6275 | 56 #include <unistd.h> |
3192 | 57 |
58 #include <sys/stat.h> | |
59 | |
60 #if _LIBC | |
61 # define struct_stat64 struct stat64 | |
6806
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
62 # define small_open __open |
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
63 # define large_open __open64 |
3192 | 64 #else |
65 # define struct_stat64 struct stat | |
6806
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
66 # define small_open open |
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
67 # define large_open open |
7575
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
68 # define __gen_tempname gen_tempname |
3192 | 69 # define __getpid getpid |
70 # define __gettimeofday gettimeofday | |
71 # define __mkdir mkdir | |
5907 | 72 # define __lxstat64(version, file, buf) lstat (file, buf) |
73 # define __xstat64(version, file, buf) stat (file, buf) | |
3192 | 74 #endif |
75 | |
76 #if ! (HAVE___SECURE_GETENV || _LIBC) | |
77 # define __secure_getenv getenv | |
78 #endif | |
79 | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
80 #ifdef _LIBC |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
81 # include <hp-timing.h> |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
82 # if HP_TIMING_AVAIL |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
83 # define RANDOM_BITS(Var) \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
84 if (__builtin_expect (value == UINT64_C (0), 0)) \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
85 { \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
86 /* If this is the first time this function is used initialize \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
87 the variable we accumulate the value in to some somewhat \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
88 random value. If we'd not do this programs at startup time \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
89 might have a reduced set of possible names, at least on slow \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
90 machines. */ \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
91 struct timeval tv; \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
92 __gettimeofday (&tv, NULL); \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
93 value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
94 } \ |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
95 HP_TIMING_NOW (Var) |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
96 # endif |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
97 #endif |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
98 |
3212
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
99 /* Use the widest available unsigned type if uint64_t is not |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
100 available. The algorithm below extracts a number less than 62**6 |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
101 (approximately 2**35.725) from uint64_t, so ancient hosts where |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
102 uintmax_t is only 32 bits lose about 3.725 bits of randomness, |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
103 which is better than not having mkstemp at all. */ |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
104 #if !defined UINT64_MAX && !defined uint64_t |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
105 # define uint64_t uintmax_t |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
106 #endif |
c211485f2a93
(uint64_t): Define to uintmax_t if
Jim Meyering <jim@meyering.net>
parents:
3192
diff
changeset
|
107 |
7575
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
108 #if _LIBC |
3192 | 109 /* Return nonzero if DIR is an existent directory. */ |
110 static int | |
111 direxists (const char *dir) | |
112 { | |
113 struct_stat64 buf; | |
114 return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); | |
115 } | |
116 | |
117 /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is | |
118 non-null and exists, uses it; otherwise uses the first of $TMPDIR, | |
119 P_tmpdir, /tmp that exists. Copies into TMPL a template suitable | |
120 for use with mk[s]temp. Will fail (-1) if DIR is non-null and | |
121 doesn't exist, none of the searched dirs exists, or there's not | |
122 enough space in TMPL. */ | |
123 int | |
124 __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, | |
125 int try_tmpdir) | |
126 { | |
127 const char *d; | |
128 size_t dlen, plen; | |
129 | |
130 if (!pfx || !pfx[0]) | |
131 { | |
132 pfx = "file"; | |
133 plen = 4; | |
134 } | |
135 else | |
136 { | |
137 plen = strlen (pfx); | |
138 if (plen > 5) | |
139 plen = 5; | |
140 } | |
141 | |
142 if (try_tmpdir) | |
143 { | |
144 d = __secure_getenv ("TMPDIR"); | |
145 if (d != NULL && direxists (d)) | |
146 dir = d; | |
147 else if (dir != NULL && direxists (dir)) | |
148 /* nothing */ ; | |
149 else | |
150 dir = NULL; | |
151 } | |
152 if (dir == NULL) | |
153 { | |
154 if (direxists (P_tmpdir)) | |
155 dir = P_tmpdir; | |
156 else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) | |
157 dir = "/tmp"; | |
158 else | |
159 { | |
160 __set_errno (ENOENT); | |
161 return -1; | |
162 } | |
163 } | |
164 | |
165 dlen = strlen (dir); | |
166 while (dlen > 1 && dir[dlen - 1] == '/') | |
167 dlen--; /* remove trailing slashes */ | |
168 | |
169 /* check we have room for "${dir}/${pfx}XXXXXX\0" */ | |
170 if (tmpl_len < dlen + 1 + plen + 6 + 1) | |
171 { | |
172 __set_errno (EINVAL); | |
173 return -1; | |
174 } | |
175 | |
176 sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); | |
177 return 0; | |
178 } | |
7575
483757159eb6
* MODULES.html.sh: Document tempname.
Eric Blake <ebb9@byu.net>
parents:
7337
diff
changeset
|
179 #endif /* _LIBC */ |
3192 | 180 |
5907 | 181 /* These are the characters used in temporary file names. */ |
3192 | 182 static const char letters[] = |
183 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |
184 | |
185 /* Generate a temporary file name based on TMPL. TMPL must match the | |
186 rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed | |
187 does not exist at the time of the call to __gen_tempname. TMPL is | |
188 overwritten with the result. | |
189 | |
190 KIND may be one of: | |
191 __GT_NOCREATE: simply verify that the name does not exist | |
192 at the time of the call. | |
193 __GT_FILE: create the file using open(O_CREAT|O_EXCL) | |
194 and return a read-write fd. The file is mode 0600. | |
195 __GT_BIGFILE: same as __GT_FILE but use open64(). | |
196 __GT_DIR: create a directory, which will be mode 0700. | |
197 | |
198 We use a clever algorithm to get hard-to-predict names. */ | |
199 int | |
200 __gen_tempname (char *tmpl, int kind) | |
201 { | |
202 int len; | |
203 char *XXXXXX; | |
204 static uint64_t value; | |
205 uint64_t random_time_bits; | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
206 unsigned int count; |
3635
2fb7a999ebce
(TMP_MAX): Remove; no longer needed.
Jim Meyering <jim@meyering.net>
parents:
3625
diff
changeset
|
207 int fd = -1; |
3192 | 208 int save_errno = errno; |
209 struct_stat64 st; | |
210 | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
211 /* A lower bound on the number of temporary files to attempt to |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
212 generate. The maximum total number of temporary file names that |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
213 can exist for a given template is 62**6. It should never be |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
214 necessary to try all these combinations. Instead if a reasonable |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
215 number of names is tried (we define reasonable as 62**3) fail to |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
216 give the system administrator the chance to remove the problems. */ |
7337
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
217 #define ATTEMPTS_MIN (62 * 62 * 62) |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
218 |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
219 /* The number of times to attempt to generate a temporary file. To |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
220 conform to POSIX, this must be no smaller than TMP_MAX. */ |
7337
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
221 #if ATTEMPTS_MIN < TMP_MAX |
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
222 unsigned int attempts = TMP_MAX; |
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
223 #else |
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
224 unsigned int attempts = ATTEMPTS_MIN; |
1735329d8bfd
* tempname.c (__gen_tempname): Change attempts_min
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
225 #endif |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
226 |
3192 | 227 len = strlen (tmpl); |
228 if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) | |
229 { | |
230 __set_errno (EINVAL); | |
231 return -1; | |
232 } | |
233 | |
234 /* This is where the Xs start. */ | |
235 XXXXXX = &tmpl[len - 6]; | |
236 | |
237 /* Get some more or less random data. */ | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
238 #ifdef RANDOM_BITS |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
239 RANDOM_BITS (random_time_bits); |
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
240 #else |
3192 | 241 { |
242 struct timeval tv; | |
243 __gettimeofday (&tv, NULL); | |
244 random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; | |
245 } | |
246 #endif | |
247 value += random_time_bits ^ __getpid (); | |
248 | |
3653
574daaf59139
Merge with version from libc.
Jim Meyering <jim@meyering.net>
parents:
3635
diff
changeset
|
249 for (count = 0; count < attempts; value += 7777, ++count) |
3192 | 250 { |
251 uint64_t v = value; | |
252 | |
253 /* Fill in the random bits. */ | |
254 XXXXXX[0] = letters[v % 62]; | |
255 v /= 62; | |
256 XXXXXX[1] = letters[v % 62]; | |
257 v /= 62; | |
258 XXXXXX[2] = letters[v % 62]; | |
259 v /= 62; | |
260 XXXXXX[3] = letters[v % 62]; | |
261 v /= 62; | |
262 XXXXXX[4] = letters[v % 62]; | |
263 v /= 62; | |
264 XXXXXX[5] = letters[v % 62]; | |
265 | |
266 switch (kind) | |
267 { | |
268 case __GT_FILE: | |
6806
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
269 fd = small_open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); |
3192 | 270 break; |
271 | |
272 case __GT_BIGFILE: | |
6806
de733e4fedea
* tempname.c (small_open, large_open): New macros.
Paul Eggert <eggert@cs.ucla.edu>
parents:
6275
diff
changeset
|
273 fd = large_open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); |
3192 | 274 break; |
275 | |
276 case __GT_DIR: | |
277 fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); | |
278 break; | |
279 | |
280 case __GT_NOCREATE: | |
281 /* This case is backward from the other three. __gen_tempname | |
282 succeeds if __xstat fails because the name does not exist. | |
283 Note the continue to bypass the common logic at the bottom | |
284 of the loop. */ | |
285 if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) | |
286 { | |
287 if (errno == ENOENT) | |
288 { | |
289 __set_errno (save_errno); | |
290 return 0; | |
291 } | |
292 else | |
293 /* Give up now. */ | |
294 return -1; | |
295 } | |
296 continue; | |
297 | |
298 default: | |
299 assert (! "invalid KIND in __gen_tempname"); | |
300 } | |
301 | |
302 if (fd >= 0) | |
303 { | |
304 __set_errno (save_errno); | |
305 return fd; | |
306 } | |
307 else if (errno != EEXIST) | |
308 return -1; | |
309 } | |
310 | |
311 /* We got out of the loop because we ran out of combinations to try. */ | |
312 __set_errno (EEXIST); | |
313 return -1; | |
314 } |