Coverage Report

Created: 2025-06-24 06:45

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