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