]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp
Merge ^/head r274961 through r276342.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Host / common / FileSpec.cpp
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 #ifndef _WIN32
12 #include <dirent.h>
13 #else
14 #include "lldb/Host/windows/windows.h"
15 #endif
16 #include <fcntl.h>
17 #ifndef _MSC_VER
18 #include <libgen.h>
19 #endif
20 #include <sys/stat.h>
21 #include <set>
22 #include <string.h>
23 #include <fstream>
24
25 #include "lldb/Host/Config.h" // Have to include this before we test the define...
26 #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
27 #include <pwd.h>
28 #endif
29
30 #include "lldb/Core/DataBufferHeap.h"
31 #include "lldb/Core/DataBufferMemoryMap.h"
32 #include "lldb/Core/RegularExpression.h"
33 #include "lldb/Core/StreamString.h"
34 #include "lldb/Core/Stream.h"
35 #include "lldb/Host/File.h"
36 #include "lldb/Host/FileSpec.h"
37 #include "lldb/Host/FileSystem.h"
38 #include "lldb/Host/Host.h"
39 #include "lldb/Utility/CleanUp.h"
40
41 #include "llvm/ADT/StringRef.h"
42 #include "llvm/Support/FileSystem.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/Program.h"
45
46 using namespace lldb;
47 using namespace lldb_private;
48
49 static bool
50 GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
51 {
52     char resolved_path[PATH_MAX];
53     if (file_spec->GetPath (resolved_path, sizeof(resolved_path)))
54         return ::stat (resolved_path, stats_ptr) == 0;
55     return false;
56 }
57
58 // Resolves the username part of a path of the form ~user/other/directories, and
59 // writes the result into dst_path.
60 void
61 FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
62 {
63 #if LLDB_CONFIG_TILDE_RESOLVES_TO_USER
64     if (path.empty() || path[0] != '~')
65         return;
66     
67     llvm::StringRef path_str(path.data());
68     size_t slash_pos = path_str.find_first_of("/", 1);
69     if (slash_pos == 1)
70     {
71         // A path of the form ~/ resolves to the current user's home dir
72         llvm::SmallString<64> home_dir;
73         if (!llvm::sys::path::home_directory(home_dir))
74             return;
75         
76         // Overwrite the ~ with the first character of the homedir, and insert
77         // the rest.  This way we only trigger one move, whereas an insert
78         // followed by a delete (or vice versa) would trigger two.
79         path[0] = home_dir[0];
80         path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end());
81         return;
82     }
83     
84     auto username_begin = path.begin()+1;
85     auto username_end = (slash_pos == llvm::StringRef::npos)
86                         ? path.end()
87                         : (path.begin() + slash_pos);
88     size_t replacement_length = std::distance(path.begin(), username_end);
89
90     llvm::SmallString<20> username(username_begin, username_end);
91     struct passwd *user_entry = ::getpwnam(username.c_str());
92     if (user_entry != nullptr)
93     {
94         // Copy over the first n characters of the path, where n is the smaller of the length
95         // of the home directory and the slash pos.
96         llvm::StringRef homedir(user_entry->pw_dir);
97         size_t initial_copy_length = std::min(homedir.size(), replacement_length);
98         auto src_begin = homedir.begin();
99         auto src_end = src_begin + initial_copy_length;
100         std::copy(src_begin, src_end, path.begin());
101         if (replacement_length > homedir.size())
102         {
103             // We copied the entire home directory, but the ~username portion of the path was
104             // longer, so there's characters that need to be removed.
105             path.erase(path.begin() + initial_copy_length, username_end);
106         }
107         else if (replacement_length < homedir.size())
108         {
109             // We copied all the way up to the slash in the destination, but there's still more
110             // characters that need to be inserted.
111             path.insert(username_end, src_end, homedir.end());
112         }
113     }
114     else
115     {
116         // Unable to resolve username (user doesn't exist?)
117         path.clear();
118     }
119 #endif
120 }
121
122 size_t
123 FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches)
124 {
125 #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
126     size_t extant_entries = matches.GetSize();
127     
128     setpwent();
129     struct passwd *user_entry;
130     const char *name_start = partial_name + 1;
131     std::set<std::string> name_list;
132     
133     while ((user_entry = getpwent()) != NULL)
134     {
135         if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name)
136         {
137             std::string tmp_buf("~");
138             tmp_buf.append(user_entry->pw_name);
139             tmp_buf.push_back('/');
140             name_list.insert(tmp_buf);                    
141         }
142     }
143     std::set<std::string>::iterator pos, end = name_list.end();
144     for (pos = name_list.begin(); pos != end; pos++)
145     {  
146         matches.AppendString((*pos).c_str());
147     }
148     return matches.GetSize() - extant_entries;
149 #else
150     // Resolving home directories is not supported, just copy the path...
151     return 0;
152 #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER    
153 }
154
155 void
156 FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
157 {
158     if (path.empty())
159         return;
160
161 #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
162     if (path[0] == '~')
163         ResolveUsername(path);
164 #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
165
166     llvm::sys::fs::make_absolute(path);
167 }
168
169 FileSpec::FileSpec()
170     : m_directory()
171     , m_filename()
172     , m_syntax(FileSystem::GetNativePathSyntax())
173 {
174 }
175
176 //------------------------------------------------------------------
177 // Default constructor that can take an optional full path to a
178 // file on disk.
179 //------------------------------------------------------------------
180 FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
181     m_directory(),
182     m_filename(),
183     m_is_resolved(false)
184 {
185     if (pathname && pathname[0])
186         SetFile(pathname, resolve_path, syntax);
187 }
188
189 //------------------------------------------------------------------
190 // Copy constructor
191 //------------------------------------------------------------------
192 FileSpec::FileSpec(const FileSpec& rhs) :
193     m_directory (rhs.m_directory),
194     m_filename (rhs.m_filename),
195     m_is_resolved (rhs.m_is_resolved),
196     m_syntax (rhs.m_syntax)
197 {
198 }
199
200 //------------------------------------------------------------------
201 // Copy constructor
202 //------------------------------------------------------------------
203 FileSpec::FileSpec(const FileSpec* rhs) :
204     m_directory(),
205     m_filename()
206 {
207     if (rhs)
208         *this = *rhs;
209 }
210
211 //------------------------------------------------------------------
212 // Virtual destructor in case anyone inherits from this class.
213 //------------------------------------------------------------------
214 FileSpec::~FileSpec()
215 {
216 }
217
218 //------------------------------------------------------------------
219 // Assignment operator.
220 //------------------------------------------------------------------
221 const FileSpec&
222 FileSpec::operator= (const FileSpec& rhs)
223 {
224     if (this != &rhs)
225     {
226         m_directory = rhs.m_directory;
227         m_filename = rhs.m_filename;
228         m_is_resolved = rhs.m_is_resolved;
229         m_syntax = rhs.m_syntax;
230     }
231     return *this;
232 }
233
234 void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
235 {
236     if (syntax == ePathSyntaxPosix ||
237         (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
238         return;
239
240     std::replace(path.begin(), path.end(), '\\', '/');
241 }
242
243 void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
244 {
245     if (syntax == ePathSyntaxPosix ||
246         (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
247         return;
248
249     std::replace(path.begin(), path.end(), '/', '\\');
250 }
251
252 //------------------------------------------------------------------
253 // Update the contents of this object with a new path. The path will
254 // be split up into a directory and filename and stored as uniqued
255 // string values for quick comparison and efficient memory usage.
256 //------------------------------------------------------------------
257 void
258 FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
259 {
260     m_filename.Clear();
261     m_directory.Clear();
262     m_is_resolved = false;
263     m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax;
264
265     if (pathname == NULL || pathname[0] == '\0')
266         return;
267
268     llvm::SmallString<64> normalized(pathname);
269     Normalize(normalized, syntax);
270
271     if (resolve)
272     {
273         FileSpec::Resolve (normalized);
274         m_is_resolved = true;
275     }
276     
277     llvm::StringRef resolve_path_ref(normalized.c_str());
278     llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
279     if (!filename_ref.empty())
280     {
281         m_filename.SetString (filename_ref);
282         llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref);
283         if (!directory_ref.empty())
284             m_directory.SetString(directory_ref);
285     }
286     else
287         m_directory.SetCString(normalized.c_str());
288 }
289
290 //----------------------------------------------------------------------
291 // Convert to pointer operator. This allows code to check any FileSpec
292 // objects to see if they contain anything valid using code such as:
293 //
294 //  if (file_spec)
295 //  {}
296 //----------------------------------------------------------------------
297 FileSpec::operator bool() const
298 {
299     return m_filename || m_directory;
300 }
301
302 //----------------------------------------------------------------------
303 // Logical NOT operator. This allows code to check any FileSpec
304 // objects to see if they are invalid using code such as:
305 //
306 //  if (!file_spec)
307 //  {}
308 //----------------------------------------------------------------------
309 bool
310 FileSpec::operator!() const
311 {
312     return !m_directory && !m_filename;
313 }
314
315 //------------------------------------------------------------------
316 // Equal to operator
317 //------------------------------------------------------------------
318 bool
319 FileSpec::operator== (const FileSpec& rhs) const
320 {
321     if (m_filename == rhs.m_filename)
322     {
323         if (m_directory == rhs.m_directory)
324             return true;
325         
326         // TODO: determine if we want to keep this code in here.
327         // The code below was added to handle a case where we were
328         // trying to set a file and line breakpoint and one path
329         // was resolved, and the other not and the directory was
330         // in a mount point that resolved to a more complete path:
331         // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
332         // this out...
333         if (IsResolved() && rhs.IsResolved())
334         {
335             // Both paths are resolved, no need to look further...
336             return false;
337         }
338         
339         FileSpec resolved_lhs(*this);
340
341         // If "this" isn't resolved, resolve it
342         if (!IsResolved())
343         {
344             if (resolved_lhs.ResolvePath())
345             {
346                 // This path wasn't resolved but now it is. Check if the resolved
347                 // directory is the same as our unresolved directory, and if so, 
348                 // we can mark this object as resolved to avoid more future resolves
349                 m_is_resolved = (m_directory == resolved_lhs.m_directory);
350             }
351             else
352                 return false;
353         }
354         
355         FileSpec resolved_rhs(rhs);
356         if (!rhs.IsResolved())
357         {
358             if (resolved_rhs.ResolvePath())
359             {
360                 // rhs's path wasn't resolved but now it is. Check if the resolved
361                 // directory is the same as rhs's unresolved directory, and if so, 
362                 // we can mark this object as resolved to avoid more future resolves
363                 rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
364             }
365             else
366                 return false;
367         }
368
369         // If we reach this point in the code we were able to resolve both paths
370         // and since we only resolve the paths if the basenames are equal, then
371         // we can just check if both directories are equal...
372         return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory();
373     }
374     return false;
375 }
376
377 //------------------------------------------------------------------
378 // Not equal to operator
379 //------------------------------------------------------------------
380 bool
381 FileSpec::operator!= (const FileSpec& rhs) const
382 {
383     return !(*this == rhs);
384 }
385
386 //------------------------------------------------------------------
387 // Less than operator
388 //------------------------------------------------------------------
389 bool
390 FileSpec::operator< (const FileSpec& rhs) const
391 {
392     return FileSpec::Compare(*this, rhs, true) < 0;
393 }
394
395 //------------------------------------------------------------------
396 // Dump a FileSpec object to a stream
397 //------------------------------------------------------------------
398 Stream&
399 lldb_private::operator << (Stream &s, const FileSpec& f)
400 {
401     f.Dump(&s);
402     return s;
403 }
404
405 //------------------------------------------------------------------
406 // Clear this object by releasing both the directory and filename
407 // string values and making them both the empty string.
408 //------------------------------------------------------------------
409 void
410 FileSpec::Clear()
411 {
412     m_directory.Clear();
413     m_filename.Clear();
414 }
415
416 //------------------------------------------------------------------
417 // Compare two FileSpec objects. If "full" is true, then both
418 // the directory and the filename must match. If "full" is false,
419 // then the directory names for "a" and "b" are only compared if
420 // they are both non-empty. This allows a FileSpec object to only
421 // contain a filename and it can match FileSpec objects that have
422 // matching filenames with different paths.
423 //
424 // Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
425 // and "1" if "a" is greater than "b".
426 //------------------------------------------------------------------
427 int
428 FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
429 {
430     int result = 0;
431
432     // If full is true, then we must compare both the directory and filename.
433
434     // If full is false, then if either directory is empty, then we match on
435     // the basename only, and if both directories have valid values, we still
436     // do a full compare. This allows for matching when we just have a filename
437     // in one of the FileSpec objects.
438
439     if (full || (a.m_directory && b.m_directory))
440     {
441         result = ConstString::Compare(a.m_directory, b.m_directory);
442         if (result)
443             return result;
444     }
445     return ConstString::Compare (a.m_filename, b.m_filename);
446 }
447
448 bool
449 FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
450 {
451     if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
452         return a.m_filename == b.m_filename;
453     else
454         return a == b;
455 }
456
457
458
459 //------------------------------------------------------------------
460 // Dump the object to the supplied stream. If the object contains
461 // a valid directory name, it will be displayed followed by a
462 // directory delimiter, and the filename.
463 //------------------------------------------------------------------
464 void
465 FileSpec::Dump(Stream *s) const
466 {
467     static ConstString g_slash_only ("/");
468     if (s)
469     {
470         m_directory.Dump(s);
471         if (m_directory && m_directory != g_slash_only)
472             s->PutChar('/');
473         m_filename.Dump(s);
474     }
475 }
476
477 //------------------------------------------------------------------
478 // Returns true if the file exists.
479 //------------------------------------------------------------------
480 bool
481 FileSpec::Exists () const
482 {
483     struct stat file_stats;
484     return GetFileStats (this, &file_stats);
485 }
486
487 bool
488 FileSpec::Readable () const
489 {
490     const uint32_t permissions = GetPermissions();
491     if (permissions & eFilePermissionsEveryoneR)
492         return true;
493     return false;
494 }
495
496 bool
497 FileSpec::ResolveExecutableLocation ()
498 {
499     if (!m_directory)
500     {
501         const char *file_cstr = m_filename.GetCString();
502         if (file_cstr)
503         {
504             const std::string file_str (file_cstr);
505             std::string path = llvm::sys::FindProgramByName (file_str);
506             llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
507             if (!dir_ref.empty())
508             {
509                 // FindProgramByName returns "." if it can't find the file.
510                 if (strcmp (".", dir_ref.data()) == 0)
511                     return false;
512
513                 m_directory.SetCString (dir_ref.data());
514                 if (Exists())
515                     return true;
516                 else
517                 {
518                     // If FindProgramByName found the file, it returns the directory + filename in its return results.
519                     // We need to separate them.
520                     FileSpec tmp_file (dir_ref.data(), false);
521                     if (tmp_file.Exists())
522                     {
523                         m_directory = tmp_file.m_directory;
524                         return true;
525                     }
526                 }
527             }
528         }
529     }
530     
531     return false;
532 }
533
534 bool
535 FileSpec::ResolvePath ()
536 {
537     if (m_is_resolved)
538         return true;    // We have already resolved this path
539
540     char path_buf[PATH_MAX];    
541     if (!GetPath (path_buf, PATH_MAX, false))
542         return false;
543     // SetFile(...) will set m_is_resolved correctly if it can resolve the path
544     SetFile (path_buf, true);
545     return m_is_resolved; 
546 }
547
548 uint64_t
549 FileSpec::GetByteSize() const
550 {
551     struct stat file_stats;
552     if (GetFileStats (this, &file_stats))
553         return file_stats.st_size;
554     return 0;
555 }
556
557 FileSpec::PathSyntax
558 FileSpec::GetPathSyntax() const
559 {
560     return m_syntax;
561 }
562
563 FileSpec::FileType
564 FileSpec::GetFileType () const
565 {
566     struct stat file_stats;
567     if (GetFileStats (this, &file_stats))
568     {
569         mode_t file_type = file_stats.st_mode & S_IFMT;
570         switch (file_type)
571         {
572         case S_IFDIR:   return eFileTypeDirectory;
573         case S_IFREG:   return eFileTypeRegular;
574 #ifndef _WIN32
575         case S_IFIFO:   return eFileTypePipe;
576         case S_IFSOCK:  return eFileTypeSocket;
577         case S_IFLNK:   return eFileTypeSymbolicLink;
578 #endif
579         default:
580             break;
581         }
582         return eFileTypeUnknown;
583     }
584     return eFileTypeInvalid;
585 }
586
587 uint32_t
588 FileSpec::GetPermissions () const
589 {
590     uint32_t file_permissions = 0;
591     if (*this)
592         FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions);
593     return file_permissions;
594 }
595
596 TimeValue
597 FileSpec::GetModificationTime () const
598 {
599     TimeValue mod_time;
600     struct stat file_stats;
601     if (GetFileStats (this, &file_stats))
602         mod_time.OffsetWithSeconds(file_stats.st_mtime);
603     return mod_time;
604 }
605
606 //------------------------------------------------------------------
607 // Directory string get accessor.
608 //------------------------------------------------------------------
609 ConstString &
610 FileSpec::GetDirectory()
611 {
612     return m_directory;
613 }
614
615 //------------------------------------------------------------------
616 // Directory string const get accessor.
617 //------------------------------------------------------------------
618 const ConstString &
619 FileSpec::GetDirectory() const
620 {
621     return m_directory;
622 }
623
624 //------------------------------------------------------------------
625 // Filename string get accessor.
626 //------------------------------------------------------------------
627 ConstString &
628 FileSpec::GetFilename()
629 {
630     return m_filename;
631 }
632
633 //------------------------------------------------------------------
634 // Filename string const get accessor.
635 //------------------------------------------------------------------
636 const ConstString &
637 FileSpec::GetFilename() const
638 {
639     return m_filename;
640 }
641
642 //------------------------------------------------------------------
643 // Extract the directory and path into a fixed buffer. This is
644 // needed as the directory and path are stored in separate string
645 // values.
646 //------------------------------------------------------------------
647 size_t
648 FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const
649 {
650     if (!path)
651         return 0;
652
653     std::string result = GetPath(denormalize);
654
655     size_t result_length = std::min(path_max_len-1, result.length());
656     ::strncpy(path, result.c_str(), result_length + 1);
657     return result_length;
658 }
659
660 std::string
661 FileSpec::GetPath (bool denormalize) const
662 {
663     llvm::SmallString<64> result;
664     if (m_directory)
665         result.append(m_directory.GetCString());
666     if (m_filename)
667         llvm::sys::path::append(result, m_filename.GetCString());
668     if (denormalize && !result.empty())
669         DeNormalize(result, m_syntax);
670
671     return std::string(result.begin(), result.end());
672 }
673
674 ConstString
675 FileSpec::GetFileNameExtension () const
676 {
677     if (m_filename)
678     {
679         const char *filename = m_filename.GetCString();
680         const char* dot_pos = strrchr(filename, '.');
681         if (dot_pos && dot_pos[1] != '\0')
682             return ConstString(dot_pos+1);
683     }
684     return ConstString();
685 }
686
687 ConstString
688 FileSpec::GetFileNameStrippingExtension () const
689 {
690     const char *filename = m_filename.GetCString();
691     if (filename == NULL)
692         return ConstString();
693     
694     const char* dot_pos = strrchr(filename, '.');
695     if (dot_pos == NULL)
696         return m_filename;
697     
698     return ConstString(filename, dot_pos-filename);
699 }
700
701 //------------------------------------------------------------------
702 // Returns a shared pointer to a data buffer that contains all or
703 // part of the contents of a file. The data is memory mapped and
704 // will lazily page in data from the file as memory is accessed.
705 // The data that is mapped will start "file_offset" bytes into the
706 // file, and "file_size" bytes will be mapped. If "file_size" is
707 // greater than the number of bytes available in the file starting
708 // at "file_offset", the number of bytes will be appropriately
709 // truncated. The final number of bytes that get mapped can be
710 // verified using the DataBuffer::GetByteSize() function.
711 //------------------------------------------------------------------
712 DataBufferSP
713 FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
714 {
715     DataBufferSP data_sp;
716     std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
717     if (mmap_data.get())
718     {
719         const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size);
720         if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size))
721             data_sp.reset(mmap_data.release());
722     }
723     return data_sp;
724 }
725
726
727 //------------------------------------------------------------------
728 // Return the size in bytes that this object takes in memory. This
729 // returns the size in bytes of this object, not any shared string
730 // values it may refer to.
731 //------------------------------------------------------------------
732 size_t
733 FileSpec::MemorySize() const
734 {
735     return m_filename.MemorySize() + m_directory.MemorySize();
736 }
737
738
739 size_t
740 FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const
741 {
742     Error error;
743     size_t bytes_read = 0;
744     char resolved_path[PATH_MAX];
745     if (GetPath(resolved_path, sizeof(resolved_path)))
746     {
747         File file;
748         error = file.Open(resolved_path, File::eOpenOptionRead);
749         if (error.Success())
750         {
751             off_t file_offset_after_seek = file_offset;
752             bytes_read = dst_len;
753             error = file.Read(dst, bytes_read, file_offset_after_seek);
754         }
755     }
756     else
757     {
758         error.SetErrorString("invalid file specification");
759     }
760     if (error_ptr)
761         *error_ptr = error;
762     return bytes_read;
763 }
764
765 //------------------------------------------------------------------
766 // Returns a shared pointer to a data buffer that contains all or
767 // part of the contents of a file. The data copies into a heap based
768 // buffer that lives in the DataBuffer shared pointer object returned.
769 // The data that is cached will start "file_offset" bytes into the
770 // file, and "file_size" bytes will be mapped. If "file_size" is
771 // greater than the number of bytes available in the file starting
772 // at "file_offset", the number of bytes will be appropriately
773 // truncated. The final number of bytes that get mapped can be
774 // verified using the DataBuffer::GetByteSize() function.
775 //------------------------------------------------------------------
776 DataBufferSP
777 FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const
778 {
779     Error error;
780     DataBufferSP data_sp;
781     char resolved_path[PATH_MAX];
782     if (GetPath(resolved_path, sizeof(resolved_path)))
783     {
784         File file;
785         error = file.Open(resolved_path, File::eOpenOptionRead);
786         if (error.Success())
787         {
788             const bool null_terminate = false;
789             error = file.Read (file_size, file_offset, null_terminate, data_sp);
790         }
791     }
792     else
793     {
794         error.SetErrorString("invalid file specification");
795     }
796     if (error_ptr)
797         *error_ptr = error;
798     return data_sp;
799 }
800
801 DataBufferSP
802 FileSpec::ReadFileContentsAsCString(Error *error_ptr)
803 {
804     Error error;
805     DataBufferSP data_sp;
806     char resolved_path[PATH_MAX];
807     if (GetPath(resolved_path, sizeof(resolved_path)))
808     {
809         File file;
810         error = file.Open(resolved_path, File::eOpenOptionRead);
811         if (error.Success())
812         {
813             off_t offset = 0;
814             size_t length = SIZE_MAX;
815             const bool null_terminate = true;
816             error = file.Read (length, offset, null_terminate, data_sp);
817         }
818     }
819     else
820     {
821         error.SetErrorString("invalid file specification");
822     }
823     if (error_ptr)
824         *error_ptr = error;
825     return data_sp;
826 }
827
828 size_t
829 FileSpec::ReadFileLines (STLStringArray &lines)
830 {
831     lines.clear();
832     char path[PATH_MAX];
833     if (GetPath(path, sizeof(path)))
834     {
835         std::ifstream file_stream (path);
836
837         if (file_stream)
838         {
839             std::string line;
840             while (getline (file_stream, line))
841                 lines.push_back (line);
842         }
843     }
844     return lines.size();
845 }
846
847 FileSpec::EnumerateDirectoryResult
848 FileSpec::EnumerateDirectory
849 (
850     const char *dir_path, 
851     bool find_directories,
852     bool find_files,
853     bool find_other,
854     EnumerateDirectoryCallbackType callback,
855     void *callback_baton
856 )
857 {
858     if (dir_path && dir_path[0])
859     {
860 #if _WIN32
861         std::string szDir(dir_path);
862         szDir += "\\*";
863
864         WIN32_FIND_DATA ffd;
865         HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd);
866
867         if (hFind == INVALID_HANDLE_VALUE)
868         {
869             return eEnumerateDirectoryResultNext;
870         }
871
872         do
873         {
874             bool call_callback = false;
875             FileSpec::FileType file_type = eFileTypeUnknown;
876             if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
877             {
878                 size_t len = strlen(ffd.cFileName);
879
880                 if (len == 1 && ffd.cFileName[0] == '.')
881                     continue;
882
883                 if (len == 2 && ffd.cFileName[0] == '.' && ffd.cFileName[1] == '.')
884                     continue;
885
886                 file_type = eFileTypeDirectory;
887                 call_callback = find_directories;
888             }
889             else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
890             {
891                 file_type = eFileTypeOther;
892                 call_callback = find_other;
893             }
894             else
895             {
896                 file_type = eFileTypeRegular;
897                 call_callback = find_files;
898             }
899             if (call_callback)
900             {
901                 char child_path[MAX_PATH];
902                 const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName);
903                 if (child_path_len < (int)(sizeof(child_path) - 1))
904                 {
905                     // Don't resolve the file type or path
906                     FileSpec child_path_spec (child_path, false);
907
908                     EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
909
910                     switch (result)
911                     {
912                     case eEnumerateDirectoryResultNext:
913                         // Enumerate next entry in the current directory. We just
914                         // exit this switch and will continue enumerating the
915                         // current directory as we currently are...
916                         break;
917
918                     case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
919                         if (FileSpec::EnumerateDirectory(child_path,
920                             find_directories,
921                             find_files,
922                             find_other,
923                             callback,
924                             callback_baton) == eEnumerateDirectoryResultQuit)
925                         {
926                             // The subdirectory returned Quit, which means to 
927                             // stop all directory enumerations at all levels.
928                             return eEnumerateDirectoryResultQuit;
929                         }
930                         break;
931
932                     case eEnumerateDirectoryResultExit:  // Exit from the current directory at the current level.
933                         // Exit from this directory level and tell parent to 
934                         // keep enumerating.
935                         return eEnumerateDirectoryResultNext;
936
937                     case eEnumerateDirectoryResultQuit:  // Stop directory enumerations at any level
938                         return eEnumerateDirectoryResultQuit;
939                     }
940                 }
941             }
942         } while (FindNextFile(hFind, &ffd) != 0);
943
944         FindClose(hFind);
945 #else
946         lldb_utility::CleanUp <DIR *, int> dir_path_dir(opendir(dir_path), NULL, closedir);
947         if (dir_path_dir.is_valid())
948         {
949             long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX);
950 #if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN)
951             if (path_max < __DARWIN_MAXPATHLEN)
952                 path_max = __DARWIN_MAXPATHLEN;
953 #endif
954             struct dirent *buf, *dp;
955             buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1);
956
957             while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp)
958             {
959                 // Only search directories
960                 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
961                 {
962                     size_t len = strlen(dp->d_name);
963
964                     if (len == 1 && dp->d_name[0] == '.')
965                         continue;
966
967                     if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
968                         continue;
969                 }
970             
971                 bool call_callback = false;
972                 FileSpec::FileType file_type = eFileTypeUnknown;
973
974                 switch (dp->d_type)
975                 {
976                 default:
977                 case DT_UNKNOWN:    file_type = eFileTypeUnknown;       call_callback = true;               break;
978                 case DT_FIFO:       file_type = eFileTypePipe;          call_callback = find_other;         break;
979                 case DT_CHR:        file_type = eFileTypeOther;         call_callback = find_other;         break;
980                 case DT_DIR:        file_type = eFileTypeDirectory;     call_callback = find_directories;   break;
981                 case DT_BLK:        file_type = eFileTypeOther;         call_callback = find_other;         break;
982                 case DT_REG:        file_type = eFileTypeRegular;       call_callback = find_files;         break;
983                 case DT_LNK:        file_type = eFileTypeSymbolicLink;  call_callback = find_other;         break;
984                 case DT_SOCK:       file_type = eFileTypeSocket;        call_callback = find_other;         break;
985 #if !defined(__OpenBSD__)
986                 case DT_WHT:        file_type = eFileTypeOther;         call_callback = find_other;         break;
987 #endif
988                 }
989
990                 if (call_callback)
991                 {
992                     char child_path[PATH_MAX];
993                     const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
994                     if (child_path_len < (int)(sizeof(child_path) - 1))
995                     {
996                         // Don't resolve the file type or path
997                         FileSpec child_path_spec (child_path, false);
998
999                         EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
1000                         
1001                         switch (result)
1002                         {
1003                         case eEnumerateDirectoryResultNext:  
1004                             // Enumerate next entry in the current directory. We just
1005                             // exit this switch and will continue enumerating the
1006                             // current directory as we currently are...
1007                             break;
1008
1009                         case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
1010                             if (FileSpec::EnumerateDirectory (child_path, 
1011                                                               find_directories, 
1012                                                               find_files, 
1013                                                               find_other, 
1014                                                               callback, 
1015                                                               callback_baton) == eEnumerateDirectoryResultQuit)
1016                             {
1017                                 // The subdirectory returned Quit, which means to 
1018                                 // stop all directory enumerations at all levels.
1019                                 if (buf)
1020                                     free (buf);
1021                                 return eEnumerateDirectoryResultQuit;
1022                             }
1023                             break;
1024                         
1025                         case eEnumerateDirectoryResultExit:  // Exit from the current directory at the current level.
1026                             // Exit from this directory level and tell parent to 
1027                             // keep enumerating.
1028                             if (buf)
1029                                 free (buf);
1030                             return eEnumerateDirectoryResultNext;
1031
1032                         case eEnumerateDirectoryResultQuit:  // Stop directory enumerations at any level
1033                             if (buf)
1034                                 free (buf);
1035                             return eEnumerateDirectoryResultQuit;
1036                         }
1037                     }
1038                 }
1039             }
1040             if (buf)
1041             {
1042                 free (buf);
1043             }
1044         }
1045 #endif
1046     }
1047     // By default when exiting a directory, we tell the parent enumeration
1048     // to continue enumerating.
1049     return eEnumerateDirectoryResultNext;    
1050 }
1051
1052 FileSpec
1053 FileSpec::CopyByAppendingPathComponent (const char *new_path)  const
1054 {
1055     const bool resolve = false;
1056     if (m_filename.IsEmpty() && m_directory.IsEmpty())
1057         return FileSpec(new_path,resolve);
1058     StreamString stream;
1059     if (m_filename.IsEmpty())
1060         stream.Printf("%s/%s",m_directory.GetCString(),new_path);
1061     else if (m_directory.IsEmpty())
1062         stream.Printf("%s/%s",m_filename.GetCString(),new_path);
1063     else
1064         stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
1065     return FileSpec(stream.GetData(),resolve);
1066 }
1067
1068 FileSpec
1069 FileSpec::CopyByRemovingLastPathComponent ()  const
1070 {
1071     const bool resolve = false;
1072     if (m_filename.IsEmpty() && m_directory.IsEmpty())
1073         return FileSpec("",resolve);
1074     if (m_directory.IsEmpty())
1075         return FileSpec("",resolve);
1076     if (m_filename.IsEmpty())
1077     {
1078         const char* dir_cstr = m_directory.GetCString();
1079         const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
1080         
1081         // check for obvious cases before doing the full thing
1082         if (!last_slash_ptr)
1083             return FileSpec("",resolve);
1084         if (last_slash_ptr == dir_cstr)
1085             return FileSpec("/",resolve);
1086         
1087         size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
1088         ConstString new_path(dir_cstr,last_slash_pos);
1089         return FileSpec(new_path.GetCString(),resolve);
1090     }
1091     else
1092         return FileSpec(m_directory.GetCString(),resolve);
1093 }
1094
1095 ConstString
1096 FileSpec::GetLastPathComponent () const
1097 {
1098     if (m_filename)
1099         return m_filename;
1100     if (m_directory)
1101     {
1102         const char* dir_cstr = m_directory.GetCString();
1103         const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
1104         if (last_slash_ptr == NULL)
1105             return m_directory;
1106         if (last_slash_ptr == dir_cstr)
1107         {
1108             if (last_slash_ptr[1] == 0)
1109                 return ConstString(last_slash_ptr);
1110             else
1111                 return ConstString(last_slash_ptr+1);
1112         }
1113         if (last_slash_ptr[1] != 0)
1114             return ConstString(last_slash_ptr+1);
1115         const char* penultimate_slash_ptr = last_slash_ptr;
1116         while (*penultimate_slash_ptr)
1117         {
1118             --penultimate_slash_ptr;
1119             if (penultimate_slash_ptr == dir_cstr)
1120                 break;
1121             if (*penultimate_slash_ptr == '/')
1122                 break;
1123         }
1124         ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr);
1125         return result;
1126     }
1127     return ConstString();
1128 }
1129
1130 void
1131 FileSpec::AppendPathComponent (const char *new_path)
1132 {
1133     const bool resolve = false;
1134     if (m_filename.IsEmpty() && m_directory.IsEmpty())
1135     {
1136         SetFile(new_path,resolve);
1137         return;
1138     }
1139     StreamString stream;
1140     if (m_filename.IsEmpty())
1141         stream.Printf("%s/%s",m_directory.GetCString(),new_path);
1142     else if (m_directory.IsEmpty())
1143         stream.Printf("%s/%s",m_filename.GetCString(),new_path);
1144     else
1145         stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
1146     SetFile(stream.GetData(), resolve);
1147 }
1148
1149 void
1150 FileSpec::RemoveLastPathComponent ()
1151 {
1152     const bool resolve = false;
1153     if (m_filename.IsEmpty() && m_directory.IsEmpty())
1154     {
1155         SetFile("",resolve);
1156         return;
1157     }
1158     if (m_directory.IsEmpty())
1159     {
1160         SetFile("",resolve);
1161         return;
1162     }
1163     if (m_filename.IsEmpty())
1164     {
1165         const char* dir_cstr = m_directory.GetCString();
1166         const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
1167         
1168         // check for obvious cases before doing the full thing
1169         if (!last_slash_ptr)
1170         {
1171             SetFile("",resolve);
1172             return;
1173         }
1174         if (last_slash_ptr == dir_cstr)
1175         {
1176             SetFile("/",resolve);
1177             return;
1178         }        
1179         size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
1180         ConstString new_path(dir_cstr,last_slash_pos);
1181         SetFile(new_path.GetCString(),resolve);
1182     }
1183     else
1184         SetFile(m_directory.GetCString(),resolve);
1185 }
1186 //------------------------------------------------------------------
1187 /// Returns true if the filespec represents an implementation source
1188 /// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
1189 /// extension).
1190 ///
1191 /// @return
1192 ///     \b true if the filespec represents an implementation source
1193 ///     file, \b false otherwise.
1194 //------------------------------------------------------------------
1195 bool
1196 FileSpec::IsSourceImplementationFile () const
1197 {
1198     ConstString extension (GetFileNameExtension());
1199     if (extension)
1200     {
1201         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)$",
1202                                                       REG_EXTENDED | REG_ICASE);
1203         return g_source_file_regex.Execute (extension.GetCString());
1204     }
1205     return false;
1206 }
1207
1208 bool
1209 FileSpec::IsRelativeToCurrentWorkingDirectory () const
1210 {
1211     const char *directory = m_directory.GetCString();
1212     if (directory && directory[0])
1213     {
1214         // If the path doesn't start with '/' or '~', return true
1215         switch (directory[0])
1216         {
1217         case '/':
1218         case '~':
1219             return false;
1220         default:
1221             return true;
1222         }
1223     }
1224     else if (m_filename)
1225     {
1226         // No directory, just a basename, return true
1227         return true;
1228     }
1229     return false;
1230 }