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