]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/File.cpp
MFV r345495:
[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
18 #ifdef _WIN32
19 #include "lldb/Host/windows/windows.h"
20 #else
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <unistd.h>
25 #endif
26
27 #include "llvm/Support/ConvertUTF.h"
28 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Process.h"
31
32 #include "lldb/Host/Config.h"
33 #include "lldb/Host/FileSystem.h"
34 #include "lldb/Host/Host.h"
35 #include "lldb/Utility/DataBufferHeap.h"
36 #include "lldb/Utility/FileSpec.h"
37 #include "lldb/Utility/Log.h"
38
39 using namespace lldb;
40 using namespace lldb_private;
41
42 static const char *GetStreamOpenModeFromOptions(uint32_t options) {
43   if (options & File::eOpenOptionAppend) {
44     if (options & File::eOpenOptionRead) {
45       if (options & File::eOpenOptionCanCreateNewOnly)
46         return "a+x";
47       else
48         return "a+";
49     } else if (options & File::eOpenOptionWrite) {
50       if (options & File::eOpenOptionCanCreateNewOnly)
51         return "ax";
52       else
53         return "a";
54     }
55   } else if (options & File::eOpenOptionRead &&
56              options & File::eOpenOptionWrite) {
57     if (options & File::eOpenOptionCanCreate) {
58       if (options & File::eOpenOptionCanCreateNewOnly)
59         return "w+x";
60       else
61         return "w+";
62     } else
63       return "r+";
64   } else if (options & File::eOpenOptionRead) {
65     return "r";
66   } else if (options & File::eOpenOptionWrite) {
67     return "w";
68   }
69   return NULL;
70 }
71
72 int File::kInvalidDescriptor = -1;
73 FILE *File::kInvalidStream = NULL;
74
75 File::~File() { Close(); }
76
77 int File::GetDescriptor() const {
78   if (DescriptorIsValid())
79     return m_descriptor;
80
81   // Don't open the file descriptor if we don't need to, just get it from the
82   // stream if we have one.
83   if (StreamIsValid()) {
84 #if defined(_WIN32)
85     return _fileno(m_stream);
86 #else
87     return fileno(m_stream);
88 #endif
89   }
90
91   // Invalid descriptor and invalid stream, return invalid descriptor.
92   return kInvalidDescriptor;
93 }
94
95 IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
96
97 void File::SetDescriptor(int fd, bool transfer_ownership) {
98   if (IsValid())
99     Close();
100   m_descriptor = fd;
101   m_should_close_fd = transfer_ownership;
102 }
103
104 FILE *File::GetStream() {
105   if (!StreamIsValid()) {
106     if (DescriptorIsValid()) {
107       const char *mode = GetStreamOpenModeFromOptions(m_options);
108       if (mode) {
109         if (!m_should_close_fd) {
110 // We must duplicate the file descriptor if we don't own it because when you
111 // call fdopen, the stream will own the fd
112 #ifdef _WIN32
113           m_descriptor = ::_dup(GetDescriptor());
114 #else
115           m_descriptor = dup(GetDescriptor());
116 #endif
117           m_should_close_fd = true;
118         }
119
120         m_stream =
121             llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode);
122
123         // If we got a stream, then we own the stream and should no longer own
124         // the descriptor because fclose() will close it for us
125
126         if (m_stream) {
127           m_own_stream = true;
128           m_should_close_fd = false;
129         }
130       }
131     }
132   }
133   return m_stream;
134 }
135
136 void File::SetStream(FILE *fh, bool transfer_ownership) {
137   if (IsValid())
138     Close();
139   m_stream = fh;
140   m_own_stream = transfer_ownership;
141 }
142
143 uint32_t File::GetPermissions(Status &error) const {
144   int fd = GetDescriptor();
145   if (fd != kInvalidDescriptor) {
146     struct stat file_stats;
147     if (::fstat(fd, &file_stats) == -1)
148       error.SetErrorToErrno();
149     else {
150       error.Clear();
151       return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
152     }
153   } else {
154     error.SetErrorString("invalid file descriptor");
155   }
156   return 0;
157 }
158
159 Status File::Close() {
160   Status error;
161   if (StreamIsValid() && m_own_stream) {
162     if (::fclose(m_stream) == EOF)
163       error.SetErrorToErrno();
164   }
165
166   if (DescriptorIsValid() && m_should_close_fd) {
167     if (::close(m_descriptor) != 0)
168       error.SetErrorToErrno();
169   }
170   m_descriptor = kInvalidDescriptor;
171   m_stream = kInvalidStream;
172   m_options = 0;
173   m_own_stream = false;
174   m_should_close_fd = false;
175   m_is_interactive = eLazyBoolCalculate;
176   m_is_real_terminal = eLazyBoolCalculate;
177   return error;
178 }
179
180 void File::Clear() {
181   m_stream = nullptr;
182   m_descriptor = -1;
183   m_options = 0;
184   m_own_stream = false;
185   m_is_interactive = m_supports_colors = m_is_real_terminal =
186       eLazyBoolCalculate;
187 }
188
189 Status File::GetFileSpec(FileSpec &file_spec) const {
190   Status error;
191 #ifdef F_GETPATH
192   if (IsValid()) {
193     char path[PATH_MAX];
194     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
195       error.SetErrorToErrno();
196     else
197       file_spec.SetFile(path, FileSpec::Style::native);
198   } else {
199     error.SetErrorString("invalid file handle");
200   }
201 #elif defined(__linux__)
202   char proc[64];
203   char path[PATH_MAX];
204   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
205     error.SetErrorString("cannot resolve file descriptor");
206   else {
207     ssize_t len;
208     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
209       error.SetErrorToErrno();
210     else {
211       path[len] = '\0';
212       file_spec.SetFile(path, FileSpec::Style::native);
213     }
214   }
215 #else
216   error.SetErrorString("File::GetFileSpec is not supported on this platform");
217 #endif
218
219   if (error.Fail())
220     file_spec.Clear();
221   return error;
222 }
223
224 off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
225   off_t result = 0;
226   if (DescriptorIsValid()) {
227     result = ::lseek(m_descriptor, offset, SEEK_SET);
228
229     if (error_ptr) {
230       if (result == -1)
231         error_ptr->SetErrorToErrno();
232       else
233         error_ptr->Clear();
234     }
235   } else if (StreamIsValid()) {
236     result = ::fseek(m_stream, offset, SEEK_SET);
237
238     if (error_ptr) {
239       if (result == -1)
240         error_ptr->SetErrorToErrno();
241       else
242         error_ptr->Clear();
243     }
244   } else if (error_ptr) {
245     error_ptr->SetErrorString("invalid file handle");
246   }
247   return result;
248 }
249
250 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
251   off_t result = -1;
252   if (DescriptorIsValid()) {
253     result = ::lseek(m_descriptor, offset, SEEK_CUR);
254
255     if (error_ptr) {
256       if (result == -1)
257         error_ptr->SetErrorToErrno();
258       else
259         error_ptr->Clear();
260     }
261   } else if (StreamIsValid()) {
262     result = ::fseek(m_stream, offset, SEEK_CUR);
263
264     if (error_ptr) {
265       if (result == -1)
266         error_ptr->SetErrorToErrno();
267       else
268         error_ptr->Clear();
269     }
270   } else if (error_ptr) {
271     error_ptr->SetErrorString("invalid file handle");
272   }
273   return result;
274 }
275
276 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
277   off_t result = -1;
278   if (DescriptorIsValid()) {
279     result = ::lseek(m_descriptor, offset, SEEK_END);
280
281     if (error_ptr) {
282       if (result == -1)
283         error_ptr->SetErrorToErrno();
284       else
285         error_ptr->Clear();
286     }
287   } else if (StreamIsValid()) {
288     result = ::fseek(m_stream, offset, SEEK_END);
289
290     if (error_ptr) {
291       if (result == -1)
292         error_ptr->SetErrorToErrno();
293       else
294         error_ptr->Clear();
295     }
296   } else if (error_ptr) {
297     error_ptr->SetErrorString("invalid file handle");
298   }
299   return result;
300 }
301
302 Status File::Flush() {
303   Status error;
304   if (StreamIsValid()) {
305     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
306       error.SetErrorToErrno();
307   } else if (!DescriptorIsValid()) {
308     error.SetErrorString("invalid file handle");
309   }
310   return error;
311 }
312
313 Status File::Sync() {
314   Status error;
315   if (DescriptorIsValid()) {
316 #ifdef _WIN32
317     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
318     if (err == 0)
319       error.SetErrorToGenericError();
320 #else
321     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
322       error.SetErrorToErrno();
323 #endif
324   } else {
325     error.SetErrorString("invalid file handle");
326   }
327   return error;
328 }
329
330 #if defined(__APPLE__)
331 // Darwin kernels only can read/write <= INT_MAX bytes
332 #define MAX_READ_SIZE INT_MAX
333 #define MAX_WRITE_SIZE INT_MAX
334 #endif
335
336 Status File::Read(void *buf, size_t &num_bytes) {
337   Status error;
338
339 #if defined(MAX_READ_SIZE)
340   if (num_bytes > MAX_READ_SIZE) {
341     uint8_t *p = (uint8_t *)buf;
342     size_t bytes_left = num_bytes;
343     // Init the num_bytes read to zero
344     num_bytes = 0;
345
346     while (bytes_left > 0) {
347       size_t curr_num_bytes;
348       if (bytes_left > MAX_READ_SIZE)
349         curr_num_bytes = MAX_READ_SIZE;
350       else
351         curr_num_bytes = bytes_left;
352
353       error = Read(p + num_bytes, curr_num_bytes);
354
355       // Update how many bytes were read
356       num_bytes += curr_num_bytes;
357       if (bytes_left < curr_num_bytes)
358         bytes_left = 0;
359       else
360         bytes_left -= curr_num_bytes;
361
362       if (error.Fail())
363         break;
364     }
365     return error;
366   }
367 #endif
368
369   ssize_t bytes_read = -1;
370   if (DescriptorIsValid()) {
371     bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
372     if (bytes_read == -1) {
373       error.SetErrorToErrno();
374       num_bytes = 0;
375     } else
376       num_bytes = bytes_read;
377   } else if (StreamIsValid()) {
378     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
379
380     if (bytes_read == 0) {
381       if (::feof(m_stream))
382         error.SetErrorString("feof");
383       else if (::ferror(m_stream))
384         error.SetErrorString("ferror");
385       num_bytes = 0;
386     } else
387       num_bytes = bytes_read;
388   } else {
389     num_bytes = 0;
390     error.SetErrorString("invalid file handle");
391   }
392   return error;
393 }
394
395 Status File::Write(const void *buf, size_t &num_bytes) {
396   Status error;
397
398 #if defined(MAX_WRITE_SIZE)
399   if (num_bytes > MAX_WRITE_SIZE) {
400     const uint8_t *p = (const uint8_t *)buf;
401     size_t bytes_left = num_bytes;
402     // Init the num_bytes written to zero
403     num_bytes = 0;
404
405     while (bytes_left > 0) {
406       size_t curr_num_bytes;
407       if (bytes_left > MAX_WRITE_SIZE)
408         curr_num_bytes = MAX_WRITE_SIZE;
409       else
410         curr_num_bytes = bytes_left;
411
412       error = Write(p + num_bytes, curr_num_bytes);
413
414       // Update how many bytes were read
415       num_bytes += curr_num_bytes;
416       if (bytes_left < curr_num_bytes)
417         bytes_left = 0;
418       else
419         bytes_left -= curr_num_bytes;
420
421       if (error.Fail())
422         break;
423     }
424     return error;
425   }
426 #endif
427
428   ssize_t bytes_written = -1;
429   if (DescriptorIsValid()) {
430     bytes_written =
431         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
432     if (bytes_written == -1) {
433       error.SetErrorToErrno();
434       num_bytes = 0;
435     } else
436       num_bytes = bytes_written;
437   } else if (StreamIsValid()) {
438     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
439
440     if (bytes_written == 0) {
441       if (::feof(m_stream))
442         error.SetErrorString("feof");
443       else if (::ferror(m_stream))
444         error.SetErrorString("ferror");
445       num_bytes = 0;
446     } else
447       num_bytes = bytes_written;
448
449   } else {
450     num_bytes = 0;
451     error.SetErrorString("invalid file handle");
452   }
453
454   return error;
455 }
456
457 Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
458   Status error;
459
460 #if defined(MAX_READ_SIZE)
461   if (num_bytes > MAX_READ_SIZE) {
462     uint8_t *p = (uint8_t *)buf;
463     size_t bytes_left = num_bytes;
464     // Init the num_bytes read to zero
465     num_bytes = 0;
466
467     while (bytes_left > 0) {
468       size_t curr_num_bytes;
469       if (bytes_left > MAX_READ_SIZE)
470         curr_num_bytes = MAX_READ_SIZE;
471       else
472         curr_num_bytes = bytes_left;
473
474       error = Read(p + num_bytes, curr_num_bytes, offset);
475
476       // Update how many bytes were read
477       num_bytes += curr_num_bytes;
478       if (bytes_left < curr_num_bytes)
479         bytes_left = 0;
480       else
481         bytes_left -= curr_num_bytes;
482
483       if (error.Fail())
484         break;
485     }
486     return error;
487   }
488 #endif
489
490 #ifndef _WIN32
491   int fd = GetDescriptor();
492   if (fd != kInvalidDescriptor) {
493     ssize_t bytes_read =
494         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
495     if (bytes_read < 0) {
496       num_bytes = 0;
497       error.SetErrorToErrno();
498     } else {
499       offset += bytes_read;
500       num_bytes = bytes_read;
501     }
502   } else {
503     num_bytes = 0;
504     error.SetErrorString("invalid file handle");
505   }
506 #else
507   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
508   SeekFromStart(offset);
509   error = Read(buf, num_bytes);
510   if (!error.Fail())
511     SeekFromStart(cur);
512 #endif
513   return error;
514 }
515
516 Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
517                   DataBufferSP &data_buffer_sp) {
518   Status error;
519
520   if (num_bytes > 0) {
521     int fd = GetDescriptor();
522     if (fd != kInvalidDescriptor) {
523       struct stat file_stats;
524       if (::fstat(fd, &file_stats) == 0) {
525         if (file_stats.st_size > offset) {
526           const size_t bytes_left = file_stats.st_size - offset;
527           if (num_bytes > bytes_left)
528             num_bytes = bytes_left;
529
530           size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
531           std::unique_ptr<DataBufferHeap> data_heap_ap;
532           data_heap_ap.reset(new DataBufferHeap());
533           data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
534
535           if (data_heap_ap.get()) {
536             error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
537             if (error.Success()) {
538               // Make sure we read exactly what we asked for and if we got
539               // less, adjust the array
540               if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
541                 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
542               data_buffer_sp.reset(data_heap_ap.release());
543               return error;
544             }
545           }
546         } else
547           error.SetErrorString("file is empty");
548       } else
549         error.SetErrorToErrno();
550     } else
551       error.SetErrorString("invalid file handle");
552   } else
553     error.SetErrorString("invalid file handle");
554
555   num_bytes = 0;
556   data_buffer_sp.reset();
557   return error;
558 }
559
560 Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
561   Status error;
562
563 #if defined(MAX_WRITE_SIZE)
564   if (num_bytes > MAX_WRITE_SIZE) {
565     const uint8_t *p = (const uint8_t *)buf;
566     size_t bytes_left = num_bytes;
567     // Init the num_bytes written to zero
568     num_bytes = 0;
569
570     while (bytes_left > 0) {
571       size_t curr_num_bytes;
572       if (bytes_left > MAX_WRITE_SIZE)
573         curr_num_bytes = MAX_WRITE_SIZE;
574       else
575         curr_num_bytes = bytes_left;
576
577       error = Write(p + num_bytes, curr_num_bytes, offset);
578
579       // Update how many bytes were read
580       num_bytes += curr_num_bytes;
581       if (bytes_left < curr_num_bytes)
582         bytes_left = 0;
583       else
584         bytes_left -= curr_num_bytes;
585
586       if (error.Fail())
587         break;
588     }
589     return error;
590   }
591 #endif
592
593   int fd = GetDescriptor();
594   if (fd != kInvalidDescriptor) {
595 #ifndef _WIN32
596     ssize_t bytes_written =
597         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
598     if (bytes_written < 0) {
599       num_bytes = 0;
600       error.SetErrorToErrno();
601     } else {
602       offset += bytes_written;
603       num_bytes = bytes_written;
604     }
605 #else
606     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
607     error = Write(buf, num_bytes);
608     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
609
610     if (!error.Fail())
611       SeekFromStart(cur);
612
613     offset = after;
614 #endif
615   } else {
616     num_bytes = 0;
617     error.SetErrorString("invalid file handle");
618   }
619   return error;
620 }
621
622 //------------------------------------------------------------------
623 // Print some formatted output to the stream.
624 //------------------------------------------------------------------
625 size_t File::Printf(const char *format, ...) {
626   va_list args;
627   va_start(args, format);
628   size_t result = PrintfVarArg(format, args);
629   va_end(args);
630   return result;
631 }
632
633 //------------------------------------------------------------------
634 // Print some formatted output to the stream.
635 //------------------------------------------------------------------
636 size_t File::PrintfVarArg(const char *format, va_list args) {
637   size_t result = 0;
638   if (DescriptorIsValid()) {
639     char *s = NULL;
640     result = vasprintf(&s, format, args);
641     if (s != NULL) {
642       if (result > 0) {
643         size_t s_len = result;
644         Write(s, s_len);
645         result = s_len;
646       }
647       free(s);
648     }
649   } else if (StreamIsValid()) {
650     result = ::vfprintf(m_stream, format, args);
651   }
652   return result;
653 }
654
655 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
656   mode_t mode = 0;
657   if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
658     mode |= O_RDWR;
659   else if (open_options & eOpenOptionWrite)
660     mode |= O_WRONLY;
661
662   if (open_options & eOpenOptionAppend)
663     mode |= O_APPEND;
664
665   if (open_options & eOpenOptionTruncate)
666     mode |= O_TRUNC;
667
668   if (open_options & eOpenOptionNonBlocking)
669     mode |= O_NONBLOCK;
670
671   if (open_options & eOpenOptionCanCreateNewOnly)
672     mode |= O_CREAT | O_EXCL;
673   else if (open_options & eOpenOptionCanCreate)
674     mode |= O_CREAT;
675
676   return mode;
677 }
678
679 void File::CalculateInteractiveAndTerminal() {
680   const int fd = GetDescriptor();
681   if (fd >= 0) {
682     m_is_interactive = eLazyBoolNo;
683     m_is_real_terminal = eLazyBoolNo;
684 #if defined(_WIN32)
685     if (_isatty(fd)) {
686       m_is_interactive = eLazyBoolYes;
687       m_is_real_terminal = eLazyBoolYes;
688 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
689       m_supports_colors = eLazyBoolYes;
690 #endif
691     }
692 #else
693     if (isatty(fd)) {
694       m_is_interactive = eLazyBoolYes;
695       struct winsize window_size;
696       if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
697         if (window_size.ws_col > 0) {
698           m_is_real_terminal = eLazyBoolYes;
699           if (llvm::sys::Process::FileDescriptorHasColors(fd))
700             m_supports_colors = eLazyBoolYes;
701         }
702       }
703     }
704 #endif
705   }
706 }
707
708 bool File::GetIsInteractive() {
709   if (m_is_interactive == eLazyBoolCalculate)
710     CalculateInteractiveAndTerminal();
711   return m_is_interactive == eLazyBoolYes;
712 }
713
714 bool File::GetIsRealTerminal() {
715   if (m_is_real_terminal == eLazyBoolCalculate)
716     CalculateInteractiveAndTerminal();
717   return m_is_real_terminal == eLazyBoolYes;
718 }
719
720 bool File::GetIsTerminalWithColors() {
721   if (m_supports_colors == eLazyBoolCalculate)
722     CalculateInteractiveAndTerminal();
723   return m_supports_colors == eLazyBoolYes;
724 }