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-exception 6 // 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 _WIN32 19 #include "lldb/Host/windows/windows.h" 20 #else 21 #include <sys/ioctl.h> 22 #include <sys/stat.h> 23 #include <termios.h> 24 #include <unistd.h> 25 #endif 26 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/Support/ConvertUTF.h" 35 #include "llvm/Support/Errno.h" 36 #include "llvm/Support/FileSystem.h" 37 #include "llvm/Support/Process.h" 38 39 using namespace lldb; 40 using namespace lldb_private; 41 using llvm::Expected; 42 43 Expected<const char *> 44 File::GetStreamOpenModeFromOptions(File::OpenOptions options) { 45 File::OpenOptions rw = 46 options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 47 File::eOpenOptionReadWrite); 48 49 if (options & File::eOpenOptionAppend) { 50 if (rw == File::eOpenOptionReadWrite) { 51 if (options & File::eOpenOptionCanCreateNewOnly) 52 return "a+x"; 53 else 54 return "a+"; 55 } else if (rw == File::eOpenOptionWriteOnly) { 56 if (options & File::eOpenOptionCanCreateNewOnly) 57 return "ax"; 58 else 59 return "a"; 60 } 61 } else if (rw == File::eOpenOptionReadWrite) { 62 if (options & File::eOpenOptionCanCreate) { 63 if (options & File::eOpenOptionCanCreateNewOnly) 64 return "w+x"; 65 else 66 return "w+"; 67 } else 68 return "r+"; 69 } else if (rw == File::eOpenOptionWriteOnly) { 70 return "w"; 71 } else if (rw == File::eOpenOptionReadOnly) { 72 return "r"; 73 } 74 return llvm::createStringError( 75 llvm::inconvertibleErrorCode(), 76 "invalid options, cannot convert to mode string"); 77 } 78 79 Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { 80 OpenOptions opts = 81 llvm::StringSwitch<OpenOptions>(mode) 82 .Cases("r", "rb", eOpenOptionReadOnly) 83 .Cases("w", "wb", eOpenOptionWriteOnly) 84 .Cases("a", "ab", 85 eOpenOptionWriteOnly | eOpenOptionAppend | 86 eOpenOptionCanCreate) 87 .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite) 88 .Cases("w+", "wb+", "w+b", 89 eOpenOptionReadWrite | eOpenOptionCanCreate | 90 eOpenOptionTruncate) 91 .Cases("a+", "ab+", "a+b", 92 eOpenOptionReadWrite | eOpenOptionAppend | 93 eOpenOptionCanCreate) 94 .Default(eOpenOptionInvalid); 95 if (opts != eOpenOptionInvalid) 96 return opts; 97 return llvm::createStringError( 98 llvm::inconvertibleErrorCode(), 99 "invalid mode, cannot convert to File::OpenOptions"); 100 } 101 102 int File::kInvalidDescriptor = -1; 103 FILE *File::kInvalidStream = nullptr; 104 105 Status File::Read(void *buf, size_t &num_bytes) { 106 return std::error_code(ENOTSUP, std::system_category()); 107 } 108 Status File::Write(const void *buf, size_t &num_bytes) { 109 return std::error_code(ENOTSUP, std::system_category()); 110 } 111 112 bool File::IsValid() const { return false; } 113 114 Status File::Close() { return Flush(); } 115 116 IOObject::WaitableHandle File::GetWaitableHandle() { 117 return IOObject::kInvalidHandleValue; 118 } 119 120 Status File::GetFileSpec(FileSpec &file_spec) const { 121 file_spec.Clear(); 122 return std::error_code(ENOTSUP, std::system_category()); 123 } 124 125 int File::GetDescriptor() const { return kInvalidDescriptor; } 126 127 FILE *File::GetStream() { return nullptr; } 128 129 off_t File::SeekFromStart(off_t offset, Status *error_ptr) { 130 if (error_ptr) 131 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 132 return -1; 133 } 134 135 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) { 136 if (error_ptr) 137 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 138 return -1; 139 } 140 141 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) { 142 if (error_ptr) 143 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 144 return -1; 145 } 146 147 Status File::Read(void *dst, size_t &num_bytes, off_t &offset) { 148 return std::error_code(ENOTSUP, std::system_category()); 149 } 150 151 Status File::Write(const void *src, size_t &num_bytes, off_t &offset) { 152 return std::error_code(ENOTSUP, std::system_category()); 153 } 154 155 Status File::Flush() { return Status(); } 156 157 Status File::Sync() { return Flush(); } 158 159 void File::CalculateInteractiveAndTerminal() { 160 const int fd = GetDescriptor(); 161 if (!DescriptorIsValid(fd)) { 162 m_is_interactive = eLazyBoolNo; 163 m_is_real_terminal = eLazyBoolNo; 164 m_supports_colors = eLazyBoolNo; 165 return; 166 } 167 m_is_interactive = eLazyBoolNo; 168 m_is_real_terminal = eLazyBoolNo; 169 #if defined(_WIN32) 170 if (_isatty(fd)) { 171 m_is_interactive = eLazyBoolYes; 172 m_is_real_terminal = eLazyBoolYes; 173 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 174 m_supports_colors = eLazyBoolYes; 175 #endif 176 } 177 #else 178 if (isatty(fd)) { 179 m_is_interactive = eLazyBoolYes; 180 struct winsize window_size; 181 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { 182 if (window_size.ws_col > 0) { 183 m_is_real_terminal = eLazyBoolYes; 184 if (llvm::sys::Process::FileDescriptorHasColors(fd)) 185 m_supports_colors = eLazyBoolYes; 186 } 187 } 188 } 189 #endif 190 } 191 192 bool File::GetIsInteractive() { 193 if (m_is_interactive == eLazyBoolCalculate) 194 CalculateInteractiveAndTerminal(); 195 return m_is_interactive == eLazyBoolYes; 196 } 197 198 bool File::GetIsRealTerminal() { 199 if (m_is_real_terminal == eLazyBoolCalculate) 200 CalculateInteractiveAndTerminal(); 201 return m_is_real_terminal == eLazyBoolYes; 202 } 203 204 bool File::GetIsTerminalWithColors() { 205 if (m_supports_colors == eLazyBoolCalculate) 206 CalculateInteractiveAndTerminal(); 207 return m_supports_colors == eLazyBoolYes; 208 } 209 210 size_t File::Printf(const char *format, ...) { 211 va_list args; 212 va_start(args, format); 213 size_t result = PrintfVarArg(format, args); 214 va_end(args); 215 return result; 216 } 217 218 size_t File::PrintfVarArg(const char *format, va_list args) { 219 llvm::SmallString<0> s; 220 if (VASprintf(s, format, args)) { 221 size_t written = s.size();; 222 Write(s.data(), written); 223 return written; 224 } 225 return 0; 226 } 227 228 Expected<File::OpenOptions> File::GetOptions() const { 229 return llvm::createStringError( 230 llvm::inconvertibleErrorCode(), 231 "GetOptions() not implemented for this File class"); 232 } 233 234 uint32_t File::GetPermissions(Status &error) const { 235 int fd = GetDescriptor(); 236 if (!DescriptorIsValid(fd)) { 237 error = std::error_code(ENOTSUP, std::system_category()); 238 return 0; 239 } 240 struct stat file_stats; 241 if (::fstat(fd, &file_stats) == -1) { 242 error.SetErrorToErrno(); 243 return 0; 244 } 245 error.Clear(); 246 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 247 } 248 249 Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; } 250 251 int NativeFile::GetDescriptor() const { 252 if (DescriptorIsValid()) 253 return m_descriptor; 254 255 // Don't open the file descriptor if we don't need to, just get it from the 256 // stream if we have one. 257 if (StreamIsValid()) { 258 #if defined(_WIN32) 259 return _fileno(m_stream); 260 #else 261 return fileno(m_stream); 262 #endif 263 } 264 265 // Invalid descriptor and invalid stream, return invalid descriptor. 266 return kInvalidDescriptor; 267 } 268 269 IOObject::WaitableHandle NativeFile::GetWaitableHandle() { 270 return GetDescriptor(); 271 } 272 273 FILE *NativeFile::GetStream() { 274 if (!StreamIsValid()) { 275 if (DescriptorIsValid()) { 276 auto mode = GetStreamOpenModeFromOptions(m_options); 277 if (!mode) 278 llvm::consumeError(mode.takeError()); 279 else { 280 if (!m_own_descriptor) { 281 // We must duplicate the file descriptor if we don't own it because when you 282 // call fdopen, the stream will own the fd 283 #ifdef _WIN32 284 m_descriptor = ::_dup(GetDescriptor()); 285 #else 286 m_descriptor = dup(GetDescriptor()); 287 #endif 288 m_own_descriptor = true; 289 } 290 291 m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, 292 mode.get()); 293 294 // If we got a stream, then we own the stream and should no longer own 295 // the descriptor because fclose() will close it for us 296 297 if (m_stream) { 298 m_own_stream = true; 299 m_own_descriptor = false; 300 } 301 } 302 } 303 } 304 return m_stream; 305 } 306 307 Status NativeFile::Close() { 308 Status error; 309 if (StreamIsValid()) { 310 if (m_own_stream) { 311 if (::fclose(m_stream) == EOF) 312 error.SetErrorToErrno(); 313 } else { 314 File::OpenOptions rw = 315 m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 316 File::eOpenOptionReadWrite); 317 318 if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) { 319 if (::fflush(m_stream) == EOF) 320 error.SetErrorToErrno(); 321 } 322 } 323 } 324 if (DescriptorIsValid() && m_own_descriptor) { 325 if (::close(m_descriptor) != 0) 326 error.SetErrorToErrno(); 327 } 328 m_descriptor = kInvalidDescriptor; 329 m_stream = kInvalidStream; 330 m_options = OpenOptions(0); 331 m_own_stream = false; 332 m_own_descriptor = false; 333 m_is_interactive = eLazyBoolCalculate; 334 m_is_real_terminal = eLazyBoolCalculate; 335 return error; 336 } 337 338 Status NativeFile::GetFileSpec(FileSpec &file_spec) const { 339 Status error; 340 #ifdef F_GETPATH 341 if (IsValid()) { 342 char path[PATH_MAX]; 343 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 344 error.SetErrorToErrno(); 345 else 346 file_spec.SetFile(path, FileSpec::Style::native); 347 } else { 348 error.SetErrorString("invalid file handle"); 349 } 350 #elif defined(__linux__) 351 char proc[64]; 352 char path[PATH_MAX]; 353 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 354 error.SetErrorString("cannot resolve file descriptor"); 355 else { 356 ssize_t len; 357 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 358 error.SetErrorToErrno(); 359 else { 360 path[len] = '\0'; 361 file_spec.SetFile(path, FileSpec::Style::native); 362 } 363 } 364 #else 365 error.SetErrorString( 366 "NativeFile::GetFileSpec is not supported on this platform"); 367 #endif 368 369 if (error.Fail()) 370 file_spec.Clear(); 371 return error; 372 } 373 374 off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) { 375 off_t result = 0; 376 if (DescriptorIsValid()) { 377 result = ::lseek(m_descriptor, offset, SEEK_SET); 378 379 if (error_ptr) { 380 if (result == -1) 381 error_ptr->SetErrorToErrno(); 382 else 383 error_ptr->Clear(); 384 } 385 } else if (StreamIsValid()) { 386 result = ::fseek(m_stream, offset, SEEK_SET); 387 388 if (error_ptr) { 389 if (result == -1) 390 error_ptr->SetErrorToErrno(); 391 else 392 error_ptr->Clear(); 393 } 394 } else if (error_ptr) { 395 error_ptr->SetErrorString("invalid file handle"); 396 } 397 return result; 398 } 399 400 off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) { 401 off_t result = -1; 402 if (DescriptorIsValid()) { 403 result = ::lseek(m_descriptor, offset, SEEK_CUR); 404 405 if (error_ptr) { 406 if (result == -1) 407 error_ptr->SetErrorToErrno(); 408 else 409 error_ptr->Clear(); 410 } 411 } else if (StreamIsValid()) { 412 result = ::fseek(m_stream, offset, SEEK_CUR); 413 414 if (error_ptr) { 415 if (result == -1) 416 error_ptr->SetErrorToErrno(); 417 else 418 error_ptr->Clear(); 419 } 420 } else if (error_ptr) { 421 error_ptr->SetErrorString("invalid file handle"); 422 } 423 return result; 424 } 425 426 off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) { 427 off_t result = -1; 428 if (DescriptorIsValid()) { 429 result = ::lseek(m_descriptor, offset, SEEK_END); 430 431 if (error_ptr) { 432 if (result == -1) 433 error_ptr->SetErrorToErrno(); 434 else 435 error_ptr->Clear(); 436 } 437 } else if (StreamIsValid()) { 438 result = ::fseek(m_stream, offset, SEEK_END); 439 440 if (error_ptr) { 441 if (result == -1) 442 error_ptr->SetErrorToErrno(); 443 else 444 error_ptr->Clear(); 445 } 446 } else if (error_ptr) { 447 error_ptr->SetErrorString("invalid file handle"); 448 } 449 return result; 450 } 451 452 Status NativeFile::Flush() { 453 Status error; 454 if (StreamIsValid()) { 455 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) 456 error.SetErrorToErrno(); 457 } else if (!DescriptorIsValid()) { 458 error.SetErrorString("invalid file handle"); 459 } 460 return error; 461 } 462 463 Status NativeFile::Sync() { 464 Status error; 465 if (DescriptorIsValid()) { 466 #ifdef _WIN32 467 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 468 if (err == 0) 469 error.SetErrorToGenericError(); 470 #else 471 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) 472 error.SetErrorToErrno(); 473 #endif 474 } else { 475 error.SetErrorString("invalid file handle"); 476 } 477 return error; 478 } 479 480 #if defined(__APPLE__) 481 // Darwin kernels only can read/write <= INT_MAX bytes 482 #define MAX_READ_SIZE INT_MAX 483 #define MAX_WRITE_SIZE INT_MAX 484 #endif 485 486 Status NativeFile::Read(void *buf, size_t &num_bytes) { 487 Status error; 488 489 #if defined(MAX_READ_SIZE) 490 if (num_bytes > MAX_READ_SIZE) { 491 uint8_t *p = (uint8_t *)buf; 492 size_t bytes_left = num_bytes; 493 // Init the num_bytes read to zero 494 num_bytes = 0; 495 496 while (bytes_left > 0) { 497 size_t curr_num_bytes; 498 if (bytes_left > MAX_READ_SIZE) 499 curr_num_bytes = MAX_READ_SIZE; 500 else 501 curr_num_bytes = bytes_left; 502 503 error = Read(p + num_bytes, curr_num_bytes); 504 505 // Update how many bytes were read 506 num_bytes += curr_num_bytes; 507 if (bytes_left < curr_num_bytes) 508 bytes_left = 0; 509 else 510 bytes_left -= curr_num_bytes; 511 512 if (error.Fail()) 513 break; 514 } 515 return error; 516 } 517 #endif 518 519 ssize_t bytes_read = -1; 520 if (DescriptorIsValid()) { 521 bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); 522 if (bytes_read == -1) { 523 error.SetErrorToErrno(); 524 num_bytes = 0; 525 } else 526 num_bytes = bytes_read; 527 } else if (StreamIsValid()) { 528 bytes_read = ::fread(buf, 1, num_bytes, m_stream); 529 530 if (bytes_read == 0) { 531 if (::feof(m_stream)) 532 error.SetErrorString("feof"); 533 else if (::ferror(m_stream)) 534 error.SetErrorString("ferror"); 535 num_bytes = 0; 536 } else 537 num_bytes = bytes_read; 538 } else { 539 num_bytes = 0; 540 error.SetErrorString("invalid file handle"); 541 } 542 return error; 543 } 544 545 Status NativeFile::Write(const void *buf, size_t &num_bytes) { 546 Status error; 547 548 #if defined(MAX_WRITE_SIZE) 549 if (num_bytes > MAX_WRITE_SIZE) { 550 const uint8_t *p = (const uint8_t *)buf; 551 size_t bytes_left = num_bytes; 552 // Init the num_bytes written to zero 553 num_bytes = 0; 554 555 while (bytes_left > 0) { 556 size_t curr_num_bytes; 557 if (bytes_left > MAX_WRITE_SIZE) 558 curr_num_bytes = MAX_WRITE_SIZE; 559 else 560 curr_num_bytes = bytes_left; 561 562 error = Write(p + num_bytes, curr_num_bytes); 563 564 // Update how many bytes were read 565 num_bytes += curr_num_bytes; 566 if (bytes_left < curr_num_bytes) 567 bytes_left = 0; 568 else 569 bytes_left -= curr_num_bytes; 570 571 if (error.Fail()) 572 break; 573 } 574 return error; 575 } 576 #endif 577 578 ssize_t bytes_written = -1; 579 if (DescriptorIsValid()) { 580 bytes_written = 581 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); 582 if (bytes_written == -1) { 583 error.SetErrorToErrno(); 584 num_bytes = 0; 585 } else 586 num_bytes = bytes_written; 587 } else if (StreamIsValid()) { 588 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); 589 590 if (bytes_written == 0) { 591 if (::feof(m_stream)) 592 error.SetErrorString("feof"); 593 else if (::ferror(m_stream)) 594 error.SetErrorString("ferror"); 595 num_bytes = 0; 596 } else 597 num_bytes = bytes_written; 598 599 } else { 600 num_bytes = 0; 601 error.SetErrorString("invalid file handle"); 602 } 603 604 return error; 605 } 606 607 Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) { 608 Status error; 609 610 #if defined(MAX_READ_SIZE) 611 if (num_bytes > MAX_READ_SIZE) { 612 uint8_t *p = (uint8_t *)buf; 613 size_t bytes_left = num_bytes; 614 // Init the num_bytes read to zero 615 num_bytes = 0; 616 617 while (bytes_left > 0) { 618 size_t curr_num_bytes; 619 if (bytes_left > MAX_READ_SIZE) 620 curr_num_bytes = MAX_READ_SIZE; 621 else 622 curr_num_bytes = bytes_left; 623 624 error = Read(p + num_bytes, curr_num_bytes, offset); 625 626 // Update how many bytes were read 627 num_bytes += curr_num_bytes; 628 if (bytes_left < curr_num_bytes) 629 bytes_left = 0; 630 else 631 bytes_left -= curr_num_bytes; 632 633 if (error.Fail()) 634 break; 635 } 636 return error; 637 } 638 #endif 639 640 #ifndef _WIN32 641 int fd = GetDescriptor(); 642 if (fd != kInvalidDescriptor) { 643 ssize_t bytes_read = 644 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); 645 if (bytes_read < 0) { 646 num_bytes = 0; 647 error.SetErrorToErrno(); 648 } else { 649 offset += bytes_read; 650 num_bytes = bytes_read; 651 } 652 } else { 653 num_bytes = 0; 654 error.SetErrorString("invalid file handle"); 655 } 656 #else 657 std::lock_guard<std::mutex> guard(offset_access_mutex); 658 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 659 SeekFromStart(offset); 660 error = Read(buf, num_bytes); 661 if (!error.Fail()) 662 SeekFromStart(cur); 663 #endif 664 return error; 665 } 666 667 Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) { 668 Status error; 669 670 #if defined(MAX_WRITE_SIZE) 671 if (num_bytes > MAX_WRITE_SIZE) { 672 const uint8_t *p = (const uint8_t *)buf; 673 size_t bytes_left = num_bytes; 674 // Init the num_bytes written to zero 675 num_bytes = 0; 676 677 while (bytes_left > 0) { 678 size_t curr_num_bytes; 679 if (bytes_left > MAX_WRITE_SIZE) 680 curr_num_bytes = MAX_WRITE_SIZE; 681 else 682 curr_num_bytes = bytes_left; 683 684 error = Write(p + num_bytes, curr_num_bytes, offset); 685 686 // Update how many bytes were read 687 num_bytes += curr_num_bytes; 688 if (bytes_left < curr_num_bytes) 689 bytes_left = 0; 690 else 691 bytes_left -= curr_num_bytes; 692 693 if (error.Fail()) 694 break; 695 } 696 return error; 697 } 698 #endif 699 700 int fd = GetDescriptor(); 701 if (fd != kInvalidDescriptor) { 702 #ifndef _WIN32 703 ssize_t bytes_written = 704 llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); 705 if (bytes_written < 0) { 706 num_bytes = 0; 707 error.SetErrorToErrno(); 708 } else { 709 offset += bytes_written; 710 num_bytes = bytes_written; 711 } 712 #else 713 std::lock_guard<std::mutex> guard(offset_access_mutex); 714 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 715 SeekFromStart(offset); 716 error = Write(buf, num_bytes); 717 long after = ::lseek(m_descriptor, 0, SEEK_CUR); 718 719 if (!error.Fail()) 720 SeekFromStart(cur); 721 722 offset = after; 723 #endif 724 } else { 725 num_bytes = 0; 726 error.SetErrorString("invalid file handle"); 727 } 728 return error; 729 } 730 731 size_t NativeFile::PrintfVarArg(const char *format, va_list args) { 732 if (StreamIsValid()) { 733 return ::vfprintf(m_stream, format, args); 734 } else { 735 return File::PrintfVarArg(format, args); 736 } 737 } 738 739 mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) { 740 mode_t mode = 0; 741 File::OpenOptions rw = 742 open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 743 File::eOpenOptionReadWrite); 744 if (rw == eOpenOptionReadWrite) 745 mode |= O_RDWR; 746 else if (rw == eOpenOptionWriteOnly) 747 mode |= O_WRONLY; 748 else if (rw == eOpenOptionReadOnly) 749 mode |= O_RDONLY; 750 751 if (open_options & eOpenOptionAppend) 752 mode |= O_APPEND; 753 754 if (open_options & eOpenOptionTruncate) 755 mode |= O_TRUNC; 756 757 if (open_options & eOpenOptionNonBlocking) 758 mode |= O_NONBLOCK; 759 760 if (open_options & eOpenOptionCanCreateNewOnly) 761 mode |= O_CREAT | O_EXCL; 762 else if (open_options & eOpenOptionCanCreate) 763 mode |= O_CREAT; 764 765 return mode; 766 } 767 768 llvm::Expected<SerialPort::Options> 769 SerialPort::OptionsFromURL(llvm::StringRef urlqs) { 770 SerialPort::Options serial_options; 771 for (llvm::StringRef x : llvm::split(urlqs, '&')) { 772 if (x.consume_front("baud=")) { 773 unsigned int baud_rate; 774 if (!llvm::to_integer(x, baud_rate, 10)) 775 return llvm::createStringError(llvm::inconvertibleErrorCode(), 776 "Invalid baud rate: %s", 777 x.str().c_str()); 778 serial_options.BaudRate = baud_rate; 779 } else if (x.consume_front("parity=")) { 780 serial_options.Parity = 781 llvm::StringSwitch<std::optional<Terminal::Parity>>(x) 782 .Case("no", Terminal::Parity::No) 783 .Case("even", Terminal::Parity::Even) 784 .Case("odd", Terminal::Parity::Odd) 785 .Case("mark", Terminal::Parity::Mark) 786 .Case("space", Terminal::Parity::Space) 787 .Default(std::nullopt); 788 if (!serial_options.Parity) 789 return llvm::createStringError( 790 llvm::inconvertibleErrorCode(), 791 "Invalid parity (must be no, even, odd, mark or space): %s", 792 x.str().c_str()); 793 } else if (x.consume_front("parity-check=")) { 794 serial_options.ParityCheck = 795 llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x) 796 .Case("no", Terminal::ParityCheck::No) 797 .Case("replace", Terminal::ParityCheck::ReplaceWithNUL) 798 .Case("ignore", Terminal::ParityCheck::Ignore) 799 // "mark" mode is not currently supported as it requires special 800 // input processing 801 // .Case("mark", Terminal::ParityCheck::Mark) 802 .Default(std::nullopt); 803 if (!serial_options.ParityCheck) 804 return llvm::createStringError( 805 llvm::inconvertibleErrorCode(), 806 "Invalid parity-check (must be no, replace, ignore or mark): %s", 807 x.str().c_str()); 808 } else if (x.consume_front("stop-bits=")) { 809 unsigned int stop_bits; 810 if (!llvm::to_integer(x, stop_bits, 10) || 811 (stop_bits != 1 && stop_bits != 2)) 812 return llvm::createStringError( 813 llvm::inconvertibleErrorCode(), 814 "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str()); 815 serial_options.StopBits = stop_bits; 816 } else 817 return llvm::createStringError(llvm::inconvertibleErrorCode(), 818 "Unknown parameter: %s", x.str().c_str()); 819 } 820 return serial_options; 821 } 822 823 llvm::Expected<std::unique_ptr<SerialPort>> 824 SerialPort::Create(int fd, OpenOptions options, Options serial_options, 825 bool transfer_ownership) { 826 std::unique_ptr<SerialPort> out{ 827 new SerialPort(fd, options, serial_options, transfer_ownership)}; 828 829 if (!out->GetIsInteractive()) 830 return llvm::createStringError(llvm::inconvertibleErrorCode(), 831 "the specified file is not a teletype"); 832 833 Terminal term{fd}; 834 if (llvm::Error error = term.SetRaw()) 835 return std::move(error); 836 if (serial_options.BaudRate) { 837 if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate)) 838 return std::move(error); 839 } 840 if (serial_options.Parity) { 841 if (llvm::Error error = term.SetParity(*serial_options.Parity)) 842 return std::move(error); 843 } 844 if (serial_options.ParityCheck) { 845 if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck)) 846 return std::move(error); 847 } 848 if (serial_options.StopBits) { 849 if (llvm::Error error = term.SetStopBits(*serial_options.StopBits)) 850 return std::move(error); 851 } 852 853 return std::move(out); 854 } 855 856 SerialPort::SerialPort(int fd, OpenOptions options, 857 SerialPort::Options serial_options, 858 bool transfer_ownership) 859 : NativeFile(fd, options, transfer_ownership), m_state(fd) {} 860 861 Status SerialPort::Close() { 862 m_state.Restore(); 863 return NativeFile::Close(); 864 } 865 866 char File::ID = 0; 867 char NativeFile::ID = 0; 868 char SerialPort::ID = 0; 869