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