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