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