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