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