329bf37e387f49caf4066381784871ba780f201a
[oota-llvm.git] / lib / System / Unix / Path.cpp
1 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific portion of the Path class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include <llvm/Config/config.h>
20 #include "Unix.h"
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <fstream>
24
25 namespace llvm {
26 using namespace sys;
27
28 Path::Path(std::string unverified_path) 
29   : path(unverified_path)
30 {
31   if (unverified_path.empty())
32     return;
33   if (this->is_valid()) 
34     return;
35   // oops, not valid.
36   path.clear();
37   ThrowErrno(unverified_path + ": path is not valid");
38 }
39
40 Path
41 Path::GetRootDirectory() {
42   Path result;
43   result.set_directory("/");
44   return result;
45 }
46
47 static inline bool IsLibrary(Path& path, const std::string& basename) {
48   if (path.append_file(std::string("lib") + basename)) {
49     if (path.append_suffix(Path::GetDLLSuffix()) && path.readable())
50       return true;
51     else if (path.elide_suffix() && path.append_suffix("a") && path.readable())
52       return true;
53     else if (path.elide_suffix() && path.append_suffix("o") && path.readable())
54       return true;
55   } else if (path.elide_file() && path.append_file(basename)) {
56     if (path.append_suffix(Path::GetDLLSuffix()) && path.readable())
57       return true;
58     else if (path.elide_suffix() && path.append_suffix("a") && path.readable())
59       return true;
60     else if (path.elide_suffix() && path.append_suffix("o") && path.readable())
61       return true;
62   }
63   path.clear();
64   return false;
65 }
66
67 Path 
68 Path::GetLibraryPath(const std::string& basename, 
69                      const std::vector<std::string>& LibPaths) {
70   Path result;
71
72   // Try the paths provided
73   for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
74        E = LibPaths.end(); I != E; ++I ) {
75     if (result.set_directory(*I) && IsLibrary(result,basename))
76       return result;
77   }
78
79   // Try /usr/lib
80   if (result.set_directory("/usr/lib/") && IsLibrary(result,basename))
81     return result;
82
83   // Try /lib
84   if (result.set_directory("/lib/") && IsLibrary(result,basename))
85     return result;
86
87   // Can't find it, give up and return invalid path.
88   result.clear();
89   return result;
90 }
91
92 Path 
93 Path::GetSystemLibraryPath1() {
94   return Path("/lib/");
95 }
96
97 Path 
98 Path::GetSystemLibraryPath2() {
99   return Path("/usr/lib/");
100 }
101
102 Path 
103 Path::GetLLVMDefaultConfigDir() {
104   return Path("/etc/llvm/");
105 }
106
107 Path 
108 Path::GetLLVMConfigDir() {
109   Path result;
110   if (result.set_directory(LLVM_ETCDIR))
111     return result;
112   return GetLLVMDefaultConfigDir();
113 }
114
115 Path
116 Path::GetUserHomeDirectory() {
117   const char* home = getenv("HOME");
118   if (home) {
119     Path result;
120     if (result.set_directory(home))
121       return result;
122   }
123   return GetRootDirectory();
124 }
125
126 bool
127 Path::is_file() const {
128   return (is_valid() && path[path.length()-1] != '/');
129 }
130
131 bool
132 Path::is_directory() const {
133   return (is_valid() && path[path.length()-1] == '/');
134 }
135
136 std::string
137 Path::get_basename() const {
138   // Find the last slash
139   size_t slash = path.rfind('/');
140   if (slash == std::string::npos)
141     slash = 0;
142   else
143     slash++;
144
145   return path.substr(slash, path.rfind('.'));
146 }
147
148 bool Path::has_magic_number(const std::string &Magic) const {
149   size_t len = Magic.size();
150   char buf[ 1 + len];
151   std::ifstream f(path.c_str());
152   f.read(buf, len);
153   buf[len] = '\0';
154   return Magic == buf;
155 }
156
157 bool 
158 Path::is_bytecode_file() const {
159   if (readable()) {
160     return has_magic_number("llvm");
161   }
162   return false;
163 }
164
165 bool
166 Path::is_archive() const {
167   if (readable()) {
168     return has_magic_number("!<arch>\012");
169   }
170   return false;
171 }
172
173 bool
174 Path::exists() const {
175   return 0 == access(path.c_str(), F_OK );
176 }
177
178 bool
179 Path::readable() const {
180   return 0 == access(path.c_str(), F_OK | R_OK );
181 }
182
183 bool
184 Path::writable() const {
185   return 0 == access(path.c_str(), F_OK | W_OK );
186 }
187
188 bool
189 Path::executable() const {
190   return 0 == access(path.c_str(), R_OK | X_OK );
191 }
192
193 std::string 
194 Path::getLast() const {
195   // Find the last slash
196   size_t pos = path.rfind('/');
197
198   // Handle the corner cases
199   if (pos == std::string::npos)
200     return path;
201
202   // If the last character is a slash
203   if (pos == path.length()-1) {
204     // Find the second to last slash
205     size_t pos2 = path.rfind('/', pos-1);
206     if (pos2 == std::string::npos)
207       return path.substr(0,pos);
208     else
209       return path.substr(pos2+1,pos-pos2-1);
210   }
211   // Return everything after the last slash
212   return path.substr(pos+1);
213 }
214
215 bool
216 Path::set_directory(const std::string& a_path) {
217   if (a_path.size() == 0)
218     return false;
219   Path save(*this);
220   path = a_path;
221   size_t last = a_path.size() -1;
222   if (last != 0 && a_path[last] != '/')
223     path += '/';
224   if (!is_valid()) {
225     path = save.path;
226     return false;
227   }
228   return true;
229 }
230
231 bool
232 Path::set_file(const std::string& a_path) {
233   if (a_path.size() == 0)
234     return false;
235   Path save(*this);
236   path = a_path;
237   size_t last = a_path.size() - 1;
238   while (last > 0 && a_path[last] == '/')
239     last--;
240   path.erase(last+1);
241   if (!is_valid()) {
242     path = save.path;
243     return false;
244   }
245   return true;
246 }
247
248 bool
249 Path::append_directory(const std::string& dir) {
250   if (is_file()) 
251     return false;
252   Path save(*this);
253   path += dir;
254   path += "/";
255   if (!is_valid()) {
256     path = save.path;
257     return false;
258   }
259   return true;
260 }
261
262 bool
263 Path::elide_directory() {
264   if (is_file()) 
265     return false;
266   size_t slashpos = path.rfind('/',path.size());
267   if (slashpos == 0 || slashpos == std::string::npos)
268     return false;
269   if (slashpos == path.size() - 1)
270     slashpos = path.rfind('/',slashpos-1);
271   if (slashpos == std::string::npos)
272     return false;
273   path.erase(slashpos);
274   return true;
275 }
276
277 bool
278 Path::append_file(const std::string& file) {
279   if (!is_directory()) 
280     return false;
281   Path save(*this);
282   path += file;
283   if (!is_valid()) {
284     path = save.path;
285     return false;
286   }
287   return true;
288 }
289
290 bool
291 Path::elide_file() {
292   if (is_directory()) 
293     return false;
294   size_t slashpos = path.rfind('/',path.size());
295   if (slashpos == std::string::npos)
296     return false;
297   path.erase(slashpos+1);
298   return true;
299 }
300
301 bool
302 Path::append_suffix(const std::string& suffix) {
303   if (is_directory()) 
304     return false;
305   Path save(*this);
306   path.append(".");
307   path.append(suffix);
308   if (!is_valid()) {
309     path = save.path;
310     return false;
311   }
312   return true;
313 }
314
315 bool 
316 Path::elide_suffix() {
317   if (is_directory()) return false;
318   size_t dotpos = path.rfind('.',path.size());
319   size_t slashpos = path.rfind('/',path.size());
320   if (slashpos != std::string::npos && dotpos != std::string::npos &&
321       dotpos > slashpos) {
322     path.erase(dotpos, path.size()-dotpos);
323     return true;
324   }
325   return false;
326 }
327
328
329 bool
330 Path::create_directory( bool create_parents) {
331   // Make sure we're dealing with a directory
332   if (!is_directory()) return false;
333
334   // Get a writeable copy of the path name
335   char pathname[MAXPATHLEN];
336   path.copy(pathname,MAXPATHLEN);
337
338   // Null-terminate the last component
339   int lastchar = path.length() - 1 ; 
340   if (pathname[lastchar] == '/') 
341     pathname[lastchar] = 0;
342
343   // If we're supposed to create intermediate directories
344   if ( create_parents ) {
345     // Find the end of the initial name component
346     char * next = strchr(pathname,'/');
347     if ( pathname[0] == '/') 
348       next = strchr(&pathname[1],'/');
349
350     // Loop through the directory components until we're done 
351     while ( next != 0 ) {
352       *next = 0;
353       if (0 != access(pathname, F_OK | R_OK | W_OK))
354         if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
355           ThrowErrno(std::string(pathname) + ": Can't create directory");
356       char* save = next;
357       next = strchr(pathname,'/');
358       *save = '/';
359     }
360   } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
361     ThrowErrno(std::string(pathname) + ": Can't create directory");
362   } 
363   return true;
364 }
365
366 bool
367 Path::create_file() {
368   // Make sure we're dealing with a file
369   if (!is_file()) return false; 
370
371   // Create the file
372   if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
373     ThrowErrno(std::string(path.c_str()) + ": Can't create file");
374
375   return true;
376 }
377
378 bool
379 Path::destroy_directory(bool remove_contents) {
380   // Make sure we're dealing with a directory
381   if (!is_directory()) return false;
382
383   // If it doesn't exist, we're done.
384   if (!exists()) return true;
385
386   if (remove_contents) {
387     // Recursively descend the directory to remove its content
388     std::string cmd("/bin/rm -rf ");
389     cmd += path;
390     system(cmd.c_str());
391   } else {
392     // Otherwise, try to just remove the one directory
393     char pathname[MAXPATHLEN];
394     path.copy(pathname,MAXPATHLEN);
395     int lastchar = path.length() - 1 ; 
396     if (pathname[lastchar] == '/') 
397       pathname[lastchar] = 0;
398     if ( 0 != rmdir(pathname))
399       ThrowErrno(std::string(pathname) + ": Can't destroy directory");
400   }
401   return true;
402 }
403
404 bool
405 Path::destroy_file() {
406   if (!is_file()) return false;
407   if (0 != unlink(path.c_str()))
408     ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
409   return true;
410 }
411
412 }
413
414 // vim: sw=2