1 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
10 // This file implements the Unix specific portion of the Path class.
12 //===----------------------------------------------------------------------===//
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //=== is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
19 #include <llvm/Config/config.h>
20 #include <llvm/Config/alloca.h>
31 Path::Path(std::string unverified_path)
32 : path(unverified_path)
34 if (unverified_path.empty())
40 ThrowErrno(unverified_path + ": path is not valid");
44 Path::GetRootDirectory() {
46 result.setDirectory("/");
50 static inline bool IsLibrary(Path& path, const std::string& basename) {
51 if (path.appendFile(std::string("lib") + basename)) {
52 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
54 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
56 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
58 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
60 } else if (path.elideFile() && path.appendFile(basename)) {
61 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
63 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
65 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
67 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
75 Path::GetLibraryPath(const std::string& basename,
76 const std::vector<std::string>& LibPaths) {
79 // Try the paths provided
80 for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
81 E = LibPaths.end(); I != E; ++I ) {
82 if (result.setDirectory(*I) && IsLibrary(result,basename))
86 // Try the LLVM lib directory in the LLVM install area
87 if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename))
91 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename))
95 if (result.setDirectory("/lib/") && IsLibrary(result,basename))
98 // Can't find it, give up and return invalid path.
104 Path::GetSystemLibraryPath1() {
105 return Path("/lib/");
109 Path::GetSystemLibraryPath2() {
110 return Path("/usr/lib/");
114 Path::GetLLVMDefaultConfigDir() {
115 return Path("/etc/llvm/");
119 Path::GetLLVMConfigDir() {
121 if (result.setDirectory(LLVM_ETCDIR))
123 return GetLLVMDefaultConfigDir();
127 Path::GetUserHomeDirectory() {
128 const char* home = getenv("HOME");
131 if (result.setDirectory(home))
134 return GetRootDirectory();
138 Path::isFile() const {
139 return (isValid() && path[path.length()-1] != '/');
143 Path::isDirectory() const {
144 return (isValid() && path[path.length()-1] == '/');
148 Path::getBasename() const {
149 // Find the last slash
150 size_t slash = path.rfind('/');
151 if (slash == std::string::npos)
156 return path.substr(slash, path.rfind('.'));
159 bool Path::hasMagicNumber(const std::string &Magic) const {
160 size_t len = Magic.size();
161 assert(len < 1024 && "Request for magic string too long");
162 char* buf = (char*) alloca(1 + len);
163 int fd = ::open(path.c_str(),O_RDONLY);
166 if (0 != ::read(fd, buf, len))
173 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
176 assert(len < 1024 && "Request for magic string too long");
177 char* buf = (char*) alloca(1 + len);
178 int fd = ::open(path.c_str(),O_RDONLY);
181 if (0 != ::read(fd, buf, len))
190 Path::isBytecodeFile() const {
193 std::ifstream f(path.c_str());
196 ThrowErrno("can't read file signature");
198 return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' &&
199 (buffer[3] == 'c' || buffer[3] == 'm'));
203 Path::isArchive() const {
205 return hasMagicNumber("!<arch>\012");
211 Path::exists() const {
212 return 0 == access(path.c_str(), F_OK );
216 Path::readable() const {
217 return 0 == access(path.c_str(), F_OK | R_OK );
221 Path::writable() const {
222 return 0 == access(path.c_str(), F_OK | W_OK );
226 Path::executable() const {
227 return 0 == access(path.c_str(), R_OK | X_OK );
231 Path::getLast() const {
232 // Find the last slash
233 size_t pos = path.rfind('/');
235 // Handle the corner cases
236 if (pos == std::string::npos)
239 // If the last character is a slash
240 if (pos == path.length()-1) {
241 // Find the second to last slash
242 size_t pos2 = path.rfind('/', pos-1);
243 if (pos2 == std::string::npos)
244 return path.substr(0,pos);
246 return path.substr(pos2+1,pos-pos2-1);
248 // Return everything after the last slash
249 return path.substr(pos+1);
253 Path::getStatusInfo(StatusInfo& info) const {
255 if (0 != stat(path.c_str(), &buf)) {
256 ThrowErrno(std::string("Can't get status: ")+path);
258 info.fileSize = buf.st_size;
259 info.modTime.fromEpochTime(buf.st_mtime);
260 info.mode = buf.st_mode;
261 info.user = buf.st_uid;
262 info.group = buf.st_gid;
263 info.isDir = S_ISDIR(buf.st_mode);
264 if (info.isDir && path[path.length()-1] != '/')
269 Path::getDirectoryContents(std::set<Path>& result) const {
272 DIR* direntries = ::opendir(path.c_str());
274 ThrowErrno(path + ": can't open directory");
277 struct dirent* de = ::readdir(direntries);
279 if (de->d_name[0] != '.') {
280 Path aPath(path + (const char*)de->d_name);
282 if (0 != stat(aPath.path.c_str(), &buf))
283 ThrowErrno(aPath.path + ": can't get status");
284 if (S_ISDIR(buf.st_mode))
286 result.insert(aPath);
288 de = ::readdir(direntries);
291 closedir(direntries);
296 Path::setDirectory(const std::string& a_path) {
297 if (a_path.size() == 0)
301 size_t last = a_path.size() -1;
302 if (last != 0 && a_path[last] != '/')
312 Path::setFile(const std::string& a_path) {
313 if (a_path.size() == 0)
317 size_t last = a_path.size() - 1;
318 while (last > 0 && a_path[last] == '/')
329 Path::appendDirectory(const std::string& dir) {
343 Path::elideDirectory() {
346 size_t slashpos = path.rfind('/',path.size());
347 if (slashpos == 0 || slashpos == std::string::npos)
349 if (slashpos == path.size() - 1)
350 slashpos = path.rfind('/',slashpos-1);
351 if (slashpos == std::string::npos)
353 path.erase(slashpos);
358 Path::appendFile(const std::string& file) {
374 size_t slashpos = path.rfind('/',path.size());
375 if (slashpos == std::string::npos)
377 path.erase(slashpos+1);
382 Path::appendSuffix(const std::string& suffix) {
396 Path::elideSuffix() {
397 if (isDirectory()) return false;
398 size_t dotpos = path.rfind('.',path.size());
399 size_t slashpos = path.rfind('/',path.size());
400 if (slashpos != std::string::npos && dotpos != std::string::npos &&
402 path.erase(dotpos, path.size()-dotpos);
410 Path::createDirectory( bool create_parents) {
411 // Make sure we're dealing with a directory
412 if (!isDirectory()) return false;
414 // Get a writeable copy of the path name
415 char pathname[MAXPATHLEN];
416 path.copy(pathname,MAXPATHLEN);
418 // Null-terminate the last component
419 int lastchar = path.length() - 1 ;
420 if (pathname[lastchar] == '/')
421 pathname[lastchar] = 0;
423 pathname[lastchar+1] = 0;
425 // If we're supposed to create intermediate directories
426 if ( create_parents ) {
427 // Find the end of the initial name component
428 char * next = strchr(pathname,'/');
429 if ( pathname[0] == '/')
430 next = strchr(&pathname[1],'/');
432 // Loop through the directory components until we're done
433 while ( next != 0 ) {
435 if (0 != access(pathname, F_OK | R_OK | W_OK))
436 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
437 ThrowErrno(std::string(pathname) + ": Can't create directory");
439 next = strchr(next+1,'/');
444 if (0 != access(pathname, F_OK | R_OK))
445 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
446 ThrowErrno(std::string(pathname) + ": Can't create directory");
452 // Make sure we're dealing with a file
453 if (!isFile()) return false;
456 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
458 ThrowErrno(path + ": Can't create file");
465 Path::createTemporaryFile() {
466 // Make sure we're dealing with a file
467 if (!isFile()) return false;
469 // Append the filename filler
470 char pathname[MAXPATHLEN];
471 path.copy(pathname,MAXPATHLEN);
472 pathname[path.length()] = 0;
473 strcat(pathname,"XXXXXX");
474 int fd = ::mkstemp(pathname);
476 ThrowErrno(path + ": Can't create temporary file");
484 Path::destroyDirectory(bool remove_contents) {
485 // Make sure we're dealing with a directory
486 if (!isDirectory()) return false;
488 // If it doesn't exist, we're done.
489 if (!exists()) return true;
491 if (remove_contents) {
492 // Recursively descend the directory to remove its content
493 std::string cmd("/bin/rm -rf ");
497 // Otherwise, try to just remove the one directory
498 char pathname[MAXPATHLEN];
499 path.copy(pathname,MAXPATHLEN);
500 int lastchar = path.length() - 1 ;
501 if (pathname[lastchar] == '/')
502 pathname[lastchar] = 0;
504 pathname[lastchar+1] = 0;
505 if ( 0 != rmdir(pathname))
506 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
512 Path::destroyFile() {
513 if (!isFile()) return false;
514 if (0 != unlink(path.c_str()))
515 ThrowErrno(path + ": Can't destroy file");
520 Path::renameFile(const Path& newName) {
521 if (!isFile()) return false;
522 if (0 != rename(path.c_str(), newName.c_str()))
523 ThrowErrno(std::string("can't rename ") + path + " as " + newName.get());
528 Path::setStatusInfo(const StatusInfo& si) const {
529 if (!isFile()) return false;
531 utb.actime = si.modTime.toPosixTime();
532 utb.modtime = utb.actime;
533 if (0 != ::utime(path.c_str(),&utb))
534 ThrowErrno(path + ": can't set file modification time");
535 if (0 != ::chmod(path.c_str(),si.mode))
536 ThrowErrno(path + ": can't set mode");