File.cpp revision 269024
1//===-- File.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#include "lldb/Host/File.h"
11
12#include <errno.h>
13#include <fcntl.h>
14#include <limits.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <sys/stat.h>
18
19#ifdef _WIN32
20#include "lldb/Host/windows/windows.h"
21#else
22#include <sys/ioctl.h>
23#endif
24
25#include "lldb/Core/DataBufferHeap.h"
26#include "lldb/Core/Error.h"
27#include "lldb/Host/Config.h"
28#include "lldb/Host/FileSpec.h"
29
30using namespace lldb;
31using namespace lldb_private;
32
33static const char *
34GetStreamOpenModeFromOptions (uint32_t options)
35{
36    if (options & File::eOpenOptionAppend)
37    {
38        if (options & File::eOpenOptionRead)
39        {
40            if (options & File::eOpenOptionCanCreateNewOnly)
41                return "a+x";
42            else
43                return "a+";
44        }
45        else if (options & File::eOpenOptionWrite)
46        {
47            if (options & File::eOpenOptionCanCreateNewOnly)
48                return "ax";
49            else
50                return "a";
51        }
52    }
53    else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
54    {
55        if (options & File::eOpenOptionCanCreate)
56        {
57            if (options & File::eOpenOptionCanCreateNewOnly)
58                return "w+x";
59            else
60                return "w+";
61        }
62        else
63            return "r+";
64    }
65    else if (options & File::eOpenOptionRead)
66    {
67        return "r";
68    }
69    else if (options & File::eOpenOptionWrite)
70    {
71        return "w";
72    }
73    return NULL;
74}
75
76int File::kInvalidDescriptor = -1;
77FILE * File::kInvalidStream = NULL;
78
79File::File(const char *path, uint32_t options, uint32_t permissions) :
80    m_descriptor (kInvalidDescriptor),
81    m_stream (kInvalidStream),
82    m_options (),
83    m_own_stream (false),
84    m_own_descriptor (false),
85    m_is_interactive (eLazyBoolCalculate),
86    m_is_real_terminal (eLazyBoolCalculate)
87{
88    Open (path, options, permissions);
89}
90
91File::File (const FileSpec& filespec,
92            uint32_t options,
93            uint32_t permissions) :
94    m_descriptor (kInvalidDescriptor),
95    m_stream (kInvalidStream),
96    m_options (0),
97    m_own_stream (false),
98    m_own_descriptor (false),
99    m_is_interactive (eLazyBoolCalculate),
100    m_is_real_terminal (eLazyBoolCalculate)
101
102{
103    if (filespec)
104    {
105        Open (filespec.GetPath().c_str(), options, permissions);
106    }
107}
108
109File::File (const File &rhs) :
110    m_descriptor (kInvalidDescriptor),
111    m_stream (kInvalidStream),
112    m_options (0),
113    m_own_stream (false),
114    m_own_descriptor (false),
115    m_is_interactive (eLazyBoolCalculate),
116    m_is_real_terminal (eLazyBoolCalculate)
117{
118    Duplicate (rhs);
119}
120
121
122File &
123File::operator = (const File &rhs)
124{
125    if (this != &rhs)
126        Duplicate (rhs);
127    return *this;
128}
129
130File::~File()
131{
132    Close ();
133}
134
135
136int
137File::GetDescriptor() const
138{
139    if (DescriptorIsValid())
140        return m_descriptor;
141
142    // Don't open the file descriptor if we don't need to, just get it from the
143    // stream if we have one.
144    if (StreamIsValid())
145        return fileno (m_stream);
146
147    // Invalid descriptor and invalid stream, return invalid descriptor.
148    return kInvalidDescriptor;
149}
150
151void
152File::SetDescriptor (int fd, bool transfer_ownership)
153{
154    if (IsValid())
155        Close();
156    m_descriptor = fd;
157    m_own_descriptor = transfer_ownership;
158}
159
160
161FILE *
162File::GetStream ()
163{
164    if (!StreamIsValid())
165    {
166        if (DescriptorIsValid())
167        {
168            const char *mode = GetStreamOpenModeFromOptions (m_options);
169            if (mode)
170            {
171                if (!m_own_descriptor)
172                {
173                    // We must duplicate the file descriptor if we don't own it because
174                    // when you call fdopen, the stream will own the fd
175#ifdef _WIN32
176                    m_descriptor = ::_dup(GetDescriptor());
177#else
178                    m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
179#endif
180                    m_own_descriptor = true;
181                }
182
183                do
184                {
185                    m_stream = ::fdopen (m_descriptor, mode);
186                } while (m_stream == NULL && errno == EINTR);
187
188                // If we got a stream, then we own the stream and should no
189                // longer own the descriptor because fclose() will close it for us
190
191                if (m_stream)
192                {
193                    m_own_stream = true;
194                    m_own_descriptor = false;
195                }
196            }
197        }
198    }
199    return m_stream;
200}
201
202
203void
204File::SetStream (FILE *fh, bool transfer_ownership)
205{
206    if (IsValid())
207        Close();
208    m_stream = fh;
209    m_own_stream = transfer_ownership;
210}
211
212Error
213File::Duplicate (const File &rhs)
214{
215    Error error;
216    if (IsValid ())
217        Close();
218
219    if (rhs.DescriptorIsValid())
220    {
221#ifdef _WIN32
222        m_descriptor = ::_dup(rhs.GetDescriptor());
223#else
224        m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
225#endif
226        if (!DescriptorIsValid())
227            error.SetErrorToErrno();
228        else
229        {
230            m_options = rhs.m_options;
231            m_own_descriptor = true;
232        }
233    }
234    else
235    {
236        error.SetErrorString ("invalid file to duplicate");
237    }
238    return error;
239}
240
241Error
242File::Open (const char *path, uint32_t options, uint32_t permissions)
243{
244    Error error;
245    if (IsValid())
246        Close ();
247
248    int oflag = 0;
249    const bool read = options & eOpenOptionRead;
250    const bool write = options & eOpenOptionWrite;
251    if (write)
252    {
253        if (read)
254            oflag |= O_RDWR;
255        else
256            oflag |= O_WRONLY;
257
258        if (options & eOpenOptionAppend)
259            oflag |= O_APPEND;
260
261        if (options & eOpenOptionTruncate)
262            oflag |= O_TRUNC;
263
264        if (options & eOpenOptionCanCreate)
265            oflag |= O_CREAT;
266
267        if (options & eOpenOptionCanCreateNewOnly)
268            oflag |= O_CREAT | O_EXCL;
269    }
270    else if (read)
271    {
272        oflag |= O_RDONLY;
273
274#ifndef _WIN32
275        if (options & eOpenoptionDontFollowSymlinks)
276            oflag |= O_NOFOLLOW;
277#endif
278    }
279
280#ifndef _WIN32
281    if (options & eOpenOptionNonBlocking)
282        oflag |= O_NONBLOCK;
283#else
284    oflag |= O_BINARY;
285#endif
286
287    mode_t mode = 0;
288    if (oflag & O_CREAT)
289    {
290        if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
291        if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
292        if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
293        if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
294        if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
295        if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
296        if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
297        if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
298        if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
299    }
300
301    do
302    {
303        m_descriptor = ::open(path, oflag, mode);
304    } while (m_descriptor < 0 && errno == EINTR);
305
306    if (!DescriptorIsValid())
307        error.SetErrorToErrno();
308    else
309    {
310        m_own_descriptor = true;
311        m_options = options;
312    }
313
314    return error;
315}
316
317uint32_t
318File::GetPermissions (const char *path, Error &error)
319{
320    if (path && path[0])
321    {
322        struct stat file_stats;
323        if (::stat (path, &file_stats) == -1)
324            error.SetErrorToErrno();
325        else
326        {
327            error.Clear();
328            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
329        }
330    }
331    else
332    {
333        if (path)
334            error.SetErrorString ("invalid path");
335        else
336            error.SetErrorString ("empty path");
337    }
338    return 0;
339}
340
341uint32_t
342File::GetPermissions(Error &error) const
343{
344    int fd = GetDescriptor();
345    if (fd != kInvalidDescriptor)
346    {
347        struct stat file_stats;
348        if (::fstat (fd, &file_stats) == -1)
349            error.SetErrorToErrno();
350        else
351        {
352            error.Clear();
353            return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
354        }
355    }
356    else
357    {
358        error.SetErrorString ("invalid file descriptor");
359    }
360    return 0;
361}
362
363
364Error
365File::Close ()
366{
367    Error error;
368    if (StreamIsValid() && m_own_stream)
369    {
370        if (::fclose (m_stream) == EOF)
371            error.SetErrorToErrno();
372    }
373
374    if (DescriptorIsValid() && m_own_descriptor)
375    {
376        if (::close (m_descriptor) != 0)
377            error.SetErrorToErrno();
378    }
379    m_descriptor = kInvalidDescriptor;
380    m_stream = kInvalidStream;
381    m_options = 0;
382    m_own_stream = false;
383    m_own_descriptor = false;
384    m_is_interactive = eLazyBoolCalculate;
385    m_is_real_terminal = eLazyBoolCalculate;
386    return error;
387}
388
389
390Error
391File::GetFileSpec (FileSpec &file_spec) const
392{
393    Error error;
394#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
395    if (IsValid ())
396    {
397        char path[PATH_MAX];
398        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
399            error.SetErrorToErrno();
400        else
401            file_spec.SetFile (path, false);
402    }
403    else
404    {
405        error.SetErrorString("invalid file handle");
406    }
407#elif defined(__linux__)
408    char proc[64];
409    char path[PATH_MAX];
410    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
411        error.SetErrorString ("cannot resolve file descriptor");
412    else
413    {
414        ssize_t len;
415        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
416            error.SetErrorToErrno();
417        else
418        {
419            path[len] = '\0';
420            file_spec.SetFile (path, false);
421        }
422    }
423#else
424    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
425#endif
426
427    if (error.Fail())
428        file_spec.Clear();
429    return error;
430}
431
432off_t
433File::SeekFromStart (off_t offset, Error *error_ptr)
434{
435    off_t result = 0;
436    if (DescriptorIsValid())
437    {
438        result = ::lseek (m_descriptor, offset, SEEK_SET);
439
440        if (error_ptr)
441        {
442            if (result == -1)
443                error_ptr->SetErrorToErrno();
444            else
445                error_ptr->Clear();
446        }
447    }
448    else if (StreamIsValid ())
449    {
450        result = ::fseek(m_stream, offset, SEEK_SET);
451
452        if (error_ptr)
453        {
454            if (result == -1)
455                error_ptr->SetErrorToErrno();
456            else
457                error_ptr->Clear();
458        }
459    }
460    else if (error_ptr)
461    {
462        error_ptr->SetErrorString("invalid file handle");
463    }
464    return result;
465}
466
467off_t
468File::SeekFromCurrent (off_t offset,  Error *error_ptr)
469{
470    off_t result = -1;
471    if (DescriptorIsValid())
472    {
473        result = ::lseek (m_descriptor, offset, SEEK_CUR);
474
475        if (error_ptr)
476        {
477            if (result == -1)
478                error_ptr->SetErrorToErrno();
479            else
480                error_ptr->Clear();
481        }
482    }
483    else if (StreamIsValid ())
484    {
485        result = ::fseek(m_stream, offset, SEEK_CUR);
486
487        if (error_ptr)
488        {
489            if (result == -1)
490                error_ptr->SetErrorToErrno();
491            else
492                error_ptr->Clear();
493        }
494    }
495    else if (error_ptr)
496    {
497        error_ptr->SetErrorString("invalid file handle");
498    }
499    return result;
500}
501
502off_t
503File::SeekFromEnd (off_t offset, Error *error_ptr)
504{
505    off_t result = -1;
506    if (DescriptorIsValid())
507    {
508        result = ::lseek (m_descriptor, offset, SEEK_END);
509
510        if (error_ptr)
511        {
512            if (result == -1)
513                error_ptr->SetErrorToErrno();
514            else
515                error_ptr->Clear();
516        }
517    }
518    else if (StreamIsValid ())
519    {
520        result = ::fseek(m_stream, offset, SEEK_END);
521
522        if (error_ptr)
523        {
524            if (result == -1)
525                error_ptr->SetErrorToErrno();
526            else
527                error_ptr->Clear();
528        }
529    }
530    else if (error_ptr)
531    {
532        error_ptr->SetErrorString("invalid file handle");
533    }
534    return result;
535}
536
537Error
538File::Flush ()
539{
540    Error error;
541    if (StreamIsValid())
542    {
543        int err = 0;
544        do
545        {
546            err = ::fflush (m_stream);
547        } while (err == EOF && errno == EINTR);
548
549        if (err == EOF)
550            error.SetErrorToErrno();
551    }
552    else if (!DescriptorIsValid())
553    {
554        error.SetErrorString("invalid file handle");
555    }
556    return error;
557}
558
559
560Error
561File::Sync ()
562{
563    Error error;
564    if (DescriptorIsValid())
565    {
566#ifdef _WIN32
567        int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
568        if (err == 0)
569            error.SetErrorToGenericError();
570#else
571        int err = 0;
572        do
573        {
574            err = ::fsync (m_descriptor);
575        } while (err == -1 && errno == EINTR);
576
577        if (err == -1)
578            error.SetErrorToErrno();
579#endif
580    }
581    else
582    {
583        error.SetErrorString("invalid file handle");
584    }
585    return error;
586}
587
588Error
589File::Read (void *buf, size_t &num_bytes)
590{
591    Error error;
592    ssize_t bytes_read = -1;
593    if (DescriptorIsValid())
594    {
595        do
596        {
597            bytes_read = ::read (m_descriptor, buf, num_bytes);
598        } while (bytes_read < 0 && errno == EINTR);
599
600        if (bytes_read == -1)
601        {
602            error.SetErrorToErrno();
603            num_bytes = 0;
604        }
605        else
606            num_bytes = bytes_read;
607    }
608    else if (StreamIsValid())
609    {
610        bytes_read = ::fread (buf, 1, num_bytes, m_stream);
611
612        if (bytes_read == 0)
613        {
614            if (::feof(m_stream))
615                error.SetErrorString ("feof");
616            else if (::ferror (m_stream))
617                error.SetErrorString ("ferror");
618            num_bytes = 0;
619        }
620        else
621            num_bytes = bytes_read;
622    }
623    else
624    {
625        num_bytes = 0;
626        error.SetErrorString("invalid file handle");
627    }
628    return error;
629}
630
631Error
632File::Write (const void *buf, size_t &num_bytes)
633{
634    Error error;
635    ssize_t bytes_written = -1;
636    if (DescriptorIsValid())
637    {
638        do
639        {
640            bytes_written = ::write (m_descriptor, buf, num_bytes);
641        } while (bytes_written < 0 && errno == EINTR);
642
643        if (bytes_written == -1)
644        {
645            error.SetErrorToErrno();
646            num_bytes = 0;
647        }
648        else
649            num_bytes = bytes_written;
650    }
651    else if (StreamIsValid())
652    {
653        bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
654
655        if (bytes_written == 0)
656        {
657            if (::feof(m_stream))
658                error.SetErrorString ("feof");
659            else if (::ferror (m_stream))
660                error.SetErrorString ("ferror");
661            num_bytes = 0;
662        }
663        else
664            num_bytes = bytes_written;
665
666    }
667    else
668    {
669        num_bytes = 0;
670        error.SetErrorString("invalid file handle");
671    }
672    return error;
673}
674
675
676Error
677File::Read (void *buf, size_t &num_bytes, off_t &offset)
678{
679#ifndef _WIN32
680    Error error;
681    int fd = GetDescriptor();
682    if (fd != kInvalidDescriptor)
683    {
684        ssize_t bytes_read = -1;
685        do
686        {
687            bytes_read = ::pread (fd, buf, num_bytes, offset);
688        } while (bytes_read < 0 && errno == EINTR);
689
690        if (bytes_read < 0)
691        {
692            num_bytes = 0;
693            error.SetErrorToErrno();
694        }
695        else
696        {
697            offset += bytes_read;
698            num_bytes = bytes_read;
699        }
700    }
701    else
702    {
703        num_bytes = 0;
704        error.SetErrorString("invalid file handle");
705    }
706    return error;
707#else
708    long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
709    SeekFromStart(offset);
710    Error error = Read(buf, num_bytes);
711    if (!error.Fail())
712        SeekFromStart(cur);
713    return error;
714#endif
715}
716
717Error
718File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
719{
720    Error error;
721
722    if (num_bytes > 0)
723    {
724        int fd = GetDescriptor();
725        if (fd != kInvalidDescriptor)
726        {
727            struct stat file_stats;
728            if (::fstat (fd, &file_stats) == 0)
729            {
730                if (file_stats.st_size > offset)
731                {
732                    const size_t bytes_left = file_stats.st_size - offset;
733                    if (num_bytes > bytes_left)
734                        num_bytes = bytes_left;
735
736                    std::unique_ptr<DataBufferHeap> data_heap_ap;
737                    data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
738
739                    if (data_heap_ap.get())
740                    {
741                        error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
742                        if (error.Success())
743                        {
744                            // Make sure we read exactly what we asked for and if we got
745                            // less, adjust the array
746                            if (num_bytes < data_heap_ap->GetByteSize())
747                                data_heap_ap->SetByteSize(num_bytes);
748                            data_buffer_sp.reset(data_heap_ap.release());
749                            return error;
750                        }
751                    }
752                }
753                else
754                    error.SetErrorString("file is empty");
755            }
756            else
757                error.SetErrorToErrno();
758        }
759        else
760            error.SetErrorString("invalid file handle");
761    }
762    else
763        error.SetErrorString("invalid file handle");
764
765    num_bytes = 0;
766    data_buffer_sp.reset();
767    return error;
768}
769
770Error
771File::Write (const void *buf, size_t &num_bytes, off_t &offset)
772{
773    Error error;
774    int fd = GetDescriptor();
775    if (fd != kInvalidDescriptor)
776    {
777#ifndef _WIN32
778        ssize_t bytes_written = -1;
779        do
780        {
781            bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
782        } while (bytes_written < 0 && errno == EINTR);
783
784        if (bytes_written < 0)
785        {
786            num_bytes = 0;
787            error.SetErrorToErrno();
788        }
789        else
790        {
791            offset += bytes_written;
792            num_bytes = bytes_written;
793        }
794#else
795        long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
796        error = Write(buf, num_bytes);
797        long after = ::lseek(m_descriptor, 0, SEEK_CUR);
798
799        if (!error.Fail())
800            SeekFromStart(cur);
801
802        ssize_t bytes_written = after - cur;
803        offset = after;
804#endif
805    }
806    else
807    {
808        num_bytes = 0;
809        error.SetErrorString("invalid file handle");
810    }
811    return error;
812}
813
814//------------------------------------------------------------------
815// Print some formatted output to the stream.
816//------------------------------------------------------------------
817size_t
818File::Printf (const char *format, ...)
819{
820    va_list args;
821    va_start (args, format);
822    size_t result = PrintfVarArg (format, args);
823    va_end (args);
824    return result;
825}
826
827//------------------------------------------------------------------
828// Print some formatted output to the stream.
829//------------------------------------------------------------------
830size_t
831File::PrintfVarArg (const char *format, va_list args)
832{
833    size_t result = 0;
834    if (DescriptorIsValid())
835    {
836        char *s = NULL;
837        result = vasprintf(&s, format, args);
838        if (s != NULL)
839        {
840            if (result > 0)
841            {
842                size_t s_len = result;
843                Write (s, s_len);
844                result = s_len;
845            }
846            free (s);
847        }
848    }
849    else if (StreamIsValid())
850    {
851        result = ::vfprintf (m_stream, format, args);
852    }
853    return result;
854}
855
856mode_t
857File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
858{
859    mode_t mode = 0;
860    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
861        mode |= O_RDWR;
862    else if (open_options & eOpenOptionWrite)
863        mode |= O_WRONLY;
864
865    if (open_options & eOpenOptionAppend)
866        mode |= O_APPEND;
867
868    if (open_options & eOpenOptionTruncate)
869        mode |= O_TRUNC;
870
871    if (open_options & eOpenOptionNonBlocking)
872        mode |= O_NONBLOCK;
873
874    if (open_options & eOpenOptionCanCreateNewOnly)
875        mode |= O_CREAT | O_EXCL;
876    else if (open_options & eOpenOptionCanCreate)
877        mode |= O_CREAT;
878
879    return mode;
880}
881
882void
883File::CalculateInteractiveAndTerminal ()
884{
885    const int fd = GetDescriptor();
886    if (fd >= 0)
887    {
888        m_is_interactive = eLazyBoolNo;
889        m_is_real_terminal = eLazyBoolNo;
890#ifndef _MSC_VER
891        if (isatty(fd))
892        {
893            m_is_interactive = eLazyBoolYes;
894            struct winsize window_size;
895            if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
896            {
897                if (window_size.ws_col > 0)
898                    m_is_real_terminal = eLazyBoolYes;
899            }
900        }
901#endif
902    }
903}
904
905bool
906File::GetIsInteractive ()
907{
908    if (m_is_interactive == eLazyBoolCalculate)
909        CalculateInteractiveAndTerminal ();
910    return m_is_interactive == eLazyBoolYes;
911}
912
913bool
914File::GetIsRealTerminal ()
915{
916    if (m_is_real_terminal == eLazyBoolCalculate)
917        CalculateInteractiveAndTerminal();
918    return m_is_real_terminal == eLazyBoolYes;
919}
920
921