| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Host/windows/FileWindows.h" | |
| #include "lldb/Host/windows/windows.h" | |
| #include <climits> | |
| #include <io.h> | |
| #include <mutex> | |
| #include <stdio.h> | |
| #include "lldb/Utility/Status.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace lldb_private; | |
| NativeFileWindows::NativeFileWindows(FILE *fh, OpenOptions options, | |
| bool transfer_ownership) | |
| : NativeFileBase(fh, options, transfer_ownership) { | |
| HANDLE h = INVALID_HANDLE_VALUE; | |
| if (fh == stdin) | |
| h = ::GetStdHandle(STD_INPUT_HANDLE); | |
| else if (fh == stdout) | |
| h = ::GetStdHandle(STD_OUTPUT_HANDLE); | |
| else if (fh == stderr) | |
| h = ::GetStdHandle(STD_ERROR_HANDLE); | |
| m_is_windows_console = | |
| h != INVALID_HANDLE_VALUE && ::GetFileType(h) == FILE_TYPE_CHAR; | |
| } | |
| NativeFileWindows::NativeFileWindows(int fd, OpenOptions options, | |
| bool transfer_ownership) | |
| : NativeFileBase(fd, options, transfer_ownership) { | |
| HANDLE h = INVALID_HANDLE_VALUE; | |
| if (fd == STDIN_FILENO) | |
| h = ::GetStdHandle(STD_INPUT_HANDLE); | |
| else if (fd == STDOUT_FILENO) | |
| h = ::GetStdHandle(STD_OUTPUT_HANDLE); | |
| else if (fd == STDERR_FILENO) | |
| h = ::GetStdHandle(STD_ERROR_HANDLE); | |
| m_is_windows_console = | |
| h != INVALID_HANDLE_VALUE && ::GetFileType(h) == FILE_TYPE_CHAR; | |
| } | |
| void NativeFileWindows::CalculateInteractiveAndTerminal() { | |
| const int fd = GetDescriptor(); | |
| if (!File::DescriptorIsValid(fd)) { | |
| m_is_interactive = eLazyBoolNo; | |
| m_is_real_terminal = eLazyBoolNo; | |
| m_supports_colors = eLazyBoolNo; | |
| return; | |
| } | |
| m_is_interactive = eLazyBoolNo; | |
| m_is_real_terminal = eLazyBoolNo; | |
| if (_isatty(fd)) { | |
| m_is_interactive = eLazyBoolYes; | |
| m_is_real_terminal = eLazyBoolYes; | |
| #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) | |
| m_supports_colors = eLazyBoolYes; | |
| #endif | |
| } | |
| } | |
| int NativeFileWindows::Fileno(FILE *fh) const { return ::_fileno(fh); } | |
| int NativeFileWindows::Dup(int fd) const { return ::_dup(fd); } | |
| IOObject::WaitableHandle NativeFileWindows::GetWaitableHandle() { | |
| return (HANDLE)_get_osfhandle(GetDescriptor()); | |
| } | |
| Status NativeFileWindows::Sync() { | |
| Status error; | |
| if (ValueGuard descriptor_guard = DescriptorIsValid()) { | |
| if (FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)) == 0) | |
| error = Status::FromErrorString("unknown error"); | |
| } else { | |
| error = Status::FromErrorString("invalid file handle"); | |
| } | |
| return error; | |
| } | |
| bool NativeFileWindows::TryWriteStreamUnlocked(const void *buf, | |
| size_t &num_bytes, | |
| Status &error) { | |
| if (!m_is_windows_console) | |
| return false; | |
| // Bypass fwrite for console output: use raw_fd_ostream so that the Windows | |
| // console renders non-ASCII characters via its UTF-16 path. | |
| llvm::raw_fd_ostream(_fileno(m_stream), false) | |
| .write((const char *)buf, num_bytes); | |
| return true; | |
| } | |
| Status NativeFileWindows::Read(void *buf, size_t &num_bytes, off_t &offset) { | |
| Status error; | |
| int fd = GetDescriptor(); | |
| if (fd != kInvalidDescriptor) { | |
| // Win32 has no pread(); emulate it by saving the current offset, seeking, | |
| // reading, and restoring. | |
| std::lock_guard<std::mutex> guard(offset_access_mutex); | |
| long cur = ::lseek(m_descriptor, 0, SEEK_CUR); | |
| SeekFromStart(offset); | |
| error = NativeFileBase::Read(buf, num_bytes); | |
| if (!error.Fail()) | |
| SeekFromStart(cur); | |
| } else { | |
| num_bytes = 0; | |
| error = Status::FromErrorString("invalid file handle"); | |
| } | |
| return error; | |
| } | |
| Status NativeFileWindows::Write(const void *buf, size_t &num_bytes, | |
| off_t &offset) { | |
| Status error; | |
| int fd = GetDescriptor(); | |
| if (fd != kInvalidDescriptor) { | |
| // Win32 has no pwrite(); same trick as Read above, but the post-write | |
| // file position is what the caller wants reported back via `offset`. | |
| std::lock_guard<std::mutex> guard(offset_access_mutex); | |
| long cur = ::lseek(m_descriptor, 0, SEEK_CUR); | |
| SeekFromStart(offset); | |
| error = NativeFileBase::Write(buf, num_bytes); | |
| long after = ::lseek(m_descriptor, 0, SEEK_CUR); | |
| if (!error.Fail()) | |
| SeekFromStart(cur); | |
| offset = after; | |
| } else { | |
| num_bytes = 0; | |
| error = Status::FromErrorString("invalid file handle"); | |
| } | |
| return error; | |
| } | |
| void NativeFileWindows::OnStreamOpened() { | |
| if ((m_options & OpenOptionsModeMask) == eOpenOptionReadOnly) | |
| setvbuf(m_stream, nullptr, _IONBF, 0); | |
| } | |
| char NativeFileWindows::ID = 0; |