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