diff options
author | emaste <emaste@FreeBSD.org> | 2014-11-26 16:48:12 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2014-11-26 16:48:12 +0000 |
commit | 0147dda7de9580d13778ecb4c9e92b83b7a63911 (patch) | |
tree | b16dc95f693ed59342b6141cd3fd9f59a6cd7e7e /contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | |
parent | bfd4c39c61ae9b29542625bb12b6f7f4b1f8c727 (diff) | |
parent | 01ee1789d6aa7294e5966a97f8d29387f6f81699 (diff) | |
download | FreeBSD-src-0147dda7de9580d13778ecb4c9e92b83b7a63911.zip FreeBSD-src-0147dda7de9580d13778ecb4c9e92b83b7a63911.tar.gz |
Update LLDB snapshot to upstream r216948 (git 50f7fe44)
This is approximately "LLDB 3.5" although with a little bit of skew,
and will go along with the Clang 3.5 import.
Sponsored by: DARPA, AFRL
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | 381 |
1 files changed, 151 insertions, 230 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp index 48f1ac7..8c4014c 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp @@ -27,21 +27,22 @@ #include <pwd.h> #endif -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" - -#include "lldb/Core/StreamString.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamString.h" #include "lldb/Core/Stream.h" +#include "lldb/Host/File.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" + using namespace lldb; using namespace lldb_private; @@ -54,104 +55,68 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) return false; } -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - -static const char* -GetCachedGlobTildeSlash() -{ - static std::string g_tilde; - if (g_tilde.empty()) - { - struct passwd *user_entry; - user_entry = getpwuid(geteuid()); - if (user_entry != NULL) - g_tilde = user_entry->pw_dir; - - if (g_tilde.empty()) - return NULL; - } - return g_tilde.c_str(); -} - -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - // Resolves the username part of a path of the form ~user/other/directories, and // writes the result into dst_path. -// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. -// Otherwise returns the number of characters copied into dst_path. If the return -// is >= dst_len, then the resolved path is too long... -size_t -FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) +void +FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) { - if (src_path == NULL || src_path[0] == '\0') - return 0; - -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - - char user_home[PATH_MAX]; - const char *user_name; - - - // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) - if (src_path[0] != '~') - { - size_t len = strlen (src_path); - if (len >= dst_len) - { - ::bcopy (src_path, dst_path, dst_len - 1); - dst_path[dst_len] = '\0'; - } - else - ::bcopy (src_path, dst_path, len + 1); - - return len; - } - - const char *first_slash = ::strchr (src_path, '/'); - char remainder[PATH_MAX]; +#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER + if (path.empty() || path[0] != '~') + return; - if (first_slash == NULL) + llvm::StringRef path_str(path.data()); + size_t slash_pos = path_str.find_first_of("/", 1); + if (slash_pos == 1) { - // The whole name is the username (minus the ~): - user_name = src_path + 1; - remainder[0] = '\0'; - } - else - { - size_t user_name_len = first_slash - src_path - 1; - ::memcpy (user_home, src_path + 1, user_name_len); - user_home[user_name_len] = '\0'; - user_name = user_home; + // A path of the form ~/ resolves to the current user's home dir + llvm::SmallString<64> home_dir; + if (!llvm::sys::path::home_directory(home_dir)) + return; - ::strcpy (remainder, first_slash); + // Overwrite the ~ with the first character of the homedir, and insert + // the rest. This way we only trigger one move, whereas an insert + // followed by a delete (or vice versa) would trigger two. + path[0] = home_dir[0]; + path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + return; } - if (user_name == NULL) - return 0; - // User name of "" means the current user... - - struct passwd *user_entry; - const char *home_dir = NULL; - - if (user_name[0] == '\0') + auto username_begin = path.begin()+1; + auto username_end = (slash_pos == llvm::StringRef::npos) + ? path.end() + : (path.begin() + slash_pos); + size_t replacement_length = std::distance(path.begin(), username_end); + + llvm::SmallString<20> username(username_begin, username_end); + struct passwd *user_entry = ::getpwnam(username.c_str()); + if (user_entry != nullptr) { - home_dir = GetCachedGlobTildeSlash(); + // Copy over the first n characters of the path, where n is the smaller of the length + // of the home directory and the slash pos. + llvm::StringRef homedir(user_entry->pw_dir); + size_t initial_copy_length = std::min(homedir.size(), replacement_length); + auto src_begin = homedir.begin(); + auto src_end = src_begin + initial_copy_length; + std::copy(src_begin, src_end, path.begin()); + if (replacement_length > homedir.size()) + { + // We copied the entire home directory, but the ~username portion of the path was + // longer, so there's characters that need to be removed. + path.erase(path.begin() + initial_copy_length, username_end); + } + else if (replacement_length < homedir.size()) + { + // We copied all the way up to the slash in the destination, but there's still more + // characters that need to be inserted. + path.insert(username_end, src_end, homedir.end()); + } } else { - user_entry = ::getpwnam (user_name); - if (user_entry != NULL) - home_dir = user_entry->pw_dir; + // Unable to resolve username (user doesn't exist?) + path.clear(); } - - if (home_dir == NULL) - return 0; - else - return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); -#else - // Resolving home directories is not supported, just copy the path... - return ::snprintf (dst_path, dst_len, "%s", src_path); -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER +#endif } size_t @@ -187,49 +152,24 @@ FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER } - - -size_t -FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) +void +FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) { - if (src_path == NULL || src_path[0] == '\0') - return 0; + if (path.empty()) + return; - // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... - char unglobbed_path[PATH_MAX]; #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (src_path[0] == '~') - { - size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); - - // If we couldn't find the user referred to, or the resultant path was too long, - // then just copy over the src_path. - if (return_count == 0 || return_count >= sizeof(unglobbed_path)) - ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); - } - else + if (path[0] == '~') + ResolveUsername(path); #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - { - ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); - } - // Now resolve the path if needed - char resolved_path[PATH_MAX]; - if (::realpath (unglobbed_path, resolved_path)) - { - // Success, copy the resolved path - return ::snprintf(dst_path, dst_len, "%s", resolved_path); - } - else - { - // Failed, just copy the unglobbed path - return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); - } + llvm::sys::fs::make_absolute(path); } -FileSpec::FileSpec() : - m_directory(), - m_filename() +FileSpec::FileSpec() + : m_directory() + , m_filename() + , m_syntax(FileSystem::GetNativePathSyntax()) { } @@ -237,13 +177,13 @@ FileSpec::FileSpec() : // Default constructor that can take an optional full path to a // file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(const char *pathname, bool resolve_path) : +FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : m_directory(), m_filename(), m_is_resolved(false) { if (pathname && pathname[0]) - SetFile(pathname, resolve_path); + SetFile(pathname, resolve_path, syntax); } //------------------------------------------------------------------ @@ -252,7 +192,8 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path) : FileSpec::FileSpec(const FileSpec& rhs) : m_directory (rhs.m_directory), m_filename (rhs.m_filename), - m_is_resolved (rhs.m_is_resolved) + m_is_resolved (rhs.m_is_resolved), + m_syntax (rhs.m_syntax) { } @@ -268,7 +209,7 @@ FileSpec::FileSpec(const FileSpec* rhs) : } //------------------------------------------------------------------ -// Virtual destrcuctor in case anyone inherits from this class. +// Virtual destructor in case anyone inherits from this class. //------------------------------------------------------------------ FileSpec::~FileSpec() { @@ -285,83 +226,65 @@ FileSpec::operator= (const FileSpec& rhs) m_directory = rhs.m_directory; m_filename = rhs.m_filename; m_is_resolved = rhs.m_is_resolved; + m_syntax = rhs.m_syntax; } return *this; } +void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) +{ + if (syntax == ePathSyntaxPosix || + (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(path.begin(), path.end(), '\\', '/'); +} + +void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) +{ + if (syntax == ePathSyntaxPosix || + (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(path.begin(), path.end(), '/', '\\'); +} + //------------------------------------------------------------------ // Update the contents of this object with a new path. The path will // be split up into a directory and filename and stored as uniqued // string values for quick comparison and efficient memory usage. //------------------------------------------------------------------ void -FileSpec::SetFile (const char *pathname, bool resolve) +FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) { m_filename.Clear(); m_directory.Clear(); m_is_resolved = false; + m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax; + if (pathname == NULL || pathname[0] == '\0') return; - char resolved_path[PATH_MAX]; - bool path_fit = true; - + llvm::SmallString<64> normalized(pathname); + Normalize(normalized, syntax); + if (resolve) { - path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); - m_is_resolved = path_fit; + FileSpec::Resolve (normalized); + m_is_resolved = true; } - else - { - // Copy the path because "basename" and "dirname" want to muck with the - // path buffer - if (::strlen (pathname) > sizeof(resolved_path) - 1) - path_fit = false; - else - ::strcpy (resolved_path, pathname); - } - - if (path_fit) + llvm::StringRef resolve_path_ref(normalized.c_str()); + llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref); + if (!filename_ref.empty()) { - char *filename = ::basename (resolved_path); - if (filename) - { - m_filename.SetCString (filename); - // Truncate the basename off the end of the resolved path - - // Only attempt to get the dirname if it looks like we have a path - if (strchr(resolved_path, '/') -#ifdef _WIN32 - || strchr(resolved_path, '\\') -#endif - ) - { - char *directory = ::dirname (resolved_path); - - // Make sure we didn't get our directory resolved to "." without having - // specified - if (directory) - m_directory.SetCString(directory); - else - { - char *last_resolved_path_slash = strrchr(resolved_path, '/'); -#ifdef _WIN32 - char* last_resolved_path_slash_windows = strrchr(resolved_path, '\\'); - if (last_resolved_path_slash_windows > last_resolved_path_slash) - last_resolved_path_slash = last_resolved_path_slash_windows; -#endif - if (last_resolved_path_slash) - { - *last_resolved_path_slash = '\0'; - m_directory.SetCString(resolved_path); - } - } - } - } - else - m_directory.SetCString(resolved_path); + m_filename.SetString (filename_ref); + llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref); + if (!directory_ref.empty()) + m_directory.SetString(directory_ref); } + else + m_directory.SetCString(normalized.c_str()); } //---------------------------------------------------------------------- @@ -562,6 +485,15 @@ FileSpec::Exists () const } bool +FileSpec::Readable () const +{ + const uint32_t permissions = GetPermissions(); + if (permissions & eFilePermissionsEveryoneR) + return true; + return false; +} + +bool FileSpec::ResolveExecutableLocation () { if (!m_directory) @@ -572,8 +504,7 @@ FileSpec::ResolveExecutableLocation () const std::string file_str (file_cstr); std::string path = llvm::sys::FindProgramByName (file_str); llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - //llvm::StringRef dir_ref = path.getDirname(); - if (! dir_ref.empty()) + if (!dir_ref.empty()) { // FindProgramByName returns "." if it can't find the file. if (strcmp (".", dir_ref.data()) == 0) @@ -607,7 +538,7 @@ FileSpec::ResolvePath () return true; // We have already resolved this path char path_buf[PATH_MAX]; - if (!GetPath (path_buf, PATH_MAX)) + if (!GetPath (path_buf, PATH_MAX, false)) return false; // SetFile(...) will set m_is_resolved correctly if it can resolve the path SetFile (path_buf, true); @@ -623,6 +554,12 @@ FileSpec::GetByteSize() const return 0; } +FileSpec::PathSyntax +FileSpec::GetPathSyntax() const +{ + return m_syntax; +} + FileSpec::FileType FileSpec::GetFileType () const { @@ -652,7 +589,7 @@ FileSpec::GetPermissions () const { uint32_t file_permissions = 0; if (*this) - Host::GetFilePermissions(GetPath().c_str(), file_permissions); + FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions); return file_permissions; } @@ -708,45 +645,30 @@ FileSpec::GetFilename() const // values. //------------------------------------------------------------------ size_t -FileSpec::GetPath(char *path, size_t path_max_len) const +FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const { - if (path_max_len) - { - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) - { - if (filename) - return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); - else - return ::snprintf (path, path_max_len, "%s", dirname); - } - else if (filename) - { - return ::snprintf (path, path_max_len, "%s", filename); - } - } - if (path) - path[0] = '\0'; - return 0; + if (!path) + return 0; + + std::string result = GetPath(denormalize); + + size_t result_length = std::min(path_max_len-1, result.length()); + ::strncpy(path, result.c_str(), result_length + 1); + return result_length; } std::string -FileSpec::GetPath (void) const +FileSpec::GetPath (bool denormalize) const { - static ConstString g_slash_only ("/"); - std::string path; - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) - { - path.append (dirname); - if (filename && m_directory != g_slash_only) - path.append ("/"); - } - if (filename) - path.append (filename); - return path; + llvm::SmallString<64> result; + if (m_directory) + result.append(m_directory.GetCString()); + if (m_filename) + llvm::sys::path::append(result, m_filename.GetCString()); + if (denormalize && !result.empty()) + DeNormalize(result, m_syntax); + + return std::string(result.begin(), result.end()); } ConstString @@ -780,7 +702,7 @@ FileSpec::GetFileNameStrippingExtension () const // Returns a shared pointer to a data buffer that contains all or // part of the contents of a file. The data is memory mapped and // will lazily page in data from the file as memory is accessed. -// The data that is mappped will start "file_offset" bytes into the +// The data that is mapped will start "file_offset" bytes into the // file, and "file_size" bytes will be mapped. If "file_size" is // greater than the number of bytes available in the file starting // at "file_offset", the number of bytes will be appropriately @@ -936,12 +858,11 @@ FileSpec::EnumerateDirectory if (dir_path && dir_path[0]) { #if _WIN32 - char szDir[MAX_PATH]; - strcpy_s(szDir, MAX_PATH, dir_path); - strcat_s(szDir, MAX_PATH, "\\*"); + std::string szDir(dir_path); + szDir += "\\*"; WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(szDir, &ffd); + HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { |