File.cpp revision 355940
1//===-- File.cpp ------------------------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/Host/File.h" 10 11#include <errno.h> 12#include <fcntl.h> 13#include <limits.h> 14#include <stdarg.h> 15#include <stdio.h> 16 17#ifdef _WIN32 18#include "lldb/Host/windows/windows.h" 19#else 20#include <sys/ioctl.h> 21#include <sys/stat.h> 22#include <termios.h> 23#include <unistd.h> 24#endif 25 26#include "llvm/Support/ConvertUTF.h" 27#include "llvm/Support/Errno.h" 28#include "llvm/Support/FileSystem.h" 29#include "llvm/Support/Process.h" 30 31#include "lldb/Host/Config.h" 32#include "lldb/Host/FileSystem.h" 33#include "lldb/Host/Host.h" 34#include "lldb/Utility/DataBufferHeap.h" 35#include "lldb/Utility/FileSpec.h" 36#include "lldb/Utility/Log.h" 37 38using namespace lldb; 39using namespace lldb_private; 40 41static const char *GetStreamOpenModeFromOptions(uint32_t options) { 42 if (options & File::eOpenOptionAppend) { 43 if (options & File::eOpenOptionRead) { 44 if (options & File::eOpenOptionCanCreateNewOnly) 45 return "a+x"; 46 else 47 return "a+"; 48 } else if (options & File::eOpenOptionWrite) { 49 if (options & File::eOpenOptionCanCreateNewOnly) 50 return "ax"; 51 else 52 return "a"; 53 } 54 } else if (options & File::eOpenOptionRead && 55 options & File::eOpenOptionWrite) { 56 if (options & File::eOpenOptionCanCreate) { 57 if (options & File::eOpenOptionCanCreateNewOnly) 58 return "w+x"; 59 else 60 return "w+"; 61 } else 62 return "r+"; 63 } else if (options & File::eOpenOptionRead) { 64 return "r"; 65 } else if (options & File::eOpenOptionWrite) { 66 return "w"; 67 } 68 return nullptr; 69} 70 71int File::kInvalidDescriptor = -1; 72FILE *File::kInvalidStream = nullptr; 73 74File::~File() { Close(); } 75 76int File::GetDescriptor() const { 77 if (DescriptorIsValid()) 78 return m_descriptor; 79 80 // Don't open the file descriptor if we don't need to, just get it from the 81 // stream if we have one. 82 if (StreamIsValid()) { 83#if defined(_WIN32) 84 return _fileno(m_stream); 85#else 86 return fileno(m_stream); 87#endif 88 } 89 90 // Invalid descriptor and invalid stream, return invalid descriptor. 91 return kInvalidDescriptor; 92} 93 94IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; } 95 96void File::SetDescriptor(int fd, bool transfer_ownership) { 97 if (IsValid()) 98 Close(); 99 m_descriptor = fd; 100 m_should_close_fd = transfer_ownership; 101} 102 103FILE *File::GetStream() { 104 if (!StreamIsValid()) { 105 if (DescriptorIsValid()) { 106 const char *mode = GetStreamOpenModeFromOptions(m_options); 107 if (mode) { 108 if (!m_should_close_fd) { 109// We must duplicate the file descriptor if we don't own it because when you 110// call fdopen, the stream will own the fd 111#ifdef _WIN32 112 m_descriptor = ::_dup(GetDescriptor()); 113#else 114 m_descriptor = dup(GetDescriptor()); 115#endif 116 m_should_close_fd = true; 117 } 118 119 m_stream = 120 llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode); 121 122 // If we got a stream, then we own the stream and should no longer own 123 // the descriptor because fclose() will close it for us 124 125 if (m_stream) { 126 m_own_stream = true; 127 m_should_close_fd = false; 128 } 129 } 130 } 131 } 132 return m_stream; 133} 134 135void File::SetStream(FILE *fh, bool transfer_ownership) { 136 if (IsValid()) 137 Close(); 138 m_stream = fh; 139 m_own_stream = transfer_ownership; 140} 141 142uint32_t File::GetPermissions(Status &error) const { 143 int fd = GetDescriptor(); 144 if (fd != kInvalidDescriptor) { 145 struct stat file_stats; 146 if (::fstat(fd, &file_stats) == -1) 147 error.SetErrorToErrno(); 148 else { 149 error.Clear(); 150 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 151 } 152 } else { 153 error.SetErrorString("invalid file descriptor"); 154 } 155 return 0; 156} 157 158Status File::Close() { 159 Status error; 160 if (StreamIsValid() && m_own_stream) { 161 if (::fclose(m_stream) == EOF) 162 error.SetErrorToErrno(); 163 } 164 165 if (DescriptorIsValid() && m_should_close_fd) { 166 if (::close(m_descriptor) != 0) 167 error.SetErrorToErrno(); 168 } 169 m_descriptor = kInvalidDescriptor; 170 m_stream = kInvalidStream; 171 m_options = 0; 172 m_own_stream = false; 173 m_should_close_fd = false; 174 m_is_interactive = eLazyBoolCalculate; 175 m_is_real_terminal = eLazyBoolCalculate; 176 return error; 177} 178 179void File::Clear() { 180 m_stream = nullptr; 181 m_descriptor = kInvalidDescriptor; 182 m_options = 0; 183 m_own_stream = false; 184 m_is_interactive = m_supports_colors = m_is_real_terminal = 185 eLazyBoolCalculate; 186} 187 188Status File::GetFileSpec(FileSpec &file_spec) const { 189 Status error; 190#ifdef F_GETPATH 191 if (IsValid()) { 192 char path[PATH_MAX]; 193 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 194 error.SetErrorToErrno(); 195 else 196 file_spec.SetFile(path, FileSpec::Style::native); 197 } else { 198 error.SetErrorString("invalid file handle"); 199 } 200#elif defined(__linux__) 201 char proc[64]; 202 char path[PATH_MAX]; 203 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 204 error.SetErrorString("cannot resolve file descriptor"); 205 else { 206 ssize_t len; 207 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 208 error.SetErrorToErrno(); 209 else { 210 path[len] = '\0'; 211 file_spec.SetFile(path, FileSpec::Style::native); 212 } 213 } 214#else 215 error.SetErrorString("File::GetFileSpec is not supported on this platform"); 216#endif 217 218 if (error.Fail()) 219 file_spec.Clear(); 220 return error; 221} 222 223off_t File::SeekFromStart(off_t offset, Status *error_ptr) { 224 off_t result = 0; 225 if (DescriptorIsValid()) { 226 result = ::lseek(m_descriptor, offset, SEEK_SET); 227 228 if (error_ptr) { 229 if (result == -1) 230 error_ptr->SetErrorToErrno(); 231 else 232 error_ptr->Clear(); 233 } 234 } else if (StreamIsValid()) { 235 result = ::fseek(m_stream, offset, SEEK_SET); 236 237 if (error_ptr) { 238 if (result == -1) 239 error_ptr->SetErrorToErrno(); 240 else 241 error_ptr->Clear(); 242 } 243 } else if (error_ptr) { 244 error_ptr->SetErrorString("invalid file handle"); 245 } 246 return result; 247} 248 249off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) { 250 off_t result = -1; 251 if (DescriptorIsValid()) { 252 result = ::lseek(m_descriptor, offset, SEEK_CUR); 253 254 if (error_ptr) { 255 if (result == -1) 256 error_ptr->SetErrorToErrno(); 257 else 258 error_ptr->Clear(); 259 } 260 } else if (StreamIsValid()) { 261 result = ::fseek(m_stream, offset, SEEK_CUR); 262 263 if (error_ptr) { 264 if (result == -1) 265 error_ptr->SetErrorToErrno(); 266 else 267 error_ptr->Clear(); 268 } 269 } else if (error_ptr) { 270 error_ptr->SetErrorString("invalid file handle"); 271 } 272 return result; 273} 274 275off_t File::SeekFromEnd(off_t offset, Status *error_ptr) { 276 off_t result = -1; 277 if (DescriptorIsValid()) { 278 result = ::lseek(m_descriptor, offset, SEEK_END); 279 280 if (error_ptr) { 281 if (result == -1) 282 error_ptr->SetErrorToErrno(); 283 else 284 error_ptr->Clear(); 285 } 286 } else if (StreamIsValid()) { 287 result = ::fseek(m_stream, offset, SEEK_END); 288 289 if (error_ptr) { 290 if (result == -1) 291 error_ptr->SetErrorToErrno(); 292 else 293 error_ptr->Clear(); 294 } 295 } else if (error_ptr) { 296 error_ptr->SetErrorString("invalid file handle"); 297 } 298 return result; 299} 300 301Status File::Flush() { 302 Status error; 303 if (StreamIsValid()) { 304 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) 305 error.SetErrorToErrno(); 306 } else if (!DescriptorIsValid()) { 307 error.SetErrorString("invalid file handle"); 308 } 309 return error; 310} 311 312Status File::Sync() { 313 Status error; 314 if (DescriptorIsValid()) { 315#ifdef _WIN32 316 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 317 if (err == 0) 318 error.SetErrorToGenericError(); 319#else 320 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) 321 error.SetErrorToErrno(); 322#endif 323 } else { 324 error.SetErrorString("invalid file handle"); 325 } 326 return error; 327} 328 329#if defined(__APPLE__) 330// Darwin kernels only can read/write <= INT_MAX bytes 331#define MAX_READ_SIZE INT_MAX 332#define MAX_WRITE_SIZE INT_MAX 333#endif 334 335Status File::Read(void *buf, size_t &num_bytes) { 336 Status error; 337 338#if defined(MAX_READ_SIZE) 339 if (num_bytes > MAX_READ_SIZE) { 340 uint8_t *p = (uint8_t *)buf; 341 size_t bytes_left = num_bytes; 342 // Init the num_bytes read to zero 343 num_bytes = 0; 344 345 while (bytes_left > 0) { 346 size_t curr_num_bytes; 347 if (bytes_left > MAX_READ_SIZE) 348 curr_num_bytes = MAX_READ_SIZE; 349 else 350 curr_num_bytes = bytes_left; 351 352 error = Read(p + num_bytes, curr_num_bytes); 353 354 // Update how many bytes were read 355 num_bytes += curr_num_bytes; 356 if (bytes_left < curr_num_bytes) 357 bytes_left = 0; 358 else 359 bytes_left -= curr_num_bytes; 360 361 if (error.Fail()) 362 break; 363 } 364 return error; 365 } 366#endif 367 368 ssize_t bytes_read = -1; 369 if (DescriptorIsValid()) { 370 bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); 371 if (bytes_read == -1) { 372 error.SetErrorToErrno(); 373 num_bytes = 0; 374 } else 375 num_bytes = bytes_read; 376 } else if (StreamIsValid()) { 377 bytes_read = ::fread(buf, 1, num_bytes, m_stream); 378 379 if (bytes_read == 0) { 380 if (::feof(m_stream)) 381 error.SetErrorString("feof"); 382 else if (::ferror(m_stream)) 383 error.SetErrorString("ferror"); 384 num_bytes = 0; 385 } else 386 num_bytes = bytes_read; 387 } else { 388 num_bytes = 0; 389 error.SetErrorString("invalid file handle"); 390 } 391 return error; 392} 393 394Status File::Write(const void *buf, size_t &num_bytes) { 395 Status error; 396 397#if defined(MAX_WRITE_SIZE) 398 if (num_bytes > MAX_WRITE_SIZE) { 399 const uint8_t *p = (const uint8_t *)buf; 400 size_t bytes_left = num_bytes; 401 // Init the num_bytes written to zero 402 num_bytes = 0; 403 404 while (bytes_left > 0) { 405 size_t curr_num_bytes; 406 if (bytes_left > MAX_WRITE_SIZE) 407 curr_num_bytes = MAX_WRITE_SIZE; 408 else 409 curr_num_bytes = bytes_left; 410 411 error = Write(p + num_bytes, curr_num_bytes); 412 413 // Update how many bytes were read 414 num_bytes += curr_num_bytes; 415 if (bytes_left < curr_num_bytes) 416 bytes_left = 0; 417 else 418 bytes_left -= curr_num_bytes; 419 420 if (error.Fail()) 421 break; 422 } 423 return error; 424 } 425#endif 426 427 ssize_t bytes_written = -1; 428 if (DescriptorIsValid()) { 429 bytes_written = 430 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); 431 if (bytes_written == -1) { 432 error.SetErrorToErrno(); 433 num_bytes = 0; 434 } else 435 num_bytes = bytes_written; 436 } else if (StreamIsValid()) { 437 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); 438 439 if (bytes_written == 0) { 440 if (::feof(m_stream)) 441 error.SetErrorString("feof"); 442 else if (::ferror(m_stream)) 443 error.SetErrorString("ferror"); 444 num_bytes = 0; 445 } else 446 num_bytes = bytes_written; 447 448 } else { 449 num_bytes = 0; 450 error.SetErrorString("invalid file handle"); 451 } 452 453 return error; 454} 455 456Status File::Read(void *buf, size_t &num_bytes, off_t &offset) { 457 Status error; 458 459#if defined(MAX_READ_SIZE) 460 if (num_bytes > MAX_READ_SIZE) { 461 uint8_t *p = (uint8_t *)buf; 462 size_t bytes_left = num_bytes; 463 // Init the num_bytes read to zero 464 num_bytes = 0; 465 466 while (bytes_left > 0) { 467 size_t curr_num_bytes; 468 if (bytes_left > MAX_READ_SIZE) 469 curr_num_bytes = MAX_READ_SIZE; 470 else 471 curr_num_bytes = bytes_left; 472 473 error = Read(p + num_bytes, curr_num_bytes, offset); 474 475 // Update how many bytes were read 476 num_bytes += curr_num_bytes; 477 if (bytes_left < curr_num_bytes) 478 bytes_left = 0; 479 else 480 bytes_left -= curr_num_bytes; 481 482 if (error.Fail()) 483 break; 484 } 485 return error; 486 } 487#endif 488 489#ifndef _WIN32 490 int fd = GetDescriptor(); 491 if (fd != kInvalidDescriptor) { 492 ssize_t bytes_read = 493 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); 494 if (bytes_read < 0) { 495 num_bytes = 0; 496 error.SetErrorToErrno(); 497 } else { 498 offset += bytes_read; 499 num_bytes = bytes_read; 500 } 501 } else { 502 num_bytes = 0; 503 error.SetErrorString("invalid file handle"); 504 } 505#else 506 std::lock_guard<std::mutex> guard(offset_access_mutex); 507 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 508 SeekFromStart(offset); 509 error = Read(buf, num_bytes); 510 if (!error.Fail()) 511 SeekFromStart(cur); 512#endif 513 return error; 514} 515 516Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate, 517 DataBufferSP &data_buffer_sp) { 518 Status error; 519 520 if (num_bytes > 0) { 521 int fd = GetDescriptor(); 522 if (fd != kInvalidDescriptor) { 523 struct stat file_stats; 524 if (::fstat(fd, &file_stats) == 0) { 525 if (file_stats.st_size > offset) { 526 const size_t bytes_left = file_stats.st_size - offset; 527 if (num_bytes > bytes_left) 528 num_bytes = bytes_left; 529 530 size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); 531 std::unique_ptr<DataBufferHeap> data_heap_up; 532 data_heap_up.reset(new DataBufferHeap()); 533 data_heap_up->SetByteSize(num_bytes_plus_nul_char); 534 535 if (data_heap_up) { 536 error = Read(data_heap_up->GetBytes(), num_bytes, offset); 537 if (error.Success()) { 538 // Make sure we read exactly what we asked for and if we got 539 // less, adjust the array 540 if (num_bytes_plus_nul_char < data_heap_up->GetByteSize()) 541 data_heap_up->SetByteSize(num_bytes_plus_nul_char); 542 data_buffer_sp.reset(data_heap_up.release()); 543 return error; 544 } 545 } 546 } else 547 error.SetErrorString("file is empty"); 548 } else 549 error.SetErrorToErrno(); 550 } else 551 error.SetErrorString("invalid file handle"); 552 } else 553 error.SetErrorString("invalid file handle"); 554 555 num_bytes = 0; 556 data_buffer_sp.reset(); 557 return error; 558} 559 560Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) { 561 Status error; 562 563#if defined(MAX_WRITE_SIZE) 564 if (num_bytes > MAX_WRITE_SIZE) { 565 const uint8_t *p = (const uint8_t *)buf; 566 size_t bytes_left = num_bytes; 567 // Init the num_bytes written to zero 568 num_bytes = 0; 569 570 while (bytes_left > 0) { 571 size_t curr_num_bytes; 572 if (bytes_left > MAX_WRITE_SIZE) 573 curr_num_bytes = MAX_WRITE_SIZE; 574 else 575 curr_num_bytes = bytes_left; 576 577 error = Write(p + num_bytes, curr_num_bytes, offset); 578 579 // Update how many bytes were read 580 num_bytes += curr_num_bytes; 581 if (bytes_left < curr_num_bytes) 582 bytes_left = 0; 583 else 584 bytes_left -= curr_num_bytes; 585 586 if (error.Fail()) 587 break; 588 } 589 return error; 590 } 591#endif 592 593 int fd = GetDescriptor(); 594 if (fd != kInvalidDescriptor) { 595#ifndef _WIN32 596 ssize_t bytes_written = 597 llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); 598 if (bytes_written < 0) { 599 num_bytes = 0; 600 error.SetErrorToErrno(); 601 } else { 602 offset += bytes_written; 603 num_bytes = bytes_written; 604 } 605#else 606 std::lock_guard<std::mutex> guard(offset_access_mutex); 607 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 608 SeekFromStart(offset); 609 error = Write(buf, num_bytes); 610 long after = ::lseek(m_descriptor, 0, SEEK_CUR); 611 612 if (!error.Fail()) 613 SeekFromStart(cur); 614 615 offset = after; 616#endif 617 } else { 618 num_bytes = 0; 619 error.SetErrorString("invalid file handle"); 620 } 621 return error; 622} 623 624// Print some formatted output to the stream. 625size_t File::Printf(const char *format, ...) { 626 va_list args; 627 va_start(args, format); 628 size_t result = PrintfVarArg(format, args); 629 va_end(args); 630 return result; 631} 632 633// Print some formatted output to the stream. 634size_t File::PrintfVarArg(const char *format, va_list args) { 635 size_t result = 0; 636 if (DescriptorIsValid()) { 637 char *s = nullptr; 638 result = vasprintf(&s, format, args); 639 if (s != nullptr) { 640 if (result > 0) { 641 size_t s_len = result; 642 Write(s, s_len); 643 result = s_len; 644 } 645 free(s); 646 } 647 } else if (StreamIsValid()) { 648 result = ::vfprintf(m_stream, format, args); 649 } 650 return result; 651} 652 653mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) { 654 mode_t mode = 0; 655 if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) 656 mode |= O_RDWR; 657 else if (open_options & eOpenOptionWrite) 658 mode |= O_WRONLY; 659 660 if (open_options & eOpenOptionAppend) 661 mode |= O_APPEND; 662 663 if (open_options & eOpenOptionTruncate) 664 mode |= O_TRUNC; 665 666 if (open_options & eOpenOptionNonBlocking) 667 mode |= O_NONBLOCK; 668 669 if (open_options & eOpenOptionCanCreateNewOnly) 670 mode |= O_CREAT | O_EXCL; 671 else if (open_options & eOpenOptionCanCreate) 672 mode |= O_CREAT; 673 674 return mode; 675} 676 677void File::CalculateInteractiveAndTerminal() { 678 const int fd = GetDescriptor(); 679 if (fd >= 0) { 680 m_is_interactive = eLazyBoolNo; 681 m_is_real_terminal = eLazyBoolNo; 682#if defined(_WIN32) 683 if (_isatty(fd)) { 684 m_is_interactive = eLazyBoolYes; 685 m_is_real_terminal = eLazyBoolYes; 686#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 687 m_supports_colors = eLazyBoolYes; 688#endif 689 } 690#else 691 if (isatty(fd)) { 692 m_is_interactive = eLazyBoolYes; 693 struct winsize window_size; 694 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { 695 if (window_size.ws_col > 0) { 696 m_is_real_terminal = eLazyBoolYes; 697 if (llvm::sys::Process::FileDescriptorHasColors(fd)) 698 m_supports_colors = eLazyBoolYes; 699 } 700 } 701 } 702#endif 703 } 704} 705 706bool File::GetIsInteractive() { 707 if (m_is_interactive == eLazyBoolCalculate) 708 CalculateInteractiveAndTerminal(); 709 return m_is_interactive == eLazyBoolYes; 710} 711 712bool File::GetIsRealTerminal() { 713 if (m_is_real_terminal == eLazyBoolCalculate) 714 CalculateInteractiveAndTerminal(); 715 return m_is_real_terminal == eLazyBoolYes; 716} 717 718bool File::GetIsTerminalWithColors() { 719 if (m_supports_colors == eLazyBoolCalculate) 720 CalculateInteractiveAndTerminal(); 721 return m_supports_colors == eLazyBoolYes; 722} 723