blob: 9d02a3e5bdd9c9c3dc89aa6d323ccf96d68395b4 [file] [log] [blame]
Reid Spencerb016a372004-09-15 05:49:50 +00001//===- llvm/System/Linux/Path.cpp - Linux Path Implementation ---*- C++ -*-===//
2//
Reid Spencercbad7012004-09-11 04:59:30 +00003// The LLVM Compiler Infrastructure
4//
Reid Spencerb016a372004-09-15 05:49:50 +00005// This file was developed by Reid Spencer and is distributed under the
Reid Spencercbad7012004-09-11 04:59:30 +00006// University of Illinois Open Source License. See LICENSE.TXT for details.
Reid Spencerb016a372004-09-15 05:49:50 +00007//
8// Modified by Henrik Bach to comply with at least MinGW.
9//
Reid Spencercbad7012004-09-11 04:59:30 +000010//===----------------------------------------------------------------------===//
11//
12// This file provides the Win32 specific implementation of the Path class.
13//
14//===----------------------------------------------------------------------===//
15
16//===----------------------------------------------------------------------===//
Reid Spencerb016a372004-09-15 05:49:50 +000017//=== WARNING: Implementation here must contain only generic Win32 code that
18//=== is guaranteed to work on *all* Win32 variants.
Reid Spencercbad7012004-09-11 04:59:30 +000019//===----------------------------------------------------------------------===//
20
Reid Spencerb016a372004-09-15 05:49:50 +000021#include <llvm/Config/config.h>
22#include <limits.h>
23#include <stdarg.h>
24#include <assert.h>
25#include <fcntl.h>
26#include <sys/stat.h>
27#include <llvm/System/Path.h>
28
29#include <windef.h>
30#include <winbase.h>
31
32#define MAXPATHLEN PATH_MAX
Reid Spencercbad7012004-09-11 04:59:30 +000033
34namespace llvm {
Reid Spencerb016a372004-09-15 05:49:50 +000035namespace sys {
Reid Spencercbad7012004-09-11 04:59:30 +000036
Reid Spencerb016a372004-09-15 05:49:50 +000037bool
38Path::is_valid() const {
39 if (path.empty())
40 return false;
41/*hb: char pathname[MAXPATHLEN];
42 if (0 == realpath(path.c_str(), pathname))
43 if (errno != EACCES && errno != EIO && errno != ENOENT && errno !=
44ENOTDIR)
45 return false;*/
46 return true;
Reid Spencercbad7012004-09-11 04:59:30 +000047}
48
Reid Spencerb016a372004-09-15 05:49:50 +000049Path
50Path::GetTemporaryDirectory() {
51 char pathname[MAXPATHLEN];
52 if (0 == GetTempPath(MAXPATHLEN,pathname))
53 ThrowError(std::string(pathname) + ": Can't create temporary directory");
54 Path result;
55 result.set_directory(pathname);
56 assert(result.is_valid() && "GetTempPath didn't create a valid pathname!");
57 return result;
58}
59
60Path::Path(std::string unverified_path)
61 : path(unverified_path)
62{
63 if (unverified_path.empty())
64 return;
65 if (this->is_valid())
66 return;
67 // oops, not valid.
68 path.clear();
69 ThrowError(unverified_path + ": path is not valid");
70}
71
72Path
73Path::GetRootDirectory() {
74 Path result;
75 result.set_directory("/");
76 return result;
77}
78
79Path
80Path::GetSystemLibraryPath1() {
81 return Path("/lib/");
82}
83
84Path
85Path::GetSystemLibraryPath2() {
86 return Path("/usr/lib/");
87}
88
89Path
90Path::GetLLVMDefaultConfigDir() {
91 return Path("/etc/llvm/");
92}
93
94Path
95Path::GetLLVMConfigDir() {
96 Path result;
97 if (result.set_directory(LLVM_ETCDIR))
98 return result;
99 return GetLLVMDefaultConfigDir();
100}
101
102Path
103Path::GetUserHomeDirectory() {
104 const char* home = getenv("HOME");
105 if (home) {
106 Path result;
107 if (result.set_directory(home))
108 return result;
109 }
110 return GetRootDirectory();
111}
112
113bool
114Path::exists() const {
115 return 0 == access(path.c_str(), F_OK );
116}
117
118bool
119Path::readable() const {
120 return 0 == access(path.c_str(), F_OK | R_OK );
121}
122
123bool
124Path::writable() const {
125 return 0 == access(path.c_str(), F_OK | W_OK );
126}
127
128bool
129Path::executable() const {
130 return 0 == access(path.c_str(), R_OK | X_OK );
131}
132
133std::string
134Path::getLast() const {
135 // Find the last slash
136 size_t pos = path.rfind('/');
137
138 // Handle the corner cases
139 if (pos == std::string::npos)
140 return path;
141
142 // If the last character is a slash
143 if (pos == path.length()-1) {
144 // Find the second to last slash
145 size_t pos2 = path.rfind('/', pos-1);
146 if (pos2 == std::string::npos)
147 return path.substr(0,pos);
148 else
149 return path.substr(pos2+1,pos-pos2-1);
150 }
151 // Return everything after the last slash
152 return path.substr(pos+1);
153}
154
155bool
156Path::set_directory(const std::string& a_path) {
157 if (a_path.size() == 0)
158 return false;
159 Path save(*this);
160 path = a_path;
161 size_t last = a_path.size() -1;
162 if (last != 0 && a_path[last] != '/')
163 path += '/';
164 if (!is_valid()) {
165 path = save.path;
166 return false;
167 }
168 return true;
169}
170
171bool
172Path::set_file(const std::string& a_path) {
173 if (a_path.size() == 0)
174 return false;
175 Path save(*this);
176 path = a_path;
177 size_t last = a_path.size() - 1;
178 while (last > 0 && a_path[last] == '/')
179 last--;
180 path.erase(last+1);
181 if (!is_valid()) {
182 path = save.path;
183 return false;
184 }
185 return true;
186}
187
188bool
189Path::append_directory(const std::string& dir) {
190 if (is_file())
191 return false;
192 Path save(*this);
193 path += dir;
194 path += "/";
195 if (!is_valid()) {
196 path = save.path;
197 return false;
198 }
199 return true;
200}
201
202bool
203Path::elide_directory() {
204 if (is_file())
205 return false;
206 size_t slashpos = path.rfind('/',path.size());
207 if (slashpos == 0 || slashpos == std::string::npos)
208 return false;
209 if (slashpos == path.size() - 1)
210 slashpos = path.rfind('/',slashpos-1);
211 if (slashpos == std::string::npos)
212 return false;
213 path.erase(slashpos);
214 return true;
215}
216
217bool
218Path::append_file(const std::string& file) {
219 if (!is_directory())
220 return false;
221 Path save(*this);
222 path += file;
223 if (!is_valid()) {
224 path = save.path;
225 return false;
226 }
227 return true;
228}
229
230bool
231Path::elide_file() {
232 if (is_directory())
233 return false;
234 size_t slashpos = path.rfind('/',path.size());
235 if (slashpos == std::string::npos)
236 return false;
237 path.erase(slashpos+1);
238 return true;
239}
240
241bool
242Path::append_suffix(const std::string& suffix) {
243 if (is_directory())
244 return false;
245 Path save(*this);
246 path.append(".");
247 path.append(suffix);
248 if (!is_valid()) {
249 path = save.path;
250 return false;
251 }
252 return true;
253}
254
255bool
256Path::elide_suffix() {
257 if (is_directory()) return false;
258 size_t dotpos = path.rfind('.',path.size());
259 size_t slashpos = path.rfind('/',path.size());
260 if (slashpos != std::string::npos && dotpos != std::string::npos &&
261 dotpos > slashpos) {
262 path.erase(dotpos, path.size()-dotpos);
263 return true;
264 }
265 return false;
266}
267
268
269bool
270Path::create_directory( bool create_parents) {
271 // Make sure we're dealing with a directory
272 if (!is_directory()) return false;
273
274 // Get a writeable copy of the path name
275 char pathname[MAXPATHLEN];
276 path.copy(pathname,MAXPATHLEN);
277
278 // Null-terminate the last component
279 int lastchar = path.length() - 1 ;
280 if (pathname[lastchar] == '/')
281 pathname[lastchar] = 0;
282
283 // If we're supposed to create intermediate directories
284 if ( create_parents ) {
285 // Find the end of the initial name component
286 char * next = strchr(pathname,'/');
287 if ( pathname[0] == '/')
288 next = strchr(&pathname[1],'/');
289
290 // Loop through the directory components until we're done
291 while ( next != 0 ) {
292 *next = 0;
293 if (0 != access(pathname, F_OK | R_OK | W_OK))
294 if (0 != mkdir(pathname))
295 ThrowError(std::string(pathname) + ": Can't create directory");
296 char* save = next;
297 next = strchr(pathname,'/');
298 *save = '/';
299 }
300 } else if (0 != mkdir(pathname)) {
301 ThrowError(std::string(pathname) + ": Can't create directory");
302 }
303 return true;
304}
305
306bool
307Path::create_file() {
308 // Make sure we're dealing with a file
309 if (!is_file()) return false;
310
311 // Create the file
312 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
313 ThrowError(std::string(path.c_str()) + ": Can't create file");
314
315 return true;
316}
317
318bool
319Path::destroy_directory(bool remove_contents) {
320 // Make sure we're dealing with a directory
321 if (!is_directory()) return false;
322
323 // If it doesn't exist, we're done.
324 if (!exists()) return true;
325
326 if (remove_contents) {
327 // Recursively descend the directory to remove its content
328 std::string cmd("/bin/rm -rf ");
329 cmd += path;
330 system(cmd.c_str());
331 } else {
332 // Otherwise, try to just remove the one directory
333 char pathname[MAXPATHLEN];
334 path.copy(pathname,MAXPATHLEN);
335 int lastchar = path.length() - 1 ;
336 if (pathname[lastchar] == '/')
337 pathname[lastchar] = 0;
338 if ( 0 != rmdir(pathname))
339 ThrowError(std::string(pathname) + ": Can't destroy directory");
340 }
341 return true;
342}
343
344bool
345Path::destroy_file() {
346 if (!is_file()) return false;
347 if (0 != unlink(path.c_str()))
348 ThrowError(std::string(path.c_str()) + ": Can't destroy file");
349 return true;
350}
351
352}
Reid Spencercbad7012004-09-11 04:59:30 +0000353}
354
355// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
Reid Spencerb016a372004-09-15 05:49:50 +0000356