rm, du, chmod, chown, chgrp: use much less memory for large directories
[coreutils/ericb.git] / gl / lib / tempname.c.diff
blob3e30c972c2a34c4123e3d054371fec0fcfb860b4
1 diff --git c/lib/tempname.c i/lib/tempname.c
2 index 2da5afe..562955a 100644
3 --- c/lib/tempname.c
4 +++ i/lib/tempname.c
5 @@ -22,6 +22,7 @@
6 #if !_LIBC
7 # include <config.h>
8 # include "tempname.h"
9 +# include "randint.h"
10 #endif
12 #include <sys/types.h>
13 @@ -49,6 +50,7 @@
14 # error report this to bug-gnulib@gnu.org
15 #endif
17 +#include <stdbool.h>
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include <string.h>
21 @@ -179,14 +181,21 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
23 #endif /* _LIBC */
25 +static inline bool _GL_ATTRIBUTE_PURE
26 +check_x_suffix (char const *s, size_t len)
28 + return len <= strspn (s, "X");
31 /* These are the characters used in temporary file names. */
32 static const char letters[] =
33 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
35 /* Generate a temporary file name based on TMPL. TMPL must match the
36 - rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix).
37 + rules for mk[s]temp (i.e. end in at least X_SUFFIX_LEN "X"s,
38 + possibly with a suffix).
39 The name constructed does not exist at the time of the call to
40 - __gen_tempname. TMPL is overwritten with the result.
41 + this function. TMPL is overwritten with the result.
43 KIND may be one of:
44 __GT_NOCREATE: simply verify that the name does not exist
45 @@ -197,23 +206,24 @@ static const char letters[] =
47 We use a clever algorithm to get hard-to-predict names. */
48 int
49 -__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
50 +gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind,
51 + size_t x_suffix_len)
53 - int len;
54 + size_t len;
55 char *XXXXXX;
56 - static uint64_t value;
57 - uint64_t random_time_bits;
58 unsigned int count;
59 int fd = -1;
60 int save_errno = errno;
61 struct_stat64 st;
62 + struct randint_source *rand_src;
64 /* A lower bound on the number of temporary files to attempt to
65 generate. The maximum total number of temporary file names that
66 can exist for a given template is 62**6. It should never be
67 necessary to try all these combinations. Instead if a reasonable
68 number of names is tried (we define reasonable as 62**3) fail to
69 - give the system administrator the chance to remove the problems. */
70 + give the system administrator the chance to remove the problems.
71 + This value requires that X_SUFFIX_LEN be at least 3. */
72 #define ATTEMPTS_MIN (62 * 62 * 62)
74 /* The number of times to attempt to generate a temporary file. To
75 @@ -225,43 +235,28 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
76 #endif
78 len = strlen (tmpl);
79 - if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6))
80 + if (len < x_suffix_len + suffixlen
81 + || ! check_x_suffix (&tmpl[len - x_suffix_len - suffixlen],
82 + x_suffix_len))
84 __set_errno (EINVAL);
85 return -1;
88 /* This is where the Xs start. */
89 - XXXXXX = &tmpl[len - 6 - suffixlen];
90 + XXXXXX = &tmpl[len - x_suffix_len - suffixlen];
92 /* Get some more or less random data. */
93 -#ifdef RANDOM_BITS
94 - RANDOM_BITS (random_time_bits);
95 -#else
96 - {
97 - struct timeval tv;
98 - __gettimeofday (&tv, NULL);
99 - random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
101 -#endif
102 - value += random_time_bits ^ __getpid ();
103 + rand_src = randint_all_new (NULL, x_suffix_len);
104 + if (! rand_src)
105 + return -1;
107 - for (count = 0; count < attempts; value += 7777, ++count)
108 + for (count = 0; count < attempts; ++count)
110 - uint64_t v = value;
112 - /* Fill in the random bits. */
113 - XXXXXX[0] = letters[v % 62];
114 - v /= 62;
115 - XXXXXX[1] = letters[v % 62];
116 - v /= 62;
117 - XXXXXX[2] = letters[v % 62];
118 - v /= 62;
119 - XXXXXX[3] = letters[v % 62];
120 - v /= 62;
121 - XXXXXX[4] = letters[v % 62];
122 - v /= 62;
123 - XXXXXX[5] = letters[v % 62];
124 + size_t i;
126 + for (i = 0; i < x_suffix_len; i++)
127 + XXXXXX[i] = letters[randint_genmax (rand_src, sizeof letters - 2)];
129 switch (kind)
131 @@ -276,7 +271,7 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
132 break;
134 case __GT_NOCREATE:
135 - /* This case is backward from the other three. __gen_tempname
136 + /* This case is backward from the other three. This function
137 succeeds if __xstat fails because the name does not exist.
138 Note the continue to bypass the common logic at the bottom
139 of the loop. */
140 @@ -285,11 +280,15 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
141 if (errno == ENOENT)
143 __set_errno (save_errno);
144 - return 0;
145 + fd = 0;
146 + goto done;
148 else
149 - /* Give up now. */
150 - return -1;
152 + /* Give up now. */
153 + fd = -1;
154 + goto done;
157 continue;
159 @@ -301,13 +300,32 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
160 if (fd >= 0)
162 __set_errno (save_errno);
163 - return fd;
164 + goto done;
166 else if (errno != EEXIST)
167 - return -1;
169 + fd = -1;
170 + goto done;
174 + randint_all_free (rand_src);
176 /* We got out of the loop because we ran out of combinations to try. */
177 __set_errno (EEXIST);
178 return -1;
180 + done:
182 + int saved_errno = errno;
183 + randint_all_free (rand_src);
184 + __set_errno (saved_errno);
186 + return fd;
189 +int
190 +__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
192 + return gen_tempname_len (tmpl, suffixlen, flags, kind, 6);