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