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