(root)/
gcc-13.2.0/
libiberty/
make-temp-file.c
       1  /* Utility to pick a temporary filename prefix.
       2     Copyright (C) 1996-2023 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  #define DIR_SEPARATOR '/'
      60  #endif
      61  
      62  /* Name of temporary file.
      63     mktemp requires 6 trailing X's.  */
      64  #define TEMP_FILE "XXXXXX"
      65  #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  {
      80    if (base != 0)
      81      return base;
      82    if (dir != 0
      83        && access (dir, R_OK | W_OK | X_OK) == 0)
      84      {
      85        /* Check to make sure dir is actually a directory. */
      86  #ifdef S_ISDIR
      87        struct stat s;
      88        if (stat (dir, &s))
      89  	return NULL;
      90        if (!S_ISDIR (s.st_mode))
      91  	return NULL;
      92  #endif
      93        return dir;
      94      }
      95    return 0;
      96  }
      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  {
     120    if (!memoized_tmpdir)
     121      {
     122  #if !defined(_WIN32) || defined(__CYGWIN__)
     123        const char *base = 0;
     124        char *tmpdir;
     125        unsigned int len;
     126        
     127  #ifdef VMS
     128        /* Try VMS standard temp logical.  */
     129        base = try_dir ("/sys$scratch", base);
     130  #else
     131        base = try_dir (getenv ("TMPDIR"), base);
     132        base = try_dir (getenv ("TMP"), base);
     133        base = try_dir (getenv ("TEMP"), base);
     134  #endif
     135        
     136  #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        if (strcmp (P_tmpdir, "\\") == 0)
     140  	base = try_dir ("\\.", base);
     141        else
     142  	base = try_dir (P_tmpdir, base);
     143  #endif
     144  
     145        /* Try /var/tmp, then /tmp.  */
     146        base = try_dir (vartmp, base);
     147        base = try_dir (tmp, base);
     148        
     149        /* If all else fails, use the current directory!  */
     150        if (base == 0)
     151  	base = ".";
     152        /* Append DIR_SEPARATOR to the directory we've chosen
     153  	 and return it.  */
     154        len = strlen (base);
     155        tmpdir = XNEWVEC (char, len + 2);
     156        strcpy (tmpdir, base);
     157        tmpdir[len] = DIR_SEPARATOR;
     158        tmpdir[len+1] = '\0';
     159        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      }
     179  
     180    return memoized_tmpdir;
     181  }
     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  {
     198    const char *base = choose_tmpdir ();
     199    char *temp_filename;
     200    int base_len, suffix_len, prefix_len;
     201    int fd;
     202  
     203    if (prefix == 0)
     204      prefix = "cc";
     205  
     206    if (suffix == 0)
     207      suffix = "";
     208  
     209    base_len = strlen (base);
     210    prefix_len = strlen (prefix);
     211    suffix_len = strlen (suffix);
     212  
     213    temp_filename = XNEWVEC (char, base_len
     214  			   + TEMP_FILE_LEN
     215  			   + suffix_len
     216  			   + prefix_len + 1);
     217    strcpy (temp_filename, base);
     218    strcpy (temp_filename + base_len, prefix);
     219    strcpy (temp_filename + base_len + prefix_len, TEMP_FILE);
     220    strcpy (temp_filename + base_len + prefix_len + TEMP_FILE_LEN, suffix);
     221  
     222    fd = mkstemps (temp_filename, suffix_len);
     223    /* Mkstemps failed.  It may be EPERM, ENOSPC etc.  */
     224    if (fd == -1)
     225      {
     226        fprintf (stderr, "Cannot create temporary file in %s: %s\n",
     227  	       base, strerror (errno));
     228        abort ();
     229      }
     230    /* We abort on failed close out of sheer paranoia.  */
     231    if (close (fd))
     232      abort ();
     233    return temp_filename;
     234  }
     235  
     236  char *
     237  make_temp_file (const char *suffix)
     238  {
     239    return make_temp_file_with_prefix (NULL, suffix);
     240  }