make-temp-file.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /* Utility to pick a temporary filename prefix.
  2. Copyright (C) 1996-2022 Free Software Foundation, Inc.
  3. This file is part of the libiberty library.
  4. Libiberty is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. Libiberty is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with libiberty; see the file COPYING.LIB. If not,
  14. write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  15. Boston, MA 02110-1301, USA. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include <stdio.h> /* May get P_tmpdir. */
  20. #include <sys/types.h>
  21. #include <errno.h>
  22. #ifdef HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #ifdef HAVE_STDLIB_H
  26. #include <stdlib.h>
  27. #endif
  28. #ifdef HAVE_STRING_H
  29. #include <string.h>
  30. #endif
  31. #ifdef HAVE_SYS_FILE_H
  32. #include <sys/file.h> /* May get R_OK, etc. on some systems. */
  33. #endif
  34. #if defined(_WIN32) && !defined(__CYGWIN__)
  35. #include <windows.h>
  36. #endif
  37. #if HAVE_SYS_STAT_H
  38. #include <sys/stat.h>
  39. #endif
  40. #ifndef R_OK
  41. #define R_OK 4
  42. #define W_OK 2
  43. #define X_OK 1
  44. #endif
  45. #include "libiberty.h"
  46. extern int mkstemps (char *, int);
  47. /* '/' works just fine on MS-DOS based systems. */
  48. #ifndef DIR_SEPARATOR
  49. #define DIR_SEPARATOR '/'
  50. #endif
  51. /* Name of temporary file.
  52. mktemp requires 6 trailing X's. */
  53. #define TEMP_FILE "XXXXXX"
  54. #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
  55. #if !defined(_WIN32) || defined(__CYGWIN__)
  56. /* Subroutine of choose_tmpdir.
  57. If BASE is non-NULL, return it.
  58. Otherwise it checks if DIR is a usable directory.
  59. If success, DIR is returned.
  60. Otherwise NULL is returned. */
  61. static inline const char *try_dir (const char *, const char *);
  62. static inline const char *
  63. try_dir (const char *dir, const char *base)
  64. {
  65. if (base != 0)
  66. return base;
  67. if (dir != 0
  68. && access (dir, R_OK | W_OK | X_OK) == 0)
  69. {
  70. /* Check to make sure dir is actually a directory. */
  71. #ifdef S_ISDIR
  72. struct stat s;
  73. if (stat (dir, &s))
  74. return NULL;
  75. if (!S_ISDIR (s.st_mode))
  76. return NULL;
  77. #endif
  78. return dir;
  79. }
  80. return 0;
  81. }
  82. static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
  83. static const char vartmp[] =
  84. { DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
  85. #endif
  86. static char *memoized_tmpdir;
  87. /*
  88. @deftypefn Replacement const char* choose_tmpdir ()
  89. Returns a pointer to a directory path suitable for creating temporary
  90. files in.
  91. @end deftypefn
  92. */
  93. const char *
  94. choose_tmpdir (void)
  95. {
  96. if (!memoized_tmpdir)
  97. {
  98. #if !defined(_WIN32) || defined(__CYGWIN__)
  99. const char *base = 0;
  100. char *tmpdir;
  101. unsigned int len;
  102. #ifdef VMS
  103. /* Try VMS standard temp logical. */
  104. base = try_dir ("/sys$scratch", base);
  105. #else
  106. base = try_dir (getenv ("TMPDIR"), base);
  107. base = try_dir (getenv ("TMP"), base);
  108. base = try_dir (getenv ("TEMP"), base);
  109. #endif
  110. #ifdef P_tmpdir
  111. /* We really want a directory name here as if concatenated with say \dir
  112. we do not end up with a double \\ which defines an UNC path. */
  113. if (strcmp (P_tmpdir, "\\") == 0)
  114. base = try_dir ("\\.", base);
  115. else
  116. base = try_dir (P_tmpdir, base);
  117. #endif
  118. /* Try /var/tmp, then /tmp. */
  119. base = try_dir (vartmp, base);
  120. base = try_dir (tmp, base);
  121. /* If all else fails, use the current directory! */
  122. if (base == 0)
  123. base = ".";
  124. /* Append DIR_SEPARATOR to the directory we've chosen
  125. and return it. */
  126. len = strlen (base);
  127. tmpdir = XNEWVEC (char, len + 2);
  128. strcpy (tmpdir, base);
  129. tmpdir[len] = DIR_SEPARATOR;
  130. tmpdir[len+1] = '\0';
  131. memoized_tmpdir = tmpdir;
  132. #else /* defined(_WIN32) && !defined(__CYGWIN__) */
  133. DWORD len;
  134. /* Figure out how much space we need. */
  135. len = GetTempPath(0, NULL);
  136. if (len)
  137. {
  138. memoized_tmpdir = XNEWVEC (char, len);
  139. if (!GetTempPath(len, memoized_tmpdir))
  140. {
  141. XDELETEVEC (memoized_tmpdir);
  142. memoized_tmpdir = NULL;
  143. }
  144. }
  145. if (!memoized_tmpdir)
  146. /* If all else fails, use the current directory. */
  147. memoized_tmpdir = xstrdup (".\\");
  148. #endif /* defined(_WIN32) && !defined(__CYGWIN__) */
  149. }
  150. return memoized_tmpdir;
  151. }
  152. /*
  153. @deftypefn Replacement char* make_temp_file (const char *@var{suffix})
  154. Return a temporary file name (as a string) or @code{NULL} if unable to
  155. create one. @var{suffix} is a suffix to append to the file name. The
  156. string is @code{malloc}ed, and the temporary file has been created.
  157. @end deftypefn
  158. */
  159. char *
  160. make_temp_file_with_prefix (const char *prefix, const char *suffix)
  161. {
  162. const char *base = choose_tmpdir ();
  163. char *temp_filename;
  164. int base_len, suffix_len, prefix_len;
  165. int fd;
  166. if (prefix == 0)
  167. prefix = "cc";
  168. if (suffix == 0)
  169. suffix = "";
  170. base_len = strlen (base);
  171. prefix_len = strlen (prefix);
  172. suffix_len = strlen (suffix);
  173. temp_filename = XNEWVEC (char, base_len
  174. + TEMP_FILE_LEN
  175. + suffix_len
  176. + prefix_len + 1);
  177. strcpy (temp_filename, base);
  178. strcpy (temp_filename + base_len, prefix);
  179. strcpy (temp_filename + base_len + prefix_len, TEMP_FILE);
  180. strcpy (temp_filename + base_len + prefix_len + TEMP_FILE_LEN, suffix);
  181. fd = mkstemps (temp_filename, suffix_len);
  182. /* Mkstemps failed. It may be EPERM, ENOSPC etc. */
  183. if (fd == -1)
  184. {
  185. fprintf (stderr, "Cannot create temporary file in %s: %s\n",
  186. base, strerror (errno));
  187. abort ();
  188. }
  189. /* We abort on failed close out of sheer paranoia. */
  190. if (close (fd))
  191. abort ();
  192. return temp_filename;
  193. }
  194. char *
  195. make_temp_file (const char *suffix)
  196. {
  197. return make_temp_file_with_prefix (NULL, suffix);
  198. }