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