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 FileSpec &file_spec, Error &error)
329 {
330     if (file_spec)
331     {
332         struct stat file_stats;
333         if (::stat(file_spec.GetCString(), &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         error.SetErrorString ("empty file spec");
343     return 0;
344 }
345 
346 uint32_t
347 File::GetPermissions(Error &error) const
348 {
349     int fd = GetDescriptor();
350     if (fd != kInvalidDescriptor)
351     {
352         struct stat file_stats;
353         if (::fstat (fd, &file_stats) == -1)
354             error.SetErrorToErrno();
355         else
356         {
357             error.Clear();
358             return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
359         }
360     }
361     else
362     {
363         error.SetErrorString ("invalid file descriptor");
364     }
365     return 0;
366 }
367 
368 
369 Error
370 File::Close ()
371 {
372     Error error;
373     if (StreamIsValid() && m_own_stream)
374     {
375         if (::fclose (m_stream) == EOF)
376             error.SetErrorToErrno();
377     }
378 
379     if (DescriptorIsValid() && m_should_close_fd)
380     {
381         if (::close (m_descriptor) != 0)
382             error.SetErrorToErrno();
383     }
384     m_descriptor = kInvalidDescriptor;
385     m_stream = kInvalidStream;
386     m_options = 0;
387     m_own_stream = false;
388     m_should_close_fd = false;
389     m_is_interactive = eLazyBoolCalculate;
390     m_is_real_terminal = eLazyBoolCalculate;
391     return error;
392 }
393 
394 
395 Error
396 File::GetFileSpec (FileSpec &file_spec) const
397 {
398     Error error;
399 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
400     if (IsValid ())
401     {
402         char path[PATH_MAX];
403         if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
404             error.SetErrorToErrno();
405         else
406             file_spec.SetFile (path, false);
407     }
408     else
409     {
410         error.SetErrorString("invalid file handle");
411     }
412 #elif defined(__linux__)
413     char proc[64];
414     char path[PATH_MAX];
415     if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
416         error.SetErrorString ("cannot resolve file descriptor");
417     else
418     {
419         ssize_t len;
420         if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
421             error.SetErrorToErrno();
422         else
423         {
424             path[len] = '\0';
425             file_spec.SetFile (path, false);
426         }
427     }
428 #else
429     error.SetErrorString ("File::GetFileSpec is not supported on this platform");
430 #endif
431 
432     if (error.Fail())
433         file_spec.Clear();
434     return error;
435 }
436 
437 off_t
438 File::SeekFromStart (off_t offset, Error *error_ptr)
439 {
440     off_t result = 0;
441     if (DescriptorIsValid())
442     {
443         result = ::lseek (m_descriptor, offset, SEEK_SET);
444 
445         if (error_ptr)
446         {
447             if (result == -1)
448                 error_ptr->SetErrorToErrno();
449             else
450                 error_ptr->Clear();
451         }
452     }
453     else if (StreamIsValid ())
454     {
455         result = ::fseek(m_stream, offset, SEEK_SET);
456 
457         if (error_ptr)
458         {
459             if (result == -1)
460                 error_ptr->SetErrorToErrno();
461             else
462                 error_ptr->Clear();
463         }
464     }
465     else if (error_ptr)
466     {
467         error_ptr->SetErrorString("invalid file handle");
468     }
469     return result;
470 }
471 
472 off_t
473 File::SeekFromCurrent (off_t offset,  Error *error_ptr)
474 {
475     off_t result = -1;
476     if (DescriptorIsValid())
477     {
478         result = ::lseek (m_descriptor, offset, SEEK_CUR);
479 
480         if (error_ptr)
481         {
482             if (result == -1)
483                 error_ptr->SetErrorToErrno();
484             else
485                 error_ptr->Clear();
486         }
487     }
488     else if (StreamIsValid ())
489     {
490         result = ::fseek(m_stream, offset, SEEK_CUR);
491 
492         if (error_ptr)
493         {
494             if (result == -1)
495                 error_ptr->SetErrorToErrno();
496             else
497                 error_ptr->Clear();
498         }
499     }
500     else if (error_ptr)
501     {
502         error_ptr->SetErrorString("invalid file handle");
503     }
504     return result;
505 }
506 
507 off_t
508 File::SeekFromEnd (off_t offset, Error *error_ptr)
509 {
510     off_t result = -1;
511     if (DescriptorIsValid())
512     {
513         result = ::lseek (m_descriptor, offset, SEEK_END);
514 
515         if (error_ptr)
516         {
517             if (result == -1)
518                 error_ptr->SetErrorToErrno();
519             else
520                 error_ptr->Clear();
521         }
522     }
523     else if (StreamIsValid ())
524     {
525         result = ::fseek(m_stream, offset, SEEK_END);
526 
527         if (error_ptr)
528         {
529             if (result == -1)
530                 error_ptr->SetErrorToErrno();
531             else
532                 error_ptr->Clear();
533         }
534     }
535     else if (error_ptr)
536     {
537         error_ptr->SetErrorString("invalid file handle");
538     }
539     return result;
540 }
541 
542 Error
543 File::Flush ()
544 {
545     Error error;
546     if (StreamIsValid())
547     {
548         int err = 0;
549         do
550         {
551             err = ::fflush (m_stream);
552         } while (err == EOF && errno == EINTR);
553 
554         if (err == EOF)
555             error.SetErrorToErrno();
556     }
557     else if (!DescriptorIsValid())
558     {
559         error.SetErrorString("invalid file handle");
560     }
561     return error;
562 }
563 
564 
565 Error
566 File::Sync ()
567 {
568     Error error;
569     if (DescriptorIsValid())
570     {
571 #ifdef _WIN32
572         int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
573         if (err == 0)
574             error.SetErrorToGenericError();
575 #else
576         int err = 0;
577         do
578         {
579             err = ::fsync (m_descriptor);
580         } while (err == -1 && errno == EINTR);
581 
582         if (err == -1)
583             error.SetErrorToErrno();
584 #endif
585     }
586     else
587     {
588         error.SetErrorString("invalid file handle");
589     }
590     return error;
591 }
592 
593 #if defined (__APPLE__)
594 // Darwin kernels only can read/write <= INT_MAX bytes
595 #define MAX_READ_SIZE INT_MAX
596 #define MAX_WRITE_SIZE INT_MAX
597 #endif
598 
599 Error
600 File::Read (void *buf, size_t &num_bytes)
601 {
602     Error error;
603 
604 #if defined (MAX_READ_SIZE)
605     if (num_bytes > MAX_READ_SIZE)
606     {
607         uint8_t *p = (uint8_t *)buf;
608         size_t bytes_left = num_bytes;
609         // Init the num_bytes read to zero
610         num_bytes = 0;
611 
612         while (bytes_left > 0)
613         {
614             size_t curr_num_bytes;
615             if (bytes_left > MAX_READ_SIZE)
616                 curr_num_bytes = MAX_READ_SIZE;
617             else
618                 curr_num_bytes = bytes_left;
619 
620             error = Read (p + num_bytes, curr_num_bytes);
621 
622             // Update how many bytes were read
623             num_bytes += curr_num_bytes;
624             if (bytes_left < curr_num_bytes)
625                 bytes_left = 0;
626             else
627                 bytes_left -= curr_num_bytes;
628 
629             if (error.Fail())
630                 break;
631         }
632         return error;
633     }
634 #endif
635 
636     ssize_t bytes_read = -1;
637     if (DescriptorIsValid())
638     {
639         do
640         {
641             bytes_read = ::read (m_descriptor, buf, num_bytes);
642         } while (bytes_read < 0 && errno == EINTR);
643 
644         if (bytes_read == -1)
645         {
646             error.SetErrorToErrno();
647             num_bytes = 0;
648         }
649         else
650             num_bytes = bytes_read;
651     }
652     else if (StreamIsValid())
653     {
654         bytes_read = ::fread (buf, 1, num_bytes, m_stream);
655 
656         if (bytes_read == 0)
657         {
658             if (::feof(m_stream))
659                 error.SetErrorString ("feof");
660             else if (::ferror (m_stream))
661                 error.SetErrorString ("ferror");
662             num_bytes = 0;
663         }
664         else
665             num_bytes = bytes_read;
666     }
667     else
668     {
669         num_bytes = 0;
670         error.SetErrorString("invalid file handle");
671     }
672     return error;
673 }
674 
675 Error
676 File::Write (const void *buf, size_t &num_bytes)
677 {
678     Error error;
679 
680 #if defined (MAX_WRITE_SIZE)
681     if (num_bytes > MAX_WRITE_SIZE)
682     {
683         const uint8_t *p = (const uint8_t *)buf;
684         size_t bytes_left = num_bytes;
685         // Init the num_bytes written to zero
686         num_bytes = 0;
687 
688         while (bytes_left > 0)
689         {
690             size_t curr_num_bytes;
691             if (bytes_left > MAX_WRITE_SIZE)
692                 curr_num_bytes = MAX_WRITE_SIZE;
693             else
694                 curr_num_bytes = bytes_left;
695 
696             error = Write (p + num_bytes, curr_num_bytes);
697 
698             // Update how many bytes were read
699             num_bytes += curr_num_bytes;
700             if (bytes_left < curr_num_bytes)
701                 bytes_left = 0;
702             else
703                 bytes_left -= curr_num_bytes;
704 
705             if (error.Fail())
706                 break;
707         }
708         return error;
709     }
710 #endif
711 
712     ssize_t bytes_written = -1;
713     if (DescriptorIsValid())
714     {
715         do
716         {
717             bytes_written = ::write (m_descriptor, buf, num_bytes);
718         } while (bytes_written < 0 && errno == EINTR);
719 
720         if (bytes_written == -1)
721         {
722             error.SetErrorToErrno();
723             num_bytes = 0;
724         }
725         else
726             num_bytes = bytes_written;
727     }
728     else if (StreamIsValid())
729     {
730         bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
731 
732         if (bytes_written == 0)
733         {
734             if (::feof(m_stream))
735                 error.SetErrorString ("feof");
736             else if (::ferror (m_stream))
737                 error.SetErrorString ("ferror");
738             num_bytes = 0;
739         }
740         else
741             num_bytes = bytes_written;
742 
743     }
744     else
745     {
746         num_bytes = 0;
747         error.SetErrorString("invalid file handle");
748     }
749 
750     return error;
751 }
752 
753 
754 Error
755 File::Read (void *buf, size_t &num_bytes, off_t &offset)
756 {
757     Error error;
758 
759 #if defined (MAX_READ_SIZE)
760     if (num_bytes > MAX_READ_SIZE)
761     {
762         uint8_t *p = (uint8_t *)buf;
763         size_t bytes_left = num_bytes;
764         // Init the num_bytes read to zero
765         num_bytes = 0;
766 
767         while (bytes_left > 0)
768         {
769             size_t curr_num_bytes;
770             if (bytes_left > MAX_READ_SIZE)
771                 curr_num_bytes = MAX_READ_SIZE;
772             else
773                 curr_num_bytes = bytes_left;
774 
775             error = Read (p + num_bytes, curr_num_bytes, offset);
776 
777             // Update how many bytes were read
778             num_bytes += curr_num_bytes;
779             if (bytes_left < curr_num_bytes)
780                 bytes_left = 0;
781             else
782                 bytes_left -= curr_num_bytes;
783 
784             if (error.Fail())
785                 break;
786         }
787         return error;
788     }
789 #endif
790 
791 #ifndef _WIN32
792     int fd = GetDescriptor();
793     if (fd != kInvalidDescriptor)
794     {
795         ssize_t bytes_read = -1;
796         do
797         {
798             bytes_read = ::pread (fd, buf, num_bytes, offset);
799         } while (bytes_read < 0 && errno == EINTR);
800 
801         if (bytes_read < 0)
802         {
803             num_bytes = 0;
804             error.SetErrorToErrno();
805         }
806         else
807         {
808             offset += bytes_read;
809             num_bytes = bytes_read;
810         }
811     }
812     else
813     {
814         num_bytes = 0;
815         error.SetErrorString("invalid file handle");
816     }
817 #else
818     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
819     SeekFromStart(offset);
820     error = Read(buf, num_bytes);
821     if (!error.Fail())
822         SeekFromStart(cur);
823 #endif
824     return error;
825 }
826 
827 Error
828 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
829 {
830     Error error;
831 
832     if (num_bytes > 0)
833     {
834         int fd = GetDescriptor();
835         if (fd != kInvalidDescriptor)
836         {
837             struct stat file_stats;
838             if (::fstat (fd, &file_stats) == 0)
839             {
840                 if (file_stats.st_size > offset)
841                 {
842                     const size_t bytes_left = file_stats.st_size - offset;
843                     if (num_bytes > bytes_left)
844                         num_bytes = bytes_left;
845 
846                     size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
847                     std::unique_ptr<DataBufferHeap> data_heap_ap;
848                     data_heap_ap.reset(new DataBufferHeap());
849                     data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
850 
851                     if (data_heap_ap.get())
852                     {
853                         error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
854                         if (error.Success())
855                         {
856                             // Make sure we read exactly what we asked for and if we got
857                             // less, adjust the array
858                             if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
859                                 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
860                             data_buffer_sp.reset(data_heap_ap.release());
861                             return error;
862                         }
863                     }
864                 }
865                 else
866                     error.SetErrorString("file is empty");
867             }
868             else
869                 error.SetErrorToErrno();
870         }
871         else
872             error.SetErrorString("invalid file handle");
873     }
874     else
875         error.SetErrorString("invalid file handle");
876 
877     num_bytes = 0;
878     data_buffer_sp.reset();
879     return error;
880 }
881 
882 Error
883 File::Write (const void *buf, size_t &num_bytes, off_t &offset)
884 {
885     Error error;
886 
887 #if defined (MAX_WRITE_SIZE)
888     if (num_bytes > MAX_WRITE_SIZE)
889     {
890         const uint8_t *p = (const uint8_t *)buf;
891         size_t bytes_left = num_bytes;
892         // Init the num_bytes written to zero
893         num_bytes = 0;
894 
895         while (bytes_left > 0)
896         {
897             size_t curr_num_bytes;
898             if (bytes_left > MAX_WRITE_SIZE)
899                 curr_num_bytes = MAX_WRITE_SIZE;
900             else
901                 curr_num_bytes = bytes_left;
902 
903             error = Write (p + num_bytes, curr_num_bytes, offset);
904 
905             // Update how many bytes were read
906             num_bytes += curr_num_bytes;
907             if (bytes_left < curr_num_bytes)
908                 bytes_left = 0;
909             else
910                 bytes_left -= curr_num_bytes;
911 
912             if (error.Fail())
913                 break;
914         }
915         return error;
916     }
917 #endif
918 
919     int fd = GetDescriptor();
920     if (fd != kInvalidDescriptor)
921     {
922 #ifndef _WIN32
923         ssize_t bytes_written = -1;
924         do
925         {
926             bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
927         } while (bytes_written < 0 && errno == EINTR);
928 
929         if (bytes_written < 0)
930         {
931             num_bytes = 0;
932             error.SetErrorToErrno();
933         }
934         else
935         {
936             offset += bytes_written;
937             num_bytes = bytes_written;
938         }
939 #else
940         long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
941         error = Write(buf, num_bytes);
942         long after = ::lseek(m_descriptor, 0, SEEK_CUR);
943 
944         if (!error.Fail())
945             SeekFromStart(cur);
946 
947         offset = after;
948 #endif
949     }
950     else
951     {
952         num_bytes = 0;
953         error.SetErrorString("invalid file handle");
954     }
955     return error;
956 }
957 
958 //------------------------------------------------------------------
959 // Print some formatted output to the stream.
960 //------------------------------------------------------------------
961 size_t
962 File::Printf (const char *format, ...)
963 {
964     va_list args;
965     va_start (args, format);
966     size_t result = PrintfVarArg (format, args);
967     va_end (args);
968     return result;
969 }
970 
971 //------------------------------------------------------------------
972 // Print some formatted output to the stream.
973 //------------------------------------------------------------------
974 size_t
975 File::PrintfVarArg (const char *format, va_list args)
976 {
977     size_t result = 0;
978     if (DescriptorIsValid())
979     {
980         char *s = NULL;
981         result = vasprintf(&s, format, args);
982         if (s != NULL)
983         {
984             if (result > 0)
985             {
986                 size_t s_len = result;
987                 Write (s, s_len);
988                 result = s_len;
989             }
990             free (s);
991         }
992     }
993     else if (StreamIsValid())
994     {
995         result = ::vfprintf (m_stream, format, args);
996     }
997     return result;
998 }
999 
1000 mode_t
1001 File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
1002 {
1003     mode_t mode = 0;
1004     if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
1005         mode |= O_RDWR;
1006     else if (open_options & eOpenOptionWrite)
1007         mode |= O_WRONLY;
1008 
1009     if (open_options & eOpenOptionAppend)
1010         mode |= O_APPEND;
1011 
1012     if (open_options & eOpenOptionTruncate)
1013         mode |= O_TRUNC;
1014 
1015     if (open_options & eOpenOptionNonBlocking)
1016         mode |= O_NONBLOCK;
1017 
1018     if (open_options & eOpenOptionCanCreateNewOnly)
1019         mode |= O_CREAT | O_EXCL;
1020     else if (open_options & eOpenOptionCanCreate)
1021         mode |= O_CREAT;
1022 
1023     return mode;
1024 }
1025 
1026 void
1027 File::CalculateInteractiveAndTerminal ()
1028 {
1029     const int fd = GetDescriptor();
1030     if (fd >= 0)
1031     {
1032         m_is_interactive = eLazyBoolNo;
1033         m_is_real_terminal = eLazyBoolNo;
1034 #if (defined(_WIN32) || defined(__ANDROID_NDK__))
1035         if (_isatty(fd))
1036         {
1037             m_is_interactive = eLazyBoolYes;
1038             m_is_real_terminal = eLazyBoolYes;
1039         }
1040 #else
1041         if (isatty(fd))
1042         {
1043             m_is_interactive = eLazyBoolYes;
1044             struct winsize window_size;
1045             if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
1046             {
1047                 if (window_size.ws_col > 0)
1048                     m_is_real_terminal = eLazyBoolYes;
1049             }
1050         }
1051 #endif
1052     }
1053 }
1054 
1055 bool
1056 File::GetIsInteractive ()
1057 {
1058     if (m_is_interactive == eLazyBoolCalculate)
1059         CalculateInteractiveAndTerminal ();
1060     return m_is_interactive == eLazyBoolYes;
1061 }
1062 
1063 bool
1064 File::GetIsRealTerminal ()
1065 {
1066     if (m_is_real_terminal == eLazyBoolCalculate)
1067         CalculateInteractiveAndTerminal();
1068     return m_is_real_terminal == eLazyBoolYes;
1069 }
1070 
1071