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