1 //===-- File.cpp ------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/File.h"
19 #include "lldb/Host/windows/windows.h"
21 #include <sys/ioctl.h>
27 #include "llvm/Support/ConvertUTF.h"
28 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
32 #include "lldb/Host/Config.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"
39 using namespace lldb_private;
41 static const char *GetStreamOpenModeFromOptions(uint32_t options) {
42 if (options & File::eOpenOptionAppend) {
43 if (options & File::eOpenOptionRead) {
44 if (options & File::eOpenOptionCanCreateNewOnly)
48 } else if (options & File::eOpenOptionWrite) {
49 if (options & File::eOpenOptionCanCreateNewOnly)
54 } else if (options & File::eOpenOptionRead &&
55 options & File::eOpenOptionWrite) {
56 if (options & File::eOpenOptionCanCreate) {
57 if (options & File::eOpenOptionCanCreateNewOnly)
63 } else if (options & File::eOpenOptionRead) {
65 } else if (options & File::eOpenOptionWrite) {
71 int File::kInvalidDescriptor = -1;
72 FILE *File::kInvalidStream = NULL;
74 File::File(const char *path, uint32_t options, uint32_t permissions)
75 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
76 m_stream(kInvalidStream), m_options(), m_own_stream(false),
77 m_is_interactive(eLazyBoolCalculate),
78 m_is_real_terminal(eLazyBoolCalculate) {
79 Open(path, options, permissions);
82 File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions)
83 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
84 m_stream(kInvalidStream), m_options(0), m_own_stream(false),
85 m_is_interactive(eLazyBoolCalculate),
86 m_is_real_terminal(eLazyBoolCalculate)
90 Open(filespec.GetPath().c_str(), options, permissions);
94 File::~File() { Close(); }
96 int File::GetDescriptor() const {
97 if (DescriptorIsValid())
100 // Don't open the file descriptor if we don't need to, just get it from the
101 // stream if we have one.
102 if (StreamIsValid()) {
104 return _fileno(m_stream);
106 return fileno(m_stream);
110 // Invalid descriptor and invalid stream, return invalid descriptor.
111 return kInvalidDescriptor;
114 IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
116 void File::SetDescriptor(int fd, bool transfer_ownership) {
120 m_should_close_fd = transfer_ownership;
123 FILE *File::GetStream() {
124 if (!StreamIsValid()) {
125 if (DescriptorIsValid()) {
126 const char *mode = GetStreamOpenModeFromOptions(m_options);
128 if (!m_should_close_fd) {
129 // We must duplicate the file descriptor if we don't own it because when you
130 // call fdopen, the stream will own the fd
132 m_descriptor = ::_dup(GetDescriptor());
134 m_descriptor = dup(GetDescriptor());
136 m_should_close_fd = true;
140 llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode);
142 // If we got a stream, then we own the stream and should no longer own
143 // the descriptor because fclose() will close it for us
147 m_should_close_fd = false;
155 void File::SetStream(FILE *fh, bool transfer_ownership) {
159 m_own_stream = transfer_ownership;
162 static int DoOpen(const char *path, int flags, int mode) {
165 if (!llvm::ConvertUTF8toWide(path, wpath))
168 ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode);
171 return ::open(path, flags, mode);
175 Status File::Open(const char *path, uint32_t options, uint32_t permissions) {
181 const bool read = options & eOpenOptionRead;
182 const bool write = options & eOpenOptionWrite;
189 if (options & eOpenOptionAppend)
192 if (options & eOpenOptionTruncate)
195 if (options & eOpenOptionCanCreate)
198 if (options & eOpenOptionCanCreateNewOnly)
199 oflag |= O_CREAT | O_EXCL;
204 if (options & eOpenOptionDontFollowSymlinks)
210 if (options & eOpenOptionNonBlocking)
212 if (options & eOpenOptionCloseOnExec)
219 if (oflag & O_CREAT) {
220 if (permissions & lldb::eFilePermissionsUserRead)
222 if (permissions & lldb::eFilePermissionsUserWrite)
224 if (permissions & lldb::eFilePermissionsUserExecute)
226 if (permissions & lldb::eFilePermissionsGroupRead)
228 if (permissions & lldb::eFilePermissionsGroupWrite)
230 if (permissions & lldb::eFilePermissionsGroupExecute)
232 if (permissions & lldb::eFilePermissionsWorldRead)
234 if (permissions & lldb::eFilePermissionsWorldWrite)
236 if (permissions & lldb::eFilePermissionsWorldExecute)
240 m_descriptor = llvm::sys::RetryAfterSignal(-1, DoOpen, path, oflag, mode);
241 if (!DescriptorIsValid())
242 error.SetErrorToErrno();
244 m_should_close_fd = true;
251 uint32_t File::GetPermissions(const FileSpec &file_spec, Status &error) {
254 auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath());
257 error = Status(Perms.getError());
260 error.SetErrorString("empty file spec");
264 uint32_t File::GetPermissions(Status &error) const {
265 int fd = GetDescriptor();
266 if (fd != kInvalidDescriptor) {
267 struct stat file_stats;
268 if (::fstat(fd, &file_stats) == -1)
269 error.SetErrorToErrno();
272 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
275 error.SetErrorString("invalid file descriptor");
280 Status File::Close() {
282 if (StreamIsValid() && m_own_stream) {
283 if (::fclose(m_stream) == EOF)
284 error.SetErrorToErrno();
287 if (DescriptorIsValid() && m_should_close_fd) {
288 if (::close(m_descriptor) != 0)
289 error.SetErrorToErrno();
291 m_descriptor = kInvalidDescriptor;
292 m_stream = kInvalidStream;
294 m_own_stream = false;
295 m_should_close_fd = false;
296 m_is_interactive = eLazyBoolCalculate;
297 m_is_real_terminal = eLazyBoolCalculate;
305 m_own_stream = false;
306 m_is_interactive = m_supports_colors = m_is_real_terminal =
310 Status File::GetFileSpec(FileSpec &file_spec) const {
315 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
316 error.SetErrorToErrno();
318 file_spec.SetFile(path, false, FileSpec::Style::native);
320 error.SetErrorString("invalid file handle");
322 #elif defined(__linux__)
325 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
326 error.SetErrorString("cannot resolve file descriptor");
329 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
330 error.SetErrorToErrno();
333 file_spec.SetFile(path, false, FileSpec::Style::native);
337 error.SetErrorString("File::GetFileSpec is not supported on this platform");
345 off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
347 if (DescriptorIsValid()) {
348 result = ::lseek(m_descriptor, offset, SEEK_SET);
352 error_ptr->SetErrorToErrno();
356 } else if (StreamIsValid()) {
357 result = ::fseek(m_stream, offset, SEEK_SET);
361 error_ptr->SetErrorToErrno();
365 } else if (error_ptr) {
366 error_ptr->SetErrorString("invalid file handle");
371 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
373 if (DescriptorIsValid()) {
374 result = ::lseek(m_descriptor, offset, SEEK_CUR);
378 error_ptr->SetErrorToErrno();
382 } else if (StreamIsValid()) {
383 result = ::fseek(m_stream, offset, SEEK_CUR);
387 error_ptr->SetErrorToErrno();
391 } else if (error_ptr) {
392 error_ptr->SetErrorString("invalid file handle");
397 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
399 if (DescriptorIsValid()) {
400 result = ::lseek(m_descriptor, offset, SEEK_END);
404 error_ptr->SetErrorToErrno();
408 } else if (StreamIsValid()) {
409 result = ::fseek(m_stream, offset, SEEK_END);
413 error_ptr->SetErrorToErrno();
417 } else if (error_ptr) {
418 error_ptr->SetErrorString("invalid file handle");
423 Status File::Flush() {
425 if (StreamIsValid()) {
426 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
427 error.SetErrorToErrno();
428 } else if (!DescriptorIsValid()) {
429 error.SetErrorString("invalid file handle");
434 Status File::Sync() {
436 if (DescriptorIsValid()) {
438 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
440 error.SetErrorToGenericError();
442 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
443 error.SetErrorToErrno();
446 error.SetErrorString("invalid file handle");
451 #if defined(__APPLE__)
452 // Darwin kernels only can read/write <= INT_MAX bytes
453 #define MAX_READ_SIZE INT_MAX
454 #define MAX_WRITE_SIZE INT_MAX
457 Status File::Read(void *buf, size_t &num_bytes) {
460 #if defined(MAX_READ_SIZE)
461 if (num_bytes > MAX_READ_SIZE) {
462 uint8_t *p = (uint8_t *)buf;
463 size_t bytes_left = num_bytes;
464 // Init the num_bytes read to zero
467 while (bytes_left > 0) {
468 size_t curr_num_bytes;
469 if (bytes_left > MAX_READ_SIZE)
470 curr_num_bytes = MAX_READ_SIZE;
472 curr_num_bytes = bytes_left;
474 error = Read(p + num_bytes, curr_num_bytes);
476 // Update how many bytes were read
477 num_bytes += curr_num_bytes;
478 if (bytes_left < curr_num_bytes)
481 bytes_left -= curr_num_bytes;
490 ssize_t bytes_read = -1;
491 if (DescriptorIsValid()) {
492 bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
493 if (bytes_read == -1) {
494 error.SetErrorToErrno();
497 num_bytes = bytes_read;
498 } else if (StreamIsValid()) {
499 bytes_read = ::fread(buf, 1, num_bytes, m_stream);
501 if (bytes_read == 0) {
502 if (::feof(m_stream))
503 error.SetErrorString("feof");
504 else if (::ferror(m_stream))
505 error.SetErrorString("ferror");
508 num_bytes = bytes_read;
511 error.SetErrorString("invalid file handle");
516 Status File::Write(const void *buf, size_t &num_bytes) {
519 #if defined(MAX_WRITE_SIZE)
520 if (num_bytes > MAX_WRITE_SIZE) {
521 const uint8_t *p = (const uint8_t *)buf;
522 size_t bytes_left = num_bytes;
523 // Init the num_bytes written to zero
526 while (bytes_left > 0) {
527 size_t curr_num_bytes;
528 if (bytes_left > MAX_WRITE_SIZE)
529 curr_num_bytes = MAX_WRITE_SIZE;
531 curr_num_bytes = bytes_left;
533 error = Write(p + num_bytes, curr_num_bytes);
535 // Update how many bytes were read
536 num_bytes += curr_num_bytes;
537 if (bytes_left < curr_num_bytes)
540 bytes_left -= curr_num_bytes;
549 ssize_t bytes_written = -1;
550 if (DescriptorIsValid()) {
552 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
553 if (bytes_written == -1) {
554 error.SetErrorToErrno();
557 num_bytes = bytes_written;
558 } else if (StreamIsValid()) {
559 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
561 if (bytes_written == 0) {
562 if (::feof(m_stream))
563 error.SetErrorString("feof");
564 else if (::ferror(m_stream))
565 error.SetErrorString("ferror");
568 num_bytes = bytes_written;
572 error.SetErrorString("invalid file handle");
578 Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
581 #if defined(MAX_READ_SIZE)
582 if (num_bytes > MAX_READ_SIZE) {
583 uint8_t *p = (uint8_t *)buf;
584 size_t bytes_left = num_bytes;
585 // Init the num_bytes read to zero
588 while (bytes_left > 0) {
589 size_t curr_num_bytes;
590 if (bytes_left > MAX_READ_SIZE)
591 curr_num_bytes = MAX_READ_SIZE;
593 curr_num_bytes = bytes_left;
595 error = Read(p + num_bytes, curr_num_bytes, offset);
597 // Update how many bytes were read
598 num_bytes += curr_num_bytes;
599 if (bytes_left < curr_num_bytes)
602 bytes_left -= curr_num_bytes;
612 int fd = GetDescriptor();
613 if (fd != kInvalidDescriptor) {
615 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
616 if (bytes_read < 0) {
618 error.SetErrorToErrno();
620 offset += bytes_read;
621 num_bytes = bytes_read;
625 error.SetErrorString("invalid file handle");
628 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
629 SeekFromStart(offset);
630 error = Read(buf, num_bytes);
637 Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
638 DataBufferSP &data_buffer_sp) {
642 int fd = GetDescriptor();
643 if (fd != kInvalidDescriptor) {
644 struct stat file_stats;
645 if (::fstat(fd, &file_stats) == 0) {
646 if (file_stats.st_size > offset) {
647 const size_t bytes_left = file_stats.st_size - offset;
648 if (num_bytes > bytes_left)
649 num_bytes = bytes_left;
651 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
652 std::unique_ptr<DataBufferHeap> data_heap_ap;
653 data_heap_ap.reset(new DataBufferHeap());
654 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
656 if (data_heap_ap.get()) {
657 error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
658 if (error.Success()) {
659 // Make sure we read exactly what we asked for and if we got
660 // less, adjust the array
661 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
662 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
663 data_buffer_sp.reset(data_heap_ap.release());
668 error.SetErrorString("file is empty");
670 error.SetErrorToErrno();
672 error.SetErrorString("invalid file handle");
674 error.SetErrorString("invalid file handle");
677 data_buffer_sp.reset();
681 Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
684 #if defined(MAX_WRITE_SIZE)
685 if (num_bytes > MAX_WRITE_SIZE) {
686 const uint8_t *p = (const uint8_t *)buf;
687 size_t bytes_left = num_bytes;
688 // Init the num_bytes written to zero
691 while (bytes_left > 0) {
692 size_t curr_num_bytes;
693 if (bytes_left > MAX_WRITE_SIZE)
694 curr_num_bytes = MAX_WRITE_SIZE;
696 curr_num_bytes = bytes_left;
698 error = Write(p + num_bytes, curr_num_bytes, offset);
700 // Update how many bytes were read
701 num_bytes += curr_num_bytes;
702 if (bytes_left < curr_num_bytes)
705 bytes_left -= curr_num_bytes;
714 int fd = GetDescriptor();
715 if (fd != kInvalidDescriptor) {
717 ssize_t bytes_written =
718 llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
719 if (bytes_written < 0) {
721 error.SetErrorToErrno();
723 offset += bytes_written;
724 num_bytes = bytes_written;
727 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
728 error = Write(buf, num_bytes);
729 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
738 error.SetErrorString("invalid file handle");
743 //------------------------------------------------------------------
744 // Print some formatted output to the stream.
745 //------------------------------------------------------------------
746 size_t File::Printf(const char *format, ...) {
748 va_start(args, format);
749 size_t result = PrintfVarArg(format, args);
754 //------------------------------------------------------------------
755 // Print some formatted output to the stream.
756 //------------------------------------------------------------------
757 size_t File::PrintfVarArg(const char *format, va_list args) {
759 if (DescriptorIsValid()) {
761 result = vasprintf(&s, format, args);
764 size_t s_len = result;
770 } else if (StreamIsValid()) {
771 result = ::vfprintf(m_stream, format, args);
776 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
778 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
780 else if (open_options & eOpenOptionWrite)
783 if (open_options & eOpenOptionAppend)
786 if (open_options & eOpenOptionTruncate)
789 if (open_options & eOpenOptionNonBlocking)
792 if (open_options & eOpenOptionCanCreateNewOnly)
793 mode |= O_CREAT | O_EXCL;
794 else if (open_options & eOpenOptionCanCreate)
800 void File::CalculateInteractiveAndTerminal() {
801 const int fd = GetDescriptor();
803 m_is_interactive = eLazyBoolNo;
804 m_is_real_terminal = eLazyBoolNo;
807 m_is_interactive = eLazyBoolYes;
808 m_is_real_terminal = eLazyBoolYes;
812 m_is_interactive = eLazyBoolYes;
813 struct winsize window_size;
814 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
815 if (window_size.ws_col > 0) {
816 m_is_real_terminal = eLazyBoolYes;
817 if (llvm::sys::Process::FileDescriptorHasColors(fd))
818 m_supports_colors = eLazyBoolYes;
826 bool File::GetIsInteractive() {
827 if (m_is_interactive == eLazyBoolCalculate)
828 CalculateInteractiveAndTerminal();
829 return m_is_interactive == eLazyBoolYes;
832 bool File::GetIsRealTerminal() {
833 if (m_is_real_terminal == eLazyBoolCalculate)
834 CalculateInteractiveAndTerminal();
835 return m_is_real_terminal == eLazyBoolYes;
838 bool File::GetIsTerminalWithColors() {
839 if (m_supports_colors == eLazyBoolCalculate)
840 CalculateInteractiveAndTerminal();
841 return m_supports_colors == eLazyBoolYes;