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