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