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