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