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