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(const 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("/");
121 static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
122 const char* at = path;
123 const char* delim = strchr(at, ';');
125 while( delim != 0 ) {
126 std::string tmp(at, size_t(delim-at));
127 if (tmpPath.setDirectory(tmp))
128 if (tmpPath.readable())
129 Paths.push_back(tmpPath);
131 delim = strchr(at, ';');
134 if (tmpPath.setDirectory(std::string(at)))
135 if (tmpPath.readable())
136 Paths.push_back(tmpPath);
141 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
142 #ifdef LTDL_SHLIBPATH_VAR
143 char* env_var = getenv(LTDL_SHLIBPATH_VAR);
145 getPathList(env_var,Paths);
148 // FIXME: Should this look at LD_LIBRARY_PATH too?
149 Paths.push_back(sys::Path("C:\\WINDOWS\\SYSTEM32\\"));
150 Paths.push_back(sys::Path("C:\\WINDOWS\\"));
154 Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
155 char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
157 getPathList(env_var,Paths);
161 Path tmpPath(std::string(LLVMGCCDIR) + "bytecode-libs/");
162 if (tmpPath.readable())
163 Paths.push_back(tmpPath);
169 if (tmpPath.setDirectory(LLVM_LIBDIR))
170 if (tmpPath.readable())
171 Paths.push_back(tmpPath);
174 GetSystemLibraryPaths(Paths);
178 Path::GetLLVMDefaultConfigDir() {
179 return Path("/etc/llvm/");
183 Path::GetLLVMConfigDir() {
184 return GetLLVMDefaultConfigDir();
188 Path::GetUserHomeDirectory() {
189 const char* home = getenv("HOME");
192 if (result.setDirectory(home))
195 return GetRootDirectory();
197 // FIXME: the above set of functions don't map to Windows very well.
200 Path::isFile() const {
201 return (isValid() && path[path.length()-1] != '/');
205 Path::isDirectory() const {
206 return (isValid() && path[path.length()-1] == '/');
210 Path::getBasename() const {
211 // Find the last slash
212 size_t slash = path.rfind('/');
213 if (slash == std::string::npos)
218 return path.substr(slash, path.rfind('.'));
221 bool Path::hasMagicNumber(const std::string &Magic) const {
222 size_t len = Magic.size();
223 char *buf = reinterpret_cast<char *>(_alloca(len+1));
224 std::ifstream f(path.c_str());
231 Path::isBytecodeFile() const {
234 std::ifstream f(path.c_str());
237 ThrowErrno("can't read file signature");
238 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
242 Path::exists() const {
243 DWORD attr = GetFileAttributes(path.c_str());
244 return attr != INVALID_FILE_ATTRIBUTES;
248 Path::readable() const {
249 // FIXME: take security attributes into account.
250 DWORD attr = GetFileAttributes(path.c_str());
251 return attr != INVALID_FILE_ATTRIBUTES;
255 Path::writable() const {
256 // FIXME: take security attributes into account.
257 DWORD attr = GetFileAttributes(path.c_str());
258 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
262 Path::executable() const {
263 // FIXME: take security attributes into account.
264 DWORD attr = GetFileAttributes(path.c_str());
265 return attr != INVALID_FILE_ATTRIBUTES;
269 Path::getLast() const {
270 // Find the last slash
271 size_t pos = path.rfind('/');
273 // Handle the corner cases
274 if (pos == std::string::npos)
277 // If the last character is a slash
278 if (pos == path.length()-1) {
279 // Find the second to last slash
280 size_t pos2 = path.rfind('/', pos-1);
281 if (pos2 == std::string::npos)
282 return path.substr(0,pos);
284 return path.substr(pos2+1,pos-pos2-1);
286 // Return everything after the last slash
287 return path.substr(pos+1);
290 void Path::makeReadable() {
293 void Path::makeWriteable() {
296 void Path::makeExecutable() {
300 Path::setDirectory(const std::string& a_path) {
301 if (a_path.size() == 0)
305 FlipBackSlashes(path);
306 size_t last = a_path.size() -1;
307 if (a_path[last] != '/')
317 Path::setFile(const std::string& a_path) {
318 if (a_path.size() == 0)
322 FlipBackSlashes(path);
323 size_t last = a_path.size() - 1;
324 while (last > 0 && a_path[last] == '/')
335 Path::appendDirectory(const std::string& dir) {
349 Path::elideDirectory() {
352 size_t slashpos = path.rfind('/',path.size());
353 if (slashpos == 0 || slashpos == std::string::npos)
355 if (slashpos == path.size() - 1)
356 slashpos = path.rfind('/',slashpos-1);
357 if (slashpos == std::string::npos)
359 path.erase(slashpos);
364 Path::appendFile(const std::string& file) {
380 size_t slashpos = path.rfind('/',path.size());
381 if (slashpos == std::string::npos)
383 path.erase(slashpos+1);
388 Path::appendSuffix(const std::string& suffix) {
402 Path::elideSuffix() {
403 if (isDirectory()) return false;
404 size_t dotpos = path.rfind('.',path.size());
405 size_t slashpos = path.rfind('/',path.size());
406 if (slashpos != std::string::npos && dotpos != std::string::npos &&
408 path.erase(dotpos, path.size()-dotpos);
416 Path::createDirectory( bool create_parents) {
417 // Make sure we're dealing with a directory
418 if (!isDirectory()) return false;
420 // Get a writeable copy of the path name
421 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
422 path.copy(pathname,path.length());
423 pathname[path.length()] = 0;
425 // Determine starting point for initial / search.
426 char *next = pathname;
427 if (pathname[0] == '/' && pathname[1] == '/') {
429 next = strchr(pathname+2, '/');
431 throw std::string(pathname) + ": badly formed remote directory";
433 next = strchr(next+1, '/');
435 throw std::string(pathname) + ": badly formed remote directory";
438 throw std::string(pathname) + ": badly formed remote directory";
440 if (pathname[1] == ':')
441 next += 2; // skip drive letter
443 next++; // skip root directory
446 // If we're supposed to create intermediate directories
447 if (create_parents) {
448 // Loop through the directory components until we're done
450 next = strchr(next, '/');
452 if (!CreateDirectory(pathname, NULL))
453 ThrowError(std::string(pathname) + ": Can't create directory: ");
457 // Drop trailing slash.
458 pathname[path.size()-1] = 0;
459 if (!CreateDirectory(pathname, NULL)) {
460 ThrowError(std::string(pathname) + ": Can't create directory: ");
468 // Make sure we're dealing with a file
469 if (!isFile()) return false;
472 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
473 FILE_ATTRIBUTE_NORMAL, NULL);
474 if (h == INVALID_HANDLE_VALUE)
475 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
482 Path::destroyDirectory(bool remove_contents) {
483 // Make sure we're dealing with a directory
484 if (!isDirectory()) return false;
486 // If it doesn't exist, we're done.
487 if (!exists()) return true;
489 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
490 path.copy(pathname,path.length()+1);
491 int lastchar = path.length() - 1 ;
492 if (pathname[lastchar] == '/')
493 pathname[lastchar] = 0;
495 if (remove_contents) {
496 // Recursively descend the directory to remove its content
497 // FIXME: The correct way of doing this on Windows isn't pretty...
498 // but this may work if unix-like utils are present.
499 std::string cmd("rm -rf ");
503 // Otherwise, try to just remove the one directory
504 if (!RemoveDirectory(pathname))
505 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
511 Path::destroyFile() {
512 if (!isFile()) return false;
514 DWORD attr = GetFileAttributes(path.c_str());
516 // If it doesn't exist, we're done.
517 if (attr == INVALID_FILE_ATTRIBUTES)
520 // Read-only files cannot be deleted on Windows. Must remove the read-only
522 if (attr & FILE_ATTRIBUTE_READONLY) {
523 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
524 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
527 if (!DeleteFile(path.c_str()))
528 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
535 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab