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 int File::kInvalidDescriptor = -1;
72 FILE *File::kInvalidStream = nullptr;
73 
74 File::~File() { Close(); }
75 
76 int File::GetDescriptor() const {
77   if (DescriptorIsValid())
78     return m_descriptor;
79 
80   // Don't open the file descriptor if we don't need to, just get it from the
81   // stream if we have one.
82   if (StreamIsValid()) {
83 #if defined(_WIN32)
84     return _fileno(m_stream);
85 #else
86     return fileno(m_stream);
87 #endif
88   }
89 
90   // Invalid descriptor and invalid stream, return invalid descriptor.
91   return kInvalidDescriptor;
92 }
93 
94 IOObject::WaitableHandle File::GetWaitableHandle() { return GetDescriptor(); }
95 
96 void File::SetDescriptor(int fd, uint32_t options, bool transfer_ownership) {
97   if (IsValid())
98     Close();
99   m_descriptor = fd;
100   m_should_close_fd = transfer_ownership;
101   m_options = options;
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 = kInvalidDescriptor;
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   std::lock_guard<std::mutex> guard(offset_access_mutex);
508   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
509   SeekFromStart(offset);
510   error = Read(buf, num_bytes);
511   if (!error.Fail())
512     SeekFromStart(cur);
513 #endif
514   return error;
515 }
516 
517 Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
518   Status error;
519 
520 #if defined(MAX_WRITE_SIZE)
521   if (num_bytes > MAX_WRITE_SIZE) {
522     const uint8_t *p = (const uint8_t *)buf;
523     size_t bytes_left = num_bytes;
524     // Init the num_bytes written to zero
525     num_bytes = 0;
526 
527     while (bytes_left > 0) {
528       size_t curr_num_bytes;
529       if (bytes_left > MAX_WRITE_SIZE)
530         curr_num_bytes = MAX_WRITE_SIZE;
531       else
532         curr_num_bytes = bytes_left;
533 
534       error = Write(p + num_bytes, curr_num_bytes, offset);
535 
536       // Update how many bytes were read
537       num_bytes += curr_num_bytes;
538       if (bytes_left < curr_num_bytes)
539         bytes_left = 0;
540       else
541         bytes_left -= curr_num_bytes;
542 
543       if (error.Fail())
544         break;
545     }
546     return error;
547   }
548 #endif
549 
550   int fd = GetDescriptor();
551   if (fd != kInvalidDescriptor) {
552 #ifndef _WIN32
553     ssize_t bytes_written =
554         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
555     if (bytes_written < 0) {
556       num_bytes = 0;
557       error.SetErrorToErrno();
558     } else {
559       offset += bytes_written;
560       num_bytes = bytes_written;
561     }
562 #else
563     std::lock_guard<std::mutex> guard(offset_access_mutex);
564     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
565     SeekFromStart(offset);
566     error = Write(buf, num_bytes);
567     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
568 
569     if (!error.Fail())
570       SeekFromStart(cur);
571 
572     offset = after;
573 #endif
574   } else {
575     num_bytes = 0;
576     error.SetErrorString("invalid file handle");
577   }
578   return error;
579 }
580 
581 // Print some formatted output to the stream.
582 size_t File::Printf(const char *format, ...) {
583   va_list args;
584   va_start(args, format);
585   size_t result = PrintfVarArg(format, args);
586   va_end(args);
587   return result;
588 }
589 
590 // Print some formatted output to the stream.
591 size_t File::PrintfVarArg(const char *format, va_list args) {
592   size_t result = 0;
593   if (DescriptorIsValid()) {
594     char *s = nullptr;
595     result = vasprintf(&s, format, args);
596     if (s != nullptr) {
597       if (result > 0) {
598         size_t s_len = result;
599         Write(s, s_len);
600         result = s_len;
601       }
602       free(s);
603     }
604   } else if (StreamIsValid()) {
605     result = ::vfprintf(m_stream, format, args);
606   }
607   return result;
608 }
609 
610 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
611   mode_t mode = 0;
612   if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
613     mode |= O_RDWR;
614   else if (open_options & eOpenOptionWrite)
615     mode |= O_WRONLY;
616 
617   if (open_options & eOpenOptionAppend)
618     mode |= O_APPEND;
619 
620   if (open_options & eOpenOptionTruncate)
621     mode |= O_TRUNC;
622 
623   if (open_options & eOpenOptionNonBlocking)
624     mode |= O_NONBLOCK;
625 
626   if (open_options & eOpenOptionCanCreateNewOnly)
627     mode |= O_CREAT | O_EXCL;
628   else if (open_options & eOpenOptionCanCreate)
629     mode |= O_CREAT;
630 
631   return mode;
632 }
633 
634 void File::CalculateInteractiveAndTerminal() {
635   const int fd = GetDescriptor();
636   if (fd >= 0) {
637     m_is_interactive = eLazyBoolNo;
638     m_is_real_terminal = eLazyBoolNo;
639 #if defined(_WIN32)
640     if (_isatty(fd)) {
641       m_is_interactive = eLazyBoolYes;
642       m_is_real_terminal = eLazyBoolYes;
643 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
644       m_supports_colors = eLazyBoolYes;
645 #endif
646     }
647 #else
648     if (isatty(fd)) {
649       m_is_interactive = eLazyBoolYes;
650       struct winsize window_size;
651       if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
652         if (window_size.ws_col > 0) {
653           m_is_real_terminal = eLazyBoolYes;
654           if (llvm::sys::Process::FileDescriptorHasColors(fd))
655             m_supports_colors = eLazyBoolYes;
656         }
657       }
658     }
659 #endif
660   }
661 }
662 
663 bool File::GetIsInteractive() {
664   if (m_is_interactive == eLazyBoolCalculate)
665     CalculateInteractiveAndTerminal();
666   return m_is_interactive == eLazyBoolYes;
667 }
668 
669 bool File::GetIsRealTerminal() {
670   if (m_is_real_terminal == eLazyBoolCalculate)
671     CalculateInteractiveAndTerminal();
672   return m_is_real_terminal == eLazyBoolYes;
673 }
674 
675 bool File::GetIsTerminalWithColors() {
676   if (m_supports_colors == eLazyBoolCalculate)
677     CalculateInteractiveAndTerminal();
678   return m_supports_colors == eLazyBoolYes;
679 }
680