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