FileSpec.cpp revision 683cb6970b55100f0f3aa9501b0c0ee8358a9c8c
1//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10 11#include <dirent.h> 12#include <fcntl.h> 13#include <libgen.h> 14#include <sys/stat.h> 15#include <string.h> 16#include <fstream> 17 18#include "lldb/Host/Config.h" // Have to include this before we test the define... 19#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 20#include <pwd.h> 21#endif 22 23#include "llvm/ADT/StringRef.h" 24#include "llvm/Support/Path.h" 25#include "llvm/Support/Program.h" 26 27#include "lldb/Host/File.h" 28#include "lldb/Host/FileSpec.h" 29#include "lldb/Core/DataBufferHeap.h" 30#include "lldb/Core/DataBufferMemoryMap.h" 31#include "lldb/Core/RegularExpression.h" 32#include "lldb/Core/Stream.h" 33#include "lldb/Host/Host.h" 34#include "lldb/Utility/CleanUp.h" 35 36using namespace lldb; 37using namespace lldb_private; 38 39static bool 40GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) 41{ 42 char resolved_path[PATH_MAX]; 43 if (file_spec->GetPath (resolved_path, sizeof(resolved_path))) 44 return ::stat (resolved_path, stats_ptr) == 0; 45 return false; 46} 47 48#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 49 50static const char* 51GetCachedGlobTildeSlash() 52{ 53 static std::string g_tilde; 54 if (g_tilde.empty()) 55 { 56 struct passwd *user_entry; 57 user_entry = getpwuid(geteuid()); 58 if (user_entry != NULL) 59 g_tilde = user_entry->pw_dir; 60 61 if (g_tilde.empty()) 62 return NULL; 63 } 64 return g_tilde.c_str(); 65} 66 67#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 68 69// Resolves the username part of a path of the form ~user/other/directories, and 70// writes the result into dst_path. 71// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. 72// Otherwise returns the number of characters copied into dst_path. If the return 73// is >= dst_len, then the resolved path is too long... 74size_t 75FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) 76{ 77 if (src_path == NULL || src_path[0] == '\0') 78 return 0; 79 80#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 81 82 char user_home[PATH_MAX]; 83 const char *user_name; 84 85 86 // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) 87 if (src_path[0] != '~') 88 { 89 size_t len = strlen (src_path); 90 if (len >= dst_len) 91 { 92 ::bcopy (src_path, dst_path, dst_len - 1); 93 dst_path[dst_len] = '\0'; 94 } 95 else 96 ::bcopy (src_path, dst_path, len + 1); 97 98 return len; 99 } 100 101 const char *first_slash = ::strchr (src_path, '/'); 102 char remainder[PATH_MAX]; 103 104 if (first_slash == NULL) 105 { 106 // The whole name is the username (minus the ~): 107 user_name = src_path + 1; 108 remainder[0] = '\0'; 109 } 110 else 111 { 112 size_t user_name_len = first_slash - src_path - 1; 113 ::memcpy (user_home, src_path + 1, user_name_len); 114 user_home[user_name_len] = '\0'; 115 user_name = user_home; 116 117 ::strcpy (remainder, first_slash); 118 } 119 120 if (user_name == NULL) 121 return 0; 122 // User name of "" means the current user... 123 124 struct passwd *user_entry; 125 const char *home_dir = NULL; 126 127 if (user_name[0] == '\0') 128 { 129 home_dir = GetCachedGlobTildeSlash(); 130 } 131 else 132 { 133 user_entry = ::getpwnam (user_name); 134 if (user_entry != NULL) 135 home_dir = user_entry->pw_dir; 136 } 137 138 if (home_dir == NULL) 139 return 0; 140 else 141 return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); 142#else 143 // Resolving home directories is not supported, just copy the path... 144 return ::snprintf (dst_path, dst_len, "%s", src_path); 145#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 146} 147 148size_t 149FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) 150{ 151#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 152 size_t extant_entries = matches.GetSize(); 153 154 setpwent(); 155 struct passwd *user_entry; 156 const char *name_start = partial_name + 1; 157 std::set<std::string> name_list; 158 159 while ((user_entry = getpwent()) != NULL) 160 { 161 if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name) 162 { 163 std::string tmp_buf("~"); 164 tmp_buf.append(user_entry->pw_name); 165 tmp_buf.push_back('/'); 166 name_list.insert(tmp_buf); 167 } 168 } 169 std::set<std::string>::iterator pos, end = name_list.end(); 170 for (pos = name_list.begin(); pos != end; pos++) 171 { 172 matches.AppendString((*pos).c_str()); 173 } 174 return matches.GetSize() - extant_entries; 175#else 176 // Resolving home directories is not supported, just copy the path... 177 return 0; 178#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 179} 180 181 182 183size_t 184FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) 185{ 186 if (src_path == NULL || src_path[0] == '\0') 187 return 0; 188 189 // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... 190 char unglobbed_path[PATH_MAX]; 191#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 192 if (src_path[0] == '~') 193 { 194 size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); 195 196 // If we couldn't find the user referred to, or the resultant path was too long, 197 // then just copy over the src_path. 198 if (return_count == 0 || return_count >= sizeof(unglobbed_path)) 199 ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 200 } 201 else 202#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER 203 { 204 ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 205 } 206 207 // Now resolve the path if needed 208 char resolved_path[PATH_MAX]; 209 if (::realpath (unglobbed_path, resolved_path)) 210 { 211 // Success, copy the resolved path 212 return ::snprintf(dst_path, dst_len, "%s", resolved_path); 213 } 214 else 215 { 216 // Failed, just copy the unglobbed path 217 return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); 218 } 219} 220 221FileSpec::FileSpec() : 222 m_directory(), 223 m_filename() 224{ 225} 226 227//------------------------------------------------------------------ 228// Default constructor that can take an optional full path to a 229// file on disk. 230//------------------------------------------------------------------ 231FileSpec::FileSpec(const char *pathname, bool resolve_path) : 232 m_directory(), 233 m_filename(), 234 m_is_resolved(false) 235{ 236 if (pathname && pathname[0]) 237 SetFile(pathname, resolve_path); 238} 239 240//------------------------------------------------------------------ 241// Copy constructor 242//------------------------------------------------------------------ 243FileSpec::FileSpec(const FileSpec& rhs) : 244 m_directory (rhs.m_directory), 245 m_filename (rhs.m_filename), 246 m_is_resolved (rhs.m_is_resolved) 247{ 248} 249 250//------------------------------------------------------------------ 251// Copy constructor 252//------------------------------------------------------------------ 253FileSpec::FileSpec(const FileSpec* rhs) : 254 m_directory(), 255 m_filename() 256{ 257 if (rhs) 258 *this = *rhs; 259} 260 261//------------------------------------------------------------------ 262// Virtual destrcuctor in case anyone inherits from this class. 263//------------------------------------------------------------------ 264FileSpec::~FileSpec() 265{ 266} 267 268//------------------------------------------------------------------ 269// Assignment operator. 270//------------------------------------------------------------------ 271const FileSpec& 272FileSpec::operator= (const FileSpec& rhs) 273{ 274 if (this != &rhs) 275 { 276 m_directory = rhs.m_directory; 277 m_filename = rhs.m_filename; 278 m_is_resolved = rhs.m_is_resolved; 279 } 280 return *this; 281} 282 283//------------------------------------------------------------------ 284// Update the contents of this object with a new path. The path will 285// be split up into a directory and filename and stored as uniqued 286// string values for quick comparison and efficient memory usage. 287//------------------------------------------------------------------ 288void 289FileSpec::SetFile (const char *pathname, bool resolve) 290{ 291 m_filename.Clear(); 292 m_directory.Clear(); 293 m_is_resolved = false; 294 if (pathname == NULL || pathname[0] == '\0') 295 return; 296 297 char resolved_path[PATH_MAX]; 298 bool path_fit = true; 299 300 if (resolve) 301 { 302 path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); 303 m_is_resolved = path_fit; 304 } 305 else 306 { 307 // Copy the path because "basename" and "dirname" want to muck with the 308 // path buffer 309 if (::strlen (pathname) > sizeof(resolved_path) - 1) 310 path_fit = false; 311 else 312 ::strcpy (resolved_path, pathname); 313 } 314 315 316 if (path_fit) 317 { 318 char *filename = ::basename (resolved_path); 319 if (filename) 320 { 321 m_filename.SetCString (filename); 322 // Truncate the basename off the end of the resolved path 323 324 // Only attempt to get the dirname if it looks like we have a path 325 if (strchr(resolved_path, '/')) 326 { 327 char *directory = ::dirname (resolved_path); 328 329 // Make sure we didn't get our directory resolved to "." without having 330 // specified 331 if (directory) 332 m_directory.SetCString(directory); 333 else 334 { 335 char *last_resolved_path_slash = strrchr(resolved_path, '/'); 336 if (last_resolved_path_slash) 337 { 338 *last_resolved_path_slash = '\0'; 339 m_directory.SetCString(resolved_path); 340 } 341 } 342 } 343 } 344 else 345 m_directory.SetCString(resolved_path); 346 } 347} 348 349//---------------------------------------------------------------------- 350// Convert to pointer operator. This allows code to check any FileSpec 351// objects to see if they contain anything valid using code such as: 352// 353// if (file_spec) 354// {} 355//---------------------------------------------------------------------- 356FileSpec::operator bool() const 357{ 358 return m_filename || m_directory; 359} 360 361//---------------------------------------------------------------------- 362// Logical NOT operator. This allows code to check any FileSpec 363// objects to see if they are invalid using code such as: 364// 365// if (!file_spec) 366// {} 367//---------------------------------------------------------------------- 368bool 369FileSpec::operator!() const 370{ 371 return !m_directory && !m_filename; 372} 373 374//------------------------------------------------------------------ 375// Equal to operator 376//------------------------------------------------------------------ 377bool 378FileSpec::operator== (const FileSpec& rhs) const 379{ 380 if (m_filename == rhs.m_filename) 381 { 382 if (m_directory == rhs.m_directory) 383 return true; 384 385 // TODO: determine if we want to keep this code in here. 386 // The code below was added to handle a case where we were 387 // trying to set a file and line breakpoint and one path 388 // was resolved, and the other not and the directory was 389 // in a mount point that resolved to a more complete path: 390 // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling 391 // this out... 392 if (IsResolved() && rhs.IsResolved()) 393 { 394 // Both paths are resolved, no need to look further... 395 return false; 396 } 397 398 FileSpec resolved_lhs(*this); 399 400 // If "this" isn't resolved, resolve it 401 if (!IsResolved()) 402 { 403 if (resolved_lhs.ResolvePath()) 404 { 405 // This path wasn't resolved but now it is. Check if the resolved 406 // directory is the same as our unresolved directory, and if so, 407 // we can mark this object as resolved to avoid more future resolves 408 m_is_resolved = (m_directory == resolved_lhs.m_directory); 409 } 410 else 411 return false; 412 } 413 414 FileSpec resolved_rhs(rhs); 415 if (!rhs.IsResolved()) 416 { 417 if (resolved_rhs.ResolvePath()) 418 { 419 // rhs's path wasn't resolved but now it is. Check if the resolved 420 // directory is the same as rhs's unresolved directory, and if so, 421 // we can mark this object as resolved to avoid more future resolves 422 rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); 423 } 424 else 425 return false; 426 } 427 428 // If we reach this point in the code we were able to resolve both paths 429 // and since we only resolve the paths if the basenames are equal, then 430 // we can just check if both directories are equal... 431 return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory(); 432 } 433 return false; 434} 435 436//------------------------------------------------------------------ 437// Not equal to operator 438//------------------------------------------------------------------ 439bool 440FileSpec::operator!= (const FileSpec& rhs) const 441{ 442 return !(*this == rhs); 443} 444 445//------------------------------------------------------------------ 446// Less than operator 447//------------------------------------------------------------------ 448bool 449FileSpec::operator< (const FileSpec& rhs) const 450{ 451 return FileSpec::Compare(*this, rhs, true) < 0; 452} 453 454//------------------------------------------------------------------ 455// Dump a FileSpec object to a stream 456//------------------------------------------------------------------ 457Stream& 458lldb_private::operator << (Stream &s, const FileSpec& f) 459{ 460 f.Dump(&s); 461 return s; 462} 463 464//------------------------------------------------------------------ 465// Clear this object by releasing both the directory and filename 466// string values and making them both the empty string. 467//------------------------------------------------------------------ 468void 469FileSpec::Clear() 470{ 471 m_directory.Clear(); 472 m_filename.Clear(); 473} 474 475//------------------------------------------------------------------ 476// Compare two FileSpec objects. If "full" is true, then both 477// the directory and the filename must match. If "full" is false, 478// then the directory names for "a" and "b" are only compared if 479// they are both non-empty. This allows a FileSpec object to only 480// contain a filename and it can match FileSpec objects that have 481// matching filenames with different paths. 482// 483// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" 484// and "1" if "a" is greater than "b". 485//------------------------------------------------------------------ 486int 487FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) 488{ 489 int result = 0; 490 491 // If full is true, then we must compare both the directory and filename. 492 493 // If full is false, then if either directory is empty, then we match on 494 // the basename only, and if both directories have valid values, we still 495 // do a full compare. This allows for matching when we just have a filename 496 // in one of the FileSpec objects. 497 498 if (full || (a.m_directory && b.m_directory)) 499 { 500 result = ConstString::Compare(a.m_directory, b.m_directory); 501 if (result) 502 return result; 503 } 504 return ConstString::Compare (a.m_filename, b.m_filename); 505} 506 507bool 508FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) 509{ 510 if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) 511 return a.m_filename == b.m_filename; 512 else 513 return a == b; 514} 515 516 517 518//------------------------------------------------------------------ 519// Dump the object to the supplied stream. If the object contains 520// a valid directory name, it will be displayed followed by a 521// directory delimiter, and the filename. 522//------------------------------------------------------------------ 523void 524FileSpec::Dump(Stream *s) const 525{ 526 if (s) 527 { 528 m_directory.Dump(s); 529 if (m_directory) 530 s->PutChar('/'); 531 m_filename.Dump(s); 532 } 533} 534 535//------------------------------------------------------------------ 536// Returns true if the file exists. 537//------------------------------------------------------------------ 538bool 539FileSpec::Exists () const 540{ 541 struct stat file_stats; 542 return GetFileStats (this, &file_stats); 543} 544 545bool 546FileSpec::ResolveExecutableLocation () 547{ 548 if (!m_directory) 549 { 550 const char *file_cstr = m_filename.GetCString(); 551 if (file_cstr) 552 { 553 const std::string file_str (file_cstr); 554 llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str); 555 const std::string &path_str = path.str(); 556 llvm::StringRef dir_ref = llvm::sys::path::parent_path(path_str); 557 //llvm::StringRef dir_ref = path.getDirname(); 558 if (! dir_ref.empty()) 559 { 560 // FindProgramByName returns "." if it can't find the file. 561 if (strcmp (".", dir_ref.data()) == 0) 562 return false; 563 564 m_directory.SetCString (dir_ref.data()); 565 if (Exists()) 566 return true; 567 else 568 { 569 // If FindProgramByName found the file, it returns the directory + filename in its return results. 570 // We need to separate them. 571 FileSpec tmp_file (dir_ref.data(), false); 572 if (tmp_file.Exists()) 573 { 574 m_directory = tmp_file.m_directory; 575 return true; 576 } 577 } 578 } 579 } 580 } 581 582 return false; 583} 584 585bool 586FileSpec::ResolvePath () 587{ 588 if (m_is_resolved) 589 return true; // We have already resolved this path 590 591 char path_buf[PATH_MAX]; 592 if (!GetPath (path_buf, PATH_MAX)) 593 return false; 594 // SetFile(...) will set m_is_resolved correctly if it can resolve the path 595 SetFile (path_buf, true); 596 return m_is_resolved; 597} 598 599uint64_t 600FileSpec::GetByteSize() const 601{ 602 struct stat file_stats; 603 if (GetFileStats (this, &file_stats)) 604 return file_stats.st_size; 605 return 0; 606} 607 608FileSpec::FileType 609FileSpec::GetFileType () const 610{ 611 struct stat file_stats; 612 if (GetFileStats (this, &file_stats)) 613 { 614 mode_t file_type = file_stats.st_mode & S_IFMT; 615 switch (file_type) 616 { 617 case S_IFDIR: return eFileTypeDirectory; 618 case S_IFIFO: return eFileTypePipe; 619 case S_IFREG: return eFileTypeRegular; 620 case S_IFSOCK: return eFileTypeSocket; 621 case S_IFLNK: return eFileTypeSymbolicLink; 622 default: 623 break; 624 } 625 return eFileTypeUnknown; 626 } 627 return eFileTypeInvalid; 628} 629 630TimeValue 631FileSpec::GetModificationTime () const 632{ 633 TimeValue mod_time; 634 struct stat file_stats; 635 if (GetFileStats (this, &file_stats)) 636 mod_time.OffsetWithSeconds(file_stats.st_mtime); 637 return mod_time; 638} 639 640//------------------------------------------------------------------ 641// Directory string get accessor. 642//------------------------------------------------------------------ 643ConstString & 644FileSpec::GetDirectory() 645{ 646 return m_directory; 647} 648 649//------------------------------------------------------------------ 650// Directory string const get accessor. 651//------------------------------------------------------------------ 652const ConstString & 653FileSpec::GetDirectory() const 654{ 655 return m_directory; 656} 657 658//------------------------------------------------------------------ 659// Filename string get accessor. 660//------------------------------------------------------------------ 661ConstString & 662FileSpec::GetFilename() 663{ 664 return m_filename; 665} 666 667//------------------------------------------------------------------ 668// Filename string const get accessor. 669//------------------------------------------------------------------ 670const ConstString & 671FileSpec::GetFilename() const 672{ 673 return m_filename; 674} 675 676//------------------------------------------------------------------ 677// Extract the directory and path into a fixed buffer. This is 678// needed as the directory and path are stored in separate string 679// values. 680//------------------------------------------------------------------ 681size_t 682FileSpec::GetPath(char *path, size_t path_max_len) const 683{ 684 if (path_max_len) 685 { 686 const char *dirname = m_directory.GetCString(); 687 const char *filename = m_filename.GetCString(); 688 if (dirname) 689 { 690 if (filename) 691 return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); 692 else 693 return ::snprintf (path, path_max_len, "%s", dirname); 694 } 695 else if (filename) 696 { 697 return ::snprintf (path, path_max_len, "%s", filename); 698 } 699 } 700 if (path) 701 path[0] = '\0'; 702 return 0; 703} 704 705ConstString 706FileSpec::GetFileNameExtension () const 707{ 708 if (m_filename) 709 { 710 const char *filename = m_filename.GetCString(); 711 const char* dot_pos = strrchr(filename, '.'); 712 if (dot_pos && dot_pos[1] != '\0') 713 return ConstString(dot_pos+1); 714 } 715 return ConstString(); 716} 717 718ConstString 719FileSpec::GetFileNameStrippingExtension () const 720{ 721 const char *filename = m_filename.GetCString(); 722 if (filename == NULL) 723 return ConstString(); 724 725 const char* dot_pos = strrchr(filename, '.'); 726 if (dot_pos == NULL) 727 return m_filename; 728 729 return ConstString(filename, dot_pos-filename); 730} 731 732//------------------------------------------------------------------ 733// Returns a shared pointer to a data buffer that contains all or 734// part of the contents of a file. The data is memory mapped and 735// will lazily page in data from the file as memory is accessed. 736// The data that is mappped will start "file_offset" bytes into the 737// file, and "file_size" bytes will be mapped. If "file_size" is 738// greater than the number of bytes available in the file starting 739// at "file_offset", the number of bytes will be appropriately 740// truncated. The final number of bytes that get mapped can be 741// verified using the DataBuffer::GetByteSize() function. 742//------------------------------------------------------------------ 743DataBufferSP 744FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const 745{ 746 DataBufferSP data_sp; 747 std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); 748 if (mmap_data.get()) 749 { 750 const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size); 751 if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size)) 752 data_sp.reset(mmap_data.release()); 753 } 754 return data_sp; 755} 756 757 758//------------------------------------------------------------------ 759// Return the size in bytes that this object takes in memory. This 760// returns the size in bytes of this object, not any shared string 761// values it may refer to. 762//------------------------------------------------------------------ 763size_t 764FileSpec::MemorySize() const 765{ 766 return m_filename.MemorySize() + m_directory.MemorySize(); 767} 768 769 770size_t 771FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const 772{ 773 Error error; 774 size_t bytes_read = 0; 775 char resolved_path[PATH_MAX]; 776 if (GetPath(resolved_path, sizeof(resolved_path))) 777 { 778 File file; 779 error = file.Open(resolved_path, File::eOpenOptionRead); 780 if (error.Success()) 781 { 782 off_t file_offset_after_seek = file_offset; 783 bytes_read = dst_len; 784 error = file.Read(dst, bytes_read, file_offset_after_seek); 785 } 786 } 787 else 788 { 789 error.SetErrorString("invalid file specification"); 790 } 791 if (error_ptr) 792 *error_ptr = error; 793 return bytes_read; 794} 795 796//------------------------------------------------------------------ 797// Returns a shared pointer to a data buffer that contains all or 798// part of the contents of a file. The data copies into a heap based 799// buffer that lives in the DataBuffer shared pointer object returned. 800// The data that is cached will start "file_offset" bytes into the 801// file, and "file_size" bytes will be mapped. If "file_size" is 802// greater than the number of bytes available in the file starting 803// at "file_offset", the number of bytes will be appropriately 804// truncated. The final number of bytes that get mapped can be 805// verified using the DataBuffer::GetByteSize() function. 806//------------------------------------------------------------------ 807DataBufferSP 808FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const 809{ 810 Error error; 811 DataBufferSP data_sp; 812 char resolved_path[PATH_MAX]; 813 if (GetPath(resolved_path, sizeof(resolved_path))) 814 { 815 File file; 816 error = file.Open(resolved_path, File::eOpenOptionRead); 817 if (error.Success()) 818 { 819 const bool null_terminate = false; 820 error = file.Read (file_size, file_offset, null_terminate, data_sp); 821 } 822 } 823 else 824 { 825 error.SetErrorString("invalid file specification"); 826 } 827 if (error_ptr) 828 *error_ptr = error; 829 return data_sp; 830} 831 832DataBufferSP 833FileSpec::ReadFileContentsAsCString(Error *error_ptr) 834{ 835 Error error; 836 DataBufferSP data_sp; 837 char resolved_path[PATH_MAX]; 838 if (GetPath(resolved_path, sizeof(resolved_path))) 839 { 840 File file; 841 error = file.Open(resolved_path, File::eOpenOptionRead); 842 if (error.Success()) 843 { 844 off_t offset = 0; 845 size_t length = SIZE_MAX; 846 const bool null_terminate = true; 847 error = file.Read (length, offset, null_terminate, data_sp); 848 } 849 } 850 else 851 { 852 error.SetErrorString("invalid file specification"); 853 } 854 if (error_ptr) 855 *error_ptr = error; 856 return data_sp; 857} 858 859size_t 860FileSpec::ReadFileLines (STLStringArray &lines) 861{ 862 lines.clear(); 863 char path[PATH_MAX]; 864 if (GetPath(path, sizeof(path))) 865 { 866 std::ifstream file_stream (path); 867 868 if (file_stream) 869 { 870 std::string line; 871 while (getline (file_stream, line)) 872 lines.push_back (line); 873 } 874 } 875 return lines.size(); 876} 877 878FileSpec::EnumerateDirectoryResult 879FileSpec::EnumerateDirectory 880( 881 const char *dir_path, 882 bool find_directories, 883 bool find_files, 884 bool find_other, 885 EnumerateDirectoryCallbackType callback, 886 void *callback_baton 887) 888{ 889 if (dir_path && dir_path[0]) 890 { 891 lldb_utility::CleanUp <DIR *, int> dir_path_dir (opendir(dir_path), NULL, closedir); 892 if (dir_path_dir.is_valid()) 893 { 894 long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX); 895#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN) 896 if (path_max < __DARWIN_MAXPATHLEN) 897 path_max = __DARWIN_MAXPATHLEN; 898#endif 899 struct dirent *buf, *dp; 900 buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1); 901 902 while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) 903 { 904 // Only search directories 905 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) 906 { 907 size_t len = strlen(dp->d_name); 908 909 if (len == 1 && dp->d_name[0] == '.') 910 continue; 911 912 if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') 913 continue; 914 } 915 916 bool call_callback = false; 917 FileSpec::FileType file_type = eFileTypeUnknown; 918 919 switch (dp->d_type) 920 { 921 default: 922 case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break; 923 case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break; 924 case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break; 925 case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break; 926 case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break; 927 case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break; 928 case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break; 929 case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break; 930#if !defined(__OpenBSD__) 931 case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break; 932#endif 933 } 934 935 if (call_callback) 936 { 937 char child_path[PATH_MAX]; 938 const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); 939 if (child_path_len < (int)(sizeof(child_path) - 1)) 940 { 941 // Don't resolve the file type or path 942 FileSpec child_path_spec (child_path, false); 943 944 EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec); 945 946 switch (result) 947 { 948 case eEnumerateDirectoryResultNext: 949 // Enumerate next entry in the current directory. We just 950 // exit this switch and will continue enumerating the 951 // current directory as we currently are... 952 break; 953 954 case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not 955 if (FileSpec::EnumerateDirectory (child_path, 956 find_directories, 957 find_files, 958 find_other, 959 callback, 960 callback_baton) == eEnumerateDirectoryResultQuit) 961 { 962 // The subdirectory returned Quit, which means to 963 // stop all directory enumerations at all levels. 964 return eEnumerateDirectoryResultQuit; 965 } 966 break; 967 968 case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. 969 // Exit from this directory level and tell parent to 970 // keep enumerating. 971 return eEnumerateDirectoryResultNext; 972 973 case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level 974 return eEnumerateDirectoryResultQuit; 975 } 976 } 977 } 978 } 979 if (buf) 980 { 981 free (buf); 982 } 983 } 984 } 985 // By default when exiting a directory, we tell the parent enumeration 986 // to continue enumerating. 987 return eEnumerateDirectoryResultNext; 988} 989 990//------------------------------------------------------------------ 991/// Returns true if the filespec represents an implementation source 992/// file (files with a ".c", ".cpp", ".m", ".mm" (many more) 993/// extension). 994/// 995/// @return 996/// \b true if the filespec represents an implementation source 997/// file, \b false otherwise. 998//------------------------------------------------------------------ 999bool 1000FileSpec::IsSourceImplementationFile () const 1001{ 1002 ConstString extension (GetFileNameExtension()); 1003 if (extension) 1004 { 1005 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)$", 1006 REG_EXTENDED | REG_ICASE); 1007 return g_source_file_regex.Execute (extension.GetCString()); 1008 } 1009 return false; 1010} 1011 1012bool 1013FileSpec::IsRelativeToCurrentWorkingDirectory () const 1014{ 1015 const char *directory = m_directory.GetCString(); 1016 if (directory && directory[0]) 1017 { 1018 // If the path doesn't start with '/' or '~', return true 1019 switch (directory[0]) 1020 { 1021 case '/': 1022 case '~': 1023 return false; 1024 default: 1025 return true; 1026 } 1027 } 1028 else if (m_filename) 1029 { 1030 // No directory, just a basename, return true 1031 return true; 1032 } 1033 return false; 1034} 1035 1036 1037