blob: 21b00ae73c5d3577dcd2c1539d3e15a401a388ca [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
Caroline Tice391a9602010-09-12 00:10:52 +000021#include "llvm/ADT/StringRef.h"
22#include "llvm/System/Path.h"
23#include "llvm/System/Program.h"
24
Chris Lattner30fdc8d2010-06-08 16:52:24 +000025#include "lldb/Core/FileSpec.h"
26#include "lldb/Core/DataBufferHeap.h"
27#include "lldb/Core/DataBufferMemoryMap.h"
28#include "lldb/Core/Stream.h"
Caroline Tice428a9a52010-09-10 04:48:55 +000029#include "lldb/Host/Host.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000030
31using namespace lldb;
32using namespace lldb_private;
33using namespace std;
34
35static bool
36GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
37{
38 char resolved_path[PATH_MAX];
39 if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path)))
40 return ::stat (resolved_path, stats_ptr) == 0;
41 return false;
42}
43
44static const char*
45GetCachedGlobTildeSlash()
46{
47 static std::string g_tilde;
48 if (g_tilde.empty())
49 {
Jim Inghamf818ca32010-07-01 01:48:53 +000050 struct passwd *user_entry;
51 user_entry = getpwuid(geteuid());
52 if (user_entry != NULL)
53 g_tilde = user_entry->pw_dir;
54
Chris Lattner30fdc8d2010-06-08 16:52:24 +000055 if (g_tilde.empty())
56 return NULL;
57 }
58 return g_tilde.c_str();
59}
60
Jim Inghamf818ca32010-07-01 01:48:53 +000061// Resolves the username part of a path of the form ~user/other/directories, and
62// writes the result into dst_path.
63// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved.
64// Otherwise returns the number of characters copied into dst_path. If the return
65// is >= dst_len, then the resolved path is too long...
Greg Claytonc982c762010-07-09 20:39:50 +000066size_t
Jim Inghamf818ca32010-07-01 01:48:53 +000067FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len)
68{
69 char user_home[PATH_MAX];
70 const char *user_name;
71
72 if (src_path == NULL || src_path[0] == '\0')
73 return 0;
Greg Claytona5d24f62010-07-01 17:07:48 +000074
Jim Inghamf818ca32010-07-01 01:48:53 +000075 // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
76 if (src_path[0] != '~')
77 {
Greg Claytonc982c762010-07-09 20:39:50 +000078 size_t len = strlen (src_path);
Jim Inghamf818ca32010-07-01 01:48:53 +000079 if (len >= dst_len)
80 {
Greg Claytona5d24f62010-07-01 17:07:48 +000081 ::bcopy (src_path, dst_path, dst_len - 1);
82 dst_path[dst_len] = '\0';
Jim Inghamf818ca32010-07-01 01:48:53 +000083 }
84 else
Greg Claytona5d24f62010-07-01 17:07:48 +000085 ::bcopy (src_path, dst_path, len + 1);
86
Jim Inghamf818ca32010-07-01 01:48:53 +000087 return len;
88 }
89
Eli Friedmanfeaeebf2010-07-02 19:15:50 +000090 const char *first_slash = ::strchr (src_path, '/');
Jim Inghamf818ca32010-07-01 01:48:53 +000091 char remainder[PATH_MAX];
92
93 if (first_slash == NULL)
94 {
95 // The whole name is the username (minus the ~):
96 user_name = src_path + 1;
97 remainder[0] = '\0';
98 }
99 else
100 {
101 int user_name_len = first_slash - src_path - 1;
Greg Claytona5d24f62010-07-01 17:07:48 +0000102 ::memcpy (user_home, src_path + 1, user_name_len);
Jim Inghamf818ca32010-07-01 01:48:53 +0000103 user_home[user_name_len] = '\0';
104 user_name = user_home;
105
Greg Claytona5d24f62010-07-01 17:07:48 +0000106 ::strcpy (remainder, first_slash);
Jim Inghamf818ca32010-07-01 01:48:53 +0000107 }
Greg Claytona5d24f62010-07-01 17:07:48 +0000108
Jim Inghamf818ca32010-07-01 01:48:53 +0000109 if (user_name == NULL)
110 return 0;
111 // User name of "" means the current user...
112
113 struct passwd *user_entry;
Greg Claytonc982c762010-07-09 20:39:50 +0000114 const char *home_dir = NULL;
Jim Inghamf818ca32010-07-01 01:48:53 +0000115
116 if (user_name[0] == '\0')
117 {
118 home_dir = GetCachedGlobTildeSlash();
119 }
120 else
121 {
Greg Claytona5d24f62010-07-01 17:07:48 +0000122 user_entry = ::getpwnam (user_name);
Jim Inghamf818ca32010-07-01 01:48:53 +0000123 if (user_entry != NULL)
124 home_dir = user_entry->pw_dir;
125 }
126
127 if (home_dir == NULL)
128 return 0;
129 else
130 return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder);
131}
132
Greg Claytonc982c762010-07-09 20:39:50 +0000133size_t
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
135{
136 if (src_path == NULL || src_path[0] == '\0')
137 return 0;
138
139 // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
140 char unglobbed_path[PATH_MAX];
Jim Inghamf818ca32010-07-01 01:48:53 +0000141 if (src_path[0] == '~')
142 {
Greg Claytonc982c762010-07-09 20:39:50 +0000143 size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path));
Jim Inghamf818ca32010-07-01 01:48:53 +0000144
145 // If we couldn't find the user referred to, or the resultant path was too long,
146 // then just copy over the src_path.
147 if (return_count == 0 || return_count >= sizeof(unglobbed_path))
148 ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
149 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000150 else
151 ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
152
153 // Now resolve the path if needed
154 char resolved_path[PATH_MAX];
155 if (::realpath (unglobbed_path, resolved_path))
156 {
157 // Success, copy the resolved path
158 return ::snprintf(dst_path, dst_len, "%s", resolved_path);
159 }
160 else
161 {
162 // Failed, just copy the unglobbed path
163 return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
164 }
165}
166
167FileSpec::FileSpec() :
168 m_directory(),
169 m_filename()
170{
171}
172
173//------------------------------------------------------------------
174// Default constructor that can take an optional full path to a
175// file on disk.
176//------------------------------------------------------------------
Jim Ingham0909e5f2010-09-16 00:57:33 +0000177FileSpec::FileSpec(const char *pathname, bool resolve_path) :
178 m_directory(),
179 m_filename()
180{
181 if (pathname && pathname[0])
182 SetFile(pathname, resolve_path);
183}
184
185//------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000186// Copy constructor
187//------------------------------------------------------------------
188FileSpec::FileSpec(const FileSpec& rhs) :
189 m_directory (rhs.m_directory),
190 m_filename (rhs.m_filename)
191{
192}
193
194//------------------------------------------------------------------
195// Copy constructor
196//------------------------------------------------------------------
197FileSpec::FileSpec(const FileSpec* rhs) :
198 m_directory(),
199 m_filename()
200{
201 if (rhs)
202 *this = *rhs;
203}
204
205//------------------------------------------------------------------
206// Virtual destrcuctor in case anyone inherits from this class.
207//------------------------------------------------------------------
208FileSpec::~FileSpec()
209{
210}
211
212//------------------------------------------------------------------
213// Assignment operator.
214//------------------------------------------------------------------
215const FileSpec&
216FileSpec::operator= (const FileSpec& rhs)
217{
218 if (this != &rhs)
219 {
220 m_directory = rhs.m_directory;
221 m_filename = rhs.m_filename;
222 }
223 return *this;
224}
225
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000226//------------------------------------------------------------------
227// Update the contents of this object with a new path. The path will
228// be split up into a directory and filename and stored as uniqued
229// string values for quick comparison and efficient memory usage.
230//------------------------------------------------------------------
231void
Jim Ingham0909e5f2010-09-16 00:57:33 +0000232FileSpec::SetFile(const char *pathname, bool resolve)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000233{
234 m_filename.Clear();
235 m_directory.Clear();
236 if (pathname == NULL || pathname[0] == '\0')
237 return;
238
239 char resolved_path[PATH_MAX];
Jim Ingham0909e5f2010-09-16 00:57:33 +0000240 bool path_fit = true;
241
242 if (resolve)
243 {
244 path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1);
245 }
246 else
247 {
248 if (strlen (pathname) > sizeof(resolved_path) - 1)
249 path_fit = false;
250 else
251 strcpy (resolved_path, pathname);
252 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000253
Jim Ingham0909e5f2010-09-16 00:57:33 +0000254
255 if (path_fit)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000256 {
257 char *filename = ::basename (resolved_path);
258 if (filename)
259 {
260 m_filename.SetCString (filename);
261 // Truncate the basename off the end of the resolved path
262
263 // Only attempt to get the dirname if it looks like we have a path
264 if (strchr(resolved_path, '/'))
265 {
266 char *directory = ::dirname (resolved_path);
267
268 // Make sure we didn't get our directory resolved to "." without having
269 // specified
270 if (directory)
271 m_directory.SetCString(directory);
272 else
273 {
274 char *last_resolved_path_slash = strrchr(resolved_path, '/');
275 if (last_resolved_path_slash)
276 {
277 *last_resolved_path_slash = '\0';
278 m_directory.SetCString(resolved_path);
279 }
280 }
281 }
282 }
283 else
284 m_directory.SetCString(resolved_path);
285 }
286}
287
288//----------------------------------------------------------------------
289// Convert to pointer operator. This allows code to check any FileSpec
290// objects to see if they contain anything valid using code such as:
291//
292// if (file_spec)
293// {}
294//----------------------------------------------------------------------
295FileSpec::operator
296void*() const
297{
298 return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL;
299}
300
301//----------------------------------------------------------------------
302// Logical NOT operator. This allows code to check any FileSpec
303// objects to see if they are invalid using code such as:
304//
305// if (!file_spec)
306// {}
307//----------------------------------------------------------------------
308bool
309FileSpec::operator!() const
310{
311 return !m_directory && !m_filename;
312}
313
314//------------------------------------------------------------------
315// Equal to operator
316//------------------------------------------------------------------
317bool
318FileSpec::operator== (const FileSpec& rhs) const
319{
320 return m_directory == rhs.m_directory && m_filename == rhs.m_filename;
321}
322
323//------------------------------------------------------------------
324// Not equal to operator
325//------------------------------------------------------------------
326bool
327FileSpec::operator!= (const FileSpec& rhs) const
328{
329 return m_filename != rhs.m_filename || m_directory != rhs.m_directory;
330}
331
332//------------------------------------------------------------------
333// Less than operator
334//------------------------------------------------------------------
335bool
336FileSpec::operator< (const FileSpec& rhs) const
337{
338 return FileSpec::Compare(*this, rhs, true) < 0;
339}
340
341//------------------------------------------------------------------
342// Dump a FileSpec object to a stream
343//------------------------------------------------------------------
344Stream&
345lldb_private::operator << (Stream &s, const FileSpec& f)
346{
347 f.Dump(&s);
348 return s;
349}
350
351//------------------------------------------------------------------
352// Clear this object by releasing both the directory and filename
353// string values and making them both the empty string.
354//------------------------------------------------------------------
355void
356FileSpec::Clear()
357{
358 m_directory.Clear();
359 m_filename.Clear();
360}
361
362//------------------------------------------------------------------
363// Compare two FileSpec objects. If "full" is true, then both
364// the directory and the filename must match. If "full" is false,
365// then the directory names for "a" and "b" are only compared if
366// they are both non-empty. This allows a FileSpec object to only
367// contain a filename and it can match FileSpec objects that have
368// matching filenames with different paths.
369//
370// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
371// and "1" if "a" is greater than "b".
372//------------------------------------------------------------------
373int
374FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
375{
376 int result = 0;
377
378 // If full is true, then we must compare both the directory and filename.
379
380 // If full is false, then if either directory is empty, then we match on
381 // the basename only, and if both directories have valid values, we still
382 // do a full compare. This allows for matching when we just have a filename
383 // in one of the FileSpec objects.
384
385 if (full || (a.m_directory && b.m_directory))
386 {
387 result = ConstString::Compare(a.m_directory, b.m_directory);
388 if (result)
389 return result;
390 }
391 return ConstString::Compare (a.m_filename, b.m_filename);
392}
393
394bool
395FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
396{
397 if (full)
398 return a == b;
399 else
400 return a.m_filename == b.m_filename;
401}
402
403
404
405//------------------------------------------------------------------
406// Dump the object to the supplied stream. If the object contains
407// a valid directory name, it will be displayed followed by a
408// directory delimiter, and the filename.
409//------------------------------------------------------------------
410void
411FileSpec::Dump(Stream *s) const
412{
413 if (m_filename)
414 m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid
415
416 if (m_directory)
417 {
418 // If dirname was valid, then we need to print a slash between
419 // the directory and the filename
420 s->PutChar('/');
421 }
422 m_filename.Dump(s);
423}
424
425//------------------------------------------------------------------
426// Returns true if the file exists.
427//------------------------------------------------------------------
428bool
429FileSpec::Exists () const
430{
431 struct stat file_stats;
432 return GetFileStats (this, &file_stats);
433}
434
Caroline Tice428a9a52010-09-10 04:48:55 +0000435bool
436FileSpec::ResolveExecutableLocation ()
437{
Greg Clayton274060b2010-10-20 20:54:39 +0000438 if (!m_directory)
Caroline Tice391a9602010-09-12 00:10:52 +0000439 {
440 const std::string file_str (m_filename.AsCString());
441 llvm::sys::Path path = llvm::sys::Program::FindProgramByName (file_str);
442 llvm::StringRef dir_ref = path.getDirname();
443 if (! dir_ref.empty())
444 {
445 // FindProgramByName returns "." if it can't find the file.
446 if (strcmp (".", dir_ref.data()) == 0)
447 return false;
448
449 m_directory.SetCString (dir_ref.data());
450 if (Exists())
451 return true;
452 else
453 {
454 // If FindProgramByName found the file, it returns the directory + filename in its return results.
455 // We need to separate them.
Greg Clayton274060b2010-10-20 20:54:39 +0000456 FileSpec tmp_file (dir_ref.data(), false);
Caroline Tice391a9602010-09-12 00:10:52 +0000457 if (tmp_file.Exists())
458 {
459 m_directory = tmp_file.m_directory;
460 return true;
461 }
462 }
463 }
464 }
465
466 return false;
Caroline Tice428a9a52010-09-10 04:48:55 +0000467}
468
Jim Ingham0909e5f2010-09-16 00:57:33 +0000469bool
470FileSpec::ResolvePath ()
471{
472 char path_buf[PATH_MAX];
473
474 if (!GetPath (path_buf, PATH_MAX))
475 return false;
476 SetFile (path_buf, true);
477 return true;
478}
479
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000480uint64_t
481FileSpec::GetByteSize() const
482{
483 struct stat file_stats;
484 if (GetFileStats (this, &file_stats))
485 return file_stats.st_size;
486 return 0;
487}
488
489FileSpec::FileType
490FileSpec::GetFileType () const
491{
492 struct stat file_stats;
493 if (GetFileStats (this, &file_stats))
494 {
495 mode_t file_type = file_stats.st_mode & S_IFMT;
496 switch (file_type)
497 {
498 case S_IFDIR: return eFileTypeDirectory;
499 case S_IFIFO: return eFileTypePipe;
500 case S_IFREG: return eFileTypeRegular;
501 case S_IFSOCK: return eFileTypeSocket;
502 case S_IFLNK: return eFileTypeSymbolicLink;
503 default:
504 break;
505 }
506 return eFileTypeUknown;
507 }
508 return eFileTypeInvalid;
509}
510
511TimeValue
512FileSpec::GetModificationTime () const
513{
514 TimeValue mod_time;
515 struct stat file_stats;
516 if (GetFileStats (this, &file_stats))
Eli Friedman6abb6342010-06-11 04:52:22 +0000517 mod_time.OffsetWithSeconds(file_stats.st_mtime);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000518 return mod_time;
519}
520
521//------------------------------------------------------------------
522// Directory string get accessor.
523//------------------------------------------------------------------
524ConstString &
525FileSpec::GetDirectory()
526{
527 return m_directory;
528}
529
530//------------------------------------------------------------------
531// Directory string const get accessor.
532//------------------------------------------------------------------
533const ConstString &
534FileSpec::GetDirectory() const
535{
536 return m_directory;
537}
538
539//------------------------------------------------------------------
540// Filename string get accessor.
541//------------------------------------------------------------------
542ConstString &
543FileSpec::GetFilename()
544{
545 return m_filename;
546}
547
548//------------------------------------------------------------------
549// Filename string const get accessor.
550//------------------------------------------------------------------
551const ConstString &
552FileSpec::GetFilename() const
553{
554 return m_filename;
555}
556
557//------------------------------------------------------------------
558// Extract the directory and path into a fixed buffer. This is
559// needed as the directory and path are stored in separate string
560// values.
561//------------------------------------------------------------------
562bool
563FileSpec::GetPath(char *path, size_t max_path_length) const
564{
Greg Claytondd36def2010-10-17 22:03:32 +0000565 if (max_path_length)
566 {
567 const char *dirname = m_directory.AsCString();
568 const char *filename = m_filename.AsCString();
569 if (dirname)
570 {
571 if (filename)
572 {
573 return (size_t)::snprintf (path, max_path_length, "%s/%s", dirname, filename) < max_path_length;
574 }
575 else
576 {
577 size_t dir_len = m_directory.GetLength() + 1;
578 if (dir_len < max_path_length)
579 {
580 ::memcpy (path, dirname, dir_len);
581 return true;
582 }
583 }
584 }
585 else if (filename)
586 {
587 size_t filename_len = m_filename.GetLength() + 1;
588 if (filename_len < max_path_length)
589 {
590 ::memcpy (path, filename, filename_len);
591 return true;
592 }
593 }
594 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000595 path[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000596 return false;
597}
598
599//------------------------------------------------------------------
600// Returns a shared pointer to a data buffer that contains all or
601// part of the contents of a file. The data is memory mapped and
602// will lazily page in data from the file as memory is accessed.
603// The data that is mappped will start "file_offset" bytes into the
604// file, and "file_size" bytes will be mapped. If "file_size" is
605// greater than the number of bytes available in the file starting
606// at "file_offset", the number of bytes will be appropriately
607// truncated. The final number of bytes that get mapped can be
608// verified using the DataBuffer::GetByteSize() function.
609//------------------------------------------------------------------
610DataBufferSP
611FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
612{
613 DataBufferSP data_sp;
614 auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
615 if (mmap_data.get())
616 {
617 if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= file_size)
618 data_sp.reset(mmap_data.release());
619 }
620 return data_sp;
621}
622
623
624//------------------------------------------------------------------
625// Return the size in bytes that this object takes in memory. This
626// returns the size in bytes of this object, not any shared string
627// values it may refer to.
628//------------------------------------------------------------------
629size_t
630FileSpec::MemorySize() const
631{
632 return m_filename.MemorySize() + m_directory.MemorySize();
633}
634
Greg Claytondda4f7b2010-06-30 23:03:03 +0000635
636size_t
637FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000638{
Greg Claytondda4f7b2010-06-30 23:03:03 +0000639 size_t bytes_read = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000640 char resolved_path[PATH_MAX];
641 if (GetPath(resolved_path, sizeof(resolved_path)))
642 {
643 int fd = ::open (resolved_path, O_RDONLY, 0);
644 if (fd != -1)
645 {
646 struct stat file_stats;
647 if (::fstat (fd, &file_stats) == 0)
648 {
649 // Read bytes directly into our basic_string buffer
650 if (file_stats.st_size > 0)
651 {
652 off_t lseek_result = 0;
653 if (file_offset > 0)
654 lseek_result = ::lseek (fd, file_offset, SEEK_SET);
655
Greg Claytondda4f7b2010-06-30 23:03:03 +0000656 if (lseek_result == file_offset)
657 {
658 ssize_t n = ::read (fd, dst, dst_len);
659 if (n >= 0)
660 bytes_read = n;
661 }
662 }
663 }
664 }
665 close(fd);
666 }
667 return bytes_read;
668}
669
670//------------------------------------------------------------------
671// Returns a shared pointer to a data buffer that contains all or
672// part of the contents of a file. The data copies into a heap based
673// buffer that lives in the DataBuffer shared pointer object returned.
674// The data that is cached will start "file_offset" bytes into the
675// file, and "file_size" bytes will be mapped. If "file_size" is
676// greater than the number of bytes available in the file starting
677// at "file_offset", the number of bytes will be appropriately
678// truncated. The final number of bytes that get mapped can be
679// verified using the DataBuffer::GetByteSize() function.
680//------------------------------------------------------------------
681DataBufferSP
682FileSpec::ReadFileContents (off_t file_offset, size_t file_size) const
683{
684 DataBufferSP data_sp;
685 char resolved_path[PATH_MAX];
686 if (GetPath(resolved_path, sizeof(resolved_path)))
687 {
688 int fd = ::open (resolved_path, O_RDONLY, 0);
689 if (fd != -1)
690 {
691 struct stat file_stats;
692 if (::fstat (fd, &file_stats) == 0)
693 {
694 if (file_stats.st_size > 0)
695 {
696 off_t lseek_result = 0;
697 if (file_offset > 0)
698 lseek_result = ::lseek (fd, file_offset, SEEK_SET);
699
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000700 if (lseek_result < 0)
701 {
702 // Get error from errno
703 }
704 else if (lseek_result == file_offset)
705 {
Greg Claytondda4f7b2010-06-30 23:03:03 +0000706 const size_t bytes_left = file_stats.st_size - file_offset;
707 size_t num_bytes_to_read = file_size;
708 if (num_bytes_to_read > bytes_left)
709 num_bytes_to_read = bytes_left;
710
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000711 std::auto_ptr<DataBufferHeap> data_heap_ap;
Greg Claytondda4f7b2010-06-30 23:03:03 +0000712 data_heap_ap.reset(new DataBufferHeap(num_bytes_to_read, '\0'));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000713
714 if (data_heap_ap.get())
715 {
716 ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize());
717 if (bytesRead >= 0)
718 {
719 // Make sure we read exactly what we asked for and if we got
720 // less, adjust the array
Greg Claytonc982c762010-07-09 20:39:50 +0000721 if ((size_t)bytesRead < data_heap_ap->GetByteSize())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000722 data_heap_ap->SetByteSize(bytesRead);
723 data_sp.reset(data_heap_ap.release());
724 }
725 }
726 }
727 }
728 }
729 }
730 close(fd);
731 }
732 return data_sp;
733}
734
735bool
736FileSpec::ReadFileLines (STLStringArray &lines)
737{
738 bool ret_val = false;
739 lines.clear();
740
741 std::string dir_str (m_directory.AsCString());
742 std::string file_str (m_filename.AsCString());
743 std::string full_name = dir_str + "/" + file_str;
744
745 ifstream file_stream (full_name.c_str());
746
747 if (file_stream)
748 {
749 std::string line;
750 while (getline (file_stream, line))
751 lines.push_back (line);
752 ret_val = true;
753 }
754
755 return ret_val;
756}