LLDB  mainline
File.cpp
Go to the documentation of this file.
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
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"
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 NULL;
69 }
70 
71 int File::kInvalidDescriptor = -1;
72 FILE *File::kInvalidStream = NULL;
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 
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 =
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 = NULL;
638  result = vasprintf(&s, format, args);
639  if (s != NULL) {
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 }
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
#define O_NONBLOCK
A file utility class.
Definition: FileSpec.h:55
#define S_IRWXU
void Clear()
Clears the object state.
Definition: FileSpec.cpp:285
#define S_IRWXG
A subclass of DataBuffer that stores a data buffer on the heap.
void SetErrorToErrno()
Set the current error to errno.
Definition: Status.cpp:223
static Permissions GetPermissions(const ELFSectionHeader &H)
void SetErrorToGenericError()
Set the current error to a generic error.
Definition: Status.cpp:231
void Clear()
Clear the object state.
Definition: Status.cpp:167
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
bool Success() const
Test for success condition.
Definition: Status.cpp:287
#define S_IRWXO
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
static const char * GetStreamOpenModeFromOptions(uint32_t options)
Definition: File.cpp:41
Definition: SBAddress.h:15
#define PATH_MAX
int vasprintf(char **ret, const char *fmt, va_list ap)
Definition: Windows.cpp:45
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:198
An error handling class.
Definition: Status.h:44