1258884Semaste//===-- File.cpp ------------------------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9254721Semaste#include "lldb/Host/File.h" 10254721Semaste 11254721Semaste#include <errno.h> 12254721Semaste#include <fcntl.h> 13254721Semaste#include <limits.h> 14254721Semaste#include <stdarg.h> 15262528Semaste#include <stdio.h> 16254721Semaste 17258054Semaste#ifdef _WIN32 18258054Semaste#include "lldb/Host/windows/windows.h" 19262528Semaste#else 20262528Semaste#include <sys/ioctl.h> 21321369Sdim#include <sys/stat.h> 22321369Sdim#include <termios.h> 23321369Sdim#include <unistd.h> 24258054Semaste#endif 25258054Semaste 26309124Sdim#include "llvm/Support/ConvertUTF.h" 27321369Sdim#include "llvm/Support/Errno.h" 28321369Sdim#include "llvm/Support/FileSystem.h" 29344779Sdim#include "llvm/Support/Process.h" 30296417Sdim 31254721Semaste#include "lldb/Host/Config.h" 32344779Sdim#include "lldb/Host/FileSystem.h" 33321369Sdim#include "lldb/Host/Host.h" 34321369Sdim#include "lldb/Utility/DataBufferHeap.h" 35321369Sdim#include "lldb/Utility/FileSpec.h" 36321369Sdim#include "lldb/Utility/Log.h" 37254721Semaste 38254721Semasteusing namespace lldb; 39254721Semasteusing namespace lldb_private; 40360784Sdimusing llvm::Expected; 41254721Semaste 42360784SdimExpected<const char *> 43360784SdimFile::GetStreamOpenModeFromOptions(File::OpenOptions options) { 44314564Sdim if (options & File::eOpenOptionAppend) { 45314564Sdim if (options & File::eOpenOptionRead) { 46314564Sdim if (options & File::eOpenOptionCanCreateNewOnly) 47314564Sdim return "a+x"; 48314564Sdim else 49314564Sdim return "a+"; 50314564Sdim } else if (options & File::eOpenOptionWrite) { 51314564Sdim if (options & File::eOpenOptionCanCreateNewOnly) 52314564Sdim return "ax"; 53314564Sdim else 54314564Sdim return "a"; 55254721Semaste } 56314564Sdim } else if (options & File::eOpenOptionRead && 57314564Sdim options & File::eOpenOptionWrite) { 58314564Sdim if (options & File::eOpenOptionCanCreate) { 59314564Sdim if (options & File::eOpenOptionCanCreateNewOnly) 60314564Sdim return "w+x"; 61314564Sdim else 62314564Sdim return "w+"; 63314564Sdim } else 64314564Sdim return "r+"; 65314564Sdim } else if (options & File::eOpenOptionRead) { 66314564Sdim return "r"; 67314564Sdim } else if (options & File::eOpenOptionWrite) { 68314564Sdim return "w"; 69314564Sdim } 70360784Sdim return llvm::createStringError( 71360784Sdim llvm::inconvertibleErrorCode(), 72360784Sdim "invalid options, cannot convert to mode string"); 73254721Semaste} 74254721Semaste 75360784SdimExpected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { 76360784Sdim OpenOptions opts = 77360784Sdim llvm::StringSwitch<OpenOptions>(mode) 78360784Sdim .Cases("r", "rb", eOpenOptionRead) 79360784Sdim .Cases("w", "wb", eOpenOptionWrite) 80360784Sdim .Cases("a", "ab", 81360784Sdim eOpenOptionWrite | eOpenOptionAppend | eOpenOptionCanCreate) 82360784Sdim .Cases("r+", "rb+", "r+b", eOpenOptionRead | eOpenOptionWrite) 83360784Sdim .Cases("w+", "wb+", "w+b", 84360784Sdim eOpenOptionRead | eOpenOptionWrite | eOpenOptionCanCreate | 85360784Sdim eOpenOptionTruncate) 86360784Sdim .Cases("a+", "ab+", "a+b", 87360784Sdim eOpenOptionRead | eOpenOptionWrite | eOpenOptionAppend | 88360784Sdim eOpenOptionCanCreate) 89360784Sdim .Default(OpenOptions()); 90360784Sdim if (opts) 91360784Sdim return opts; 92360784Sdim return llvm::createStringError( 93360784Sdim llvm::inconvertibleErrorCode(), 94360784Sdim "invalid mode, cannot convert to File::OpenOptions"); 95360784Sdim} 96360784Sdim 97254721Semasteint File::kInvalidDescriptor = -1; 98353358SdimFILE *File::kInvalidStream = nullptr; 99254721Semaste 100360784SdimStatus File::Read(void *buf, size_t &num_bytes) { 101360784Sdim return std::error_code(ENOTSUP, std::system_category()); 102360784Sdim} 103360784SdimStatus File::Write(const void *buf, size_t &num_bytes) { 104360784Sdim return std::error_code(ENOTSUP, std::system_category()); 105360784Sdim} 106254721Semaste 107360784Sdimbool File::IsValid() const { return false; } 108360784Sdim 109360784SdimStatus File::Close() { return Flush(); } 110360784Sdim 111360784SdimIOObject::WaitableHandle File::GetWaitableHandle() { 112360784Sdim return IOObject::kInvalidHandleValue; 113360784Sdim} 114360784Sdim 115360784SdimStatus File::GetFileSpec(FileSpec &file_spec) const { 116360784Sdim file_spec.Clear(); 117360784Sdim return std::error_code(ENOTSUP, std::system_category()); 118360784Sdim} 119360784Sdim 120360784Sdimint File::GetDescriptor() const { return kInvalidDescriptor; } 121360784Sdim 122360784SdimFILE *File::GetStream() { return nullptr; } 123360784Sdim 124360784Sdimoff_t File::SeekFromStart(off_t offset, Status *error_ptr) { 125360784Sdim if (error_ptr) 126360784Sdim *error_ptr = std::error_code(ENOTSUP, std::system_category()); 127360784Sdim return -1; 128360784Sdim} 129360784Sdim 130360784Sdimoff_t File::SeekFromCurrent(off_t offset, Status *error_ptr) { 131360784Sdim if (error_ptr) 132360784Sdim *error_ptr = std::error_code(ENOTSUP, std::system_category()); 133360784Sdim return -1; 134360784Sdim} 135360784Sdim 136360784Sdimoff_t File::SeekFromEnd(off_t offset, Status *error_ptr) { 137360784Sdim if (error_ptr) 138360784Sdim *error_ptr = std::error_code(ENOTSUP, std::system_category()); 139360784Sdim return -1; 140360784Sdim} 141360784Sdim 142360784SdimStatus File::Read(void *dst, size_t &num_bytes, off_t &offset) { 143360784Sdim return std::error_code(ENOTSUP, std::system_category()); 144360784Sdim} 145360784Sdim 146360784SdimStatus File::Write(const void *src, size_t &num_bytes, off_t &offset) { 147360784Sdim return std::error_code(ENOTSUP, std::system_category()); 148360784Sdim} 149360784Sdim 150360784SdimStatus File::Flush() { return Status(); } 151360784Sdim 152360784SdimStatus File::Sync() { return Flush(); } 153360784Sdim 154360784Sdimvoid File::CalculateInteractiveAndTerminal() { 155360784Sdim const int fd = GetDescriptor(); 156360784Sdim if (!DescriptorIsValid(fd)) { 157360784Sdim m_is_interactive = eLazyBoolNo; 158360784Sdim m_is_real_terminal = eLazyBoolNo; 159360784Sdim m_supports_colors = eLazyBoolNo; 160360784Sdim return; 161360784Sdim } 162360784Sdim m_is_interactive = eLazyBoolNo; 163360784Sdim m_is_real_terminal = eLazyBoolNo; 164360784Sdim#if defined(_WIN32) 165360784Sdim if (_isatty(fd)) { 166360784Sdim m_is_interactive = eLazyBoolYes; 167360784Sdim m_is_real_terminal = eLazyBoolYes; 168360784Sdim#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 169360784Sdim m_supports_colors = eLazyBoolYes; 170360784Sdim#endif 171360784Sdim } 172360784Sdim#else 173360784Sdim if (isatty(fd)) { 174360784Sdim m_is_interactive = eLazyBoolYes; 175360784Sdim struct winsize window_size; 176360784Sdim if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { 177360784Sdim if (window_size.ws_col > 0) { 178360784Sdim m_is_real_terminal = eLazyBoolYes; 179360784Sdim if (llvm::sys::Process::FileDescriptorHasColors(fd)) 180360784Sdim m_supports_colors = eLazyBoolYes; 181360784Sdim } 182360784Sdim } 183360784Sdim } 184360784Sdim#endif 185360784Sdim} 186360784Sdim 187360784Sdimbool File::GetIsInteractive() { 188360784Sdim if (m_is_interactive == eLazyBoolCalculate) 189360784Sdim CalculateInteractiveAndTerminal(); 190360784Sdim return m_is_interactive == eLazyBoolYes; 191360784Sdim} 192360784Sdim 193360784Sdimbool File::GetIsRealTerminal() { 194360784Sdim if (m_is_real_terminal == eLazyBoolCalculate) 195360784Sdim CalculateInteractiveAndTerminal(); 196360784Sdim return m_is_real_terminal == eLazyBoolYes; 197360784Sdim} 198360784Sdim 199360784Sdimbool File::GetIsTerminalWithColors() { 200360784Sdim if (m_supports_colors == eLazyBoolCalculate) 201360784Sdim CalculateInteractiveAndTerminal(); 202360784Sdim return m_supports_colors == eLazyBoolYes; 203360784Sdim} 204360784Sdim 205360784Sdimsize_t File::Printf(const char *format, ...) { 206360784Sdim va_list args; 207360784Sdim va_start(args, format); 208360784Sdim size_t result = PrintfVarArg(format, args); 209360784Sdim va_end(args); 210360784Sdim return result; 211360784Sdim} 212360784Sdim 213360784Sdimsize_t File::PrintfVarArg(const char *format, va_list args) { 214360784Sdim size_t result = 0; 215360784Sdim char *s = nullptr; 216360784Sdim result = vasprintf(&s, format, args); 217360784Sdim if (s != nullptr) { 218360784Sdim if (result > 0) { 219360784Sdim size_t s_len = result; 220360784Sdim Write(s, s_len); 221360784Sdim result = s_len; 222360784Sdim } 223360784Sdim free(s); 224360784Sdim } 225360784Sdim return result; 226360784Sdim} 227360784Sdim 228360784SdimExpected<File::OpenOptions> File::GetOptions() const { 229360784Sdim return llvm::createStringError( 230360784Sdim llvm::inconvertibleErrorCode(), 231360784Sdim "GetOptions() not implemented for this File class"); 232360784Sdim} 233360784Sdim 234360784Sdimuint32_t File::GetPermissions(Status &error) const { 235360784Sdim int fd = GetDescriptor(); 236360784Sdim if (!DescriptorIsValid(fd)) { 237360784Sdim error = std::error_code(ENOTSUP, std::system_category()); 238360784Sdim return 0; 239360784Sdim } 240360784Sdim struct stat file_stats; 241360784Sdim if (::fstat(fd, &file_stats) == -1) { 242360784Sdim error.SetErrorToErrno(); 243360784Sdim return 0; 244360784Sdim } 245360784Sdim error.Clear(); 246360784Sdim return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 247360784Sdim} 248360784Sdim 249360784SdimExpected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; } 250360784Sdim 251360784Sdimint NativeFile::GetDescriptor() const { 252314564Sdim if (DescriptorIsValid()) 253314564Sdim return m_descriptor; 254254721Semaste 255314564Sdim // Don't open the file descriptor if we don't need to, just get it from the 256314564Sdim // stream if we have one. 257314564Sdim if (StreamIsValid()) { 258341825Sdim#if defined(_WIN32) 259314564Sdim return _fileno(m_stream); 260296417Sdim#else 261314564Sdim return fileno(m_stream); 262296417Sdim#endif 263314564Sdim } 264254721Semaste 265314564Sdim // Invalid descriptor and invalid stream, return invalid descriptor. 266314564Sdim return kInvalidDescriptor; 267254721Semaste} 268254721Semaste 269360784SdimIOObject::WaitableHandle NativeFile::GetWaitableHandle() { 270360784Sdim return GetDescriptor(); 271254721Semaste} 272254721Semaste 273360784SdimFILE *NativeFile::GetStream() { 274314564Sdim if (!StreamIsValid()) { 275314564Sdim if (DescriptorIsValid()) { 276360784Sdim auto mode = GetStreamOpenModeFromOptions(m_options); 277360784Sdim if (!mode) 278360784Sdim llvm::consumeError(mode.takeError()); 279360784Sdim else { 280360784Sdim if (!m_own_descriptor) { 281341825Sdim// We must duplicate the file descriptor if we don't own it because when you 282341825Sdim// call fdopen, the stream will own the fd 283262528Semaste#ifdef _WIN32 284314564Sdim m_descriptor = ::_dup(GetDescriptor()); 285262528Semaste#else 286314564Sdim m_descriptor = dup(GetDescriptor()); 287262528Semaste#endif 288360784Sdim m_own_descriptor = true; 289314564Sdim } 290262528Semaste 291360784Sdim m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, 292360784Sdim mode.get()); 293262528Semaste 294341825Sdim // If we got a stream, then we own the stream and should no longer own 295341825Sdim // the descriptor because fclose() will close it for us 296262528Semaste 297314564Sdim if (m_stream) { 298314564Sdim m_own_stream = true; 299360784Sdim m_own_descriptor = false; 300254721Semaste } 301314564Sdim } 302254721Semaste } 303314564Sdim } 304314564Sdim return m_stream; 305254721Semaste} 306254721Semaste 307360784SdimStatus NativeFile::Close() { 308360784Sdim Status error; 309360784Sdim if (StreamIsValid()) { 310360784Sdim if (m_own_stream) { 311360784Sdim if (::fclose(m_stream) == EOF) 312360784Sdim error.SetErrorToErrno(); 313360784Sdim } else if (m_options & eOpenOptionWrite) { 314360784Sdim if (::fflush(m_stream) == EOF) 315360784Sdim error.SetErrorToErrno(); 316258054Semaste } 317314564Sdim } 318360784Sdim if (DescriptorIsValid() && m_own_descriptor) { 319314564Sdim if (::close(m_descriptor) != 0) 320314564Sdim error.SetErrorToErrno(); 321314564Sdim } 322314564Sdim m_descriptor = kInvalidDescriptor; 323314564Sdim m_stream = kInvalidStream; 324360784Sdim m_options = OpenOptions(0); 325314564Sdim m_own_stream = false; 326360784Sdim m_own_descriptor = false; 327314564Sdim m_is_interactive = eLazyBoolCalculate; 328314564Sdim m_is_real_terminal = eLazyBoolCalculate; 329314564Sdim return error; 330254721Semaste} 331254721Semaste 332360784SdimStatus NativeFile::GetFileSpec(FileSpec &file_spec) const { 333321369Sdim Status error; 334321369Sdim#ifdef F_GETPATH 335314564Sdim if (IsValid()) { 336254721Semaste char path[PATH_MAX]; 337314564Sdim if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 338314564Sdim error.SetErrorToErrno(); 339254721Semaste else 340344779Sdim file_spec.SetFile(path, FileSpec::Style::native); 341314564Sdim } else { 342314564Sdim error.SetErrorString("invalid file handle"); 343314564Sdim } 344314564Sdim#elif defined(__linux__) 345314564Sdim char proc[64]; 346314564Sdim char path[PATH_MAX]; 347314564Sdim if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 348314564Sdim error.SetErrorString("cannot resolve file descriptor"); 349314564Sdim else { 350314564Sdim ssize_t len; 351314564Sdim if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 352314564Sdim error.SetErrorToErrno(); 353314564Sdim else { 354314564Sdim path[len] = '\0'; 355344779Sdim file_spec.SetFile(path, FileSpec::Style::native); 356254721Semaste } 357314564Sdim } 358254721Semaste#else 359360784Sdim error.SetErrorString( 360360784Sdim "NativeFile::GetFileSpec is not supported on this platform"); 361254721Semaste#endif 362254721Semaste 363314564Sdim if (error.Fail()) 364314564Sdim file_spec.Clear(); 365314564Sdim return error; 366254721Semaste} 367254721Semaste 368360784Sdimoff_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) { 369314564Sdim off_t result = 0; 370314564Sdim if (DescriptorIsValid()) { 371314564Sdim result = ::lseek(m_descriptor, offset, SEEK_SET); 372254721Semaste 373314564Sdim if (error_ptr) { 374314564Sdim if (result == -1) 375314564Sdim error_ptr->SetErrorToErrno(); 376314564Sdim else 377314564Sdim error_ptr->Clear(); 378254721Semaste } 379314564Sdim } else if (StreamIsValid()) { 380314564Sdim result = ::fseek(m_stream, offset, SEEK_SET); 381314564Sdim 382314564Sdim if (error_ptr) { 383314564Sdim if (result == -1) 384314564Sdim error_ptr->SetErrorToErrno(); 385314564Sdim else 386314564Sdim error_ptr->Clear(); 387254721Semaste } 388314564Sdim } else if (error_ptr) { 389314564Sdim error_ptr->SetErrorString("invalid file handle"); 390314564Sdim } 391314564Sdim return result; 392254721Semaste} 393254721Semaste 394360784Sdimoff_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) { 395314564Sdim off_t result = -1; 396314564Sdim if (DescriptorIsValid()) { 397314564Sdim result = ::lseek(m_descriptor, offset, SEEK_CUR); 398314564Sdim 399314564Sdim if (error_ptr) { 400314564Sdim if (result == -1) 401314564Sdim error_ptr->SetErrorToErrno(); 402314564Sdim else 403314564Sdim error_ptr->Clear(); 404254721Semaste } 405314564Sdim } else if (StreamIsValid()) { 406314564Sdim result = ::fseek(m_stream, offset, SEEK_CUR); 407314564Sdim 408314564Sdim if (error_ptr) { 409314564Sdim if (result == -1) 410314564Sdim error_ptr->SetErrorToErrno(); 411314564Sdim else 412314564Sdim error_ptr->Clear(); 413254721Semaste } 414314564Sdim } else if (error_ptr) { 415314564Sdim error_ptr->SetErrorString("invalid file handle"); 416314564Sdim } 417314564Sdim return result; 418254721Semaste} 419254721Semaste 420360784Sdimoff_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) { 421314564Sdim off_t result = -1; 422314564Sdim if (DescriptorIsValid()) { 423314564Sdim result = ::lseek(m_descriptor, offset, SEEK_END); 424314564Sdim 425314564Sdim if (error_ptr) { 426314564Sdim if (result == -1) 427314564Sdim error_ptr->SetErrorToErrno(); 428314564Sdim else 429314564Sdim error_ptr->Clear(); 430254721Semaste } 431314564Sdim } else if (StreamIsValid()) { 432314564Sdim result = ::fseek(m_stream, offset, SEEK_END); 433314564Sdim 434314564Sdim if (error_ptr) { 435314564Sdim if (result == -1) 436314564Sdim error_ptr->SetErrorToErrno(); 437314564Sdim else 438314564Sdim error_ptr->Clear(); 439254721Semaste } 440314564Sdim } else if (error_ptr) { 441314564Sdim error_ptr->SetErrorString("invalid file handle"); 442314564Sdim } 443314564Sdim return result; 444254721Semaste} 445254721Semaste 446360784SdimStatus NativeFile::Flush() { 447321369Sdim Status error; 448314564Sdim if (StreamIsValid()) { 449321369Sdim if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) 450314564Sdim error.SetErrorToErrno(); 451314564Sdim } else if (!DescriptorIsValid()) { 452314564Sdim error.SetErrorString("invalid file handle"); 453314564Sdim } 454314564Sdim return error; 455254721Semaste} 456254721Semaste 457360784SdimStatus NativeFile::Sync() { 458321369Sdim Status error; 459314564Sdim if (DescriptorIsValid()) { 460258054Semaste#ifdef _WIN32 461314564Sdim int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 462314564Sdim if (err == 0) 463314564Sdim error.SetErrorToGenericError(); 464258054Semaste#else 465321369Sdim if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) 466314564Sdim error.SetErrorToErrno(); 467258054Semaste#endif 468314564Sdim } else { 469314564Sdim error.SetErrorString("invalid file handle"); 470314564Sdim } 471314564Sdim return error; 472254721Semaste} 473254721Semaste 474314564Sdim#if defined(__APPLE__) 475288943Sdim// Darwin kernels only can read/write <= INT_MAX bytes 476288943Sdim#define MAX_READ_SIZE INT_MAX 477288943Sdim#define MAX_WRITE_SIZE INT_MAX 478288943Sdim#endif 479288943Sdim 480360784SdimStatus NativeFile::Read(void *buf, size_t &num_bytes) { 481321369Sdim Status error; 482288943Sdim 483314564Sdim#if defined(MAX_READ_SIZE) 484314564Sdim if (num_bytes > MAX_READ_SIZE) { 485314564Sdim uint8_t *p = (uint8_t *)buf; 486314564Sdim size_t bytes_left = num_bytes; 487314564Sdim // Init the num_bytes read to zero 488314564Sdim num_bytes = 0; 489288943Sdim 490314564Sdim while (bytes_left > 0) { 491314564Sdim size_t curr_num_bytes; 492314564Sdim if (bytes_left > MAX_READ_SIZE) 493314564Sdim curr_num_bytes = MAX_READ_SIZE; 494314564Sdim else 495314564Sdim curr_num_bytes = bytes_left; 496288943Sdim 497314564Sdim error = Read(p + num_bytes, curr_num_bytes); 498288943Sdim 499314564Sdim // Update how many bytes were read 500314564Sdim num_bytes += curr_num_bytes; 501314564Sdim if (bytes_left < curr_num_bytes) 502314564Sdim bytes_left = 0; 503314564Sdim else 504314564Sdim bytes_left -= curr_num_bytes; 505288943Sdim 506314564Sdim if (error.Fail()) 507314564Sdim break; 508288943Sdim } 509314564Sdim return error; 510314564Sdim } 511288943Sdim#endif 512288943Sdim 513314564Sdim ssize_t bytes_read = -1; 514314564Sdim if (DescriptorIsValid()) { 515321369Sdim bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); 516314564Sdim if (bytes_read == -1) { 517314564Sdim error.SetErrorToErrno(); 518314564Sdim num_bytes = 0; 519314564Sdim } else 520314564Sdim num_bytes = bytes_read; 521314564Sdim } else if (StreamIsValid()) { 522314564Sdim bytes_read = ::fread(buf, 1, num_bytes, m_stream); 523254721Semaste 524314564Sdim if (bytes_read == 0) { 525314564Sdim if (::feof(m_stream)) 526314564Sdim error.SetErrorString("feof"); 527314564Sdim else if (::ferror(m_stream)) 528314564Sdim error.SetErrorString("ferror"); 529314564Sdim num_bytes = 0; 530314564Sdim } else 531314564Sdim num_bytes = bytes_read; 532314564Sdim } else { 533314564Sdim num_bytes = 0; 534314564Sdim error.SetErrorString("invalid file handle"); 535314564Sdim } 536314564Sdim return error; 537254721Semaste} 538288943Sdim 539360784SdimStatus NativeFile::Write(const void *buf, size_t &num_bytes) { 540321369Sdim Status error; 541288943Sdim 542314564Sdim#if defined(MAX_WRITE_SIZE) 543314564Sdim if (num_bytes > MAX_WRITE_SIZE) { 544314564Sdim const uint8_t *p = (const uint8_t *)buf; 545314564Sdim size_t bytes_left = num_bytes; 546314564Sdim // Init the num_bytes written to zero 547314564Sdim num_bytes = 0; 548288943Sdim 549314564Sdim while (bytes_left > 0) { 550314564Sdim size_t curr_num_bytes; 551314564Sdim if (bytes_left > MAX_WRITE_SIZE) 552314564Sdim curr_num_bytes = MAX_WRITE_SIZE; 553314564Sdim else 554314564Sdim curr_num_bytes = bytes_left; 555288943Sdim 556314564Sdim error = Write(p + num_bytes, curr_num_bytes); 557288943Sdim 558314564Sdim // Update how many bytes were read 559314564Sdim num_bytes += curr_num_bytes; 560314564Sdim if (bytes_left < curr_num_bytes) 561314564Sdim bytes_left = 0; 562314564Sdim else 563314564Sdim bytes_left -= curr_num_bytes; 564314564Sdim 565314564Sdim if (error.Fail()) 566314564Sdim break; 567288943Sdim } 568314564Sdim return error; 569314564Sdim } 570288943Sdim#endif 571288943Sdim 572314564Sdim ssize_t bytes_written = -1; 573314564Sdim if (DescriptorIsValid()) { 574321369Sdim bytes_written = 575321369Sdim llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); 576314564Sdim if (bytes_written == -1) { 577314564Sdim error.SetErrorToErrno(); 578314564Sdim num_bytes = 0; 579314564Sdim } else 580314564Sdim num_bytes = bytes_written; 581314564Sdim } else if (StreamIsValid()) { 582314564Sdim bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); 583254721Semaste 584314564Sdim if (bytes_written == 0) { 585314564Sdim if (::feof(m_stream)) 586314564Sdim error.SetErrorString("feof"); 587314564Sdim else if (::ferror(m_stream)) 588314564Sdim error.SetErrorString("ferror"); 589314564Sdim num_bytes = 0; 590314564Sdim } else 591314564Sdim num_bytes = bytes_written; 592276479Sdim 593314564Sdim } else { 594314564Sdim num_bytes = 0; 595314564Sdim error.SetErrorString("invalid file handle"); 596314564Sdim } 597314564Sdim 598314564Sdim return error; 599254721Semaste} 600254721Semaste 601360784SdimStatus NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) { 602321369Sdim Status error; 603254721Semaste 604314564Sdim#if defined(MAX_READ_SIZE) 605314564Sdim if (num_bytes > MAX_READ_SIZE) { 606314564Sdim uint8_t *p = (uint8_t *)buf; 607314564Sdim size_t bytes_left = num_bytes; 608314564Sdim // Init the num_bytes read to zero 609314564Sdim num_bytes = 0; 610288943Sdim 611314564Sdim while (bytes_left > 0) { 612314564Sdim size_t curr_num_bytes; 613314564Sdim if (bytes_left > MAX_READ_SIZE) 614314564Sdim curr_num_bytes = MAX_READ_SIZE; 615314564Sdim else 616314564Sdim curr_num_bytes = bytes_left; 617288943Sdim 618314564Sdim error = Read(p + num_bytes, curr_num_bytes, offset); 619288943Sdim 620314564Sdim // Update how many bytes were read 621314564Sdim num_bytes += curr_num_bytes; 622314564Sdim if (bytes_left < curr_num_bytes) 623314564Sdim bytes_left = 0; 624314564Sdim else 625314564Sdim bytes_left -= curr_num_bytes; 626288943Sdim 627314564Sdim if (error.Fail()) 628314564Sdim break; 629288943Sdim } 630314564Sdim return error; 631314564Sdim } 632288943Sdim#endif 633288943Sdim 634258054Semaste#ifndef _WIN32 635314564Sdim int fd = GetDescriptor(); 636314564Sdim if (fd != kInvalidDescriptor) { 637321369Sdim ssize_t bytes_read = 638321369Sdim llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); 639314564Sdim if (bytes_read < 0) { 640314564Sdim num_bytes = 0; 641314564Sdim error.SetErrorToErrno(); 642314564Sdim } else { 643314564Sdim offset += bytes_read; 644314564Sdim num_bytes = bytes_read; 645254721Semaste } 646314564Sdim } else { 647314564Sdim num_bytes = 0; 648314564Sdim error.SetErrorString("invalid file handle"); 649314564Sdim } 650258054Semaste#else 651353358Sdim std::lock_guard<std::mutex> guard(offset_access_mutex); 652314564Sdim long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 653314564Sdim SeekFromStart(offset); 654314564Sdim error = Read(buf, num_bytes); 655314564Sdim if (!error.Fail()) 656314564Sdim SeekFromStart(cur); 657288943Sdim#endif 658314564Sdim return error; 659254721Semaste} 660254721Semaste 661360784SdimStatus NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) { 662321369Sdim Status error; 663314564Sdim 664314564Sdim#if defined(MAX_WRITE_SIZE) 665314564Sdim if (num_bytes > MAX_WRITE_SIZE) { 666314564Sdim const uint8_t *p = (const uint8_t *)buf; 667314564Sdim size_t bytes_left = num_bytes; 668314564Sdim // Init the num_bytes written to zero 669314564Sdim num_bytes = 0; 670288943Sdim 671314564Sdim while (bytes_left > 0) { 672314564Sdim size_t curr_num_bytes; 673314564Sdim if (bytes_left > MAX_WRITE_SIZE) 674314564Sdim curr_num_bytes = MAX_WRITE_SIZE; 675314564Sdim else 676314564Sdim curr_num_bytes = bytes_left; 677288943Sdim 678314564Sdim error = Write(p + num_bytes, curr_num_bytes, offset); 679288943Sdim 680314564Sdim // Update how many bytes were read 681314564Sdim num_bytes += curr_num_bytes; 682314564Sdim if (bytes_left < curr_num_bytes) 683314564Sdim bytes_left = 0; 684314564Sdim else 685314564Sdim bytes_left -= curr_num_bytes; 686288943Sdim 687314564Sdim if (error.Fail()) 688314564Sdim break; 689288943Sdim } 690314564Sdim return error; 691314564Sdim } 692288943Sdim#endif 693288943Sdim 694314564Sdim int fd = GetDescriptor(); 695314564Sdim if (fd != kInvalidDescriptor) { 696258054Semaste#ifndef _WIN32 697321369Sdim ssize_t bytes_written = 698321369Sdim llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); 699314564Sdim if (bytes_written < 0) { 700314564Sdim num_bytes = 0; 701314564Sdim error.SetErrorToErrno(); 702314564Sdim } else { 703314564Sdim offset += bytes_written; 704314564Sdim num_bytes = bytes_written; 705314564Sdim } 706258054Semaste#else 707353358Sdim std::lock_guard<std::mutex> guard(offset_access_mutex); 708314564Sdim long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 709353358Sdim SeekFromStart(offset); 710314564Sdim error = Write(buf, num_bytes); 711314564Sdim long after = ::lseek(m_descriptor, 0, SEEK_CUR); 712258054Semaste 713314564Sdim if (!error.Fail()) 714314564Sdim SeekFromStart(cur); 715258054Semaste 716314564Sdim offset = after; 717258054Semaste#endif 718314564Sdim } else { 719314564Sdim num_bytes = 0; 720314564Sdim error.SetErrorString("invalid file handle"); 721314564Sdim } 722314564Sdim return error; 723254721Semaste} 724254721Semaste 725360784Sdimsize_t NativeFile::PrintfVarArg(const char *format, va_list args) { 726360784Sdim if (StreamIsValid()) { 727360784Sdim return ::vfprintf(m_stream, format, args); 728360784Sdim } else { 729360784Sdim return File::PrintfVarArg(format, args); 730314564Sdim } 731254721Semaste} 732258054Semaste 733360784Sdimmode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) { 734314564Sdim mode_t mode = 0; 735314564Sdim if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) 736314564Sdim mode |= O_RDWR; 737314564Sdim else if (open_options & eOpenOptionWrite) 738314564Sdim mode |= O_WRONLY; 739258054Semaste 740314564Sdim if (open_options & eOpenOptionAppend) 741314564Sdim mode |= O_APPEND; 742258054Semaste 743314564Sdim if (open_options & eOpenOptionTruncate) 744314564Sdim mode |= O_TRUNC; 745258054Semaste 746314564Sdim if (open_options & eOpenOptionNonBlocking) 747314564Sdim mode |= O_NONBLOCK; 748258054Semaste 749314564Sdim if (open_options & eOpenOptionCanCreateNewOnly) 750314564Sdim mode |= O_CREAT | O_EXCL; 751314564Sdim else if (open_options & eOpenOptionCanCreate) 752314564Sdim mode |= O_CREAT; 753314564Sdim 754314564Sdim return mode; 755258054Semaste} 756262528Semaste 757360784Sdimchar File::ID = 0; 758360784Sdimchar NativeFile::ID = 0; 759