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