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