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