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