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