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