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