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