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