Optimizations for FileSpec.

llvm-svn: 215124
This commit is contained in:
Zachary Turner
2014-08-07 17:33:36 +00:00
parent df62f20c75
commit 3f55974024
6 changed files with 118 additions and 202 deletions

View File

@@ -570,8 +570,8 @@ public:
lldb::DataBufferSP
ReadFileContentsAsCString(Error *error_ptr = NULL);
static void Normalize(llvm::StringRef path, llvm::SmallVectorImpl<char> &result, PathSyntax syntax);
static void DeNormalize(llvm::StringRef path, llvm::SmallVectorImpl<char> &result, PathSyntax syntax);
static void Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax = ePathSyntaxHostNative);
static void DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax = ePathSyntaxHostNative);
//------------------------------------------------------------------
/// Change the file specified with a new path.
@@ -636,22 +636,11 @@ public:
/// exist, the contents of \a src_path will be copied to \a dst_path
/// unchanged.
///
/// @param[in] src_path
/// Input path to be resolved.
///
/// @param[in] dst_path
/// Buffer to store the resolved path.
///
/// @param[in] dst_len
/// Size of the buffer pointed to by dst_path.
///
/// @result
/// The number of characters required to write the resolved path. If the
/// resolved path doesn't fit in dst_len, dst_len-1 characters will
/// be written to \a dst_path, but the actual required length will still be returned.
/// @param[in] path
/// Input path to be resolved, in the form of a llvm::SmallString or similar.
//------------------------------------------------------------------
static size_t
Resolve (const char *src_path, char *dst_path, size_t dst_len);
static void
Resolve (llvm::SmallVectorImpl<char> &path);
FileSpec
CopyByAppendingPathComponent (const char *new_path) const;
@@ -679,18 +668,9 @@ public:
///
/// @param[in] dst_path
/// Buffer to store the resolved path.
///
/// @param[in] dst_len
/// Size of the buffer pointed to by dst_path.
///
/// @result
/// The number of characters required to write the resolved path, or 0 if
/// the user name could not be found. If the
/// resolved path doesn't fit in dst_len, dst_len-1 characters will
/// be written to \a dst_path, but the actual required length will still be returned.
//------------------------------------------------------------------
static size_t
ResolveUsername (const char *src_path, char *dst_path, size_t dst_len);
static void
ResolveUsername (llvm::SmallVectorImpl<char> &path);
static size_t
ResolvePartialUsername (const char *partial_name, StringList &matches);

View File

@@ -16,6 +16,8 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
@@ -89,7 +91,11 @@ SBFileSpec::ResolveExecutableLocation ()
int
SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len)
{
return lldb_private::FileSpec::Resolve (src_path, dst_path, dst_len);
llvm::SmallString<64> result(src_path);
lldb_private::FileSpec::Resolve (result);
size_t result_length = std::min(dst_len-1, result.size());
::strncpy(dst_path, result.c_str(), result_length + 1);
return result_length;
}
const char *

View File

@@ -30,6 +30,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb_private;
CommandCompletions::CommonCompletionElement
@@ -221,7 +223,7 @@ DiskFilesOrDirectories
end_ptr = strrchr(partial_name_copy, '/');
// This will store the resolved form of the containing directory
char containing_part[PATH_MAX];
llvm::SmallString<64> containing_part;
if (end_ptr == NULL)
{
@@ -232,14 +234,11 @@ DiskFilesOrDirectories
// Nothing here but the user name. We could just put a slash on the end,
// but for completeness sake we'll resolve the user name and only put a slash
// on the end if it exists.
char resolved_username[PATH_MAX];
size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
sizeof (resolved_username));
llvm::SmallString<64> resolved_username(partial_name_copy);
FileSpec::ResolveUsername (resolved_username);
// Not sure how this would happen, a username longer than PATH_MAX? Still...
if (resolved_username_len >= sizeof (resolved_username))
return matches.GetSize();
else if (resolved_username_len == 0)
if (resolved_username.size() == 0)
{
// The user name didn't resolve, let's look in the password database for matches.
// The user name database contains duplicates, and is not in alphabetical order, so
@@ -263,8 +262,7 @@ DiskFilesOrDirectories
else
{
// The containing part is the CWD, and the whole string is the remainder.
containing_part[0] = '.';
containing_part[1] = '\0';
containing_part = ".";
strcpy(remainder, partial_name_copy);
end_ptr = partial_name_copy;
}
@@ -274,14 +272,11 @@ DiskFilesOrDirectories
if (end_ptr == partial_name_copy)
{
// We're completing a file or directory in the root volume.
containing_part[0] = '/';
containing_part[1] = '\0';
containing_part = "/";
}
else
{
size_t len = end_ptr - partial_name_copy;
memcpy(containing_part, partial_name_copy, len);
containing_part[len] = '\0';
containing_part.append(partial_name_copy, end_ptr);
}
// Push end_ptr past the final "/" and set remainder.
end_ptr++;
@@ -293,11 +288,9 @@ DiskFilesOrDirectories
if (*partial_name_copy == '~')
{
size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
containing_part,
sizeof (containing_part));
FileSpec::ResolveUsername(containing_part);
// User name doesn't exist, we're not getting any further...
if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
if (containing_part.empty())
return matches.GetSize();
}
@@ -314,7 +307,7 @@ DiskFilesOrDirectories
parameters.end_ptr = end_ptr;
parameters.baselen = baselen;
FileSpec::EnumerateDirectory(containing_part, true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
return matches.GetSize();
}

View File

@@ -28,6 +28,7 @@
#endif
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
@@ -77,81 +78,66 @@ GetCachedGlobTildeSlash()
// 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 LLDB_CONFIG_TILDE_RESOLVES_TO_USER
if (path.empty() || path[0] != '~')
return;
// If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
if (src_path[0] != '~')
llvm::StringRef path_str(path.data());
size_t slash_pos = path_str.find_first_of("/", 1);
if (slash_pos == 1)
{
size_t len = strlen (src_path);
if (len >= dst_len)
// 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;
// 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;
}
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)
{
// 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())
{
::bcopy (src_path, dst_path, dst_len - 1);
dst_path[dst_len] = '\0';
// 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
::bcopy (src_path, dst_path, len + 1);
return len;
}
const char *first_slash = ::strchr (src_path, '/');
char remainder[PATH_MAX];
if (first_slash == NULL)
{
// 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;
::strcpy (remainder, first_slash);
// Unable to resolve username (user doesn't exist?)
path.clear();
}
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')
{
home_dir = GetCachedGlobTildeSlash();
}
else
{
user_entry = ::getpwnam (user_name);
if (user_entry != NULL)
home_dir = user_entry->pw_dir;
}
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,44 +173,18 @@ 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() :
@@ -292,24 +252,20 @@ FileSpec::operator= (const FileSpec& rhs)
return *this;
}
void FileSpec::Normalize(llvm::StringRef path, llvm::SmallVectorImpl<char> &result, PathSyntax syntax)
void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
{
result.clear();
result.append(path.begin(), path.end());
if (syntax == ePathSyntaxPosix || (syntax == ePathSyntaxHostNative && Host::GetHostPathSyntax() == ePathSyntaxPosix))
return;
std::replace(result.begin(), result.end(), '\\', '/');
std::replace(path.begin(), path.end(), '\\', '/');
}
void FileSpec::DeNormalize(llvm::StringRef path, llvm::SmallVectorImpl<char> &result, PathSyntax syntax)
void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
{
result.clear();
result.append(path.begin(), path.end());
if (syntax == ePathSyntaxPosix || (syntax == ePathSyntaxHostNative && Host::GetHostPathSyntax() == ePathSyntaxPosix))
return;
std::replace(result.begin(), result.end(), '/', '\\');
std::replace(path.begin(), path.end(), '/', '\\');
}
//------------------------------------------------------------------
@@ -328,41 +284,26 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
if (pathname == NULL || pathname[0] == '\0')
return;
llvm::SmallString<64> normalized;
Normalize(pathname, normalized, syntax);
llvm::SmallString<64> normalized(pathname);
Normalize(normalized, syntax);
std::vector<char> resolved_path(PATH_MAX);
bool path_fit = true;
if (resolve)
{
path_fit = (FileSpec::Resolve (normalized.c_str(), &resolved_path[0], resolved_path.size()) < resolved_path.size() - 1);
m_is_resolved = path_fit;
}
else
{
// Copy the path because "basename" and "dirname" want to muck with the
// path buffer
if (normalized.size() > resolved_path.size() - 1)
path_fit = false;
else
::strcpy (&resolved_path[0], normalized.c_str());
FileSpec::Resolve (normalized);
m_is_resolved = true;
}
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())
{
llvm::StringRef resolve_path_ref(&resolved_path[0]);
llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
if (!filename_ref.empty())
{
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(&resolved_path[0]);
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());
}
//----------------------------------------------------------------------
@@ -732,11 +673,7 @@ FileSpec::GetPath (bool denormalize) const
if (m_filename)
llvm::sys::path::append(result, m_filename.GetCString());
if (denormalize && !result.empty())
{
llvm::SmallString<64> denormalized;
DeNormalize(result.c_str(), denormalized, m_syntax);
result = denormalized;
}
DeNormalize(result, m_syntax);
return std::string(result.begin(), result.end());
}

View File

@@ -1119,7 +1119,6 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
{
char raw_path[PATH_MAX];
char resolved_path[PATH_MAX];
lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
#if defined (__APPLE__)
@@ -1159,8 +1158,9 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
log->Printf ("Host::%s() failed to find /lib/liblldb within the shared lib path, bailing on bin path construction", __FUNCTION__);
}
#endif // #if defined (__APPLE__)
FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
g_lldb_support_exe_dir.SetCString(resolved_path);
llvm::SmallString<64> resolved_path(raw_path);
FileSpec::Resolve (resolved_path);
g_lldb_support_exe_dir.SetCString(resolved_path.c_str());
}
if (log)
log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString());
@@ -1217,7 +1217,6 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
{
char raw_path[PATH_MAX];
char resolved_path[PATH_MAX];
#if defined(_WIN32)
lldb_file_spec.AppendPathComponent("../lib/site-packages");
lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
@@ -1248,8 +1247,9 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
#if defined (__APPLE__)
}
#endif
FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
g_lldb_python_dir.SetCString(resolved_path);
llvm::SmallString<64> resolved_path(raw_path);
FileSpec::Resolve (resolved_path);
g_lldb_python_dir.SetCString(resolved_path.c_str());
}
if (log)

View File

@@ -28,6 +28,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
@@ -241,15 +243,13 @@ TargetList::CreateTarget (Debugger &debugger,
{
// we want to expand the tilde but we don't want to resolve any symbolic links
// so we can't use the FileSpec constructor's resolve flag
char unglobbed_path[PATH_MAX];
unglobbed_path[0] = '\0';
llvm::SmallString<64> unglobbed_path(user_exe_path);
FileSpec::ResolveUsername(unglobbed_path);
size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path));
if (return_count == 0 || return_count >= sizeof(unglobbed_path))
::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path);
file = FileSpec(unglobbed_path, false);
if (unglobbed_path.empty())
file = FileSpec(user_exe_path, false);
else
file = FileSpec(unglobbed_path.c_str(), false);
}
bool user_exe_path_is_bundle = false;