Changes For Bug 352
[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
24 namespace llvm {
25 using namespace sys;
26
27 Path::Path(std::string unverified_path) 
28   : path(unverified_path)
29 {
30   if (unverified_path.empty())
31     return;
32   if (this->is_valid()) 
33     return;
34   // oops, not valid.
35   path.clear();
36   ThrowErrno(unverified_path + ": path is not valid");
37 }
38
39 Path
40 Path::GetRootDirectory() {
41   Path result;
42   result.set_directory("/");
43   return result;
44 }
45
46 Path 
47 Path::GetSystemLibraryPath1() {
48   return Path("/lib/");
49 }
50
51 Path 
52 Path::GetSystemLibraryPath2() {
53   return Path("/usr/lib/");
54 }
55
56 Path 
57 Path::GetLLVMDefaultConfigDir() {
58   return Path("/etc/llvm/");
59 }
60
61 Path 
62 Path::GetLLVMConfigDir() {
63   Path result;
64   if (result.set_directory(LLVM_ETCDIR))
65     return result;
66   return GetLLVMDefaultConfigDir();
67 }
68
69 Path
70 Path::GetUserHomeDirectory() {
71   const char* home = getenv("HOME");
72   if (home) {
73     Path result;
74     if (result.set_directory(home))
75       return result;
76   }
77   return GetRootDirectory();
78 }
79
80 bool
81 Path::exists() const {
82   return 0 == access(path.c_str(), F_OK );
83 }
84
85 bool
86 Path::readable() const {
87   return 0 == access(path.c_str(), F_OK | R_OK );
88 }
89
90 bool
91 Path::writable() const {
92   return 0 == access(path.c_str(), F_OK | W_OK );
93 }
94
95 bool
96 Path::executable() const {
97   return 0 == access(path.c_str(), R_OK | X_OK );
98 }
99
100 std::string 
101 Path::getLast() const {
102   // Find the last slash
103   size_t pos = path.rfind('/');
104
105   // Handle the corner cases
106   if (pos == std::string::npos)
107     return path;
108
109   // If the last character is a slash
110   if (pos == path.length()-1) {
111     // Find the second to last slash
112     size_t pos2 = path.rfind('/', pos-1);
113     if (pos2 == std::string::npos)
114       return path.substr(0,pos);
115     else
116       return path.substr(pos2+1,pos-pos2-1);
117   }
118   // Return everything after the last slash
119   return path.substr(pos+1);
120 }
121
122 bool
123 Path::set_directory(const std::string& a_path) {
124   if (a_path.size() == 0)
125     return false;
126   Path save(*this);
127   path = a_path;
128   size_t last = a_path.size() -1;
129   if (last != 0 && a_path[last] != '/')
130     path += '/';
131   if (!is_valid()) {
132     path = save.path;
133     return false;
134   }
135   return true;
136 }
137
138 bool
139 Path::set_file(const std::string& a_path) {
140   if (a_path.size() == 0)
141     return false;
142   Path save(*this);
143   path = a_path;
144   size_t last = a_path.size() - 1;
145   while (last > 0 && a_path[last] == '/')
146     last--;
147   path.erase(last+1);
148   if (!is_valid()) {
149     path = save.path;
150     return false;
151   }
152   return true;
153 }
154
155 bool
156 Path::append_directory(const std::string& dir) {
157   if (is_file()) 
158     return false;
159   Path save(*this);
160   path += dir;
161   path += "/";
162   if (!is_valid()) {
163     path = save.path;
164     return false;
165   }
166   return true;
167 }
168
169 bool
170 Path::elide_directory() {
171   if (is_file()) 
172     return false;
173   size_t slashpos = path.rfind('/',path.size());
174   if (slashpos == 0 || slashpos == std::string::npos)
175     return false;
176   if (slashpos == path.size() - 1)
177     slashpos = path.rfind('/',slashpos-1);
178   if (slashpos == std::string::npos)
179     return false;
180   path.erase(slashpos);
181   return true;
182 }
183
184 bool
185 Path::append_file(const std::string& file) {
186   if (!is_directory()) 
187     return false;
188   Path save(*this);
189   path += file;
190   if (!is_valid()) {
191     path = save.path;
192     return false;
193   }
194   return true;
195 }
196
197 bool
198 Path::elide_file() {
199   if (is_directory()) 
200     return false;
201   size_t slashpos = path.rfind('/',path.size());
202   if (slashpos == std::string::npos)
203     return false;
204   path.erase(slashpos+1);
205   return true;
206 }
207
208 bool
209 Path::append_suffix(const std::string& suffix) {
210   if (is_directory()) 
211     return false;
212   Path save(*this);
213   path.append(".");
214   path.append(suffix);
215   if (!is_valid()) {
216     path = save.path;
217     return false;
218   }
219   return true;
220 }
221
222 bool 
223 Path::elide_suffix() {
224   if (is_directory()) return false;
225   size_t dotpos = path.rfind('.',path.size());
226   size_t slashpos = path.rfind('/',path.size());
227   if (slashpos != std::string::npos && dotpos != std::string::npos &&
228       dotpos > slashpos) {
229     path.erase(dotpos, path.size()-dotpos);
230     return true;
231   }
232   return false;
233 }
234
235
236 bool
237 Path::create_directory( bool create_parents) {
238   // Make sure we're dealing with a directory
239   if (!is_directory()) return false;
240
241   // Get a writeable copy of the path name
242   char pathname[MAXPATHLEN];
243   path.copy(pathname,MAXPATHLEN);
244
245   // Null-terminate the last component
246   int lastchar = path.length() - 1 ; 
247   if (pathname[lastchar] == '/') 
248     pathname[lastchar] = 0;
249
250   // If we're supposed to create intermediate directories
251   if ( create_parents ) {
252     // Find the end of the initial name component
253     char * next = strchr(pathname,'/');
254     if ( pathname[0] == '/') 
255       next = strchr(&pathname[1],'/');
256
257     // Loop through the directory components until we're done 
258     while ( next != 0 ) {
259       *next = 0;
260       if (0 != access(pathname, F_OK | R_OK | W_OK))
261         if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
262           ThrowErrno(std::string(pathname) + ": Can't create directory");
263       char* save = next;
264       next = strchr(pathname,'/');
265       *save = '/';
266     }
267   } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
268     ThrowErrno(std::string(pathname) + ": Can't create directory");
269   } 
270   return true;
271 }
272
273 bool
274 Path::create_file() {
275   // Make sure we're dealing with a file
276   if (!is_file()) return false; 
277
278   // Create the file
279   if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
280     ThrowErrno(std::string(path.c_str()) + ": Can't create file");
281
282   return true;
283 }
284
285 bool
286 Path::destroy_directory(bool remove_contents) {
287   // Make sure we're dealing with a directory
288   if (!is_directory()) return false;
289
290   // If it doesn't exist, we're done.
291   if (!exists()) return true;
292
293   if (remove_contents) {
294     // Recursively descend the directory to remove its content
295     std::string cmd("/bin/rm -rf ");
296     cmd += path;
297     system(cmd.c_str());
298   } else {
299     // Otherwise, try to just remove the one directory
300     char pathname[MAXPATHLEN];
301     path.copy(pathname,MAXPATHLEN);
302     int lastchar = path.length() - 1 ; 
303     if (pathname[lastchar] == '/') 
304       pathname[lastchar] = 0;
305     if ( 0 != rmdir(pathname))
306       ThrowErrno(std::string(pathname) + ": Can't destroy directory");
307   }
308   return true;
309 }
310
311 bool
312 Path::destroy_file() {
313   if (!is_file()) return false;
314   if (0 != unlink(path.c_str()))
315     ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
316   return true;
317 }
318
319 }
320
321 // vim: sw=2