1 //===- llvm/System/Linux/Path.cpp - Linux 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 // Modified by Henrik Bach to comply with at least MinGW.
9 // Ported to Win32 by Jeff Cohen.
11 //===----------------------------------------------------------------------===//
13 // This file provides the Win32 specific implementation of the Path class.
15 //===----------------------------------------------------------------------===//
17 //===----------------------------------------------------------------------===//
18 //=== WARNING: Implementation here must contain only generic Win32 code that
19 //=== is guaranteed to work on *all* Win32 variants.
20 //===----------------------------------------------------------------------===//
26 static void FlipBackSlashes(std::string& s) {
27 for (size_t i = 0; i < s.size(); i++)
36 Path::isValid() const {
40 // If there is a colon, it must be the second character, preceded by a letter
41 // and followed by something.
42 size_t len = path.size();
43 size_t pos = path.rfind(':',len);
44 if (pos != std::string::npos) {
45 if (pos != 1 || !isalpha(path[0]) || len < 3)
49 // Check for illegal characters.
50 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
51 "\013\014\015\016\017\020\021\022\023\024\025\026"
52 "\027\030\031\032\033\034\035\036\037")
56 // A file or directory name may not end in a period.
57 if (path[len-1] == '.')
59 if (len >= 2 && path[len-2] == '.' && path[len-1] == '/')
62 // A file or directory name may not end in a space.
63 if (path[len-1] == ' ')
65 if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/')
71 static Path *TempDirectory = NULL;
74 Path::GetTemporaryDirectory() {
76 return *TempDirectory;
78 char pathname[MAX_PATH];
79 if (!GetTempPath(MAX_PATH, pathname))
80 throw std::string("Can't determine temporary directory");
83 result.setDirectory(pathname);
85 // Append a subdirectory passed on our process id so multiple LLVMs don't
86 // step on each other's toes.
87 sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
88 result.appendDirectory(pathname);
90 // If there's a directory left over from a previous LLVM execution that
91 // happened to have the same process id, get rid of it.
92 result.destroyDirectory(true);
94 // And finally (re-)create the empty directory.
95 result.createDirectory(false);
96 TempDirectory = new Path(result);
97 return *TempDirectory;
100 Path::Path(std::string unverified_path)
101 : path(unverified_path)
103 FlipBackSlashes(path);
104 if (unverified_path.empty())
110 throw std::string(unverified_path + ": path is not valid");
113 // FIXME: the following set of functions don't map to Windows very well.
115 Path::GetRootDirectory() {
117 result.setDirectory("/");
122 Path::GetDLLSuffix() {
126 static inline bool IsLibrary(Path& path, const std::string& basename) {
127 if (path.appendFile(std::string("lib") + basename)) {
128 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
130 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
132 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
134 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
136 } else if (path.elideFile() && path.appendFile(basename)) {
137 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
139 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
141 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
143 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
151 Path::GetLibraryPath(const std::string& basename,
152 const std::vector<std::string>& LibPaths) {
155 // Try the paths provided
156 for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
157 E = LibPaths.end(); I != E; ++I ) {
158 if (result.setDirectory(*I) && IsLibrary(result,basename))
162 // Try the LLVM lib directory in the LLVM install area
163 //if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename))
167 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename))
171 if (result.setDirectory("/lib/") && IsLibrary(result,basename))
174 // Can't find it, give up and return invalid path.
180 Path::GetSystemLibraryPath1() {
181 return Path("/lib/");
185 Path::GetSystemLibraryPath2() {
186 return Path("/usr/lib/");
190 Path::GetLLVMDefaultConfigDir() {
191 return Path("/etc/llvm/");
195 Path::GetLLVMConfigDir() {
196 return GetLLVMDefaultConfigDir();
200 Path::GetUserHomeDirectory() {
201 const char* home = getenv("HOME");
204 if (result.setDirectory(home))
207 return GetRootDirectory();
209 // FIXME: the above set of functions don't map to Windows very well.
212 Path::isFile() const {
213 return (isValid() && path[path.length()-1] != '/');
217 Path::isDirectory() const {
218 return (isValid() && path[path.length()-1] == '/');
222 Path::getBasename() const {
223 // Find the last slash
224 size_t slash = path.rfind('/');
225 if (slash == std::string::npos)
230 return path.substr(slash, path.rfind('.'));
233 bool Path::hasMagicNumber(const std::string &Magic) const {
234 size_t len = Magic.size();
235 char *buf = reinterpret_cast<char *>(_alloca(len+1));
236 std::ifstream f(path.c_str());
243 Path::isBytecodeFile() const {
246 std::ifstream f(path.c_str());
249 ThrowErrno("can't read file signature");
250 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
254 Path::isArchive() const {
256 return hasMagicNumber("!<arch>\012");
262 Path::exists() const {
263 DWORD attr = GetFileAttributes(path.c_str());
264 return attr != INVALID_FILE_ATTRIBUTES;
268 Path::readable() const {
269 // FIXME: take security attributes into account.
270 DWORD attr = GetFileAttributes(path.c_str());
271 return attr != INVALID_FILE_ATTRIBUTES;
275 Path::writable() const {
276 // FIXME: take security attributes into account.
277 DWORD attr = GetFileAttributes(path.c_str());
278 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
282 Path::executable() const {
283 // FIXME: take security attributes into account.
284 DWORD attr = GetFileAttributes(path.c_str());
285 return attr != INVALID_FILE_ATTRIBUTES;
289 Path::getLast() const {
290 // Find the last slash
291 size_t pos = path.rfind('/');
293 // Handle the corner cases
294 if (pos == std::string::npos)
297 // If the last character is a slash
298 if (pos == path.length()-1) {
299 // Find the second to last slash
300 size_t pos2 = path.rfind('/', pos-1);
301 if (pos2 == std::string::npos)
302 return path.substr(0,pos);
304 return path.substr(pos2+1,pos-pos2-1);
306 // Return everything after the last slash
307 return path.substr(pos+1);
311 Path::setDirectory(const std::string& a_path) {
312 if (a_path.size() == 0)
316 FlipBackSlashes(path);
317 size_t last = a_path.size() -1;
318 if (last != 0 && a_path[last] != '/')
328 Path::setFile(const std::string& a_path) {
329 if (a_path.size() == 0)
333 FlipBackSlashes(path);
334 size_t last = a_path.size() - 1;
335 while (last > 0 && a_path[last] == '/')
346 Path::appendDirectory(const std::string& dir) {
360 Path::elideDirectory() {
363 size_t slashpos = path.rfind('/',path.size());
364 if (slashpos == 0 || slashpos == std::string::npos)
366 if (slashpos == path.size() - 1)
367 slashpos = path.rfind('/',slashpos-1);
368 if (slashpos == std::string::npos)
370 path.erase(slashpos);
375 Path::appendFile(const std::string& file) {
391 size_t slashpos = path.rfind('/',path.size());
392 if (slashpos == std::string::npos)
394 path.erase(slashpos+1);
399 Path::appendSuffix(const std::string& suffix) {
413 Path::elideSuffix() {
414 if (isDirectory()) return false;
415 size_t dotpos = path.rfind('.',path.size());
416 size_t slashpos = path.rfind('/',path.size());
417 if (slashpos != std::string::npos && dotpos != std::string::npos &&
419 path.erase(dotpos, path.size()-dotpos);
427 Path::createDirectory( bool create_parents) {
428 // Make sure we're dealing with a directory
429 if (!isDirectory()) return false;
431 // Get a writeable copy of the path name
432 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
433 path.copy(pathname,path.length());
434 pathname[path.length()] = 0;
436 // Determine starting point for initial / search.
437 char *next = pathname;
438 if (pathname[0] == '/' && pathname[1] == '/') {
440 next = strchr(pathname+2, '/');
442 throw std::string(pathname) + ": badly formed remote directory";
444 next = strchr(next+1, '/');
446 throw std::string(pathname) + ": badly formed remote directory";
449 throw std::string(pathname) + ": badly formed remote directory";
451 if (pathname[1] == ':')
452 next += 2; // skip drive letter
454 next++; // skip root directory
457 // If we're supposed to create intermediate directories
458 if (create_parents) {
459 // Loop through the directory components until we're done
461 next = strchr(next, '/');
463 if (!CreateDirectory(pathname, NULL))
464 ThrowError(std::string(pathname) + ": Can't create directory: ");
468 // Drop trailing slash.
469 pathname[path.size()-1] = 0;
470 if (!CreateDirectory(pathname, NULL)) {
471 ThrowError(std::string(pathname) + ": Can't create directory: ");
479 // Make sure we're dealing with a file
480 if (!isFile()) return false;
483 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
484 FILE_ATTRIBUTE_NORMAL, NULL);
485 if (h == INVALID_HANDLE_VALUE)
486 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
493 Path::destroyDirectory(bool remove_contents) {
494 // Make sure we're dealing with a directory
495 if (!isDirectory()) return false;
497 // If it doesn't exist, we're done.
498 if (!exists()) return true;
500 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
501 path.copy(pathname,path.length()+1);
502 int lastchar = path.length() - 1 ;
503 if (pathname[lastchar] == '/')
504 pathname[lastchar] = 0;
506 if (remove_contents) {
507 // Recursively descend the directory to remove its content
508 // FIXME: The correct way of doing this on Windows isn't pretty...
509 // but this may work if unix-like utils are present.
510 std::string cmd("rm -rf ");
514 // Otherwise, try to just remove the one directory
515 if (!RemoveDirectory(pathname))
516 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
522 Path::destroyFile() {
523 if (!isFile()) return false;
525 DWORD attr = GetFileAttributes(path.c_str());
527 // If it doesn't exist, we're done.
528 if (attr == INVALID_FILE_ATTRIBUTES)
531 // Read-only files cannot be deleted on Windows. Must remove the read-only
533 if (attr & FILE_ATTRIBUTE_READONLY) {
534 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
535 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
538 if (!DeleteFile(path.c_str()))
539 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
546 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab