diff options
Diffstat (limited to 'gnulib/import/tempname.c')
-rw-r--r-- | gnulib/import/tempname.c | 280 |
1 files changed, 139 insertions, 141 deletions
diff --git a/gnulib/import/tempname.c b/gnulib/import/tempname.c index 0aad061..cfb0fc4 100644 --- a/gnulib/import/tempname.c +++ b/gnulib/import/tempname.c @@ -1,24 +1,22 @@ -/* tempname.c - generate the name of a temporary file. +/* Copyright (C) 1991-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. - Copyright (C) 1991-2003, 2005-2007, 2009-2020 Free Software Foundation, Inc. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. - 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 - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, + The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. -/* Extracted from glibc sysdeps/posix/tempname.c. See also tmpdir.c. */ + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ #if !_LIBC -# include <config.h> +# include <libc-config.h> # include "tempname.h" #endif @@ -26,9 +24,6 @@ #include <assert.h> #include <errno.h> -#ifndef __set_errno -# define __set_errno(Val) errno = (Val) -#endif #include <stdio.h> #ifndef P_tmpdir @@ -52,51 +47,39 @@ #include <string.h> #include <fcntl.h> -#include <sys/time.h> #include <stdint.h> -#include <unistd.h> - +#include <sys/random.h> #include <sys/stat.h> #if _LIBC # define struct_stat64 struct stat64 +# define __secure_getenv __libc_secure_getenv #else # define struct_stat64 struct stat -# define __try_tempname try_tempname # define __gen_tempname gen_tempname -# define __getpid getpid -# define __gettimeofday gettimeofday # define __mkdir mkdir # define __open open # define __lxstat64(version, file, buf) lstat (file, buf) #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 +# include <random-bits.h> +# define RANDOM_BITS(Var) ((Var) = random_bits ()) +typedef uint32_t random_value; +# define RANDOM_VALUE_MAX UINT32_MAX +# define BASE_62_DIGITS 5 /* 62**5 < UINT32_MAX */ +# define BASE_62_POWER (62 * 62 * 62 * 62 * 62) /* 2**BASE_62_DIGITS */ +#else +/* Use getrandom if it works, falling back on a 64-bit linear + congruential generator that starts with whatever Var's value + happens to be. */ +# define RANDOM_BITS(Var) \ + ((void) (getrandom (&(Var), sizeof (Var), 0) == sizeof (Var) \ + || ((Var) = 2862933555777941757 * (Var) + 3037000493))) +typedef uint_fast64_t random_value; +# define RANDOM_VALUE_MAX UINT_FAST64_MAX +# define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */ +# define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) #endif #if _LIBC @@ -172,18 +155,80 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, } #endif /* _LIBC */ +#if _LIBC +static int try_tempname_len (char *, int, void *, int (*) (char *, void *), + size_t); +#endif + +static int +try_file (char *tmpl, void *flags) +{ + int *openflags = flags; + return __open (tmpl, + (*openflags & ~O_ACCMODE) + | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +} + +static int +try_dir (char *tmpl, void *flags _GL_UNUSED) +{ + return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); +} + +static int +try_nocreate (char *tmpl, void *flags _GL_UNUSED) +{ + struct_stat64 st; + + if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW) + __set_errno (EEXIST); + return errno == ENOENT ? 0 : -1; +} + /* 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 at least X_SUFFIX_LEN "X"s, + possibly with a suffix). + The name constructed does not exist at the time of the call to + this function. TMPL is overwritten with the result. + + KIND may be one of: + __GT_NOCREATE: simply verify that the name does not exist + at the time of the call. + __GT_FILE: create the file using open(O_CREAT|O_EXCL) + and return a read-write fd. The file is mode 0600. + __GT_DIR: create a directory, which will be mode 0700. + + We use a clever algorithm to get hard-to-predict names. */ +#ifdef _LIBC +static +#endif int -__try_tempname (char *tmpl, int suffixlen, void *args, - int (*tryfunc) (char *, void *)) +gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, + size_t x_suffix_len) { - int len; + static int (*const tryfunc[]) (char *, void *) = + { + [__GT_FILE] = try_file, + [__GT_DIR] = try_dir, + [__GT_NOCREATE] = try_nocreate + }; + return try_tempname_len (tmpl, suffixlen, &flags, tryfunc[kind], + x_suffix_len); +} + +#ifdef _LIBC +static +#endif +int +try_tempname_len (char *tmpl, int suffixlen, void *args, + int (*tryfunc) (char *, void *), size_t x_suffix_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; @@ -193,7 +238,8 @@ __try_tempname (char *tmpl, int suffixlen, void *args, can exist for a given template is 62**6. It should never be necessary to try all of these combinations. Instead if a reasonable number of names is tried (we define reasonable as 62**3) fail to - give the system administrator the chance to remove the problems. */ + give the system administrator the chance to remove the problems. + This value requires that X_SUFFIX_LEN be at least 3. */ #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To @@ -204,44 +250,45 @@ __try_tempname (char *tmpl, int suffixlen, void *args, unsigned int attempts = ATTEMPTS_MIN; #endif + /* A random variable. */ + random_value v; + + /* How many random base-62 digits can currently be extracted from V. */ + int vdigits = 0; + + /* Least unfair value for V. If V is less than this, V can generate + BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ + random_value const unfair_min + = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER; + len = strlen (tmpl); - if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) + if (len < x_suffix_len + suffixlen + || strspn (&tmpl[len - x_suffix_len - suffixlen], "X") < x_suffix_len) { __set_errno (EINVAL); return -1; } /* This is where the Xs start. */ - XXXXXX = &tmpl[len - 6 - suffixlen]; - - /* 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 (); + XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; - 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]; + for (size_t i = 0; i < x_suffix_len; i++) + { + if (vdigits == 0) + { + do + RANDOM_BITS (v); + while (unfair_min <= v); + + vdigits = BASE_62_DIGITS; + } + + XXXXXX[i] = letters[v % 62]; + v /= 62; + vdigits--; + } fd = tryfunc (tmpl, args); if (fd >= 0) @@ -258,66 +305,17 @@ __try_tempname (char *tmpl, int suffixlen, void *args, return -1; } -static int -try_file (char *tmpl, void *flags) -{ - int *openflags = flags; - return __open (tmpl, - (*openflags & ~O_ACCMODE) - | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); -} - -static int -try_dir (char *tmpl, void *flags _GL_UNUSED) -{ - return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); -} - -static int -try_nocreate (char *tmpl, void *flags _GL_UNUSED) +int +__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) { - struct_stat64 st; - - if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW) - __set_errno (EEXIST); - return errno == ENOENT ? 0 : -1; + return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); } -/* Generate a temporary file name based on TMPL. TMPL must match the - rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). - The name constructed does not exist at the time of the call to - __gen_tempname. TMPL is overwritten with the result. - - KIND may be one of: - __GT_NOCREATE: simply verify that the name does not exist - at the time of the call. - __GT_FILE: create the file using open(O_CREAT|O_EXCL) - and return a read-write fd. The file is mode 0600. - __GT_DIR: create a directory, which will be mode 0700. - - We use a clever algorithm to get hard-to-predict names. */ +#if !_LIBC int -__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) +try_tempname (char *tmpl, int suffixlen, void *args, + int (*tryfunc) (char *, void *)) { - int (*tryfunc) (char *, void *); - - switch (kind) - { - case __GT_FILE: - tryfunc = try_file; - break; - - case __GT_DIR: - tryfunc = try_dir; - break; - - case __GT_NOCREATE: - tryfunc = try_nocreate; - break; - - default: - assert (! "invalid KIND in __gen_tempname"); - abort (); - } - return __try_tempname (tmpl, suffixlen, &flags, tryfunc); + return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); } +#endif |