1 // -*- C++ -*-
2 /**
3 * @brief This class provides operating system specific variables
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "openturns/OTwindows.h" // For CreateProcess
23 #include "openturns/Os.hxx"
24 #include "openturns/Log.hxx"
25 #include "openturns/OSS.hxx"
26 #include "openturns/ResourceMap.hxx" // For ResourceMap
27
28 // include OTConfig that defines OPENTURNS_HAVE_XXX
29 #include "openturns/OTconfig.hxx"
30
31 #ifdef OPENTURNS_HAVE_UNISTD_H
32 # include <unistd.h> // for rmdir, unlink
33 #endif
34
35 #include <cstdlib> // for system(3)
36
37 #ifdef OPENTURNS_HAVE_SYS_TYPES_H
38 # include <sys/types.h> // for stat
39 #endif
40
41 #ifdef OPENTURNS_HAVE_SYS_STAT_H
42 # include <sys/stat.h> // for stat
43 #endif
44
45 #include <fcntl.h>
46 #ifndef _WIN32
47 #include <ftw.h> // for stat(2)
48 #endif
49
50 #ifdef _MSC_VER
51 # include <direct.h>
52 # define MKDIR(p, mode) _mkdir(p)
53 # if !defined(S_ISDIR)
54 # define S_ISDIR(mode) (((mode) & S_IFDIR) != 0)
55 # endif
56 # if !defined(S_ISREG)
57 # define S_ISREG(mode) (((mode) & S_IFREG) != 0)
58 # endif
59 #elif defined(_WIN32)
60 # define MKDIR(p, mode) mkdir(p)
61 #else
62 # define MKDIR(p, mode) mkdir(p, mode)
63 #endif
64
65 BEGIN_NAMESPACE_OPENTURNS
66
GetDirectorySeparator()67 const char * Os::GetDirectorySeparator()
68 {
69 #ifndef _WIN32
70 return "/";
71 #else
72 return "\\";
73 #endif
74 }
75
GetDirectoryListSeparator()76 const char * Os::GetDirectoryListSeparator()
77 {
78 #ifndef _WIN32
79 return ":";
80 #else
81 return ";";
82 #endif
83 }
84
GetEndOfLine()85 const char * Os::GetEndOfLine()
86 {
87 return "\n";
88 }
89
GetDeleteCommandOutput()90 String Os::GetDeleteCommandOutput()
91 {
92 #ifndef _WIN32
93 return " > /dev/null 2>&1";
94 #else
95 return " > NUL";
96 #endif
97 }
98
99 // Returns 0 if no error
ExecuteCommand(const String & command)100 int Os::ExecuteCommand(const String & command)
101 {
102 int rc = -1;
103 LOGINFO( OSS() << "Execute command=" << command );
104 #ifdef _WIN32
105 if ( ResourceMap::GetAsBool("Os-CreateProcess"))
106 {
107 // Startup information
108 STARTUPINFO si;
109 ZeroMemory(&si, sizeof(si));
110 si.cb = sizeof(si);
111 si.dwFlags = STARTF_USESHOWWINDOW;
112 si.wShowWindow = SW_HIDE;
113
114 // Process information
115 PROCESS_INFORMATION pi;
116 ZeroMemory(&pi, sizeof(pi));
117
118 // Create the process
119 DWORD dwProcessFlags = 0;
120 char * cmd = strdup(command.c_str());
121 const Bool processOk = CreateProcess(NULL, cmd, NULL, NULL, true, dwProcessFlags, NULL, NULL, &si, &pi) != 0;
122 free(cmd);
123 if ( processOk )
124 {
125 // Wait for the external application to finish
126 DWORD waitRc = WaitForSingleObject(pi.hProcess, INFINITE);
127 if ( waitRc != WAIT_FAILED )
128 {
129 DWORD exit_code = 0;
130 const Bool codeOk = GetExitCodeProcess(pi.hProcess, &exit_code) != 0;
131 if (codeOk)
132 {
133 rc = exit_code;
134 }
135 else
136 {
137 rc = GetLastError();
138 }
139 }
140
141 // Close everything
142 CloseHandle(pi.hProcess);
143 CloseHandle(pi.hThread);
144 }
145 else
146 {
147 rc = GetLastError();
148 }
149 } // use create process
150 else
151 #endif
152 {
153 rc = system(command.c_str());
154 }
155 LOGINFO( OSS() << "Return code=" << rc << " for command=" << command );
156 return rc;
157 }
158
159
Remove(const String & fileName)160 void Os::Remove(const String& fileName)
161 {
162 if (!ResourceMap::GetAsBool("Os-RemoveFiles")) return;
163 if (remove(fileName.c_str()) == -1)
164 {
165 Log::Warn(OSS() << "Warning: cannot remove file " << fileName);
166 }
167 }
168
169 // Function helper for Os::MakeDirectory: replace backslash by slash
170 static void
convert_backslashes(String & path)171 convert_backslashes(String & path)
172 {
173 #ifdef _WIN32
174 const char* current_char = path.c_str();
175 String::size_type pos = 0;
176 // On Windows, leading \\ is for network paths and must not be stripped
177 if (*current_char == '\\' && *(current_char + 1) == '\\')
178 {
179 pos = 2;
180 current_char += pos;
181 }
182 for ( ; *current_char != '\0'; ++pos, ++current_char )
183 {
184 if (*current_char == '\\') path[pos] = '/';
185 }
186 #else
187 (void) path;
188 #endif
189 }
190
IsDirectory(const String & fileName)191 Bool Os::IsDirectory(const String & fileName)
192 {
193 struct stat dir_stat;
194 if(stat(fileName.c_str(), &dir_stat) != 0) return false;
195 return S_ISDIR(dir_stat.st_mode);
196 }
197
IsFile(const String & fileName)198 Bool Os::IsFile(const String & fileName)
199 {
200 struct stat dir_stat;
201 if(stat(fileName.c_str(), &dir_stat) != 0) return false;
202 return S_ISREG(dir_stat.st_mode);
203 }
204
205 // Returns 0 if no error
MakeDirectory(const String & path)206 int Os::MakeDirectory(const String & path)
207 {
208 if (path.empty()) return 1;
209 if (IsDirectory(path)) return 0;
210
211 String slashPath(path);
212 convert_backslashes(slashPath);
213
214 String::size_type pos = 0;
215 while((pos = slashPath.find('/', pos)) != String::npos)
216 {
217 String current_dir(path.substr(0, pos));
218 const char * cpath = current_dir.c_str();
219 if (!IsDirectory(current_dir) && (0 != MKDIR(cpath, 0777))) return 1;
220 pos++;
221 }
222
223 return 0;
224 }
225
226 #ifndef _WIN32
deleteRegularFileOrDirectory(const char * path,const struct stat *,int typeflag,struct FTW *)227 static int deleteRegularFileOrDirectory(const char * path,
228 const struct stat *,
229 int typeflag,
230 struct FTW * )
231 {
232 int rc;
233
234 switch (typeflag)
235 {
236 case FTW_DP:
237 rc = rmdir( path );
238 if ( rc < 0 ) return 1;
239 break;
240
241 case FTW_SL:
242 case FTW_SLN:
243 case FTW_F:
244 rc = unlink( path );
245 if ( rc < 0 ) return 1;
246 break;
247
248 } /* end switch */
249
250 return 0;
251 }
252 #endif /* !WIN32 */
253
254
255
256 // Delete a directory and its contents recursively. Returns 0 if no error
DeleteDirectory(const String & path)257 int Os::DeleteDirectory(const String & path)
258 {
259 if (path.empty()) return 1;
260 if (!IsDirectory(path)) return 1;
261
262 // Refuse to delete root directory (/) and current directory (.)
263 if (path == "/" || path == ".") return 1;
264
265 const char * directory = path.c_str();
266 #ifdef _WIN32
267 if ( ((strlen( directory ) == 3) && (directory[1] == ':') && (directory[2] == '\\' || directory[2] == '/')) ||
268 ((strlen( directory ) == 2) && (directory[1] == ':')) )
269 {
270 // do not delete root directory
271 return 1;
272 }
273 #endif
274
275 int rc = 0;
276
277 #ifndef _WIN32
278
279 rc = nftw(directory, deleteRegularFileOrDirectory, 20, FTW_DEPTH);
280
281 #else /* WIN32 */
282
283 UnsignedInteger countdown = ResourceMap::GetAsUnsignedInteger("OS-DeleteTimeout");
284 const String rmdirCmd("rmdir /Q /S \"" + path + "\"" + " > NUL 2>&1");
285 Bool directoryExists = true;
286
287 do
288 {
289 rc = system(rmdirCmd.c_str());
290
291 // check if directory still there (rmdir dos command always return 0)
292 directoryExists = IsDirectory(path);
293 if (directoryExists)
294 {
295 if (countdown == 0) return 1;
296 -- countdown;
297 }
298 Sleep(1000);
299 }
300 while (directoryExists);
301
302 #endif /* WIN32 */
303
304 return rc;
305 }
306
307
308 END_NAMESPACE_OPENTURNS
309