LLVM API Documentation
00001 //===- llvm/System/Linux/Path.cpp - Linux 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 // Modified by Henrik Bach to comply with at least MinGW. 00009 // Ported to Win32 by Jeff Cohen. 00010 // 00011 //===----------------------------------------------------------------------===// 00012 // 00013 // This file provides the Win32 specific implementation of the Path class. 00014 // 00015 //===----------------------------------------------------------------------===// 00016 00017 //===----------------------------------------------------------------------===// 00018 //=== WARNING: Implementation here must contain only generic Win32 code that 00019 //=== is guaranteed to work on *all* Win32 variants. 00020 //===----------------------------------------------------------------------===// 00021 00022 #include "Win32.h" 00023 #include <fstream> 00024 #include <malloc.h> 00025 00026 static void FlipBackSlashes(std::string& s) { 00027 for (size_t i = 0; i < s.size(); i++) 00028 if (s[i] == '\\') 00029 s[i] = '/'; 00030 } 00031 00032 namespace llvm { 00033 namespace sys { 00034 00035 bool 00036 Path::isValid() const { 00037 if (path.empty()) 00038 return false; 00039 00040 // If there is a colon, it must be the second character, preceded by a letter 00041 // and followed by something. 00042 size_t len = path.size(); 00043 size_t pos = path.rfind(':',len); 00044 if (pos != std::string::npos) { 00045 if (pos != 1 || !isalpha(path[0]) || len < 3) 00046 return false; 00047 } 00048 00049 // Check for illegal characters. 00050 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" 00051 "\013\014\015\016\017\020\021\022\023\024\025\026" 00052 "\027\030\031\032\033\034\035\036\037") 00053 != std::string::npos) 00054 return false; 00055 00056 // A file or directory name may not end in a period. 00057 if (path[len-1] == '.') 00058 return false; 00059 if (len >= 2 && path[len-2] == '.' && path[len-1] == '/') 00060 return false; 00061 00062 // A file or directory name may not end in a space. 00063 if (path[len-1] == ' ') 00064 return false; 00065 if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/') 00066 return false; 00067 00068 return true; 00069 } 00070 00071 static Path *TempDirectory = NULL; 00072 00073 Path 00074 Path::GetTemporaryDirectory() { 00075 if (TempDirectory) 00076 return *TempDirectory; 00077 00078 char pathname[MAX_PATH]; 00079 if (!GetTempPath(MAX_PATH, pathname)) 00080 throw std::string("Can't determine temporary directory"); 00081 00082 Path result; 00083 result.setDirectory(pathname); 00084 00085 // Append a subdirectory passed on our process id so multiple LLVMs don't 00086 // step on each other's toes. 00087 sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); 00088 result.appendDirectory(pathname); 00089 00090 // If there's a directory left over from a previous LLVM execution that 00091 // happened to have the same process id, get rid of it. 00092 result.destroyDirectory(true); 00093 00094 // And finally (re-)create the empty directory. 00095 result.createDirectory(false); 00096 TempDirectory = new Path(result); 00097 return *TempDirectory; 00098 } 00099 00100 Path::Path(std::string unverified_path) 00101 : path(unverified_path) 00102 { 00103 FlipBackSlashes(path); 00104 if (unverified_path.empty()) 00105 return; 00106 if (this->isValid()) 00107 return; 00108 // oops, not valid. 00109 path.clear(); 00110 throw std::string(unverified_path + ": path is not valid"); 00111 } 00112 00113 // FIXME: the following set of functions don't map to Windows very well. 00114 Path 00115 Path::GetRootDirectory() { 00116 Path result; 00117 result.setDirectory("/"); 00118 return result; 00119 } 00120 00121 std::string 00122 Path::GetDLLSuffix() { 00123 return "dll"; 00124 } 00125 00126 static inline bool IsLibrary(Path& path, const std::string& basename) { 00127 if (path.appendFile(std::string("lib") + basename)) { 00128 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable()) 00129 return true; 00130 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable()) 00131 return true; 00132 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable()) 00133 return true; 00134 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable()) 00135 return true; 00136 } else if (path.elideFile() && path.appendFile(basename)) { 00137 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable()) 00138 return true; 00139 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable()) 00140 return true; 00141 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable()) 00142 return true; 00143 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable()) 00144 return true; 00145 } 00146 path.clear(); 00147 return false; 00148 } 00149 00150 Path 00151 Path::GetLibraryPath(const std::string& basename, 00152 const std::vector<std::string>& LibPaths) { 00153 Path result; 00154 00155 // Try the paths provided 00156 for (std::vector<std::string>::const_iterator I = LibPaths.begin(), 00157 E = LibPaths.end(); I != E; ++I ) { 00158 if (result.setDirectory(*I) && IsLibrary(result,basename)) 00159 return result; 00160 } 00161 00162 // Try the LLVM lib directory in the LLVM install area 00163 //if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename)) 00164 // return result; 00165 00166 // Try /usr/lib 00167 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename)) 00168 return result; 00169 00170 // Try /lib 00171 if (result.setDirectory("/lib/") && IsLibrary(result,basename)) 00172 return result; 00173 00174 // Can't find it, give up and return invalid path. 00175 result.clear(); 00176 return result; 00177 } 00178 00179 Path 00180 Path::GetSystemLibraryPath1() { 00181 return Path("/lib/"); 00182 } 00183 00184 Path 00185 Path::GetSystemLibraryPath2() { 00186 return Path("/usr/lib/"); 00187 } 00188 00189 Path 00190 Path::GetLLVMDefaultConfigDir() { 00191 return Path("/etc/llvm/"); 00192 } 00193 00194 Path 00195 Path::GetLLVMConfigDir() { 00196 return GetLLVMDefaultConfigDir(); 00197 } 00198 00199 Path 00200 Path::GetUserHomeDirectory() { 00201 const char* home = getenv("HOME"); 00202 if (home) { 00203 Path result; 00204 if (result.setDirectory(home)) 00205 return result; 00206 } 00207 return GetRootDirectory(); 00208 } 00209 // FIXME: the above set of functions don't map to Windows very well. 00210 00211 bool 00212 Path::isFile() const { 00213 return (isValid() && path[path.length()-1] != '/'); 00214 } 00215 00216 bool 00217 Path::isDirectory() const { 00218 return (isValid() && path[path.length()-1] == '/'); 00219 } 00220 00221 std::string 00222 Path::getBasename() const { 00223 // Find the last slash 00224 size_t slash = path.rfind('/'); 00225 if (slash == std::string::npos) 00226 slash = 0; 00227 else 00228 slash++; 00229 00230 return path.substr(slash, path.rfind('.')); 00231 } 00232 00233 bool Path::hasMagicNumber(const std::string &Magic) const { 00234 size_t len = Magic.size(); 00235 char *buf = reinterpret_cast<char *>(_alloca(len+1)); 00236 std::ifstream f(path.c_str()); 00237 f.read(buf, len); 00238 buf[len] = '\0'; 00239 return Magic == buf; 00240 } 00241 00242 bool 00243 Path::isBytecodeFile() const { 00244 char buffer[ 4]; 00245 buffer[0] = 0; 00246 std::ifstream f(path.c_str()); 00247 f.read(buffer, 4); 00248 if (f.bad()) 00249 ThrowErrno("can't read file signature"); 00250 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4); 00251 } 00252 00253 bool 00254 Path::isArchive() const { 00255 if (readable()) { 00256 return hasMagicNumber("!<arch>\012"); 00257 } 00258 return false; 00259 } 00260 00261 bool 00262 Path::exists() const { 00263 DWORD attr = GetFileAttributes(path.c_str()); 00264 return attr != INVALID_FILE_ATTRIBUTES; 00265 } 00266 00267 bool 00268 Path::readable() const { 00269 // FIXME: take security attributes into account. 00270 DWORD attr = GetFileAttributes(path.c_str()); 00271 return attr != INVALID_FILE_ATTRIBUTES; 00272 } 00273 00274 bool 00275 Path::writable() const { 00276 // FIXME: take security attributes into account. 00277 DWORD attr = GetFileAttributes(path.c_str()); 00278 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); 00279 } 00280 00281 bool 00282 Path::executable() const { 00283 // FIXME: take security attributes into account. 00284 DWORD attr = GetFileAttributes(path.c_str()); 00285 return attr != INVALID_FILE_ATTRIBUTES; 00286 } 00287 00288 std::string 00289 Path::getLast() const { 00290 // Find the last slash 00291 size_t pos = path.rfind('/'); 00292 00293 // Handle the corner cases 00294 if (pos == std::string::npos) 00295 return path; 00296 00297 // If the last character is a slash 00298 if (pos == path.length()-1) { 00299 // Find the second to last slash 00300 size_t pos2 = path.rfind('/', pos-1); 00301 if (pos2 == std::string::npos) 00302 return path.substr(0,pos); 00303 else 00304 return path.substr(pos2+1,pos-pos2-1); 00305 } 00306 // Return everything after the last slash 00307 return path.substr(pos+1); 00308 } 00309 00310 bool 00311 Path::setDirectory(const std::string& a_path) { 00312 if (a_path.size() == 0) 00313 return false; 00314 Path save(*this); 00315 path = a_path; 00316 FlipBackSlashes(path); 00317 size_t last = a_path.size() -1; 00318 if (last != 0 && a_path[last] != '/') 00319 path += '/'; 00320 if (!isValid()) { 00321 path = save.path; 00322 return false; 00323 } 00324 return true; 00325 } 00326 00327 bool 00328 Path::setFile(const std::string& a_path) { 00329 if (a_path.size() == 0) 00330 return false; 00331 Path save(*this); 00332 path = a_path; 00333 FlipBackSlashes(path); 00334 size_t last = a_path.size() - 1; 00335 while (last > 0 && a_path[last] == '/') 00336 last--; 00337 path.erase(last+1); 00338 if (!isValid()) { 00339 path = save.path; 00340 return false; 00341 } 00342 return true; 00343 } 00344 00345 bool 00346 Path::appendDirectory(const std::string& dir) { 00347 if (isFile()) 00348 return false; 00349 Path save(*this); 00350 path += dir; 00351 path += "/"; 00352 if (!isValid()) { 00353 path = save.path; 00354 return false; 00355 } 00356 return true; 00357 } 00358 00359 bool 00360 Path::elideDirectory() { 00361 if (isFile()) 00362 return false; 00363 size_t slashpos = path.rfind('/',path.size()); 00364 if (slashpos == 0 || slashpos == std::string::npos) 00365 return false; 00366 if (slashpos == path.size() - 1) 00367 slashpos = path.rfind('/',slashpos-1); 00368 if (slashpos == std::string::npos) 00369 return false; 00370 path.erase(slashpos); 00371 return true; 00372 } 00373 00374 bool 00375 Path::appendFile(const std::string& file) { 00376 if (!isDirectory()) 00377 return false; 00378 Path save(*this); 00379 path += file; 00380 if (!isValid()) { 00381 path = save.path; 00382 return false; 00383 } 00384 return true; 00385 } 00386 00387 bool 00388 Path::elideFile() { 00389 if (isDirectory()) 00390 return false; 00391 size_t slashpos = path.rfind('/',path.size()); 00392 if (slashpos == std::string::npos) 00393 return false; 00394 path.erase(slashpos+1); 00395 return true; 00396 } 00397 00398 bool 00399 Path::appendSuffix(const std::string& suffix) { 00400 if (isDirectory()) 00401 return false; 00402 Path save(*this); 00403 path.append("."); 00404 path.append(suffix); 00405 if (!isValid()) { 00406 path = save.path; 00407 return false; 00408 } 00409 return true; 00410 } 00411 00412 bool 00413 Path::elideSuffix() { 00414 if (isDirectory()) return false; 00415 size_t dotpos = path.rfind('.',path.size()); 00416 size_t slashpos = path.rfind('/',path.size()); 00417 if (slashpos != std::string::npos && dotpos != std::string::npos && 00418 dotpos > slashpos) { 00419 path.erase(dotpos, path.size()-dotpos); 00420 return true; 00421 } 00422 return false; 00423 } 00424 00425 00426 bool 00427 Path::createDirectory( bool create_parents) { 00428 // Make sure we're dealing with a directory 00429 if (!isDirectory()) return false; 00430 00431 // Get a writeable copy of the path name 00432 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1)); 00433 path.copy(pathname,path.length()); 00434 pathname[path.length()] = 0; 00435 00436 // Determine starting point for initial / search. 00437 char *next = pathname; 00438 if (pathname[0] == '/' && pathname[1] == '/') { 00439 // Skip host name. 00440 next = strchr(pathname+2, '/'); 00441 if (next == NULL) 00442 throw std::string(pathname) + ": badly formed remote directory"; 00443 // Skip share name. 00444 next = strchr(next+1, '/'); 00445 if (next == NULL) 00446 throw std::string(pathname) + ": badly formed remote directory"; 00447 next++; 00448 if (*next == 0) 00449 throw std::string(pathname) + ": badly formed remote directory"; 00450 } else { 00451 if (pathname[1] == ':') 00452 next += 2; // skip drive letter 00453 if (*next == '/') 00454 next++; // skip root directory 00455 } 00456 00457 // If we're supposed to create intermediate directories 00458 if (create_parents) { 00459 // Loop through the directory components until we're done 00460 while (*next) { 00461 next = strchr(next, '/'); 00462 *next = 0; 00463 if (!CreateDirectory(pathname, NULL)) 00464 ThrowError(std::string(pathname) + ": Can't create directory: "); 00465 *next++ = '/'; 00466 } 00467 } else { 00468 // Drop trailing slash. 00469 pathname[path.size()-1] = 0; 00470 if (!CreateDirectory(pathname, NULL)) { 00471 ThrowError(std::string(pathname) + ": Can't create directory: "); 00472 } 00473 } 00474 return true; 00475 } 00476 00477 bool 00478 Path::createFile() { 00479 // Make sure we're dealing with a file 00480 if (!isFile()) return false; 00481 00482 // Create the file 00483 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, 00484 FILE_ATTRIBUTE_NORMAL, NULL); 00485 if (h == INVALID_HANDLE_VALUE) 00486 ThrowError(std::string(path.c_str()) + ": Can't create file: "); 00487 00488 CloseHandle(h); 00489 return true; 00490 } 00491 00492 bool 00493 Path::destroyDirectory(bool remove_contents) { 00494 // Make sure we're dealing with a directory 00495 if (!isDirectory()) return false; 00496 00497 // If it doesn't exist, we're done. 00498 if (!exists()) return true; 00499 00500 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1)); 00501 path.copy(pathname,path.length()+1); 00502 int lastchar = path.length() - 1 ; 00503 if (pathname[lastchar] == '/') 00504 pathname[lastchar] = 0; 00505 00506 if (remove_contents) { 00507 // Recursively descend the directory to remove its content 00508 // FIXME: The correct way of doing this on Windows isn't pretty... 00509 // but this may work if unix-like utils are present. 00510 std::string cmd("rm -rf "); 00511 cmd += path; 00512 system(cmd.c_str()); 00513 } else { 00514 // Otherwise, try to just remove the one directory 00515 if (!RemoveDirectory(pathname)) 00516 ThrowError(std::string(pathname) + ": Can't destroy directory: "); 00517 } 00518 return true; 00519 } 00520 00521 bool 00522 Path::destroyFile() { 00523 if (!isFile()) return false; 00524 00525 DWORD attr = GetFileAttributes(path.c_str()); 00526 00527 // If it doesn't exist, we're done. 00528 if (attr == INVALID_FILE_ATTRIBUTES) 00529 return true; 00530 00531 // Read-only files cannot be deleted on Windows. Must remove the read-only 00532 // attribute first. 00533 if (attr & FILE_ATTRIBUTE_READONLY) { 00534 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) 00535 ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); 00536 } 00537 00538 if (!DeleteFile(path.c_str())) 00539 ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); 00540 return true; 00541 } 00542 00543 } 00544 } 00545 00546 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab 00547