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