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