FileSpec.cpp revision c4547c59f2e8390bdbf92484c851be06395b8e77
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 <fcntl.h> 12#include <libgen.h> 13#include <stdlib.h> 14#include <sys/param.h> 15#include <sys/stat.h> 16#include <sys/types.h> 17#include <pwd.h> 18 19#include <fstream> 20 21#include "llvm/ADT/StringRef.h" 22#include "llvm/System/Path.h" 23#include "llvm/System/Program.h" 24 25#include "lldb/Core/FileSpec.h" 26#include "lldb/Core/DataBufferHeap.h" 27#include "lldb/Core/DataBufferMemoryMap.h" 28#include "lldb/Core/Stream.h" 29#include "lldb/Host/Host.h" 30 31using namespace lldb; 32using namespace lldb_private; 33using namespace std; 34 35static bool 36GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) 37{ 38 char resolved_path[PATH_MAX]; 39 if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path))) 40 return ::stat (resolved_path, stats_ptr) == 0; 41 return false; 42} 43 44static const char* 45GetCachedGlobTildeSlash() 46{ 47 static std::string g_tilde; 48 if (g_tilde.empty()) 49 { 50 struct passwd *user_entry; 51 user_entry = getpwuid(geteuid()); 52 if (user_entry != NULL) 53 g_tilde = user_entry->pw_dir; 54 55 if (g_tilde.empty()) 56 return NULL; 57 } 58 return g_tilde.c_str(); 59} 60 61// Resolves the username part of a path of the form ~user/other/directories, and 62// writes the result into dst_path. 63// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. 64// Otherwise returns the number of characters copied into dst_path. If the return 65// is >= dst_len, then the resolved path is too long... 66size_t 67FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) 68{ 69 char user_home[PATH_MAX]; 70 const char *user_name; 71 72 if (src_path == NULL || src_path[0] == '\0') 73 return 0; 74 75 // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) 76 if (src_path[0] != '~') 77 { 78 size_t len = strlen (src_path); 79 if (len >= dst_len) 80 { 81 ::bcopy (src_path, dst_path, dst_len - 1); 82 dst_path[dst_len] = '\0'; 83 } 84 else 85 ::bcopy (src_path, dst_path, len + 1); 86 87 return len; 88 } 89 90 const char *first_slash = ::strchr (src_path, '/'); 91 char remainder[PATH_MAX]; 92 93 if (first_slash == NULL) 94 { 95 // The whole name is the username (minus the ~): 96 user_name = src_path + 1; 97 remainder[0] = '\0'; 98 } 99 else 100 { 101 int user_name_len = first_slash - src_path - 1; 102 ::memcpy (user_home, src_path + 1, user_name_len); 103 user_home[user_name_len] = '\0'; 104 user_name = user_home; 105 106 ::strcpy (remainder, first_slash); 107 } 108 109 if (user_name == NULL) 110 return 0; 111 // User name of "" means the current user... 112 113 struct passwd *user_entry; 114 const char *home_dir = NULL; 115 116 if (user_name[0] == '\0') 117 { 118 home_dir = GetCachedGlobTildeSlash(); 119 } 120 else 121 { 122 user_entry = ::getpwnam (user_name); 123 if (user_entry != NULL) 124 home_dir = user_entry->pw_dir; 125 } 126 127 if (home_dir == NULL) 128 return 0; 129 else 130 return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); 131} 132 133size_t 134FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) 135{ 136 if (src_path == NULL || src_path[0] == '\0') 137 return 0; 138 139 // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... 140 char unglobbed_path[PATH_MAX]; 141 if (src_path[0] == '~') 142 { 143 size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); 144 145 // If we couldn't find the user referred to, or the resultant path was too long, 146 // then just copy over the src_path. 147 if (return_count == 0 || return_count >= sizeof(unglobbed_path)) 148 ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 149 } 150 else 151 ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 152 153 // Now resolve the path if needed 154 char resolved_path[PATH_MAX]; 155 if (::realpath (unglobbed_path, resolved_path)) 156 { 157 // Success, copy the resolved path 158 return ::snprintf(dst_path, dst_len, "%s", resolved_path); 159 } 160 else 161 { 162 // Failed, just copy the unglobbed path 163 return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); 164 } 165} 166 167FileSpec::FileSpec() : 168 m_directory(), 169 m_filename() 170{ 171} 172 173//------------------------------------------------------------------ 174// Default constructor that can take an optional full path to a 175// file on disk. 176//------------------------------------------------------------------ 177FileSpec::FileSpec(const char *pathname) : 178 m_directory(), 179 m_filename() 180{ 181 if (pathname && pathname[0]) 182 SetFile(pathname); 183} 184 185//------------------------------------------------------------------ 186// Default constructor that can take an optional full path to a 187// file on disk. 188//------------------------------------------------------------------ 189FileSpec::FileSpec(const char *pathname, bool resolve_path) : 190 m_directory(), 191 m_filename() 192{ 193 if (pathname && pathname[0]) 194 SetFile(pathname, resolve_path); 195} 196 197//------------------------------------------------------------------ 198// Copy constructor 199//------------------------------------------------------------------ 200FileSpec::FileSpec(const FileSpec& rhs) : 201 m_directory (rhs.m_directory), 202 m_filename (rhs.m_filename) 203{ 204} 205 206//------------------------------------------------------------------ 207// Copy constructor 208//------------------------------------------------------------------ 209FileSpec::FileSpec(const FileSpec* rhs) : 210 m_directory(), 211 m_filename() 212{ 213 if (rhs) 214 *this = *rhs; 215} 216 217//------------------------------------------------------------------ 218// Virtual destrcuctor in case anyone inherits from this class. 219//------------------------------------------------------------------ 220FileSpec::~FileSpec() 221{ 222} 223 224//------------------------------------------------------------------ 225// Assignment operator. 226//------------------------------------------------------------------ 227const FileSpec& 228FileSpec::operator= (const FileSpec& rhs) 229{ 230 if (this != &rhs) 231 { 232 m_directory = rhs.m_directory; 233 m_filename = rhs.m_filename; 234 } 235 return *this; 236} 237 238//------------------------------------------------------------------ 239// Update the contents of this object with a new path. The path will 240// be split up into a directory and filename and stored as uniqued 241// string values for quick comparison and efficient memory usage. 242//------------------------------------------------------------------ 243void 244FileSpec::SetFile(const char *pathname, bool resolve) 245{ 246 m_filename.Clear(); 247 m_directory.Clear(); 248 if (pathname == NULL || pathname[0] == '\0') 249 return; 250 251 char resolved_path[PATH_MAX]; 252 bool path_fit = true; 253 254 if (resolve) 255 { 256 path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); 257 } 258 else 259 { 260 if (strlen (pathname) > sizeof(resolved_path) - 1) 261 path_fit = false; 262 else 263 strcpy (resolved_path, pathname); 264 } 265 266 267 if (path_fit) 268 { 269 char *filename = ::basename (resolved_path); 270 if (filename) 271 { 272 m_filename.SetCString (filename); 273 // Truncate the basename off the end of the resolved path 274 275 // Only attempt to get the dirname if it looks like we have a path 276 if (strchr(resolved_path, '/')) 277 { 278 char *directory = ::dirname (resolved_path); 279 280 // Make sure we didn't get our directory resolved to "." without having 281 // specified 282 if (directory) 283 m_directory.SetCString(directory); 284 else 285 { 286 char *last_resolved_path_slash = strrchr(resolved_path, '/'); 287 if (last_resolved_path_slash) 288 { 289 *last_resolved_path_slash = '\0'; 290 m_directory.SetCString(resolved_path); 291 } 292 } 293 } 294 } 295 else 296 m_directory.SetCString(resolved_path); 297 } 298} 299 300//---------------------------------------------------------------------- 301// Convert to pointer operator. This allows code to check any FileSpec 302// objects to see if they contain anything valid using code such as: 303// 304// if (file_spec) 305// {} 306//---------------------------------------------------------------------- 307FileSpec::operator 308void*() const 309{ 310 return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL; 311} 312 313//---------------------------------------------------------------------- 314// Logical NOT operator. This allows code to check any FileSpec 315// objects to see if they are invalid using code such as: 316// 317// if (!file_spec) 318// {} 319//---------------------------------------------------------------------- 320bool 321FileSpec::operator!() const 322{ 323 return !m_directory && !m_filename; 324} 325 326//------------------------------------------------------------------ 327// Equal to operator 328//------------------------------------------------------------------ 329bool 330FileSpec::operator== (const FileSpec& rhs) const 331{ 332 return m_directory == rhs.m_directory && m_filename == rhs.m_filename; 333} 334 335//------------------------------------------------------------------ 336// Not equal to operator 337//------------------------------------------------------------------ 338bool 339FileSpec::operator!= (const FileSpec& rhs) const 340{ 341 return m_filename != rhs.m_filename || m_directory != rhs.m_directory; 342} 343 344//------------------------------------------------------------------ 345// Less than operator 346//------------------------------------------------------------------ 347bool 348FileSpec::operator< (const FileSpec& rhs) const 349{ 350 return FileSpec::Compare(*this, rhs, true) < 0; 351} 352 353//------------------------------------------------------------------ 354// Dump a FileSpec object to a stream 355//------------------------------------------------------------------ 356Stream& 357lldb_private::operator << (Stream &s, const FileSpec& f) 358{ 359 f.Dump(&s); 360 return s; 361} 362 363//------------------------------------------------------------------ 364// Clear this object by releasing both the directory and filename 365// string values and making them both the empty string. 366//------------------------------------------------------------------ 367void 368FileSpec::Clear() 369{ 370 m_directory.Clear(); 371 m_filename.Clear(); 372} 373 374//------------------------------------------------------------------ 375// Compare two FileSpec objects. If "full" is true, then both 376// the directory and the filename must match. If "full" is false, 377// then the directory names for "a" and "b" are only compared if 378// they are both non-empty. This allows a FileSpec object to only 379// contain a filename and it can match FileSpec objects that have 380// matching filenames with different paths. 381// 382// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" 383// and "1" if "a" is greater than "b". 384//------------------------------------------------------------------ 385int 386FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) 387{ 388 int result = 0; 389 390 // If full is true, then we must compare both the directory and filename. 391 392 // If full is false, then if either directory is empty, then we match on 393 // the basename only, and if both directories have valid values, we still 394 // do a full compare. This allows for matching when we just have a filename 395 // in one of the FileSpec objects. 396 397 if (full || (a.m_directory && b.m_directory)) 398 { 399 result = ConstString::Compare(a.m_directory, b.m_directory); 400 if (result) 401 return result; 402 } 403 return ConstString::Compare (a.m_filename, b.m_filename); 404} 405 406bool 407FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) 408{ 409 if (full) 410 return a == b; 411 else 412 return a.m_filename == b.m_filename; 413} 414 415 416 417//------------------------------------------------------------------ 418// Dump the object to the supplied stream. If the object contains 419// a valid directory name, it will be displayed followed by a 420// directory delimiter, and the filename. 421//------------------------------------------------------------------ 422void 423FileSpec::Dump(Stream *s) const 424{ 425 if (m_filename) 426 m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid 427 428 if (m_directory) 429 { 430 // If dirname was valid, then we need to print a slash between 431 // the directory and the filename 432 s->PutChar('/'); 433 } 434 m_filename.Dump(s); 435} 436 437//------------------------------------------------------------------ 438// Returns true if the file exists. 439//------------------------------------------------------------------ 440bool 441FileSpec::Exists () const 442{ 443 struct stat file_stats; 444 return GetFileStats (this, &file_stats); 445} 446 447bool 448FileSpec::ResolveExecutableLocation () 449{ 450 if (m_directory.GetLength() == 0) 451 { 452 const std::string file_str (m_filename.AsCString()); 453 llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str); 454 llvm::StringRef dir_ref = path.getDirname(); 455 if (! dir_ref.empty()) 456 { 457 // FindProgramByName returns "." if it can't find the file. 458 if (strcmp (".", dir_ref.data()) == 0) 459 return false; 460 461 m_directory.SetCString (dir_ref.data()); 462 if (Exists()) 463 return true; 464 else 465 { 466 // If FindProgramByName found the file, it returns the directory + filename in its return results. 467 // We need to separate them. 468 FileSpec tmp_file (dir_ref.data()); 469 if (tmp_file.Exists()) 470 { 471 m_directory = tmp_file.m_directory; 472 return true; 473 } 474 } 475 } 476 } 477 478 return false; 479} 480 481bool 482FileSpec::ResolvePath () 483{ 484 char path_buf[PATH_MAX]; 485 486 if (!GetPath (path_buf, PATH_MAX)) 487 return false; 488 SetFile (path_buf, true); 489 return true; 490} 491 492uint64_t 493FileSpec::GetByteSize() const 494{ 495 struct stat file_stats; 496 if (GetFileStats (this, &file_stats)) 497 return file_stats.st_size; 498 return 0; 499} 500 501FileSpec::FileType 502FileSpec::GetFileType () const 503{ 504 struct stat file_stats; 505 if (GetFileStats (this, &file_stats)) 506 { 507 mode_t file_type = file_stats.st_mode & S_IFMT; 508 switch (file_type) 509 { 510 case S_IFDIR: return eFileTypeDirectory; 511 case S_IFIFO: return eFileTypePipe; 512 case S_IFREG: return eFileTypeRegular; 513 case S_IFSOCK: return eFileTypeSocket; 514 case S_IFLNK: return eFileTypeSymbolicLink; 515 default: 516 break; 517 } 518 return eFileTypeUknown; 519 } 520 return eFileTypeInvalid; 521} 522 523TimeValue 524FileSpec::GetModificationTime () const 525{ 526 TimeValue mod_time; 527 struct stat file_stats; 528 if (GetFileStats (this, &file_stats)) 529 mod_time.OffsetWithSeconds(file_stats.st_mtime); 530 return mod_time; 531} 532 533//------------------------------------------------------------------ 534// Directory string get accessor. 535//------------------------------------------------------------------ 536ConstString & 537FileSpec::GetDirectory() 538{ 539 return m_directory; 540} 541 542//------------------------------------------------------------------ 543// Directory string const get accessor. 544//------------------------------------------------------------------ 545const ConstString & 546FileSpec::GetDirectory() const 547{ 548 return m_directory; 549} 550 551//------------------------------------------------------------------ 552// Filename string get accessor. 553//------------------------------------------------------------------ 554ConstString & 555FileSpec::GetFilename() 556{ 557 return m_filename; 558} 559 560//------------------------------------------------------------------ 561// Filename string const get accessor. 562//------------------------------------------------------------------ 563const ConstString & 564FileSpec::GetFilename() const 565{ 566 return m_filename; 567} 568 569//------------------------------------------------------------------ 570// Extract the directory and path into a fixed buffer. This is 571// needed as the directory and path are stored in separate string 572// values. 573//------------------------------------------------------------------ 574bool 575FileSpec::GetPath(char *path, size_t max_path_length) const 576{ 577 if (max_path_length == 0) 578 return false; 579 580 path[0] = '\0'; 581 const char *dirname = m_directory.AsCString(); 582 const char *filename = m_filename.AsCString(); 583 if (dirname) 584 { 585 if (filename && filename[0]) 586 { 587 return (size_t)::snprintf (path, max_path_length, "%s/%s", dirname, filename) < max_path_length; 588 } 589 else 590 { 591 ::strncpy (path, dirname, max_path_length); 592 } 593 } 594 else if (filename) 595 { 596 ::strncpy (path, filename, max_path_length); 597 } 598 else 599 { 600 return false; 601 } 602 603 // Any code paths that reach here assume that strncpy, or a similar function was called 604 // where any remaining bytes will be filled with NULLs and that the string won't be 605 // NULL terminated if it won't fit in the buffer. 606 607 // If the last character is NULL, then all went well 608 if (path[max_path_length-1] == '\0') 609 return true; 610 611 // Make sure the path is terminated, as it didn't fit into "path" 612 path[max_path_length-1] = '\0'; 613 return false; 614} 615 616//------------------------------------------------------------------ 617// Returns a shared pointer to a data buffer that contains all or 618// part of the contents of a file. The data is memory mapped and 619// will lazily page in data from the file as memory is accessed. 620// The data that is mappped will start "file_offset" bytes into the 621// file, and "file_size" bytes will be mapped. If "file_size" is 622// greater than the number of bytes available in the file starting 623// at "file_offset", the number of bytes will be appropriately 624// truncated. The final number of bytes that get mapped can be 625// verified using the DataBuffer::GetByteSize() function. 626//------------------------------------------------------------------ 627DataBufferSP 628FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const 629{ 630 DataBufferSP data_sp; 631 auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); 632 if (mmap_data.get()) 633 { 634 if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= file_size) 635 data_sp.reset(mmap_data.release()); 636 } 637 return data_sp; 638} 639 640 641//------------------------------------------------------------------ 642// Return the size in bytes that this object takes in memory. This 643// returns the size in bytes of this object, not any shared string 644// values it may refer to. 645//------------------------------------------------------------------ 646size_t 647FileSpec::MemorySize() const 648{ 649 return m_filename.MemorySize() + m_directory.MemorySize(); 650} 651 652 653size_t 654FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len) const 655{ 656 size_t bytes_read = 0; 657 char resolved_path[PATH_MAX]; 658 if (GetPath(resolved_path, sizeof(resolved_path))) 659 { 660 int fd = ::open (resolved_path, O_RDONLY, 0); 661 if (fd != -1) 662 { 663 struct stat file_stats; 664 if (::fstat (fd, &file_stats) == 0) 665 { 666 // Read bytes directly into our basic_string buffer 667 if (file_stats.st_size > 0) 668 { 669 off_t lseek_result = 0; 670 if (file_offset > 0) 671 lseek_result = ::lseek (fd, file_offset, SEEK_SET); 672 673 if (lseek_result == file_offset) 674 { 675 ssize_t n = ::read (fd, dst, dst_len); 676 if (n >= 0) 677 bytes_read = n; 678 } 679 } 680 } 681 } 682 close(fd); 683 } 684 return bytes_read; 685} 686 687//------------------------------------------------------------------ 688// Returns a shared pointer to a data buffer that contains all or 689// part of the contents of a file. The data copies into a heap based 690// buffer that lives in the DataBuffer shared pointer object returned. 691// The data that is cached will start "file_offset" bytes into the 692// file, and "file_size" bytes will be mapped. If "file_size" is 693// greater than the number of bytes available in the file starting 694// at "file_offset", the number of bytes will be appropriately 695// truncated. The final number of bytes that get mapped can be 696// verified using the DataBuffer::GetByteSize() function. 697//------------------------------------------------------------------ 698DataBufferSP 699FileSpec::ReadFileContents (off_t file_offset, size_t file_size) const 700{ 701 DataBufferSP data_sp; 702 char resolved_path[PATH_MAX]; 703 if (GetPath(resolved_path, sizeof(resolved_path))) 704 { 705 int fd = ::open (resolved_path, O_RDONLY, 0); 706 if (fd != -1) 707 { 708 struct stat file_stats; 709 if (::fstat (fd, &file_stats) == 0) 710 { 711 if (file_stats.st_size > 0) 712 { 713 off_t lseek_result = 0; 714 if (file_offset > 0) 715 lseek_result = ::lseek (fd, file_offset, SEEK_SET); 716 717 if (lseek_result < 0) 718 { 719 // Get error from errno 720 } 721 else if (lseek_result == file_offset) 722 { 723 const size_t bytes_left = file_stats.st_size - file_offset; 724 size_t num_bytes_to_read = file_size; 725 if (num_bytes_to_read > bytes_left) 726 num_bytes_to_read = bytes_left; 727 728 std::auto_ptr<DataBufferHeap> data_heap_ap; 729 data_heap_ap.reset(new DataBufferHeap(num_bytes_to_read, '\0')); 730 731 if (data_heap_ap.get()) 732 { 733 ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize()); 734 if (bytesRead >= 0) 735 { 736 // Make sure we read exactly what we asked for and if we got 737 // less, adjust the array 738 if ((size_t)bytesRead < data_heap_ap->GetByteSize()) 739 data_heap_ap->SetByteSize(bytesRead); 740 data_sp.reset(data_heap_ap.release()); 741 } 742 } 743 } 744 } 745 } 746 } 747 close(fd); 748 } 749 return data_sp; 750} 751 752bool 753FileSpec::ReadFileLines (STLStringArray &lines) 754{ 755 bool ret_val = false; 756 lines.clear(); 757 758 std::string dir_str (m_directory.AsCString()); 759 std::string file_str (m_filename.AsCString()); 760 std::string full_name = dir_str + "/" + file_str; 761 762 ifstream file_stream (full_name.c_str()); 763 764 if (file_stream) 765 { 766 std::string line; 767 while (getline (file_stream, line)) 768 lines.push_back (line); 769 ret_val = true; 770 } 771 772 return ret_val; 773} 774