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