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