blob: d0749bd35544109a628d7c484092595314f5e0cb [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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
Greg Clayton4272cc72011-02-02 02:24:04 +000011#include <dirent.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000012#include <fcntl.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000013#include <libgen.h>
14#include <stdlib.h>
15#include <sys/param.h>
16#include <sys/stat.h>
17#include <sys/types.h>
Jim Inghamf818ca32010-07-01 01:48:53 +000018#include <pwd.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019
20#include <fstream>
21
Caroline Tice391a9602010-09-12 00:10:52 +000022#include "llvm/ADT/StringRef.h"
Greg Clayton38a61402010-12-02 23:20:03 +000023#include "llvm/Support/Path.h"
24#include "llvm/Support/Program.h"
Caroline Tice391a9602010-09-12 00:10:52 +000025
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026#include "lldb/Core/FileSpec.h"
27#include "lldb/Core/DataBufferHeap.h"
28#include "lldb/Core/DataBufferMemoryMap.h"
29#include "lldb/Core/Stream.h"
Caroline Tice428a9a52010-09-10 04:48:55 +000030#include "lldb/Host/Host.h"
Greg Clayton4272cc72011-02-02 02:24:04 +000031#include "lldb/Utility/CleanUp.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032
33using namespace lldb;
34using namespace lldb_private;
35using namespace std;
36
37static bool
38GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
39{
40 char resolved_path[PATH_MAX];
41 if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path)))
42 return ::stat (resolved_path, stats_ptr) == 0;
43 return false;
44}
45
46static const char*
47GetCachedGlobTildeSlash()
48{
49 static std::string g_tilde;
50 if (g_tilde.empty())
51 {
Jim Inghamf818ca32010-07-01 01:48:53 +000052 struct passwd *user_entry;
53 user_entry = getpwuid(geteuid());
54 if (user_entry != NULL)
55 g_tilde = user_entry->pw_dir;
56
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057 if (g_tilde.empty())
58 return NULL;
59 }
60 return g_tilde.c_str();
61}
62
Jim Inghamf818ca32010-07-01 01:48:53 +000063// Resolves the username part of a path of the form ~user/other/directories, and
64// writes the result into dst_path.
65// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved.
66// Otherwise returns the number of characters copied into dst_path. If the return
67// is >= dst_len, then the resolved path is too long...
Greg Claytonc982c762010-07-09 20:39:50 +000068size_t
Jim Inghamf818ca32010-07-01 01:48:53 +000069FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len)
70{
71 char user_home[PATH_MAX];
72 const char *user_name;
73
74 if (src_path == NULL || src_path[0] == '\0')
75 return 0;
Greg Claytona5d24f62010-07-01 17:07:48 +000076
Jim Inghamf818ca32010-07-01 01:48:53 +000077 // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
78 if (src_path[0] != '~')
79 {
Greg Claytonc982c762010-07-09 20:39:50 +000080 size_t len = strlen (src_path);
Jim Inghamf818ca32010-07-01 01:48:53 +000081 if (len >= dst_len)
82 {
Greg Claytona5d24f62010-07-01 17:07:48 +000083 ::bcopy (src_path, dst_path, dst_len - 1);
84 dst_path[dst_len] = '\0';
Jim Inghamf818ca32010-07-01 01:48:53 +000085 }
86 else
Greg Claytona5d24f62010-07-01 17:07:48 +000087 ::bcopy (src_path, dst_path, len + 1);
88
Jim Inghamf818ca32010-07-01 01:48:53 +000089 return len;
90 }
91
Eli Friedmanfeaeebf2010-07-02 19:15:50 +000092 const char *first_slash = ::strchr (src_path, '/');
Jim Inghamf818ca32010-07-01 01:48:53 +000093 char remainder[PATH_MAX];
94
95 if (first_slash == NULL)
96 {
97 // The whole name is the username (minus the ~):
98 user_name = src_path + 1;
99 remainder[0] = '\0';
100 }
101 else
102 {
103 int user_name_len = first_slash - src_path - 1;
Greg Claytona5d24f62010-07-01 17:07:48 +0000104 ::memcpy (user_home, src_path + 1, user_name_len);
Jim Inghamf818ca32010-07-01 01:48:53 +0000105 user_home[user_name_len] = '\0';
106 user_name = user_home;
107
Greg Claytona5d24f62010-07-01 17:07:48 +0000108 ::strcpy (remainder, first_slash);
Jim Inghamf818ca32010-07-01 01:48:53 +0000109 }
Greg Claytona5d24f62010-07-01 17:07:48 +0000110
Jim Inghamf818ca32010-07-01 01:48:53 +0000111 if (user_name == NULL)
112 return 0;
113 // User name of "" means the current user...
114
115 struct passwd *user_entry;
Greg Claytonc982c762010-07-09 20:39:50 +0000116 const char *home_dir = NULL;
Jim Inghamf818ca32010-07-01 01:48:53 +0000117
118 if (user_name[0] == '\0')
119 {
120 home_dir = GetCachedGlobTildeSlash();
121 }
122 else
123 {
Greg Claytona5d24f62010-07-01 17:07:48 +0000124 user_entry = ::getpwnam (user_name);
Jim Inghamf818ca32010-07-01 01:48:53 +0000125 if (user_entry != NULL)
126 home_dir = user_entry->pw_dir;
127 }
128
129 if (home_dir == NULL)
130 return 0;
131 else
132 return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder);
133}
134
Greg Claytonc982c762010-07-09 20:39:50 +0000135size_t
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
137{
138 if (src_path == NULL || src_path[0] == '\0')
139 return 0;
140
141 // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
142 char unglobbed_path[PATH_MAX];
Jim Inghamf818ca32010-07-01 01:48:53 +0000143 if (src_path[0] == '~')
144 {
Greg Claytonc982c762010-07-09 20:39:50 +0000145 size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path));
Jim Inghamf818ca32010-07-01 01:48:53 +0000146
147 // If we couldn't find the user referred to, or the resultant path was too long,
148 // then just copy over the src_path.
149 if (return_count == 0 || return_count >= sizeof(unglobbed_path))
150 ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
151 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 else
153 ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
154
155 // Now resolve the path if needed
156 char resolved_path[PATH_MAX];
157 if (::realpath (unglobbed_path, resolved_path))
158 {
159 // Success, copy the resolved path
160 return ::snprintf(dst_path, dst_len, "%s", resolved_path);
161 }
162 else
163 {
164 // Failed, just copy the unglobbed path
165 return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
166 }
167}
168
169FileSpec::FileSpec() :
170 m_directory(),
171 m_filename()
172{
173}
174
175//------------------------------------------------------------------
176// Default constructor that can take an optional full path to a
177// file on disk.
178//------------------------------------------------------------------
Jim Ingham0909e5f2010-09-16 00:57:33 +0000179FileSpec::FileSpec(const char *pathname, bool resolve_path) :
180 m_directory(),
Greg Clayton7481c202010-11-08 00:28:40 +0000181 m_filename(),
182 m_is_resolved(false)
Jim Ingham0909e5f2010-09-16 00:57:33 +0000183{
184 if (pathname && pathname[0])
185 SetFile(pathname, resolve_path);
186}
187
188//------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189// Copy constructor
190//------------------------------------------------------------------
191FileSpec::FileSpec(const FileSpec& rhs) :
192 m_directory (rhs.m_directory),
Greg Clayton7481c202010-11-08 00:28:40 +0000193 m_filename (rhs.m_filename),
194 m_is_resolved (rhs.m_is_resolved)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000195{
196}
197
198//------------------------------------------------------------------
199// Copy constructor
200//------------------------------------------------------------------
201FileSpec::FileSpec(const FileSpec* rhs) :
202 m_directory(),
203 m_filename()
204{
205 if (rhs)
206 *this = *rhs;
207}
208
209//------------------------------------------------------------------
210// Virtual destrcuctor in case anyone inherits from this class.
211//------------------------------------------------------------------
212FileSpec::~FileSpec()
213{
214}
215
216//------------------------------------------------------------------
217// Assignment operator.
218//------------------------------------------------------------------
219const FileSpec&
220FileSpec::operator= (const FileSpec& rhs)
221{
222 if (this != &rhs)
223 {
224 m_directory = rhs.m_directory;
225 m_filename = rhs.m_filename;
Greg Clayton7481c202010-11-08 00:28:40 +0000226 m_is_resolved = rhs.m_is_resolved;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000227 }
228 return *this;
229}
230
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000231//------------------------------------------------------------------
232// Update the contents of this object with a new path. The path will
233// be split up into a directory and filename and stored as uniqued
234// string values for quick comparison and efficient memory usage.
235//------------------------------------------------------------------
236void
Greg Clayton7481c202010-11-08 00:28:40 +0000237FileSpec::SetFile (const char *pathname, bool resolve)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000238{
239 m_filename.Clear();
240 m_directory.Clear();
Greg Clayton7481c202010-11-08 00:28:40 +0000241 m_is_resolved = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000242 if (pathname == NULL || pathname[0] == '\0')
243 return;
244
245 char resolved_path[PATH_MAX];
Jim Ingham0909e5f2010-09-16 00:57:33 +0000246 bool path_fit = true;
247
248 if (resolve)
249 {
250 path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1);
Greg Clayton7481c202010-11-08 00:28:40 +0000251 m_is_resolved = path_fit;
Jim Ingham0909e5f2010-09-16 00:57:33 +0000252 }
253 else
254 {
Greg Clayton7481c202010-11-08 00:28:40 +0000255 // Copy the path because "basename" and "dirname" want to muck with the
256 // path buffer
257 if (::strlen (pathname) > sizeof(resolved_path) - 1)
Jim Ingham0909e5f2010-09-16 00:57:33 +0000258 path_fit = false;
259 else
Greg Clayton7481c202010-11-08 00:28:40 +0000260 ::strcpy (resolved_path, pathname);
Jim Ingham0909e5f2010-09-16 00:57:33 +0000261 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000262
Jim Ingham0909e5f2010-09-16 00:57:33 +0000263
264 if (path_fit)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000265 {
266 char *filename = ::basename (resolved_path);
267 if (filename)
268 {
269 m_filename.SetCString (filename);
270 // Truncate the basename off the end of the resolved path
271
272 // Only attempt to get the dirname if it looks like we have a path
273 if (strchr(resolved_path, '/'))
274 {
275 char *directory = ::dirname (resolved_path);
276
277 // Make sure we didn't get our directory resolved to "." without having
278 // specified
279 if (directory)
280 m_directory.SetCString(directory);
281 else
282 {
283 char *last_resolved_path_slash = strrchr(resolved_path, '/');
284 if (last_resolved_path_slash)
285 {
286 *last_resolved_path_slash = '\0';
287 m_directory.SetCString(resolved_path);
288 }
289 }
290 }
291 }
292 else
293 m_directory.SetCString(resolved_path);
294 }
295}
296
297//----------------------------------------------------------------------
298// Convert to pointer operator. This allows code to check any FileSpec
299// objects to see if they contain anything valid using code such as:
300//
301// if (file_spec)
302// {}
303//----------------------------------------------------------------------
304FileSpec::operator
305void*() const
306{
307 return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL;
308}
309
310//----------------------------------------------------------------------
311// Logical NOT operator. This allows code to check any FileSpec
312// objects to see if they are invalid using code such as:
313//
314// if (!file_spec)
315// {}
316//----------------------------------------------------------------------
317bool
318FileSpec::operator!() const
319{
320 return !m_directory && !m_filename;
321}
322
323//------------------------------------------------------------------
324// Equal to operator
325//------------------------------------------------------------------
326bool
327FileSpec::operator== (const FileSpec& rhs) const
328{
Greg Clayton7481c202010-11-08 00:28:40 +0000329 if (m_filename == rhs.m_filename)
330 {
331 if (m_directory == rhs.m_directory)
332 return true;
333
334 // TODO: determine if we want to keep this code in here.
335 // The code below was added to handle a case where we were
336 // trying to set a file and line breakpoint and one path
337 // was resolved, and the other not and the directory was
338 // in a mount point that resolved to a more complete path:
339 // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
340 // this out...
341 if (IsResolved() && rhs.IsResolved())
342 {
343 // Both paths are resolved, no need to look further...
344 return false;
345 }
346
347 FileSpec resolved_lhs(*this);
348
349 // If "this" isn't resolved, resolve it
350 if (!IsResolved())
351 {
352 if (resolved_lhs.ResolvePath())
353 {
354 // This path wasn't resolved but now it is. Check if the resolved
355 // directory is the same as our unresolved directory, and if so,
356 // we can mark this object as resolved to avoid more future resolves
357 m_is_resolved = (m_directory == resolved_lhs.m_directory);
358 }
359 else
360 return false;
361 }
362
363 FileSpec resolved_rhs(rhs);
364 if (!rhs.IsResolved())
365 {
366 if (resolved_rhs.ResolvePath())
367 {
368 // rhs's path wasn't resolved but now it is. Check if the resolved
369 // directory is the same as rhs's unresolved directory, and if so,
370 // we can mark this object as resolved to avoid more future resolves
371 rhs.m_is_resolved = (m_directory == resolved_rhs.m_directory);
372 }
373 else
374 return false;
375 }
376
377 // If we reach this point in the code we were able to resolve both paths
378 // and since we only resolve the paths if the basenames are equal, then
379 // we can just check if both directories are equal...
380 return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory();
381 }
382 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000383}
384
385//------------------------------------------------------------------
386// Not equal to operator
387//------------------------------------------------------------------
388bool
389FileSpec::operator!= (const FileSpec& rhs) const
390{
Greg Clayton7481c202010-11-08 00:28:40 +0000391 return !(*this == rhs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000392}
393
394//------------------------------------------------------------------
395// Less than operator
396//------------------------------------------------------------------
397bool
398FileSpec::operator< (const FileSpec& rhs) const
399{
400 return FileSpec::Compare(*this, rhs, true) < 0;
401}
402
403//------------------------------------------------------------------
404// Dump a FileSpec object to a stream
405//------------------------------------------------------------------
406Stream&
407lldb_private::operator << (Stream &s, const FileSpec& f)
408{
409 f.Dump(&s);
410 return s;
411}
412
413//------------------------------------------------------------------
414// Clear this object by releasing both the directory and filename
415// string values and making them both the empty string.
416//------------------------------------------------------------------
417void
418FileSpec::Clear()
419{
420 m_directory.Clear();
421 m_filename.Clear();
422}
423
424//------------------------------------------------------------------
425// Compare two FileSpec objects. If "full" is true, then both
426// the directory and the filename must match. If "full" is false,
427// then the directory names for "a" and "b" are only compared if
428// they are both non-empty. This allows a FileSpec object to only
429// contain a filename and it can match FileSpec objects that have
430// matching filenames with different paths.
431//
432// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
433// and "1" if "a" is greater than "b".
434//------------------------------------------------------------------
435int
436FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
437{
438 int result = 0;
439
440 // If full is true, then we must compare both the directory and filename.
441
442 // If full is false, then if either directory is empty, then we match on
443 // the basename only, and if both directories have valid values, we still
444 // do a full compare. This allows for matching when we just have a filename
445 // in one of the FileSpec objects.
446
447 if (full || (a.m_directory && b.m_directory))
448 {
449 result = ConstString::Compare(a.m_directory, b.m_directory);
450 if (result)
451 return result;
452 }
453 return ConstString::Compare (a.m_filename, b.m_filename);
454}
455
456bool
457FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
458{
459 if (full)
460 return a == b;
461 else
462 return a.m_filename == b.m_filename;
463}
464
465
466
467//------------------------------------------------------------------
468// Dump the object to the supplied stream. If the object contains
469// a valid directory name, it will be displayed followed by a
470// directory delimiter, and the filename.
471//------------------------------------------------------------------
472void
473FileSpec::Dump(Stream *s) const
474{
475 if (m_filename)
476 m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid
477
478 if (m_directory)
479 {
480 // If dirname was valid, then we need to print a slash between
481 // the directory and the filename
482 s->PutChar('/');
483 }
484 m_filename.Dump(s);
485}
486
487//------------------------------------------------------------------
488// Returns true if the file exists.
489//------------------------------------------------------------------
490bool
491FileSpec::Exists () const
492{
493 struct stat file_stats;
494 return GetFileStats (this, &file_stats);
495}
496
Caroline Tice428a9a52010-09-10 04:48:55 +0000497bool
498FileSpec::ResolveExecutableLocation ()
499{
Greg Clayton274060b2010-10-20 20:54:39 +0000500 if (!m_directory)
Caroline Tice391a9602010-09-12 00:10:52 +0000501 {
Greg Clayton58f41712011-01-25 21:32:01 +0000502 const char *file_cstr = m_filename.GetCString();
503 if (file_cstr)
Caroline Tice391a9602010-09-12 00:10:52 +0000504 {
Greg Clayton58f41712011-01-25 21:32:01 +0000505 const std::string file_str (file_cstr);
506 llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str);
507 const std::string &path_str = path.str();
508 llvm::StringRef dir_ref = llvm::sys::path::parent_path(path_str);
509 //llvm::StringRef dir_ref = path.getDirname();
510 if (! dir_ref.empty())
Caroline Tice391a9602010-09-12 00:10:52 +0000511 {
Greg Clayton58f41712011-01-25 21:32:01 +0000512 // FindProgramByName returns "." if it can't find the file.
513 if (strcmp (".", dir_ref.data()) == 0)
514 return false;
515
516 m_directory.SetCString (dir_ref.data());
517 if (Exists())
Caroline Tice391a9602010-09-12 00:10:52 +0000518 return true;
Greg Clayton58f41712011-01-25 21:32:01 +0000519 else
520 {
521 // If FindProgramByName found the file, it returns the directory + filename in its return results.
522 // We need to separate them.
523 FileSpec tmp_file (dir_ref.data(), false);
524 if (tmp_file.Exists())
525 {
526 m_directory = tmp_file.m_directory;
527 return true;
528 }
Caroline Tice391a9602010-09-12 00:10:52 +0000529 }
530 }
531 }
532 }
533
534 return false;
Caroline Tice428a9a52010-09-10 04:48:55 +0000535}
536
Jim Ingham0909e5f2010-09-16 00:57:33 +0000537bool
538FileSpec::ResolvePath ()
539{
Greg Clayton7481c202010-11-08 00:28:40 +0000540 if (m_is_resolved)
541 return true; // We have already resolved this path
542
543 char path_buf[PATH_MAX];
Jim Ingham0909e5f2010-09-16 00:57:33 +0000544 if (!GetPath (path_buf, PATH_MAX))
545 return false;
Greg Clayton7481c202010-11-08 00:28:40 +0000546 // SetFile(...) will set m_is_resolved correctly if it can resolve the path
Jim Ingham0909e5f2010-09-16 00:57:33 +0000547 SetFile (path_buf, true);
Greg Clayton7481c202010-11-08 00:28:40 +0000548 return m_is_resolved;
Jim Ingham0909e5f2010-09-16 00:57:33 +0000549}
550
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000551uint64_t
552FileSpec::GetByteSize() const
553{
554 struct stat file_stats;
555 if (GetFileStats (this, &file_stats))
556 return file_stats.st_size;
557 return 0;
558}
559
560FileSpec::FileType
561FileSpec::GetFileType () const
562{
563 struct stat file_stats;
564 if (GetFileStats (this, &file_stats))
565 {
566 mode_t file_type = file_stats.st_mode & S_IFMT;
567 switch (file_type)
568 {
569 case S_IFDIR: return eFileTypeDirectory;
570 case S_IFIFO: return eFileTypePipe;
571 case S_IFREG: return eFileTypeRegular;
572 case S_IFSOCK: return eFileTypeSocket;
573 case S_IFLNK: return eFileTypeSymbolicLink;
574 default:
575 break;
576 }
Greg Clayton4272cc72011-02-02 02:24:04 +0000577 return eFileTypeUnknown;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000578 }
579 return eFileTypeInvalid;
580}
581
582TimeValue
583FileSpec::GetModificationTime () const
584{
585 TimeValue mod_time;
586 struct stat file_stats;
587 if (GetFileStats (this, &file_stats))
Eli Friedman6abb6342010-06-11 04:52:22 +0000588 mod_time.OffsetWithSeconds(file_stats.st_mtime);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000589 return mod_time;
590}
591
592//------------------------------------------------------------------
593// Directory string get accessor.
594//------------------------------------------------------------------
595ConstString &
596FileSpec::GetDirectory()
597{
598 return m_directory;
599}
600
601//------------------------------------------------------------------
602// Directory string const get accessor.
603//------------------------------------------------------------------
604const ConstString &
605FileSpec::GetDirectory() const
606{
607 return m_directory;
608}
609
610//------------------------------------------------------------------
611// Filename string get accessor.
612//------------------------------------------------------------------
613ConstString &
614FileSpec::GetFilename()
615{
616 return m_filename;
617}
618
619//------------------------------------------------------------------
620// Filename string const get accessor.
621//------------------------------------------------------------------
622const ConstString &
623FileSpec::GetFilename() const
624{
625 return m_filename;
626}
627
628//------------------------------------------------------------------
629// Extract the directory and path into a fixed buffer. This is
630// needed as the directory and path are stored in separate string
631// values.
632//------------------------------------------------------------------
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000633size_t
634FileSpec::GetPath(char *path, size_t path_max_len) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000635{
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000636 if (path_max_len)
Greg Claytondd36def2010-10-17 22:03:32 +0000637 {
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000638 const char *dirname = m_directory.GetCString();
639 const char *filename = m_filename.GetCString();
Greg Claytondd36def2010-10-17 22:03:32 +0000640 if (dirname)
641 {
642 if (filename)
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000643 return ::snprintf (path, path_max_len, "%s/%s", dirname, filename);
Greg Claytondd36def2010-10-17 22:03:32 +0000644 else
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000645 return ::snprintf (path, path_max_len, "%s", dirname);
Greg Claytondd36def2010-10-17 22:03:32 +0000646 }
647 else if (filename)
648 {
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000649 return ::snprintf (path, path_max_len, "%s", filename);
Greg Claytondd36def2010-10-17 22:03:32 +0000650 }
651 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000652 path[0] = '\0';
Greg Claytoncfd1ace2010-10-31 03:01:06 +0000653 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000654}
655
656//------------------------------------------------------------------
657// Returns a shared pointer to a data buffer that contains all or
658// part of the contents of a file. The data is memory mapped and
659// will lazily page in data from the file as memory is accessed.
660// The data that is mappped will start "file_offset" bytes into the
661// file, and "file_size" bytes will be mapped. If "file_size" is
662// greater than the number of bytes available in the file starting
663// at "file_offset", the number of bytes will be appropriately
664// truncated. The final number of bytes that get mapped can be
665// verified using the DataBuffer::GetByteSize() function.
666//------------------------------------------------------------------
667DataBufferSP
668FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
669{
670 DataBufferSP data_sp;
671 auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
672 if (mmap_data.get())
673 {
674 if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= file_size)
675 data_sp.reset(mmap_data.release());
676 }
677 return data_sp;
678}
679
680
681//------------------------------------------------------------------
682// Return the size in bytes that this object takes in memory. This
683// returns the size in bytes of this object, not any shared string
684// values it may refer to.
685//------------------------------------------------------------------
686size_t
687FileSpec::MemorySize() const
688{
689 return m_filename.MemorySize() + m_directory.MemorySize();
690}
691
Greg Claytondda4f7b2010-06-30 23:03:03 +0000692
693size_t
694FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000695{
Greg Claytondda4f7b2010-06-30 23:03:03 +0000696 size_t bytes_read = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000697 char resolved_path[PATH_MAX];
698 if (GetPath(resolved_path, sizeof(resolved_path)))
699 {
700 int fd = ::open (resolved_path, O_RDONLY, 0);
701 if (fd != -1)
702 {
703 struct stat file_stats;
704 if (::fstat (fd, &file_stats) == 0)
705 {
706 // Read bytes directly into our basic_string buffer
707 if (file_stats.st_size > 0)
708 {
709 off_t lseek_result = 0;
710 if (file_offset > 0)
711 lseek_result = ::lseek (fd, file_offset, SEEK_SET);
712
Greg Claytondda4f7b2010-06-30 23:03:03 +0000713 if (lseek_result == file_offset)
714 {
715 ssize_t n = ::read (fd, dst, dst_len);
716 if (n >= 0)
717 bytes_read = n;
718 }
719 }
720 }
721 }
722 close(fd);
723 }
724 return bytes_read;
725}
726
727//------------------------------------------------------------------
728// Returns a shared pointer to a data buffer that contains all or
729// part of the contents of a file. The data copies into a heap based
730// buffer that lives in the DataBuffer shared pointer object returned.
731// The data that is cached will start "file_offset" bytes into the
732// file, and "file_size" bytes will be mapped. If "file_size" is
733// greater than the number of bytes available in the file starting
734// at "file_offset", the number of bytes will be appropriately
735// truncated. The final number of bytes that get mapped can be
736// verified using the DataBuffer::GetByteSize() function.
737//------------------------------------------------------------------
738DataBufferSP
739FileSpec::ReadFileContents (off_t file_offset, size_t file_size) const
740{
741 DataBufferSP data_sp;
742 char resolved_path[PATH_MAX];
743 if (GetPath(resolved_path, sizeof(resolved_path)))
744 {
745 int fd = ::open (resolved_path, O_RDONLY, 0);
746 if (fd != -1)
747 {
748 struct stat file_stats;
749 if (::fstat (fd, &file_stats) == 0)
750 {
751 if (file_stats.st_size > 0)
752 {
753 off_t lseek_result = 0;
754 if (file_offset > 0)
755 lseek_result = ::lseek (fd, file_offset, SEEK_SET);
756
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000757 if (lseek_result < 0)
758 {
759 // Get error from errno
760 }
761 else if (lseek_result == file_offset)
762 {
Greg Claytondda4f7b2010-06-30 23:03:03 +0000763 const size_t bytes_left = file_stats.st_size - file_offset;
764 size_t num_bytes_to_read = file_size;
765 if (num_bytes_to_read > bytes_left)
766 num_bytes_to_read = bytes_left;
767
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000768 std::auto_ptr<DataBufferHeap> data_heap_ap;
Greg Claytondda4f7b2010-06-30 23:03:03 +0000769 data_heap_ap.reset(new DataBufferHeap(num_bytes_to_read, '\0'));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000770
771 if (data_heap_ap.get())
772 {
773 ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize());
774 if (bytesRead >= 0)
775 {
776 // Make sure we read exactly what we asked for and if we got
777 // less, adjust the array
Greg Claytonc982c762010-07-09 20:39:50 +0000778 if ((size_t)bytesRead < data_heap_ap->GetByteSize())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000779 data_heap_ap->SetByteSize(bytesRead);
780 data_sp.reset(data_heap_ap.release());
781 }
782 }
783 }
784 }
785 }
786 }
787 close(fd);
788 }
789 return data_sp;
790}
791
Greg Clayton58fc50e2010-10-20 22:52:05 +0000792size_t
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000793FileSpec::ReadFileLines (STLStringArray &lines)
794{
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000795 lines.clear();
Greg Clayton58fc50e2010-10-20 22:52:05 +0000796 char path[PATH_MAX];
797 if (GetPath(path, sizeof(path)))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000798 {
Greg Clayton58fc50e2010-10-20 22:52:05 +0000799 ifstream file_stream (path);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000800
Greg Clayton58fc50e2010-10-20 22:52:05 +0000801 if (file_stream)
802 {
803 std::string line;
804 while (getline (file_stream, line))
805 lines.push_back (line);
806 }
807 }
808 return lines.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000809}
Greg Clayton4272cc72011-02-02 02:24:04 +0000810
811FileSpec::EnumerateDirectoryResult
812FileSpec::EnumerateDirectory
813(
814 const char *dir_path,
815 bool find_directories,
816 bool find_files,
817 bool find_other,
818 EnumerateDirectoryCallbackType callback,
819 void *callback_baton
820)
821{
822 if (dir_path && dir_path[0])
823 {
824 lldb_utility::CleanUp <DIR *, int> dir_path_dir (opendir(dir_path), NULL, closedir);
825 if (dir_path_dir.is_valid())
826 {
827 struct dirent* dp;
828 while ((dp = readdir(dir_path_dir.get())) != NULL)
829 {
830 // Only search directories
831 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
832 {
833 if (dp->d_namlen == 1 && dp->d_name[0] == '.')
834 continue;
835
836 if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
837 continue;
838 }
839
840 bool call_callback = false;
841 FileSpec::FileType file_type = eFileTypeUnknown;
842
843 switch (dp->d_type)
844 {
845 default:
846 case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break;
847 case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break;
848 case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break;
849 case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break;
850 case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break;
851 case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break;
852 case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break;
853 case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break;
854 case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break;
855 }
856
857 if (call_callback)
858 {
859 char child_path[PATH_MAX];
860 const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
861 if (child_path_len < sizeof(child_path) - 1)
862 {
863 // Don't resolve the file type or path
864 FileSpec child_path_spec (child_path, false);
865
866 EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
867
868 switch (result)
869 {
870 default:
871 case eEnumerateDirectoryResultNext:
872 // Enumerate next entry in the current directory. We just
873 // exit this switch and will continue enumerating the
874 // current directory as we currently are...
875 break;
876
877 case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
878 if (FileSpec::EnumerateDirectory (child_path,
879 find_directories,
880 find_files,
881 find_other,
882 callback,
883 callback_baton) == eEnumerateDirectoryResultQuit)
884 {
885 // The subdirectory returned Quit, which means to
886 // stop all directory enumerations at all levels.
887 return eEnumerateDirectoryResultQuit;
888 }
889 break;
890
891 case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
892 // Exit from this directory level and tell parent to
893 // keep enumerating.
894 return eEnumerateDirectoryResultNext;
895
896 case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
897 return eEnumerateDirectoryResultQuit;
898 }
899 }
900 }
901 }
902 }
903 }
904 // By default when exiting a directory, we tell the parent enumeration
905 // to continue enumerating.
906 return eEnumerateDirectoryResultNext;
907}
908