975 lines · cpp
1//===-- File.cpp ----------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/File.h"10 11#include <cerrno>12#include <climits>13#include <cstdarg>14#include <cstdio>15#include <fcntl.h>16#include <optional>17 18#ifdef _WIN3219#include "lldb/Host/windows/windows.h"20#else21#include <sys/ioctl.h>22#include <sys/stat.h>23#include <termios.h>24#include <unistd.h>25#endif26 27#include "lldb/Host/Config.h"28#include "lldb/Host/FileSystem.h"29#include "lldb/Host/Host.h"30#include "lldb/Utility/DataBufferHeap.h"31#include "lldb/Utility/FileSpec.h"32#include "lldb/Utility/Log.h"33#include "lldb/Utility/VASPrintf.h"34#include "llvm/ADT/StringExtras.h"35#include "llvm/Support/ConvertUTF.h"36#include "llvm/Support/Errno.h"37#include "llvm/Support/FileSystem.h"38#include "llvm/Support/Process.h"39#include "llvm/Support/raw_ostream.h"40 41using namespace lldb;42using namespace lldb_private;43using llvm::Expected;44 45Expected<const char *>46File::GetStreamOpenModeFromOptions(File::OpenOptions options) {47 File::OpenOptions rw =48 options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |49 File::eOpenOptionReadWrite);50 51 if (options & File::eOpenOptionAppend) {52 if (rw == File::eOpenOptionReadWrite) {53 if (options & File::eOpenOptionCanCreateNewOnly)54 return "a+x";55 else56 return "a+";57 } else if (rw == File::eOpenOptionWriteOnly) {58 if (options & File::eOpenOptionCanCreateNewOnly)59 return "ax";60 else61 return "a";62 }63 } else if (rw == File::eOpenOptionReadWrite) {64 if (options & File::eOpenOptionCanCreate) {65 if (options & File::eOpenOptionCanCreateNewOnly)66 return "w+x";67 else68 return "w+";69 } else70 return "r+";71 } else if (rw == File::eOpenOptionWriteOnly) {72 return "w";73 } else if (rw == File::eOpenOptionReadOnly) {74 return "r";75 }76 return llvm::createStringError(77 llvm::inconvertibleErrorCode(),78 "invalid options, cannot convert to mode string");79}80 81Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {82 OpenOptions opts =83 llvm::StringSwitch<OpenOptions>(mode)84 .Cases({"r", "rb"}, eOpenOptionReadOnly)85 .Cases({"w", "wb"}, eOpenOptionWriteOnly)86 .Cases({"a", "ab"}, eOpenOptionWriteOnly | eOpenOptionAppend |87 eOpenOptionCanCreate)88 .Cases({"r+", "rb+", "r+b"}, eOpenOptionReadWrite)89 .Cases({"w+", "wb+", "w+b"}, eOpenOptionReadWrite |90 eOpenOptionCanCreate |91 eOpenOptionTruncate)92 .Cases({"a+", "ab+", "a+b"}, eOpenOptionReadWrite |93 eOpenOptionAppend |94 eOpenOptionCanCreate)95 .Default(eOpenOptionInvalid);96 if (opts != eOpenOptionInvalid)97 return opts;98 return llvm::createStringError(99 llvm::inconvertibleErrorCode(),100 "invalid mode, cannot convert to File::OpenOptions");101}102 103int File::kInvalidDescriptor = -1;104FILE *File::kInvalidStream = nullptr;105 106Status File::Read(void *buf, size_t &num_bytes) {107 return std::error_code(ENOTSUP, std::system_category());108}109Status File::Write(const void *buf, size_t &num_bytes) {110 return std::error_code(ENOTSUP, std::system_category());111}112 113bool File::IsValid() const { return false; }114 115Status File::Close() { return Flush(); }116 117IOObject::WaitableHandle File::GetWaitableHandle() {118 return IOObject::kInvalidHandleValue;119}120 121Status File::GetFileSpec(FileSpec &file_spec) const {122 file_spec.Clear();123 return std::error_code(ENOTSUP, std::system_category());124}125 126int File::GetDescriptor() const { return kInvalidDescriptor; }127 128FILE *File::GetStream() { return nullptr; }129 130off_t File::SeekFromStart(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::SeekFromCurrent(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 142off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {143 if (error_ptr)144 *error_ptr = std::error_code(ENOTSUP, std::system_category());145 return -1;146}147 148Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {149 return std::error_code(ENOTSUP, std::system_category());150}151 152Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {153 return std::error_code(ENOTSUP, std::system_category());154}155 156Status File::Flush() { return Status(); }157 158Status File::Sync() { return Flush(); }159 160void File::CalculateInteractiveAndTerminal() {161 const int fd = GetDescriptor();162 if (!DescriptorIsValid(fd)) {163 m_is_interactive = eLazyBoolNo;164 m_is_real_terminal = eLazyBoolNo;165 m_supports_colors = eLazyBoolNo;166 return;167 }168 m_is_interactive = eLazyBoolNo;169 m_is_real_terminal = eLazyBoolNo;170#if defined(_WIN32)171 if (_isatty(fd)) {172 m_is_interactive = eLazyBoolYes;173 m_is_real_terminal = eLazyBoolYes;174#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)175 m_supports_colors = eLazyBoolYes;176#endif177 }178#else179 if (isatty(fd)) {180 m_is_interactive = eLazyBoolYes;181 struct winsize window_size;182 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {183 if (window_size.ws_col > 0) {184 m_is_real_terminal = eLazyBoolYes;185 if (llvm::sys::Process::FileDescriptorHasColors(fd))186 m_supports_colors = eLazyBoolYes;187 }188 }189 }190#endif191}192 193bool File::GetIsInteractive() {194 if (m_is_interactive == eLazyBoolCalculate)195 CalculateInteractiveAndTerminal();196 return m_is_interactive == eLazyBoolYes;197}198 199bool File::GetIsRealTerminal() {200 if (m_is_real_terminal == eLazyBoolCalculate)201 CalculateInteractiveAndTerminal();202 return m_is_real_terminal == eLazyBoolYes;203}204 205bool File::GetIsTerminalWithColors() {206 if (m_supports_colors == eLazyBoolCalculate)207 CalculateInteractiveAndTerminal();208 return m_supports_colors == eLazyBoolYes;209}210 211size_t File::Printf(const char *format, ...) {212 va_list args;213 va_start(args, format);214 size_t result = PrintfVarArg(format, args);215 va_end(args);216 return result;217}218 219size_t File::PrintfVarArg(const char *format, va_list args) {220 llvm::SmallString<0> s;221 if (VASprintf(s, format, args)) {222 size_t written = s.size();223 Write(s.data(), written);224 return written;225 }226 return 0;227}228 229Expected<File::OpenOptions> File::GetOptions() const {230 return llvm::createStringError(231 llvm::inconvertibleErrorCode(),232 "GetOptions() not implemented for this File class");233}234 235uint32_t File::GetPermissions(Status &error) const {236 int fd = GetDescriptor();237 if (!DescriptorIsValid(fd)) {238 error = std::error_code(ENOTSUP, std::system_category());239 return 0;240 }241 struct stat file_stats;242 if (::fstat(fd, &file_stats) == -1) {243 error = Status::FromErrno();244 return 0;245 }246 error.Clear();247 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);248}249 250NativeFile::NativeFile() = default;251 252NativeFile::NativeFile(FILE *fh, OpenOptions options, bool transfer_ownership)253 : m_stream(fh), m_options(options), m_own_stream(transfer_ownership) {254#ifdef _WIN32255 // In order to properly display non ASCII characters in Windows, we need to256 // use Windows APIs to print to the console. This is only required if the257 // stream outputs to a console.258 int fd = _fileno(fh);259 is_windows_console =260 ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;261#else262#ifndef NDEBUG263 int fd = fileno(fh);264 if (fd != -1) {265 int required_mode = ConvertOpenOptionsForPOSIXOpen(options) & O_ACCMODE;266 int mode = fcntl(fd, F_GETFL);267 if (mode != -1) {268 mode &= O_ACCMODE;269 // Check that the file is open with a valid subset of the requested file270 // access mode, e.g. if we expected the file to be writable then ensure it271 // was opened with O_WRONLY or O_RDWR.272 assert(273 (required_mode == O_RDWR && mode == O_RDWR) ||274 (required_mode == O_RDONLY && (mode == O_RDWR || mode == O_RDONLY) ||275 (required_mode == O_WRONLY &&276 (mode == O_RDWR || mode == O_WRONLY))) &&277 "invalid file access mode");278 }279 }280#endif281#endif282}283 284NativeFile::NativeFile(int fd, OpenOptions options, bool transfer_ownership)285 : m_descriptor(fd), m_own_descriptor(transfer_ownership),286 m_options(options) {287#ifdef _WIN32288 // In order to properly display non ASCII characters in Windows, we need to289 // use Windows APIs to print to the console. This is only required if the290 // file outputs to a console.291 is_windows_console =292 ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;293#endif294}295 296bool NativeFile::IsValid() const {297 std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex,298 m_stream_mutex);299 return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();300}301 302Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }303 304int NativeFile::GetDescriptor() const {305 if (ValueGuard descriptor_guard = DescriptorIsValid()) {306 return m_descriptor;307 }308 309 // Don't open the file descriptor if we don't need to, just get it from the310 // stream if we have one.311 if (ValueGuard stream_guard = StreamIsValid()) {312#if defined(_WIN32)313 return _fileno(m_stream);314#else315 return fileno(m_stream);316#endif317 }318 319 // Invalid descriptor and invalid stream, return invalid descriptor.320 return kInvalidDescriptor;321}322 323IOObject::WaitableHandle NativeFile::GetWaitableHandle() {324#ifdef _WIN32325 return (HANDLE)_get_osfhandle(GetDescriptor());326#else327 return GetDescriptor();328#endif329}330 331FILE *NativeFile::GetStream() {332 ValueGuard stream_guard = StreamIsValid();333 if (!stream_guard) {334 if (ValueGuard descriptor_guard = DescriptorIsValid()) {335 auto mode = GetStreamOpenModeFromOptions(m_options);336 if (!mode)337 llvm::consumeError(mode.takeError());338 else {339 if (!m_own_descriptor) {340// We must duplicate the file descriptor if we don't own it because when you341// call fdopen, the stream will own the fd342#ifdef _WIN32343 m_descriptor = ::_dup(m_descriptor);344#else345 m_descriptor = dup(m_descriptor);346#endif347 m_own_descriptor = true;348 }349 350 m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,351 mode.get());352 353 // If we got a stream, then we own the stream and should no longer own354 // the descriptor because fclose() will close it for us355 356 if (m_stream) {357 m_own_stream = true;358 m_own_descriptor = false;359 }360 }361 }362 }363 return m_stream;364}365 366Status NativeFile::Close() {367 std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex,368 m_stream_mutex);369 370 Status error;371 372 if (StreamIsValidUnlocked()) {373 if (m_own_stream) {374 if (::fclose(m_stream) == EOF)375 error = Status::FromErrno();376 } else {377 File::OpenOptions rw =378 m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |379 File::eOpenOptionReadWrite);380 381 if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {382 if (::fflush(m_stream) == EOF)383 error = Status::FromErrno();384 }385 }386 }387 388 if (DescriptorIsValidUnlocked() && m_own_descriptor) {389 if (::close(m_descriptor) != 0)390 error = Status::FromErrno();391 }392 393 m_stream = kInvalidStream;394 m_own_stream = false;395 m_descriptor = kInvalidDescriptor;396 m_own_descriptor = false;397 m_options = OpenOptions(0);398 m_is_interactive = eLazyBoolCalculate;399 m_is_real_terminal = eLazyBoolCalculate;400 return error;401}402 403Status NativeFile::GetFileSpec(FileSpec &file_spec) const {404 Status error;405#ifdef F_GETPATH406 if (IsValid()) {407 char path[PATH_MAX];408 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)409 error = Status::FromErrno();410 else411 file_spec.SetFile(path, FileSpec::Style::native);412 } else {413 error = Status::FromErrorString("invalid file handle");414 }415#elif defined(__linux__)416 char proc[64];417 char path[PATH_MAX];418 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)419 error = Status::FromErrorString("cannot resolve file descriptor");420 else {421 ssize_t len;422 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)423 error = Status::FromErrno();424 else {425 path[len] = '\0';426 file_spec.SetFile(path, FileSpec::Style::native);427 }428 }429#else430 error = Status::FromErrorString(431 "NativeFile::GetFileSpec is not supported on this platform");432#endif433 434 if (error.Fail())435 file_spec.Clear();436 return error;437}438 439off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {440 off_t result = 0;441 if (ValueGuard descriptor_guard = DescriptorIsValid()) {442 result = ::lseek(m_descriptor, offset, SEEK_SET);443 444 if (error_ptr) {445 if (result == -1)446 *error_ptr = Status::FromErrno();447 else448 error_ptr->Clear();449 }450 return result;451 }452 453 if (ValueGuard stream_guard = StreamIsValid()) {454 result = ::fseek(m_stream, offset, SEEK_SET);455 456 if (error_ptr) {457 if (result == -1)458 *error_ptr = Status::FromErrno();459 else460 error_ptr->Clear();461 }462 return result;463 }464 465 if (error_ptr)466 *error_ptr = Status::FromErrorString("invalid file handle");467 return result;468}469 470off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {471 off_t result = -1;472 if (ValueGuard descriptor_guard = DescriptorIsValid()) {473 result = ::lseek(m_descriptor, offset, SEEK_CUR);474 475 if (error_ptr) {476 if (result == -1)477 *error_ptr = Status::FromErrno();478 else479 error_ptr->Clear();480 }481 return result;482 }483 484 if (ValueGuard stream_guard = StreamIsValid()) {485 result = ::fseek(m_stream, offset, SEEK_CUR);486 487 if (error_ptr) {488 if (result == -1)489 *error_ptr = Status::FromErrno();490 else491 error_ptr->Clear();492 }493 return result;494 }495 496 if (error_ptr)497 *error_ptr = Status::FromErrorString("invalid file handle");498 return result;499}500 501off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {502 off_t result = -1;503 if (ValueGuard descriptor_guard = DescriptorIsValid()) {504 result = ::lseek(m_descriptor, offset, SEEK_END);505 506 if (error_ptr) {507 if (result == -1)508 *error_ptr = Status::FromErrno();509 else510 error_ptr->Clear();511 }512 return result;513 }514 515 if (ValueGuard stream_guard = StreamIsValid()) {516 result = ::fseek(m_stream, offset, SEEK_END);517 518 if (error_ptr) {519 if (result == -1)520 *error_ptr = Status::FromErrno();521 else522 error_ptr->Clear();523 }524 }525 526 if (error_ptr)527 *error_ptr = Status::FromErrorString("invalid file handle");528 return result;529}530 531Status NativeFile::Flush() {532 Status error;533 if (ValueGuard stream_guard = StreamIsValid()) {534 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)535 error = Status::FromErrno();536 return error;537 }538 539 {540 ValueGuard descriptor_guard = DescriptorIsValid();541 if (!descriptor_guard)542 error = Status::FromErrorString("invalid file handle");543 }544 return error;545}546 547Status NativeFile::Sync() {548 Status error;549 if (ValueGuard descriptor_guard = DescriptorIsValid()) {550#ifdef _WIN32551 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));552 if (err == 0)553 error = Status::FromErrorString("unknown error");554#else555 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)556 error = Status::FromErrno();557#endif558 } else {559 error = Status::FromErrorString("invalid file handle");560 }561 return error;562}563 564#if defined(__APPLE__)565// Darwin kernels only can read/write <= INT_MAX bytes566#define MAX_READ_SIZE INT_MAX567#define MAX_WRITE_SIZE INT_MAX568#endif569 570Status NativeFile::Read(void *buf, size_t &num_bytes) {571 Status error;572 573 // Ensure the file is open for reading.574 if ((m_options & File::OpenOptionsModeMask) == eOpenOptionWriteOnly)575 return Status(std::make_error_code(std::errc::bad_file_descriptor));576 577#if defined(MAX_READ_SIZE)578 if (num_bytes > MAX_READ_SIZE) {579 uint8_t *p = (uint8_t *)buf;580 size_t bytes_left = num_bytes;581 // Init the num_bytes read to zero582 num_bytes = 0;583 584 while (bytes_left > 0) {585 size_t curr_num_bytes;586 if (bytes_left > MAX_READ_SIZE)587 curr_num_bytes = MAX_READ_SIZE;588 else589 curr_num_bytes = bytes_left;590 591 error = Read(p + num_bytes, curr_num_bytes);592 593 // Update how many bytes were read594 num_bytes += curr_num_bytes;595 if (bytes_left < curr_num_bytes)596 bytes_left = 0;597 else598 bytes_left -= curr_num_bytes;599 600 if (error.Fail())601 break;602 }603 return error;604 }605#endif606 607 ssize_t bytes_read = -1;608 if (ValueGuard descriptor_guard = DescriptorIsValid()) {609 bytes_read =610 llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);611 if (bytes_read == -1) {612 error = Status::FromErrno();613 num_bytes = 0;614 } else615 num_bytes = bytes_read;616 return error;617 }618 619 if (ValueGuard file_lock = StreamIsValid()) {620 bytes_read = ::fread(buf, 1, num_bytes, m_stream);621 622 if (bytes_read == 0) {623 if (::feof(m_stream))624 error = Status::FromErrorString("feof");625 else if (::ferror(m_stream))626 error = Status::FromErrorString("ferror");627 num_bytes = 0;628 } else629 num_bytes = bytes_read;630 return error;631 }632 633 num_bytes = 0;634 error = Status::FromErrorString("invalid file handle");635 return error;636}637 638Status NativeFile::Write(const void *buf, size_t &num_bytes) {639 Status error;640 641 // Ensure the file is open for writing.642 if ((m_options & File::OpenOptionsModeMask) == File::eOpenOptionReadOnly)643 return Status(std::make_error_code(std::errc::bad_file_descriptor));644 645#if defined(MAX_WRITE_SIZE)646 if (num_bytes > MAX_WRITE_SIZE) {647 const uint8_t *p = (const uint8_t *)buf;648 size_t bytes_left = num_bytes;649 // Init the num_bytes written to zero650 num_bytes = 0;651 652 while (bytes_left > 0) {653 size_t curr_num_bytes;654 if (bytes_left > MAX_WRITE_SIZE)655 curr_num_bytes = MAX_WRITE_SIZE;656 else657 curr_num_bytes = bytes_left;658 659 error = Write(p + num_bytes, curr_num_bytes);660 661 // Update how many bytes were read662 num_bytes += curr_num_bytes;663 if (bytes_left < curr_num_bytes)664 bytes_left = 0;665 else666 bytes_left -= curr_num_bytes;667 668 if (error.Fail())669 break;670 }671 return error;672 }673#endif674 675 ssize_t bytes_written = -1;676 if (ValueGuard descriptor_guard = DescriptorIsValid()) {677 bytes_written =678 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);679 if (bytes_written == -1) {680 error = Status::FromErrno();681 num_bytes = 0;682 } else683 num_bytes = bytes_written;684 return error;685 }686 687 if (ValueGuard stream_guard = StreamIsValid()) {688#ifdef _WIN32689 if (is_windows_console) {690 llvm::raw_fd_ostream(_fileno(m_stream), false)691 .write((const char *)buf, num_bytes);692 return error;693 }694#endif695 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);696 697 if (bytes_written == 0) {698 if (::feof(m_stream))699 error = Status::FromErrorString("feof");700 else if (::ferror(m_stream))701 error = Status::FromErrorString("ferror");702 num_bytes = 0;703 } else704 num_bytes = bytes_written;705 return error;706 }707 708 num_bytes = 0;709 error = Status::FromErrorString("invalid file handle");710 return error;711}712 713Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {714 Status error;715 716#if defined(MAX_READ_SIZE)717 if (num_bytes > MAX_READ_SIZE) {718 uint8_t *p = (uint8_t *)buf;719 size_t bytes_left = num_bytes;720 // Init the num_bytes read to zero721 num_bytes = 0;722 723 while (bytes_left > 0) {724 size_t curr_num_bytes;725 if (bytes_left > MAX_READ_SIZE)726 curr_num_bytes = MAX_READ_SIZE;727 else728 curr_num_bytes = bytes_left;729 730 error = Read(p + num_bytes, curr_num_bytes, offset);731 732 // Update how many bytes were read733 num_bytes += curr_num_bytes;734 if (bytes_left < curr_num_bytes)735 bytes_left = 0;736 else737 bytes_left -= curr_num_bytes;738 739 if (error.Fail())740 break;741 }742 return error;743 }744#endif745 746#ifndef _WIN32747 int fd = GetDescriptor();748 if (fd != kInvalidDescriptor) {749 ssize_t bytes_read =750 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);751 if (bytes_read < 0) {752 num_bytes = 0;753 error = Status::FromErrno();754 } else {755 offset += bytes_read;756 num_bytes = bytes_read;757 }758 } else {759 num_bytes = 0;760 error = Status::FromErrorString("invalid file handle");761 }762#else763 std::lock_guard<std::mutex> guard(offset_access_mutex);764 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);765 SeekFromStart(offset);766 error = Read(buf, num_bytes);767 if (!error.Fail())768 SeekFromStart(cur);769#endif770 return error;771}772 773Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {774 Status error;775 776#if defined(MAX_WRITE_SIZE)777 if (num_bytes > MAX_WRITE_SIZE) {778 const uint8_t *p = (const uint8_t *)buf;779 size_t bytes_left = num_bytes;780 // Init the num_bytes written to zero781 num_bytes = 0;782 783 while (bytes_left > 0) {784 size_t curr_num_bytes;785 if (bytes_left > MAX_WRITE_SIZE)786 curr_num_bytes = MAX_WRITE_SIZE;787 else788 curr_num_bytes = bytes_left;789 790 error = Write(p + num_bytes, curr_num_bytes, offset);791 792 // Update how many bytes were read793 num_bytes += curr_num_bytes;794 if (bytes_left < curr_num_bytes)795 bytes_left = 0;796 else797 bytes_left -= curr_num_bytes;798 799 if (error.Fail())800 break;801 }802 return error;803 }804#endif805 806 int fd = GetDescriptor();807 if (fd != kInvalidDescriptor) {808#ifndef _WIN32809 ssize_t bytes_written = llvm::sys::RetryAfterSignal(810 -1, ::pwrite, m_descriptor, buf, num_bytes, offset);811 if (bytes_written < 0) {812 num_bytes = 0;813 error = Status::FromErrno();814 } else {815 offset += bytes_written;816 num_bytes = bytes_written;817 }818#else819 std::lock_guard<std::mutex> guard(offset_access_mutex);820 long cur = ::lseek(m_descriptor, 0, SEEK_CUR);821 SeekFromStart(offset);822 error = Write(buf, num_bytes);823 long after = ::lseek(m_descriptor, 0, SEEK_CUR);824 825 if (!error.Fail())826 SeekFromStart(cur);827 828 offset = after;829#endif830 } else {831 num_bytes = 0;832 error = Status::FromErrorString("invalid file handle");833 }834 return error;835}836 837size_t NativeFile::PrintfVarArg(const char *format, va_list args) {838 if (StreamIsValid()) {839 return ::vfprintf(m_stream, format, args);840 } else {841 return File::PrintfVarArg(format, args);842 }843}844 845mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {846 mode_t mode = 0;847 File::OpenOptions rw =848 open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |849 File::eOpenOptionReadWrite);850 if (rw == eOpenOptionReadWrite)851 mode |= O_RDWR;852 else if (rw == eOpenOptionWriteOnly)853 mode |= O_WRONLY;854 else if (rw == eOpenOptionReadOnly)855 mode |= O_RDONLY;856 857 if (open_options & eOpenOptionAppend)858 mode |= O_APPEND;859 860 if (open_options & eOpenOptionTruncate)861 mode |= O_TRUNC;862 863 if (open_options & eOpenOptionNonBlocking)864 mode |= O_NONBLOCK;865 866 if (open_options & eOpenOptionCanCreateNewOnly)867 mode |= O_CREAT | O_EXCL;868 else if (open_options & eOpenOptionCanCreate)869 mode |= O_CREAT;870 871 return mode;872}873 874llvm::Expected<SerialPort::Options>875SerialPort::OptionsFromURL(llvm::StringRef urlqs) {876 SerialPort::Options serial_options;877 for (llvm::StringRef x : llvm::split(urlqs, '&')) {878 if (x.consume_front("baud=")) {879 unsigned int baud_rate;880 if (!llvm::to_integer(x, baud_rate, 10))881 return llvm::createStringError(llvm::inconvertibleErrorCode(),882 "Invalid baud rate: %s",883 x.str().c_str());884 serial_options.BaudRate = baud_rate;885 } else if (x.consume_front("parity=")) {886 serial_options.Parity =887 llvm::StringSwitch<std::optional<Terminal::Parity>>(x)888 .Case("no", Terminal::Parity::No)889 .Case("even", Terminal::Parity::Even)890 .Case("odd", Terminal::Parity::Odd)891 .Case("mark", Terminal::Parity::Mark)892 .Case("space", Terminal::Parity::Space)893 .Default(std::nullopt);894 if (!serial_options.Parity)895 return llvm::createStringError(896 llvm::inconvertibleErrorCode(),897 "Invalid parity (must be no, even, odd, mark or space): %s",898 x.str().c_str());899 } else if (x.consume_front("parity-check=")) {900 serial_options.ParityCheck =901 llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)902 .Case("no", Terminal::ParityCheck::No)903 .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)904 .Case("ignore", Terminal::ParityCheck::Ignore)905 // "mark" mode is not currently supported as it requires special906 // input processing907 // .Case("mark", Terminal::ParityCheck::Mark)908 .Default(std::nullopt);909 if (!serial_options.ParityCheck)910 return llvm::createStringError(911 llvm::inconvertibleErrorCode(),912 "Invalid parity-check (must be no, replace, ignore or mark): %s",913 x.str().c_str());914 } else if (x.consume_front("stop-bits=")) {915 unsigned int stop_bits;916 if (!llvm::to_integer(x, stop_bits, 10) ||917 (stop_bits != 1 && stop_bits != 2))918 return llvm::createStringError(919 llvm::inconvertibleErrorCode(),920 "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());921 serial_options.StopBits = stop_bits;922 } else923 return llvm::createStringError(llvm::inconvertibleErrorCode(),924 "Unknown parameter: %s", x.str().c_str());925 }926 return serial_options;927}928 929llvm::Expected<std::unique_ptr<SerialPort>>930SerialPort::Create(int fd, OpenOptions options, Options serial_options,931 bool transfer_ownership) {932 std::unique_ptr<SerialPort> out{933 new SerialPort(fd, options, serial_options, transfer_ownership)};934 935 if (!out->GetIsInteractive())936 return llvm::createStringError(llvm::inconvertibleErrorCode(),937 "the specified file is not a teletype");938 939 Terminal term{fd};940 if (llvm::Error error = term.SetRaw())941 return std::move(error);942 if (serial_options.BaudRate) {943 if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))944 return std::move(error);945 }946 if (serial_options.Parity) {947 if (llvm::Error error = term.SetParity(*serial_options.Parity))948 return std::move(error);949 }950 if (serial_options.ParityCheck) {951 if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))952 return std::move(error);953 }954 if (serial_options.StopBits) {955 if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))956 return std::move(error);957 }958 959 return std::move(out);960}961 962SerialPort::SerialPort(int fd, OpenOptions options,963 SerialPort::Options serial_options,964 bool transfer_ownership)965 : NativeFile(fd, options, transfer_ownership), m_state(fd) {}966 967Status SerialPort::Close() {968 m_state.Restore();969 return NativeFile::Close();970}971 972char File::ID = 0;973char NativeFile::ID = 0;974char SerialPort::ID = 0;975