vul_temp_filename.cxx
Go to the documentation of this file.
1 // This is core/vul/vul_temp_filename.cxx
2 
3 #include <string>
4 #include <ctime>
5 #include <cstdlib>
6 #include <cstdio>
7 #include "vul_temp_filename.h"
8 #ifdef _MSC_VER
9 # include <vcl_msvc_warnings.h>
10 #endif
11 
12 #if defined (_MSC_VER) || defined(__MINGW32__)
13 
14 # include <Windows.h>
15 #else
16 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
17  // Helper functions for Unix
18 
19  #include <unistd.h> // for unlink
20  #include <fcntl.h> // for O_CREATE,...
21 
22  namespace {
23  // The filename is okay if it doesn't exist and can be opened for
24  // writing.
25  bool is_okay( const std::string& name )
26  {
27  bool okay = true;
28  int fd = open( name.c_str(), O_CREAT|O_EXCL, 0600 );
29  if ( fd == -1 ) {
30  okay = false;
31  } else {
32  unlink( name.c_str() );
33  close( fd );
34  }
35  return okay;
36  }
37 
38 
39  // Initialise the random number seed with the time. Maybe need to
40  // include things like (Unix) process id, but I don't think the
41  // randomness is that crucial.
42  int init_randomizer()
43  {
44  std::srand( std::time( nullptr ) );
45  return 0;
46  }
47  static int random_seed_trigger = init_randomizer();
48 
49  char random_letter()
50  {
51  // Make sure the random character is a letter.
52  int r = std::rand() % (26+26); // 26 uppercase and 26 lowercase letters
53  return (r<26) ? char('A'+r) : char('a'+r-26);
54  }
55 
56  char random_char()
57  {
58  // Make sure the random character is a letter or number.
59  int r = std::rand() % (26+26+10); // 2x26 letters, 10 digits
60  return (r<26) ? char('A'+r) : (r<52) ? char('a'+r-26) : char('0'+r-52);
61  }
62  }
63 #else
64 # warning "This is neither unix nor MS-windows - please add specifics to " __FILE__
65 #endif
66 #endif
67 
68 std::string
70 {
71 #if defined(_MSC_VER) || defined(__MINGW32__)
72  char path[ _MAX_PATH ];
73  char* file;
74  if ( GetTempPath( _MAX_PATH, path ) == 0 )
75  return "";
76  // Can't use GetTempFileName, because the function actually creates the
77  // temporary file! This would mean that every call to this function creates
78  // yet another file that will lie around if the caller doesn't use the generated
79  // filename. And I don't trust the implementation enough to just unlink the file
80  // before returning.
81  file = _tempnam( path, "" );
82  if ( file == 0 )
83  return "";
84  return file;
85 #else
86 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
87  // Don't use tmpnam, since it causes linker warnings (and sometimes
88  // linker errors). Instead reimplement. Sigh.
89  const unsigned int num_char_in_filename = 7+1; // should always be at least 1
90  std::string filename;
91  std::string tempdir;
92  unsigned int count = 0;
93  bool okay = false;
94 
95  if ( std::getenv( "TMP" ) ) {
96  tempdir = std::getenv( "TMP" );
97  } else {
98  tempdir = P_tmpdir; // defined in stdio.h
99  }
100  char lastchar = ( tempdir.size() > 0 ) ? tempdir[tempdir.size()-1] : ' ';
101  if (lastchar != '/' && lastchar != '\\')
102  tempdir += "/";
103 
104  while ( !okay && count < 10 ) {
105  char buf[ num_char_in_filename+1 ];
106  buf[0] = random_letter(); // make sure first char is a letter
107  for ( unsigned int i=1; i < num_char_in_filename; ++i )
108  buf[i] = random_char();
109  buf[num_char_in_filename] = '\0';
110  filename = tempdir + buf;
111  ++count;
112  okay = is_okay( filename );
113  };
114 
115  if ( okay )
116  return filename;
117  else
118  return "";
119 #else
120 # warning "This is neither unix nor MS-windows - please add specifics to " __FILE__
121 #endif
122 #endif
123 }
Generates a temporary filename.
std::string vul_temp_filename()
Generates a temporary filename.