blob: 4f4d347f0928e9e17b6e33ac2fa49f4ad3dda8c8 [file] [log] [blame]
Reid Spencerb89a2232004-08-25 06:20:07 +00001//===- 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
Reid Spencer8e665952004-08-29 05:24:01 +000016//=== is guaranteed to work on *all* UNIX variants.
Reid Spencerb89a2232004-08-25 06:20:07 +000017//===----------------------------------------------------------------------===//
18
Reid Spencer551ccae2004-09-01 22:55:40 +000019#include <llvm/Config/config.h>
Reid Spencerb89a2232004-08-25 06:20:07 +000020#include "Unix.h"
21#include <sys/stat.h>
22#include <fcntl.h>
Reid Spencer1b554b42004-09-11 04:55:08 +000023#include <fstream>
Reid Spencerb89a2232004-08-25 06:20:07 +000024
Reid Spencer8e665952004-08-29 05:24:01 +000025namespace llvm {
26using namespace sys;
Reid Spencerb89a2232004-08-25 06:20:07 +000027
Reid Spencer8e665952004-08-29 05:24:01 +000028Path::Path(std::string unverified_path)
29 : path(unverified_path)
Reid Spencerb89a2232004-08-25 06:20:07 +000030{
Reid Spencer8e665952004-08-29 05:24:01 +000031 if (unverified_path.empty())
32 return;
Reid Spencer07adb282004-11-05 22:15:36 +000033 if (this->isValid())
Reid Spencer8e665952004-08-29 05:24:01 +000034 return;
35 // oops, not valid.
36 path.clear();
37 ThrowErrno(unverified_path + ": path is not valid");
Reid Spencerb89a2232004-08-25 06:20:07 +000038}
39
Reid Spencer8e665952004-08-29 05:24:01 +000040Path
41Path::GetRootDirectory() {
42 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +000043 result.setDirectory("/");
Reid Spencer8e665952004-08-29 05:24:01 +000044 return result;
45}
46
Reid Spencer74e72612004-09-14 00:16:39 +000047static inline bool IsLibrary(Path& path, const std::string& basename) {
Reid Spencer07adb282004-11-05 22:15:36 +000048 if (path.appendFile(std::string("lib") + basename)) {
49 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000050 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000051 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000052 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000053 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000054 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000055 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
Reid Spencer0cc2d0a2004-09-16 16:36:10 +000056 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000057 } else if (path.elideFile() && path.appendFile(basename)) {
58 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000059 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000060 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000061 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000062 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
Reid Spencer74e72612004-09-14 00:16:39 +000063 return true;
Reid Spencer07adb282004-11-05 22:15:36 +000064 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
Reid Spencer0cc2d0a2004-09-16 16:36:10 +000065 return true;
Reid Spencer74e72612004-09-14 00:16:39 +000066 }
67 path.clear();
68 return false;
69}
70
71Path
72Path::GetLibraryPath(const std::string& basename,
73 const std::vector<std::string>& LibPaths) {
74 Path result;
75
76 // Try the paths provided
77 for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
78 E = LibPaths.end(); I != E; ++I ) {
Reid Spencer07adb282004-11-05 22:15:36 +000079 if (result.setDirectory(*I) && IsLibrary(result,basename))
Reid Spencer74e72612004-09-14 00:16:39 +000080 return result;
81 }
82
Reid Spencer0cc2d0a2004-09-16 16:36:10 +000083 // Try the LLVM lib directory in the LLVM install area
Reid Spencer07adb282004-11-05 22:15:36 +000084 if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename))
Reid Spencer0cc2d0a2004-09-16 16:36:10 +000085 return result;
86
Reid Spencer74e72612004-09-14 00:16:39 +000087 // Try /usr/lib
Reid Spencer07adb282004-11-05 22:15:36 +000088 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename))
Reid Spencer74e72612004-09-14 00:16:39 +000089 return result;
90
91 // Try /lib
Reid Spencer07adb282004-11-05 22:15:36 +000092 if (result.setDirectory("/lib/") && IsLibrary(result,basename))
Reid Spencer74e72612004-09-14 00:16:39 +000093 return result;
94
95 // Can't find it, give up and return invalid path.
96 result.clear();
97 return result;
98}
99
Reid Spencer8e665952004-08-29 05:24:01 +0000100Path
101Path::GetSystemLibraryPath1() {
102 return Path("/lib/");
103}
104
105Path
106Path::GetSystemLibraryPath2() {
107 return Path("/usr/lib/");
108}
109
110Path
111Path::GetLLVMDefaultConfigDir() {
112 return Path("/etc/llvm/");
113}
114
115Path
116Path::GetLLVMConfigDir() {
117 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000118 if (result.setDirectory(LLVM_ETCDIR))
Reid Spencer8e665952004-08-29 05:24:01 +0000119 return result;
120 return GetLLVMDefaultConfigDir();
121}
122
123Path
124Path::GetUserHomeDirectory() {
125 const char* home = getenv("HOME");
126 if (home) {
127 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000128 if (result.setDirectory(home))
Reid Spencer8e665952004-08-29 05:24:01 +0000129 return result;
130 }
131 return GetRootDirectory();
132}
133
134bool
Reid Spencer07adb282004-11-05 22:15:36 +0000135Path::isFile() const {
136 return (isValid() && path[path.length()-1] != '/');
Reid Spencer1b554b42004-09-11 04:55:08 +0000137}
138
139bool
Reid Spencer07adb282004-11-05 22:15:36 +0000140Path::isDirectory() const {
141 return (isValid() && path[path.length()-1] == '/');
Reid Spencer1b554b42004-09-11 04:55:08 +0000142}
143
144std::string
Reid Spencer07adb282004-11-05 22:15:36 +0000145Path::getBasename() const {
Reid Spencer1b554b42004-09-11 04:55:08 +0000146 // Find the last slash
147 size_t slash = path.rfind('/');
148 if (slash == std::string::npos)
149 slash = 0;
150 else
151 slash++;
152
153 return path.substr(slash, path.rfind('.'));
154}
155
Reid Spencer07adb282004-11-05 22:15:36 +0000156bool Path::hasMagicNumber(const std::string &Magic) const {
Reid Spencer1b554b42004-09-11 04:55:08 +0000157 size_t len = Magic.size();
158 char buf[ 1 + len];
159 std::ifstream f(path.c_str());
160 f.read(buf, len);
161 buf[len] = '\0';
162 return Magic == buf;
163}
164
165bool
Reid Spencer07adb282004-11-05 22:15:36 +0000166Path::isBytecodeFile() const {
Reid Spencer1b554b42004-09-11 04:55:08 +0000167 if (readable()) {
Reid Spencer07adb282004-11-05 22:15:36 +0000168 return hasMagicNumber("llvm");
Reid Spencer1b554b42004-09-11 04:55:08 +0000169 }
170 return false;
171}
172
173bool
Reid Spencer07adb282004-11-05 22:15:36 +0000174Path::isArchive() const {
Reid Spencer1b554b42004-09-11 04:55:08 +0000175 if (readable()) {
Reid Spencer07adb282004-11-05 22:15:36 +0000176 return hasMagicNumber("!<arch>\012");
Reid Spencer1b554b42004-09-11 04:55:08 +0000177 }
178 return false;
179}
180
181bool
Reid Spencer8e665952004-08-29 05:24:01 +0000182Path::exists() const {
183 return 0 == access(path.c_str(), F_OK );
184}
185
186bool
187Path::readable() const {
188 return 0 == access(path.c_str(), F_OK | R_OK );
189}
190
191bool
192Path::writable() const {
193 return 0 == access(path.c_str(), F_OK | W_OK );
194}
195
196bool
197Path::executable() const {
198 return 0 == access(path.c_str(), R_OK | X_OK );
199}
200
201std::string
202Path::getLast() const {
203 // Find the last slash
204 size_t pos = path.rfind('/');
205
206 // Handle the corner cases
207 if (pos == std::string::npos)
208 return path;
209
210 // If the last character is a slash
211 if (pos == path.length()-1) {
212 // Find the second to last slash
213 size_t pos2 = path.rfind('/', pos-1);
214 if (pos2 == std::string::npos)
215 return path.substr(0,pos);
216 else
217 return path.substr(pos2+1,pos-pos2-1);
218 }
219 // Return everything after the last slash
220 return path.substr(pos+1);
221}
222
223bool
Reid Spencer07adb282004-11-05 22:15:36 +0000224Path::setDirectory(const std::string& a_path) {
Reid Spencer8e665952004-08-29 05:24:01 +0000225 if (a_path.size() == 0)
226 return false;
227 Path save(*this);
228 path = a_path;
229 size_t last = a_path.size() -1;
230 if (last != 0 && a_path[last] != '/')
231 path += '/';
Reid Spencer07adb282004-11-05 22:15:36 +0000232 if (!isValid()) {
Reid Spencer8e665952004-08-29 05:24:01 +0000233 path = save.path;
234 return false;
235 }
236 return true;
237}
238
239bool
Reid Spencer07adb282004-11-05 22:15:36 +0000240Path::setFile(const std::string& a_path) {
Reid Spencer8e665952004-08-29 05:24:01 +0000241 if (a_path.size() == 0)
242 return false;
243 Path save(*this);
244 path = a_path;
245 size_t last = a_path.size() - 1;
246 while (last > 0 && a_path[last] == '/')
247 last--;
248 path.erase(last+1);
Reid Spencer07adb282004-11-05 22:15:36 +0000249 if (!isValid()) {
Reid Spencer8e665952004-08-29 05:24:01 +0000250 path = save.path;
251 return false;
252 }
253 return true;
254}
255
256bool
Reid Spencer07adb282004-11-05 22:15:36 +0000257Path::appendDirectory(const std::string& dir) {
258 if (isFile())
Reid Spencer8e665952004-08-29 05:24:01 +0000259 return false;
260 Path save(*this);
261 path += dir;
262 path += "/";
Reid Spencer07adb282004-11-05 22:15:36 +0000263 if (!isValid()) {
Reid Spencer8e665952004-08-29 05:24:01 +0000264 path = save.path;
265 return false;
266 }
267 return true;
268}
269
270bool
Reid Spencer07adb282004-11-05 22:15:36 +0000271Path::elideDirectory() {
272 if (isFile())
Reid Spencer8e665952004-08-29 05:24:01 +0000273 return false;
274 size_t slashpos = path.rfind('/',path.size());
275 if (slashpos == 0 || slashpos == std::string::npos)
276 return false;
277 if (slashpos == path.size() - 1)
278 slashpos = path.rfind('/',slashpos-1);
279 if (slashpos == std::string::npos)
280 return false;
281 path.erase(slashpos);
282 return true;
283}
284
285bool
Reid Spencer07adb282004-11-05 22:15:36 +0000286Path::appendFile(const std::string& file) {
287 if (!isDirectory())
Reid Spencer8e665952004-08-29 05:24:01 +0000288 return false;
289 Path save(*this);
290 path += file;
Reid Spencer07adb282004-11-05 22:15:36 +0000291 if (!isValid()) {
Reid Spencer8e665952004-08-29 05:24:01 +0000292 path = save.path;
293 return false;
294 }
295 return true;
296}
297
298bool
Reid Spencer07adb282004-11-05 22:15:36 +0000299Path::elideFile() {
300 if (isDirectory())
Reid Spencer8e665952004-08-29 05:24:01 +0000301 return false;
302 size_t slashpos = path.rfind('/',path.size());
303 if (slashpos == std::string::npos)
304 return false;
305 path.erase(slashpos+1);
306 return true;
307}
308
309bool
Reid Spencer07adb282004-11-05 22:15:36 +0000310Path::appendSuffix(const std::string& suffix) {
311 if (isDirectory())
Reid Spencer8e665952004-08-29 05:24:01 +0000312 return false;
313 Path save(*this);
314 path.append(".");
315 path.append(suffix);
Reid Spencer07adb282004-11-05 22:15:36 +0000316 if (!isValid()) {
Reid Spencer8e665952004-08-29 05:24:01 +0000317 path = save.path;
318 return false;
319 }
320 return true;
321}
322
323bool
Reid Spencer07adb282004-11-05 22:15:36 +0000324Path::elideSuffix() {
325 if (isDirectory()) return false;
Reid Spencer8e665952004-08-29 05:24:01 +0000326 size_t dotpos = path.rfind('.',path.size());
327 size_t slashpos = path.rfind('/',path.size());
328 if (slashpos != std::string::npos && dotpos != std::string::npos &&
329 dotpos > slashpos) {
330 path.erase(dotpos, path.size()-dotpos);
331 return true;
332 }
333 return false;
334}
335
336
337bool
Reid Spencer07adb282004-11-05 22:15:36 +0000338Path::createDirectory( bool create_parents) {
Reid Spencer8e665952004-08-29 05:24:01 +0000339 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000340 if (!isDirectory()) return false;
Reid Spencer8e665952004-08-29 05:24:01 +0000341
342 // Get a writeable copy of the path name
343 char pathname[MAXPATHLEN];
344 path.copy(pathname,MAXPATHLEN);
345
346 // Null-terminate the last component
347 int lastchar = path.length() - 1 ;
348 if (pathname[lastchar] == '/')
349 pathname[lastchar] = 0;
350
351 // If we're supposed to create intermediate directories
352 if ( create_parents ) {
353 // Find the end of the initial name component
354 char * next = strchr(pathname,'/');
355 if ( pathname[0] == '/')
356 next = strchr(&pathname[1],'/');
357
358 // Loop through the directory components until we're done
359 while ( next != 0 ) {
360 *next = 0;
361 if (0 != access(pathname, F_OK | R_OK | W_OK))
362 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
363 ThrowErrno(std::string(pathname) + ": Can't create directory");
364 char* save = next;
365 next = strchr(pathname,'/');
366 *save = '/';
367 }
368 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
369 ThrowErrno(std::string(pathname) + ": Can't create directory");
370 }
371 return true;
372}
373
374bool
Reid Spencer07adb282004-11-05 22:15:36 +0000375Path::createFile() {
Reid Spencer8e665952004-08-29 05:24:01 +0000376 // Make sure we're dealing with a file
Reid Spencer07adb282004-11-05 22:15:36 +0000377 if (!isFile()) return false;
Reid Spencer8e665952004-08-29 05:24:01 +0000378
379 // Create the file
Reid Spencer622e2202004-09-18 19:25:11 +0000380 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
381 if (fd < 0)
Reid Spencer8e665952004-08-29 05:24:01 +0000382 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
Reid Spencer622e2202004-09-18 19:25:11 +0000383 ::close(fd);
Reid Spencer8e665952004-08-29 05:24:01 +0000384
385 return true;
Reid Spencerb89a2232004-08-25 06:20:07 +0000386}
387
Reid Spencer8e665952004-08-29 05:24:01 +0000388bool
Reid Spencer07adb282004-11-05 22:15:36 +0000389Path::destroyDirectory(bool remove_contents) {
Reid Spencer8e665952004-08-29 05:24:01 +0000390 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000391 if (!isDirectory()) return false;
Reid Spencer8e665952004-08-29 05:24:01 +0000392
393 // If it doesn't exist, we're done.
394 if (!exists()) return true;
395
396 if (remove_contents) {
397 // Recursively descend the directory to remove its content
398 std::string cmd("/bin/rm -rf ");
399 cmd += path;
400 system(cmd.c_str());
401 } else {
402 // Otherwise, try to just remove the one directory
403 char pathname[MAXPATHLEN];
404 path.copy(pathname,MAXPATHLEN);
405 int lastchar = path.length() - 1 ;
406 if (pathname[lastchar] == '/')
407 pathname[lastchar] = 0;
408 if ( 0 != rmdir(pathname))
409 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
410 }
411 return true;
412}
413
414bool
Reid Spencer07adb282004-11-05 22:15:36 +0000415Path::destroyFile() {
416 if (!isFile()) return false;
Reid Spencer8e665952004-08-29 05:24:01 +0000417 if (0 != unlink(path.c_str()))
418 ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
419 return true;
420}
421
Reid Spencerb89a2232004-08-25 06:20:07 +0000422}
423
424// vim: sw=2