CBMC
tempfile.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening
6 
7 \*******************************************************************/
8 
9 #include "tempfile.h"
10 
11 // clang-format off
12 // clang-format must not re-order includes here to avoid pragma_push/pragma_pop
13 #ifdef _WIN32
14 #include <util/pragma_push.def>
15 #ifdef _MSC_VER
16 #pragma warning(disable:4668)
17  // using #if/#elif on undefined macro
18 #pragma warning(disable : 5039)
19 // pointer or reference to potentially throwing function passed to extern C
20 #endif
21 #include <fcntl.h>
22 #include <process.h>
23 #include <sys/stat.h>
24 #include <windows.h>
25 #include <io.h>
26 #include <tchar.h>
27 #define getpid _getpid
28 #define open _open
29 #define close _close
30 #include <util/pragma_pop.def>
31 #endif
32 // clang-format on
33 
34 #include <cstdlib>
35 #include <cstring>
36 #include <filesystem>
37 
38 #include "exception_utils.h"
39 
40 #if defined(__linux__) || \
41  defined(__FreeBSD_kernel__) || \
42  defined(__GNU__) || \
43  defined(__unix__) || \
44  defined(__CYGWIN__) || \
45  defined(__MACH__)
46 #include <unistd.h>
47 #endif
48 
51 #ifdef _WIN32
52 #define mkstemps my_mkstemps
53 int my_mkstemps(char *template_str, int suffix_len)
54 {
55  // The template should be of the form tmpXXXXXXsuffix
56 
57  std::size_t template_length=strlen(template_str);
58 
59  if(suffix_len<0)
60  return -1;
61 
62  if(static_cast<std::size_t>(suffix_len+6)>template_length)
63  return -1; // suffix too long
64 
65  char *XXXXXX_pos=
66  template_str+template_length-6-suffix_len;
67 
68  if(strncmp(XXXXXX_pos, "XXXXXX", 6)!=0)
69  return -1; // XXXXXX missing
70 
71  static const char letters_and_numbers[]=
72  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
73 
74  static long long unsigned int random_state;
75  random_state+=getpid()+123;
76 
77  for(unsigned attempt = 0; attempt < 1000; ++attempt)
78  {
79  unsigned long long number=random_state;
80 
81  for(unsigned i=0; i<6; i++)
82  {
83  XXXXXX_pos[i]=letters_and_numbers[number%62];
84  number/=62;
85  }
86 
87  int fd=open(template_str, O_RDWR|O_CREAT|O_EXCL, 0600);
88  if(fd>=0)
89  return fd; // ok
90 
91  random_state+=4321+getpid(); // avoid repeating
92  }
93 
94  template_str[0]=0;
95  return -1; // error
96 }
97 #endif
98 
99 std::string get_temporary_file(
100  const std::string &prefix,
101  const std::string &suffix)
102 {
103  #ifdef _WIN32
104  char lpTempPathBuffer[MAX_PATH];
105  DWORD dwRetVal;
106 
107  dwRetVal=
108  GetTempPathA(
109  MAX_PATH, // length of the buffer
110  lpTempPathBuffer); // buffer for path
111 
112  if(dwRetVal>MAX_PATH || (dwRetVal==0))
113  throw system_exceptiont("Failed to get temporary directory");
114 
115  // the path returned by GetTempPath ends with a backslash
116  std::string t_template=
117  std::string(lpTempPathBuffer)+prefix+
118  std::to_string(getpid())+".XXXXXX"+suffix;
119  #else
120  std::string dir="/tmp/";
121  const char *TMPDIR_env=getenv("TMPDIR");
122  if(TMPDIR_env!=nullptr)
123  dir=TMPDIR_env;
124  if(*dir.rbegin()!='/')
125  dir+='/';
126 
127  std::string t_template=
128  dir+prefix+std::to_string(getpid())+".XXXXXX"+suffix;
129  #endif
130 
131  char *t_ptr=strdup(t_template.c_str());
132 
133  int fd=mkstemps(t_ptr, suffix.size());
134 
135  if(fd<0)
136  throw system_exceptiont("Failed to open temporary file");
137 
138  close(fd);
139 
140  std::string result=std::string(t_ptr);
141  free(t_ptr);
142  return result;
143 }
144 
146 {
147  if(!name.empty())
148  std::filesystem::remove(name);
149 }
Thrown when some external system fails unexpectedly.
std::string name
Definition: tempfile.h:51
char * getenv(const char *name)
Definition: stdlib.c:496
void free(void *ptr)
Definition: stdlib.c:317
int strncmp(const char *s1, const char *s2, size_t n)
Definition: string.c:464
char * strdup(const char *str)
Definition: string.c:590
size_t strlen(const char *s)
Definition: string.c:561
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
std::string get_temporary_file(const std::string &prefix, const std::string &suffix)
Substitute for mkstemps (OpenBSD standard) for Windows, where it is unavailable.
Definition: tempfile.cpp:99
int close(int fildes)
Definition: unistd.c:139