xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/common/File.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===-- File.cpp ----------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Host/File.h"
100b57cec5SDimitry Andric 
11fe6060f1SDimitry Andric #include <cerrno>
12fe6060f1SDimitry Andric #include <climits>
13fe6060f1SDimitry Andric #include <cstdarg>
14fe6060f1SDimitry Andric #include <cstdio>
150b57cec5SDimitry Andric #include <fcntl.h>
16bdd1243dSDimitry Andric #include <optional>
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #ifdef _WIN32
190b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h"
200b57cec5SDimitry Andric #else
210b57cec5SDimitry Andric #include <sys/ioctl.h>
220b57cec5SDimitry Andric #include <sys/stat.h>
230b57cec5SDimitry Andric #include <termios.h>
240b57cec5SDimitry Andric #include <unistd.h>
250b57cec5SDimitry Andric #endif
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #include "lldb/Host/Config.h"
280b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
290b57cec5SDimitry Andric #include "lldb/Host/Host.h"
300b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
310b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
320b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
3381ad6265SDimitry Andric #include "lldb/Utility/VASPrintf.h"
3406c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
3581ad6265SDimitry Andric #include "llvm/Support/ConvertUTF.h"
3681ad6265SDimitry Andric #include "llvm/Support/Errno.h"
3781ad6265SDimitry Andric #include "llvm/Support/FileSystem.h"
3881ad6265SDimitry Andric #include "llvm/Support/Process.h"
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric using namespace lldb;
410b57cec5SDimitry Andric using namespace lldb_private;
429dba64beSDimitry Andric using llvm::Expected;
430b57cec5SDimitry Andric 
449dba64beSDimitry Andric Expected<const char *>
GetStreamOpenModeFromOptions(File::OpenOptions options)459dba64beSDimitry Andric File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
46349cc55cSDimitry Andric   File::OpenOptions rw =
47349cc55cSDimitry Andric       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
48349cc55cSDimitry Andric                  File::eOpenOptionReadWrite);
49349cc55cSDimitry Andric 
500b57cec5SDimitry Andric   if (options & File::eOpenOptionAppend) {
51349cc55cSDimitry Andric     if (rw == File::eOpenOptionReadWrite) {
520b57cec5SDimitry Andric       if (options & File::eOpenOptionCanCreateNewOnly)
530b57cec5SDimitry Andric         return "a+x";
540b57cec5SDimitry Andric       else
550b57cec5SDimitry Andric         return "a+";
56349cc55cSDimitry Andric     } else if (rw == File::eOpenOptionWriteOnly) {
570b57cec5SDimitry Andric       if (options & File::eOpenOptionCanCreateNewOnly)
580b57cec5SDimitry Andric         return "ax";
590b57cec5SDimitry Andric       else
600b57cec5SDimitry Andric         return "a";
610b57cec5SDimitry Andric     }
62349cc55cSDimitry Andric   } else if (rw == File::eOpenOptionReadWrite) {
630b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreate) {
640b57cec5SDimitry Andric       if (options & File::eOpenOptionCanCreateNewOnly)
650b57cec5SDimitry Andric         return "w+x";
660b57cec5SDimitry Andric       else
670b57cec5SDimitry Andric         return "w+";
680b57cec5SDimitry Andric     } else
690b57cec5SDimitry Andric       return "r+";
70349cc55cSDimitry Andric   } else if (rw == File::eOpenOptionWriteOnly) {
710b57cec5SDimitry Andric     return "w";
72349cc55cSDimitry Andric   } else if (rw == File::eOpenOptionReadOnly) {
73349cc55cSDimitry Andric     return "r";
740b57cec5SDimitry Andric   }
759dba64beSDimitry Andric   return llvm::createStringError(
769dba64beSDimitry Andric       llvm::inconvertibleErrorCode(),
779dba64beSDimitry Andric       "invalid options, cannot convert to mode string");
789dba64beSDimitry Andric }
799dba64beSDimitry Andric 
GetOptionsFromMode(llvm::StringRef mode)809dba64beSDimitry Andric Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
819dba64beSDimitry Andric   OpenOptions opts =
829dba64beSDimitry Andric       llvm::StringSwitch<OpenOptions>(mode)
83349cc55cSDimitry Andric           .Cases("r", "rb", eOpenOptionReadOnly)
84349cc55cSDimitry Andric           .Cases("w", "wb", eOpenOptionWriteOnly)
859dba64beSDimitry Andric           .Cases("a", "ab",
86349cc55cSDimitry Andric                  eOpenOptionWriteOnly | eOpenOptionAppend |
87349cc55cSDimitry Andric                  eOpenOptionCanCreate)
88349cc55cSDimitry Andric           .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
899dba64beSDimitry Andric           .Cases("w+", "wb+", "w+b",
90349cc55cSDimitry Andric                  eOpenOptionReadWrite | eOpenOptionCanCreate |
919dba64beSDimitry Andric                  eOpenOptionTruncate)
929dba64beSDimitry Andric           .Cases("a+", "ab+", "a+b",
93349cc55cSDimitry Andric                  eOpenOptionReadWrite | eOpenOptionAppend |
949dba64beSDimitry Andric                      eOpenOptionCanCreate)
95349cc55cSDimitry Andric           .Default(eOpenOptionInvalid);
96349cc55cSDimitry Andric   if (opts != eOpenOptionInvalid)
979dba64beSDimitry Andric     return opts;
989dba64beSDimitry Andric   return llvm::createStringError(
999dba64beSDimitry Andric       llvm::inconvertibleErrorCode(),
1009dba64beSDimitry Andric       "invalid mode, cannot convert to File::OpenOptions");
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric int File::kInvalidDescriptor = -1;
1040b57cec5SDimitry Andric FILE *File::kInvalidStream = nullptr;
1050b57cec5SDimitry Andric 
Read(void * buf,size_t & num_bytes)1069dba64beSDimitry Andric Status File::Read(void *buf, size_t &num_bytes) {
1079dba64beSDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
1089dba64beSDimitry Andric }
Write(const void * buf,size_t & num_bytes)1099dba64beSDimitry Andric Status File::Write(const void *buf, size_t &num_bytes) {
1109dba64beSDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
1119dba64beSDimitry Andric }
1120b57cec5SDimitry Andric 
IsValid() const1139dba64beSDimitry Andric bool File::IsValid() const { return false; }
1149dba64beSDimitry Andric 
Close()1159dba64beSDimitry Andric Status File::Close() { return Flush(); }
1169dba64beSDimitry Andric 
GetWaitableHandle()1179dba64beSDimitry Andric IOObject::WaitableHandle File::GetWaitableHandle() {
1189dba64beSDimitry Andric   return IOObject::kInvalidHandleValue;
1199dba64beSDimitry Andric }
1209dba64beSDimitry Andric 
GetFileSpec(FileSpec & file_spec) const1219dba64beSDimitry Andric Status File::GetFileSpec(FileSpec &file_spec) const {
1229dba64beSDimitry Andric   file_spec.Clear();
1239dba64beSDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
1249dba64beSDimitry Andric }
1259dba64beSDimitry Andric 
GetDescriptor() const1269dba64beSDimitry Andric int File::GetDescriptor() const { return kInvalidDescriptor; }
1279dba64beSDimitry Andric 
GetStream()1289dba64beSDimitry Andric FILE *File::GetStream() { return nullptr; }
1299dba64beSDimitry Andric 
SeekFromStart(off_t offset,Status * error_ptr)1309dba64beSDimitry Andric off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
1319dba64beSDimitry Andric   if (error_ptr)
1329dba64beSDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
1339dba64beSDimitry Andric   return -1;
1349dba64beSDimitry Andric }
1359dba64beSDimitry Andric 
SeekFromCurrent(off_t offset,Status * error_ptr)1369dba64beSDimitry Andric off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
1379dba64beSDimitry Andric   if (error_ptr)
1389dba64beSDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
1399dba64beSDimitry Andric   return -1;
1409dba64beSDimitry Andric }
1419dba64beSDimitry Andric 
SeekFromEnd(off_t offset,Status * error_ptr)1429dba64beSDimitry Andric off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
1439dba64beSDimitry Andric   if (error_ptr)
1449dba64beSDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
1459dba64beSDimitry Andric   return -1;
1469dba64beSDimitry Andric }
1479dba64beSDimitry Andric 
Read(void * dst,size_t & num_bytes,off_t & offset)1489dba64beSDimitry Andric Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
1499dba64beSDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
1509dba64beSDimitry Andric }
1519dba64beSDimitry Andric 
Write(const void * src,size_t & num_bytes,off_t & offset)1529dba64beSDimitry Andric Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
1539dba64beSDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
1549dba64beSDimitry Andric }
1559dba64beSDimitry Andric 
Flush()1569dba64beSDimitry Andric Status File::Flush() { return Status(); }
1579dba64beSDimitry Andric 
Sync()1589dba64beSDimitry Andric Status File::Sync() { return Flush(); }
1599dba64beSDimitry Andric 
CalculateInteractiveAndTerminal()1609dba64beSDimitry Andric void File::CalculateInteractiveAndTerminal() {
1619dba64beSDimitry Andric   const int fd = GetDescriptor();
1629dba64beSDimitry Andric   if (!DescriptorIsValid(fd)) {
1639dba64beSDimitry Andric     m_is_interactive = eLazyBoolNo;
1649dba64beSDimitry Andric     m_is_real_terminal = eLazyBoolNo;
1659dba64beSDimitry Andric     m_supports_colors = eLazyBoolNo;
1669dba64beSDimitry Andric     return;
1679dba64beSDimitry Andric   }
1689dba64beSDimitry Andric   m_is_interactive = eLazyBoolNo;
1699dba64beSDimitry Andric   m_is_real_terminal = eLazyBoolNo;
1709dba64beSDimitry Andric #if defined(_WIN32)
1719dba64beSDimitry Andric   if (_isatty(fd)) {
1729dba64beSDimitry Andric     m_is_interactive = eLazyBoolYes;
1739dba64beSDimitry Andric     m_is_real_terminal = eLazyBoolYes;
1749dba64beSDimitry Andric #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1759dba64beSDimitry Andric     m_supports_colors = eLazyBoolYes;
1769dba64beSDimitry Andric #endif
1779dba64beSDimitry Andric   }
1789dba64beSDimitry Andric #else
1799dba64beSDimitry Andric   if (isatty(fd)) {
1809dba64beSDimitry Andric     m_is_interactive = eLazyBoolYes;
1819dba64beSDimitry Andric     struct winsize window_size;
1829dba64beSDimitry Andric     if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
1839dba64beSDimitry Andric       if (window_size.ws_col > 0) {
1849dba64beSDimitry Andric         m_is_real_terminal = eLazyBoolYes;
1859dba64beSDimitry Andric         if (llvm::sys::Process::FileDescriptorHasColors(fd))
1869dba64beSDimitry Andric           m_supports_colors = eLazyBoolYes;
1879dba64beSDimitry Andric       }
1889dba64beSDimitry Andric     }
1899dba64beSDimitry Andric   }
1909dba64beSDimitry Andric #endif
1919dba64beSDimitry Andric }
1929dba64beSDimitry Andric 
GetIsInteractive()1939dba64beSDimitry Andric bool File::GetIsInteractive() {
1949dba64beSDimitry Andric   if (m_is_interactive == eLazyBoolCalculate)
1959dba64beSDimitry Andric     CalculateInteractiveAndTerminal();
1969dba64beSDimitry Andric   return m_is_interactive == eLazyBoolYes;
1979dba64beSDimitry Andric }
1989dba64beSDimitry Andric 
GetIsRealTerminal()1999dba64beSDimitry Andric bool File::GetIsRealTerminal() {
2009dba64beSDimitry Andric   if (m_is_real_terminal == eLazyBoolCalculate)
2019dba64beSDimitry Andric     CalculateInteractiveAndTerminal();
2029dba64beSDimitry Andric   return m_is_real_terminal == eLazyBoolYes;
2039dba64beSDimitry Andric }
2049dba64beSDimitry Andric 
GetIsTerminalWithColors()2059dba64beSDimitry Andric bool File::GetIsTerminalWithColors() {
2069dba64beSDimitry Andric   if (m_supports_colors == eLazyBoolCalculate)
2079dba64beSDimitry Andric     CalculateInteractiveAndTerminal();
2089dba64beSDimitry Andric   return m_supports_colors == eLazyBoolYes;
2099dba64beSDimitry Andric }
2109dba64beSDimitry Andric 
Printf(const char * format,...)2119dba64beSDimitry Andric size_t File::Printf(const char *format, ...) {
2129dba64beSDimitry Andric   va_list args;
2139dba64beSDimitry Andric   va_start(args, format);
2149dba64beSDimitry Andric   size_t result = PrintfVarArg(format, args);
2159dba64beSDimitry Andric   va_end(args);
2169dba64beSDimitry Andric   return result;
2179dba64beSDimitry Andric }
2189dba64beSDimitry Andric 
PrintfVarArg(const char * format,va_list args)2199dba64beSDimitry Andric size_t File::PrintfVarArg(const char *format, va_list args) {
22081ad6265SDimitry Andric   llvm::SmallString<0> s;
22181ad6265SDimitry Andric   if (VASprintf(s, format, args)) {
222*5f757f3fSDimitry Andric     size_t written = s.size();
22381ad6265SDimitry Andric     Write(s.data(), written);
22481ad6265SDimitry Andric     return written;
2259dba64beSDimitry Andric   }
22681ad6265SDimitry Andric   return 0;
2279dba64beSDimitry Andric }
2289dba64beSDimitry Andric 
GetOptions() const2299dba64beSDimitry Andric Expected<File::OpenOptions> File::GetOptions() const {
2309dba64beSDimitry Andric   return llvm::createStringError(
2319dba64beSDimitry Andric       llvm::inconvertibleErrorCode(),
2329dba64beSDimitry Andric       "GetOptions() not implemented for this File class");
2339dba64beSDimitry Andric }
2349dba64beSDimitry Andric 
GetPermissions(Status & error) const2359dba64beSDimitry Andric uint32_t File::GetPermissions(Status &error) const {
2369dba64beSDimitry Andric   int fd = GetDescriptor();
2379dba64beSDimitry Andric   if (!DescriptorIsValid(fd)) {
2389dba64beSDimitry Andric     error = std::error_code(ENOTSUP, std::system_category());
2399dba64beSDimitry Andric     return 0;
2409dba64beSDimitry Andric   }
2419dba64beSDimitry Andric   struct stat file_stats;
2429dba64beSDimitry Andric   if (::fstat(fd, &file_stats) == -1) {
2439dba64beSDimitry Andric     error.SetErrorToErrno();
2449dba64beSDimitry Andric     return 0;
2459dba64beSDimitry Andric   }
2469dba64beSDimitry Andric   error.Clear();
2479dba64beSDimitry Andric   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
2489dba64beSDimitry Andric }
2499dba64beSDimitry Andric 
IsValid() const250*5f757f3fSDimitry Andric bool NativeFile::IsValid() const {
251*5f757f3fSDimitry Andric   std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
252*5f757f3fSDimitry Andric   return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();
253*5f757f3fSDimitry Andric }
254*5f757f3fSDimitry Andric 
GetOptions() const2559dba64beSDimitry Andric Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
2569dba64beSDimitry Andric 
GetDescriptor() const2579dba64beSDimitry Andric int NativeFile::GetDescriptor() const {
258*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
2590b57cec5SDimitry Andric     return m_descriptor;
260*5f757f3fSDimitry Andric   }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // Don't open the file descriptor if we don't need to, just get it from the
2630b57cec5SDimitry Andric   // stream if we have one.
264*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
2650b57cec5SDimitry Andric #if defined(_WIN32)
2660b57cec5SDimitry Andric     return _fileno(m_stream);
2670b57cec5SDimitry Andric #else
2680b57cec5SDimitry Andric     return fileno(m_stream);
2690b57cec5SDimitry Andric #endif
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   // Invalid descriptor and invalid stream, return invalid descriptor.
2730b57cec5SDimitry Andric   return kInvalidDescriptor;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
GetWaitableHandle()2769dba64beSDimitry Andric IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
2779dba64beSDimitry Andric   return GetDescriptor();
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
GetStream()2809dba64beSDimitry Andric FILE *NativeFile::GetStream() {
281*5f757f3fSDimitry Andric   ValueGuard stream_guard = StreamIsValid();
282*5f757f3fSDimitry Andric   if (!stream_guard) {
283*5f757f3fSDimitry Andric     if (ValueGuard descriptor_guard = DescriptorIsValid()) {
2849dba64beSDimitry Andric       auto mode = GetStreamOpenModeFromOptions(m_options);
2859dba64beSDimitry Andric       if (!mode)
2869dba64beSDimitry Andric         llvm::consumeError(mode.takeError());
2879dba64beSDimitry Andric       else {
2889dba64beSDimitry Andric         if (!m_own_descriptor) {
2890b57cec5SDimitry Andric // We must duplicate the file descriptor if we don't own it because when you
2900b57cec5SDimitry Andric // call fdopen, the stream will own the fd
2910b57cec5SDimitry Andric #ifdef _WIN32
292*5f757f3fSDimitry Andric           m_descriptor = ::_dup(m_descriptor);
2930b57cec5SDimitry Andric #else
294*5f757f3fSDimitry Andric           m_descriptor = dup(m_descriptor);
2950b57cec5SDimitry Andric #endif
2969dba64beSDimitry Andric           m_own_descriptor = true;
2970b57cec5SDimitry Andric         }
2980b57cec5SDimitry Andric 
2999dba64beSDimitry Andric         m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
3009dba64beSDimitry Andric                                                mode.get());
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric         // If we got a stream, then we own the stream and should no longer own
3030b57cec5SDimitry Andric         // the descriptor because fclose() will close it for us
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric         if (m_stream) {
3060b57cec5SDimitry Andric           m_own_stream = true;
3079dba64beSDimitry Andric           m_own_descriptor = false;
3080b57cec5SDimitry Andric         }
3090b57cec5SDimitry Andric       }
3100b57cec5SDimitry Andric     }
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric   return m_stream;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric 
Close()3159dba64beSDimitry Andric Status NativeFile::Close() {
316*5f757f3fSDimitry Andric   std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
317*5f757f3fSDimitry Andric 
3180b57cec5SDimitry Andric   Status error;
319*5f757f3fSDimitry Andric 
320*5f757f3fSDimitry Andric   if (StreamIsValidUnlocked()) {
3219dba64beSDimitry Andric     if (m_own_stream) {
3220b57cec5SDimitry Andric       if (::fclose(m_stream) == EOF)
3230b57cec5SDimitry Andric         error.SetErrorToErrno();
324349cc55cSDimitry Andric     } else {
325349cc55cSDimitry Andric       File::OpenOptions rw =
326349cc55cSDimitry Andric           m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
327349cc55cSDimitry Andric                        File::eOpenOptionReadWrite);
328349cc55cSDimitry Andric 
329349cc55cSDimitry Andric       if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
3309dba64beSDimitry Andric         if (::fflush(m_stream) == EOF)
3319dba64beSDimitry Andric           error.SetErrorToErrno();
3320b57cec5SDimitry Andric       }
3339dba64beSDimitry Andric     }
334349cc55cSDimitry Andric   }
335*5f757f3fSDimitry Andric 
336*5f757f3fSDimitry Andric   if (DescriptorIsValidUnlocked() && m_own_descriptor) {
3370b57cec5SDimitry Andric     if (::close(m_descriptor) != 0)
3380b57cec5SDimitry Andric       error.SetErrorToErrno();
3390b57cec5SDimitry Andric   }
340*5f757f3fSDimitry Andric 
3410b57cec5SDimitry Andric   m_stream = kInvalidStream;
3420b57cec5SDimitry Andric   m_own_stream = false;
343*5f757f3fSDimitry Andric   m_descriptor = kInvalidDescriptor;
3449dba64beSDimitry Andric   m_own_descriptor = false;
345*5f757f3fSDimitry Andric   m_options = OpenOptions(0);
3460b57cec5SDimitry Andric   m_is_interactive = eLazyBoolCalculate;
3470b57cec5SDimitry Andric   m_is_real_terminal = eLazyBoolCalculate;
3480b57cec5SDimitry Andric   return error;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
GetFileSpec(FileSpec & file_spec) const3519dba64beSDimitry Andric Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
3520b57cec5SDimitry Andric   Status error;
3530b57cec5SDimitry Andric #ifdef F_GETPATH
3540b57cec5SDimitry Andric   if (IsValid()) {
3550b57cec5SDimitry Andric     char path[PATH_MAX];
3560b57cec5SDimitry Andric     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
3570b57cec5SDimitry Andric       error.SetErrorToErrno();
3580b57cec5SDimitry Andric     else
3590b57cec5SDimitry Andric       file_spec.SetFile(path, FileSpec::Style::native);
3600b57cec5SDimitry Andric   } else {
3610b57cec5SDimitry Andric     error.SetErrorString("invalid file handle");
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric #elif defined(__linux__)
3640b57cec5SDimitry Andric   char proc[64];
3650b57cec5SDimitry Andric   char path[PATH_MAX];
3660b57cec5SDimitry Andric   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
3670b57cec5SDimitry Andric     error.SetErrorString("cannot resolve file descriptor");
3680b57cec5SDimitry Andric   else {
3690b57cec5SDimitry Andric     ssize_t len;
3700b57cec5SDimitry Andric     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
3710b57cec5SDimitry Andric       error.SetErrorToErrno();
3720b57cec5SDimitry Andric     else {
3730b57cec5SDimitry Andric       path[len] = '\0';
3740b57cec5SDimitry Andric       file_spec.SetFile(path, FileSpec::Style::native);
3750b57cec5SDimitry Andric     }
3760b57cec5SDimitry Andric   }
3770b57cec5SDimitry Andric #else
3789dba64beSDimitry Andric   error.SetErrorString(
3799dba64beSDimitry Andric       "NativeFile::GetFileSpec is not supported on this platform");
3800b57cec5SDimitry Andric #endif
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   if (error.Fail())
3830b57cec5SDimitry Andric     file_spec.Clear();
3840b57cec5SDimitry Andric   return error;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
SeekFromStart(off_t offset,Status * error_ptr)3879dba64beSDimitry Andric off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
3880b57cec5SDimitry Andric   off_t result = 0;
389*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
3900b57cec5SDimitry Andric     result = ::lseek(m_descriptor, offset, SEEK_SET);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric     if (error_ptr) {
3930b57cec5SDimitry Andric       if (result == -1)
3940b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
3950b57cec5SDimitry Andric       else
3960b57cec5SDimitry Andric         error_ptr->Clear();
3970b57cec5SDimitry Andric     }
398*5f757f3fSDimitry Andric     return result;
399*5f757f3fSDimitry Andric   }
400*5f757f3fSDimitry Andric 
401*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
4020b57cec5SDimitry Andric     result = ::fseek(m_stream, offset, SEEK_SET);
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     if (error_ptr) {
4050b57cec5SDimitry Andric       if (result == -1)
4060b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
4070b57cec5SDimitry Andric       else
4080b57cec5SDimitry Andric         error_ptr->Clear();
4090b57cec5SDimitry Andric     }
410*5f757f3fSDimitry Andric     return result;
4110b57cec5SDimitry Andric   }
412*5f757f3fSDimitry Andric 
413*5f757f3fSDimitry Andric   if (error_ptr)
414*5f757f3fSDimitry Andric     error_ptr->SetErrorString("invalid file handle");
4150b57cec5SDimitry Andric   return result;
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
SeekFromCurrent(off_t offset,Status * error_ptr)4189dba64beSDimitry Andric off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
4190b57cec5SDimitry Andric   off_t result = -1;
420*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
4210b57cec5SDimitry Andric     result = ::lseek(m_descriptor, offset, SEEK_CUR);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric     if (error_ptr) {
4240b57cec5SDimitry Andric       if (result == -1)
4250b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
4260b57cec5SDimitry Andric       else
4270b57cec5SDimitry Andric         error_ptr->Clear();
4280b57cec5SDimitry Andric     }
429*5f757f3fSDimitry Andric     return result;
430*5f757f3fSDimitry Andric   }
431*5f757f3fSDimitry Andric 
432*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
4330b57cec5SDimitry Andric     result = ::fseek(m_stream, offset, SEEK_CUR);
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric     if (error_ptr) {
4360b57cec5SDimitry Andric       if (result == -1)
4370b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
4380b57cec5SDimitry Andric       else
4390b57cec5SDimitry Andric         error_ptr->Clear();
4400b57cec5SDimitry Andric     }
441*5f757f3fSDimitry Andric     return result;
4420b57cec5SDimitry Andric   }
443*5f757f3fSDimitry Andric 
444*5f757f3fSDimitry Andric   if (error_ptr)
445*5f757f3fSDimitry Andric     error_ptr->SetErrorString("invalid file handle");
4460b57cec5SDimitry Andric   return result;
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
SeekFromEnd(off_t offset,Status * error_ptr)4499dba64beSDimitry Andric off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
4500b57cec5SDimitry Andric   off_t result = -1;
451*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
4520b57cec5SDimitry Andric     result = ::lseek(m_descriptor, offset, SEEK_END);
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric     if (error_ptr) {
4550b57cec5SDimitry Andric       if (result == -1)
4560b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
4570b57cec5SDimitry Andric       else
4580b57cec5SDimitry Andric         error_ptr->Clear();
4590b57cec5SDimitry Andric     }
460*5f757f3fSDimitry Andric     return result;
461*5f757f3fSDimitry Andric   }
462*5f757f3fSDimitry Andric 
463*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
4640b57cec5SDimitry Andric     result = ::fseek(m_stream, offset, SEEK_END);
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric     if (error_ptr) {
4670b57cec5SDimitry Andric       if (result == -1)
4680b57cec5SDimitry Andric         error_ptr->SetErrorToErrno();
4690b57cec5SDimitry Andric       else
4700b57cec5SDimitry Andric         error_ptr->Clear();
4710b57cec5SDimitry Andric     }
4720b57cec5SDimitry Andric   }
473*5f757f3fSDimitry Andric 
474*5f757f3fSDimitry Andric   if (error_ptr)
475*5f757f3fSDimitry Andric     error_ptr->SetErrorString("invalid file handle");
4760b57cec5SDimitry Andric   return result;
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric 
Flush()4799dba64beSDimitry Andric Status NativeFile::Flush() {
4800b57cec5SDimitry Andric   Status error;
481*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
4820b57cec5SDimitry Andric     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
4830b57cec5SDimitry Andric       error.SetErrorToErrno();
484*5f757f3fSDimitry Andric     return error;
485*5f757f3fSDimitry Andric   }
486*5f757f3fSDimitry Andric 
487*5f757f3fSDimitry Andric   {
488*5f757f3fSDimitry Andric     ValueGuard descriptor_guard = DescriptorIsValid();
489*5f757f3fSDimitry Andric     if (!descriptor_guard)
4900b57cec5SDimitry Andric       error.SetErrorString("invalid file handle");
4910b57cec5SDimitry Andric   }
4920b57cec5SDimitry Andric   return error;
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
Sync()4959dba64beSDimitry Andric Status NativeFile::Sync() {
4960b57cec5SDimitry Andric   Status error;
497*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
4980b57cec5SDimitry Andric #ifdef _WIN32
4990b57cec5SDimitry Andric     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
5000b57cec5SDimitry Andric     if (err == 0)
5010b57cec5SDimitry Andric       error.SetErrorToGenericError();
5020b57cec5SDimitry Andric #else
5030b57cec5SDimitry Andric     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
5040b57cec5SDimitry Andric       error.SetErrorToErrno();
5050b57cec5SDimitry Andric #endif
5060b57cec5SDimitry Andric   } else {
5070b57cec5SDimitry Andric     error.SetErrorString("invalid file handle");
5080b57cec5SDimitry Andric   }
5090b57cec5SDimitry Andric   return error;
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric #if defined(__APPLE__)
5130b57cec5SDimitry Andric // Darwin kernels only can read/write <= INT_MAX bytes
5140b57cec5SDimitry Andric #define MAX_READ_SIZE INT_MAX
5150b57cec5SDimitry Andric #define MAX_WRITE_SIZE INT_MAX
5160b57cec5SDimitry Andric #endif
5170b57cec5SDimitry Andric 
Read(void * buf,size_t & num_bytes)5189dba64beSDimitry Andric Status NativeFile::Read(void *buf, size_t &num_bytes) {
5190b57cec5SDimitry Andric   Status error;
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric #if defined(MAX_READ_SIZE)
5220b57cec5SDimitry Andric   if (num_bytes > MAX_READ_SIZE) {
5230b57cec5SDimitry Andric     uint8_t *p = (uint8_t *)buf;
5240b57cec5SDimitry Andric     size_t bytes_left = num_bytes;
5250b57cec5SDimitry Andric     // Init the num_bytes read to zero
5260b57cec5SDimitry Andric     num_bytes = 0;
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric     while (bytes_left > 0) {
5290b57cec5SDimitry Andric       size_t curr_num_bytes;
5300b57cec5SDimitry Andric       if (bytes_left > MAX_READ_SIZE)
5310b57cec5SDimitry Andric         curr_num_bytes = MAX_READ_SIZE;
5320b57cec5SDimitry Andric       else
5330b57cec5SDimitry Andric         curr_num_bytes = bytes_left;
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric       error = Read(p + num_bytes, curr_num_bytes);
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric       // Update how many bytes were read
5380b57cec5SDimitry Andric       num_bytes += curr_num_bytes;
5390b57cec5SDimitry Andric       if (bytes_left < curr_num_bytes)
5400b57cec5SDimitry Andric         bytes_left = 0;
5410b57cec5SDimitry Andric       else
5420b57cec5SDimitry Andric         bytes_left -= curr_num_bytes;
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric       if (error.Fail())
5450b57cec5SDimitry Andric         break;
5460b57cec5SDimitry Andric     }
5470b57cec5SDimitry Andric     return error;
5480b57cec5SDimitry Andric   }
5490b57cec5SDimitry Andric #endif
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric   ssize_t bytes_read = -1;
552*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
553*5f757f3fSDimitry Andric     bytes_read =
554*5f757f3fSDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
5550b57cec5SDimitry Andric     if (bytes_read == -1) {
5560b57cec5SDimitry Andric       error.SetErrorToErrno();
5570b57cec5SDimitry Andric       num_bytes = 0;
5580b57cec5SDimitry Andric     } else
5590b57cec5SDimitry Andric       num_bytes = bytes_read;
560*5f757f3fSDimitry Andric     return error;
561*5f757f3fSDimitry Andric   }
562*5f757f3fSDimitry Andric 
563*5f757f3fSDimitry Andric   if (ValueGuard file_lock = StreamIsValid()) {
5640b57cec5SDimitry Andric     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric     if (bytes_read == 0) {
5670b57cec5SDimitry Andric       if (::feof(m_stream))
5680b57cec5SDimitry Andric         error.SetErrorString("feof");
5690b57cec5SDimitry Andric       else if (::ferror(m_stream))
5700b57cec5SDimitry Andric         error.SetErrorString("ferror");
5710b57cec5SDimitry Andric       num_bytes = 0;
5720b57cec5SDimitry Andric     } else
5730b57cec5SDimitry Andric       num_bytes = bytes_read;
574*5f757f3fSDimitry Andric     return error;
575*5f757f3fSDimitry Andric   }
576*5f757f3fSDimitry Andric 
5770b57cec5SDimitry Andric   num_bytes = 0;
5780b57cec5SDimitry Andric   error.SetErrorString("invalid file handle");
5790b57cec5SDimitry Andric   return error;
5800b57cec5SDimitry Andric }
5810b57cec5SDimitry Andric 
Write(const void * buf,size_t & num_bytes)5829dba64beSDimitry Andric Status NativeFile::Write(const void *buf, size_t &num_bytes) {
5830b57cec5SDimitry Andric   Status error;
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric #if defined(MAX_WRITE_SIZE)
5860b57cec5SDimitry Andric   if (num_bytes > MAX_WRITE_SIZE) {
5870b57cec5SDimitry Andric     const uint8_t *p = (const uint8_t *)buf;
5880b57cec5SDimitry Andric     size_t bytes_left = num_bytes;
5890b57cec5SDimitry Andric     // Init the num_bytes written to zero
5900b57cec5SDimitry Andric     num_bytes = 0;
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric     while (bytes_left > 0) {
5930b57cec5SDimitry Andric       size_t curr_num_bytes;
5940b57cec5SDimitry Andric       if (bytes_left > MAX_WRITE_SIZE)
5950b57cec5SDimitry Andric         curr_num_bytes = MAX_WRITE_SIZE;
5960b57cec5SDimitry Andric       else
5970b57cec5SDimitry Andric         curr_num_bytes = bytes_left;
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric       error = Write(p + num_bytes, curr_num_bytes);
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric       // Update how many bytes were read
6020b57cec5SDimitry Andric       num_bytes += curr_num_bytes;
6030b57cec5SDimitry Andric       if (bytes_left < curr_num_bytes)
6040b57cec5SDimitry Andric         bytes_left = 0;
6050b57cec5SDimitry Andric       else
6060b57cec5SDimitry Andric         bytes_left -= curr_num_bytes;
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric       if (error.Fail())
6090b57cec5SDimitry Andric         break;
6100b57cec5SDimitry Andric     }
6110b57cec5SDimitry Andric     return error;
6120b57cec5SDimitry Andric   }
6130b57cec5SDimitry Andric #endif
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric   ssize_t bytes_written = -1;
616*5f757f3fSDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
6170b57cec5SDimitry Andric     bytes_written =
6180b57cec5SDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
6190b57cec5SDimitry Andric     if (bytes_written == -1) {
6200b57cec5SDimitry Andric       error.SetErrorToErrno();
6210b57cec5SDimitry Andric       num_bytes = 0;
6220b57cec5SDimitry Andric     } else
6230b57cec5SDimitry Andric       num_bytes = bytes_written;
624*5f757f3fSDimitry Andric     return error;
625*5f757f3fSDimitry Andric   }
626*5f757f3fSDimitry Andric 
627*5f757f3fSDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
6280b57cec5SDimitry Andric     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric     if (bytes_written == 0) {
6310b57cec5SDimitry Andric       if (::feof(m_stream))
6320b57cec5SDimitry Andric         error.SetErrorString("feof");
6330b57cec5SDimitry Andric       else if (::ferror(m_stream))
6340b57cec5SDimitry Andric         error.SetErrorString("ferror");
6350b57cec5SDimitry Andric       num_bytes = 0;
6360b57cec5SDimitry Andric     } else
6370b57cec5SDimitry Andric       num_bytes = bytes_written;
638*5f757f3fSDimitry Andric     return error;
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric 
641*5f757f3fSDimitry Andric   num_bytes = 0;
642*5f757f3fSDimitry Andric   error.SetErrorString("invalid file handle");
6430b57cec5SDimitry Andric   return error;
6440b57cec5SDimitry Andric }
6450b57cec5SDimitry Andric 
Read(void * buf,size_t & num_bytes,off_t & offset)6469dba64beSDimitry Andric Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
6470b57cec5SDimitry Andric   Status error;
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric #if defined(MAX_READ_SIZE)
6500b57cec5SDimitry Andric   if (num_bytes > MAX_READ_SIZE) {
6510b57cec5SDimitry Andric     uint8_t *p = (uint8_t *)buf;
6520b57cec5SDimitry Andric     size_t bytes_left = num_bytes;
6530b57cec5SDimitry Andric     // Init the num_bytes read to zero
6540b57cec5SDimitry Andric     num_bytes = 0;
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric     while (bytes_left > 0) {
6570b57cec5SDimitry Andric       size_t curr_num_bytes;
6580b57cec5SDimitry Andric       if (bytes_left > MAX_READ_SIZE)
6590b57cec5SDimitry Andric         curr_num_bytes = MAX_READ_SIZE;
6600b57cec5SDimitry Andric       else
6610b57cec5SDimitry Andric         curr_num_bytes = bytes_left;
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric       error = Read(p + num_bytes, curr_num_bytes, offset);
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric       // Update how many bytes were read
6660b57cec5SDimitry Andric       num_bytes += curr_num_bytes;
6670b57cec5SDimitry Andric       if (bytes_left < curr_num_bytes)
6680b57cec5SDimitry Andric         bytes_left = 0;
6690b57cec5SDimitry Andric       else
6700b57cec5SDimitry Andric         bytes_left -= curr_num_bytes;
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric       if (error.Fail())
6730b57cec5SDimitry Andric         break;
6740b57cec5SDimitry Andric     }
6750b57cec5SDimitry Andric     return error;
6760b57cec5SDimitry Andric   }
6770b57cec5SDimitry Andric #endif
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric #ifndef _WIN32
6800b57cec5SDimitry Andric   int fd = GetDescriptor();
6810b57cec5SDimitry Andric   if (fd != kInvalidDescriptor) {
6820b57cec5SDimitry Andric     ssize_t bytes_read =
6830b57cec5SDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
6840b57cec5SDimitry Andric     if (bytes_read < 0) {
6850b57cec5SDimitry Andric       num_bytes = 0;
6860b57cec5SDimitry Andric       error.SetErrorToErrno();
6870b57cec5SDimitry Andric     } else {
6880b57cec5SDimitry Andric       offset += bytes_read;
6890b57cec5SDimitry Andric       num_bytes = bytes_read;
6900b57cec5SDimitry Andric     }
6910b57cec5SDimitry Andric   } else {
6920b57cec5SDimitry Andric     num_bytes = 0;
6930b57cec5SDimitry Andric     error.SetErrorString("invalid file handle");
6940b57cec5SDimitry Andric   }
6950b57cec5SDimitry Andric #else
6960b57cec5SDimitry Andric   std::lock_guard<std::mutex> guard(offset_access_mutex);
6970b57cec5SDimitry Andric   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
6980b57cec5SDimitry Andric   SeekFromStart(offset);
6990b57cec5SDimitry Andric   error = Read(buf, num_bytes);
7000b57cec5SDimitry Andric   if (!error.Fail())
7010b57cec5SDimitry Andric     SeekFromStart(cur);
7020b57cec5SDimitry Andric #endif
7030b57cec5SDimitry Andric   return error;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
Write(const void * buf,size_t & num_bytes,off_t & offset)7069dba64beSDimitry Andric Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
7070b57cec5SDimitry Andric   Status error;
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric #if defined(MAX_WRITE_SIZE)
7100b57cec5SDimitry Andric   if (num_bytes > MAX_WRITE_SIZE) {
7110b57cec5SDimitry Andric     const uint8_t *p = (const uint8_t *)buf;
7120b57cec5SDimitry Andric     size_t bytes_left = num_bytes;
7130b57cec5SDimitry Andric     // Init the num_bytes written to zero
7140b57cec5SDimitry Andric     num_bytes = 0;
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric     while (bytes_left > 0) {
7170b57cec5SDimitry Andric       size_t curr_num_bytes;
7180b57cec5SDimitry Andric       if (bytes_left > MAX_WRITE_SIZE)
7190b57cec5SDimitry Andric         curr_num_bytes = MAX_WRITE_SIZE;
7200b57cec5SDimitry Andric       else
7210b57cec5SDimitry Andric         curr_num_bytes = bytes_left;
7220b57cec5SDimitry Andric 
7230b57cec5SDimitry Andric       error = Write(p + num_bytes, curr_num_bytes, offset);
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric       // Update how many bytes were read
7260b57cec5SDimitry Andric       num_bytes += curr_num_bytes;
7270b57cec5SDimitry Andric       if (bytes_left < curr_num_bytes)
7280b57cec5SDimitry Andric         bytes_left = 0;
7290b57cec5SDimitry Andric       else
7300b57cec5SDimitry Andric         bytes_left -= curr_num_bytes;
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric       if (error.Fail())
7330b57cec5SDimitry Andric         break;
7340b57cec5SDimitry Andric     }
7350b57cec5SDimitry Andric     return error;
7360b57cec5SDimitry Andric   }
7370b57cec5SDimitry Andric #endif
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   int fd = GetDescriptor();
7400b57cec5SDimitry Andric   if (fd != kInvalidDescriptor) {
7410b57cec5SDimitry Andric #ifndef _WIN32
7420b57cec5SDimitry Andric     ssize_t bytes_written =
7430b57cec5SDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
7440b57cec5SDimitry Andric     if (bytes_written < 0) {
7450b57cec5SDimitry Andric       num_bytes = 0;
7460b57cec5SDimitry Andric       error.SetErrorToErrno();
7470b57cec5SDimitry Andric     } else {
7480b57cec5SDimitry Andric       offset += bytes_written;
7490b57cec5SDimitry Andric       num_bytes = bytes_written;
7500b57cec5SDimitry Andric     }
7510b57cec5SDimitry Andric #else
7520b57cec5SDimitry Andric     std::lock_guard<std::mutex> guard(offset_access_mutex);
7530b57cec5SDimitry Andric     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
7540b57cec5SDimitry Andric     SeekFromStart(offset);
7550b57cec5SDimitry Andric     error = Write(buf, num_bytes);
7560b57cec5SDimitry Andric     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric     if (!error.Fail())
7590b57cec5SDimitry Andric       SeekFromStart(cur);
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric     offset = after;
7620b57cec5SDimitry Andric #endif
7630b57cec5SDimitry Andric   } else {
7640b57cec5SDimitry Andric     num_bytes = 0;
7650b57cec5SDimitry Andric     error.SetErrorString("invalid file handle");
7660b57cec5SDimitry Andric   }
7670b57cec5SDimitry Andric   return error;
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric 
PrintfVarArg(const char * format,va_list args)7709dba64beSDimitry Andric size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
7719dba64beSDimitry Andric   if (StreamIsValid()) {
7729dba64beSDimitry Andric     return ::vfprintf(m_stream, format, args);
7739dba64beSDimitry Andric   } else {
7749dba64beSDimitry Andric     return File::PrintfVarArg(format, args);
7759dba64beSDimitry Andric   }
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric 
ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)7789dba64beSDimitry Andric mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
7790b57cec5SDimitry Andric   mode_t mode = 0;
780349cc55cSDimitry Andric   File::OpenOptions rw =
781349cc55cSDimitry Andric       open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
782349cc55cSDimitry Andric                       File::eOpenOptionReadWrite);
783349cc55cSDimitry Andric   if (rw == eOpenOptionReadWrite)
7840b57cec5SDimitry Andric     mode |= O_RDWR;
785349cc55cSDimitry Andric   else if (rw == eOpenOptionWriteOnly)
7860b57cec5SDimitry Andric     mode |= O_WRONLY;
787349cc55cSDimitry Andric   else if (rw == eOpenOptionReadOnly)
788349cc55cSDimitry Andric     mode |= O_RDONLY;
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric   if (open_options & eOpenOptionAppend)
7910b57cec5SDimitry Andric     mode |= O_APPEND;
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   if (open_options & eOpenOptionTruncate)
7940b57cec5SDimitry Andric     mode |= O_TRUNC;
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric   if (open_options & eOpenOptionNonBlocking)
7970b57cec5SDimitry Andric     mode |= O_NONBLOCK;
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric   if (open_options & eOpenOptionCanCreateNewOnly)
8000b57cec5SDimitry Andric     mode |= O_CREAT | O_EXCL;
8010b57cec5SDimitry Andric   else if (open_options & eOpenOptionCanCreate)
8020b57cec5SDimitry Andric     mode |= O_CREAT;
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   return mode;
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric 
807349cc55cSDimitry Andric llvm::Expected<SerialPort::Options>
OptionsFromURL(llvm::StringRef urlqs)808349cc55cSDimitry Andric SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
809349cc55cSDimitry Andric   SerialPort::Options serial_options;
810349cc55cSDimitry Andric   for (llvm::StringRef x : llvm::split(urlqs, '&')) {
811349cc55cSDimitry Andric     if (x.consume_front("baud=")) {
812349cc55cSDimitry Andric       unsigned int baud_rate;
813349cc55cSDimitry Andric       if (!llvm::to_integer(x, baud_rate, 10))
814349cc55cSDimitry Andric         return llvm::createStringError(llvm::inconvertibleErrorCode(),
815349cc55cSDimitry Andric                                        "Invalid baud rate: %s",
816349cc55cSDimitry Andric                                        x.str().c_str());
817349cc55cSDimitry Andric       serial_options.BaudRate = baud_rate;
818349cc55cSDimitry Andric     } else if (x.consume_front("parity=")) {
819349cc55cSDimitry Andric       serial_options.Parity =
820bdd1243dSDimitry Andric           llvm::StringSwitch<std::optional<Terminal::Parity>>(x)
821349cc55cSDimitry Andric               .Case("no", Terminal::Parity::No)
822349cc55cSDimitry Andric               .Case("even", Terminal::Parity::Even)
823349cc55cSDimitry Andric               .Case("odd", Terminal::Parity::Odd)
824349cc55cSDimitry Andric               .Case("mark", Terminal::Parity::Mark)
825349cc55cSDimitry Andric               .Case("space", Terminal::Parity::Space)
826bdd1243dSDimitry Andric               .Default(std::nullopt);
827349cc55cSDimitry Andric       if (!serial_options.Parity)
828349cc55cSDimitry Andric         return llvm::createStringError(
829349cc55cSDimitry Andric             llvm::inconvertibleErrorCode(),
830349cc55cSDimitry Andric             "Invalid parity (must be no, even, odd, mark or space): %s",
831349cc55cSDimitry Andric             x.str().c_str());
832349cc55cSDimitry Andric     } else if (x.consume_front("parity-check=")) {
833349cc55cSDimitry Andric       serial_options.ParityCheck =
834bdd1243dSDimitry Andric           llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)
835349cc55cSDimitry Andric               .Case("no", Terminal::ParityCheck::No)
836349cc55cSDimitry Andric               .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
837349cc55cSDimitry Andric               .Case("ignore", Terminal::ParityCheck::Ignore)
838349cc55cSDimitry Andric               // "mark" mode is not currently supported as it requires special
839349cc55cSDimitry Andric               // input processing
840349cc55cSDimitry Andric               // .Case("mark", Terminal::ParityCheck::Mark)
841bdd1243dSDimitry Andric               .Default(std::nullopt);
842349cc55cSDimitry Andric       if (!serial_options.ParityCheck)
843349cc55cSDimitry Andric         return llvm::createStringError(
844349cc55cSDimitry Andric             llvm::inconvertibleErrorCode(),
845349cc55cSDimitry Andric             "Invalid parity-check (must be no, replace, ignore or mark): %s",
846349cc55cSDimitry Andric             x.str().c_str());
847349cc55cSDimitry Andric     } else if (x.consume_front("stop-bits=")) {
848349cc55cSDimitry Andric       unsigned int stop_bits;
849349cc55cSDimitry Andric       if (!llvm::to_integer(x, stop_bits, 10) ||
850349cc55cSDimitry Andric           (stop_bits != 1 && stop_bits != 2))
851349cc55cSDimitry Andric         return llvm::createStringError(
852349cc55cSDimitry Andric             llvm::inconvertibleErrorCode(),
853349cc55cSDimitry Andric             "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
854349cc55cSDimitry Andric       serial_options.StopBits = stop_bits;
855349cc55cSDimitry Andric     } else
856349cc55cSDimitry Andric       return llvm::createStringError(llvm::inconvertibleErrorCode(),
857349cc55cSDimitry Andric                                      "Unknown parameter: %s", x.str().c_str());
858349cc55cSDimitry Andric   }
859349cc55cSDimitry Andric   return serial_options;
860349cc55cSDimitry Andric }
861349cc55cSDimitry Andric 
862349cc55cSDimitry Andric llvm::Expected<std::unique_ptr<SerialPort>>
Create(int fd,OpenOptions options,Options serial_options,bool transfer_ownership)863349cc55cSDimitry Andric SerialPort::Create(int fd, OpenOptions options, Options serial_options,
864349cc55cSDimitry Andric                    bool transfer_ownership) {
865349cc55cSDimitry Andric   std::unique_ptr<SerialPort> out{
866349cc55cSDimitry Andric       new SerialPort(fd, options, serial_options, transfer_ownership)};
867349cc55cSDimitry Andric 
868349cc55cSDimitry Andric   if (!out->GetIsInteractive())
869349cc55cSDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
870349cc55cSDimitry Andric                                    "the specified file is not a teletype");
871349cc55cSDimitry Andric 
872349cc55cSDimitry Andric   Terminal term{fd};
873349cc55cSDimitry Andric   if (llvm::Error error = term.SetRaw())
874349cc55cSDimitry Andric     return std::move(error);
875349cc55cSDimitry Andric   if (serial_options.BaudRate) {
876bdd1243dSDimitry Andric     if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))
877349cc55cSDimitry Andric       return std::move(error);
878349cc55cSDimitry Andric   }
879349cc55cSDimitry Andric   if (serial_options.Parity) {
880bdd1243dSDimitry Andric     if (llvm::Error error = term.SetParity(*serial_options.Parity))
881349cc55cSDimitry Andric       return std::move(error);
882349cc55cSDimitry Andric   }
883349cc55cSDimitry Andric   if (serial_options.ParityCheck) {
884bdd1243dSDimitry Andric     if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))
885349cc55cSDimitry Andric       return std::move(error);
886349cc55cSDimitry Andric   }
887349cc55cSDimitry Andric   if (serial_options.StopBits) {
888bdd1243dSDimitry Andric     if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))
889349cc55cSDimitry Andric       return std::move(error);
890349cc55cSDimitry Andric   }
891349cc55cSDimitry Andric 
892349cc55cSDimitry Andric   return std::move(out);
893349cc55cSDimitry Andric }
894349cc55cSDimitry Andric 
SerialPort(int fd,OpenOptions options,SerialPort::Options serial_options,bool transfer_ownership)895349cc55cSDimitry Andric SerialPort::SerialPort(int fd, OpenOptions options,
896349cc55cSDimitry Andric                        SerialPort::Options serial_options,
897349cc55cSDimitry Andric                        bool transfer_ownership)
898349cc55cSDimitry Andric     : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
899349cc55cSDimitry Andric 
Close()900349cc55cSDimitry Andric Status SerialPort::Close() {
901349cc55cSDimitry Andric   m_state.Restore();
902349cc55cSDimitry Andric   return NativeFile::Close();
903349cc55cSDimitry Andric }
904349cc55cSDimitry Andric 
9059dba64beSDimitry Andric char File::ID = 0;
9069dba64beSDimitry Andric char NativeFile::ID = 0;
907349cc55cSDimitry Andric char SerialPort::ID = 0;
908