LLVM API Documentation
00001 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Reid Spencer and is distributed under the 00006 // University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the Unix specific portion of the Path class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 //===----------------------------------------------------------------------===// 00015 //=== WARNING: Implementation here must contain only generic UNIX code that 00016 //=== is guaranteed to work on *all* UNIX variants. 00017 //===----------------------------------------------------------------------===// 00018 00019 #include <llvm/Config/config.h> 00020 #include <llvm/Config/alloca.h> 00021 #include "Unix.h" 00022 #include <sys/stat.h> 00023 #include <fcntl.h> 00024 #include <fstream> 00025 #include <utime.h> 00026 #include <dirent.h> 00027 00028 namespace llvm { 00029 using namespace sys; 00030 00031 Path::Path(std::string unverified_path) 00032 : path(unverified_path) 00033 { 00034 if (unverified_path.empty()) 00035 return; 00036 if (this->isValid()) 00037 return; 00038 // oops, not valid. 00039 path.clear(); 00040 ThrowErrno(unverified_path + ": path is not valid"); 00041 } 00042 00043 Path 00044 Path::GetRootDirectory() { 00045 Path result; 00046 result.setDirectory("/"); 00047 return result; 00048 } 00049 00050 static inline bool IsLibrary(Path& path, const std::string& basename) { 00051 if (path.appendFile(std::string("lib") + basename)) { 00052 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable()) 00053 return true; 00054 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable()) 00055 return true; 00056 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable()) 00057 return true; 00058 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable()) 00059 return true; 00060 } else if (path.elideFile() && path.appendFile(basename)) { 00061 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable()) 00062 return true; 00063 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable()) 00064 return true; 00065 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable()) 00066 return true; 00067 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable()) 00068 return true; 00069 } 00070 path.clear(); 00071 return false; 00072 } 00073 00074 Path 00075 Path::GetLibraryPath(const std::string& basename, 00076 const std::vector<std::string>& LibPaths) { 00077 Path result; 00078 00079 // Try the paths provided 00080 for (std::vector<std::string>::const_iterator I = LibPaths.begin(), 00081 E = LibPaths.end(); I != E; ++I ) { 00082 if (result.setDirectory(*I) && IsLibrary(result,basename)) 00083 return result; 00084 } 00085 00086 // Try the LLVM lib directory in the LLVM install area 00087 if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename)) 00088 return result; 00089 00090 // Try /usr/lib 00091 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename)) 00092 return result; 00093 00094 // Try /lib 00095 if (result.setDirectory("/lib/") && IsLibrary(result,basename)) 00096 return result; 00097 00098 // Can't find it, give up and return invalid path. 00099 result.clear(); 00100 return result; 00101 } 00102 00103 Path 00104 Path::GetSystemLibraryPath1() { 00105 return Path("/lib/"); 00106 } 00107 00108 Path 00109 Path::GetSystemLibraryPath2() { 00110 return Path("/usr/lib/"); 00111 } 00112 00113 Path 00114 Path::GetLLVMDefaultConfigDir() { 00115 return Path("/etc/llvm/"); 00116 } 00117 00118 Path 00119 Path::GetLLVMConfigDir() { 00120 Path result; 00121 if (result.setDirectory(LLVM_ETCDIR)) 00122 return result; 00123 return GetLLVMDefaultConfigDir(); 00124 } 00125 00126 Path 00127 Path::GetUserHomeDirectory() { 00128 const char* home = getenv("HOME"); 00129 if (home) { 00130 Path result; 00131 if (result.setDirectory(home)) 00132 return result; 00133 } 00134 return GetRootDirectory(); 00135 } 00136 00137 bool 00138 Path::isFile() const { 00139 return (isValid() && path[path.length()-1] != '/'); 00140 } 00141 00142 bool 00143 Path::isDirectory() const { 00144 return (isValid() && path[path.length()-1] == '/'); 00145 } 00146 00147 std::string 00148 Path::getBasename() const { 00149 // Find the last slash 00150 size_t slash = path.rfind('/'); 00151 if (slash == std::string::npos) 00152 slash = 0; 00153 else 00154 slash++; 00155 00156 return path.substr(slash, path.rfind('.')); 00157 } 00158 00159 bool Path::hasMagicNumber(const std::string &Magic) const { 00160 size_t len = Magic.size(); 00161 assert(len < 1024 && "Request for magic string too long"); 00162 char* buf = (char*) alloca(1 + len); 00163 int fd = ::open(path.c_str(),O_RDONLY); 00164 if (fd < 0) 00165 return false; 00166 if (0 != ::read(fd, buf, len)) 00167 return false; 00168 close(fd); 00169 buf[len] = '\0'; 00170 return Magic == buf; 00171 } 00172 00173 bool Path::getMagicNumber(std::string& Magic, unsigned len) const { 00174 if (!isFile()) 00175 return false; 00176 assert(len < 1024 && "Request for magic string too long"); 00177 char* buf = (char*) alloca(1 + len); 00178 int fd = ::open(path.c_str(),O_RDONLY); 00179 if (fd < 0) 00180 return false; 00181 ssize_t bytes_read = ::read(fd, buf, len); 00182 ::close(fd); 00183 if (ssize_t(len) != bytes_read) { 00184 Magic.clear(); 00185 return false; 00186 } 00187 Magic.assign(buf,len); 00188 return true; 00189 } 00190 00191 bool 00192 Path::isBytecodeFile() const { 00193 char buffer[ 4]; 00194 buffer[0] = 0; 00195 std::ifstream f(path.c_str()); 00196 f.read(buffer, 4); 00197 if (f.bad()) 00198 ThrowErrno("can't read file signature"); 00199 00200 return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' && 00201 (buffer[3] == 'c' || buffer[3] == 'm')); 00202 } 00203 00204 bool 00205 Path::isArchive() const { 00206 if (readable()) { 00207 return hasMagicNumber("!<arch>\012"); 00208 } 00209 return false; 00210 } 00211 00212 bool 00213 Path::exists() const { 00214 return 0 == access(path.c_str(), F_OK ); 00215 } 00216 00217 bool 00218 Path::readable() const { 00219 return 0 == access(path.c_str(), F_OK | R_OK ); 00220 } 00221 00222 bool 00223 Path::writable() const { 00224 return 0 == access(path.c_str(), F_OK | W_OK ); 00225 } 00226 00227 bool 00228 Path::executable() const { 00229 return 0 == access(path.c_str(), R_OK | X_OK ); 00230 } 00231 00232 std::string 00233 Path::getLast() const { 00234 // Find the last slash 00235 size_t pos = path.rfind('/'); 00236 00237 // Handle the corner cases 00238 if (pos == std::string::npos) 00239 return path; 00240 00241 // If the last character is a slash 00242 if (pos == path.length()-1) { 00243 // Find the second to last slash 00244 size_t pos2 = path.rfind('/', pos-1); 00245 if (pos2 == std::string::npos) 00246 return path.substr(0,pos); 00247 else 00248 return path.substr(pos2+1,pos-pos2-1); 00249 } 00250 // Return everything after the last slash 00251 return path.substr(pos+1); 00252 } 00253 00254 void 00255 Path::getStatusInfo(StatusInfo& info) const { 00256 struct stat buf; 00257 if (0 != stat(path.c_str(), &buf)) { 00258 ThrowErrno(std::string("Can't get status: ")+path); 00259 } 00260 info.fileSize = buf.st_size; 00261 info.modTime.fromEpochTime(buf.st_mtime); 00262 info.mode = buf.st_mode; 00263 info.user = buf.st_uid; 00264 info.group = buf.st_gid; 00265 info.isDir = S_ISDIR(buf.st_mode); 00266 if (info.isDir && path[path.length()-1] != '/') 00267 path += '/'; 00268 } 00269 00270 bool 00271 Path::getDirectoryContents(std::set<Path>& result) const { 00272 if (!isDirectory()) 00273 return false; 00274 DIR* direntries = ::opendir(path.c_str()); 00275 if (direntries == 0) 00276 ThrowErrno(path + ": can't open directory"); 00277 00278 result.clear(); 00279 struct dirent* de = ::readdir(direntries); 00280 while (de != 0) { 00281 if (de->d_name[0] != '.') { 00282 Path aPath(path + (const char*)de->d_name); 00283 struct stat buf; 00284 if (0 != stat(aPath.path.c_str(), &buf)) 00285 ThrowErrno(aPath.path + ": can't get status"); 00286 if (S_ISDIR(buf.st_mode)) 00287 aPath.path += "/"; 00288 result.insert(aPath); 00289 } 00290 de = ::readdir(direntries); 00291 } 00292 00293 closedir(direntries); 00294 return true; 00295 } 00296 00297 bool 00298 Path::setDirectory(const std::string& a_path) { 00299 if (a_path.size() == 0) 00300 return false; 00301 Path save(*this); 00302 path = a_path; 00303 size_t last = a_path.size() -1; 00304 if (last != 0 && a_path[last] != '/') 00305 path += '/'; 00306 if (!isValid()) { 00307 path = save.path; 00308 return false; 00309 } 00310 return true; 00311 } 00312 00313 bool 00314 Path::setFile(const std::string& a_path) { 00315 if (a_path.size() == 0) 00316 return false; 00317 Path save(*this); 00318 path = a_path; 00319 size_t last = a_path.size() - 1; 00320 while (last > 0 && a_path[last] == '/') 00321 last--; 00322 path.erase(last+1); 00323 if (!isValid()) { 00324 path = save.path; 00325 return false; 00326 } 00327 return true; 00328 } 00329 00330 bool 00331 Path::appendDirectory(const std::string& dir) { 00332 if (isFile()) 00333 return false; 00334 Path save(*this); 00335 path += dir; 00336 path += "/"; 00337 if (!isValid()) { 00338 path = save.path; 00339 return false; 00340 } 00341 return true; 00342 } 00343 00344 bool 00345 Path::elideDirectory() { 00346 if (isFile()) 00347 return false; 00348 size_t slashpos = path.rfind('/',path.size()); 00349 if (slashpos == 0 || slashpos == std::string::npos) 00350 return false; 00351 if (slashpos == path.size() - 1) 00352 slashpos = path.rfind('/',slashpos-1); 00353 if (slashpos == std::string::npos) 00354 return false; 00355 path.erase(slashpos); 00356 return true; 00357 } 00358 00359 bool 00360 Path::appendFile(const std::string& file) { 00361 if (!isDirectory()) 00362 return false; 00363 Path save(*this); 00364 path += file; 00365 if (!isValid()) { 00366 path = save.path; 00367 return false; 00368 } 00369 return true; 00370 } 00371 00372 bool 00373 Path::elideFile() { 00374 if (isDirectory()) 00375 return false; 00376 size_t slashpos = path.rfind('/',path.size()); 00377 if (slashpos == std::string::npos) 00378 return false; 00379 path.erase(slashpos+1); 00380 return true; 00381 } 00382 00383 bool 00384 Path::appendSuffix(const std::string& suffix) { 00385 if (isDirectory()) 00386 return false; 00387 Path save(*this); 00388 path.append("."); 00389 path.append(suffix); 00390 if (!isValid()) { 00391 path = save.path; 00392 return false; 00393 } 00394 return true; 00395 } 00396 00397 bool 00398 Path::elideSuffix() { 00399 if (isDirectory()) return false; 00400 size_t dotpos = path.rfind('.',path.size()); 00401 size_t slashpos = path.rfind('/',path.size()); 00402 if (slashpos != std::string::npos && dotpos != std::string::npos && 00403 dotpos > slashpos) { 00404 path.erase(dotpos, path.size()-dotpos); 00405 return true; 00406 } 00407 return false; 00408 } 00409 00410 00411 bool 00412 Path::createDirectory( bool create_parents) { 00413 // Make sure we're dealing with a directory 00414 if (!isDirectory()) return false; 00415 00416 // Get a writeable copy of the path name 00417 char pathname[MAXPATHLEN]; 00418 path.copy(pathname,MAXPATHLEN); 00419 00420 // Null-terminate the last component 00421 int lastchar = path.length() - 1 ; 00422 if (pathname[lastchar] == '/') 00423 pathname[lastchar] = 0; 00424 else 00425 pathname[lastchar+1] = 0; 00426 00427 // If we're supposed to create intermediate directories 00428 if ( create_parents ) { 00429 // Find the end of the initial name component 00430 char * next = strchr(pathname,'/'); 00431 if ( pathname[0] == '/') 00432 next = strchr(&pathname[1],'/'); 00433 00434 // Loop through the directory components until we're done 00435 while ( next != 0 ) { 00436 *next = 0; 00437 if (0 != access(pathname, F_OK | R_OK | W_OK)) 00438 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00439 ThrowErrno(std::string(pathname) + ": Can't create directory"); 00440 char* save = next; 00441 next = strchr(next+1,'/'); 00442 *save = '/'; 00443 } 00444 } 00445 00446 if (0 != access(pathname, F_OK | R_OK)) 00447 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) 00448 ThrowErrno(std::string(pathname) + ": Can't create directory"); 00449 return true; 00450 } 00451 00452 bool 00453 Path::createFile() { 00454 // Make sure we're dealing with a file 00455 if (!isFile()) return false; 00456 00457 // Create the file 00458 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); 00459 if (fd < 0) 00460 ThrowErrno(path + ": Can't create file"); 00461 ::close(fd); 00462 00463 return true; 00464 } 00465 00466 bool 00467 Path::createTemporaryFile() { 00468 // Make sure we're dealing with a file 00469 if (!isFile()) return false; 00470 00471 // Append the filename filler 00472 char pathname[MAXPATHLEN]; 00473 path.copy(pathname,MAXPATHLEN); 00474 pathname[path.length()] = 0; 00475 strcat(pathname,"XXXXXX"); 00476 int fd = ::mkstemp(pathname); 00477 if (fd < 0) { 00478 ThrowErrno(path + ": Can't create temporary file"); 00479 } 00480 path = pathname; 00481 ::close(fd); 00482 return true; 00483 } 00484 00485 bool 00486 Path::destroyDirectory(bool remove_contents) { 00487 // Make sure we're dealing with a directory 00488 if (!isDirectory()) return false; 00489 00490 // If it doesn't exist, we're done. 00491 if (!exists()) return true; 00492 00493 if (remove_contents) { 00494 // Recursively descend the directory to remove its content 00495 std::string cmd("/bin/rm -rf "); 00496 cmd += path; 00497 system(cmd.c_str()); 00498 } else { 00499 // Otherwise, try to just remove the one directory 00500 char pathname[MAXPATHLEN]; 00501 path.copy(pathname,MAXPATHLEN); 00502 int lastchar = path.length() - 1 ; 00503 if (pathname[lastchar] == '/') 00504 pathname[lastchar] = 0; 00505 else 00506 pathname[lastchar+1] = 0; 00507 if ( 0 != rmdir(pathname)) 00508 ThrowErrno(std::string(pathname) + ": Can't destroy directory"); 00509 } 00510 return true; 00511 } 00512 00513 bool 00514 Path::destroyFile() { 00515 if (!isFile()) return false; 00516 if (0 != unlink(path.c_str())) 00517 ThrowErrno(path + ": Can't destroy file"); 00518 return true; 00519 } 00520 00521 bool 00522 Path::renameFile(const Path& newName) { 00523 if (!isFile()) return false; 00524 if (0 != rename(path.c_str(), newName.c_str())) 00525 ThrowErrno(std::string("can't rename ") + path + " as " + newName.get()); 00526 return true; 00527 } 00528 00529 bool 00530 Path::setStatusInfo(const StatusInfo& si) const { 00531 if (!isFile()) return false; 00532 struct utimbuf utb; 00533 utb.actime = si.modTime.toPosixTime(); 00534 utb.modtime = utb.actime; 00535 if (0 != ::utime(path.c_str(),&utb)) 00536 ThrowErrno(path + ": can't set file modification time"); 00537 if (0 != ::chmod(path.c_str(),si.mode)) 00538 ThrowErrno(path + ": can't set mode"); 00539 return true; 00540 } 00541 00542 } 00543 00544 // vim: sw=2