1dda28197Spatrick //===-- File.cpp ----------------------------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include "lldb/Host/File.h" 10061da546Spatrick 11*be691f3bSpatrick #include <cerrno> 12*be691f3bSpatrick #include <climits> 13*be691f3bSpatrick #include <cstdarg> 14*be691f3bSpatrick #include <cstdio> 15061da546Spatrick #include <fcntl.h> 16061da546Spatrick 17061da546Spatrick #ifdef _WIN32 18061da546Spatrick #include "lldb/Host/windows/windows.h" 19061da546Spatrick #else 20061da546Spatrick #include <sys/ioctl.h> 21061da546Spatrick #include <sys/stat.h> 22061da546Spatrick #include <termios.h> 23061da546Spatrick #include <unistd.h> 24061da546Spatrick #endif 25061da546Spatrick 26061da546Spatrick #include "llvm/Support/ConvertUTF.h" 27061da546Spatrick #include "llvm/Support/Errno.h" 28061da546Spatrick #include "llvm/Support/FileSystem.h" 29061da546Spatrick #include "llvm/Support/Process.h" 30061da546Spatrick 31061da546Spatrick #include "lldb/Host/Config.h" 32061da546Spatrick #include "lldb/Host/FileSystem.h" 33061da546Spatrick #include "lldb/Host/Host.h" 34061da546Spatrick #include "lldb/Utility/DataBufferHeap.h" 35061da546Spatrick #include "lldb/Utility/FileSpec.h" 36061da546Spatrick #include "lldb/Utility/Log.h" 37061da546Spatrick 38061da546Spatrick using namespace lldb; 39061da546Spatrick using namespace lldb_private; 40061da546Spatrick using llvm::Expected; 41061da546Spatrick 42061da546Spatrick Expected<const char *> 43061da546Spatrick File::GetStreamOpenModeFromOptions(File::OpenOptions options) { 44061da546Spatrick if (options & File::eOpenOptionAppend) { 45061da546Spatrick if (options & File::eOpenOptionRead) { 46061da546Spatrick if (options & File::eOpenOptionCanCreateNewOnly) 47061da546Spatrick return "a+x"; 48061da546Spatrick else 49061da546Spatrick return "a+"; 50061da546Spatrick } else if (options & File::eOpenOptionWrite) { 51061da546Spatrick if (options & File::eOpenOptionCanCreateNewOnly) 52061da546Spatrick return "ax"; 53061da546Spatrick else 54061da546Spatrick return "a"; 55061da546Spatrick } 56061da546Spatrick } else if (options & File::eOpenOptionRead && 57061da546Spatrick options & File::eOpenOptionWrite) { 58061da546Spatrick if (options & File::eOpenOptionCanCreate) { 59061da546Spatrick if (options & File::eOpenOptionCanCreateNewOnly) 60061da546Spatrick return "w+x"; 61061da546Spatrick else 62061da546Spatrick return "w+"; 63061da546Spatrick } else 64061da546Spatrick return "r+"; 65061da546Spatrick } else if (options & File::eOpenOptionRead) { 66061da546Spatrick return "r"; 67061da546Spatrick } else if (options & File::eOpenOptionWrite) { 68061da546Spatrick return "w"; 69061da546Spatrick } 70061da546Spatrick return llvm::createStringError( 71061da546Spatrick llvm::inconvertibleErrorCode(), 72061da546Spatrick "invalid options, cannot convert to mode string"); 73061da546Spatrick } 74061da546Spatrick 75061da546Spatrick Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { 76061da546Spatrick OpenOptions opts = 77061da546Spatrick llvm::StringSwitch<OpenOptions>(mode) 78061da546Spatrick .Cases("r", "rb", eOpenOptionRead) 79061da546Spatrick .Cases("w", "wb", eOpenOptionWrite) 80061da546Spatrick .Cases("a", "ab", 81061da546Spatrick eOpenOptionWrite | eOpenOptionAppend | eOpenOptionCanCreate) 82061da546Spatrick .Cases("r+", "rb+", "r+b", eOpenOptionRead | eOpenOptionWrite) 83061da546Spatrick .Cases("w+", "wb+", "w+b", 84061da546Spatrick eOpenOptionRead | eOpenOptionWrite | eOpenOptionCanCreate | 85061da546Spatrick eOpenOptionTruncate) 86061da546Spatrick .Cases("a+", "ab+", "a+b", 87061da546Spatrick eOpenOptionRead | eOpenOptionWrite | eOpenOptionAppend | 88061da546Spatrick eOpenOptionCanCreate) 89061da546Spatrick .Default(OpenOptions()); 90061da546Spatrick if (opts) 91061da546Spatrick return opts; 92061da546Spatrick return llvm::createStringError( 93061da546Spatrick llvm::inconvertibleErrorCode(), 94061da546Spatrick "invalid mode, cannot convert to File::OpenOptions"); 95061da546Spatrick } 96061da546Spatrick 97061da546Spatrick int File::kInvalidDescriptor = -1; 98061da546Spatrick FILE *File::kInvalidStream = nullptr; 99061da546Spatrick 100061da546Spatrick Status File::Read(void *buf, size_t &num_bytes) { 101061da546Spatrick return std::error_code(ENOTSUP, std::system_category()); 102061da546Spatrick } 103061da546Spatrick Status File::Write(const void *buf, size_t &num_bytes) { 104061da546Spatrick return std::error_code(ENOTSUP, std::system_category()); 105061da546Spatrick } 106061da546Spatrick 107061da546Spatrick bool File::IsValid() const { return false; } 108061da546Spatrick 109061da546Spatrick Status File::Close() { return Flush(); } 110061da546Spatrick 111061da546Spatrick IOObject::WaitableHandle File::GetWaitableHandle() { 112061da546Spatrick return IOObject::kInvalidHandleValue; 113061da546Spatrick } 114061da546Spatrick 115061da546Spatrick Status File::GetFileSpec(FileSpec &file_spec) const { 116061da546Spatrick file_spec.Clear(); 117061da546Spatrick return std::error_code(ENOTSUP, std::system_category()); 118061da546Spatrick } 119061da546Spatrick 120061da546Spatrick int File::GetDescriptor() const { return kInvalidDescriptor; } 121061da546Spatrick 122061da546Spatrick FILE *File::GetStream() { return nullptr; } 123061da546Spatrick 124061da546Spatrick off_t File::SeekFromStart(off_t offset, Status *error_ptr) { 125061da546Spatrick if (error_ptr) 126061da546Spatrick *error_ptr = std::error_code(ENOTSUP, std::system_category()); 127061da546Spatrick return -1; 128061da546Spatrick } 129061da546Spatrick 130061da546Spatrick off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) { 131061da546Spatrick if (error_ptr) 132061da546Spatrick *error_ptr = std::error_code(ENOTSUP, std::system_category()); 133061da546Spatrick return -1; 134061da546Spatrick } 135061da546Spatrick 136061da546Spatrick off_t File::SeekFromEnd(off_t offset, Status *error_ptr) { 137061da546Spatrick if (error_ptr) 138061da546Spatrick *error_ptr = std::error_code(ENOTSUP, std::system_category()); 139061da546Spatrick return -1; 140061da546Spatrick } 141061da546Spatrick 142061da546Spatrick Status File::Read(void *dst, size_t &num_bytes, off_t &offset) { 143061da546Spatrick return std::error_code(ENOTSUP, std::system_category()); 144061da546Spatrick } 145061da546Spatrick 146061da546Spatrick Status File::Write(const void *src, size_t &num_bytes, off_t &offset) { 147061da546Spatrick return std::error_code(ENOTSUP, std::system_category()); 148061da546Spatrick } 149061da546Spatrick 150061da546Spatrick Status File::Flush() { return Status(); } 151061da546Spatrick 152061da546Spatrick Status File::Sync() { return Flush(); } 153061da546Spatrick 154061da546Spatrick void File::CalculateInteractiveAndTerminal() { 155061da546Spatrick const int fd = GetDescriptor(); 156061da546Spatrick if (!DescriptorIsValid(fd)) { 157061da546Spatrick m_is_interactive = eLazyBoolNo; 158061da546Spatrick m_is_real_terminal = eLazyBoolNo; 159061da546Spatrick m_supports_colors = eLazyBoolNo; 160061da546Spatrick return; 161061da546Spatrick } 162061da546Spatrick m_is_interactive = eLazyBoolNo; 163061da546Spatrick m_is_real_terminal = eLazyBoolNo; 164061da546Spatrick #if defined(_WIN32) 165061da546Spatrick if (_isatty(fd)) { 166061da546Spatrick m_is_interactive = eLazyBoolYes; 167061da546Spatrick m_is_real_terminal = eLazyBoolYes; 168061da546Spatrick #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 169061da546Spatrick m_supports_colors = eLazyBoolYes; 170061da546Spatrick #endif 171061da546Spatrick } 172061da546Spatrick #else 173061da546Spatrick if (isatty(fd)) { 174061da546Spatrick m_is_interactive = eLazyBoolYes; 175061da546Spatrick struct winsize window_size; 176061da546Spatrick if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { 177061da546Spatrick if (window_size.ws_col > 0) { 178061da546Spatrick m_is_real_terminal = eLazyBoolYes; 179061da546Spatrick if (llvm::sys::Process::FileDescriptorHasColors(fd)) 180061da546Spatrick m_supports_colors = eLazyBoolYes; 181061da546Spatrick } 182061da546Spatrick } 183061da546Spatrick } 184061da546Spatrick #endif 185061da546Spatrick } 186061da546Spatrick 187061da546Spatrick bool File::GetIsInteractive() { 188061da546Spatrick if (m_is_interactive == eLazyBoolCalculate) 189061da546Spatrick CalculateInteractiveAndTerminal(); 190061da546Spatrick return m_is_interactive == eLazyBoolYes; 191061da546Spatrick } 192061da546Spatrick 193061da546Spatrick bool File::GetIsRealTerminal() { 194061da546Spatrick if (m_is_real_terminal == eLazyBoolCalculate) 195061da546Spatrick CalculateInteractiveAndTerminal(); 196061da546Spatrick return m_is_real_terminal == eLazyBoolYes; 197061da546Spatrick } 198061da546Spatrick 199061da546Spatrick bool File::GetIsTerminalWithColors() { 200061da546Spatrick if (m_supports_colors == eLazyBoolCalculate) 201061da546Spatrick CalculateInteractiveAndTerminal(); 202061da546Spatrick return m_supports_colors == eLazyBoolYes; 203061da546Spatrick } 204061da546Spatrick 205061da546Spatrick size_t File::Printf(const char *format, ...) { 206061da546Spatrick va_list args; 207061da546Spatrick va_start(args, format); 208061da546Spatrick size_t result = PrintfVarArg(format, args); 209061da546Spatrick va_end(args); 210061da546Spatrick return result; 211061da546Spatrick } 212061da546Spatrick 213061da546Spatrick size_t File::PrintfVarArg(const char *format, va_list args) { 214061da546Spatrick size_t result = 0; 215061da546Spatrick char *s = nullptr; 216061da546Spatrick result = vasprintf(&s, format, args); 217061da546Spatrick if (s != nullptr) { 218061da546Spatrick if (result > 0) { 219061da546Spatrick size_t s_len = result; 220061da546Spatrick Write(s, s_len); 221061da546Spatrick result = s_len; 222061da546Spatrick } 223061da546Spatrick free(s); 224061da546Spatrick } 225061da546Spatrick return result; 226061da546Spatrick } 227061da546Spatrick 228061da546Spatrick Expected<File::OpenOptions> File::GetOptions() const { 229061da546Spatrick return llvm::createStringError( 230061da546Spatrick llvm::inconvertibleErrorCode(), 231061da546Spatrick "GetOptions() not implemented for this File class"); 232061da546Spatrick } 233061da546Spatrick 234061da546Spatrick uint32_t File::GetPermissions(Status &error) const { 235061da546Spatrick int fd = GetDescriptor(); 236061da546Spatrick if (!DescriptorIsValid(fd)) { 237061da546Spatrick error = std::error_code(ENOTSUP, std::system_category()); 238061da546Spatrick return 0; 239061da546Spatrick } 240061da546Spatrick struct stat file_stats; 241061da546Spatrick if (::fstat(fd, &file_stats) == -1) { 242061da546Spatrick error.SetErrorToErrno(); 243061da546Spatrick return 0; 244061da546Spatrick } 245061da546Spatrick error.Clear(); 246061da546Spatrick return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 247061da546Spatrick } 248061da546Spatrick 249061da546Spatrick Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; } 250061da546Spatrick 251061da546Spatrick int NativeFile::GetDescriptor() const { 252061da546Spatrick if (DescriptorIsValid()) 253061da546Spatrick return m_descriptor; 254061da546Spatrick 255061da546Spatrick // Don't open the file descriptor if we don't need to, just get it from the 256061da546Spatrick // stream if we have one. 257061da546Spatrick if (StreamIsValid()) { 258061da546Spatrick #if defined(_WIN32) 259061da546Spatrick return _fileno(m_stream); 260061da546Spatrick #else 261061da546Spatrick return fileno(m_stream); 262061da546Spatrick #endif 263061da546Spatrick } 264061da546Spatrick 265061da546Spatrick // Invalid descriptor and invalid stream, return invalid descriptor. 266061da546Spatrick return kInvalidDescriptor; 267061da546Spatrick } 268061da546Spatrick 269061da546Spatrick IOObject::WaitableHandle NativeFile::GetWaitableHandle() { 270061da546Spatrick return GetDescriptor(); 271061da546Spatrick } 272061da546Spatrick 273061da546Spatrick FILE *NativeFile::GetStream() { 274061da546Spatrick if (!StreamIsValid()) { 275061da546Spatrick if (DescriptorIsValid()) { 276061da546Spatrick auto mode = GetStreamOpenModeFromOptions(m_options); 277061da546Spatrick if (!mode) 278061da546Spatrick llvm::consumeError(mode.takeError()); 279061da546Spatrick else { 280061da546Spatrick if (!m_own_descriptor) { 281061da546Spatrick // We must duplicate the file descriptor if we don't own it because when you 282061da546Spatrick // call fdopen, the stream will own the fd 283061da546Spatrick #ifdef _WIN32 284061da546Spatrick m_descriptor = ::_dup(GetDescriptor()); 285061da546Spatrick #else 286061da546Spatrick m_descriptor = dup(GetDescriptor()); 287061da546Spatrick #endif 288061da546Spatrick m_own_descriptor = true; 289061da546Spatrick } 290061da546Spatrick 291061da546Spatrick m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, 292061da546Spatrick mode.get()); 293061da546Spatrick 294061da546Spatrick // If we got a stream, then we own the stream and should no longer own 295061da546Spatrick // the descriptor because fclose() will close it for us 296061da546Spatrick 297061da546Spatrick if (m_stream) { 298061da546Spatrick m_own_stream = true; 299061da546Spatrick m_own_descriptor = false; 300061da546Spatrick } 301061da546Spatrick } 302061da546Spatrick } 303061da546Spatrick } 304061da546Spatrick return m_stream; 305061da546Spatrick } 306061da546Spatrick 307061da546Spatrick Status NativeFile::Close() { 308061da546Spatrick Status error; 309061da546Spatrick if (StreamIsValid()) { 310061da546Spatrick if (m_own_stream) { 311061da546Spatrick if (::fclose(m_stream) == EOF) 312061da546Spatrick error.SetErrorToErrno(); 313061da546Spatrick } else if (m_options & eOpenOptionWrite) { 314061da546Spatrick if (::fflush(m_stream) == EOF) 315061da546Spatrick error.SetErrorToErrno(); 316061da546Spatrick } 317061da546Spatrick } 318061da546Spatrick if (DescriptorIsValid() && m_own_descriptor) { 319061da546Spatrick if (::close(m_descriptor) != 0) 320061da546Spatrick error.SetErrorToErrno(); 321061da546Spatrick } 322061da546Spatrick m_descriptor = kInvalidDescriptor; 323061da546Spatrick m_stream = kInvalidStream; 324061da546Spatrick m_options = OpenOptions(0); 325061da546Spatrick m_own_stream = false; 326061da546Spatrick m_own_descriptor = false; 327061da546Spatrick m_is_interactive = eLazyBoolCalculate; 328061da546Spatrick m_is_real_terminal = eLazyBoolCalculate; 329061da546Spatrick return error; 330061da546Spatrick } 331061da546Spatrick 332061da546Spatrick Status NativeFile::GetFileSpec(FileSpec &file_spec) const { 333061da546Spatrick Status error; 334061da546Spatrick #ifdef F_GETPATH 335061da546Spatrick if (IsValid()) { 336061da546Spatrick char path[PATH_MAX]; 337061da546Spatrick if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 338061da546Spatrick error.SetErrorToErrno(); 339061da546Spatrick else 340061da546Spatrick file_spec.SetFile(path, FileSpec::Style::native); 341061da546Spatrick } else { 342061da546Spatrick error.SetErrorString("invalid file handle"); 343061da546Spatrick } 344061da546Spatrick #elif defined(__linux__) 345061da546Spatrick char proc[64]; 346061da546Spatrick char path[PATH_MAX]; 347061da546Spatrick if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 348061da546Spatrick error.SetErrorString("cannot resolve file descriptor"); 349061da546Spatrick else { 350061da546Spatrick ssize_t len; 351061da546Spatrick if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 352061da546Spatrick error.SetErrorToErrno(); 353061da546Spatrick else { 354061da546Spatrick path[len] = '\0'; 355061da546Spatrick file_spec.SetFile(path, FileSpec::Style::native); 356061da546Spatrick } 357061da546Spatrick } 358061da546Spatrick #else 359061da546Spatrick error.SetErrorString( 360061da546Spatrick "NativeFile::GetFileSpec is not supported on this platform"); 361061da546Spatrick #endif 362061da546Spatrick 363061da546Spatrick if (error.Fail()) 364061da546Spatrick file_spec.Clear(); 365061da546Spatrick return error; 366061da546Spatrick } 367061da546Spatrick 368061da546Spatrick off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) { 369061da546Spatrick off_t result = 0; 370061da546Spatrick if (DescriptorIsValid()) { 371061da546Spatrick result = ::lseek(m_descriptor, offset, SEEK_SET); 372061da546Spatrick 373061da546Spatrick if (error_ptr) { 374061da546Spatrick if (result == -1) 375061da546Spatrick error_ptr->SetErrorToErrno(); 376061da546Spatrick else 377061da546Spatrick error_ptr->Clear(); 378061da546Spatrick } 379061da546Spatrick } else if (StreamIsValid()) { 380061da546Spatrick result = ::fseek(m_stream, offset, SEEK_SET); 381061da546Spatrick 382061da546Spatrick if (error_ptr) { 383061da546Spatrick if (result == -1) 384061da546Spatrick error_ptr->SetErrorToErrno(); 385061da546Spatrick else 386061da546Spatrick error_ptr->Clear(); 387061da546Spatrick } 388061da546Spatrick } else if (error_ptr) { 389061da546Spatrick error_ptr->SetErrorString("invalid file handle"); 390061da546Spatrick } 391061da546Spatrick return result; 392061da546Spatrick } 393061da546Spatrick 394061da546Spatrick off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) { 395061da546Spatrick off_t result = -1; 396061da546Spatrick if (DescriptorIsValid()) { 397061da546Spatrick result = ::lseek(m_descriptor, offset, SEEK_CUR); 398061da546Spatrick 399061da546Spatrick if (error_ptr) { 400061da546Spatrick if (result == -1) 401061da546Spatrick error_ptr->SetErrorToErrno(); 402061da546Spatrick else 403061da546Spatrick error_ptr->Clear(); 404061da546Spatrick } 405061da546Spatrick } else if (StreamIsValid()) { 406061da546Spatrick result = ::fseek(m_stream, offset, SEEK_CUR); 407061da546Spatrick 408061da546Spatrick if (error_ptr) { 409061da546Spatrick if (result == -1) 410061da546Spatrick error_ptr->SetErrorToErrno(); 411061da546Spatrick else 412061da546Spatrick error_ptr->Clear(); 413061da546Spatrick } 414061da546Spatrick } else if (error_ptr) { 415061da546Spatrick error_ptr->SetErrorString("invalid file handle"); 416061da546Spatrick } 417061da546Spatrick return result; 418061da546Spatrick } 419061da546Spatrick 420061da546Spatrick off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) { 421061da546Spatrick off_t result = -1; 422061da546Spatrick if (DescriptorIsValid()) { 423061da546Spatrick result = ::lseek(m_descriptor, offset, SEEK_END); 424061da546Spatrick 425061da546Spatrick if (error_ptr) { 426061da546Spatrick if (result == -1) 427061da546Spatrick error_ptr->SetErrorToErrno(); 428061da546Spatrick else 429061da546Spatrick error_ptr->Clear(); 430061da546Spatrick } 431061da546Spatrick } else if (StreamIsValid()) { 432061da546Spatrick result = ::fseek(m_stream, offset, SEEK_END); 433061da546Spatrick 434061da546Spatrick if (error_ptr) { 435061da546Spatrick if (result == -1) 436061da546Spatrick error_ptr->SetErrorToErrno(); 437061da546Spatrick else 438061da546Spatrick error_ptr->Clear(); 439061da546Spatrick } 440061da546Spatrick } else if (error_ptr) { 441061da546Spatrick error_ptr->SetErrorString("invalid file handle"); 442061da546Spatrick } 443061da546Spatrick return result; 444061da546Spatrick } 445061da546Spatrick 446061da546Spatrick Status NativeFile::Flush() { 447061da546Spatrick Status error; 448061da546Spatrick if (StreamIsValid()) { 449061da546Spatrick if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) 450061da546Spatrick error.SetErrorToErrno(); 451061da546Spatrick } else if (!DescriptorIsValid()) { 452061da546Spatrick error.SetErrorString("invalid file handle"); 453061da546Spatrick } 454061da546Spatrick return error; 455061da546Spatrick } 456061da546Spatrick 457061da546Spatrick Status NativeFile::Sync() { 458061da546Spatrick Status error; 459061da546Spatrick if (DescriptorIsValid()) { 460061da546Spatrick #ifdef _WIN32 461061da546Spatrick int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 462061da546Spatrick if (err == 0) 463061da546Spatrick error.SetErrorToGenericError(); 464061da546Spatrick #else 465061da546Spatrick if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) 466061da546Spatrick error.SetErrorToErrno(); 467061da546Spatrick #endif 468061da546Spatrick } else { 469061da546Spatrick error.SetErrorString("invalid file handle"); 470061da546Spatrick } 471061da546Spatrick return error; 472061da546Spatrick } 473061da546Spatrick 474061da546Spatrick #if defined(__APPLE__) 475061da546Spatrick // Darwin kernels only can read/write <= INT_MAX bytes 476061da546Spatrick #define MAX_READ_SIZE INT_MAX 477061da546Spatrick #define MAX_WRITE_SIZE INT_MAX 478061da546Spatrick #endif 479061da546Spatrick 480061da546Spatrick Status NativeFile::Read(void *buf, size_t &num_bytes) { 481061da546Spatrick Status error; 482061da546Spatrick 483061da546Spatrick #if defined(MAX_READ_SIZE) 484061da546Spatrick if (num_bytes > MAX_READ_SIZE) { 485061da546Spatrick uint8_t *p = (uint8_t *)buf; 486061da546Spatrick size_t bytes_left = num_bytes; 487061da546Spatrick // Init the num_bytes read to zero 488061da546Spatrick num_bytes = 0; 489061da546Spatrick 490061da546Spatrick while (bytes_left > 0) { 491061da546Spatrick size_t curr_num_bytes; 492061da546Spatrick if (bytes_left > MAX_READ_SIZE) 493061da546Spatrick curr_num_bytes = MAX_READ_SIZE; 494061da546Spatrick else 495061da546Spatrick curr_num_bytes = bytes_left; 496061da546Spatrick 497061da546Spatrick error = Read(p + num_bytes, curr_num_bytes); 498061da546Spatrick 499061da546Spatrick // Update how many bytes were read 500061da546Spatrick num_bytes += curr_num_bytes; 501061da546Spatrick if (bytes_left < curr_num_bytes) 502061da546Spatrick bytes_left = 0; 503061da546Spatrick else 504061da546Spatrick bytes_left -= curr_num_bytes; 505061da546Spatrick 506061da546Spatrick if (error.Fail()) 507061da546Spatrick break; 508061da546Spatrick } 509061da546Spatrick return error; 510061da546Spatrick } 511061da546Spatrick #endif 512061da546Spatrick 513061da546Spatrick ssize_t bytes_read = -1; 514061da546Spatrick if (DescriptorIsValid()) { 515061da546Spatrick bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); 516061da546Spatrick if (bytes_read == -1) { 517061da546Spatrick error.SetErrorToErrno(); 518061da546Spatrick num_bytes = 0; 519061da546Spatrick } else 520061da546Spatrick num_bytes = bytes_read; 521061da546Spatrick } else if (StreamIsValid()) { 522061da546Spatrick bytes_read = ::fread(buf, 1, num_bytes, m_stream); 523061da546Spatrick 524061da546Spatrick if (bytes_read == 0) { 525061da546Spatrick if (::feof(m_stream)) 526061da546Spatrick error.SetErrorString("feof"); 527061da546Spatrick else if (::ferror(m_stream)) 528061da546Spatrick error.SetErrorString("ferror"); 529061da546Spatrick num_bytes = 0; 530061da546Spatrick } else 531061da546Spatrick num_bytes = bytes_read; 532061da546Spatrick } else { 533061da546Spatrick num_bytes = 0; 534061da546Spatrick error.SetErrorString("invalid file handle"); 535061da546Spatrick } 536061da546Spatrick return error; 537061da546Spatrick } 538061da546Spatrick 539061da546Spatrick Status NativeFile::Write(const void *buf, size_t &num_bytes) { 540061da546Spatrick Status error; 541061da546Spatrick 542061da546Spatrick #if defined(MAX_WRITE_SIZE) 543061da546Spatrick if (num_bytes > MAX_WRITE_SIZE) { 544061da546Spatrick const uint8_t *p = (const uint8_t *)buf; 545061da546Spatrick size_t bytes_left = num_bytes; 546061da546Spatrick // Init the num_bytes written to zero 547061da546Spatrick num_bytes = 0; 548061da546Spatrick 549061da546Spatrick while (bytes_left > 0) { 550061da546Spatrick size_t curr_num_bytes; 551061da546Spatrick if (bytes_left > MAX_WRITE_SIZE) 552061da546Spatrick curr_num_bytes = MAX_WRITE_SIZE; 553061da546Spatrick else 554061da546Spatrick curr_num_bytes = bytes_left; 555061da546Spatrick 556061da546Spatrick error = Write(p + num_bytes, curr_num_bytes); 557061da546Spatrick 558061da546Spatrick // Update how many bytes were read 559061da546Spatrick num_bytes += curr_num_bytes; 560061da546Spatrick if (bytes_left < curr_num_bytes) 561061da546Spatrick bytes_left = 0; 562061da546Spatrick else 563061da546Spatrick bytes_left -= curr_num_bytes; 564061da546Spatrick 565061da546Spatrick if (error.Fail()) 566061da546Spatrick break; 567061da546Spatrick } 568061da546Spatrick return error; 569061da546Spatrick } 570061da546Spatrick #endif 571061da546Spatrick 572061da546Spatrick ssize_t bytes_written = -1; 573061da546Spatrick if (DescriptorIsValid()) { 574061da546Spatrick bytes_written = 575061da546Spatrick llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); 576061da546Spatrick if (bytes_written == -1) { 577061da546Spatrick error.SetErrorToErrno(); 578061da546Spatrick num_bytes = 0; 579061da546Spatrick } else 580061da546Spatrick num_bytes = bytes_written; 581061da546Spatrick } else if (StreamIsValid()) { 582061da546Spatrick bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); 583061da546Spatrick 584061da546Spatrick if (bytes_written == 0) { 585061da546Spatrick if (::feof(m_stream)) 586061da546Spatrick error.SetErrorString("feof"); 587061da546Spatrick else if (::ferror(m_stream)) 588061da546Spatrick error.SetErrorString("ferror"); 589061da546Spatrick num_bytes = 0; 590061da546Spatrick } else 591061da546Spatrick num_bytes = bytes_written; 592061da546Spatrick 593061da546Spatrick } else { 594061da546Spatrick num_bytes = 0; 595061da546Spatrick error.SetErrorString("invalid file handle"); 596061da546Spatrick } 597061da546Spatrick 598061da546Spatrick return error; 599061da546Spatrick } 600061da546Spatrick 601061da546Spatrick Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) { 602061da546Spatrick Status error; 603061da546Spatrick 604061da546Spatrick #if defined(MAX_READ_SIZE) 605061da546Spatrick if (num_bytes > MAX_READ_SIZE) { 606061da546Spatrick uint8_t *p = (uint8_t *)buf; 607061da546Spatrick size_t bytes_left = num_bytes; 608061da546Spatrick // Init the num_bytes read to zero 609061da546Spatrick num_bytes = 0; 610061da546Spatrick 611061da546Spatrick while (bytes_left > 0) { 612061da546Spatrick size_t curr_num_bytes; 613061da546Spatrick if (bytes_left > MAX_READ_SIZE) 614061da546Spatrick curr_num_bytes = MAX_READ_SIZE; 615061da546Spatrick else 616061da546Spatrick curr_num_bytes = bytes_left; 617061da546Spatrick 618061da546Spatrick error = Read(p + num_bytes, curr_num_bytes, offset); 619061da546Spatrick 620061da546Spatrick // Update how many bytes were read 621061da546Spatrick num_bytes += curr_num_bytes; 622061da546Spatrick if (bytes_left < curr_num_bytes) 623061da546Spatrick bytes_left = 0; 624061da546Spatrick else 625061da546Spatrick bytes_left -= curr_num_bytes; 626061da546Spatrick 627061da546Spatrick if (error.Fail()) 628061da546Spatrick break; 629061da546Spatrick } 630061da546Spatrick return error; 631061da546Spatrick } 632061da546Spatrick #endif 633061da546Spatrick 634061da546Spatrick #ifndef _WIN32 635061da546Spatrick int fd = GetDescriptor(); 636061da546Spatrick if (fd != kInvalidDescriptor) { 637061da546Spatrick ssize_t bytes_read = 638061da546Spatrick llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); 639061da546Spatrick if (bytes_read < 0) { 640061da546Spatrick num_bytes = 0; 641061da546Spatrick error.SetErrorToErrno(); 642061da546Spatrick } else { 643061da546Spatrick offset += bytes_read; 644061da546Spatrick num_bytes = bytes_read; 645061da546Spatrick } 646061da546Spatrick } else { 647061da546Spatrick num_bytes = 0; 648061da546Spatrick error.SetErrorString("invalid file handle"); 649061da546Spatrick } 650061da546Spatrick #else 651061da546Spatrick std::lock_guard<std::mutex> guard(offset_access_mutex); 652061da546Spatrick long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 653061da546Spatrick SeekFromStart(offset); 654061da546Spatrick error = Read(buf, num_bytes); 655061da546Spatrick if (!error.Fail()) 656061da546Spatrick SeekFromStart(cur); 657061da546Spatrick #endif 658061da546Spatrick return error; 659061da546Spatrick } 660061da546Spatrick 661061da546Spatrick Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) { 662061da546Spatrick Status error; 663061da546Spatrick 664061da546Spatrick #if defined(MAX_WRITE_SIZE) 665061da546Spatrick if (num_bytes > MAX_WRITE_SIZE) { 666061da546Spatrick const uint8_t *p = (const uint8_t *)buf; 667061da546Spatrick size_t bytes_left = num_bytes; 668061da546Spatrick // Init the num_bytes written to zero 669061da546Spatrick num_bytes = 0; 670061da546Spatrick 671061da546Spatrick while (bytes_left > 0) { 672061da546Spatrick size_t curr_num_bytes; 673061da546Spatrick if (bytes_left > MAX_WRITE_SIZE) 674061da546Spatrick curr_num_bytes = MAX_WRITE_SIZE; 675061da546Spatrick else 676061da546Spatrick curr_num_bytes = bytes_left; 677061da546Spatrick 678061da546Spatrick error = Write(p + num_bytes, curr_num_bytes, offset); 679061da546Spatrick 680061da546Spatrick // Update how many bytes were read 681061da546Spatrick num_bytes += curr_num_bytes; 682061da546Spatrick if (bytes_left < curr_num_bytes) 683061da546Spatrick bytes_left = 0; 684061da546Spatrick else 685061da546Spatrick bytes_left -= curr_num_bytes; 686061da546Spatrick 687061da546Spatrick if (error.Fail()) 688061da546Spatrick break; 689061da546Spatrick } 690061da546Spatrick return error; 691061da546Spatrick } 692061da546Spatrick #endif 693061da546Spatrick 694061da546Spatrick int fd = GetDescriptor(); 695061da546Spatrick if (fd != kInvalidDescriptor) { 696061da546Spatrick #ifndef _WIN32 697061da546Spatrick ssize_t bytes_written = 698061da546Spatrick llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); 699061da546Spatrick if (bytes_written < 0) { 700061da546Spatrick num_bytes = 0; 701061da546Spatrick error.SetErrorToErrno(); 702061da546Spatrick } else { 703061da546Spatrick offset += bytes_written; 704061da546Spatrick num_bytes = bytes_written; 705061da546Spatrick } 706061da546Spatrick #else 707061da546Spatrick std::lock_guard<std::mutex> guard(offset_access_mutex); 708061da546Spatrick long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 709061da546Spatrick SeekFromStart(offset); 710061da546Spatrick error = Write(buf, num_bytes); 711061da546Spatrick long after = ::lseek(m_descriptor, 0, SEEK_CUR); 712061da546Spatrick 713061da546Spatrick if (!error.Fail()) 714061da546Spatrick SeekFromStart(cur); 715061da546Spatrick 716061da546Spatrick offset = after; 717061da546Spatrick #endif 718061da546Spatrick } else { 719061da546Spatrick num_bytes = 0; 720061da546Spatrick error.SetErrorString("invalid file handle"); 721061da546Spatrick } 722061da546Spatrick return error; 723061da546Spatrick } 724061da546Spatrick 725061da546Spatrick size_t NativeFile::PrintfVarArg(const char *format, va_list args) { 726061da546Spatrick if (StreamIsValid()) { 727061da546Spatrick return ::vfprintf(m_stream, format, args); 728061da546Spatrick } else { 729061da546Spatrick return File::PrintfVarArg(format, args); 730061da546Spatrick } 731061da546Spatrick } 732061da546Spatrick 733061da546Spatrick mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) { 734061da546Spatrick mode_t mode = 0; 735061da546Spatrick if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) 736061da546Spatrick mode |= O_RDWR; 737061da546Spatrick else if (open_options & eOpenOptionWrite) 738061da546Spatrick mode |= O_WRONLY; 739061da546Spatrick 740061da546Spatrick if (open_options & eOpenOptionAppend) 741061da546Spatrick mode |= O_APPEND; 742061da546Spatrick 743061da546Spatrick if (open_options & eOpenOptionTruncate) 744061da546Spatrick mode |= O_TRUNC; 745061da546Spatrick 746061da546Spatrick if (open_options & eOpenOptionNonBlocking) 747061da546Spatrick mode |= O_NONBLOCK; 748061da546Spatrick 749061da546Spatrick if (open_options & eOpenOptionCanCreateNewOnly) 750061da546Spatrick mode |= O_CREAT | O_EXCL; 751061da546Spatrick else if (open_options & eOpenOptionCanCreate) 752061da546Spatrick mode |= O_CREAT; 753061da546Spatrick 754061da546Spatrick return mode; 755061da546Spatrick } 756061da546Spatrick 757061da546Spatrick char File::ID = 0; 758061da546Spatrick char NativeFile::ID = 0; 759