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