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