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