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