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 ssize_t bytes_read = ::read(fd, buf, len);
183 if (ssize_t(len) != bytes_read) {
187 Magic.assign(buf,len);
192 Path::isBytecodeFile() const {
195 std::ifstream f(path.c_str());
198 ThrowErrno("can't read file signature");
200 return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' &&
201 (buffer[3] == 'c' || buffer[3] == 'm'));
205 Path::isArchive() const {
207 return hasMagicNumber("!<arch>\012");
213 Path::exists() const {
214 return 0 == access(path.c_str(), F_OK );
218 Path::readable() const {
219 return 0 == access(path.c_str(), F_OK | R_OK );
223 Path::writable() const {
224 return 0 == access(path.c_str(), F_OK | W_OK );
228 Path::executable() const {
229 return 0 == access(path.c_str(), R_OK | X_OK );
233 Path::getLast() const {
234 // Find the last slash
235 size_t pos = path.rfind('/');
237 // Handle the corner cases
238 if (pos == std::string::npos)
241 // If the last character is a slash
242 if (pos == path.length()-1) {
243 // Find the second to last slash
244 size_t pos2 = path.rfind('/', pos-1);
245 if (pos2 == std::string::npos)
246 return path.substr(0,pos);
248 return path.substr(pos2+1,pos-pos2-1);
250 // Return everything after the last slash
251 return path.substr(pos+1);
255 Path::getStatusInfo(StatusInfo& info) const {
257 if (0 != stat(path.c_str(), &buf)) {
258 ThrowErrno(std::string("Can't get status: ")+path);
260 info.fileSize = buf.st_size;
261 info.modTime.fromEpochTime(buf.st_mtime);
262 info.mode = buf.st_mode;
263 info.user = buf.st_uid;
264 info.group = buf.st_gid;
265 info.isDir = S_ISDIR(buf.st_mode);
266 if (info.isDir && path[path.length()-1] != '/')
271 Path::getDirectoryContents(std::set<Path>& result) const {
274 DIR* direntries = ::opendir(path.c_str());
276 ThrowErrno(path + ": can't open directory");
279 struct dirent* de = ::readdir(direntries);
281 if (de->d_name[0] != '.') {
282 Path aPath(path + (const char*)de->d_name);
284 if (0 != stat(aPath.path.c_str(), &buf))
285 ThrowErrno(aPath.path + ": can't get status");
286 if (S_ISDIR(buf.st_mode))
288 result.insert(aPath);
290 de = ::readdir(direntries);
293 closedir(direntries);
298 Path::setDirectory(const std::string& a_path) {
299 if (a_path.size() == 0)
303 size_t last = a_path.size() -1;
304 if (last != 0 && a_path[last] != '/')
314 Path::setFile(const std::string& a_path) {
315 if (a_path.size() == 0)
319 size_t last = a_path.size() - 1;
320 while (last > 0 && a_path[last] == '/')
331 Path::appendDirectory(const std::string& dir) {
345 Path::elideDirectory() {
348 size_t slashpos = path.rfind('/',path.size());
349 if (slashpos == 0 || slashpos == std::string::npos)
351 if (slashpos == path.size() - 1)
352 slashpos = path.rfind('/',slashpos-1);
353 if (slashpos == std::string::npos)
355 path.erase(slashpos);
360 Path::appendFile(const std::string& file) {
376 size_t slashpos = path.rfind('/',path.size());
377 if (slashpos == std::string::npos)
379 path.erase(slashpos+1);
384 Path::appendSuffix(const std::string& suffix) {
398 Path::elideSuffix() {
399 if (isDirectory()) return false;
400 size_t dotpos = path.rfind('.',path.size());
401 size_t slashpos = path.rfind('/',path.size());
402 if (slashpos != std::string::npos && dotpos != std::string::npos &&
404 path.erase(dotpos, path.size()-dotpos);
412 Path::createDirectory( bool create_parents) {
413 // Make sure we're dealing with a directory
414 if (!isDirectory()) return false;
416 // Get a writeable copy of the path name
417 char pathname[MAXPATHLEN];
418 path.copy(pathname,MAXPATHLEN);
420 // Null-terminate the last component
421 int lastchar = path.length() - 1 ;
422 if (pathname[lastchar] == '/')
423 pathname[lastchar] = 0;
425 pathname[lastchar+1] = 0;
427 // If we're supposed to create intermediate directories
428 if ( create_parents ) {
429 // Find the end of the initial name component
430 char * next = strchr(pathname,'/');
431 if ( pathname[0] == '/')
432 next = strchr(&pathname[1],'/');
434 // Loop through the directory components until we're done
435 while ( next != 0 ) {
437 if (0 != access(pathname, F_OK | R_OK | W_OK))
438 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
439 ThrowErrno(std::string(pathname) + ": Can't create directory");
441 next = strchr(next+1,'/');
446 if (0 != access(pathname, F_OK | R_OK))
447 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
448 ThrowErrno(std::string(pathname) + ": Can't create directory");
454 // Make sure we're dealing with a file
455 if (!isFile()) return false;
458 int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
460 ThrowErrno(path + ": Can't create file");
467 Path::createTemporaryFile() {
468 // Make sure we're dealing with a file
469 if (!isFile()) return false;
471 // Append the filename filler
472 char pathname[MAXPATHLEN];
473 path.copy(pathname,MAXPATHLEN);
474 pathname[path.length()] = 0;
475 strcat(pathname,"XXXXXX");
476 int fd = ::mkstemp(pathname);
478 ThrowErrno(path + ": Can't create temporary file");
486 Path::destroyDirectory(bool remove_contents) {
487 // Make sure we're dealing with a directory
488 if (!isDirectory()) return false;
490 // If it doesn't exist, we're done.
491 if (!exists()) return true;
493 if (remove_contents) {
494 // Recursively descend the directory to remove its content
495 std::string cmd("/bin/rm -rf ");
499 // Otherwise, try to just remove the one directory
500 char pathname[MAXPATHLEN];
501 path.copy(pathname,MAXPATHLEN);
502 int lastchar = path.length() - 1 ;
503 if (pathname[lastchar] == '/')
504 pathname[lastchar] = 0;
506 pathname[lastchar+1] = 0;
507 if ( 0 != rmdir(pathname))
508 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
514 Path::destroyFile() {
515 if (!isFile()) return false;
516 if (0 != unlink(path.c_str()))
517 ThrowErrno(path + ": Can't destroy file");
522 Path::renameFile(const Path& newName) {
523 if (!isFile()) return false;
524 if (0 != rename(path.c_str(), newName.c_str()))
525 ThrowErrno(std::string("can't rename ") + path + " as " + newName.get());
530 Path::setStatusInfo(const StatusInfo& si) const {
531 if (!isFile()) return false;
533 utb.actime = si.modTime.toPosixTime();
534 utb.modtime = utb.actime;
535 if (0 != ::utime(path.c_str(),&utb))
536 ThrowErrno(path + ": can't set file modification time");
537 if (0 != ::chmod(path.c_str(),si.mode))
538 ThrowErrno(path + ": can't set mode");