diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | gl/lib/tempname.c | 125 | ||||
-rw-r--r-- | gl/lib/tempname.h | 4 | ||||
-rw-r--r-- | gl/modules/tempname | 4 |
4 files changed, 78 insertions, 71 deletions
@@ -1,5 +1,21 @@ 2007-10-07 Jim Meyering <meyering@redhat.com> + Make tempname more random, via the randint module. + * gl/modules/tempname (Depends-on): Add randint and stdbool. + * gl/lib/tempname.c: Include randint.h and stdbool.h. + (uint64_t): Remove definition. Not needed. + [_LIBC] (RANDOM_BITS): Remove this block, now that we have proper + random bits. + (check_x_suffix): New function. + (gen_tempname_len): Rename from __gen_tempname. + Add a parameter, x_suffix_len, telling how many X's there must be at + the end of the template. + Use pseudo-random numbers all the way, rather than adding 7777 + from one iteration to the next. + (__gen_tempname): New function, to call gen_tempname_len, requiring a + suffix length of 6. + * gl/lib/tempname.h: Add prototype for gen_tempname_len. + Convert coreutils' rand*.{c,h,m4} into modules. First step: move these files to gl/lib: * lib/rand-isaac.c, lib/rand-isaac.h diff --git a/gl/lib/tempname.c b/gl/lib/tempname.c index e213600e3..14eddd908 100644 --- a/gl/lib/tempname.c +++ b/gl/lib/tempname.c @@ -23,6 +23,7 @@ #if !_LIBC # include <config.h> # include "tempname.h" +# include "randint.h" #endif #include <sys/types.h> @@ -47,6 +48,7 @@ # define __GT_NOCREATE 3 #endif +#include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -78,34 +80,6 @@ # define __secure_getenv getenv #endif -#ifdef _LIBC -# include <hp-timing.h> -# if HP_TIMING_AVAIL -# define RANDOM_BITS(Var) \ - if (__builtin_expect (value == UINT64_C (0), 0)) \ - { \ - /* If this is the first time this function is used initialize \ - the variable we accumulate the value in to some somewhat \ - random value. If we'd not do this programs at startup time \ - might have a reduced set of possible names, at least on slow \ - machines. */ \ - struct timeval tv; \ - __gettimeofday (&tv, NULL); \ - value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ - } \ - HP_TIMING_NOW (Var) -# endif -#endif - -/* Use the widest available unsigned type if uint64_t is not - available. The algorithm below extracts a number less than 62**6 - (approximately 2**35.725) from uint64_t, so ancient hosts where - uintmax_t is only 32 bits lose about 3.725 bits of randomness, - which is better than not having mkstemp at all. */ -#if !defined UINT64_MAX && !defined uint64_t -# define uint64_t uintmax_t -#endif - #if _LIBC /* Return nonzero if DIR is an existent directory. */ static int @@ -179,12 +153,18 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, } #endif /* _LIBC */ +static inline bool +check_x_suffix (char const *s, size_t len) +{ + return strspn (s, "X") == len; +} + /* These are the characters used in temporary file names. */ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -/* Generate a temporary file name based on TMPL. TMPL must match the - rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed +/* Generate a temporary file name based on TMPL. TMPL must end in a + a sequence of at least X_SUFFIX_LEN "X"s. The name constructed does not exist at the time of the call to __gen_tempname. TMPL is overwritten with the result. @@ -198,16 +178,15 @@ static const char letters[] = We use a clever algorithm to get hard-to-predict names. */ int -__gen_tempname (char *tmpl, int kind) +gen_tempname_len (char *tmpl, int kind, size_t x_suffix_len) { - int len; + size_t len; char *XXXXXX; - static uint64_t value; - uint64_t random_time_bits; unsigned int count; int fd = -1; int save_errno = errno; struct_stat64 st; + struct randint_source *rand_src; /* A lower bound on the number of temporary files to attempt to generate. The maximum total number of temporary file names that @@ -226,43 +205,28 @@ __gen_tempname (char *tmpl, int kind) #endif len = strlen (tmpl); - if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) + if (len < x_suffix_len || ! check_x_suffix (&tmpl[len - x_suffix_len], + x_suffix_len)) { __set_errno (EINVAL); return -1; } - /* This is where the Xs start. */ - XXXXXX = &tmpl[len - 6]; + rand_src = randint_all_new (NULL, 8); + if (! rand_src) + return -1; - /* Get some more or less random data. */ -#ifdef RANDOM_BITS - RANDOM_BITS (random_time_bits); -#else - { - struct timeval tv; - __gettimeofday (&tv, NULL); - random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; - } -#endif - value += random_time_bits ^ __getpid (); + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - x_suffix_len]; - for (count = 0; count < attempts; value += 7777, ++count) + for (count = 0; count < attempts; ++count) { - uint64_t v = value; - - /* Fill in the random bits. */ - XXXXXX[0] = letters[v % 62]; - v /= 62; - XXXXXX[1] = letters[v % 62]; - v /= 62; - XXXXXX[2] = letters[v % 62]; - v /= 62; - XXXXXX[3] = letters[v % 62]; - v /= 62; - XXXXXX[4] = letters[v % 62]; - v /= 62; - XXXXXX[5] = letters[v % 62]; + size_t i; + + for (i = 0; i < x_suffix_len; i++) + { + XXXXXX[i] = letters[randint_genmax (rand_src, sizeof letters - 2)]; + } switch (kind) { @@ -279,7 +243,7 @@ __gen_tempname (char *tmpl, int kind) break; case __GT_NOCREATE: - /* This case is backward from the other three. __gen_tempname + /* This case is backward from the other three. This function succeeds if __xstat fails because the name does not exist. Note the continue to bypass the common logic at the bottom of the loop. */ @@ -288,11 +252,15 @@ __gen_tempname (char *tmpl, int kind) if (errno == ENOENT) { __set_errno (save_errno); - return 0; + fd = 0; + goto done; } else - /* Give up now. */ - return -1; + { + /* Give up now. */ + fd = -1; + goto done; + } } continue; @@ -303,13 +271,32 @@ __gen_tempname (char *tmpl, int kind) if (fd >= 0) { __set_errno (save_errno); - return fd; + goto done; } else if (errno != EEXIST) - return -1; + { + fd = -1; + goto done; + } } + randint_all_free (rand_src); + /* We got out of the loop because we ran out of combinations to try. */ __set_errno (EEXIST); return -1; + + done: + { + int saved_errno = errno; + randint_all_free (rand_src); + __set_errno (saved_errno); + } + return fd; +} + +int +__gen_tempname (char *tmpl, int kind) +{ + return gen_tempname_len (tmpl, kind, 6); } diff --git a/gl/lib/tempname.h b/gl/lib/tempname.h index c51fa6942..4e0469b3f 100644 --- a/gl/lib/tempname.h +++ b/gl/lib/tempname.h @@ -1,6 +1,6 @@ /* Create a temporary file or directory. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,4 +37,6 @@ GT_DIR: create a directory, which will be mode 0700. We use a clever algorithm to get hard-to-predict names. */ +#include <stddef.h> extern int gen_tempname (char *tmpl, int kind); +extern int gen_tempname_len (char *tmpl, int kind, size_t x_suffix_len); diff --git a/gl/modules/tempname b/gl/modules/tempname index af689de6f..3d8431796 100644 --- a/gl/modules/tempname +++ b/gl/modules/tempname @@ -1,5 +1,5 @@ Description: -gen_tempname() function: create a private temporary file or directory. +gen_tempname, gen_tempname_len: create a private temporary file or directory. Files: lib/tempname.c @@ -9,6 +9,8 @@ m4/tempname.m4 Depends-on: extensions gettimeofday +randint +stdbool stdint sys_stat sys_time |