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