tempname.c 9.0 KB

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