cprover
file_util.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: File Utilities
4 
5 Author:
6 
7 Date: January 2012
8 
9 \*******************************************************************/
10 
13 
14 #include "file_util.h"
15 
16 #include "exception_utils.h"
17 
18 #include <cerrno>
19 #include <cstring>
20 
21 #if defined(__linux__) || \
22  defined(__FreeBSD_kernel__) || \
23  defined(__GNU__) || \
24  defined(__unix__) || \
25  defined(__CYGWIN__) || \
26  defined(__MACH__)
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <dirent.h>
30 #include <cstdlib>
31 #include <cstdio>
32 #endif
33 
34 #ifdef _WIN32
35 #include <util/pragma_push.def>
36 #ifdef _MSC_VER
37 #pragma warning(disable:4668)
38  // using #if/#elif on undefined macro
39 #pragma warning(disable : 5039)
40 // pointer or reference to potentially throwing function passed to extern C
41 #endif
42 #include <io.h>
43 #include <windows.h>
44 #include <direct.h>
45 #include <util/unicode.h>
46 #define chdir _chdir
47 #include <util/pragma_pop.def>
48 #endif
49 
52 {
53 #ifndef _WIN32
54  errno=0;
55  char *wd=realpath(".", nullptr);
56 
57  if(wd == nullptr || errno != 0)
58  throw system_exceptiont(
59  std::string("realpath failed: ") + std::strerror(errno));
60 
61  std::string working_directory=wd;
62  free(wd);
63 #else
64  TCHAR buffer[4096];
65  DWORD retval=GetCurrentDirectory(4096, buffer);
66  if(retval == 0)
67  throw system_exceptiont("failed to get current directory of process");
68 
69 # ifdef UNICODE
70  std::string working_directory(narrow(buffer));
71 # else
72  std::string working_directory(buffer);
73 # endif
74 
75 #endif
76 
77  return working_directory;
78 }
79 
82 void set_current_path(const std::string &path)
83 {
84  if(chdir(path.c_str()) != 0)
85  throw system_exceptiont(
86  std::string("chdir failed: ") + std::strerror(errno));
87 }
88 
90 #ifdef _WIN32
91 
92 void delete_directory_utf16(const std::wstring &path)
93 {
94  std::wstring pattern=path + L"\\*";
95  // NOLINTNEXTLINE(readability/identifiers)
96  struct _wfinddata_t info;
97  intptr_t hFile=_wfindfirst(pattern.c_str(), &info);
98  if(hFile!=-1)
99  {
100  do
101  {
102  if(wcscmp(info.name, L".")==0 || wcscmp(info.name, L"..")==0)
103  continue;
104  std::wstring sub_path=path+L"\\"+info.name;
105  if(info.attrib & _A_SUBDIR)
106  delete_directory_utf16(sub_path);
107  else
108  DeleteFileW(sub_path.c_str());
109  }
110  while(_wfindnext(hFile, &info)==0);
111  _findclose(hFile);
112  RemoveDirectoryW(path.c_str());
113  }
114 }
115 
116 #endif
117 
118 void delete_directory(const std::string &path)
119 {
120 #ifdef _WIN32
121  delete_directory_utf16(utf8_to_utf16_native_endian(path));
122 #else
123  DIR *dir=opendir(path.c_str());
124  if(dir!=nullptr)
125  {
126  struct dirent *ent;
127  while((ent=readdir(dir))!=nullptr)
128  {
129  // Needed for Alpine Linux
130  if(strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0)
131  continue;
132 
133  std::string sub_path=path+"/"+ent->d_name;
134 
135  struct stat stbuf;
136  int result=stat(sub_path.c_str(), &stbuf);
137  if(result!=0)
138  throw system_exceptiont(
139  std::string("Stat failed: ") + std::strerror(errno));
140 
141  if(S_ISDIR(stbuf.st_mode))
142  delete_directory(sub_path);
143  else
144  {
145  result=remove(sub_path.c_str());
146  if(result!=0)
147  throw system_exceptiont(
148  std::string("Remove failed: ") + std::strerror(errno));
149  }
150  }
151  closedir(dir);
152  }
153  rmdir(path.c_str());
154 #endif
155 }
156 
159 std::string concat_dir_file(
160  const std::string &directory,
161  const std::string &file_name)
162 {
163  #ifdef _WIN32
164  return (file_name.size() > 1 && file_name[0] != '/' && file_name[1] == ':') ?
165  file_name : directory + "\\" + file_name;
166  #else
167  return (!file_name.empty() && file_name[0]=='/') ?
168  file_name : directory+"/"+file_name;
169  #endif
170 }
171 
172 bool is_directory(const std::string &path)
173 {
174  if(path.empty())
175  return false;
176 
177 #ifdef _WIN32
178 
179  auto attributes = ::GetFileAttributesW(widen(path).c_str());
180  if (attributes == INVALID_FILE_ATTRIBUTES)
181  return false;
182  else
183  return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
184 
185 #else
186 
187  struct stat buf;
188 
189  if(stat(path.c_str(), &buf)!=0)
190  return false;
191  else
192  return (buf.st_mode & S_IFDIR) != 0;
193 
194 #endif
195 }
196 
197 bool create_directory(const std::string &path)
198 {
199 #ifdef _WIN32
200  return _mkdir(path.c_str()) == 0;
201 #else
202  // the umask matches what std::filesystem::create_directory does
203  return mkdir(path.c_str(), 0777) == 0;
204 #endif
205 }
exception_utils.h
file_util.h
create_directory
bool create_directory(const std::string &path)
Create a directory with given path C++17 will allow us to use std::filesystem::create_directory.
Definition: file_util.cpp:197
concat_dir_file
std::string concat_dir_file(const std::string &directory, const std::string &file_name)
Definition: file_util.cpp:159
system_exceptiont
Thrown when some external system fails unexpectedly.
Definition: exception_utils.h:61
is_directory
bool is_directory(const std::string &path)
Definition: file_util.cpp:172
widen
std::wstring widen(const char *s)
Definition: unicode.cpp:57
utf8_to_utf16_native_endian
std::wstring utf8_to_utf16_native_endian(const std::string &in)
Convert UTF8-encoded string to UTF-16 with architecture-native endianness.
Definition: unicode.cpp:201
narrow
output_type narrow(input_type input)
Run-time checked narrowing cast.
Definition: narrow.h:34
unicode.h
get_current_working_directory
std::string get_current_working_directory()
Definition: file_util.cpp:51
set_current_path
void set_current_path(const std::string &path)
Set working directory.
Definition: file_util.cpp:82
delete_directory
void delete_directory(const std::string &path)
deletes all files in 'path' and then the directory itself
Definition: file_util.cpp:118
free
void free(void *)