]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/File.cpp
MFV r277870
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Host / common / File.cpp
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 #else
292     oflag |= O_BINARY;
293 #endif
294
295     mode_t mode = 0;
296     if (oflag & O_CREAT)
297     {
298         if (permissions & lldb::eFilePermissionsUserRead)     mode |= S_IRUSR;
299         if (permissions & lldb::eFilePermissionsUserWrite)    mode |= S_IWUSR;
300         if (permissions & lldb::eFilePermissionsUserExecute)  mode |= S_IXUSR;
301         if (permissions & lldb::eFilePermissionsGroupRead)    mode |= S_IRGRP;
302         if (permissions & lldb::eFilePermissionsGroupWrite)   mode |= S_IWGRP;
303         if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
304         if (permissions & lldb::eFilePermissionsWorldRead)    mode |= S_IROTH;
305         if (permissions & lldb::eFilePermissionsWorldWrite)   mode |= S_IWOTH;
306         if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
307     }
308
309     do
310     {
311         m_descriptor = ::open(path, oflag, mode);
312     } while (m_descriptor < 0 && errno == EINTR);
313
314     if (!DescriptorIsValid())
315         error.SetErrorToErrno();
316     else
317     {
318         m_should_close_fd = true;
319         m_options = options;
320     }
321     
322     return error;
323 }
324
325 uint32_t
326 File::GetPermissions (const char *path, Error &error)
327 {
328     if (path && path[0])
329     {
330         struct stat file_stats;
331         if (::stat (path, &file_stats) == -1)
332             error.SetErrorToErrno();
333         else
334         {
335             error.Clear();
336             return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
337         }
338     }
339     else
340     {
341         if (path)
342             error.SetErrorString ("invalid path");
343         else
344             error.SetErrorString ("empty path");        
345     }
346     return 0;
347 }
348
349 uint32_t
350 File::GetPermissions(Error &error) const
351 {
352     int fd = GetDescriptor();
353     if (fd != kInvalidDescriptor)
354     {
355         struct stat file_stats;
356         if (::fstat (fd, &file_stats) == -1)
357             error.SetErrorToErrno();
358         else
359         {
360             error.Clear();
361             return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
362         }
363     }
364     else
365     {
366         error.SetErrorString ("invalid file descriptor");
367     }
368     return 0;
369 }
370
371
372 Error
373 File::Close ()
374 {
375     Error error;
376     if (StreamIsValid() && m_own_stream)
377     {
378         if (::fclose (m_stream) == EOF)
379             error.SetErrorToErrno();
380     }
381     
382     if (DescriptorIsValid() && m_should_close_fd)
383     {
384         if (::close (m_descriptor) != 0)
385             error.SetErrorToErrno();
386     }
387     m_descriptor = kInvalidDescriptor;
388     m_stream = kInvalidStream;
389     m_options = 0;
390     m_own_stream = false;
391     m_should_close_fd = false;
392     m_is_interactive = eLazyBoolCalculate;
393     m_is_real_terminal = eLazyBoolCalculate;
394     return error;
395 }
396
397
398 Error
399 File::GetFileSpec (FileSpec &file_spec) const
400 {
401     Error error;
402 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
403     if (IsValid ())
404     {
405         char path[PATH_MAX];
406         if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
407             error.SetErrorToErrno();
408         else
409             file_spec.SetFile (path, false);
410     }
411     else 
412     {
413         error.SetErrorString("invalid file handle");
414     }
415 #elif defined(__linux__)
416     char proc[64];
417     char path[PATH_MAX];
418     if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
419         error.SetErrorString ("cannot resolve file descriptor");
420     else
421     {
422         ssize_t len;
423         if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
424             error.SetErrorToErrno();
425         else
426         {
427             path[len] = '\0';
428             file_spec.SetFile (path, false);
429         }
430     }
431 #else
432     error.SetErrorString ("File::GetFileSpec is not supported on this platform");
433 #endif
434
435     if (error.Fail())
436         file_spec.Clear();
437     return error;
438 }
439
440 off_t
441 File::SeekFromStart (off_t offset, Error *error_ptr)
442 {
443     off_t result = 0;
444     if (DescriptorIsValid())
445     {
446         result = ::lseek (m_descriptor, offset, SEEK_SET);
447
448         if (error_ptr)
449         {
450             if (result == -1)
451                 error_ptr->SetErrorToErrno();
452             else
453                 error_ptr->Clear();
454         }
455     }
456     else if (StreamIsValid ())
457     {
458         result = ::fseek(m_stream, offset, SEEK_SET);
459         
460         if (error_ptr)
461         {
462             if (result == -1)
463                 error_ptr->SetErrorToErrno();
464             else
465                 error_ptr->Clear();
466         }
467     }
468     else if (error_ptr)
469     {
470         error_ptr->SetErrorString("invalid file handle");
471     }
472     return result;
473 }
474
475 off_t
476 File::SeekFromCurrent (off_t offset,  Error *error_ptr)
477 {
478     off_t result = -1;
479     if (DescriptorIsValid())
480     {
481         result = ::lseek (m_descriptor, offset, SEEK_CUR);
482         
483         if (error_ptr)
484         {
485             if (result == -1)
486                 error_ptr->SetErrorToErrno();
487             else
488                 error_ptr->Clear();
489         }
490     }
491     else if (StreamIsValid ())
492     {
493         result = ::fseek(m_stream, offset, SEEK_CUR);
494         
495         if (error_ptr)
496         {
497             if (result == -1)
498                 error_ptr->SetErrorToErrno();
499             else
500                 error_ptr->Clear();
501         }
502     }
503     else if (error_ptr)
504     {
505         error_ptr->SetErrorString("invalid file handle");
506     }
507     return result;
508 }
509
510 off_t
511 File::SeekFromEnd (off_t offset, Error *error_ptr)
512 {
513     off_t result = -1;
514     if (DescriptorIsValid())
515     {
516         result = ::lseek (m_descriptor, offset, SEEK_END);
517         
518         if (error_ptr)
519         {
520             if (result == -1)
521                 error_ptr->SetErrorToErrno();
522             else
523                 error_ptr->Clear();
524         }
525     }
526     else if (StreamIsValid ())
527     {
528         result = ::fseek(m_stream, offset, SEEK_END);
529         
530         if (error_ptr)
531         {
532             if (result == -1)
533                 error_ptr->SetErrorToErrno();
534             else
535                 error_ptr->Clear();
536         }
537     }
538     else if (error_ptr)
539     {
540         error_ptr->SetErrorString("invalid file handle");
541     }
542     return result;
543 }
544
545 Error
546 File::Flush ()
547 {
548     Error error;
549     if (StreamIsValid())
550     {
551         int err = 0;
552         do
553         {
554             err = ::fflush (m_stream);
555         } while (err == EOF && errno == EINTR);
556         
557         if (err == EOF)
558             error.SetErrorToErrno();
559     }
560     else if (!DescriptorIsValid())
561     {
562         error.SetErrorString("invalid file handle");
563     }
564     return error;
565 }
566
567
568 Error
569 File::Sync ()
570 {
571     Error error;
572     if (DescriptorIsValid())
573     {
574 #ifdef _WIN32
575         int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
576         if (err == 0)
577             error.SetErrorToGenericError();
578 #else
579         int err = 0;
580         do
581         {
582             err = ::fsync (m_descriptor);
583         } while (err == -1 && errno == EINTR);
584         
585         if (err == -1)
586             error.SetErrorToErrno();
587 #endif
588     }
589     else 
590     {
591         error.SetErrorString("invalid file handle");
592     }
593     return error;
594 }
595
596 Error
597 File::Read (void *buf, size_t &num_bytes)
598 {
599     Error error;
600     ssize_t bytes_read = -1;
601     if (DescriptorIsValid())
602     {
603         do
604         {
605             bytes_read = ::read (m_descriptor, buf, num_bytes);
606         } while (bytes_read < 0 && errno == EINTR);
607
608         if (bytes_read == -1)
609         {
610             error.SetErrorToErrno();
611             num_bytes = 0;
612         }
613         else
614             num_bytes = bytes_read;
615     }
616     else if (StreamIsValid())
617     {
618         bytes_read = ::fread (buf, 1, num_bytes, m_stream);
619
620         if (bytes_read == 0)
621         {
622             if (::feof(m_stream))
623                 error.SetErrorString ("feof");
624             else if (::ferror (m_stream))
625                 error.SetErrorString ("ferror");
626             num_bytes = 0;
627         }
628         else
629             num_bytes = bytes_read;
630     }
631     else 
632     {
633         num_bytes = 0;
634         error.SetErrorString("invalid file handle");
635     }
636     return error;
637 }
638           
639 Error
640 File::Write (const void *buf, size_t &num_bytes)
641 {
642     Error error;
643     ssize_t bytes_written = -1;
644     if (DescriptorIsValid())
645     {
646         do
647         {
648             bytes_written = ::write (m_descriptor, buf, num_bytes);
649         } while (bytes_written < 0 && errno == EINTR);
650
651         if (bytes_written == -1)
652         {
653             error.SetErrorToErrno();
654             num_bytes = 0;
655         }
656         else
657             num_bytes = bytes_written;
658     }
659     else if (StreamIsValid())
660     {
661         bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
662
663         if (bytes_written == 0)
664         {
665             if (::feof(m_stream))
666                 error.SetErrorString ("feof");
667             else if (::ferror (m_stream))
668                 error.SetErrorString ("ferror");
669             num_bytes = 0;
670         }
671         else
672             num_bytes = bytes_written;
673         
674     }
675     else 
676     {
677         num_bytes = 0;
678         error.SetErrorString("invalid file handle");
679     }
680
681     return error;
682 }
683
684
685 Error
686 File::Read (void *buf, size_t &num_bytes, off_t &offset)
687 {
688 #ifndef _WIN32
689     Error error;
690     int fd = GetDescriptor();
691     if (fd != kInvalidDescriptor)
692     {
693         ssize_t bytes_read = -1;
694         do
695         {
696             bytes_read = ::pread (fd, buf, num_bytes, offset);
697         } while (bytes_read < 0 && errno == EINTR);
698
699         if (bytes_read < 0)
700         {
701             num_bytes = 0;
702             error.SetErrorToErrno();
703         }
704         else
705         {
706             offset += bytes_read;
707             num_bytes = bytes_read;
708         }
709     }
710     else 
711     {
712         num_bytes = 0;
713         error.SetErrorString("invalid file handle");
714     }
715     return error;
716 #else
717     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
718     SeekFromStart(offset);
719     Error error = Read(buf, num_bytes);
720     if (!error.Fail())
721         SeekFromStart(cur);
722     return error;
723 #endif
724 }
725
726 Error
727 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
728 {
729     Error error;
730     
731     if (num_bytes > 0)
732     {
733         int fd = GetDescriptor();
734         if (fd != kInvalidDescriptor)
735         {
736             struct stat file_stats;
737             if (::fstat (fd, &file_stats) == 0)
738             {
739                 if (file_stats.st_size > offset)
740                 {
741                     const size_t bytes_left = file_stats.st_size - offset;
742                     if (num_bytes > bytes_left)
743                         num_bytes = bytes_left;
744                         
745                     std::unique_ptr<DataBufferHeap> data_heap_ap;
746                     data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
747                         
748                     if (data_heap_ap.get())
749                     {
750                         error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
751                         if (error.Success())
752                         {
753                             // Make sure we read exactly what we asked for and if we got
754                             // less, adjust the array
755                             if (num_bytes < data_heap_ap->GetByteSize())
756                                 data_heap_ap->SetByteSize(num_bytes);
757                             data_buffer_sp.reset(data_heap_ap.release());
758                             return error;
759                         }
760                     }
761                 }
762                 else 
763                     error.SetErrorString("file is empty");
764             }
765             else
766                 error.SetErrorToErrno();
767         }
768         else 
769             error.SetErrorString("invalid file handle");
770     }
771     else
772         error.SetErrorString("invalid file handle");
773
774     num_bytes = 0;
775     data_buffer_sp.reset();
776     return error;
777 }
778
779 Error
780 File::Write (const void *buf, size_t &num_bytes, off_t &offset)
781 {
782     Error error;
783     int fd = GetDescriptor();
784     if (fd != kInvalidDescriptor)
785     {
786 #ifndef _WIN32
787         ssize_t bytes_written = -1;
788         do
789         {
790             bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
791         } while (bytes_written < 0 && errno == EINTR);
792
793         if (bytes_written < 0)
794         {
795             num_bytes = 0;
796             error.SetErrorToErrno();
797         }
798         else
799         {
800             offset += bytes_written;
801             num_bytes = bytes_written;
802         }
803 #else
804         long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
805         error = Write(buf, num_bytes);
806         long after = ::lseek(m_descriptor, 0, SEEK_CUR);
807
808         if (!error.Fail())
809             SeekFromStart(cur);
810
811         ssize_t bytes_written = after - cur;
812         offset = after;
813 #endif
814     }
815     else 
816     {
817         num_bytes = 0;
818         error.SetErrorString("invalid file handle");
819     }
820     return error;
821 }
822
823 //------------------------------------------------------------------
824 // Print some formatted output to the stream.
825 //------------------------------------------------------------------
826 size_t
827 File::Printf (const char *format, ...)
828 {
829     va_list args;
830     va_start (args, format);
831     size_t result = PrintfVarArg (format, args);
832     va_end (args);
833     return result;
834 }
835
836 //------------------------------------------------------------------
837 // Print some formatted output to the stream.
838 //------------------------------------------------------------------
839 size_t
840 File::PrintfVarArg (const char *format, va_list args)
841 {
842     size_t result = 0;
843     if (DescriptorIsValid())
844     {
845         char *s = NULL;
846         result = vasprintf(&s, format, args);
847         if (s != NULL)
848         {
849             if (result > 0)
850             {
851                 size_t s_len = result;
852                 Write (s, s_len);
853                 result = s_len;
854             }
855             free (s);
856         }
857     }
858     else if (StreamIsValid())
859     {
860         result = ::vfprintf (m_stream, format, args);
861     }
862     return result;
863 }
864
865 mode_t
866 File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
867 {
868     mode_t mode = 0;
869     if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
870         mode |= O_RDWR;
871     else if (open_options & eOpenOptionWrite)
872         mode |= O_WRONLY;
873     
874     if (open_options & eOpenOptionAppend)
875         mode |= O_APPEND;
876
877     if (open_options & eOpenOptionTruncate)
878         mode |= O_TRUNC;
879
880     if (open_options & eOpenOptionNonBlocking)
881         mode |= O_NONBLOCK;
882
883     if (open_options & eOpenOptionCanCreateNewOnly)
884         mode |= O_CREAT | O_EXCL;
885     else if (open_options & eOpenOptionCanCreate)
886         mode |= O_CREAT;
887
888     return mode;
889 }
890
891 void
892 File::CalculateInteractiveAndTerminal ()
893 {
894     const int fd = GetDescriptor();
895     if (fd >= 0)
896     {
897         m_is_interactive = eLazyBoolNo;
898         m_is_real_terminal = eLazyBoolNo;
899 #ifdef _WIN32
900         if (_isatty(fd))
901         {
902             m_is_interactive = eLazyBoolYes;
903             m_is_real_terminal = eLazyBoolYes;
904         }
905 #else
906         if (isatty(fd))
907         {
908             m_is_interactive = eLazyBoolYes;
909             struct winsize window_size;
910             if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
911             {
912                 if (window_size.ws_col > 0)
913                     m_is_real_terminal = eLazyBoolYes;
914             }
915         }
916 #endif
917     }
918 }
919
920 bool
921 File::GetIsInteractive ()
922 {
923     if (m_is_interactive == eLazyBoolCalculate)
924         CalculateInteractiveAndTerminal ();
925     return m_is_interactive == eLazyBoolYes;
926 }
927
928 bool
929 File::GetIsRealTerminal ()
930 {
931     if (m_is_real_terminal == eLazyBoolCalculate)
932         CalculateInteractiveAndTerminal();
933     return m_is_real_terminal == eLazyBoolYes;
934 }
935