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>
24 #include "llvm/Support/ConvertUTF.h"
25 #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
27 #include "lldb/Core/DataBufferHeap.h"
28 #include "lldb/Core/Error.h"
29 #include "lldb/Core/Log.h"
30 #include "lldb/Host/Config.h"
31 #include "lldb/Host/FileSpec.h"
32 #include "lldb/Host/FileSystem.h"
35 using namespace lldb_private;
37 static const char *GetStreamOpenModeFromOptions(uint32_t options) {
38 if (options & File::eOpenOptionAppend) {
39 if (options & File::eOpenOptionRead) {
40 if (options & File::eOpenOptionCanCreateNewOnly)
44 } else if (options & File::eOpenOptionWrite) {
45 if (options & File::eOpenOptionCanCreateNewOnly)
50 } else if (options & File::eOpenOptionRead &&
51 options & File::eOpenOptionWrite) {
52 if (options & File::eOpenOptionCanCreate) {
53 if (options & File::eOpenOptionCanCreateNewOnly)
59 } else if (options & File::eOpenOptionRead) {
61 } else if (options & File::eOpenOptionWrite) {
67 int File::kInvalidDescriptor = -1;
68 FILE *File::kInvalidStream = NULL;
70 File::File(const char *path, uint32_t options, uint32_t permissions)
71 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
72 m_stream(kInvalidStream), m_options(), m_own_stream(false),
73 m_is_interactive(eLazyBoolCalculate),
74 m_is_real_terminal(eLazyBoolCalculate) {
75 Open(path, options, permissions);
78 File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions)
79 : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
80 m_stream(kInvalidStream), m_options(0), m_own_stream(false),
81 m_is_interactive(eLazyBoolCalculate),
82 m_is_real_terminal(eLazyBoolCalculate)
86 Open(filespec.GetPath().c_str(), options, permissions);
90 File::~File() { Close(); }
92 int File::GetDescriptor() const {
93 if (DescriptorIsValid())
96 // Don't open the file descriptor if we don't need to, just get it from the
97 // stream if we have one.
98 if (StreamIsValid()) {
99 #if defined(LLVM_ON_WIN32)
100 return _fileno(m_stream);
102 return fileno(m_stream);
106 // Invalid descriptor and invalid stream, return invalid descriptor.
107 return kInvalidDescriptor;
110 IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; }
112 void File::SetDescriptor(int fd, bool transfer_ownership) {
116 m_should_close_fd = transfer_ownership;
119 FILE *File::GetStream() {
120 if (!StreamIsValid()) {
121 if (DescriptorIsValid()) {
122 const char *mode = GetStreamOpenModeFromOptions(m_options);
124 if (!m_should_close_fd) {
125 // We must duplicate the file descriptor if we don't own it because
126 // when you call fdopen, the stream will own the fd
128 m_descriptor = ::_dup(GetDescriptor());
130 m_descriptor = dup(GetDescriptor());
132 m_should_close_fd = true;
136 m_stream = ::fdopen(m_descriptor, mode);
137 } while (m_stream == NULL && errno == EINTR);
139 // If we got a stream, then we own the stream and should no
140 // longer own the descriptor because fclose() will close it for us
144 m_should_close_fd = false;
152 void File::SetStream(FILE *fh, bool transfer_ownership) {
156 m_own_stream = transfer_ownership;
159 Error File::Open(const char *path, uint32_t options, uint32_t permissions) {
165 const bool read = options & eOpenOptionRead;
166 const bool write = options & eOpenOptionWrite;
173 if (options & eOpenOptionAppend)
176 if (options & eOpenOptionTruncate)
179 if (options & eOpenOptionCanCreate)
182 if (options & eOpenOptionCanCreateNewOnly)
183 oflag |= O_CREAT | O_EXCL;
188 if (options & eOpenOptionDontFollowSymlinks)
194 if (options & eOpenOptionNonBlocking)
196 if (options & eOpenOptionCloseOnExec)
203 if (oflag & O_CREAT) {
204 if (permissions & lldb::eFilePermissionsUserRead)
206 if (permissions & lldb::eFilePermissionsUserWrite)
208 if (permissions & lldb::eFilePermissionsUserExecute)
210 if (permissions & lldb::eFilePermissionsGroupRead)
212 if (permissions & lldb::eFilePermissionsGroupWrite)
214 if (permissions & lldb::eFilePermissionsGroupExecute)
216 if (permissions & lldb::eFilePermissionsWorldRead)
218 if (permissions & lldb::eFilePermissionsWorldWrite)
220 if (permissions & lldb::eFilePermissionsWorldExecute)
227 if (!llvm::ConvertUTF8toWide(path, wpath)) {
229 error.SetErrorString("Error converting path to UTF-16");
232 ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode);
234 m_descriptor = ::open(path, oflag, mode);
236 } while (m_descriptor < 0 && errno == EINTR);
238 if (!DescriptorIsValid())
239 error.SetErrorToErrno();
241 m_should_close_fd = true;
248 uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) {
250 struct stat file_stats;
251 int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats);
252 if (stat_result == -1)
253 error.SetErrorToErrno();
256 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
259 error.SetErrorString("empty file spec");
263 uint32_t File::GetPermissions(Error &error) const {
264 int fd = GetDescriptor();
265 if (fd != kInvalidDescriptor) {
266 struct stat file_stats;
267 if (::fstat(fd, &file_stats) == -1)
268 error.SetErrorToErrno();
271 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
274 error.SetErrorString("invalid file descriptor");
279 Error File::Close() {
281 if (StreamIsValid() && m_own_stream) {
282 if (::fclose(m_stream) == EOF)
283 error.SetErrorToErrno();
286 if (DescriptorIsValid() && m_should_close_fd) {
287 if (::close(m_descriptor) != 0)
288 error.SetErrorToErrno();
290 m_descriptor = kInvalidDescriptor;
291 m_stream = kInvalidStream;
293 m_own_stream = false;
294 m_should_close_fd = false;
295 m_is_interactive = eLazyBoolCalculate;
296 m_is_real_terminal = eLazyBoolCalculate;
304 m_own_stream = false;
305 m_is_interactive = m_supports_colors = m_is_real_terminal =
309 Error File::GetFileSpec(FileSpec &file_spec) const {
311 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
314 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
315 error.SetErrorToErrno();
317 file_spec.SetFile(path, false);
319 error.SetErrorString("invalid file handle");
321 #elif defined(__linux__)
324 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
325 error.SetErrorString("cannot resolve file descriptor");
328 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
329 error.SetErrorToErrno();
332 file_spec.SetFile(path, false);
336 error.SetErrorString("File::GetFileSpec is not supported on this platform");
344 off_t File::SeekFromStart(off_t offset, Error *error_ptr) {
346 if (DescriptorIsValid()) {
347 result = ::lseek(m_descriptor, offset, SEEK_SET);
351 error_ptr->SetErrorToErrno();
355 } else if (StreamIsValid()) {
356 result = ::fseek(m_stream, offset, SEEK_SET);
360 error_ptr->SetErrorToErrno();
364 } else if (error_ptr) {
365 error_ptr->SetErrorString("invalid file handle");
370 off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) {
372 if (DescriptorIsValid()) {
373 result = ::lseek(m_descriptor, offset, SEEK_CUR);
377 error_ptr->SetErrorToErrno();
381 } else if (StreamIsValid()) {
382 result = ::fseek(m_stream, offset, SEEK_CUR);
386 error_ptr->SetErrorToErrno();
390 } else if (error_ptr) {
391 error_ptr->SetErrorString("invalid file handle");
396 off_t File::SeekFromEnd(off_t offset, Error *error_ptr) {
398 if (DescriptorIsValid()) {
399 result = ::lseek(m_descriptor, offset, SEEK_END);
403 error_ptr->SetErrorToErrno();
407 } else if (StreamIsValid()) {
408 result = ::fseek(m_stream, offset, SEEK_END);
412 error_ptr->SetErrorToErrno();
416 } else if (error_ptr) {
417 error_ptr->SetErrorString("invalid file handle");
422 Error File::Flush() {
424 if (StreamIsValid()) {
427 err = ::fflush(m_stream);
428 } while (err == EOF && errno == EINTR);
431 error.SetErrorToErrno();
432 } else if (!DescriptorIsValid()) {
433 error.SetErrorString("invalid file handle");
440 if (DescriptorIsValid()) {
442 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
444 error.SetErrorToGenericError();
448 err = ::fsync(m_descriptor);
449 } while (err == -1 && errno == EINTR);
452 error.SetErrorToErrno();
455 error.SetErrorString("invalid file handle");
460 #if defined(__APPLE__)
461 // Darwin kernels only can read/write <= INT_MAX bytes
462 #define MAX_READ_SIZE INT_MAX
463 #define MAX_WRITE_SIZE INT_MAX
466 Error File::Read(void *buf, size_t &num_bytes) {
469 #if defined(MAX_READ_SIZE)
470 if (num_bytes > MAX_READ_SIZE) {
471 uint8_t *p = (uint8_t *)buf;
472 size_t bytes_left = num_bytes;
473 // Init the num_bytes read to zero
476 while (bytes_left > 0) {
477 size_t curr_num_bytes;
478 if (bytes_left > MAX_READ_SIZE)
479 curr_num_bytes = MAX_READ_SIZE;
481 curr_num_bytes = bytes_left;
483 error = Read(p + num_bytes, curr_num_bytes);
485 // Update how many bytes were read
486 num_bytes += curr_num_bytes;
487 if (bytes_left < curr_num_bytes)
490 bytes_left -= curr_num_bytes;
499 ssize_t bytes_read = -1;
500 if (DescriptorIsValid()) {
502 bytes_read = ::read(m_descriptor, buf, num_bytes);
503 } while (bytes_read < 0 && errno == EINTR);
505 if (bytes_read == -1) {
506 error.SetErrorToErrno();
509 num_bytes = bytes_read;
510 } else if (StreamIsValid()) {
511 bytes_read = ::fread(buf, 1, num_bytes, m_stream);
513 if (bytes_read == 0) {
514 if (::feof(m_stream))
515 error.SetErrorString("feof");
516 else if (::ferror(m_stream))
517 error.SetErrorString("ferror");
520 num_bytes = bytes_read;
523 error.SetErrorString("invalid file handle");
528 Error File::Write(const void *buf, size_t &num_bytes) {
531 #if defined(MAX_WRITE_SIZE)
532 if (num_bytes > MAX_WRITE_SIZE) {
533 const uint8_t *p = (const uint8_t *)buf;
534 size_t bytes_left = num_bytes;
535 // Init the num_bytes written to zero
538 while (bytes_left > 0) {
539 size_t curr_num_bytes;
540 if (bytes_left > MAX_WRITE_SIZE)
541 curr_num_bytes = MAX_WRITE_SIZE;
543 curr_num_bytes = bytes_left;
545 error = Write(p + num_bytes, curr_num_bytes);
547 // Update how many bytes were read
548 num_bytes += curr_num_bytes;
549 if (bytes_left < curr_num_bytes)
552 bytes_left -= curr_num_bytes;
561 ssize_t bytes_written = -1;
562 if (DescriptorIsValid()) {
564 bytes_written = ::write(m_descriptor, buf, num_bytes);
565 } while (bytes_written < 0 && errno == EINTR);
567 if (bytes_written == -1) {
568 error.SetErrorToErrno();
571 num_bytes = bytes_written;
572 } else if (StreamIsValid()) {
573 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
575 if (bytes_written == 0) {
576 if (::feof(m_stream))
577 error.SetErrorString("feof");
578 else if (::ferror(m_stream))
579 error.SetErrorString("ferror");
582 num_bytes = bytes_written;
586 error.SetErrorString("invalid file handle");
592 Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
595 #if defined(MAX_READ_SIZE)
596 if (num_bytes > MAX_READ_SIZE) {
597 uint8_t *p = (uint8_t *)buf;
598 size_t bytes_left = num_bytes;
599 // Init the num_bytes read to zero
602 while (bytes_left > 0) {
603 size_t curr_num_bytes;
604 if (bytes_left > MAX_READ_SIZE)
605 curr_num_bytes = MAX_READ_SIZE;
607 curr_num_bytes = bytes_left;
609 error = Read(p + num_bytes, curr_num_bytes, offset);
611 // Update how many bytes were read
612 num_bytes += curr_num_bytes;
613 if (bytes_left < curr_num_bytes)
616 bytes_left -= curr_num_bytes;
626 int fd = GetDescriptor();
627 if (fd != kInvalidDescriptor) {
628 ssize_t bytes_read = -1;
630 bytes_read = ::pread(fd, buf, num_bytes, offset);
631 } while (bytes_read < 0 && errno == EINTR);
633 if (bytes_read < 0) {
635 error.SetErrorToErrno();
637 offset += bytes_read;
638 num_bytes = bytes_read;
642 error.SetErrorString("invalid file handle");
645 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
646 SeekFromStart(offset);
647 error = Read(buf, num_bytes);
654 Error File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
655 DataBufferSP &data_buffer_sp) {
659 int fd = GetDescriptor();
660 if (fd != kInvalidDescriptor) {
661 struct stat file_stats;
662 if (::fstat(fd, &file_stats) == 0) {
663 if (file_stats.st_size > offset) {
664 const size_t bytes_left = file_stats.st_size - offset;
665 if (num_bytes > bytes_left)
666 num_bytes = bytes_left;
668 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
669 std::unique_ptr<DataBufferHeap> data_heap_ap;
670 data_heap_ap.reset(new DataBufferHeap());
671 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
673 if (data_heap_ap.get()) {
674 error = Read(data_heap_ap->GetBytes(), num_bytes, offset);
675 if (error.Success()) {
676 // Make sure we read exactly what we asked for and if we got
677 // less, adjust the array
678 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
679 data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
680 data_buffer_sp.reset(data_heap_ap.release());
685 error.SetErrorString("file is empty");
687 error.SetErrorToErrno();
689 error.SetErrorString("invalid file handle");
691 error.SetErrorString("invalid file handle");
694 data_buffer_sp.reset();
698 Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
701 #if defined(MAX_WRITE_SIZE)
702 if (num_bytes > MAX_WRITE_SIZE) {
703 const uint8_t *p = (const uint8_t *)buf;
704 size_t bytes_left = num_bytes;
705 // Init the num_bytes written to zero
708 while (bytes_left > 0) {
709 size_t curr_num_bytes;
710 if (bytes_left > MAX_WRITE_SIZE)
711 curr_num_bytes = MAX_WRITE_SIZE;
713 curr_num_bytes = bytes_left;
715 error = Write(p + num_bytes, curr_num_bytes, offset);
717 // Update how many bytes were read
718 num_bytes += curr_num_bytes;
719 if (bytes_left < curr_num_bytes)
722 bytes_left -= curr_num_bytes;
731 int fd = GetDescriptor();
732 if (fd != kInvalidDescriptor) {
734 ssize_t bytes_written = -1;
736 bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset);
737 } while (bytes_written < 0 && errno == EINTR);
739 if (bytes_written < 0) {
741 error.SetErrorToErrno();
743 offset += bytes_written;
744 num_bytes = bytes_written;
747 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
748 error = Write(buf, num_bytes);
749 long after = ::lseek(m_descriptor, 0, SEEK_CUR);
758 error.SetErrorString("invalid file handle");
763 //------------------------------------------------------------------
764 // Print some formatted output to the stream.
765 //------------------------------------------------------------------
766 size_t File::Printf(const char *format, ...) {
768 va_start(args, format);
769 size_t result = PrintfVarArg(format, args);
774 //------------------------------------------------------------------
775 // Print some formatted output to the stream.
776 //------------------------------------------------------------------
777 size_t File::PrintfVarArg(const char *format, va_list args) {
779 if (DescriptorIsValid()) {
781 result = vasprintf(&s, format, args);
784 size_t s_len = result;
790 } else if (StreamIsValid()) {
791 result = ::vfprintf(m_stream, format, args);
796 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
798 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
800 else if (open_options & eOpenOptionWrite)
803 if (open_options & eOpenOptionAppend)
806 if (open_options & eOpenOptionTruncate)
809 if (open_options & eOpenOptionNonBlocking)
812 if (open_options & eOpenOptionCanCreateNewOnly)
813 mode |= O_CREAT | O_EXCL;
814 else if (open_options & eOpenOptionCanCreate)
820 void File::CalculateInteractiveAndTerminal() {
821 const int fd = GetDescriptor();
823 m_is_interactive = eLazyBoolNo;
824 m_is_real_terminal = eLazyBoolNo;
827 m_is_interactive = eLazyBoolYes;
828 m_is_real_terminal = eLazyBoolYes;
832 m_is_interactive = eLazyBoolYes;
833 struct winsize window_size;
834 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
835 if (window_size.ws_col > 0) {
836 m_is_real_terminal = eLazyBoolYes;
837 if (llvm::sys::Process::FileDescriptorHasColors(fd))
838 m_supports_colors = eLazyBoolYes;
846 bool File::GetIsInteractive() {
847 if (m_is_interactive == eLazyBoolCalculate)
848 CalculateInteractiveAndTerminal();
849 return m_is_interactive == eLazyBoolYes;
852 bool File::GetIsRealTerminal() {
853 if (m_is_real_terminal == eLazyBoolCalculate)
854 CalculateInteractiveAndTerminal();
855 return m_is_real_terminal == eLazyBoolYes;
858 bool File::GetIsTerminalWithColors() {
859 if (m_supports_colors == eLazyBoolCalculate)
860 CalculateInteractiveAndTerminal();
861 return m_supports_colors == eLazyBoolYes;