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>
26 #include "llvm/Support/ConvertUTF.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
30 #include "lldb/Host/Config.h"
31 #include "lldb/Utility/DataBufferHeap.h"
32 #include "lldb/Utility/FileSpec.h"
33 #include "lldb/Utility/Log.h"
36 using namespace lldb_private;
38 static const char *GetStreamOpenModeFromOptions(uint32_t options) {
39 if (options & File::eOpenOptionAppend) {
40 if (options & File::eOpenOptionRead) {
41 if (options & File::eOpenOptionCanCreateNewOnly)
45 } else if (options & File::eOpenOptionWrite) {
46 if (options & File::eOpenOptionCanCreateNewOnly)
51 } else if (options & File::eOpenOptionRead &&
52 options & File::eOpenOptionWrite) {
53 if (options & File::eOpenOptionCanCreate) {
54 if (options & File::eOpenOptionCanCreateNewOnly)
60 } else if (options & File::eOpenOptionRead) {
62 } else if (options & File::eOpenOptionWrite) {
68 int File::kInvalidDescriptor = -1;
69 FILE *File::kInvalidStream = NULL;
71 File::File(const char *path, uint32_t options, uint32_t permissions)
72 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
73 m_stream(kInvalidStream), m_options(), m_own_stream(false),
74 m_is_interactive(eLazyBoolCalculate),
75 m_is_real_terminal(eLazyBoolCalculate) {
76 Open(path, options, permissions);
79 File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions)
80 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
81 m_stream(kInvalidStream), m_options(0), m_own_stream(false),
82 m_is_interactive(eLazyBoolCalculate),
83 m_is_real_terminal(eLazyBoolCalculate)
87 Open(filespec.GetPath().c_str(), options, permissions);
91 File::~File() { Close(); }
93 int File::GetDescriptor() const {
94 if (DescriptorIsValid())
97 // Don't open the file descriptor if we don't need to, just get it from the
98 // stream if we have one.
99 if (StreamIsValid()) {
100 #if defined(LLVM_ON_WIN32)
101 return _fileno(m_stream);
103 return fileno(m_stream);
107 // Invalid descriptor and invalid stream, return invalid descriptor.
108 return kInvalidDescriptor;
111 IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
113 void File::SetDescriptor(int fd, bool transfer_ownership) {
117 m_should_close_fd = transfer_ownership;
120 FILE *File::GetStream() {
121 if (!StreamIsValid()) {
122 if (DescriptorIsValid()) {
123 const char *mode = GetStreamOpenModeFromOptions(m_options);
125 if (!m_should_close_fd) {
126 // We must duplicate the file descriptor if we don't own it because
127 // when you call fdopen, the stream will own the fd
129 m_descriptor = ::_dup(GetDescriptor());
131 m_descriptor = dup(GetDescriptor());
133 m_should_close_fd = true;
137 m_stream = ::fdopen(m_descriptor, mode);
138 } while (m_stream == NULL && errno == EINTR);
140 // If we got a stream, then we own the stream and should no
141 // longer own the descriptor because fclose() will close it for us
145 m_should_close_fd = false;
153 void File::SetStream(FILE *fh, bool transfer_ownership) {
157 m_own_stream = transfer_ownership;
160 Error File::Open(const char *path, uint32_t options, uint32_t permissions) {
166 const bool read = options & eOpenOptionRead;
167 const bool write = options & eOpenOptionWrite;
174 if (options & eOpenOptionAppend)
177 if (options & eOpenOptionTruncate)
180 if (options & eOpenOptionCanCreate)
183 if (options & eOpenOptionCanCreateNewOnly)
184 oflag |= O_CREAT | O_EXCL;
189 if (options & eOpenOptionDontFollowSymlinks)
195 if (options & eOpenOptionNonBlocking)
197 if (options & eOpenOptionCloseOnExec)
204 if (oflag & O_CREAT) {
205 if (permissions & lldb::eFilePermissionsUserRead)
207 if (permissions & lldb::eFilePermissionsUserWrite)
209 if (permissions & lldb::eFilePermissionsUserExecute)
211 if (permissions & lldb::eFilePermissionsGroupRead)
213 if (permissions & lldb::eFilePermissionsGroupWrite)
215 if (permissions & lldb::eFilePermissionsGroupExecute)
217 if (permissions & lldb::eFilePermissionsWorldRead)
219 if (permissions & lldb::eFilePermissionsWorldWrite)
221 if (permissions & lldb::eFilePermissionsWorldExecute)
228 if (!llvm::ConvertUTF8toWide(path, wpath)) {
230 error.SetErrorString("Error converting path to UTF-16");
233 ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode);
235 m_descriptor = ::open(path, oflag, mode);
237 } while (m_descriptor < 0 && errno == EINTR);
239 if (!DescriptorIsValid())
240 error.SetErrorToErrno();
242 m_should_close_fd = true;
249 uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) {
252 auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath());
255 error = Error(Perms.getError());
258 error.SetErrorString("empty file spec");
262 uint32_t File::GetPermissions(Error &error) const {
263 int fd = GetDescriptor();
264 if (fd != kInvalidDescriptor) {
265 struct stat file_stats;
266 if (::fstat(fd, &file_stats) == -1)
267 error.SetErrorToErrno();
270 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
273 error.SetErrorString("invalid file descriptor");
278 Error File::Close() {
280 if (StreamIsValid() && m_own_stream) {
281 if (::fclose(m_stream) == EOF)
282 error.SetErrorToErrno();
285 if (DescriptorIsValid() && m_should_close_fd) {
286 if (::close(m_descriptor) != 0)
287 error.SetErrorToErrno();
289 m_descriptor = kInvalidDescriptor;
290 m_stream = kInvalidStream;
292 m_own_stream = false;
293 m_should_close_fd = false;
294 m_is_interactive = eLazyBoolCalculate;
295 m_is_real_terminal = eLazyBoolCalculate;
303 m_own_stream = false;
304 m_is_interactive = m_supports_colors = m_is_real_terminal =
308 Error File::GetFileSpec(FileSpec &file_spec) const {
313 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
314 error.SetErrorToErrno();
316 file_spec.SetFile(path, false);
318 error.SetErrorString("invalid file handle");
320 #elif defined(__linux__)
323 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
324 error.SetErrorString("cannot resolve file descriptor");
327 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
328 error.SetErrorToErrno();
331 file_spec.SetFile(path, false);
335 error.SetErrorString("File::GetFileSpec is not supported on this platform");
343 off_t File::SeekFromStart(off_t offset, Error *error_ptr) {
345 if (DescriptorIsValid()) {
346 result = ::lseek(m_descriptor, offset, SEEK_SET);
350 error_ptr->SetErrorToErrno();
354 } else if (StreamIsValid()) {
355 result = ::fseek(m_stream, offset, SEEK_SET);
359 error_ptr->SetErrorToErrno();
363 } else if (error_ptr) {
364 error_ptr->SetErrorString("invalid file handle");
369 off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) {
371 if (DescriptorIsValid()) {
372 result = ::lseek(m_descriptor, offset, SEEK_CUR);
376 error_ptr->SetErrorToErrno();
380 } else if (StreamIsValid()) {
381 result = ::fseek(m_stream, offset, SEEK_CUR);
385 error_ptr->SetErrorToErrno();
389 } else if (error_ptr) {
390 error_ptr->SetErrorString("invalid file handle");
395 off_t File::SeekFromEnd(off_t offset, Error *error_ptr) {
397 if (DescriptorIsValid()) {
398 result = ::lseek(m_descriptor, offset, SEEK_END);
402 error_ptr->SetErrorToErrno();
406 } else if (StreamIsValid()) {
407 result = ::fseek(m_stream, offset, SEEK_END);
411 error_ptr->SetErrorToErrno();
415 } else if (error_ptr) {
416 error_ptr->SetErrorString("invalid file handle");
421 Error File::Flush() {
423 if (StreamIsValid()) {
426 err = ::fflush(m_stream);
427 } while (err == EOF && errno == EINTR);
430 error.SetErrorToErrno();
431 } else if (!DescriptorIsValid()) {
432 error.SetErrorString("invalid file handle");
439 if (DescriptorIsValid()) {
441 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
443 error.SetErrorToGenericError();
447 err = ::fsync(m_descriptor);
448 } while (err == -1 && errno == EINTR);
451 error.SetErrorToErrno();
454 error.SetErrorString("invalid file handle");
459 #if defined(__APPLE__)
460 // Darwin kernels only can read/write <= INT_MAX bytes
461 #define MAX_READ_SIZE INT_MAX
462 #define MAX_WRITE_SIZE INT_MAX
465 Error File::Read(void *buf, size_t &num_bytes) {
468 #if defined(MAX_READ_SIZE)
469 if (num_bytes > MAX_READ_SIZE) {
470 uint8_t *p = (uint8_t *)buf;
471 size_t bytes_left = num_bytes;
472 // Init the num_bytes read to zero
475 while (bytes_left > 0) {
476 size_t curr_num_bytes;
477 if (bytes_left > MAX_READ_SIZE)
478 curr_num_bytes = MAX_READ_SIZE;
480 curr_num_bytes = bytes_left;
482 error = Read(p + num_bytes, curr_num_bytes);
484 // Update how many bytes were read
485 num_bytes += curr_num_bytes;
486 if (bytes_left < curr_num_bytes)
489 bytes_left -= curr_num_bytes;
498 ssize_t bytes_read = -1;
499 if (DescriptorIsValid()) {
501 bytes_read = ::read(m_descriptor, buf, num_bytes);
502 } while (bytes_read < 0 && errno == EINTR);
504 if (bytes_read == -1) {
505 error.SetErrorToErrno();
508 num_bytes = bytes_read;
509 } else if (StreamIsValid()) {
510 bytes_read = ::fread(buf, 1, num_bytes, m_stream);
512 if (bytes_read == 0) {
513 if (::feof(m_stream))
514 error.SetErrorString("feof");
515 else if (::ferror(m_stream))
516 error.SetErrorString("ferror");
519 num_bytes = bytes_read;
522 error.SetErrorString("invalid file handle");
527 Error File::Write(const void *buf, size_t &num_bytes) {
530 #if defined(MAX_WRITE_SIZE)
531 if (num_bytes > MAX_WRITE_SIZE) {
532 const uint8_t *p = (const uint8_t *)buf;
533 size_t bytes_left = num_bytes;
534 // Init the num_bytes written to zero
537 while (bytes_left > 0) {
538 size_t curr_num_bytes;
539 if (bytes_left > MAX_WRITE_SIZE)
540 curr_num_bytes = MAX_WRITE_SIZE;
542 curr_num_bytes = bytes_left;
544 error = Write(p + num_bytes, curr_num_bytes);
546 // Update how many bytes were read
547 num_bytes += curr_num_bytes;
548 if (bytes_left < curr_num_bytes)
551 bytes_left -= curr_num_bytes;
560 ssize_t bytes_written = -1;
561 if (DescriptorIsValid()) {
563 bytes_written = ::write(m_descriptor, buf, num_bytes);
564 } while (bytes_written < 0 && errno == EINTR);
566 if (bytes_written == -1) {
567 error.SetErrorToErrno();
570 num_bytes = bytes_written;
571 } else if (StreamIsValid()) {
572 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
574 if (bytes_written == 0) {
575 if (::feof(m_stream))
576 error.SetErrorString("feof");
577 else if (::ferror(m_stream))
578 error.SetErrorString("ferror");
581 num_bytes = bytes_written;
585 error.SetErrorString("invalid file handle");
591 Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
594 #if defined(MAX_READ_SIZE)
595 if (num_bytes > MAX_READ_SIZE) {
596 uint8_t *p = (uint8_t *)buf;
597 size_t bytes_left = num_bytes;
598 // Init the num_bytes read to zero
601 while (bytes_left > 0) {
602 size_t curr_num_bytes;
603 if (bytes_left > MAX_READ_SIZE)
604 curr_num_bytes = MAX_READ_SIZE;
606 curr_num_bytes = bytes_left;
608 error = Read(p + num_bytes, curr_num_bytes, offset);
610 // Update how many bytes were read
611 num_bytes += curr_num_bytes;
612 if (bytes_left < curr_num_bytes)
615 bytes_left -= curr_num_bytes;
625 int fd = GetDescriptor();
626 if (fd != kInvalidDescriptor) {
627 ssize_t bytes_read = -1;
629 bytes_read = ::pread(fd, buf, num_bytes, offset);
630 } while (bytes_read < 0 && errno == EINTR);
632 if (bytes_read < 0) {
634 error.SetErrorToErrno();
636 offset += bytes_read;
637 num_bytes = bytes_read;
641 error.SetErrorString("invalid file handle");
644 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
645 SeekFromStart(offset);
646 error = Read(buf, num_bytes);
653 Error File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
654 DataBufferSP &data_buffer_sp) {
658 int fd = GetDescriptor();
659 if (fd != kInvalidDescriptor) {
660 struct stat file_stats;
661 if (::fstat(fd, &file_stats) == 0) {
662 if (file_stats.st_size > offset) {
663 const size_t bytes_left = file_stats.st_size - offset;
664 if (num_bytes > bytes_left)
665 num_bytes = bytes_left;
667 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
668 std::unique_ptr<DataBufferHeap> data_heap_ap;
669 data_heap_ap.reset(new DataBufferHeap());
670 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
672 if (data_heap_ap.get()) {
673 error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
674 if (error.Success()) {
675 // Make sure we read exactly what we asked for and if we got
676 // less, adjust the array
677 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
678 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
679 data_buffer_sp.reset(data_heap_ap.release());
684 error.SetErrorString("file is empty");
686 error.SetErrorToErrno();
688 error.SetErrorString("invalid file handle");
690 error.SetErrorString("invalid file handle");
693 data_buffer_sp.reset();
697 Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
700 #if defined(MAX_WRITE_SIZE)
701 if (num_bytes > MAX_WRITE_SIZE) {
702 const uint8_t *p = (const uint8_t *)buf;
703 size_t bytes_left = num_bytes;
704 // Init the num_bytes written to zero
707 while (bytes_left > 0) {
708 size_t curr_num_bytes;
709 if (bytes_left > MAX_WRITE_SIZE)
710 curr_num_bytes = MAX_WRITE_SIZE;
712 curr_num_bytes = bytes_left;
714 error = Write(p + num_bytes, curr_num_bytes, offset);
716 // Update how many bytes were read
717 num_bytes += curr_num_bytes;
718 if (bytes_left < curr_num_bytes)
721 bytes_left -= curr_num_bytes;
730 int fd = GetDescriptor();
731 if (fd != kInvalidDescriptor) {
733 ssize_t bytes_written = -1;
735 bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset);
736 } while (bytes_written < 0 && errno == EINTR);
738 if (bytes_written < 0) {
740 error.SetErrorToErrno();
742 offset += bytes_written;
743 num_bytes = bytes_written;
746 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
747 error = Write(buf, num_bytes);
748 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
757 error.SetErrorString("invalid file handle");
762 //------------------------------------------------------------------
763 // Print some formatted output to the stream.
764 //------------------------------------------------------------------
765 size_t File::Printf(const char *format, ...) {
767 va_start(args, format);
768 size_t result = PrintfVarArg(format, args);
773 //------------------------------------------------------------------
774 // Print some formatted output to the stream.
775 //------------------------------------------------------------------
776 size_t File::PrintfVarArg(const char *format, va_list args) {
778 if (DescriptorIsValid()) {
780 result = vasprintf(&s, format, args);
783 size_t s_len = result;
789 } else if (StreamIsValid()) {
790 result = ::vfprintf(m_stream, format, args);
795 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
797 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
799 else if (open_options & eOpenOptionWrite)
802 if (open_options & eOpenOptionAppend)
805 if (open_options & eOpenOptionTruncate)
808 if (open_options & eOpenOptionNonBlocking)
811 if (open_options & eOpenOptionCanCreateNewOnly)
812 mode |= O_CREAT | O_EXCL;
813 else if (open_options & eOpenOptionCanCreate)
819 void File::CalculateInteractiveAndTerminal() {
820 const int fd = GetDescriptor();
822 m_is_interactive = eLazyBoolNo;
823 m_is_real_terminal = eLazyBoolNo;
826 m_is_interactive = eLazyBoolYes;
827 m_is_real_terminal = eLazyBoolYes;
831 m_is_interactive = eLazyBoolYes;
832 struct winsize window_size;
833 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
834 if (window_size.ws_col > 0) {
835 m_is_real_terminal = eLazyBoolYes;
836 if (llvm::sys::Process::FileDescriptorHasColors(fd))
837 m_supports_colors = eLazyBoolYes;
845 bool File::GetIsInteractive() {
846 if (m_is_interactive == eLazyBoolCalculate)
847 CalculateInteractiveAndTerminal();
848 return m_is_interactive == eLazyBoolYes;
851 bool File::GetIsRealTerminal() {
852 if (m_is_real_terminal == eLazyBoolCalculate)
853 CalculateInteractiveAndTerminal();
854 return m_is_real_terminal == eLazyBoolYes;
857 bool File::GetIsTerminalWithColors() {
858 if (m_supports_colors == eLazyBoolCalculate)
859 CalculateInteractiveAndTerminal();
860 return m_supports_colors == eLazyBoolYes;