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