FileSpec.cpp revision 27345db7bc4167078014798032137b0452f4cab9
1554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// 2554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// 3554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// The LLVM Compiler Infrastructure 4554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// 5554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// This file is distributed under the University of Illinois Open Source 6554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// License. See LICENSE.TXT for details. 7f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina// 8f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina//===----------------------------------------------------------------------===// 9a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 10554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 11a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#include <fcntl.h> 12554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include <libgen.h> 13554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include <stdlib.h> 14c289743864e2ab926a95e617a5cd1d29b26d1825mtklein@google.com#include <sys/param.h> 15554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include <sys/stat.h> 16554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include <sys/types.h> 17f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina#include <pwd.h> 18554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 19644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org#include <fstream> 20644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org 21554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include "llvm/ADT/StringRef.h" 22644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org#include "llvm/Support/Path.h" 23554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include "llvm/Support/Program.h" 24554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 25554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include "lldb/Core/FileSpec.h" 26554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include "lldb/Core/DataBufferHeap.h" 27554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com#include "lldb/Core/DataBufferMemoryMap.h" 283361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org#include "lldb/Core/Stream.h" 293361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org#include "lldb/Host/Host.h" 30554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 31554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comusing namespace lldb; 32554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comusing namespace lldb_private; 33554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comusing namespace std; 34554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 35554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comstatic bool 36554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comGetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) 37554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com{ 38554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com char resolved_path[PATH_MAX]; 39f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path))) 40554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com return ::stat (resolved_path, stats_ptr) == 0; 41554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com return false; 42554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com} 43554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 4415e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.comstatic const char* 4515e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.comGetCachedGlobTildeSlash() 46554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com{ 4777472f06f88b85e85fb690584c85d0a42e74b685sugoi@google.com static std::string g_tilde; 4815e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.com if (g_tilde.empty()) 4915e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.com { 5015e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.com struct passwd *user_entry; 51554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com user_entry = getpwuid(geteuid()); 52554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com if (user_entry != NULL) 53f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina g_tilde = user_entry->pw_dir; 54554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 55644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org if (g_tilde.empty()) 56644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org return NULL; 57554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com } 58644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org return g_tilde.c_str(); 59554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com} 60554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 61554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// Resolves the username part of a path of the form ~user/other/directories, and 62554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// writes the result into dst_path. 63554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. 643361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org// Otherwise returns the number of characters copied into dst_path. If the return 65554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com// is >= dst_len, then the resolved path is too long... 663361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.orgsize_t 67554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.comFileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) 68554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com{ 69554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com char user_home[PATH_MAX]; 70554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com const char *user_name; 71554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 72554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com if (src_path == NULL || src_path[0] == '\0') 73554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com return 0; 74554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com 75554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) 76554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com if (src_path[0] != '~') 77f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina { 78554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com size_t len = strlen (src_path); 79554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com if (len >= dst_len) 80f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina { 81a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com ::bcopy (src_path, dst_path, dst_len - 1); 82644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org dst_path[dst_len] = '\0'; 83644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org } 84a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com else 85644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org ::bcopy (src_path, dst_path, len + 1); 86a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 87a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com return len; 88a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 89a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 90a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com const char *first_slash = ::strchr (src_path, '/'); 913361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org char remainder[PATH_MAX]; 923361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org 93a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (first_slash == NULL) 94a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 95a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // The whole name is the username (minus the ~): 96a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com user_name = src_path + 1; 97a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com remainder[0] = '\0'; 98a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 99a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com else 100a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 101a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com int user_name_len = first_slash - src_path - 1; 102a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com ::memcpy (user_home, src_path + 1, user_name_len); 103f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina user_home[user_name_len] = '\0'; 104a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com user_name = user_home; 105a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 106a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com ::strcpy (remainder, first_slash); 107a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 108f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina 109a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (user_name == NULL) 110644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org return 0; 111644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org // User name of "" means the current user... 112a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 113644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org struct passwd *user_entry; 114a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com const char *home_dir = NULL; 115a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 116a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (user_name[0] == '\0') 117a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 118a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com home_dir = GetCachedGlobTildeSlash(); 1193361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org } 1203361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org else 121a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 122a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com user_entry = ::getpwnam (user_name); 123a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (user_entry != NULL) 124a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com home_dir = user_entry->pw_dir; 125a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 126a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 127a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (home_dir == NULL) 128a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com return 0; 129a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com else 130f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); 131a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com} 132a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 133a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.comsize_t 134a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.comFileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) 135a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com{ 13677472f06f88b85e85fb690584c85d0a42e74b685sugoi@google.com if (src_path == NULL || src_path[0] == '\0') 137a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com return 0; 138a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 139f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... 140a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com char unglobbed_path[PATH_MAX]; 141644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org if (src_path[0] == '~') 142644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org { 143a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); 144644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org 145a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // If we couldn't find the user referred to, or the resultant path was too long, 146a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // then just copy over the src_path. 147a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (return_count == 0 || return_count >= sizeof(unglobbed_path)) 148a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 149a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 1503361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org else 151a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); 1523361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org 153a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // Now resolve the path if needed 154a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com char resolved_path[PATH_MAX]; 155a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (::realpath (unglobbed_path, resolved_path)) 156a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 157a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // Success, copy the resolved path 158a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com return ::snprintf(dst_path, dst_len, "%s", resolved_path); 159a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 160a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com else 161a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com { 162a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com // Failed, just copy the unglobbed path 163f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); 164a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com } 165a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com} 166f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina 167a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.comFileSpec::FileSpec() : 168644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org m_directory(), 169644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org m_filename() 170a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com{ 171644629c1c7913a43ced172b98d56e0f471bc348bcommit-bot@chromium.org} 172a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 173a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com//------------------------------------------------------------------ 174a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com// Default constructor that can take an optional full path to a 175a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com// file on disk. 176a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com//------------------------------------------------------------------ 1773361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.orgFileSpec::FileSpec(const char *pathname, bool resolve_path) : 1783361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org m_directory(), 179a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com m_filename(), 180a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com m_is_resolved(false) 181a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com{ 182a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com if (pathname && pathname[0]) 183a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com SetFile(pathname, resolve_path); 184a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com} 185a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com 186a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com//------------------------------------------------------------------ 187a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com// Copy constructor 188a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com//------------------------------------------------------------------ 189f168b86d7fafc5c20c87bebc6fd393cb17e120catfarinaFileSpec::FileSpec(const FileSpec& rhs) : 190a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com m_directory (rhs.m_directory), 191a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com m_filename (rhs.m_filename), 192554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com m_is_resolved (rhs.m_is_resolved) 193554875210043b34178f7ed6ac5bd682b1fad367bbungeman@google.com{ 194410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com} 195410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com 196410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com//------------------------------------------------------------------ 197a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com// Copy constructor 198410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com//------------------------------------------------------------------ 199410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.comFileSpec::FileSpec(const FileSpec* rhs) : 200410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com m_directory(), 201 m_filename() 202{ 203 if (rhs) 204 *this = *rhs; 205} 206 207//------------------------------------------------------------------ 208// Virtual destrcuctor in case anyone inherits from this class. 209//------------------------------------------------------------------ 210FileSpec::~FileSpec() 211{ 212} 213 214//------------------------------------------------------------------ 215// Assignment operator. 216//------------------------------------------------------------------ 217const FileSpec& 218FileSpec::operator= (const FileSpec& rhs) 219{ 220 if (this != &rhs) 221 { 222 m_directory = rhs.m_directory; 223 m_filename = rhs.m_filename; 224 m_is_resolved = rhs.m_is_resolved; 225 } 226 return *this; 227} 228 229//------------------------------------------------------------------ 230// Update the contents of this object with a new path. The path will 231// be split up into a directory and filename and stored as uniqued 232// string values for quick comparison and efficient memory usage. 233//------------------------------------------------------------------ 234void 235FileSpec::SetFile (const char *pathname, bool resolve) 236{ 237 m_filename.Clear(); 238 m_directory.Clear(); 239 m_is_resolved = false; 240 if (pathname == NULL || pathname[0] == '\0') 241 return; 242 243 char resolved_path[PATH_MAX]; 244 bool path_fit = true; 245 246 if (resolve) 247 { 248 path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); 249 m_is_resolved = path_fit; 250 } 251 else 252 { 253 // Copy the path because "basename" and "dirname" want to muck with the 254 // path buffer 255 if (::strlen (pathname) > sizeof(resolved_path) - 1) 256 path_fit = false; 257 else 258 ::strcpy (resolved_path, pathname); 259 } 260 261 262 if (path_fit) 263 { 264 char *filename = ::basename (resolved_path); 265 if (filename) 266 { 267 m_filename.SetCString (filename); 268 // Truncate the basename off the end of the resolved path 269 270 // Only attempt to get the dirname if it looks like we have a path 271 if (strchr(resolved_path, '/')) 272 { 273 char *directory = ::dirname (resolved_path); 274 275 // Make sure we didn't get our directory resolved to "." without having 276 // specified 277 if (directory) 278 m_directory.SetCString(directory); 279 else 280 { 281 char *last_resolved_path_slash = strrchr(resolved_path, '/'); 282 if (last_resolved_path_slash) 283 { 284 *last_resolved_path_slash = '\0'; 285 m_directory.SetCString(resolved_path); 286 } 287 } 288 } 289 } 290 else 291 m_directory.SetCString(resolved_path); 292 } 293} 294 295//---------------------------------------------------------------------- 296// Convert to pointer operator. This allows code to check any FileSpec 297// objects to see if they contain anything valid using code such as: 298// 299// if (file_spec) 300// {} 301//---------------------------------------------------------------------- 302FileSpec::operator 303void*() const 304{ 305 return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL; 306} 307 308//---------------------------------------------------------------------- 309// Logical NOT operator. This allows code to check any FileSpec 310// objects to see if they are invalid using code such as: 311// 312// if (!file_spec) 313// {} 314//---------------------------------------------------------------------- 315bool 316FileSpec::operator!() const 317{ 318 return !m_directory && !m_filename; 319} 320 321//------------------------------------------------------------------ 322// Equal to operator 323//------------------------------------------------------------------ 324bool 325FileSpec::operator== (const FileSpec& rhs) const 326{ 327 if (m_filename == rhs.m_filename) 328 { 329 if (m_directory == rhs.m_directory) 330 return true; 331 332 // TODO: determine if we want to keep this code in here. 333 // The code below was added to handle a case where we were 334 // trying to set a file and line breakpoint and one path 335 // was resolved, and the other not and the directory was 336 // in a mount point that resolved to a more complete path: 337 // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling 338 // this out... 339 if (IsResolved() && rhs.IsResolved()) 340 { 341 // Both paths are resolved, no need to look further... 342 return false; 343 } 344 345 FileSpec resolved_lhs(*this); 346 347 // If "this" isn't resolved, resolve it 348 if (!IsResolved()) 349 { 350 if (resolved_lhs.ResolvePath()) 351 { 352 // This path wasn't resolved but now it is. Check if the resolved 353 // directory is the same as our unresolved directory, and if so, 354 // we can mark this object as resolved to avoid more future resolves 355 m_is_resolved = (m_directory == resolved_lhs.m_directory); 356 } 357 else 358 return false; 359 } 360 361 FileSpec resolved_rhs(rhs); 362 if (!rhs.IsResolved()) 363 { 364 if (resolved_rhs.ResolvePath()) 365 { 366 // rhs's path wasn't resolved but now it is. Check if the resolved 367 // directory is the same as rhs's unresolved directory, and if so, 368 // we can mark this object as resolved to avoid more future resolves 369 rhs.m_is_resolved = (m_directory == resolved_rhs.m_directory); 370 } 371 else 372 return false; 373 } 374 375 // If we reach this point in the code we were able to resolve both paths 376 // and since we only resolve the paths if the basenames are equal, then 377 // we can just check if both directories are equal... 378 return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory(); 379 } 380 return false; 381} 382 383//------------------------------------------------------------------ 384// Not equal to operator 385//------------------------------------------------------------------ 386bool 387FileSpec::operator!= (const FileSpec& rhs) const 388{ 389 return !(*this == rhs); 390} 391 392//------------------------------------------------------------------ 393// Less than operator 394//------------------------------------------------------------------ 395bool 396FileSpec::operator< (const FileSpec& rhs) const 397{ 398 return FileSpec::Compare(*this, rhs, true) < 0; 399} 400 401//------------------------------------------------------------------ 402// Dump a FileSpec object to a stream 403//------------------------------------------------------------------ 404Stream& 405lldb_private::operator << (Stream &s, const FileSpec& f) 406{ 407 f.Dump(&s); 408 return s; 409} 410 411//------------------------------------------------------------------ 412// Clear this object by releasing both the directory and filename 413// string values and making them both the empty string. 414//------------------------------------------------------------------ 415void 416FileSpec::Clear() 417{ 418 m_directory.Clear(); 419 m_filename.Clear(); 420} 421 422//------------------------------------------------------------------ 423// Compare two FileSpec objects. If "full" is true, then both 424// the directory and the filename must match. If "full" is false, 425// then the directory names for "a" and "b" are only compared if 426// they are both non-empty. This allows a FileSpec object to only 427// contain a filename and it can match FileSpec objects that have 428// matching filenames with different paths. 429// 430// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" 431// and "1" if "a" is greater than "b". 432//------------------------------------------------------------------ 433int 434FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) 435{ 436 int result = 0; 437 438 // If full is true, then we must compare both the directory and filename. 439 440 // If full is false, then if either directory is empty, then we match on 441 // the basename only, and if both directories have valid values, we still 442 // do a full compare. This allows for matching when we just have a filename 443 // in one of the FileSpec objects. 444 445 if (full || (a.m_directory && b.m_directory)) 446 { 447 result = ConstString::Compare(a.m_directory, b.m_directory); 448 if (result) 449 return result; 450 } 451 return ConstString::Compare (a.m_filename, b.m_filename); 452} 453 454bool 455FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) 456{ 457 if (full) 458 return a == b; 459 else 460 return a.m_filename == b.m_filename; 461} 462 463 464 465//------------------------------------------------------------------ 466// Dump the object to the supplied stream. If the object contains 467// a valid directory name, it will be displayed followed by a 468// directory delimiter, and the filename. 469//------------------------------------------------------------------ 470void 471FileSpec::Dump(Stream *s) const 472{ 473 if (m_filename) 474 m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid 475 476 if (m_directory) 477 { 478 // If dirname was valid, then we need to print a slash between 479 // the directory and the filename 480 s->PutChar('/'); 481 } 482 m_filename.Dump(s); 483} 484 485//------------------------------------------------------------------ 486// Returns true if the file exists. 487//------------------------------------------------------------------ 488bool 489FileSpec::Exists () const 490{ 491 struct stat file_stats; 492 return GetFileStats (this, &file_stats); 493} 494 495bool 496FileSpec::ResolveExecutableLocation () 497{ 498 if (!m_directory) 499 { 500 const char *file_cstr = m_filename.GetCString(); 501 if (file_cstr) 502 { 503 const std::string file_str (file_cstr); 504 llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str); 505 const std::string &path_str = path.str(); 506 llvm::StringRef dir_ref = llvm::sys::path::parent_path(path_str); 507 //llvm::StringRef dir_ref = path.getDirname(); 508 if (! dir_ref.empty()) 509 { 510 // FindProgramByName returns "." if it can't find the file. 511 if (strcmp (".", dir_ref.data()) == 0) 512 return false; 513 514 m_directory.SetCString (dir_ref.data()); 515 if (Exists()) 516 return true; 517 else 518 { 519 // If FindProgramByName found the file, it returns the directory + filename in its return results. 520 // We need to separate them. 521 FileSpec tmp_file (dir_ref.data(), false); 522 if (tmp_file.Exists()) 523 { 524 m_directory = tmp_file.m_directory; 525 return true; 526 } 527 } 528 } 529 } 530 } 531 532 return false; 533} 534 535bool 536FileSpec::ResolvePath () 537{ 538 if (m_is_resolved) 539 return true; // We have already resolved this path 540 541 char path_buf[PATH_MAX]; 542 if (!GetPath (path_buf, PATH_MAX)) 543 return false; 544 // SetFile(...) will set m_is_resolved correctly if it can resolve the path 545 SetFile (path_buf, true); 546 return m_is_resolved; 547} 548 549uint64_t 550FileSpec::GetByteSize() const 551{ 552 struct stat file_stats; 553 if (GetFileStats (this, &file_stats)) 554 return file_stats.st_size; 555 return 0; 556} 557 558FileSpec::FileType 559FileSpec::GetFileType () const 560{ 561 struct stat file_stats; 562 if (GetFileStats (this, &file_stats)) 563 { 564 mode_t file_type = file_stats.st_mode & S_IFMT; 565 switch (file_type) 566 { 567 case S_IFDIR: return eFileTypeDirectory; 568 case S_IFIFO: return eFileTypePipe; 569 case S_IFREG: return eFileTypeRegular; 570 case S_IFSOCK: return eFileTypeSocket; 571 case S_IFLNK: return eFileTypeSymbolicLink; 572 default: 573 break; 574 } 575 return eFileTypeUknown; 576 } 577 return eFileTypeInvalid; 578} 579 580TimeValue 581FileSpec::GetModificationTime () const 582{ 583 TimeValue mod_time; 584 struct stat file_stats; 585 if (GetFileStats (this, &file_stats)) 586 mod_time.OffsetWithSeconds(file_stats.st_mtime); 587 return mod_time; 588} 589 590//------------------------------------------------------------------ 591// Directory string get accessor. 592//------------------------------------------------------------------ 593ConstString & 594FileSpec::GetDirectory() 595{ 596 return m_directory; 597} 598 599//------------------------------------------------------------------ 600// Directory string const get accessor. 601//------------------------------------------------------------------ 602const ConstString & 603FileSpec::GetDirectory() const 604{ 605 return m_directory; 606} 607 608//------------------------------------------------------------------ 609// Filename string get accessor. 610//------------------------------------------------------------------ 611ConstString & 612FileSpec::GetFilename() 613{ 614 return m_filename; 615} 616 617//------------------------------------------------------------------ 618// Filename string const get accessor. 619//------------------------------------------------------------------ 620const ConstString & 621FileSpec::GetFilename() const 622{ 623 return m_filename; 624} 625 626//------------------------------------------------------------------ 627// Extract the directory and path into a fixed buffer. This is 628// needed as the directory and path are stored in separate string 629// values. 630//------------------------------------------------------------------ 631size_t 632FileSpec::GetPath(char *path, size_t path_max_len) const 633{ 634 if (path_max_len) 635 { 636 const char *dirname = m_directory.GetCString(); 637 const char *filename = m_filename.GetCString(); 638 if (dirname) 639 { 640 if (filename) 641 return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); 642 else 643 return ::snprintf (path, path_max_len, "%s", dirname); 644 } 645 else if (filename) 646 { 647 return ::snprintf (path, path_max_len, "%s", filename); 648 } 649 } 650 path[0] = '\0'; 651 return 0; 652} 653 654//------------------------------------------------------------------ 655// Returns a shared pointer to a data buffer that contains all or 656// part of the contents of a file. The data is memory mapped and 657// will lazily page in data from the file as memory is accessed. 658// The data that is mappped will start "file_offset" bytes into the 659// file, and "file_size" bytes will be mapped. If "file_size" is 660// greater than the number of bytes available in the file starting 661// at "file_offset", the number of bytes will be appropriately 662// truncated. The final number of bytes that get mapped can be 663// verified using the DataBuffer::GetByteSize() function. 664//------------------------------------------------------------------ 665DataBufferSP 666FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const 667{ 668 DataBufferSP data_sp; 669 auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); 670 if (mmap_data.get()) 671 { 672 if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= file_size) 673 data_sp.reset(mmap_data.release()); 674 } 675 return data_sp; 676} 677 678 679//------------------------------------------------------------------ 680// Return the size in bytes that this object takes in memory. This 681// returns the size in bytes of this object, not any shared string 682// values it may refer to. 683//------------------------------------------------------------------ 684size_t 685FileSpec::MemorySize() const 686{ 687 return m_filename.MemorySize() + m_directory.MemorySize(); 688} 689 690 691size_t 692FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len) const 693{ 694 size_t bytes_read = 0; 695 char resolved_path[PATH_MAX]; 696 if (GetPath(resolved_path, sizeof(resolved_path))) 697 { 698 int fd = ::open (resolved_path, O_RDONLY, 0); 699 if (fd != -1) 700 { 701 struct stat file_stats; 702 if (::fstat (fd, &file_stats) == 0) 703 { 704 // Read bytes directly into our basic_string buffer 705 if (file_stats.st_size > 0) 706 { 707 off_t lseek_result = 0; 708 if (file_offset > 0) 709 lseek_result = ::lseek (fd, file_offset, SEEK_SET); 710 711 if (lseek_result == file_offset) 712 { 713 ssize_t n = ::read (fd, dst, dst_len); 714 if (n >= 0) 715 bytes_read = n; 716 } 717 } 718 } 719 } 720 close(fd); 721 } 722 return bytes_read; 723} 724 725//------------------------------------------------------------------ 726// Returns a shared pointer to a data buffer that contains all or 727// part of the contents of a file. The data copies into a heap based 728// buffer that lives in the DataBuffer shared pointer object returned. 729// The data that is cached will start "file_offset" bytes into the 730// file, and "file_size" bytes will be mapped. If "file_size" is 731// greater than the number of bytes available in the file starting 732// at "file_offset", the number of bytes will be appropriately 733// truncated. The final number of bytes that get mapped can be 734// verified using the DataBuffer::GetByteSize() function. 735//------------------------------------------------------------------ 736DataBufferSP 737FileSpec::ReadFileContents (off_t file_offset, size_t file_size) const 738{ 739 DataBufferSP data_sp; 740 char resolved_path[PATH_MAX]; 741 if (GetPath(resolved_path, sizeof(resolved_path))) 742 { 743 int fd = ::open (resolved_path, O_RDONLY, 0); 744 if (fd != -1) 745 { 746 struct stat file_stats; 747 if (::fstat (fd, &file_stats) == 0) 748 { 749 if (file_stats.st_size > 0) 750 { 751 off_t lseek_result = 0; 752 if (file_offset > 0) 753 lseek_result = ::lseek (fd, file_offset, SEEK_SET); 754 755 if (lseek_result < 0) 756 { 757 // Get error from errno 758 } 759 else if (lseek_result == file_offset) 760 { 761 const size_t bytes_left = file_stats.st_size - file_offset; 762 size_t num_bytes_to_read = file_size; 763 if (num_bytes_to_read > bytes_left) 764 num_bytes_to_read = bytes_left; 765 766 std::auto_ptr<DataBufferHeap> data_heap_ap; 767 data_heap_ap.reset(new DataBufferHeap(num_bytes_to_read, '\0')); 768 769 if (data_heap_ap.get()) 770 { 771 ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize()); 772 if (bytesRead >= 0) 773 { 774 // Make sure we read exactly what we asked for and if we got 775 // less, adjust the array 776 if ((size_t)bytesRead < data_heap_ap->GetByteSize()) 777 data_heap_ap->SetByteSize(bytesRead); 778 data_sp.reset(data_heap_ap.release()); 779 } 780 } 781 } 782 } 783 } 784 } 785 close(fd); 786 } 787 return data_sp; 788} 789 790size_t 791FileSpec::ReadFileLines (STLStringArray &lines) 792{ 793 lines.clear(); 794 char path[PATH_MAX]; 795 if (GetPath(path, sizeof(path))) 796 { 797 ifstream file_stream (path); 798 799 if (file_stream) 800 { 801 std::string line; 802 while (getline (file_stream, line)) 803 lines.push_back (line); 804 } 805 } 806 return lines.size(); 807} 808