summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/Unix
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-03-10 17:39:21 +0000
committerZachary Turner <zturner@google.com>2017-03-10 17:39:21 +0000
commite48ace6a65514a4f71669c50fd5d4ead67acdc7f (patch)
treef16ef818e20451ed8031e0fe16248b273043dfd8 /llvm/lib/Support/Unix
parent62e0759d56b34c0b044a180e1bc89c419531cf57 (diff)
downloadbcm5719-llvm-e48ace6a65514a4f71669c50fd5d4ead67acdc7f.tar.gz
bcm5719-llvm-e48ace6a65514a4f71669c50fd5d4ead67acdc7f.zip
Add llvm::sys::fs::real_path.
LLVM already has real_path like functionality, but it is cumbersome to use and involves clean up after (e.g. you have to call openFileForRead, then close the resulting FD). Furthermore, on Windows it doesn't work for directories since opening a directory and opening a file require slightly different flags. So I add a simple function `real_path` which works for all paths on all platforms and has a simple to use interface. In doing so, I add the ability to opt in to resolving tilde expressions (e.g. ~/foo), which are normally handled by the shell. Differential Revision: https://reviews.llvm.org/D30668 llvm-svn: 297483
Diffstat (limited to 'llvm/lib/Support/Unix')
-rw-r--r--llvm/lib/Support/Unix/Path.inc64
1 files changed, 63 insertions, 1 deletions
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 43549c0f564..cdc692b8f1f 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -48,6 +48,8 @@
# endif
#endif
+#include <pwd.h>
+
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <sys/attr.h>
@@ -478,6 +480,45 @@ std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
return std::error_code();
}
+static void expandTildeExpr(SmallVectorImpl<char> &Path) {
+ StringRef PathStr(Path.begin(), Path.size());
+ if (PathStr.empty() || !PathStr.startswith("~"))
+ return;
+
+ PathStr = PathStr.drop_front();
+ StringRef Expr = PathStr.take_until(path::is_separator);
+ StringRef Remainder = PathStr.substr(Expr.size() + 1);
+ SmallString<128> Storage;
+ if (Expr.empty()) {
+ // This is just ~/..., resolve it to the current user's home dir.
+ if (!path::home_directory(Storage)) {
+ // For some reason we couldn't get the home directory. Just exit.
+ return;
+ }
+
+ // Overwrite the first character and insert the rest.
+ Path[0] = Storage[0];
+ Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
+ return;
+ }
+
+ // This is a string of the form ~username/, look up this user's entry in the
+ // password database.
+ struct passwd *Entry = nullptr;
+ std::string User = Expr.str();
+ Entry = ::getpwnam(User.c_str());
+
+ if (!Entry) {
+ // Unable to look up the entry, just return back the original path.
+ return;
+ }
+
+ Storage = Remainder;
+ Path.clear();
+ Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir));
+ llvm::sys::path::append(Path, Storage);
+}
+
static std::error_code fillStatus(int StatRet, const struct stat &Status,
file_status &Result) {
if (StatRet != 0) {
@@ -839,6 +880,28 @@ std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
return std::error_code();
}
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
+ bool expand_tilde) {
+ dest.clear();
+ if (path.isTriviallyEmpty())
+ return std::error_code();
+
+ if (expand_tilde) {
+ SmallString<128> Storage;
+ path.toVector(Storage);
+ expandTildeExpr(Storage);
+ return real_path(Storage, dest, false);
+ }
+
+ int fd;
+ std::error_code EC = openFileForRead(path, fd, &dest);
+
+ if (EC)
+ return EC;
+ ::close(fd);
+ return std::error_code();
+}
+
} // end namespace fs
namespace path {
@@ -849,7 +912,6 @@ bool home_directory(SmallVectorImpl<char> &result) {
result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
return true;
}
-
return false;
}
OpenPOWER on IntegriCloud