Path: blob/main/contrib/llvm-project/lldb/source/Host/common/File.cpp
39606 views
//===-- File.cpp ----------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Host/File.h"910#include <cerrno>11#include <climits>12#include <cstdarg>13#include <cstdio>14#include <fcntl.h>15#include <optional>1617#ifdef _WIN3218#include "lldb/Host/windows/windows.h"19#else20#include <sys/ioctl.h>21#include <sys/stat.h>22#include <termios.h>23#include <unistd.h>24#endif2526#include "lldb/Host/Config.h"27#include "lldb/Host/FileSystem.h"28#include "lldb/Host/Host.h"29#include "lldb/Utility/DataBufferHeap.h"30#include "lldb/Utility/FileSpec.h"31#include "lldb/Utility/Log.h"32#include "lldb/Utility/VASPrintf.h"33#include "llvm/ADT/StringExtras.h"34#include "llvm/Support/ConvertUTF.h"35#include "llvm/Support/Errno.h"36#include "llvm/Support/FileSystem.h"37#include "llvm/Support/Process.h"3839using namespace lldb;40using namespace lldb_private;41using llvm::Expected;4243Expected<const char *>44File::GetStreamOpenModeFromOptions(File::OpenOptions options) {45File::OpenOptions rw =46options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |47File::eOpenOptionReadWrite);4849if (options & File::eOpenOptionAppend) {50if (rw == File::eOpenOptionReadWrite) {51if (options & File::eOpenOptionCanCreateNewOnly)52return "a+x";53else54return "a+";55} else if (rw == File::eOpenOptionWriteOnly) {56if (options & File::eOpenOptionCanCreateNewOnly)57return "ax";58else59return "a";60}61} else if (rw == File::eOpenOptionReadWrite) {62if (options & File::eOpenOptionCanCreate) {63if (options & File::eOpenOptionCanCreateNewOnly)64return "w+x";65else66return "w+";67} else68return "r+";69} else if (rw == File::eOpenOptionWriteOnly) {70return "w";71} else if (rw == File::eOpenOptionReadOnly) {72return "r";73}74return llvm::createStringError(75llvm::inconvertibleErrorCode(),76"invalid options, cannot convert to mode string");77}7879Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {80OpenOptions opts =81llvm::StringSwitch<OpenOptions>(mode)82.Cases("r", "rb", eOpenOptionReadOnly)83.Cases("w", "wb", eOpenOptionWriteOnly)84.Cases("a", "ab",85eOpenOptionWriteOnly | eOpenOptionAppend |86eOpenOptionCanCreate)87.Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)88.Cases("w+", "wb+", "w+b",89eOpenOptionReadWrite | eOpenOptionCanCreate |90eOpenOptionTruncate)91.Cases("a+", "ab+", "a+b",92eOpenOptionReadWrite | eOpenOptionAppend |93eOpenOptionCanCreate)94.Default(eOpenOptionInvalid);95if (opts != eOpenOptionInvalid)96return opts;97return llvm::createStringError(98llvm::inconvertibleErrorCode(),99"invalid mode, cannot convert to File::OpenOptions");100}101102int File::kInvalidDescriptor = -1;103FILE *File::kInvalidStream = nullptr;104105Status File::Read(void *buf, size_t &num_bytes) {106return std::error_code(ENOTSUP, std::system_category());107}108Status File::Write(const void *buf, size_t &num_bytes) {109return std::error_code(ENOTSUP, std::system_category());110}111112bool File::IsValid() const { return false; }113114Status File::Close() { return Flush(); }115116IOObject::WaitableHandle File::GetWaitableHandle() {117return IOObject::kInvalidHandleValue;118}119120Status File::GetFileSpec(FileSpec &file_spec) const {121file_spec.Clear();122return std::error_code(ENOTSUP, std::system_category());123}124125int File::GetDescriptor() const { return kInvalidDescriptor; }126127FILE *File::GetStream() { return nullptr; }128129off_t File::SeekFromStart(off_t offset, Status *error_ptr) {130if (error_ptr)131*error_ptr = std::error_code(ENOTSUP, std::system_category());132return -1;133}134135off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {136if (error_ptr)137*error_ptr = std::error_code(ENOTSUP, std::system_category());138return -1;139}140141off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {142if (error_ptr)143*error_ptr = std::error_code(ENOTSUP, std::system_category());144return -1;145}146147Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {148return std::error_code(ENOTSUP, std::system_category());149}150151Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {152return std::error_code(ENOTSUP, std::system_category());153}154155Status File::Flush() { return Status(); }156157Status File::Sync() { return Flush(); }158159void File::CalculateInteractiveAndTerminal() {160const int fd = GetDescriptor();161if (!DescriptorIsValid(fd)) {162m_is_interactive = eLazyBoolNo;163m_is_real_terminal = eLazyBoolNo;164m_supports_colors = eLazyBoolNo;165return;166}167m_is_interactive = eLazyBoolNo;168m_is_real_terminal = eLazyBoolNo;169#if defined(_WIN32)170if (_isatty(fd)) {171m_is_interactive = eLazyBoolYes;172m_is_real_terminal = eLazyBoolYes;173#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)174m_supports_colors = eLazyBoolYes;175#endif176}177#else178if (isatty(fd)) {179m_is_interactive = eLazyBoolYes;180struct winsize window_size;181if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {182if (window_size.ws_col > 0) {183m_is_real_terminal = eLazyBoolYes;184if (llvm::sys::Process::FileDescriptorHasColors(fd))185m_supports_colors = eLazyBoolYes;186}187}188}189#endif190}191192bool File::GetIsInteractive() {193if (m_is_interactive == eLazyBoolCalculate)194CalculateInteractiveAndTerminal();195return m_is_interactive == eLazyBoolYes;196}197198bool File::GetIsRealTerminal() {199if (m_is_real_terminal == eLazyBoolCalculate)200CalculateInteractiveAndTerminal();201return m_is_real_terminal == eLazyBoolYes;202}203204bool File::GetIsTerminalWithColors() {205if (m_supports_colors == eLazyBoolCalculate)206CalculateInteractiveAndTerminal();207return m_supports_colors == eLazyBoolYes;208}209210size_t File::Printf(const char *format, ...) {211va_list args;212va_start(args, format);213size_t result = PrintfVarArg(format, args);214va_end(args);215return result;216}217218size_t File::PrintfVarArg(const char *format, va_list args) {219llvm::SmallString<0> s;220if (VASprintf(s, format, args)) {221size_t written = s.size();222Write(s.data(), written);223return written;224}225return 0;226}227228Expected<File::OpenOptions> File::GetOptions() const {229return llvm::createStringError(230llvm::inconvertibleErrorCode(),231"GetOptions() not implemented for this File class");232}233234uint32_t File::GetPermissions(Status &error) const {235int fd = GetDescriptor();236if (!DescriptorIsValid(fd)) {237error = std::error_code(ENOTSUP, std::system_category());238return 0;239}240struct stat file_stats;241if (::fstat(fd, &file_stats) == -1) {242error.SetErrorToErrno();243return 0;244}245error.Clear();246return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);247}248249bool NativeFile::IsValid() const {250std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);251return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();252}253254Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }255256int NativeFile::GetDescriptor() const {257if (ValueGuard descriptor_guard = DescriptorIsValid()) {258return m_descriptor;259}260261// Don't open the file descriptor if we don't need to, just get it from the262// stream if we have one.263if (ValueGuard stream_guard = StreamIsValid()) {264#if defined(_WIN32)265return _fileno(m_stream);266#else267return fileno(m_stream);268#endif269}270271// Invalid descriptor and invalid stream, return invalid descriptor.272return kInvalidDescriptor;273}274275IOObject::WaitableHandle NativeFile::GetWaitableHandle() {276return GetDescriptor();277}278279FILE *NativeFile::GetStream() {280ValueGuard stream_guard = StreamIsValid();281if (!stream_guard) {282if (ValueGuard descriptor_guard = DescriptorIsValid()) {283auto mode = GetStreamOpenModeFromOptions(m_options);284if (!mode)285llvm::consumeError(mode.takeError());286else {287if (!m_own_descriptor) {288// We must duplicate the file descriptor if we don't own it because when you289// call fdopen, the stream will own the fd290#ifdef _WIN32291m_descriptor = ::_dup(m_descriptor);292#else293m_descriptor = dup(m_descriptor);294#endif295m_own_descriptor = true;296}297298m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,299mode.get());300301// If we got a stream, then we own the stream and should no longer own302// the descriptor because fclose() will close it for us303304if (m_stream) {305m_own_stream = true;306m_own_descriptor = false;307}308}309}310}311return m_stream;312}313314Status NativeFile::Close() {315std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);316317Status error;318319if (StreamIsValidUnlocked()) {320if (m_own_stream) {321if (::fclose(m_stream) == EOF)322error.SetErrorToErrno();323} else {324File::OpenOptions rw =325m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |326File::eOpenOptionReadWrite);327328if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {329if (::fflush(m_stream) == EOF)330error.SetErrorToErrno();331}332}333}334335if (DescriptorIsValidUnlocked() && m_own_descriptor) {336if (::close(m_descriptor) != 0)337error.SetErrorToErrno();338}339340m_stream = kInvalidStream;341m_own_stream = false;342m_descriptor = kInvalidDescriptor;343m_own_descriptor = false;344m_options = OpenOptions(0);345m_is_interactive = eLazyBoolCalculate;346m_is_real_terminal = eLazyBoolCalculate;347return error;348}349350Status NativeFile::GetFileSpec(FileSpec &file_spec) const {351Status error;352#ifdef F_GETPATH353if (IsValid()) {354char path[PATH_MAX];355if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)356error.SetErrorToErrno();357else358file_spec.SetFile(path, FileSpec::Style::native);359} else {360error.SetErrorString("invalid file handle");361}362#elif defined(__linux__)363char proc[64];364char path[PATH_MAX];365if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)366error.SetErrorString("cannot resolve file descriptor");367else {368ssize_t len;369if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)370error.SetErrorToErrno();371else {372path[len] = '\0';373file_spec.SetFile(path, FileSpec::Style::native);374}375}376#else377error.SetErrorString(378"NativeFile::GetFileSpec is not supported on this platform");379#endif380381if (error.Fail())382file_spec.Clear();383return error;384}385386off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {387off_t result = 0;388if (ValueGuard descriptor_guard = DescriptorIsValid()) {389result = ::lseek(m_descriptor, offset, SEEK_SET);390391if (error_ptr) {392if (result == -1)393error_ptr->SetErrorToErrno();394else395error_ptr->Clear();396}397return result;398}399400if (ValueGuard stream_guard = StreamIsValid()) {401result = ::fseek(m_stream, offset, SEEK_SET);402403if (error_ptr) {404if (result == -1)405error_ptr->SetErrorToErrno();406else407error_ptr->Clear();408}409return result;410}411412if (error_ptr)413error_ptr->SetErrorString("invalid file handle");414return result;415}416417off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {418off_t result = -1;419if (ValueGuard descriptor_guard = DescriptorIsValid()) {420result = ::lseek(m_descriptor, offset, SEEK_CUR);421422if (error_ptr) {423if (result == -1)424error_ptr->SetErrorToErrno();425else426error_ptr->Clear();427}428return result;429}430431if (ValueGuard stream_guard = StreamIsValid()) {432result = ::fseek(m_stream, offset, SEEK_CUR);433434if (error_ptr) {435if (result == -1)436error_ptr->SetErrorToErrno();437else438error_ptr->Clear();439}440return result;441}442443if (error_ptr)444error_ptr->SetErrorString("invalid file handle");445return result;446}447448off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {449off_t result = -1;450if (ValueGuard descriptor_guard = DescriptorIsValid()) {451result = ::lseek(m_descriptor, offset, SEEK_END);452453if (error_ptr) {454if (result == -1)455error_ptr->SetErrorToErrno();456else457error_ptr->Clear();458}459return result;460}461462if (ValueGuard stream_guard = StreamIsValid()) {463result = ::fseek(m_stream, offset, SEEK_END);464465if (error_ptr) {466if (result == -1)467error_ptr->SetErrorToErrno();468else469error_ptr->Clear();470}471}472473if (error_ptr)474error_ptr->SetErrorString("invalid file handle");475return result;476}477478Status NativeFile::Flush() {479Status error;480if (ValueGuard stream_guard = StreamIsValid()) {481if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)482error.SetErrorToErrno();483return error;484}485486{487ValueGuard descriptor_guard = DescriptorIsValid();488if (!descriptor_guard)489error.SetErrorString("invalid file handle");490}491return error;492}493494Status NativeFile::Sync() {495Status error;496if (ValueGuard descriptor_guard = DescriptorIsValid()) {497#ifdef _WIN32498int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));499if (err == 0)500error.SetErrorToGenericError();501#else502if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)503error.SetErrorToErrno();504#endif505} else {506error.SetErrorString("invalid file handle");507}508return error;509}510511#if defined(__APPLE__)512// Darwin kernels only can read/write <= INT_MAX bytes513#define MAX_READ_SIZE INT_MAX514#define MAX_WRITE_SIZE INT_MAX515#endif516517Status NativeFile::Read(void *buf, size_t &num_bytes) {518Status error;519520#if defined(MAX_READ_SIZE)521if (num_bytes > MAX_READ_SIZE) {522uint8_t *p = (uint8_t *)buf;523size_t bytes_left = num_bytes;524// Init the num_bytes read to zero525num_bytes = 0;526527while (bytes_left > 0) {528size_t curr_num_bytes;529if (bytes_left > MAX_READ_SIZE)530curr_num_bytes = MAX_READ_SIZE;531else532curr_num_bytes = bytes_left;533534error = Read(p + num_bytes, curr_num_bytes);535536// Update how many bytes were read537num_bytes += curr_num_bytes;538if (bytes_left < curr_num_bytes)539bytes_left = 0;540else541bytes_left -= curr_num_bytes;542543if (error.Fail())544break;545}546return error;547}548#endif549550ssize_t bytes_read = -1;551if (ValueGuard descriptor_guard = DescriptorIsValid()) {552bytes_read =553llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);554if (bytes_read == -1) {555error.SetErrorToErrno();556num_bytes = 0;557} else558num_bytes = bytes_read;559return error;560}561562if (ValueGuard file_lock = StreamIsValid()) {563bytes_read = ::fread(buf, 1, num_bytes, m_stream);564565if (bytes_read == 0) {566if (::feof(m_stream))567error.SetErrorString("feof");568else if (::ferror(m_stream))569error.SetErrorString("ferror");570num_bytes = 0;571} else572num_bytes = bytes_read;573return error;574}575576num_bytes = 0;577error.SetErrorString("invalid file handle");578return error;579}580581Status NativeFile::Write(const void *buf, size_t &num_bytes) {582Status error;583584#if defined(MAX_WRITE_SIZE)585if (num_bytes > MAX_WRITE_SIZE) {586const uint8_t *p = (const uint8_t *)buf;587size_t bytes_left = num_bytes;588// Init the num_bytes written to zero589num_bytes = 0;590591while (bytes_left > 0) {592size_t curr_num_bytes;593if (bytes_left > MAX_WRITE_SIZE)594curr_num_bytes = MAX_WRITE_SIZE;595else596curr_num_bytes = bytes_left;597598error = Write(p + num_bytes, curr_num_bytes);599600// Update how many bytes were read601num_bytes += curr_num_bytes;602if (bytes_left < curr_num_bytes)603bytes_left = 0;604else605bytes_left -= curr_num_bytes;606607if (error.Fail())608break;609}610return error;611}612#endif613614ssize_t bytes_written = -1;615if (ValueGuard descriptor_guard = DescriptorIsValid()) {616bytes_written =617llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);618if (bytes_written == -1) {619error.SetErrorToErrno();620num_bytes = 0;621} else622num_bytes = bytes_written;623return error;624}625626if (ValueGuard stream_guard = StreamIsValid()) {627bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);628629if (bytes_written == 0) {630if (::feof(m_stream))631error.SetErrorString("feof");632else if (::ferror(m_stream))633error.SetErrorString("ferror");634num_bytes = 0;635} else636num_bytes = bytes_written;637return error;638}639640num_bytes = 0;641error.SetErrorString("invalid file handle");642return error;643}644645Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {646Status error;647648#if defined(MAX_READ_SIZE)649if (num_bytes > MAX_READ_SIZE) {650uint8_t *p = (uint8_t *)buf;651size_t bytes_left = num_bytes;652// Init the num_bytes read to zero653num_bytes = 0;654655while (bytes_left > 0) {656size_t curr_num_bytes;657if (bytes_left > MAX_READ_SIZE)658curr_num_bytes = MAX_READ_SIZE;659else660curr_num_bytes = bytes_left;661662error = Read(p + num_bytes, curr_num_bytes, offset);663664// Update how many bytes were read665num_bytes += curr_num_bytes;666if (bytes_left < curr_num_bytes)667bytes_left = 0;668else669bytes_left -= curr_num_bytes;670671if (error.Fail())672break;673}674return error;675}676#endif677678#ifndef _WIN32679int fd = GetDescriptor();680if (fd != kInvalidDescriptor) {681ssize_t bytes_read =682llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);683if (bytes_read < 0) {684num_bytes = 0;685error.SetErrorToErrno();686} else {687offset += bytes_read;688num_bytes = bytes_read;689}690} else {691num_bytes = 0;692error.SetErrorString("invalid file handle");693}694#else695std::lock_guard<std::mutex> guard(offset_access_mutex);696long cur = ::lseek(m_descriptor, 0, SEEK_CUR);697SeekFromStart(offset);698error = Read(buf, num_bytes);699if (!error.Fail())700SeekFromStart(cur);701#endif702return error;703}704705Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {706Status error;707708#if defined(MAX_WRITE_SIZE)709if (num_bytes > MAX_WRITE_SIZE) {710const uint8_t *p = (const uint8_t *)buf;711size_t bytes_left = num_bytes;712// Init the num_bytes written to zero713num_bytes = 0;714715while (bytes_left > 0) {716size_t curr_num_bytes;717if (bytes_left > MAX_WRITE_SIZE)718curr_num_bytes = MAX_WRITE_SIZE;719else720curr_num_bytes = bytes_left;721722error = Write(p + num_bytes, curr_num_bytes, offset);723724// Update how many bytes were read725num_bytes += curr_num_bytes;726if (bytes_left < curr_num_bytes)727bytes_left = 0;728else729bytes_left -= curr_num_bytes;730731if (error.Fail())732break;733}734return error;735}736#endif737738int fd = GetDescriptor();739if (fd != kInvalidDescriptor) {740#ifndef _WIN32741ssize_t bytes_written =742llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);743if (bytes_written < 0) {744num_bytes = 0;745error.SetErrorToErrno();746} else {747offset += bytes_written;748num_bytes = bytes_written;749}750#else751std::lock_guard<std::mutex> guard(offset_access_mutex);752long cur = ::lseek(m_descriptor, 0, SEEK_CUR);753SeekFromStart(offset);754error = Write(buf, num_bytes);755long after = ::lseek(m_descriptor, 0, SEEK_CUR);756757if (!error.Fail())758SeekFromStart(cur);759760offset = after;761#endif762} else {763num_bytes = 0;764error.SetErrorString("invalid file handle");765}766return error;767}768769size_t NativeFile::PrintfVarArg(const char *format, va_list args) {770if (StreamIsValid()) {771return ::vfprintf(m_stream, format, args);772} else {773return File::PrintfVarArg(format, args);774}775}776777mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {778mode_t mode = 0;779File::OpenOptions rw =780open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |781File::eOpenOptionReadWrite);782if (rw == eOpenOptionReadWrite)783mode |= O_RDWR;784else if (rw == eOpenOptionWriteOnly)785mode |= O_WRONLY;786else if (rw == eOpenOptionReadOnly)787mode |= O_RDONLY;788789if (open_options & eOpenOptionAppend)790mode |= O_APPEND;791792if (open_options & eOpenOptionTruncate)793mode |= O_TRUNC;794795if (open_options & eOpenOptionNonBlocking)796mode |= O_NONBLOCK;797798if (open_options & eOpenOptionCanCreateNewOnly)799mode |= O_CREAT | O_EXCL;800else if (open_options & eOpenOptionCanCreate)801mode |= O_CREAT;802803return mode;804}805806llvm::Expected<SerialPort::Options>807SerialPort::OptionsFromURL(llvm::StringRef urlqs) {808SerialPort::Options serial_options;809for (llvm::StringRef x : llvm::split(urlqs, '&')) {810if (x.consume_front("baud=")) {811unsigned int baud_rate;812if (!llvm::to_integer(x, baud_rate, 10))813return llvm::createStringError(llvm::inconvertibleErrorCode(),814"Invalid baud rate: %s",815x.str().c_str());816serial_options.BaudRate = baud_rate;817} else if (x.consume_front("parity=")) {818serial_options.Parity =819llvm::StringSwitch<std::optional<Terminal::Parity>>(x)820.Case("no", Terminal::Parity::No)821.Case("even", Terminal::Parity::Even)822.Case("odd", Terminal::Parity::Odd)823.Case("mark", Terminal::Parity::Mark)824.Case("space", Terminal::Parity::Space)825.Default(std::nullopt);826if (!serial_options.Parity)827return llvm::createStringError(828llvm::inconvertibleErrorCode(),829"Invalid parity (must be no, even, odd, mark or space): %s",830x.str().c_str());831} else if (x.consume_front("parity-check=")) {832serial_options.ParityCheck =833llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)834.Case("no", Terminal::ParityCheck::No)835.Case("replace", Terminal::ParityCheck::ReplaceWithNUL)836.Case("ignore", Terminal::ParityCheck::Ignore)837// "mark" mode is not currently supported as it requires special838// input processing839// .Case("mark", Terminal::ParityCheck::Mark)840.Default(std::nullopt);841if (!serial_options.ParityCheck)842return llvm::createStringError(843llvm::inconvertibleErrorCode(),844"Invalid parity-check (must be no, replace, ignore or mark): %s",845x.str().c_str());846} else if (x.consume_front("stop-bits=")) {847unsigned int stop_bits;848if (!llvm::to_integer(x, stop_bits, 10) ||849(stop_bits != 1 && stop_bits != 2))850return llvm::createStringError(851llvm::inconvertibleErrorCode(),852"Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());853serial_options.StopBits = stop_bits;854} else855return llvm::createStringError(llvm::inconvertibleErrorCode(),856"Unknown parameter: %s", x.str().c_str());857}858return serial_options;859}860861llvm::Expected<std::unique_ptr<SerialPort>>862SerialPort::Create(int fd, OpenOptions options, Options serial_options,863bool transfer_ownership) {864std::unique_ptr<SerialPort> out{865new SerialPort(fd, options, serial_options, transfer_ownership)};866867if (!out->GetIsInteractive())868return llvm::createStringError(llvm::inconvertibleErrorCode(),869"the specified file is not a teletype");870871Terminal term{fd};872if (llvm::Error error = term.SetRaw())873return std::move(error);874if (serial_options.BaudRate) {875if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))876return std::move(error);877}878if (serial_options.Parity) {879if (llvm::Error error = term.SetParity(*serial_options.Parity))880return std::move(error);881}882if (serial_options.ParityCheck) {883if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))884return std::move(error);885}886if (serial_options.StopBits) {887if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))888return std::move(error);889}890891return std::move(out);892}893894SerialPort::SerialPort(int fd, OpenOptions options,895SerialPort::Options serial_options,896bool transfer_ownership)897: NativeFile(fd, options, transfer_ownership), m_state(fd) {}898899Status SerialPort::Close() {900m_state.Restore();901return NativeFile::Close();902}903904char File::ID = 0;905char NativeFile::ID = 0;906char SerialPort::ID = 0;907908909