1254721Semaste//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste 11254721Semaste#include <dirent.h> 12254721Semaste#include <fcntl.h> 13254721Semaste#include <libgen.h> 14254721Semaste#include <sys/stat.h> 15254721Semaste#include <set> 16254721Semaste#include <string.h> 17254721Semaste#include <fstream> 18254721Semaste 19254721Semaste#include "lldb/Host/Config.h" // Have to include this before we test the define... 20254721Semaste#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 21254721Semaste#include <pwd.h> 22254721Semaste#endif 23254721Semaste 24254721Semaste#include "llvm/ADT/StringRef.h" 25254721Semaste#include "llvm/Support/Path.h" 26254721Semaste#include "llvm/Support/Program.h" 27254721Semaste 28254721Semaste#include "lldb/Host/File.h" 29254721Semaste#include "lldb/Host/FileSpec.h" 30254721Semaste#include "lldb/Core/DataBufferHeap.h" 31254721Semaste#include "lldb/Core/DataBufferMemoryMap.h" 32254721Semaste#include "lldb/Core/RegularExpression.h" 33254721Semaste#include "lldb/Core/Stream.h" 34254721Semaste#include "lldb/Host/Host.h" 35254721Semaste#include "lldb/Utility/CleanUp.h" 36254721Semaste 37254721Semasteusing namespace lldb; 38254721Semasteusing namespace lldb_private; 39254721Semaste 40254721Semastestatic bool 41254721SemasteGetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) 42254721Semaste{ 43254721Semaste char resolved_path[PATH_MAX]; 44254721Semaste if (file_spec->GetPath (resolved_path, sizeof(resolved_path))) 45254721Semaste return ::stat (resolved_path, stats_ptr) == 0; 46254721Semaste return false; 47254721Semaste} 48254721Semaste 49254721Semaste#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 50254721Semaste 51254721Semastestatic const char* 52254721SemasteGetCachedGlobTildeSlash() 53254721Semaste{ 54254721Semaste static std::string g_tilde; 55254721Semaste if (g_tilde.empty()) 56254721Semaste { 57254721Semaste struct passwd *user_entry; 58254721Semaste user_entry = getpwuid(geteuid()); 59254721Semaste if (user_entry != NULL) 60254721Semaste g_tilde = user_entry->pw_dir; 61254721Semaste 62254721Semaste if (g_tilde.empty()) 63254721Semaste return NULL; 64254721Semaste } 65254721Semaste return g_tilde.c_str(); 66254721Semaste} 67254721Semaste 68254721Semaste#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 69254721Semaste 70254721Semaste// Resolves the username part of a path of the form ~user/other/directories, and 71254721Semaste// writes the result into dst_path. 72254721Semaste// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. 73254721Semaste// Otherwise returns the number of characters copied into dst_path. If the return 74254721Semaste// is >= dst_len, then the resolved path is too long... 75254721Semastesize_t 76254721SemasteFileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) 77254721Semaste{ 78254721Semaste if (src_path == NULL || src_path[0] == '\0') 79254721Semaste return 0; 80254721Semaste 81254721Semaste#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 82254721Semaste 83254721Semaste char user_home[PATH_MAX]; 84254721Semaste const char *user_name; 85254721Semaste 86254721Semaste 87254721Semaste // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) 88254721Semaste if (src_path[0] != '~') 89254721Semaste { 90254721Semaste size_t len = strlen (src_path); 91254721Semaste if (len >= dst_len) 92254721Semaste { 93254721Semaste ::bcopy (src_path, dst_path, dst_len - 1); 94254721Semaste dst_path[dst_len] = '\0'; 95254721Semaste } 96254721Semaste else 97254721Semaste ::bcopy (src_path, dst_path, len + 1); 98254721Semaste 99254721Semaste return len; 100254721Semaste } 101254721Semaste 102254721Semaste const char *first_slash = ::strchr (src_path, '/'); 103254721Semaste char remainder[PATH_MAX]; 104254721Semaste 105254721Semaste if (first_slash == NULL) 106254721Semaste { 107254721Semaste // The whole name is the username (minus the ~): 108254721Semaste user_name = src_path + 1; 109254721Semaste remainder[0] = '\0'; 110254721Semaste } 111254721Semaste else 112254721Semaste { 113254721Semaste size_t user_name_len = first_slash - src_path - 1; 114254721Semaste ::memcpy (user_home, src_path + 1, user_name_len); 115254721Semaste user_home[user_name_len] = '\0'; 116254721Semaste user_name = user_home; 117254721Semaste 118254721Semaste ::strcpy (remainder, first_slash); 119254721Semaste } 120254721Semaste 121254721Semaste if (user_name == NULL) 122254721Semaste return 0; 123254721Semaste // User name of "" means the current user... 124254721Semaste 125254721Semaste struct passwd *user_entry; 126254721Semaste const char *home_dir = NULL; 127254721Semaste 128254721Semaste if (user_name[0] == '\0') 129254721Semaste { 130254721Semaste home_dir = GetCachedGlobTildeSlash(); 131254721Semaste } 132254721Semaste else 133254721Semaste { 134254721Semaste user_entry = ::getpwnam (user_name); 135254721Semaste if (user_entry != NULL) 136254721Semaste home_dir = user_entry->pw_dir; 137254721Semaste } 138254721Semaste 139254721Semaste if (home_dir == NULL) 140254721Semaste return 0; 141254721Semaste else 142254721Semaste return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); 143254721Semaste#else 144254721Semaste // Resolving home directories is not supported, just copy the path... 145254721Semaste return ::snprintf (dst_path, dst_len, "%s", src_path); 146254721Semaste#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 147254721Semaste} 148254721Semaste 149254721Semastesize_t 150254721SemasteFileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) 151254721Semaste{ 152254721Semaste#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 153254721Semaste size_t extant_entries = matches.GetSize(); 154254721Semaste 155254721Semaste setpwent(); 156254721Semaste struct passwd *user_entry; 157254721Semaste const char *name_start = partial_name + 1; 158254721Semaste std::set<std::string> name_list; 159254721Semaste 160254721Semaste while ((user_entry = getpwent()) != NULL) 161254721Semaste { 162254721Semaste if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name) 163254721Semaste { 164254721Semaste std::string tmp_buf("~"); 165254721Semaste tmp_buf.append(user_entry->pw_name); 166254721Semaste tmp_buf.push_back('/'); 167254721Semaste name_list.insert(tmp_buf); 168254721Semaste } 169254721Semaste } 170254721Semaste std::set<std::string>::iterator pos, end = name_list.end(); 171254721Semaste for (pos = name_list.begin(); pos != end; pos++) 172254721Semaste { 173254721Semaste matches.AppendString((*pos).c_str()); 174254721Semaste } 175254721Semaste return matches.GetSize() - extant_entries; 176254721Semaste#else 177254721Semaste // Resolving home directories is not supported, just copy the path... 178254721Semaste return 0; 179254721Semaste#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 180254721Semaste} 181254721Semaste 182254721Semaste 183254721Semaste 184254721Semastesize_t 185254721SemasteFileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) 186254721Semaste{ 187254721Semaste if (src_path == NULL || src_path[0] == '\0') 188254721Semaste return 0; 189254721Semaste 190254721Semaste // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... 191254721Semaste char unglobbed_path[PATH_MAX]; 192254721Semaste#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 193254721Semaste if (src_path[0] == '~') 194254721Semaste { 195254721Semaste size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); 196254721Semaste 197254721Semaste // If we couldn't find the user referred to, or the resultant path was too long, 198254721Semaste // then just copy over the src_path. 199254721Semaste if (return_count == 0 || return_count >= sizeof(unglobbed_path)) 200254721Semaste ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 201254721Semaste } 202254721Semaste else 203254721Semaste#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 204254721Semaste { 205254721Semaste ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 206254721Semaste } 207254721Semaste 208254721Semaste // Now resolve the path if needed 209254721Semaste char resolved_path[PATH_MAX]; 210254721Semaste if (::realpath (unglobbed_path, resolved_path)) 211254721Semaste { 212254721Semaste // Success, copy the resolved path 213254721Semaste return ::snprintf(dst_path, dst_len, "%s", resolved_path); 214254721Semaste } 215254721Semaste else 216254721Semaste { 217254721Semaste // Failed, just copy the unglobbed path 218254721Semaste return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); 219254721Semaste } 220254721Semaste} 221254721Semaste 222254721SemasteFileSpec::FileSpec() : 223254721Semaste m_directory(), 224254721Semaste m_filename() 225254721Semaste{ 226254721Semaste} 227254721Semaste 228254721Semaste//------------------------------------------------------------------ 229254721Semaste// Default constructor that can take an optional full path to a 230254721Semaste// file on disk. 231254721Semaste//------------------------------------------------------------------ 232254721SemasteFileSpec::FileSpec(const char *pathname, bool resolve_path) : 233254721Semaste m_directory(), 234254721Semaste m_filename(), 235254721Semaste m_is_resolved(false) 236254721Semaste{ 237254721Semaste if (pathname && pathname[0]) 238254721Semaste SetFile(pathname, resolve_path); 239254721Semaste} 240254721Semaste 241254721Semaste//------------------------------------------------------------------ 242254721Semaste// Copy constructor 243254721Semaste//------------------------------------------------------------------ 244254721SemasteFileSpec::FileSpec(const FileSpec& rhs) : 245254721Semaste m_directory (rhs.m_directory), 246254721Semaste m_filename (rhs.m_filename), 247254721Semaste m_is_resolved (rhs.m_is_resolved) 248254721Semaste{ 249254721Semaste} 250254721Semaste 251254721Semaste//------------------------------------------------------------------ 252254721Semaste// Copy constructor 253254721Semaste//------------------------------------------------------------------ 254254721SemasteFileSpec::FileSpec(const FileSpec* rhs) : 255254721Semaste m_directory(), 256254721Semaste m_filename() 257254721Semaste{ 258254721Semaste if (rhs) 259254721Semaste *this = *rhs; 260254721Semaste} 261254721Semaste 262254721Semaste//------------------------------------------------------------------ 263254721Semaste// Virtual destrcuctor in case anyone inherits from this class. 264254721Semaste//------------------------------------------------------------------ 265254721SemasteFileSpec::~FileSpec() 266254721Semaste{ 267254721Semaste} 268254721Semaste 269254721Semaste//------------------------------------------------------------------ 270254721Semaste// Assignment operator. 271254721Semaste//------------------------------------------------------------------ 272254721Semasteconst FileSpec& 273254721SemasteFileSpec::operator= (const FileSpec& rhs) 274254721Semaste{ 275254721Semaste if (this != &rhs) 276254721Semaste { 277254721Semaste m_directory = rhs.m_directory; 278254721Semaste m_filename = rhs.m_filename; 279254721Semaste m_is_resolved = rhs.m_is_resolved; 280254721Semaste } 281254721Semaste return *this; 282254721Semaste} 283254721Semaste 284254721Semaste//------------------------------------------------------------------ 285254721Semaste// Update the contents of this object with a new path. The path will 286254721Semaste// be split up into a directory and filename and stored as uniqued 287254721Semaste// string values for quick comparison and efficient memory usage. 288254721Semaste//------------------------------------------------------------------ 289254721Semastevoid 290254721SemasteFileSpec::SetFile (const char *pathname, bool resolve) 291254721Semaste{ 292254721Semaste m_filename.Clear(); 293254721Semaste m_directory.Clear(); 294254721Semaste m_is_resolved = false; 295254721Semaste if (pathname == NULL || pathname[0] == '\0') 296254721Semaste return; 297254721Semaste 298254721Semaste char resolved_path[PATH_MAX]; 299254721Semaste bool path_fit = true; 300254721Semaste 301254721Semaste if (resolve) 302254721Semaste { 303254721Semaste path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); 304254721Semaste m_is_resolved = path_fit; 305254721Semaste } 306254721Semaste else 307254721Semaste { 308254721Semaste // Copy the path because "basename" and "dirname" want to muck with the 309254721Semaste // path buffer 310254721Semaste if (::strlen (pathname) > sizeof(resolved_path) - 1) 311254721Semaste path_fit = false; 312254721Semaste else 313254721Semaste ::strcpy (resolved_path, pathname); 314254721Semaste } 315254721Semaste 316254721Semaste 317254721Semaste if (path_fit) 318254721Semaste { 319254721Semaste char *filename = ::basename (resolved_path); 320254721Semaste if (filename) 321254721Semaste { 322254721Semaste m_filename.SetCString (filename); 323254721Semaste // Truncate the basename off the end of the resolved path 324254721Semaste 325254721Semaste // Only attempt to get the dirname if it looks like we have a path 326254721Semaste if (strchr(resolved_path, '/')) 327254721Semaste { 328254721Semaste char *directory = ::dirname (resolved_path); 329254721Semaste 330254721Semaste // Make sure we didn't get our directory resolved to "." without having 331254721Semaste // specified 332254721Semaste if (directory) 333254721Semaste m_directory.SetCString(directory); 334254721Semaste else 335254721Semaste { 336254721Semaste char *last_resolved_path_slash = strrchr(resolved_path, '/'); 337254721Semaste if (last_resolved_path_slash) 338254721Semaste { 339254721Semaste *last_resolved_path_slash = '\0'; 340254721Semaste m_directory.SetCString(resolved_path); 341254721Semaste } 342254721Semaste } 343254721Semaste } 344254721Semaste } 345254721Semaste else 346254721Semaste m_directory.SetCString(resolved_path); 347254721Semaste } 348254721Semaste} 349254721Semaste 350254721Semaste//---------------------------------------------------------------------- 351254721Semaste// Convert to pointer operator. This allows code to check any FileSpec 352254721Semaste// objects to see if they contain anything valid using code such as: 353254721Semaste// 354254721Semaste// if (file_spec) 355254721Semaste// {} 356254721Semaste//---------------------------------------------------------------------- 357254721SemasteFileSpec::operator bool() const 358254721Semaste{ 359254721Semaste return m_filename || m_directory; 360254721Semaste} 361254721Semaste 362254721Semaste//---------------------------------------------------------------------- 363254721Semaste// Logical NOT operator. This allows code to check any FileSpec 364254721Semaste// objects to see if they are invalid using code such as: 365254721Semaste// 366254721Semaste// if (!file_spec) 367254721Semaste// {} 368254721Semaste//---------------------------------------------------------------------- 369254721Semastebool 370254721SemasteFileSpec::operator!() const 371254721Semaste{ 372254721Semaste return !m_directory && !m_filename; 373254721Semaste} 374254721Semaste 375254721Semaste//------------------------------------------------------------------ 376254721Semaste// Equal to operator 377254721Semaste//------------------------------------------------------------------ 378254721Semastebool 379254721SemasteFileSpec::operator== (const FileSpec& rhs) const 380254721Semaste{ 381254721Semaste if (m_filename == rhs.m_filename) 382254721Semaste { 383254721Semaste if (m_directory == rhs.m_directory) 384254721Semaste return true; 385254721Semaste 386254721Semaste // TODO: determine if we want to keep this code in here. 387254721Semaste // The code below was added to handle a case where we were 388254721Semaste // trying to set a file and line breakpoint and one path 389254721Semaste // was resolved, and the other not and the directory was 390254721Semaste // in a mount point that resolved to a more complete path: 391254721Semaste // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling 392254721Semaste // this out... 393254721Semaste if (IsResolved() && rhs.IsResolved()) 394254721Semaste { 395254721Semaste // Both paths are resolved, no need to look further... 396254721Semaste return false; 397254721Semaste } 398254721Semaste 399254721Semaste FileSpec resolved_lhs(*this); 400254721Semaste 401254721Semaste // If "this" isn't resolved, resolve it 402254721Semaste if (!IsResolved()) 403254721Semaste { 404254721Semaste if (resolved_lhs.ResolvePath()) 405254721Semaste { 406254721Semaste // This path wasn't resolved but now it is. Check if the resolved 407254721Semaste // directory is the same as our unresolved directory, and if so, 408254721Semaste // we can mark this object as resolved to avoid more future resolves 409254721Semaste m_is_resolved = (m_directory == resolved_lhs.m_directory); 410254721Semaste } 411254721Semaste else 412254721Semaste return false; 413254721Semaste } 414254721Semaste 415254721Semaste FileSpec resolved_rhs(rhs); 416254721Semaste if (!rhs.IsResolved()) 417254721Semaste { 418254721Semaste if (resolved_rhs.ResolvePath()) 419254721Semaste { 420254721Semaste // rhs's path wasn't resolved but now it is. Check if the resolved 421254721Semaste // directory is the same as rhs's unresolved directory, and if so, 422254721Semaste // we can mark this object as resolved to avoid more future resolves 423254721Semaste rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); 424254721Semaste } 425254721Semaste else 426254721Semaste return false; 427254721Semaste } 428254721Semaste 429254721Semaste // If we reach this point in the code we were able to resolve both paths 430254721Semaste // and since we only resolve the paths if the basenames are equal, then 431254721Semaste // we can just check if both directories are equal... 432254721Semaste return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory(); 433254721Semaste } 434254721Semaste return false; 435254721Semaste} 436254721Semaste 437254721Semaste//------------------------------------------------------------------ 438254721Semaste// Not equal to operator 439254721Semaste//------------------------------------------------------------------ 440254721Semastebool 441254721SemasteFileSpec::operator!= (const FileSpec& rhs) const 442254721Semaste{ 443254721Semaste return !(*this == rhs); 444254721Semaste} 445254721Semaste 446254721Semaste//------------------------------------------------------------------ 447254721Semaste// Less than operator 448254721Semaste//------------------------------------------------------------------ 449254721Semastebool 450254721SemasteFileSpec::operator< (const FileSpec& rhs) const 451254721Semaste{ 452254721Semaste return FileSpec::Compare(*this, rhs, true) < 0; 453254721Semaste} 454254721Semaste 455254721Semaste//------------------------------------------------------------------ 456254721Semaste// Dump a FileSpec object to a stream 457254721Semaste//------------------------------------------------------------------ 458254721SemasteStream& 459254721Semastelldb_private::operator << (Stream &s, const FileSpec& f) 460254721Semaste{ 461254721Semaste f.Dump(&s); 462254721Semaste return s; 463254721Semaste} 464254721Semaste 465254721Semaste//------------------------------------------------------------------ 466254721Semaste// Clear this object by releasing both the directory and filename 467254721Semaste// string values and making them both the empty string. 468254721Semaste//------------------------------------------------------------------ 469254721Semastevoid 470254721SemasteFileSpec::Clear() 471254721Semaste{ 472254721Semaste m_directory.Clear(); 473254721Semaste m_filename.Clear(); 474254721Semaste} 475254721Semaste 476254721Semaste//------------------------------------------------------------------ 477254721Semaste// Compare two FileSpec objects. If "full" is true, then both 478254721Semaste// the directory and the filename must match. If "full" is false, 479254721Semaste// then the directory names for "a" and "b" are only compared if 480254721Semaste// they are both non-empty. This allows a FileSpec object to only 481254721Semaste// contain a filename and it can match FileSpec objects that have 482254721Semaste// matching filenames with different paths. 483254721Semaste// 484254721Semaste// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" 485254721Semaste// and "1" if "a" is greater than "b". 486254721Semaste//------------------------------------------------------------------ 487254721Semasteint 488254721SemasteFileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) 489254721Semaste{ 490254721Semaste int result = 0; 491254721Semaste 492254721Semaste // If full is true, then we must compare both the directory and filename. 493254721Semaste 494254721Semaste // If full is false, then if either directory is empty, then we match on 495254721Semaste // the basename only, and if both directories have valid values, we still 496254721Semaste // do a full compare. This allows for matching when we just have a filename 497254721Semaste // in one of the FileSpec objects. 498254721Semaste 499254721Semaste if (full || (a.m_directory && b.m_directory)) 500254721Semaste { 501254721Semaste result = ConstString::Compare(a.m_directory, b.m_directory); 502254721Semaste if (result) 503254721Semaste return result; 504254721Semaste } 505254721Semaste return ConstString::Compare (a.m_filename, b.m_filename); 506254721Semaste} 507254721Semaste 508254721Semastebool 509254721SemasteFileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) 510254721Semaste{ 511254721Semaste if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) 512254721Semaste return a.m_filename == b.m_filename; 513254721Semaste else 514254721Semaste return a == b; 515254721Semaste} 516254721Semaste 517254721Semaste 518254721Semaste 519254721Semaste//------------------------------------------------------------------ 520254721Semaste// Dump the object to the supplied stream. If the object contains 521254721Semaste// a valid directory name, it will be displayed followed by a 522254721Semaste// directory delimiter, and the filename. 523254721Semaste//------------------------------------------------------------------ 524254721Semastevoid 525254721SemasteFileSpec::Dump(Stream *s) const 526254721Semaste{ 527254721Semaste static ConstString g_slash_only ("/"); 528254721Semaste if (s) 529254721Semaste { 530254721Semaste m_directory.Dump(s); 531254721Semaste if (m_directory && m_directory != g_slash_only) 532254721Semaste s->PutChar('/'); 533254721Semaste m_filename.Dump(s); 534254721Semaste } 535254721Semaste} 536254721Semaste 537254721Semaste//------------------------------------------------------------------ 538254721Semaste// Returns true if the file exists. 539254721Semaste//------------------------------------------------------------------ 540254721Semastebool 541254721SemasteFileSpec::Exists () const 542254721Semaste{ 543254721Semaste struct stat file_stats; 544254721Semaste return GetFileStats (this, &file_stats); 545254721Semaste} 546254721Semaste 547254721Semastebool 548254721SemasteFileSpec::ResolveExecutableLocation () 549254721Semaste{ 550254721Semaste if (!m_directory) 551254721Semaste { 552254721Semaste const char *file_cstr = m_filename.GetCString(); 553254721Semaste if (file_cstr) 554254721Semaste { 555254721Semaste const std::string file_str (file_cstr); 556254768Semaste llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str); 557254768Semaste const std::string &path_str = path.str(); 558254768Semaste llvm::StringRef dir_ref = llvm::sys::path::parent_path(path_str); 559254721Semaste //llvm::StringRef dir_ref = path.getDirname(); 560254721Semaste if (! dir_ref.empty()) 561254721Semaste { 562254721Semaste // FindProgramByName returns "." if it can't find the file. 563254721Semaste if (strcmp (".", dir_ref.data()) == 0) 564254721Semaste return false; 565254721Semaste 566254721Semaste m_directory.SetCString (dir_ref.data()); 567254721Semaste if (Exists()) 568254721Semaste return true; 569254721Semaste else 570254721Semaste { 571254721Semaste // If FindProgramByName found the file, it returns the directory + filename in its return results. 572254721Semaste // We need to separate them. 573254721Semaste FileSpec tmp_file (dir_ref.data(), false); 574254721Semaste if (tmp_file.Exists()) 575254721Semaste { 576254721Semaste m_directory = tmp_file.m_directory; 577254721Semaste return true; 578254721Semaste } 579254721Semaste } 580254721Semaste } 581254721Semaste } 582254721Semaste } 583254721Semaste 584254721Semaste return false; 585254721Semaste} 586254721Semaste 587254721Semastebool 588254721SemasteFileSpec::ResolvePath () 589254721Semaste{ 590254721Semaste if (m_is_resolved) 591254721Semaste return true; // We have already resolved this path 592254721Semaste 593254721Semaste char path_buf[PATH_MAX]; 594254721Semaste if (!GetPath (path_buf, PATH_MAX)) 595254721Semaste return false; 596254721Semaste // SetFile(...) will set m_is_resolved correctly if it can resolve the path 597254721Semaste SetFile (path_buf, true); 598254721Semaste return m_is_resolved; 599254721Semaste} 600254721Semaste 601254721Semasteuint64_t 602254721SemasteFileSpec::GetByteSize() const 603254721Semaste{ 604254721Semaste struct stat file_stats; 605254721Semaste if (GetFileStats (this, &file_stats)) 606254721Semaste return file_stats.st_size; 607254721Semaste return 0; 608254721Semaste} 609254721Semaste 610254721SemasteFileSpec::FileType 611254721SemasteFileSpec::GetFileType () const 612254721Semaste{ 613254721Semaste struct stat file_stats; 614254721Semaste if (GetFileStats (this, &file_stats)) 615254721Semaste { 616254721Semaste mode_t file_type = file_stats.st_mode & S_IFMT; 617254721Semaste switch (file_type) 618254721Semaste { 619254721Semaste case S_IFDIR: return eFileTypeDirectory; 620254721Semaste case S_IFIFO: return eFileTypePipe; 621254721Semaste case S_IFREG: return eFileTypeRegular; 622254721Semaste case S_IFSOCK: return eFileTypeSocket; 623254721Semaste case S_IFLNK: return eFileTypeSymbolicLink; 624254721Semaste default: 625254721Semaste break; 626254721Semaste } 627254721Semaste return eFileTypeUnknown; 628254721Semaste } 629254721Semaste return eFileTypeInvalid; 630254721Semaste} 631254721Semaste 632254721SemasteTimeValue 633254721SemasteFileSpec::GetModificationTime () const 634254721Semaste{ 635254721Semaste TimeValue mod_time; 636254721Semaste struct stat file_stats; 637254721Semaste if (GetFileStats (this, &file_stats)) 638254721Semaste mod_time.OffsetWithSeconds(file_stats.st_mtime); 639254721Semaste return mod_time; 640254721Semaste} 641254721Semaste 642254721Semaste//------------------------------------------------------------------ 643254721Semaste// Directory string get accessor. 644254721Semaste//------------------------------------------------------------------ 645254721SemasteConstString & 646254721SemasteFileSpec::GetDirectory() 647254721Semaste{ 648254721Semaste return m_directory; 649254721Semaste} 650254721Semaste 651254721Semaste//------------------------------------------------------------------ 652254721Semaste// Directory string const get accessor. 653254721Semaste//------------------------------------------------------------------ 654254721Semasteconst ConstString & 655254721SemasteFileSpec::GetDirectory() const 656254721Semaste{ 657254721Semaste return m_directory; 658254721Semaste} 659254721Semaste 660254721Semaste//------------------------------------------------------------------ 661254721Semaste// Filename string get accessor. 662254721Semaste//------------------------------------------------------------------ 663254721SemasteConstString & 664254721SemasteFileSpec::GetFilename() 665254721Semaste{ 666254721Semaste return m_filename; 667254721Semaste} 668254721Semaste 669254721Semaste//------------------------------------------------------------------ 670254721Semaste// Filename string const get accessor. 671254721Semaste//------------------------------------------------------------------ 672254721Semasteconst ConstString & 673254721SemasteFileSpec::GetFilename() const 674254721Semaste{ 675254721Semaste return m_filename; 676254721Semaste} 677254721Semaste 678254721Semaste//------------------------------------------------------------------ 679254721Semaste// Extract the directory and path into a fixed buffer. This is 680254721Semaste// needed as the directory and path are stored in separate string 681254721Semaste// values. 682254721Semaste//------------------------------------------------------------------ 683254721Semastesize_t 684254721SemasteFileSpec::GetPath(char *path, size_t path_max_len) const 685254721Semaste{ 686254721Semaste if (path_max_len) 687254721Semaste { 688254721Semaste const char *dirname = m_directory.GetCString(); 689254721Semaste const char *filename = m_filename.GetCString(); 690254721Semaste if (dirname) 691254721Semaste { 692254721Semaste if (filename) 693254721Semaste return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); 694254721Semaste else 695254721Semaste return ::snprintf (path, path_max_len, "%s", dirname); 696254721Semaste } 697254721Semaste else if (filename) 698254721Semaste { 699254721Semaste return ::snprintf (path, path_max_len, "%s", filename); 700254721Semaste } 701254721Semaste } 702254721Semaste if (path) 703254721Semaste path[0] = '\0'; 704254721Semaste return 0; 705254721Semaste} 706254721Semaste 707254721Semastestd::string 708254721SemasteFileSpec::GetPath (void) const 709254721Semaste{ 710254721Semaste static ConstString g_slash_only ("/"); 711254721Semaste std::string path; 712254721Semaste const char *dirname = m_directory.GetCString(); 713254721Semaste const char *filename = m_filename.GetCString(); 714254721Semaste if (dirname) 715254721Semaste { 716254721Semaste path.append (dirname); 717254721Semaste if (filename && m_directory != g_slash_only) 718254721Semaste path.append ("/"); 719254721Semaste } 720254721Semaste if (filename) 721254721Semaste path.append (filename); 722254721Semaste return path; 723254721Semaste} 724254721Semaste 725254721SemasteConstString 726254721SemasteFileSpec::GetFileNameExtension () const 727254721Semaste{ 728254721Semaste if (m_filename) 729254721Semaste { 730254721Semaste const char *filename = m_filename.GetCString(); 731254721Semaste const char* dot_pos = strrchr(filename, '.'); 732254721Semaste if (dot_pos && dot_pos[1] != '\0') 733254721Semaste return ConstString(dot_pos+1); 734254721Semaste } 735254721Semaste return ConstString(); 736254721Semaste} 737254721Semaste 738254721SemasteConstString 739254721SemasteFileSpec::GetFileNameStrippingExtension () const 740254721Semaste{ 741254721Semaste const char *filename = m_filename.GetCString(); 742254721Semaste if (filename == NULL) 743254721Semaste return ConstString(); 744254721Semaste 745254721Semaste const char* dot_pos = strrchr(filename, '.'); 746254721Semaste if (dot_pos == NULL) 747254721Semaste return m_filename; 748254721Semaste 749254721Semaste return ConstString(filename, dot_pos-filename); 750254721Semaste} 751254721Semaste 752254721Semaste//------------------------------------------------------------------ 753254721Semaste// Returns a shared pointer to a data buffer that contains all or 754254721Semaste// part of the contents of a file. The data is memory mapped and 755254721Semaste// will lazily page in data from the file as memory is accessed. 756254721Semaste// The data that is mappped will start "file_offset" bytes into the 757254721Semaste// file, and "file_size" bytes will be mapped. If "file_size" is 758254721Semaste// greater than the number of bytes available in the file starting 759254721Semaste// at "file_offset", the number of bytes will be appropriately 760254721Semaste// truncated. The final number of bytes that get mapped can be 761254721Semaste// verified using the DataBuffer::GetByteSize() function. 762254721Semaste//------------------------------------------------------------------ 763254721SemasteDataBufferSP 764254721SemasteFileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const 765254721Semaste{ 766254721Semaste DataBufferSP data_sp; 767254721Semaste std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); 768254721Semaste if (mmap_data.get()) 769254721Semaste { 770254721Semaste const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size); 771254721Semaste if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size)) 772254721Semaste data_sp.reset(mmap_data.release()); 773254721Semaste } 774254721Semaste return data_sp; 775254721Semaste} 776254721Semaste 777254721Semaste 778254721Semaste//------------------------------------------------------------------ 779254721Semaste// Return the size in bytes that this object takes in memory. This 780254721Semaste// returns the size in bytes of this object, not any shared string 781254721Semaste// values it may refer to. 782254721Semaste//------------------------------------------------------------------ 783254721Semastesize_t 784254721SemasteFileSpec::MemorySize() const 785254721Semaste{ 786254721Semaste return m_filename.MemorySize() + m_directory.MemorySize(); 787254721Semaste} 788254721Semaste 789254721Semaste 790254721Semastesize_t 791254721SemasteFileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const 792254721Semaste{ 793254721Semaste Error error; 794254721Semaste size_t bytes_read = 0; 795254721Semaste char resolved_path[PATH_MAX]; 796254721Semaste if (GetPath(resolved_path, sizeof(resolved_path))) 797254721Semaste { 798254721Semaste File file; 799254721Semaste error = file.Open(resolved_path, File::eOpenOptionRead); 800254721Semaste if (error.Success()) 801254721Semaste { 802254721Semaste off_t file_offset_after_seek = file_offset; 803254721Semaste bytes_read = dst_len; 804254721Semaste error = file.Read(dst, bytes_read, file_offset_after_seek); 805254721Semaste } 806254721Semaste } 807254721Semaste else 808254721Semaste { 809254721Semaste error.SetErrorString("invalid file specification"); 810254721Semaste } 811254721Semaste if (error_ptr) 812254721Semaste *error_ptr = error; 813254721Semaste return bytes_read; 814254721Semaste} 815254721Semaste 816254721Semaste//------------------------------------------------------------------ 817254721Semaste// Returns a shared pointer to a data buffer that contains all or 818254721Semaste// part of the contents of a file. The data copies into a heap based 819254721Semaste// buffer that lives in the DataBuffer shared pointer object returned. 820254721Semaste// The data that is cached will start "file_offset" bytes into the 821254721Semaste// file, and "file_size" bytes will be mapped. If "file_size" is 822254721Semaste// greater than the number of bytes available in the file starting 823254721Semaste// at "file_offset", the number of bytes will be appropriately 824254721Semaste// truncated. The final number of bytes that get mapped can be 825254721Semaste// verified using the DataBuffer::GetByteSize() function. 826254721Semaste//------------------------------------------------------------------ 827254721SemasteDataBufferSP 828254721SemasteFileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const 829254721Semaste{ 830254721Semaste Error error; 831254721Semaste DataBufferSP data_sp; 832254721Semaste char resolved_path[PATH_MAX]; 833254721Semaste if (GetPath(resolved_path, sizeof(resolved_path))) 834254721Semaste { 835254721Semaste File file; 836254721Semaste error = file.Open(resolved_path, File::eOpenOptionRead); 837254721Semaste if (error.Success()) 838254721Semaste { 839254721Semaste const bool null_terminate = false; 840254721Semaste error = file.Read (file_size, file_offset, null_terminate, data_sp); 841254721Semaste } 842254721Semaste } 843254721Semaste else 844254721Semaste { 845254721Semaste error.SetErrorString("invalid file specification"); 846254721Semaste } 847254721Semaste if (error_ptr) 848254721Semaste *error_ptr = error; 849254721Semaste return data_sp; 850254721Semaste} 851254721Semaste 852254721SemasteDataBufferSP 853254721SemasteFileSpec::ReadFileContentsAsCString(Error *error_ptr) 854254721Semaste{ 855254721Semaste Error error; 856254721Semaste DataBufferSP data_sp; 857254721Semaste char resolved_path[PATH_MAX]; 858254721Semaste if (GetPath(resolved_path, sizeof(resolved_path))) 859254721Semaste { 860254721Semaste File file; 861254721Semaste error = file.Open(resolved_path, File::eOpenOptionRead); 862254721Semaste if (error.Success()) 863254721Semaste { 864254721Semaste off_t offset = 0; 865254721Semaste size_t length = SIZE_MAX; 866254721Semaste const bool null_terminate = true; 867254721Semaste error = file.Read (length, offset, null_terminate, data_sp); 868254721Semaste } 869254721Semaste } 870254721Semaste else 871254721Semaste { 872254721Semaste error.SetErrorString("invalid file specification"); 873254721Semaste } 874254721Semaste if (error_ptr) 875254721Semaste *error_ptr = error; 876254721Semaste return data_sp; 877254721Semaste} 878254721Semaste 879254721Semastesize_t 880254721SemasteFileSpec::ReadFileLines (STLStringArray &lines) 881254721Semaste{ 882254721Semaste lines.clear(); 883254721Semaste char path[PATH_MAX]; 884254721Semaste if (GetPath(path, sizeof(path))) 885254721Semaste { 886254721Semaste std::ifstream file_stream (path); 887254721Semaste 888254721Semaste if (file_stream) 889254721Semaste { 890254721Semaste std::string line; 891254721Semaste while (getline (file_stream, line)) 892254721Semaste lines.push_back (line); 893254721Semaste } 894254721Semaste } 895254721Semaste return lines.size(); 896254721Semaste} 897254721Semaste 898254721SemasteFileSpec::EnumerateDirectoryResult 899254721SemasteFileSpec::EnumerateDirectory 900254721Semaste( 901254721Semaste const char *dir_path, 902254721Semaste bool find_directories, 903254721Semaste bool find_files, 904254721Semaste bool find_other, 905254721Semaste EnumerateDirectoryCallbackType callback, 906254721Semaste void *callback_baton 907254721Semaste) 908254721Semaste{ 909254721Semaste if (dir_path && dir_path[0]) 910254721Semaste { 911254721Semaste lldb_utility::CleanUp <DIR *, int> dir_path_dir (opendir(dir_path), NULL, closedir); 912254721Semaste if (dir_path_dir.is_valid()) 913254721Semaste { 914254721Semaste long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX); 915254721Semaste#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN) 916254721Semaste if (path_max < __DARWIN_MAXPATHLEN) 917254721Semaste path_max = __DARWIN_MAXPATHLEN; 918254721Semaste#endif 919254721Semaste struct dirent *buf, *dp; 920254721Semaste buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1); 921254721Semaste 922254721Semaste while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) 923254721Semaste { 924254721Semaste // Only search directories 925254721Semaste if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) 926254721Semaste { 927254721Semaste size_t len = strlen(dp->d_name); 928254721Semaste 929254721Semaste if (len == 1 && dp->d_name[0] == '.') 930254721Semaste continue; 931254721Semaste 932254721Semaste if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') 933254721Semaste continue; 934254721Semaste } 935254721Semaste 936254721Semaste bool call_callback = false; 937254721Semaste FileSpec::FileType file_type = eFileTypeUnknown; 938254721Semaste 939254721Semaste switch (dp->d_type) 940254721Semaste { 941254721Semaste default: 942254721Semaste case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break; 943254721Semaste case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break; 944254721Semaste case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break; 945254721Semaste case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break; 946254721Semaste case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break; 947254721Semaste case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break; 948254721Semaste case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break; 949254721Semaste case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break; 950254721Semaste#if !defined(__OpenBSD__) 951254721Semaste case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break; 952254721Semaste#endif 953254721Semaste } 954254721Semaste 955254721Semaste if (call_callback) 956254721Semaste { 957254721Semaste char child_path[PATH_MAX]; 958254721Semaste const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); 959254721Semaste if (child_path_len < (int)(sizeof(child_path) - 1)) 960254721Semaste { 961254721Semaste // Don't resolve the file type or path 962254721Semaste FileSpec child_path_spec (child_path, false); 963254721Semaste 964254721Semaste EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec); 965254721Semaste 966254721Semaste switch (result) 967254721Semaste { 968254721Semaste case eEnumerateDirectoryResultNext: 969254721Semaste // Enumerate next entry in the current directory. We just 970254721Semaste // exit this switch and will continue enumerating the 971254721Semaste // current directory as we currently are... 972254721Semaste break; 973254721Semaste 974254721Semaste case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not 975254721Semaste if (FileSpec::EnumerateDirectory (child_path, 976254721Semaste find_directories, 977254721Semaste find_files, 978254721Semaste find_other, 979254721Semaste callback, 980254721Semaste callback_baton) == eEnumerateDirectoryResultQuit) 981254721Semaste { 982254721Semaste // The subdirectory returned Quit, which means to 983254721Semaste // stop all directory enumerations at all levels. 984254721Semaste if (buf) 985254721Semaste free (buf); 986254721Semaste return eEnumerateDirectoryResultQuit; 987254721Semaste } 988254721Semaste break; 989254721Semaste 990254721Semaste case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. 991254721Semaste // Exit from this directory level and tell parent to 992254721Semaste // keep enumerating. 993254721Semaste if (buf) 994254721Semaste free (buf); 995254721Semaste return eEnumerateDirectoryResultNext; 996254721Semaste 997254721Semaste case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level 998254721Semaste if (buf) 999254721Semaste free (buf); 1000254721Semaste return eEnumerateDirectoryResultQuit; 1001254721Semaste } 1002254721Semaste } 1003254721Semaste } 1004254721Semaste } 1005254721Semaste if (buf) 1006254721Semaste { 1007254721Semaste free (buf); 1008254721Semaste } 1009254721Semaste } 1010254721Semaste } 1011254721Semaste // By default when exiting a directory, we tell the parent enumeration 1012254721Semaste // to continue enumerating. 1013254721Semaste return eEnumerateDirectoryResultNext; 1014254721Semaste} 1015254721Semaste 1016254721Semaste//------------------------------------------------------------------ 1017254721Semaste/// Returns true if the filespec represents an implementation source 1018254721Semaste/// file (files with a ".c", ".cpp", ".m", ".mm" (many more) 1019254721Semaste/// extension). 1020254721Semaste/// 1021254721Semaste/// @return 1022254721Semaste/// \b true if the filespec represents an implementation source 1023254721Semaste/// file, \b false otherwise. 1024254721Semaste//------------------------------------------------------------------ 1025254721Semastebool 1026254721SemasteFileSpec::IsSourceImplementationFile () const 1027254721Semaste{ 1028254721Semaste ConstString extension (GetFileNameExtension()); 1029254721Semaste if (extension) 1030254721Semaste { 1031254721Semaste static RegularExpression g_source_file_regex ("^(c|m|mm|cpp|c\\+\\+|cxx|cc|cp|s|asm|f|f77|f90|f95|f03|for|ftn|fpp|ada|adb|ads)$", 1032254721Semaste REG_EXTENDED | REG_ICASE); 1033254721Semaste return g_source_file_regex.Execute (extension.GetCString()); 1034254721Semaste } 1035254721Semaste return false; 1036254721Semaste} 1037254721Semaste 1038254721Semastebool 1039254721SemasteFileSpec::IsRelativeToCurrentWorkingDirectory () const 1040254721Semaste{ 1041254721Semaste const char *directory = m_directory.GetCString(); 1042254721Semaste if (directory && directory[0]) 1043254721Semaste { 1044254721Semaste // If the path doesn't start with '/' or '~', return true 1045254721Semaste switch (directory[0]) 1046254721Semaste { 1047254721Semaste case '/': 1048254721Semaste case '~': 1049254721Semaste return false; 1050254721Semaste default: 1051254721Semaste return true; 1052254721Semaste } 1053254721Semaste } 1054254721Semaste else if (m_filename) 1055254721Semaste { 1056254721Semaste // No directory, just a basename, return true 1057254721Semaste return true; 1058254721Semaste } 1059254721Semaste return false; 1060254721Semaste} 1061