//===-- RealpathPrefixes.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Utility/RealpathPrefixes.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/lldb-private-types.h" using namespace lldb_private; RealpathPrefixes::RealpathPrefixes( const FileSpecList &file_spec_list, llvm::IntrusiveRefCntPtr fs) : m_fs(fs) { m_prefixes.reserve(file_spec_list.GetSize()); for (const FileSpec &file_spec : file_spec_list) { m_prefixes.emplace_back(file_spec.GetPath()); } } std::optional RealpathPrefixes::ResolveSymlinks(const FileSpec &file_spec) { if (m_prefixes.empty()) return std::nullopt; // Test if `b` is a *path* prefix of `a` (not just *string* prefix). // E.g. "/foo/bar" is a path prefix of "/foo/bar/baz" but not "/foo/barbaz". auto is_path_prefix = [](llvm::StringRef a, llvm::StringRef b, bool case_sensitive, llvm::sys::path::Style style) -> bool { if (case_sensitive ? a.consume_front(b) : a.consume_front_insensitive(b)) // If `b` isn't "/", then it won't end with "/" because it comes from // `FileSpec`. After `a` consumes `b`, `a` should either be empty (i.e. // `a` == `b`) or end with "/" (the remainder of `a` is a subdirectory). return b == "/" || a.empty() || llvm::sys::path::is_separator(a[0], style); return false; }; std::string file_spec_path = file_spec.GetPath(); for (const std::string &prefix : m_prefixes) { if (is_path_prefix(file_spec_path, prefix, file_spec.IsCaseSensitive(), file_spec.GetPathStyle())) { // Stats and logging. IncreaseSourceRealpathAttemptCount(); Log *log = GetLog(LLDBLog::Source); LLDB_LOGF(log, "Realpath'ing support file %s", file_spec_path.c_str()); // One prefix matched. Try to realpath. PathSmallString buff; std::error_code ec = m_fs->getRealPath(file_spec_path, buff); if (ec) return std::nullopt; FileSpec realpath(buff, file_spec.GetPathStyle()); // Only return realpath if it is different from the original file_spec. if (realpath != file_spec) return realpath; return std::nullopt; } } // No prefix matched return std::nullopt; }