Home | History | Annotate | Line # | Download | only in libiberty
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