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