diff options
Diffstat (limited to 'source/Host/common/FileSpec.cpp')
-rw-r--r-- | source/Host/common/FileSpec.cpp | 412 |
1 files changed, 282 insertions, 130 deletions
diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp index 6a6de53cd311..ceb094b9ede7 100644 --- a/source/Host/common/FileSpec.cpp +++ b/source/Host/common/FileSpec.cpp @@ -27,6 +27,7 @@ #include <pwd.h> #endif +#include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" @@ -46,7 +47,45 @@ using namespace lldb; using namespace lldb_private; -static bool +namespace { + +bool +PathSyntaxIsPosix(FileSpec::PathSyntax syntax) +{ + return (syntax == FileSpec::ePathSyntaxPosix || + (syntax == FileSpec::ePathSyntaxHostNative && + FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); +} + +char +GetPathSeparator(FileSpec::PathSyntax syntax) +{ + return PathSyntaxIsPosix(syntax) ? '/' : '\\'; +} + +void +Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) +{ + if (PathSyntaxIsPosix(syntax)) return; + + std::replace(path.begin(), path.end(), '\\', '/'); + // Windows path can have \\ slashes which can be changed by replace + // call above to //. Here we remove the duplicate. + auto iter = std::unique ( path.begin(), path.end(), + []( char &c1, char &c2 ){ + return (c1 == '/' && c2 == '/');}); + path.erase(iter, path.end()); +} + +void +Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) +{ + if (PathSyntaxIsPosix(syntax)) return; + + std::replace(path.begin(), path.end(), '/', '\\'); +} + +bool GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) { char resolved_path[PATH_MAX]; @@ -55,6 +94,8 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) return false; } +} + // Resolves the username part of a path of the form ~user/other/directories, and // writes the result into dst_path. This will also resolve "~" to the current user. // If you want to complete "~" to the list of users, pass it to ResolvePartialUsername. @@ -164,7 +205,20 @@ FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) ResolveUsername(path); #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER + // Save a copy of the original path that's passed in + llvm::SmallString<PATH_MAX> original_path(path.begin(), path.end()); + llvm::sys::fs::make_absolute(path); + + + path.push_back(0); // Be sure we have a nul terminated string + path.pop_back(); + struct stat file_stats; + if (::stat (path.data(), &file_stats) != 0) + { + path.clear(); + path.append(original_path.begin(), original_path.end()); + } } FileSpec::FileSpec() : @@ -188,6 +242,21 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : SetFile(pathname, resolve_path, syntax); } +FileSpec::FileSpec(const char *pathname, bool resolve_path, ArchSpec arch) : + FileSpec{pathname, resolve_path, arch.GetTriple().isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix} +{ +} + +FileSpec::FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax) : + FileSpec{path.c_str(), resolve_path, syntax} +{ +} + +FileSpec::FileSpec(const std::string &path, bool resolve_path, ArchSpec arch) : + FileSpec{path.c_str(), resolve_path, arch} +{ +} + //------------------------------------------------------------------ // Copy constructor //------------------------------------------------------------------ @@ -233,30 +302,6 @@ FileSpec::operator= (const FileSpec& rhs) 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(), '\\', '/'); - // Windows path can have \\ slashes which can be changed by replace - // call above to //. Here we remove the duplicate. - auto iter = std::unique ( path.begin(), path.end(), - []( char &c1, char &c2 ){ - return (c1 == '/' && c2 == '/');}); - path.erase(iter, 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 @@ -299,6 +344,27 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) m_directory.SetCString(normalized.c_str()); } +void +FileSpec::SetFile(const char *pathname, bool resolve, ArchSpec arch) +{ + return SetFile(pathname, resolve, + arch.GetTriple().isOSWindows() + ? ePathSyntaxWindows + : ePathSyntaxPosix); +} + +void +FileSpec::SetFile(const std::string &pathname, bool resolve, PathSyntax syntax) +{ + return SetFile(pathname.c_str(), resolve, syntax); +} + +void +FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch) +{ + return SetFile(pathname.c_str(), resolve, arch); +} + //---------------------------------------------------------------------- // Convert to pointer operator. This allows code to check any FileSpec // objects to see if they contain anything valid using code such as: @@ -480,6 +546,14 @@ FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_ba } void +FileSpec::NormalizePath () +{ + ConstString normalized_directory; + FileSpec::RemoveBackupDots(m_directory, normalized_directory); + m_directory = normalized_directory; +} + +void FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str) { const char *input = input_const_str.GetCString(); @@ -545,6 +619,8 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res { if (had_dots) { + while (before_sep.startswith("//")) + before_sep = before_sep.substr(1); if (!before_sep.empty()) { result.append(before_sep.data(), before_sep.size()); @@ -590,13 +666,13 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res void FileSpec::Dump(Stream *s) const { - static ConstString g_slash_only ("/"); if (s) { - m_directory.Dump(s); - if (m_directory && m_directory != g_slash_only) - s->PutChar('/'); - m_filename.Dump(s); + std::string path{GetPath(true)}; + s->PutCString(path.c_str()); + char path_separator = GetPathSeparator(m_syntax); + if (!m_filename && !path.empty() && path.back() != path_separator) + s->PutChar(path_separator); } } @@ -718,7 +794,7 @@ FileSpec::GetPermissions () const { uint32_t file_permissions = 0; if (*this) - FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions); + FileSystem::GetFilePermissions(*this, file_permissions); return file_permissions; } @@ -780,26 +856,37 @@ FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const 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; + ::snprintf(path, path_max_len, "%s", result.c_str()); + return std::min(path_max_len-1, result.length()); } std::string -FileSpec::GetPath (bool denormalize) const +FileSpec::GetPath(bool denormalize) const { 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); - + GetPath(result, denormalize); return std::string(result.begin(), result.end()); } +const char * +FileSpec::GetCString(bool denormalize) const +{ + return ConstString{GetPath(denormalize)}.AsCString(NULL); +} + +void +FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const +{ + path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end()); + if (m_directory) + path.insert(path.end(), '/'); + path.append(m_filename.GetStringRef().begin(), m_filename.GetStringRef().end()); + Normalize(path, m_syntax); + if (path.size() > 1 && path.back() == '/') path.pop_back(); + if (denormalize && !path.empty()) + Denormalize(path, m_syntax); +} + ConstString FileSpec::GetFileNameExtension () const { @@ -852,6 +939,15 @@ FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const return data_sp; } +DataBufferSP +FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const +{ + if (FileSystem::IsLocal(*this)) + return MemoryMapFileContents(file_offset, file_size); + else + return ReadFileContents(file_offset, file_size, NULL); +} + //------------------------------------------------------------------ // Return the size in bytes that this object takes in memory. This @@ -974,15 +1070,7 @@ FileSpec::ReadFileLines (STLStringArray &lines) } FileSpec::EnumerateDirectoryResult -FileSpec::EnumerateDirectory -( - const char *dir_path, - bool find_directories, - bool find_files, - bool find_other, - EnumerateDirectoryCallbackType callback, - void *callback_baton -) +FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback) { if (dir_path && dir_path[0]) { @@ -1000,7 +1088,6 @@ FileSpec::EnumerateDirectory do { - bool call_callback = false; FileSpec::FileType file_type = eFileTypeUnknown; if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -1013,31 +1100,27 @@ FileSpec::EnumerateDirectory continue; file_type = eFileTypeDirectory; - call_callback = find_directories; } else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { file_type = eFileTypeOther; - call_callback = find_other; } else { file_type = eFileTypeRegular; - call_callback = find_files; } - if (call_callback) + + char child_path[MAX_PATH]; + const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName); + if (child_path_len < (int)(sizeof(child_path) - 1)) { - char child_path[MAX_PATH]; - const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName); - if (child_path_len < (int)(sizeof(child_path) - 1)) - { - // Don't resolve the file type or path - FileSpec child_path_spec (child_path, false); + // Don't resolve the file type or path + FileSpec child_path_spec (child_path, false); - EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec); + EnumerateDirectoryResult result = callback (file_type, child_path_spec); - switch (result) - { + switch (result) + { case eEnumerateDirectoryResultNext: // Enumerate next entry in the current directory. We just // exit this switch and will continue enumerating the @@ -1045,27 +1128,21 @@ FileSpec::EnumerateDirectory break; case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::EnumerateDirectory(child_path, - find_directories, - find_files, - find_other, - callback, - callback_baton) == eEnumerateDirectoryResultQuit) + if (FileSpec::ForEachItemInDirectory(child_path, callback) == eEnumerateDirectoryResultQuit) { - // The subdirectory returned Quit, which means to + // The subdirectory returned Quit, which means to // stop all directory enumerations at all levels. return eEnumerateDirectoryResultQuit; } break; case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to + // Exit from this directory level and tell parent to // keep enumerating. return eEnumerateDirectoryResultNext; case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level return eEnumerateDirectoryResultQuit; - } } } } while (FindNextFile(hFind, &ffd) != 0); @@ -1098,80 +1175,71 @@ FileSpec::EnumerateDirectory if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') continue; } - - bool call_callback = false; + FileSpec::FileType file_type = eFileTypeUnknown; switch (dp->d_type) { - default: - case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break; - case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break; - case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break; - case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break; - case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break; - case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break; - case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break; - case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break; + default: + case DT_UNKNOWN: file_type = eFileTypeUnknown; break; + case DT_FIFO: file_type = eFileTypePipe; break; + case DT_CHR: file_type = eFileTypeOther; break; + case DT_DIR: file_type = eFileTypeDirectory; break; + case DT_BLK: file_type = eFileTypeOther; break; + case DT_REG: file_type = eFileTypeRegular; break; + case DT_LNK: file_type = eFileTypeSymbolicLink; break; + case DT_SOCK: file_type = eFileTypeSocket; break; #if !defined(__OpenBSD__) - case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break; + case DT_WHT: file_type = eFileTypeOther; break; #endif } - if (call_callback) + char child_path[PATH_MAX]; + + // Don't make paths with "/foo//bar", that just confuses everybody. + int child_path_len; + if (dir_path_last_char == '/') + child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name); + else + child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); + + if (child_path_len < (int)(sizeof(child_path) - 1)) { - char child_path[PATH_MAX]; + // Don't resolve the file type or path + FileSpec child_path_spec (child_path, false); - // Don't make paths with "/foo//bar", that just confuses everybody. - int child_path_len; - if (dir_path_last_char == '/') - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name); - else - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); + EnumerateDirectoryResult result = callback (file_type, child_path_spec); - if (child_path_len < (int)(sizeof(child_path) - 1)) + switch (result) { - // Don't resolve the file type or path - FileSpec child_path_spec (child_path, false); - - EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec); - - switch (result) - { - case eEnumerateDirectoryResultNext: + case eEnumerateDirectoryResultNext: // Enumerate next entry in the current directory. We just // exit this switch and will continue enumerating the // current directory as we currently are... break; case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::EnumerateDirectory (child_path, - find_directories, - find_files, - find_other, - callback, - callback_baton) == eEnumerateDirectoryResultQuit) + if (FileSpec::ForEachItemInDirectory (child_path, callback) == eEnumerateDirectoryResultQuit) { - // The subdirectory returned Quit, which means to + // The subdirectory returned Quit, which means to // stop all directory enumerations at all levels. if (buf) free (buf); return eEnumerateDirectoryResultQuit; } break; - + case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to + // Exit from this directory level and tell parent to // keep enumerating. if (buf) free (buf); return eEnumerateDirectoryResultNext; - + case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level if (buf) free (buf); return eEnumerateDirectoryResultQuit; - } } } } @@ -1187,6 +1255,39 @@ FileSpec::EnumerateDirectory return eEnumerateDirectoryResultNext; } +FileSpec::EnumerateDirectoryResult +FileSpec::EnumerateDirectory +( + const char *dir_path, + bool find_directories, + bool find_files, + bool find_other, + EnumerateDirectoryCallbackType callback, + void *callback_baton +) +{ + return ForEachItemInDirectory(dir_path, + [&find_directories, &find_files, &find_other, &callback, &callback_baton] + (FileType file_type, const FileSpec &file_spec) { + switch (file_type) + { + case FileType::eFileTypeDirectory: + if (find_directories) + return callback(callback_baton, file_type, file_spec); + break; + case FileType::eFileTypeRegular: + if (find_files) + return callback(callback_baton, file_type, file_spec); + break; + default: + if (find_other) + return callback(callback_baton, file_type, file_spec); + break; + } + return eEnumerateDirectoryResultNext; + }); +} + FileSpec FileSpec::CopyByAppendingPathComponent (const char *new_path) const { @@ -1266,25 +1367,70 @@ FileSpec::GetLastPathComponent () const } void -FileSpec::AppendPathComponent (const char *new_path) +FileSpec::PrependPathComponent(const char *new_path) { + if (!new_path) return; const bool resolve = false; if (m_filename.IsEmpty() && m_directory.IsEmpty()) { - SetFile(new_path,resolve); + SetFile(new_path, resolve); return; } StreamString stream; if (m_filename.IsEmpty()) - stream.Printf("%s/%s",m_directory.GetCString(),new_path); + stream.Printf("%s/%s", new_path, m_directory.GetCString()); else if (m_directory.IsEmpty()) - stream.Printf("%s/%s",m_filename.GetCString(),new_path); + stream.Printf("%s/%s", new_path, m_filename.GetCString()); else - stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path); + stream.Printf("%s/%s/%s", new_path, m_directory.GetCString(), m_filename.GetCString()); SetFile(stream.GetData(), resolve); } void +FileSpec::PrependPathComponent(const std::string &new_path) +{ + return PrependPathComponent(new_path.c_str()); +} + +void +FileSpec::PrependPathComponent(const FileSpec &new_path) +{ + return PrependPathComponent(new_path.GetPath(false)); +} + +void +FileSpec::AppendPathComponent(const char *new_path) +{ + if (!new_path) return; + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) + { + SetFile(new_path, resolve); + return; + } + StreamString stream; + if (m_filename.IsEmpty()) + stream.Printf("%s/%s", m_directory.GetCString(), new_path); + else if (m_directory.IsEmpty()) + stream.Printf("%s/%s", m_filename.GetCString(), new_path); + else + stream.Printf("%s/%s/%s", m_directory.GetCString(), m_filename.GetCString(), new_path); + SetFile(stream.GetData(), resolve); +} + +void +FileSpec::AppendPathComponent(const std::string &new_path) +{ + return AppendPathComponent(new_path.c_str()); +} + +void +FileSpec::AppendPathComponent(const FileSpec &new_path) +{ + return AppendPathComponent(new_path.GetPath(false)); +} + +void FileSpec::RemoveLastPathComponent () { const bool resolve = false; @@ -1343,22 +1489,14 @@ FileSpec::IsSourceImplementationFile () const } bool -FileSpec::IsRelativeToCurrentWorkingDirectory () const +FileSpec::IsRelative() const { const char *dir = m_directory.GetCString(); llvm::StringRef directory(dir ? dir : ""); if (directory.size() > 0) { - if (m_syntax == ePathSyntaxWindows) - { - if (directory.size() >= 2 && directory[1] == ':') - return false; - if (directory[0] == '/') - return false; - return true; - } - else + if (PathSyntaxIsPosix(m_syntax)) { // If the path doesn't start with '/' or '~', return true switch (directory[0]) @@ -1370,6 +1508,14 @@ FileSpec::IsRelativeToCurrentWorkingDirectory () const return true; } } + else + { + if (directory.size() >= 2 && directory[1] == ':') + return false; + if (directory[0] == '/') + return false; + return true; + } } else if (m_filename) { @@ -1378,3 +1524,9 @@ FileSpec::IsRelativeToCurrentWorkingDirectory () const } return false; } + +bool +FileSpec::IsAbsolute() const +{ + return !FileSpec::IsRelative(); +} |