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