//
// The LLVM Compiler Infrastructure
//
-// This file was developed by Reid Spencer and is distributed under the
-// University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
#if HAVE_UTIME_H
#include <utime.h>
#endif
# endif
#endif
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
// Put in a hack for Cygwin which falsely reports that the mkdtemp function
// is available when it is not.
#ifdef __CYGWIN__
namespace llvm {
using namespace sys;
+extern const char sys::PathSeparator = ':';
+
+Path::Path(const std::string& p)
+ : path(p) {}
+
+Path::Path(const char *StrStart, unsigned StrLen)
+ : path(StrStart, StrLen) {}
+
bool
Path::isValid() const {
// Check some obvious things
#endif
}
-static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
- const char* at = path;
- const char* delim = strchr(at, ':');
- Path tmpPath;
- while( delim != 0 ) {
- std::string tmp(at, size_t(delim-at));
- if (tmpPath.set(tmp))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
- at = delim + 1;
- delim = strchr(at, ':');
- }
- if (*at != 0)
- if (tmpPath.set(std::string(at)))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
-
-}
-
void
Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
#ifdef LTDL_SHLIBPATH_VAR
}
void
-Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
+Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
if (env_var != 0) {
getPathList(env_var,Paths);
return GetRootDirectory();
}
+Path
+Path::GetCurrentDirectory() {
+ char pathname[MAXPATHLEN];
+ if (!getcwd(pathname,MAXPATHLEN)) {
+ assert (false && "Could not query current working directory.");
+ return Path("");
+ }
+
+ return Path(pathname);
+}
+
+/// GetMainExecutable - Return the path to the main executable, given the
+/// value of argv[0] from program startup.
+Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
+#if defined(__CYGWIN__)
+ char exe_link[64];
+ snprintf(exe_link, sizeof(exe_link), "/proc/%d/exe", getpid());
+ char exe_path[MAXPATHLEN];
+ ssize_t len = readlink(exe_link, exe_path, sizeof(exe_path));
+ if (len > 0 && len < MAXPATHLEN - 1) {
+ exe_path[len] = '\0';
+ return Path(std::string(exe_path));
+ }
+#elif defined(HAVE_DLFCN_H)
+ // Use dladdr to get executable path if available.
+ Dl_info DLInfo;
+ int err = dladdr(MainAddr, &DLInfo);
+ if (err != 0)
+ return Path(std::string(DLInfo.dli_fname));
+#endif
+ return Path();
+}
+
+
+std::string Path::getDirname() const {
+ return getDirnameCharSep(path, '/');
+}
std::string
Path::getBasename() const {
// Find the last slash
- size_t slash = path.rfind('/');
+ std::string::size_type slash = path.rfind('/');
if (slash == std::string::npos)
slash = 0;
else
slash++;
- size_t dot = path.rfind('.');
+ std::string::size_type dot = path.rfind('.');
if (dot == std::string::npos || dot < slash)
return path.substr(slash);
else
return path.substr(slash, dot - slash);
}
-bool Path::hasMagicNumber(const std::string &Magic) const {
- size_t len = Magic.size();
- assert(len < 1024 && "Request for magic string too long");
- char* buf = (char*) alloca(1 + len);
- int fd = ::open(path.c_str(), O_RDONLY);
- if (fd < 0)
- return false;
- size_t read_len = ::read(fd, buf, len);
- close(fd);
- if (len != read_len)
- return false;
- buf[len] = '\0';
- return Magic == buf;
+std::string
+Path::getSuffix() const {
+ // Find the last slash
+ std::string::size_type slash = path.rfind('/');
+ if (slash == std::string::npos)
+ slash = 0;
+ else
+ slash++;
+
+ std::string::size_type dot = path.rfind('.');
+ if (dot == std::string::npos || dot < slash)
+ return std::string();
+ else
+ return path.substr(dot + 1);
}
bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
return true;
}
-bool
-Path::isBytecodeFile() const {
- char buffer[4];
- buffer[0] = 0;
- int fd = ::open(path.c_str(), O_RDONLY);
- if (fd < 0)
- return false;
- ssize_t bytes_read = ::read(fd, buffer, 4);
- ::close(fd);
- if (4 != bytes_read)
- return false;
-
- return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' &&
- (buffer[3] == 'c' || buffer[3] == 'm'));
-}
-
bool
Path::exists() const {
return 0 == access(path.c_str(), F_OK );
}
+bool
+Path::isDirectory() const {
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf))
+ return false;
+ return buf.st_mode & S_IFDIR ? true : false;
+}
+
bool
Path::canRead() const {
return 0 == access(path.c_str(), F_OK | R_OK );
Path::canExecute() const {
if (0 != access(path.c_str(), R_OK | X_OK ))
return false;
- struct stat st;
- int r = stat(path.c_str(), &st);
- if (r != 0 || !S_ISREG(st.st_mode))
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf))
+ return false;
+ if (!S_ISREG(buf.st_mode))
return false;
return true;
}
return path.substr(pos+1);
}
-bool
-Path::getFileStatus(FileStatus &info, bool update, std::string *ErrStr) const {
- if (status == 0 || update) {
+const FileStatus *
+PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
+ if (!fsIsValid || update) {
struct stat buf;
- if (0 != stat(path.c_str(), &buf))
- return MakeErrMsg(ErrStr, path + ": can't get status of file");
- if (status == 0)
- status = new FileStatus;
- status->fileSize = buf.st_size;
- status->modTime.fromEpochTime(buf.st_mtime);
- status->mode = buf.st_mode;
- status->user = buf.st_uid;
- status->group = buf.st_gid;
- status->uniqueID = uint64_t(buf.st_ino);
- status->isDir = S_ISDIR(buf.st_mode);
- status->isFile = S_ISREG(buf.st_mode);
+ if (0 != stat(path.c_str(), &buf)) {
+ MakeErrMsg(ErrStr, path + ": can't get status of file");
+ return 0;
+ }
+ status.fileSize = buf.st_size;
+ status.modTime.fromEpochTime(buf.st_mtime);
+ status.mode = buf.st_mode;
+ status.user = buf.st_uid;
+ status.group = buf.st_gid;
+ status.uniqueID = uint64_t(buf.st_ino);
+ status.isDir = S_ISDIR(buf.st_mode);
+ status.isFile = S_ISREG(buf.st_mode);
+ fsIsValid = true;
}
- info = *status;
- return false;
+ return &status;
}
static bool AddPermissionBits(const Path &File, int bits) {
umask(mask); // Restore the umask.
// Get the file's current mode.
- FileStatus Stat;
- if (File.getFileStatus(Stat)) return false;
-
+ struct stat buf;
+ if (0 != stat(File.toString().c_str(), &buf))
+ return false;
// Change the file to have whichever permissions bits from 'bits'
// that the umask would not disable.
- if ((chmod(File.c_str(), (Stat.getMode() | (bits & ~mask)))) == -1)
- return false;
-
+ if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1)
+ return false;
return true;
}
return false;
}
+static bool createDirectoryHelper(char* beg, char* end, bool create_parents) {
+
+ if (access(beg, F_OK | R_OK | W_OK) == 0)
+ return false;
+
+ if (create_parents) {
+
+ char* c = end;
+
+ for (; c != beg; --c)
+ if (*c == '/') {
+
+ // Recurse to handling the parent directory.
+ *c = '\0';
+ bool x = createDirectoryHelper(beg, c, create_parents);
+ *c = '/';
+
+ // Return if we encountered an error.
+ if (x)
+ return true;
+
+ break;
+ }
+ }
+
+ return mkdir(beg, S_IRWXU | S_IRWXG) != 0;
+}
+
bool
Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) {
// Get a writeable copy of the path name
path.copy(pathname,MAXPATHLEN);
// Null-terminate the last component
- int lastchar = path.length() - 1 ;
- if (pathname[lastchar] == '/')
- pathname[lastchar] = 0;
- else
- pathname[lastchar+1] = 0;
-
- // If we're supposed to create intermediate directories
- if ( create_parents ) {
- // Find the end of the initial name component
- char * next = strchr(pathname,'/');
- if ( pathname[0] == '/')
- next = strchr(&pathname[1],'/');
-
- // Loop through the directory components until we're done
- while ( next != 0 ) {
- *next = 0;
- if (0 != access(pathname, F_OK | R_OK | W_OK))
- if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
- return MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create directory");
- }
- char* save = next;
- next = strchr(next+1,'/');
- *save = '/';
- }
- }
-
- if (0 != access(pathname, F_OK | R_OK))
- if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
- return MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create directory");
- }
+ size_t lastchar = path.length() - 1 ;
+
+ if (pathname[lastchar] != '/')
+ ++lastchar;
+
+ pathname[lastchar] = 0;
+
+ if (createDirectoryHelper(pathname, pathname+lastchar, create_parents))
+ return MakeErrMsg(ErrMsg,
+ std::string(pathname) + ": can't create directory");
+
return false;
}
bool
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- FileStatus Status;
- if (getFileStatus(Status, ErrStr))
+ // Get the status so we can determin if its a file or directory
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf)) {
+ MakeErrMsg(ErrStr, path + ": can't get status of file");
return true;
-
- // Note: this check catches strange situations. In all cases, LLVM should only
- // be involved in the creation and deletion of regular files. This check
- // ensures that what we're trying to erase is a regular file. It effectively
- // prevents LLVM from erasing things like /dev/null, any block special file,
- // or other things that aren't "regular" files.
- if (Status.isFile) {
+ }
+
+ // Note: this check catches strange situations. In all cases, LLVM should
+ // only be involved in the creation and deletion of regular files. This
+ // check ensures that what we're trying to erase is a regular file. It
+ // effectively prevents LLVM from erasing things like /dev/null, any block
+ // special file, or other things that aren't "regular" files.
+ if (S_ISREG(buf.st_mode)) {
if (unlink(path.c_str()) != 0)
return MakeErrMsg(ErrStr, path + ": can't destroy file");
return false;
}
- if (!Status.isDir) {
+ if (!S_ISDIR(buf.st_mode)) {
if (ErrStr) *ErrStr = "not a file or directory";
return true;
}
+
if (remove_contents) {
// Recursively descend the directory to remove its contents.
std::string cmd = "/bin/rm -rf " + path;
// Otherwise, try to just remove the one directory.
char pathname[MAXPATHLEN];
path.copy(pathname, MAXPATHLEN);
- int lastchar = path.length() - 1 ;
+ size_t lastchar = path.length() - 1;
if (pathname[lastchar] == '/')
pathname[lastchar] = 0;
else
if (rmdir(pathname) != 0)
return MakeErrMsg(ErrStr,
- std::string(pathname) + ": can't destroy directory");
+ std::string(pathname) + ": can't erase directory");
return false;
}
return false;
}
-bool
+bool
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
struct utimbuf utb;
utb.actime = si.modTime.toPosixTime();
return false;
}
+const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
+ int Flags = MAP_PRIVATE;
+#ifdef MAP_FILE
+ Flags |= MAP_FILE;
+#endif
+ void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, 0);
+ if (BasePtr == MAP_FAILED)
+ return 0;
+ return (const char*)BasePtr;
+}
+
+void Path::UnMapFilePages(const char *BasePtr, uint64_t FileSize) {
+ ::munmap((void*)BasePtr, FileSize);
+}
+
} // end llvm namespace