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