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 FileSpec &file_spec, Error &error) 329 { 330 if (file_spec) 331 { 332 struct stat file_stats; 333 if (::stat(file_spec.GetCString(), &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 error.SetErrorString ("empty file spec"); 343 return 0; 344 } 345 346 uint32_t 347 File::GetPermissions(Error &error) const 348 { 349 int fd = GetDescriptor(); 350 if (fd != kInvalidDescriptor) 351 { 352 struct stat file_stats; 353 if (::fstat (fd, &file_stats) == -1) 354 error.SetErrorToErrno(); 355 else 356 { 357 error.Clear(); 358 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 359 } 360 } 361 else 362 { 363 error.SetErrorString ("invalid file descriptor"); 364 } 365 return 0; 366 } 367 368 369 Error 370 File::Close () 371 { 372 Error error; 373 if (StreamIsValid() && m_own_stream) 374 { 375 if (::fclose (m_stream) == EOF) 376 error.SetErrorToErrno(); 377 } 378 379 if (DescriptorIsValid() && m_should_close_fd) 380 { 381 if (::close (m_descriptor) != 0) 382 error.SetErrorToErrno(); 383 } 384 m_descriptor = kInvalidDescriptor; 385 m_stream = kInvalidStream; 386 m_options = 0; 387 m_own_stream = false; 388 m_should_close_fd = false; 389 m_is_interactive = eLazyBoolCalculate; 390 m_is_real_terminal = eLazyBoolCalculate; 391 return error; 392 } 393 394 395 Error 396 File::GetFileSpec (FileSpec &file_spec) const 397 { 398 Error error; 399 #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 400 if (IsValid ()) 401 { 402 char path[PATH_MAX]; 403 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 404 error.SetErrorToErrno(); 405 else 406 file_spec.SetFile (path, false); 407 } 408 else 409 { 410 error.SetErrorString("invalid file handle"); 411 } 412 #elif defined(__linux__) 413 char proc[64]; 414 char path[PATH_MAX]; 415 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 416 error.SetErrorString ("cannot resolve file descriptor"); 417 else 418 { 419 ssize_t len; 420 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 421 error.SetErrorToErrno(); 422 else 423 { 424 path[len] = '\0'; 425 file_spec.SetFile (path, false); 426 } 427 } 428 #else 429 error.SetErrorString ("File::GetFileSpec is not supported on this platform"); 430 #endif 431 432 if (error.Fail()) 433 file_spec.Clear(); 434 return error; 435 } 436 437 off_t 438 File::SeekFromStart (off_t offset, Error *error_ptr) 439 { 440 off_t result = 0; 441 if (DescriptorIsValid()) 442 { 443 result = ::lseek (m_descriptor, offset, SEEK_SET); 444 445 if (error_ptr) 446 { 447 if (result == -1) 448 error_ptr->SetErrorToErrno(); 449 else 450 error_ptr->Clear(); 451 } 452 } 453 else if (StreamIsValid ()) 454 { 455 result = ::fseek(m_stream, offset, SEEK_SET); 456 457 if (error_ptr) 458 { 459 if (result == -1) 460 error_ptr->SetErrorToErrno(); 461 else 462 error_ptr->Clear(); 463 } 464 } 465 else if (error_ptr) 466 { 467 error_ptr->SetErrorString("invalid file handle"); 468 } 469 return result; 470 } 471 472 off_t 473 File::SeekFromCurrent (off_t offset, Error *error_ptr) 474 { 475 off_t result = -1; 476 if (DescriptorIsValid()) 477 { 478 result = ::lseek (m_descriptor, offset, SEEK_CUR); 479 480 if (error_ptr) 481 { 482 if (result == -1) 483 error_ptr->SetErrorToErrno(); 484 else 485 error_ptr->Clear(); 486 } 487 } 488 else if (StreamIsValid ()) 489 { 490 result = ::fseek(m_stream, offset, SEEK_CUR); 491 492 if (error_ptr) 493 { 494 if (result == -1) 495 error_ptr->SetErrorToErrno(); 496 else 497 error_ptr->Clear(); 498 } 499 } 500 else if (error_ptr) 501 { 502 error_ptr->SetErrorString("invalid file handle"); 503 } 504 return result; 505 } 506 507 off_t 508 File::SeekFromEnd (off_t offset, Error *error_ptr) 509 { 510 off_t result = -1; 511 if (DescriptorIsValid()) 512 { 513 result = ::lseek (m_descriptor, offset, SEEK_END); 514 515 if (error_ptr) 516 { 517 if (result == -1) 518 error_ptr->SetErrorToErrno(); 519 else 520 error_ptr->Clear(); 521 } 522 } 523 else if (StreamIsValid ()) 524 { 525 result = ::fseek(m_stream, offset, SEEK_END); 526 527 if (error_ptr) 528 { 529 if (result == -1) 530 error_ptr->SetErrorToErrno(); 531 else 532 error_ptr->Clear(); 533 } 534 } 535 else if (error_ptr) 536 { 537 error_ptr->SetErrorString("invalid file handle"); 538 } 539 return result; 540 } 541 542 Error 543 File::Flush () 544 { 545 Error error; 546 if (StreamIsValid()) 547 { 548 int err = 0; 549 do 550 { 551 err = ::fflush (m_stream); 552 } while (err == EOF && errno == EINTR); 553 554 if (err == EOF) 555 error.SetErrorToErrno(); 556 } 557 else if (!DescriptorIsValid()) 558 { 559 error.SetErrorString("invalid file handle"); 560 } 561 return error; 562 } 563 564 565 Error 566 File::Sync () 567 { 568 Error error; 569 if (DescriptorIsValid()) 570 { 571 #ifdef _WIN32 572 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 573 if (err == 0) 574 error.SetErrorToGenericError(); 575 #else 576 int err = 0; 577 do 578 { 579 err = ::fsync (m_descriptor); 580 } while (err == -1 && errno == EINTR); 581 582 if (err == -1) 583 error.SetErrorToErrno(); 584 #endif 585 } 586 else 587 { 588 error.SetErrorString("invalid file handle"); 589 } 590 return error; 591 } 592 593 #if defined (__APPLE__) 594 // Darwin kernels only can read/write <= INT_MAX bytes 595 #define MAX_READ_SIZE INT_MAX 596 #define MAX_WRITE_SIZE INT_MAX 597 #endif 598 599 Error 600 File::Read (void *buf, size_t &num_bytes) 601 { 602 Error error; 603 604 #if defined (MAX_READ_SIZE) 605 if (num_bytes > MAX_READ_SIZE) 606 { 607 uint8_t *p = (uint8_t *)buf; 608 size_t bytes_left = num_bytes; 609 // Init the num_bytes read to zero 610 num_bytes = 0; 611 612 while (bytes_left > 0) 613 { 614 size_t curr_num_bytes; 615 if (bytes_left > MAX_READ_SIZE) 616 curr_num_bytes = MAX_READ_SIZE; 617 else 618 curr_num_bytes = bytes_left; 619 620 error = Read (p + num_bytes, curr_num_bytes); 621 622 // Update how many bytes were read 623 num_bytes += curr_num_bytes; 624 if (bytes_left < curr_num_bytes) 625 bytes_left = 0; 626 else 627 bytes_left -= curr_num_bytes; 628 629 if (error.Fail()) 630 break; 631 } 632 return error; 633 } 634 #endif 635 636 ssize_t bytes_read = -1; 637 if (DescriptorIsValid()) 638 { 639 do 640 { 641 bytes_read = ::read (m_descriptor, buf, num_bytes); 642 } while (bytes_read < 0 && errno == EINTR); 643 644 if (bytes_read == -1) 645 { 646 error.SetErrorToErrno(); 647 num_bytes = 0; 648 } 649 else 650 num_bytes = bytes_read; 651 } 652 else if (StreamIsValid()) 653 { 654 bytes_read = ::fread (buf, 1, num_bytes, m_stream); 655 656 if (bytes_read == 0) 657 { 658 if (::feof(m_stream)) 659 error.SetErrorString ("feof"); 660 else if (::ferror (m_stream)) 661 error.SetErrorString ("ferror"); 662 num_bytes = 0; 663 } 664 else 665 num_bytes = bytes_read; 666 } 667 else 668 { 669 num_bytes = 0; 670 error.SetErrorString("invalid file handle"); 671 } 672 return error; 673 } 674 675 Error 676 File::Write (const void *buf, size_t &num_bytes) 677 { 678 Error error; 679 680 #if defined (MAX_WRITE_SIZE) 681 if (num_bytes > MAX_WRITE_SIZE) 682 { 683 const uint8_t *p = (const uint8_t *)buf; 684 size_t bytes_left = num_bytes; 685 // Init the num_bytes written to zero 686 num_bytes = 0; 687 688 while (bytes_left > 0) 689 { 690 size_t curr_num_bytes; 691 if (bytes_left > MAX_WRITE_SIZE) 692 curr_num_bytes = MAX_WRITE_SIZE; 693 else 694 curr_num_bytes = bytes_left; 695 696 error = Write (p + num_bytes, curr_num_bytes); 697 698 // Update how many bytes were read 699 num_bytes += curr_num_bytes; 700 if (bytes_left < curr_num_bytes) 701 bytes_left = 0; 702 else 703 bytes_left -= curr_num_bytes; 704 705 if (error.Fail()) 706 break; 707 } 708 return error; 709 } 710 #endif 711 712 ssize_t bytes_written = -1; 713 if (DescriptorIsValid()) 714 { 715 do 716 { 717 bytes_written = ::write (m_descriptor, buf, num_bytes); 718 } while (bytes_written < 0 && errno == EINTR); 719 720 if (bytes_written == -1) 721 { 722 error.SetErrorToErrno(); 723 num_bytes = 0; 724 } 725 else 726 num_bytes = bytes_written; 727 } 728 else if (StreamIsValid()) 729 { 730 bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); 731 732 if (bytes_written == 0) 733 { 734 if (::feof(m_stream)) 735 error.SetErrorString ("feof"); 736 else if (::ferror (m_stream)) 737 error.SetErrorString ("ferror"); 738 num_bytes = 0; 739 } 740 else 741 num_bytes = bytes_written; 742 743 } 744 else 745 { 746 num_bytes = 0; 747 error.SetErrorString("invalid file handle"); 748 } 749 750 return error; 751 } 752 753 754 Error 755 File::Read (void *buf, size_t &num_bytes, off_t &offset) 756 { 757 Error error; 758 759 #if defined (MAX_READ_SIZE) 760 if (num_bytes > MAX_READ_SIZE) 761 { 762 uint8_t *p = (uint8_t *)buf; 763 size_t bytes_left = num_bytes; 764 // Init the num_bytes read to zero 765 num_bytes = 0; 766 767 while (bytes_left > 0) 768 { 769 size_t curr_num_bytes; 770 if (bytes_left > MAX_READ_SIZE) 771 curr_num_bytes = MAX_READ_SIZE; 772 else 773 curr_num_bytes = bytes_left; 774 775 error = Read (p + num_bytes, curr_num_bytes, offset); 776 777 // Update how many bytes were read 778 num_bytes += curr_num_bytes; 779 if (bytes_left < curr_num_bytes) 780 bytes_left = 0; 781 else 782 bytes_left -= curr_num_bytes; 783 784 if (error.Fail()) 785 break; 786 } 787 return error; 788 } 789 #endif 790 791 #ifndef _WIN32 792 int fd = GetDescriptor(); 793 if (fd != kInvalidDescriptor) 794 { 795 ssize_t bytes_read = -1; 796 do 797 { 798 bytes_read = ::pread (fd, buf, num_bytes, offset); 799 } while (bytes_read < 0 && errno == EINTR); 800 801 if (bytes_read < 0) 802 { 803 num_bytes = 0; 804 error.SetErrorToErrno(); 805 } 806 else 807 { 808 offset += bytes_read; 809 num_bytes = bytes_read; 810 } 811 } 812 else 813 { 814 num_bytes = 0; 815 error.SetErrorString("invalid file handle"); 816 } 817 #else 818 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 819 SeekFromStart(offset); 820 error = Read(buf, num_bytes); 821 if (!error.Fail()) 822 SeekFromStart(cur); 823 #endif 824 return error; 825 } 826 827 Error 828 File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) 829 { 830 Error error; 831 832 if (num_bytes > 0) 833 { 834 int fd = GetDescriptor(); 835 if (fd != kInvalidDescriptor) 836 { 837 struct stat file_stats; 838 if (::fstat (fd, &file_stats) == 0) 839 { 840 if (file_stats.st_size > offset) 841 { 842 const size_t bytes_left = file_stats.st_size - offset; 843 if (num_bytes > bytes_left) 844 num_bytes = bytes_left; 845 846 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); 847 std::unique_ptr<DataBufferHeap> data_heap_ap; 848 data_heap_ap.reset(new DataBufferHeap()); 849 data_heap_ap->SetByteSize(num_bytes_plus_nul_char); 850 851 if (data_heap_ap.get()) 852 { 853 error = Read (data_heap_ap->GetBytes(), num_bytes, offset); 854 if (error.Success()) 855 { 856 // Make sure we read exactly what we asked for and if we got 857 // less, adjust the array 858 if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize()) 859 data_heap_ap->SetByteSize(num_bytes_plus_nul_char); 860 data_buffer_sp.reset(data_heap_ap.release()); 861 return error; 862 } 863 } 864 } 865 else 866 error.SetErrorString("file is empty"); 867 } 868 else 869 error.SetErrorToErrno(); 870 } 871 else 872 error.SetErrorString("invalid file handle"); 873 } 874 else 875 error.SetErrorString("invalid file handle"); 876 877 num_bytes = 0; 878 data_buffer_sp.reset(); 879 return error; 880 } 881 882 Error 883 File::Write (const void *buf, size_t &num_bytes, off_t &offset) 884 { 885 Error error; 886 887 #if defined (MAX_WRITE_SIZE) 888 if (num_bytes > MAX_WRITE_SIZE) 889 { 890 const uint8_t *p = (const uint8_t *)buf; 891 size_t bytes_left = num_bytes; 892 // Init the num_bytes written to zero 893 num_bytes = 0; 894 895 while (bytes_left > 0) 896 { 897 size_t curr_num_bytes; 898 if (bytes_left > MAX_WRITE_SIZE) 899 curr_num_bytes = MAX_WRITE_SIZE; 900 else 901 curr_num_bytes = bytes_left; 902 903 error = Write (p + num_bytes, curr_num_bytes, offset); 904 905 // Update how many bytes were read 906 num_bytes += curr_num_bytes; 907 if (bytes_left < curr_num_bytes) 908 bytes_left = 0; 909 else 910 bytes_left -= curr_num_bytes; 911 912 if (error.Fail()) 913 break; 914 } 915 return error; 916 } 917 #endif 918 919 int fd = GetDescriptor(); 920 if (fd != kInvalidDescriptor) 921 { 922 #ifndef _WIN32 923 ssize_t bytes_written = -1; 924 do 925 { 926 bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); 927 } while (bytes_written < 0 && errno == EINTR); 928 929 if (bytes_written < 0) 930 { 931 num_bytes = 0; 932 error.SetErrorToErrno(); 933 } 934 else 935 { 936 offset += bytes_written; 937 num_bytes = bytes_written; 938 } 939 #else 940 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 941 error = Write(buf, num_bytes); 942 long after = ::lseek(m_descriptor, 0, SEEK_CUR); 943 944 if (!error.Fail()) 945 SeekFromStart(cur); 946 947 offset = after; 948 #endif 949 } 950 else 951 { 952 num_bytes = 0; 953 error.SetErrorString("invalid file handle"); 954 } 955 return error; 956 } 957 958 //------------------------------------------------------------------ 959 // Print some formatted output to the stream. 960 //------------------------------------------------------------------ 961 size_t 962 File::Printf (const char *format, ...) 963 { 964 va_list args; 965 va_start (args, format); 966 size_t result = PrintfVarArg (format, args); 967 va_end (args); 968 return result; 969 } 970 971 //------------------------------------------------------------------ 972 // Print some formatted output to the stream. 973 //------------------------------------------------------------------ 974 size_t 975 File::PrintfVarArg (const char *format, va_list args) 976 { 977 size_t result = 0; 978 if (DescriptorIsValid()) 979 { 980 char *s = NULL; 981 result = vasprintf(&s, format, args); 982 if (s != NULL) 983 { 984 if (result > 0) 985 { 986 size_t s_len = result; 987 Write (s, s_len); 988 result = s_len; 989 } 990 free (s); 991 } 992 } 993 else if (StreamIsValid()) 994 { 995 result = ::vfprintf (m_stream, format, args); 996 } 997 return result; 998 } 999 1000 mode_t 1001 File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options) 1002 { 1003 mode_t mode = 0; 1004 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) 1005 mode |= O_RDWR; 1006 else if (open_options & eOpenOptionWrite) 1007 mode |= O_WRONLY; 1008 1009 if (open_options & eOpenOptionAppend) 1010 mode |= O_APPEND; 1011 1012 if (open_options & eOpenOptionTruncate) 1013 mode |= O_TRUNC; 1014 1015 if (open_options & eOpenOptionNonBlocking) 1016 mode |= O_NONBLOCK; 1017 1018 if (open_options & eOpenOptionCanCreateNewOnly) 1019 mode |= O_CREAT | O_EXCL; 1020 else if (open_options & eOpenOptionCanCreate) 1021 mode |= O_CREAT; 1022 1023 return mode; 1024 } 1025 1026 void 1027 File::CalculateInteractiveAndTerminal () 1028 { 1029 const int fd = GetDescriptor(); 1030 if (fd >= 0) 1031 { 1032 m_is_interactive = eLazyBoolNo; 1033 m_is_real_terminal = eLazyBoolNo; 1034 #if (defined(_WIN32) || defined(__ANDROID_NDK__)) 1035 if (_isatty(fd)) 1036 { 1037 m_is_interactive = eLazyBoolYes; 1038 m_is_real_terminal = eLazyBoolYes; 1039 } 1040 #else 1041 if (isatty(fd)) 1042 { 1043 m_is_interactive = eLazyBoolYes; 1044 struct winsize window_size; 1045 if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) 1046 { 1047 if (window_size.ws_col > 0) 1048 m_is_real_terminal = eLazyBoolYes; 1049 } 1050 } 1051 #endif 1052 } 1053 } 1054 1055 bool 1056 File::GetIsInteractive () 1057 { 1058 if (m_is_interactive == eLazyBoolCalculate) 1059 CalculateInteractiveAndTerminal (); 1060 return m_is_interactive == eLazyBoolYes; 1061 } 1062 1063 bool 1064 File::GetIsRealTerminal () 1065 { 1066 if (m_is_real_terminal == eLazyBoolCalculate) 1067 CalculateInteractiveAndTerminal(); 1068 return m_is_real_terminal == eLazyBoolYes; 1069 } 1070 1071