180814287SRaphael Isemann //===-- File.cpp ----------------------------------------------------------===//
2504f89a7SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6504f89a7SGreg Clayton //
7504f89a7SGreg Clayton //===----------------------------------------------------------------------===//
8504f89a7SGreg Clayton 
9504f89a7SGreg Clayton #include "lldb/Host/File.h"
10504f89a7SGreg Clayton 
1176e47d48SRaphael Isemann #include <cerrno>
1276e47d48SRaphael Isemann #include <climits>
1376e47d48SRaphael Isemann #include <cstdarg>
1476e47d48SRaphael Isemann #include <cstdio>
15504f89a7SGreg Clayton #include <fcntl.h>
16504f89a7SGreg Clayton 
17b2f1fb29SVirgile Bello #ifdef _WIN32
18b2f1fb29SVirgile Bello #include "lldb/Host/windows/windows.h"
1994667bcfSDeepak Panickal #else
2094667bcfSDeepak Panickal #include <sys/ioctl.h>
215821a3bfSZachary Turner #include <sys/stat.h>
22b8ad0155SPavel Labath #include <termios.h>
23b6dbe9a9SPavel Labath #include <unistd.h>
24b2f1fb29SVirgile Bello #endif
25b2f1fb29SVirgile Bello 
26925137cfSGreg Clayton #include "lldb/Host/Config.h"
27d7c2b798SJonas Devlieghere #include "lldb/Host/FileSystem.h"
28c1a6b128SPavel Labath #include "lldb/Host/Host.h"
29666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
305713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
316f9e6901SZachary Turner #include "lldb/Utility/Log.h"
321410a486SPavel Labath #include "lldb/Utility/VASPrintf.h"
331410a486SPavel Labath #include "llvm/Support/ConvertUTF.h"
341410a486SPavel Labath #include "llvm/Support/Errno.h"
351410a486SPavel Labath #include "llvm/Support/FileSystem.h"
361410a486SPavel Labath #include "llvm/Support/Process.h"
37504f89a7SGreg Clayton 
38504f89a7SGreg Clayton using namespace lldb;
39504f89a7SGreg Clayton using namespace lldb_private;
4062c9fe42SLawrence D'Anna using llvm::Expected;
41504f89a7SGreg Clayton 
42d9b553ecSLawrence D'Anna Expected<const char *>
GetStreamOpenModeFromOptions(File::OpenOptions options)43d9b553ecSLawrence D'Anna File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
4414735cabSMichał Górny   File::OpenOptions rw =
4514735cabSMichał Górny       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
4614735cabSMichał Górny                  File::eOpenOptionReadWrite);
4714735cabSMichał Górny 
48b9c1b51eSKate Stone   if (options & File::eOpenOptionAppend) {
4914735cabSMichał Górny     if (rw == File::eOpenOptionReadWrite) {
5051b1e2d2SGreg Clayton       if (options & File::eOpenOptionCanCreateNewOnly)
5151b1e2d2SGreg Clayton         return "a+x";
5251b1e2d2SGreg Clayton       else
5351b1e2d2SGreg Clayton         return "a+";
5414735cabSMichał Górny     } else if (rw == File::eOpenOptionWriteOnly) {
5551b1e2d2SGreg Clayton       if (options & File::eOpenOptionCanCreateNewOnly)
5651b1e2d2SGreg Clayton         return "ax";
5751b1e2d2SGreg Clayton       else
5851b1e2d2SGreg Clayton         return "a";
5951b1e2d2SGreg Clayton     }
6014735cabSMichał Górny   } else if (rw == File::eOpenOptionReadWrite) {
61b9c1b51eSKate Stone     if (options & File::eOpenOptionCanCreate) {
6251b1e2d2SGreg Clayton       if (options & File::eOpenOptionCanCreateNewOnly)
6351b1e2d2SGreg Clayton         return "w+x";
6451b1e2d2SGreg Clayton       else
6551b1e2d2SGreg Clayton         return "w+";
66b9c1b51eSKate Stone     } else
6751b1e2d2SGreg Clayton       return "r+";
6814735cabSMichał Górny   } else if (rw == File::eOpenOptionWriteOnly) {
6951b1e2d2SGreg Clayton     return "w";
7014735cabSMichał Górny   } else if (rw == File::eOpenOptionReadOnly) {
7114735cabSMichał Górny     return "r";
7251b1e2d2SGreg Clayton   }
7362c9fe42SLawrence D'Anna   return llvm::createStringError(
7462c9fe42SLawrence D'Anna       llvm::inconvertibleErrorCode(),
7562c9fe42SLawrence D'Anna       "invalid options, cannot convert to mode string");
7651b1e2d2SGreg Clayton }
7751b1e2d2SGreg Clayton 
GetOptionsFromMode(llvm::StringRef mode)7862c9fe42SLawrence D'Anna Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
7962c9fe42SLawrence D'Anna   OpenOptions opts =
8062c9fe42SLawrence D'Anna       llvm::StringSwitch<OpenOptions>(mode)
8114735cabSMichał Górny           .Cases("r", "rb", eOpenOptionReadOnly)
8214735cabSMichał Górny           .Cases("w", "wb", eOpenOptionWriteOnly)
83342b1b2eSPavel Labath           .Cases("a", "ab",
8414735cabSMichał Górny                  eOpenOptionWriteOnly | eOpenOptionAppend |
8514735cabSMichał Górny                  eOpenOptionCanCreate)
8614735cabSMichał Górny           .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
87342b1b2eSPavel Labath           .Cases("w+", "wb+", "w+b",
8814735cabSMichał Górny                  eOpenOptionReadWrite | eOpenOptionCanCreate |
89342b1b2eSPavel Labath                  eOpenOptionTruncate)
90342b1b2eSPavel Labath           .Cases("a+", "ab+", "a+b",
9114735cabSMichał Górny                  eOpenOptionReadWrite | eOpenOptionAppend |
92342b1b2eSPavel Labath                      eOpenOptionCanCreate)
938bbef4f9SMichał Górny           .Default(eOpenOptionInvalid);
948bbef4f9SMichał Górny   if (opts != eOpenOptionInvalid)
9562c9fe42SLawrence D'Anna     return opts;
9662c9fe42SLawrence D'Anna   return llvm::createStringError(
9762c9fe42SLawrence D'Anna       llvm::inconvertibleErrorCode(),
9862c9fe42SLawrence D'Anna       "invalid mode, cannot convert to File::OpenOptions");
9957504530SLawrence D'Anna }
10057504530SLawrence D'Anna 
10151b1e2d2SGreg Clayton int File::kInvalidDescriptor = -1;
102248a1305SKonrad Kleine FILE *File::kInvalidStream = nullptr;
10351b1e2d2SGreg Clayton 
Read(void * buf,size_t & num_bytes)104f913fd6eSLawrence D'Anna Status File::Read(void *buf, size_t &num_bytes) {
105f913fd6eSLawrence D'Anna   return std::error_code(ENOTSUP, std::system_category());
106f913fd6eSLawrence D'Anna }
Write(const void * buf,size_t & num_bytes)107f913fd6eSLawrence D'Anna Status File::Write(const void *buf, size_t &num_bytes) {
108f913fd6eSLawrence D'Anna   return std::error_code(ENOTSUP, std::system_category());
109f913fd6eSLawrence D'Anna }
110504f89a7SGreg Clayton 
IsValid() const111f913fd6eSLawrence D'Anna bool File::IsValid() const { return false; }
112f913fd6eSLawrence D'Anna 
Close()113f913fd6eSLawrence D'Anna Status File::Close() { return Flush(); }
114f913fd6eSLawrence D'Anna 
GetWaitableHandle()115f913fd6eSLawrence D'Anna IOObject::WaitableHandle File::GetWaitableHandle() {
116f913fd6eSLawrence D'Anna   return IOObject::kInvalidHandleValue;
117f913fd6eSLawrence D'Anna }
118f913fd6eSLawrence D'Anna 
GetFileSpec(FileSpec & file_spec) const119f913fd6eSLawrence D'Anna Status File::GetFileSpec(FileSpec &file_spec) const {
120f913fd6eSLawrence D'Anna   file_spec.Clear();
121f913fd6eSLawrence D'Anna   return std::error_code(ENOTSUP, std::system_category());
122f913fd6eSLawrence D'Anna }
123f913fd6eSLawrence D'Anna 
GetDescriptor() const124f913fd6eSLawrence D'Anna int File::GetDescriptor() const { return kInvalidDescriptor; }
125f913fd6eSLawrence D'Anna 
GetStream()126f913fd6eSLawrence D'Anna FILE *File::GetStream() { return nullptr; }
127f913fd6eSLawrence D'Anna 
SeekFromStart(off_t offset,Status * error_ptr)128f913fd6eSLawrence D'Anna off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
129f913fd6eSLawrence D'Anna   if (error_ptr)
130f913fd6eSLawrence D'Anna     *error_ptr = std::error_code(ENOTSUP, std::system_category());
131f913fd6eSLawrence D'Anna   return -1;
132f913fd6eSLawrence D'Anna }
133f913fd6eSLawrence D'Anna 
SeekFromCurrent(off_t offset,Status * error_ptr)134f913fd6eSLawrence D'Anna off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
135f913fd6eSLawrence D'Anna   if (error_ptr)
136f913fd6eSLawrence D'Anna     *error_ptr = std::error_code(ENOTSUP, std::system_category());
137f913fd6eSLawrence D'Anna   return -1;
138f913fd6eSLawrence D'Anna }
139f913fd6eSLawrence D'Anna 
SeekFromEnd(off_t offset,Status * error_ptr)140f913fd6eSLawrence D'Anna off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
141f913fd6eSLawrence D'Anna   if (error_ptr)
142f913fd6eSLawrence D'Anna     *error_ptr = std::error_code(ENOTSUP, std::system_category());
143f913fd6eSLawrence D'Anna   return -1;
144f913fd6eSLawrence D'Anna }
145f913fd6eSLawrence D'Anna 
Read(void * dst,size_t & num_bytes,off_t & offset)146f913fd6eSLawrence D'Anna Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
147f913fd6eSLawrence D'Anna   return std::error_code(ENOTSUP, std::system_category());
148f913fd6eSLawrence D'Anna }
149f913fd6eSLawrence D'Anna 
Write(const void * src,size_t & num_bytes,off_t & offset)150f913fd6eSLawrence D'Anna Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
151f913fd6eSLawrence D'Anna   return std::error_code(ENOTSUP, std::system_category());
152f913fd6eSLawrence D'Anna }
153f913fd6eSLawrence D'Anna 
Flush()154f913fd6eSLawrence D'Anna Status File::Flush() { return Status(); }
155f913fd6eSLawrence D'Anna 
Sync()156f913fd6eSLawrence D'Anna Status File::Sync() { return Flush(); }
157f913fd6eSLawrence D'Anna 
CalculateInteractiveAndTerminal()158f913fd6eSLawrence D'Anna void File::CalculateInteractiveAndTerminal() {
159f913fd6eSLawrence D'Anna   const int fd = GetDescriptor();
160f913fd6eSLawrence D'Anna   if (!DescriptorIsValid(fd)) {
161f913fd6eSLawrence D'Anna     m_is_interactive = eLazyBoolNo;
162f913fd6eSLawrence D'Anna     m_is_real_terminal = eLazyBoolNo;
163f913fd6eSLawrence D'Anna     m_supports_colors = eLazyBoolNo;
164f913fd6eSLawrence D'Anna     return;
165f913fd6eSLawrence D'Anna   }
166f913fd6eSLawrence D'Anna   m_is_interactive = eLazyBoolNo;
167f913fd6eSLawrence D'Anna   m_is_real_terminal = eLazyBoolNo;
168f913fd6eSLawrence D'Anna #if defined(_WIN32)
169f913fd6eSLawrence D'Anna   if (_isatty(fd)) {
170f913fd6eSLawrence D'Anna     m_is_interactive = eLazyBoolYes;
171f913fd6eSLawrence D'Anna     m_is_real_terminal = eLazyBoolYes;
172f913fd6eSLawrence D'Anna #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
173f913fd6eSLawrence D'Anna     m_supports_colors = eLazyBoolYes;
174f913fd6eSLawrence D'Anna #endif
175f913fd6eSLawrence D'Anna   }
176f913fd6eSLawrence D'Anna #else
177f913fd6eSLawrence D'Anna   if (isatty(fd)) {
178f913fd6eSLawrence D'Anna     m_is_interactive = eLazyBoolYes;
179f913fd6eSLawrence D'Anna     struct winsize window_size;
180f913fd6eSLawrence D'Anna     if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
181f913fd6eSLawrence D'Anna       if (window_size.ws_col > 0) {
182f913fd6eSLawrence D'Anna         m_is_real_terminal = eLazyBoolYes;
183f913fd6eSLawrence D'Anna         if (llvm::sys::Process::FileDescriptorHasColors(fd))
184f913fd6eSLawrence D'Anna           m_supports_colors = eLazyBoolYes;
185f913fd6eSLawrence D'Anna       }
186f913fd6eSLawrence D'Anna     }
187f913fd6eSLawrence D'Anna   }
188f913fd6eSLawrence D'Anna #endif
189f913fd6eSLawrence D'Anna }
190f913fd6eSLawrence D'Anna 
GetIsInteractive()191f913fd6eSLawrence D'Anna bool File::GetIsInteractive() {
192f913fd6eSLawrence D'Anna   if (m_is_interactive == eLazyBoolCalculate)
193f913fd6eSLawrence D'Anna     CalculateInteractiveAndTerminal();
194f913fd6eSLawrence D'Anna   return m_is_interactive == eLazyBoolYes;
195f913fd6eSLawrence D'Anna }
196f913fd6eSLawrence D'Anna 
GetIsRealTerminal()197f913fd6eSLawrence D'Anna bool File::GetIsRealTerminal() {
198f913fd6eSLawrence D'Anna   if (m_is_real_terminal == eLazyBoolCalculate)
199f913fd6eSLawrence D'Anna     CalculateInteractiveAndTerminal();
200f913fd6eSLawrence D'Anna   return m_is_real_terminal == eLazyBoolYes;
201f913fd6eSLawrence D'Anna }
202f913fd6eSLawrence D'Anna 
GetIsTerminalWithColors()203f913fd6eSLawrence D'Anna bool File::GetIsTerminalWithColors() {
204f913fd6eSLawrence D'Anna   if (m_supports_colors == eLazyBoolCalculate)
205f913fd6eSLawrence D'Anna     CalculateInteractiveAndTerminal();
206f913fd6eSLawrence D'Anna   return m_supports_colors == eLazyBoolYes;
207f913fd6eSLawrence D'Anna }
208f913fd6eSLawrence D'Anna 
Printf(const char * format,...)209f913fd6eSLawrence D'Anna size_t File::Printf(const char *format, ...) {
210f913fd6eSLawrence D'Anna   va_list args;
211f913fd6eSLawrence D'Anna   va_start(args, format);
212f913fd6eSLawrence D'Anna   size_t result = PrintfVarArg(format, args);
213f913fd6eSLawrence D'Anna   va_end(args);
214f913fd6eSLawrence D'Anna   return result;
215f913fd6eSLawrence D'Anna }
216f913fd6eSLawrence D'Anna 
PrintfVarArg(const char * format,va_list args)217f913fd6eSLawrence D'Anna size_t File::PrintfVarArg(const char *format, va_list args) {
2181410a486SPavel Labath   llvm::SmallString<0> s;
2191410a486SPavel Labath   if (VASprintf(s, format, args)) {
2201410a486SPavel Labath     size_t written = s.size();;
2211410a486SPavel Labath     Write(s.data(), written);
2221410a486SPavel Labath     return written;
223f913fd6eSLawrence D'Anna   }
2241410a486SPavel Labath   return 0;
225f913fd6eSLawrence D'Anna }
226f913fd6eSLawrence D'Anna 
GetOptions() const227d9b553ecSLawrence D'Anna Expected<File::OpenOptions> File::GetOptions() const {
228d9b553ecSLawrence D'Anna   return llvm::createStringError(
229d9b553ecSLawrence D'Anna       llvm::inconvertibleErrorCode(),
230d9b553ecSLawrence D'Anna       "GetOptions() not implemented for this File class");
231d9b553ecSLawrence D'Anna }
232d9b553ecSLawrence D'Anna 
GetPermissions(Status & error) const233f913fd6eSLawrence D'Anna uint32_t File::GetPermissions(Status &error) const {
234f913fd6eSLawrence D'Anna   int fd = GetDescriptor();
235f913fd6eSLawrence D'Anna   if (!DescriptorIsValid(fd)) {
236f913fd6eSLawrence D'Anna     error = std::error_code(ENOTSUP, std::system_category());
237f913fd6eSLawrence D'Anna     return 0;
238f913fd6eSLawrence D'Anna   }
239f913fd6eSLawrence D'Anna   struct stat file_stats;
240f913fd6eSLawrence D'Anna   if (::fstat(fd, &file_stats) == -1) {
241f913fd6eSLawrence D'Anna     error.SetErrorToErrno();
242f913fd6eSLawrence D'Anna     return 0;
243f913fd6eSLawrence D'Anna   }
244f913fd6eSLawrence D'Anna   error.Clear();
245f913fd6eSLawrence D'Anna   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
246f913fd6eSLawrence D'Anna }
247f913fd6eSLawrence D'Anna 
GetOptions() const248d9b553ecSLawrence D'Anna Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
249d9b553ecSLawrence D'Anna 
GetDescriptor() const250f913fd6eSLawrence D'Anna int NativeFile::GetDescriptor() const {
25151b1e2d2SGreg Clayton   if (DescriptorIsValid())
25251b1e2d2SGreg Clayton     return m_descriptor;
25351b1e2d2SGreg Clayton 
25451b1e2d2SGreg Clayton   // Don't open the file descriptor if we don't need to, just get it from the
25551b1e2d2SGreg Clayton   // stream if we have one.
256b9c1b51eSKate Stone   if (StreamIsValid()) {
257b1cb0b79SNico Weber #if defined(_WIN32)
2589c40264fSZachary Turner     return _fileno(m_stream);
2599c40264fSZachary Turner #else
26051b1e2d2SGreg Clayton     return fileno(m_stream);
2619c40264fSZachary Turner #endif
2629c40264fSZachary Turner   }
26351b1e2d2SGreg Clayton 
26451b1e2d2SGreg Clayton   // Invalid descriptor and invalid stream, return invalid descriptor.
26551b1e2d2SGreg Clayton   return kInvalidDescriptor;
26651b1e2d2SGreg Clayton }
26751b1e2d2SGreg Clayton 
GetWaitableHandle()268f913fd6eSLawrence D'Anna IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
269f913fd6eSLawrence D'Anna   return GetDescriptor();
270f913fd6eSLawrence D'Anna }
27198688922SZachary Turner 
GetStream()272f913fd6eSLawrence D'Anna FILE *NativeFile::GetStream() {
273b9c1b51eSKate Stone   if (!StreamIsValid()) {
274b9c1b51eSKate Stone     if (DescriptorIsValid()) {
27562c9fe42SLawrence D'Anna       auto mode = GetStreamOpenModeFromOptions(m_options);
27662c9fe42SLawrence D'Anna       if (!mode)
27762c9fe42SLawrence D'Anna         llvm::consumeError(mode.takeError());
27862c9fe42SLawrence D'Anna       else {
27911751271SLawrence D'Anna         if (!m_own_descriptor) {
28005097246SAdrian Prantl // We must duplicate the file descriptor if we don't own it because when you
28105097246SAdrian Prantl // call fdopen, the stream will own the fd
28244d93782SGreg Clayton #ifdef _WIN32
28344d93782SGreg Clayton           m_descriptor = ::_dup(GetDescriptor());
28444d93782SGreg Clayton #else
28535e06390SEnrico Granata           m_descriptor = dup(GetDescriptor());
28644d93782SGreg Clayton #endif
28711751271SLawrence D'Anna           m_own_descriptor = true;
28844d93782SGreg Clayton         }
28944d93782SGreg Clayton 
29062c9fe42SLawrence D'Anna         m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
29162c9fe42SLawrence D'Anna                                                mode.get());
29244d93782SGreg Clayton 
29305097246SAdrian Prantl         // If we got a stream, then we own the stream and should no longer own
29405097246SAdrian Prantl         // the descriptor because fclose() will close it for us
29544d93782SGreg Clayton 
296b9c1b51eSKate Stone         if (m_stream) {
29744d93782SGreg Clayton           m_own_stream = true;
29811751271SLawrence D'Anna           m_own_descriptor = false;
29944d93782SGreg Clayton         }
30096c09687SGreg Clayton       }
30151b1e2d2SGreg Clayton     }
30251b1e2d2SGreg Clayton   }
30351b1e2d2SGreg Clayton   return m_stream;
30451b1e2d2SGreg Clayton }
30551b1e2d2SGreg Clayton 
Close()306f913fd6eSLawrence D'Anna Status NativeFile::Close() {
30797206d57SZachary Turner   Status error;
30857504530SLawrence D'Anna   if (StreamIsValid()) {
30957504530SLawrence D'Anna     if (m_own_stream) {
31051b1e2d2SGreg Clayton       if (::fclose(m_stream) == EOF)
311504f89a7SGreg Clayton         error.SetErrorToErrno();
31214735cabSMichał Górny     } else {
31314735cabSMichał Górny       File::OpenOptions rw =
31414735cabSMichał Górny           m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
31514735cabSMichał Górny                        File::eOpenOptionReadWrite);
31614735cabSMichał Górny 
31714735cabSMichał Górny       if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
31857504530SLawrence D'Anna         if (::fflush(m_stream) == EOF)
31957504530SLawrence D'Anna           error.SetErrorToErrno();
32057504530SLawrence D'Anna       }
32151b1e2d2SGreg Clayton     }
32214735cabSMichał Górny   }
32311751271SLawrence D'Anna   if (DescriptorIsValid() && m_own_descriptor) {
32451b1e2d2SGreg Clayton     if (::close(m_descriptor) != 0)
32551b1e2d2SGreg Clayton       error.SetErrorToErrno();
32651b1e2d2SGreg Clayton   }
32751b1e2d2SGreg Clayton   m_descriptor = kInvalidDescriptor;
32851b1e2d2SGreg Clayton   m_stream = kInvalidStream;
32962c9fe42SLawrence D'Anna   m_options = OpenOptions(0);
33044d93782SGreg Clayton   m_own_stream = false;
33111751271SLawrence D'Anna   m_own_descriptor = false;
332340b0309SGreg Clayton   m_is_interactive = eLazyBoolCalculate;
333340b0309SGreg Clayton   m_is_real_terminal = eLazyBoolCalculate;
334504f89a7SGreg Clayton   return error;
335504f89a7SGreg Clayton }
336504f89a7SGreg Clayton 
GetFileSpec(FileSpec & file_spec) const337f913fd6eSLawrence D'Anna Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
33897206d57SZachary Turner   Status error;
339b90bee04SChris Bieneman #ifdef F_GETPATH
340b9c1b51eSKate Stone   if (IsValid()) {
341968fa38eSGreg Clayton     char path[PATH_MAX];
34251b1e2d2SGreg Clayton     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
343968fa38eSGreg Clayton       error.SetErrorToErrno();
344968fa38eSGreg Clayton     else
3458f3be7a3SJonas Devlieghere       file_spec.SetFile(path, FileSpec::Style::native);
346b9c1b51eSKate Stone   } else {
347968fa38eSGreg Clayton     error.SetErrorString("invalid file handle");
348925137cfSGreg Clayton   }
34994d08626SGreg Clayton #elif defined(__linux__)
35094d08626SGreg Clayton   char proc[64];
35194d08626SGreg Clayton   char path[PATH_MAX];
35294d08626SGreg Clayton   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
35386edbf41SGreg Clayton     error.SetErrorString("cannot resolve file descriptor");
354b9c1b51eSKate Stone   else {
35594d08626SGreg Clayton     ssize_t len;
35694d08626SGreg Clayton     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
35794d08626SGreg Clayton       error.SetErrorToErrno();
358b9c1b51eSKate Stone     else {
35994d08626SGreg Clayton       path[len] = '\0';
3608f3be7a3SJonas Devlieghere       file_spec.SetFile(path, FileSpec::Style::native);
36194d08626SGreg Clayton     }
36294d08626SGreg Clayton   }
363925137cfSGreg Clayton #else
364f913fd6eSLawrence D'Anna   error.SetErrorString(
365f913fd6eSLawrence D'Anna       "NativeFile::GetFileSpec is not supported on this platform");
366925137cfSGreg Clayton #endif
367968fa38eSGreg Clayton 
368968fa38eSGreg Clayton   if (error.Fail())
369968fa38eSGreg Clayton     file_spec.Clear();
370968fa38eSGreg Clayton   return error;
371968fa38eSGreg Clayton }
372968fa38eSGreg Clayton 
SeekFromStart(off_t offset,Status * error_ptr)373f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
37443d8279fSGreg Clayton   off_t result = 0;
375b9c1b51eSKate Stone   if (DescriptorIsValid()) {
37643d8279fSGreg Clayton     result = ::lseek(m_descriptor, offset, SEEK_SET);
377968fa38eSGreg Clayton 
378b9c1b51eSKate Stone     if (error_ptr) {
37943d8279fSGreg Clayton       if (result == -1)
38043d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
381968fa38eSGreg Clayton       else
38243d8279fSGreg Clayton         error_ptr->Clear();
383968fa38eSGreg Clayton     }
384b9c1b51eSKate Stone   } else if (StreamIsValid()) {
38543d8279fSGreg Clayton     result = ::fseek(m_stream, offset, SEEK_SET);
38643d8279fSGreg Clayton 
387b9c1b51eSKate Stone     if (error_ptr) {
38843d8279fSGreg Clayton       if (result == -1)
38943d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
39043d8279fSGreg Clayton       else
39143d8279fSGreg Clayton         error_ptr->Clear();
39243d8279fSGreg Clayton     }
393b9c1b51eSKate Stone   } else if (error_ptr) {
39443d8279fSGreg Clayton     error_ptr->SetErrorString("invalid file handle");
39543d8279fSGreg Clayton   }
39643d8279fSGreg Clayton   return result;
397968fa38eSGreg Clayton }
398968fa38eSGreg Clayton 
SeekFromCurrent(off_t offset,Status * error_ptr)399f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
40043d8279fSGreg Clayton   off_t result = -1;
401b9c1b51eSKate Stone   if (DescriptorIsValid()) {
40243d8279fSGreg Clayton     result = ::lseek(m_descriptor, offset, SEEK_CUR);
403968fa38eSGreg Clayton 
404b9c1b51eSKate Stone     if (error_ptr) {
40543d8279fSGreg Clayton       if (result == -1)
40643d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
407968fa38eSGreg Clayton       else
40843d8279fSGreg Clayton         error_ptr->Clear();
409968fa38eSGreg Clayton     }
410b9c1b51eSKate Stone   } else if (StreamIsValid()) {
41143d8279fSGreg Clayton     result = ::fseek(m_stream, offset, SEEK_CUR);
41243d8279fSGreg Clayton 
413b9c1b51eSKate Stone     if (error_ptr) {
41443d8279fSGreg Clayton       if (result == -1)
41543d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
41643d8279fSGreg Clayton       else
41743d8279fSGreg Clayton         error_ptr->Clear();
41843d8279fSGreg Clayton     }
419b9c1b51eSKate Stone   } else if (error_ptr) {
42043d8279fSGreg Clayton     error_ptr->SetErrorString("invalid file handle");
42143d8279fSGreg Clayton   }
42243d8279fSGreg Clayton   return result;
423968fa38eSGreg Clayton }
424968fa38eSGreg Clayton 
SeekFromEnd(off_t offset,Status * error_ptr)425f913fd6eSLawrence D'Anna off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
42643d8279fSGreg Clayton   off_t result = -1;
427b9c1b51eSKate Stone   if (DescriptorIsValid()) {
42843d8279fSGreg Clayton     result = ::lseek(m_descriptor, offset, SEEK_END);
429968fa38eSGreg Clayton 
430b9c1b51eSKate Stone     if (error_ptr) {
43143d8279fSGreg Clayton       if (result == -1)
43243d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
43343d8279fSGreg Clayton       else
43443d8279fSGreg Clayton         error_ptr->Clear();
435968fa38eSGreg Clayton     }
436b9c1b51eSKate Stone   } else if (StreamIsValid()) {
43743d8279fSGreg Clayton     result = ::fseek(m_stream, offset, SEEK_END);
43843d8279fSGreg Clayton 
439b9c1b51eSKate Stone     if (error_ptr) {
44043d8279fSGreg Clayton       if (result == -1)
44143d8279fSGreg Clayton         error_ptr->SetErrorToErrno();
44243d8279fSGreg Clayton       else
44343d8279fSGreg Clayton         error_ptr->Clear();
44443d8279fSGreg Clayton     }
445b9c1b51eSKate Stone   } else if (error_ptr) {
44643d8279fSGreg Clayton     error_ptr->SetErrorString("invalid file handle");
44743d8279fSGreg Clayton   }
44843d8279fSGreg Clayton   return result;
449968fa38eSGreg Clayton }
450968fa38eSGreg Clayton 
Flush()451f913fd6eSLawrence D'Anna Status NativeFile::Flush() {
45297206d57SZachary Turner   Status error;
453b9c1b51eSKate Stone   if (StreamIsValid()) {
454c1a6b128SPavel Labath     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
45551b1e2d2SGreg Clayton       error.SetErrorToErrno();
456b9c1b51eSKate Stone   } else if (!DescriptorIsValid()) {
45751b1e2d2SGreg Clayton     error.SetErrorString("invalid file handle");
45851b1e2d2SGreg Clayton   }
45951b1e2d2SGreg Clayton   return error;
46051b1e2d2SGreg Clayton }
46151b1e2d2SGreg Clayton 
Sync()462f913fd6eSLawrence D'Anna Status NativeFile::Sync() {
46397206d57SZachary Turner   Status error;
464b9c1b51eSKate Stone   if (DescriptorIsValid()) {
465b2f1fb29SVirgile Bello #ifdef _WIN32
466b2f1fb29SVirgile Bello     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
467b2f1fb29SVirgile Bello     if (err == 0)
468b2f1fb29SVirgile Bello       error.SetErrorToGenericError();
469b2f1fb29SVirgile Bello #else
470c1a6b128SPavel Labath     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
471968fa38eSGreg Clayton       error.SetErrorToErrno();
472b2f1fb29SVirgile Bello #endif
473b9c1b51eSKate Stone   } else {
474968fa38eSGreg Clayton     error.SetErrorString("invalid file handle");
475968fa38eSGreg Clayton   }
476968fa38eSGreg Clayton   return error;
477968fa38eSGreg Clayton }
478846b64bfSGreg Clayton 
47929aac9a5SGreg Clayton #if defined(__APPLE__)
48029aac9a5SGreg Clayton // Darwin kernels only can read/write <= INT_MAX bytes
48129aac9a5SGreg Clayton #define MAX_READ_SIZE INT_MAX
48229aac9a5SGreg Clayton #define MAX_WRITE_SIZE INT_MAX
48329aac9a5SGreg Clayton #endif
48429aac9a5SGreg Clayton 
Read(void * buf,size_t & num_bytes)485f913fd6eSLawrence D'Anna Status NativeFile::Read(void *buf, size_t &num_bytes) {
48697206d57SZachary Turner   Status error;
48729aac9a5SGreg Clayton 
48829aac9a5SGreg Clayton #if defined(MAX_READ_SIZE)
489b9c1b51eSKate Stone   if (num_bytes > MAX_READ_SIZE) {
49029aac9a5SGreg Clayton     uint8_t *p = (uint8_t *)buf;
49129aac9a5SGreg Clayton     size_t bytes_left = num_bytes;
49229aac9a5SGreg Clayton     // Init the num_bytes read to zero
49329aac9a5SGreg Clayton     num_bytes = 0;
49429aac9a5SGreg Clayton 
495b9c1b51eSKate Stone     while (bytes_left > 0) {
49629aac9a5SGreg Clayton       size_t curr_num_bytes;
49729aac9a5SGreg Clayton       if (bytes_left > MAX_READ_SIZE)
49829aac9a5SGreg Clayton         curr_num_bytes = MAX_READ_SIZE;
49929aac9a5SGreg Clayton       else
50029aac9a5SGreg Clayton         curr_num_bytes = bytes_left;
50129aac9a5SGreg Clayton 
50229aac9a5SGreg Clayton       error = Read(p + num_bytes, curr_num_bytes);
50329aac9a5SGreg Clayton 
50429aac9a5SGreg Clayton       // Update how many bytes were read
50529aac9a5SGreg Clayton       num_bytes += curr_num_bytes;
50629aac9a5SGreg Clayton       if (bytes_left < curr_num_bytes)
50729aac9a5SGreg Clayton         bytes_left = 0;
50829aac9a5SGreg Clayton       else
50929aac9a5SGreg Clayton         bytes_left -= curr_num_bytes;
51029aac9a5SGreg Clayton 
51129aac9a5SGreg Clayton       if (error.Fail())
51229aac9a5SGreg Clayton         break;
51329aac9a5SGreg Clayton     }
51429aac9a5SGreg Clayton     return error;
51529aac9a5SGreg Clayton   }
51629aac9a5SGreg Clayton #endif
51729aac9a5SGreg Clayton 
51896c09687SGreg Clayton   ssize_t bytes_read = -1;
519b9c1b51eSKate Stone   if (DescriptorIsValid()) {
520c1a6b128SPavel Labath     bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
521b9c1b51eSKate Stone     if (bytes_read == -1) {
522504f89a7SGreg Clayton       error.SetErrorToErrno();
523504f89a7SGreg Clayton       num_bytes = 0;
524b9c1b51eSKate Stone     } else
525504f89a7SGreg Clayton       num_bytes = bytes_read;
526b9c1b51eSKate Stone   } else if (StreamIsValid()) {
52796c09687SGreg Clayton     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
52896c09687SGreg Clayton 
529b9c1b51eSKate Stone     if (bytes_read == 0) {
53051b1e2d2SGreg Clayton       if (::feof(m_stream))
53151b1e2d2SGreg Clayton         error.SetErrorString("feof");
53251b1e2d2SGreg Clayton       else if (::ferror(m_stream))
53351b1e2d2SGreg Clayton         error.SetErrorString("ferror");
53451b1e2d2SGreg Clayton       num_bytes = 0;
535b9c1b51eSKate Stone     } else
53651b1e2d2SGreg Clayton       num_bytes = bytes_read;
537b9c1b51eSKate Stone   } else {
538504f89a7SGreg Clayton     num_bytes = 0;
539504f89a7SGreg Clayton     error.SetErrorString("invalid file handle");
540504f89a7SGreg Clayton   }
541504f89a7SGreg Clayton   return error;
542504f89a7SGreg Clayton }
543504f89a7SGreg Clayton 
Write(const void * buf,size_t & num_bytes)544f913fd6eSLawrence D'Anna Status NativeFile::Write(const void *buf, size_t &num_bytes) {
54597206d57SZachary Turner   Status error;
54629aac9a5SGreg Clayton 
54729aac9a5SGreg Clayton #if defined(MAX_WRITE_SIZE)
548b9c1b51eSKate Stone   if (num_bytes > MAX_WRITE_SIZE) {
54929aac9a5SGreg Clayton     const uint8_t *p = (const uint8_t *)buf;
55029aac9a5SGreg Clayton     size_t bytes_left = num_bytes;
55129aac9a5SGreg Clayton     // Init the num_bytes written to zero
55229aac9a5SGreg Clayton     num_bytes = 0;
55329aac9a5SGreg Clayton 
554b9c1b51eSKate Stone     while (bytes_left > 0) {
55529aac9a5SGreg Clayton       size_t curr_num_bytes;
55629aac9a5SGreg Clayton       if (bytes_left > MAX_WRITE_SIZE)
55729aac9a5SGreg Clayton         curr_num_bytes = MAX_WRITE_SIZE;
55829aac9a5SGreg Clayton       else
55929aac9a5SGreg Clayton         curr_num_bytes = bytes_left;
56029aac9a5SGreg Clayton 
56129aac9a5SGreg Clayton       error = Write(p + num_bytes, curr_num_bytes);
56229aac9a5SGreg Clayton 
56329aac9a5SGreg Clayton       // Update how many bytes were read
56429aac9a5SGreg Clayton       num_bytes += curr_num_bytes;
56529aac9a5SGreg Clayton       if (bytes_left < curr_num_bytes)
56629aac9a5SGreg Clayton         bytes_left = 0;
56729aac9a5SGreg Clayton       else
56829aac9a5SGreg Clayton         bytes_left -= curr_num_bytes;
56929aac9a5SGreg Clayton 
57029aac9a5SGreg Clayton       if (error.Fail())
57129aac9a5SGreg Clayton         break;
57229aac9a5SGreg Clayton     }
57329aac9a5SGreg Clayton     return error;
57429aac9a5SGreg Clayton   }
57529aac9a5SGreg Clayton #endif
57629aac9a5SGreg Clayton 
57796c09687SGreg Clayton   ssize_t bytes_written = -1;
578b9c1b51eSKate Stone   if (DescriptorIsValid()) {
579c1a6b128SPavel Labath     bytes_written =
580c1a6b128SPavel Labath         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
581b9c1b51eSKate Stone     if (bytes_written == -1) {
582504f89a7SGreg Clayton       error.SetErrorToErrno();
583504f89a7SGreg Clayton       num_bytes = 0;
584b9c1b51eSKate Stone     } else
585504f89a7SGreg Clayton       num_bytes = bytes_written;
586b9c1b51eSKate Stone   } else if (StreamIsValid()) {
58796c09687SGreg Clayton     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
58896c09687SGreg Clayton 
589b9c1b51eSKate Stone     if (bytes_written == 0) {
59051b1e2d2SGreg Clayton       if (::feof(m_stream))
59151b1e2d2SGreg Clayton         error.SetErrorString("feof");
59251b1e2d2SGreg Clayton       else if (::ferror(m_stream))
59351b1e2d2SGreg Clayton         error.SetErrorString("ferror");
59451b1e2d2SGreg Clayton       num_bytes = 0;
595b9c1b51eSKate Stone     } else
59651b1e2d2SGreg Clayton       num_bytes = bytes_written;
59751b1e2d2SGreg Clayton 
598b9c1b51eSKate Stone   } else {
599504f89a7SGreg Clayton     num_bytes = 0;
600504f89a7SGreg Clayton     error.SetErrorString("invalid file handle");
601504f89a7SGreg Clayton   }
60298688922SZachary Turner 
603504f89a7SGreg Clayton   return error;
604504f89a7SGreg Clayton }
605504f89a7SGreg Clayton 
Read(void * buf,size_t & num_bytes,off_t & offset)606f913fd6eSLawrence D'Anna Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
60797206d57SZachary Turner   Status error;
60829aac9a5SGreg Clayton 
60929aac9a5SGreg Clayton #if defined(MAX_READ_SIZE)
610b9c1b51eSKate Stone   if (num_bytes > MAX_READ_SIZE) {
61129aac9a5SGreg Clayton     uint8_t *p = (uint8_t *)buf;
61229aac9a5SGreg Clayton     size_t bytes_left = num_bytes;
61329aac9a5SGreg Clayton     // Init the num_bytes read to zero
61429aac9a5SGreg Clayton     num_bytes = 0;
61529aac9a5SGreg Clayton 
616b9c1b51eSKate Stone     while (bytes_left > 0) {
61729aac9a5SGreg Clayton       size_t curr_num_bytes;
61829aac9a5SGreg Clayton       if (bytes_left > MAX_READ_SIZE)
61929aac9a5SGreg Clayton         curr_num_bytes = MAX_READ_SIZE;
62029aac9a5SGreg Clayton       else
62129aac9a5SGreg Clayton         curr_num_bytes = bytes_left;
62229aac9a5SGreg Clayton 
62329aac9a5SGreg Clayton       error = Read(p + num_bytes, curr_num_bytes, offset);
62429aac9a5SGreg Clayton 
62529aac9a5SGreg Clayton       // Update how many bytes were read
62629aac9a5SGreg Clayton       num_bytes += curr_num_bytes;
62729aac9a5SGreg Clayton       if (bytes_left < curr_num_bytes)
62829aac9a5SGreg Clayton         bytes_left = 0;
62929aac9a5SGreg Clayton       else
63029aac9a5SGreg Clayton         bytes_left -= curr_num_bytes;
63129aac9a5SGreg Clayton 
63229aac9a5SGreg Clayton       if (error.Fail())
63329aac9a5SGreg Clayton         break;
63429aac9a5SGreg Clayton     }
63529aac9a5SGreg Clayton     return error;
63629aac9a5SGreg Clayton   }
63729aac9a5SGreg Clayton #endif
63829aac9a5SGreg Clayton 
63929aac9a5SGreg Clayton #ifndef _WIN32
64051b1e2d2SGreg Clayton   int fd = GetDescriptor();
641b9c1b51eSKate Stone   if (fd != kInvalidDescriptor) {
642c1a6b128SPavel Labath     ssize_t bytes_read =
643c1a6b128SPavel Labath         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
644b9c1b51eSKate Stone     if (bytes_read < 0) {
645846b64bfSGreg Clayton       num_bytes = 0;
646846b64bfSGreg Clayton       error.SetErrorToErrno();
647b9c1b51eSKate Stone     } else {
648846b64bfSGreg Clayton       offset += bytes_read;
649846b64bfSGreg Clayton       num_bytes = bytes_read;
650846b64bfSGreg Clayton     }
651b9c1b51eSKate Stone   } else {
652846b64bfSGreg Clayton     num_bytes = 0;
653846b64bfSGreg Clayton     error.SetErrorString("invalid file handle");
654846b64bfSGreg Clayton   }
655b2f1fb29SVirgile Bello #else
6563a142495SAaron Smith   std::lock_guard<std::mutex> guard(offset_access_mutex);
657b2f1fb29SVirgile Bello   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
658b2f1fb29SVirgile Bello   SeekFromStart(offset);
65929aac9a5SGreg Clayton   error = Read(buf, num_bytes);
660b2f1fb29SVirgile Bello   if (!error.Fail())
661b2f1fb29SVirgile Bello     SeekFromStart(cur);
662b2f1fb29SVirgile Bello #endif
66329aac9a5SGreg Clayton   return error;
664846b64bfSGreg Clayton }
665846b64bfSGreg Clayton 
Write(const void * buf,size_t & num_bytes,off_t & offset)666f913fd6eSLawrence D'Anna Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
66797206d57SZachary Turner   Status error;
6687965e545SGreg Clayton 
66929aac9a5SGreg Clayton #if defined(MAX_WRITE_SIZE)
670b9c1b51eSKate Stone   if (num_bytes > MAX_WRITE_SIZE) {
67129aac9a5SGreg Clayton     const uint8_t *p = (const uint8_t *)buf;
67229aac9a5SGreg Clayton     size_t bytes_left = num_bytes;
67329aac9a5SGreg Clayton     // Init the num_bytes written to zero
67429aac9a5SGreg Clayton     num_bytes = 0;
67529aac9a5SGreg Clayton 
676b9c1b51eSKate Stone     while (bytes_left > 0) {
67729aac9a5SGreg Clayton       size_t curr_num_bytes;
67829aac9a5SGreg Clayton       if (bytes_left > MAX_WRITE_SIZE)
67929aac9a5SGreg Clayton         curr_num_bytes = MAX_WRITE_SIZE;
68029aac9a5SGreg Clayton       else
68129aac9a5SGreg Clayton         curr_num_bytes = bytes_left;
68229aac9a5SGreg Clayton 
68329aac9a5SGreg Clayton       error = Write(p + num_bytes, curr_num_bytes, offset);
68429aac9a5SGreg Clayton 
68529aac9a5SGreg Clayton       // Update how many bytes were read
68629aac9a5SGreg Clayton       num_bytes += curr_num_bytes;
68729aac9a5SGreg Clayton       if (bytes_left < curr_num_bytes)
68829aac9a5SGreg Clayton         bytes_left = 0;
68929aac9a5SGreg Clayton       else
69029aac9a5SGreg Clayton         bytes_left -= curr_num_bytes;
69129aac9a5SGreg Clayton 
69229aac9a5SGreg Clayton       if (error.Fail())
69329aac9a5SGreg Clayton         break;
69429aac9a5SGreg Clayton     }
69529aac9a5SGreg Clayton     return error;
69629aac9a5SGreg Clayton   }
69729aac9a5SGreg Clayton #endif
69829aac9a5SGreg Clayton 
69951b1e2d2SGreg Clayton   int fd = GetDescriptor();
700b9c1b51eSKate Stone   if (fd != kInvalidDescriptor) {
701b2f1fb29SVirgile Bello #ifndef _WIN32
702c1a6b128SPavel Labath     ssize_t bytes_written =
703c1a6b128SPavel Labath         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
704b9c1b51eSKate Stone     if (bytes_written < 0) {
705846b64bfSGreg Clayton       num_bytes = 0;
706846b64bfSGreg Clayton       error.SetErrorToErrno();
707b9c1b51eSKate Stone     } else {
708846b64bfSGreg Clayton       offset += bytes_written;
709846b64bfSGreg Clayton       num_bytes = bytes_written;
710846b64bfSGreg Clayton     }
711b2f1fb29SVirgile Bello #else
7123a142495SAaron Smith     std::lock_guard<std::mutex> guard(offset_access_mutex);
713b2f1fb29SVirgile Bello     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
7143a142495SAaron Smith     SeekFromStart(offset);
715b2f1fb29SVirgile Bello     error = Write(buf, num_bytes);
716b2f1fb29SVirgile Bello     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
717b2f1fb29SVirgile Bello 
718b2f1fb29SVirgile Bello     if (!error.Fail())
719b2f1fb29SVirgile Bello       SeekFromStart(cur);
720b2f1fb29SVirgile Bello 
721b2f1fb29SVirgile Bello     offset = after;
722b2f1fb29SVirgile Bello #endif
723b9c1b51eSKate Stone   } else {
724846b64bfSGreg Clayton     num_bytes = 0;
725846b64bfSGreg Clayton     error.SetErrorString("invalid file handle");
726846b64bfSGreg Clayton   }
727846b64bfSGreg Clayton   return error;
728846b64bfSGreg Clayton }
729846b64bfSGreg Clayton 
PrintfVarArg(const char * format,va_list args)730f913fd6eSLawrence D'Anna size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
731f913fd6eSLawrence D'Anna   if (StreamIsValid()) {
732f913fd6eSLawrence D'Anna     return ::vfprintf(m_stream, format, args);
733f913fd6eSLawrence D'Anna   } else {
734f913fd6eSLawrence D'Anna     return File::PrintfVarArg(format, args);
73551b1e2d2SGreg Clayton   }
73651b1e2d2SGreg Clayton }
737e0f8f574SDaniel Malea 
ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)73862c9fe42SLawrence D'Anna mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
739e0f8f574SDaniel Malea   mode_t mode = 0;
74014735cabSMichał Górny   File::OpenOptions rw =
74114735cabSMichał Górny       open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
74214735cabSMichał Górny                       File::eOpenOptionReadWrite);
74314735cabSMichał Górny   if (rw == eOpenOptionReadWrite)
744e0f8f574SDaniel Malea     mode |= O_RDWR;
74514735cabSMichał Górny   else if (rw == eOpenOptionWriteOnly)
746e0f8f574SDaniel Malea     mode |= O_WRONLY;
74714735cabSMichał Górny   else if (rw == eOpenOptionReadOnly)
74814735cabSMichał Górny     mode |= O_RDONLY;
749e0f8f574SDaniel Malea 
750e0f8f574SDaniel Malea   if (open_options & eOpenOptionAppend)
751e0f8f574SDaniel Malea     mode |= O_APPEND;
752e0f8f574SDaniel Malea 
753e0f8f574SDaniel Malea   if (open_options & eOpenOptionTruncate)
754e0f8f574SDaniel Malea     mode |= O_TRUNC;
755e0f8f574SDaniel Malea 
756e0f8f574SDaniel Malea   if (open_options & eOpenOptionNonBlocking)
757e0f8f574SDaniel Malea     mode |= O_NONBLOCK;
758e0f8f574SDaniel Malea 
759e0f8f574SDaniel Malea   if (open_options & eOpenOptionCanCreateNewOnly)
760e0f8f574SDaniel Malea     mode |= O_CREAT | O_EXCL;
761e0f8f574SDaniel Malea   else if (open_options & eOpenOptionCanCreate)
762e0f8f574SDaniel Malea     mode |= O_CREAT;
763e0f8f574SDaniel Malea 
764e0f8f574SDaniel Malea   return mode;
765e0f8f574SDaniel Malea }
766d9b553ecSLawrence D'Anna 
7674a7b4beaSMichał Górny llvm::Expected<SerialPort::Options>
OptionsFromURL(llvm::StringRef urlqs)7684a7b4beaSMichał Górny SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
7694a7b4beaSMichał Górny   SerialPort::Options serial_options;
77066e06cc8SMichał Górny   for (llvm::StringRef x : llvm::split(urlqs, '&')) {
7714a7b4beaSMichał Górny     if (x.consume_front("baud=")) {
7724a7b4beaSMichał Górny       unsigned int baud_rate;
7734a7b4beaSMichał Górny       if (!llvm::to_integer(x, baud_rate, 10))
7744a7b4beaSMichał Górny         return llvm::createStringError(llvm::inconvertibleErrorCode(),
7754a7b4beaSMichał Górny                                        "Invalid baud rate: %s",
7764a7b4beaSMichał Górny                                        x.str().c_str());
7774a7b4beaSMichał Górny       serial_options.BaudRate = baud_rate;
7784a7b4beaSMichał Górny     } else if (x.consume_front("parity=")) {
7794a7b4beaSMichał Górny       serial_options.Parity =
7804a7b4beaSMichał Górny           llvm::StringSwitch<llvm::Optional<Terminal::Parity>>(x)
7814a7b4beaSMichał Górny               .Case("no", Terminal::Parity::No)
7824a7b4beaSMichał Górny               .Case("even", Terminal::Parity::Even)
7834a7b4beaSMichał Górny               .Case("odd", Terminal::Parity::Odd)
7844a7b4beaSMichał Górny               .Case("mark", Terminal::Parity::Mark)
7854a7b4beaSMichał Górny               .Case("space", Terminal::Parity::Space)
7864a7b4beaSMichał Górny               .Default(llvm::None);
7874a7b4beaSMichał Górny       if (!serial_options.Parity)
7884a7b4beaSMichał Górny         return llvm::createStringError(
7894a7b4beaSMichał Górny             llvm::inconvertibleErrorCode(),
7904a7b4beaSMichał Górny             "Invalid parity (must be no, even, odd, mark or space): %s",
7914a7b4beaSMichał Górny             x.str().c_str());
79221bb808eSMichał Górny     } else if (x.consume_front("parity-check=")) {
79321bb808eSMichał Górny       serial_options.ParityCheck =
79421bb808eSMichał Górny           llvm::StringSwitch<llvm::Optional<Terminal::ParityCheck>>(x)
79521bb808eSMichał Górny               .Case("no", Terminal::ParityCheck::No)
79621bb808eSMichał Górny               .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
79721bb808eSMichał Górny               .Case("ignore", Terminal::ParityCheck::Ignore)
79821bb808eSMichał Górny               // "mark" mode is not currently supported as it requires special
79921bb808eSMichał Górny               // input processing
80021bb808eSMichał Górny               // .Case("mark", Terminal::ParityCheck::Mark)
80121bb808eSMichał Górny               .Default(llvm::None);
80221bb808eSMichał Górny       if (!serial_options.ParityCheck)
80321bb808eSMichał Górny         return llvm::createStringError(
80421bb808eSMichał Górny             llvm::inconvertibleErrorCode(),
80521bb808eSMichał Górny             "Invalid parity-check (must be no, replace, ignore or mark): %s",
80621bb808eSMichał Górny             x.str().c_str());
8074a7b4beaSMichał Górny     } else if (x.consume_front("stop-bits=")) {
8084a7b4beaSMichał Górny       unsigned int stop_bits;
8094a7b4beaSMichał Górny       if (!llvm::to_integer(x, stop_bits, 10) ||
8104a7b4beaSMichał Górny           (stop_bits != 1 && stop_bits != 2))
8114a7b4beaSMichał Górny         return llvm::createStringError(
8124a7b4beaSMichał Górny             llvm::inconvertibleErrorCode(),
8134a7b4beaSMichał Górny             "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
8144a7b4beaSMichał Górny       serial_options.StopBits = stop_bits;
8154a7b4beaSMichał Górny     } else
8164a7b4beaSMichał Górny       return llvm::createStringError(llvm::inconvertibleErrorCode(),
8174a7b4beaSMichał Górny                                      "Unknown parameter: %s", x.str().c_str());
8184a7b4beaSMichał Górny   }
8194a7b4beaSMichał Górny   return serial_options;
8204a7b4beaSMichał Górny }
8214a7b4beaSMichał Górny 
8224a7b4beaSMichał Górny llvm::Expected<std::unique_ptr<SerialPort>>
Create(int fd,OpenOptions options,Options serial_options,bool transfer_ownership)8234a7b4beaSMichał Górny SerialPort::Create(int fd, OpenOptions options, Options serial_options,
8244a7b4beaSMichał Górny                    bool transfer_ownership) {
8254a7b4beaSMichał Górny   std::unique_ptr<SerialPort> out{
8264a7b4beaSMichał Górny       new SerialPort(fd, options, serial_options, transfer_ownership)};
8274a7b4beaSMichał Górny 
8284a7b4beaSMichał Górny   if (!out->GetIsInteractive())
8294a7b4beaSMichał Górny     return llvm::createStringError(llvm::inconvertibleErrorCode(),
8304a7b4beaSMichał Górny                                    "the specified file is not a teletype");
8314a7b4beaSMichał Górny 
8324a7b4beaSMichał Górny   Terminal term{fd};
8334a7b4beaSMichał Górny   if (llvm::Error error = term.SetRaw())
834b8c3683dSMichał Górny     return std::move(error);
8354a7b4beaSMichał Górny   if (serial_options.BaudRate) {
836*5cff5142SKazu Hirata     if (llvm::Error error = term.SetBaudRate(serial_options.BaudRate.value()))
837b8c3683dSMichał Górny       return std::move(error);
8384a7b4beaSMichał Górny   }
8394a7b4beaSMichał Górny   if (serial_options.Parity) {
840*5cff5142SKazu Hirata     if (llvm::Error error = term.SetParity(serial_options.Parity.value()))
841b8c3683dSMichał Górny       return std::move(error);
8424a7b4beaSMichał Górny   }
84321bb808eSMichał Górny   if (serial_options.ParityCheck) {
8443b7c3a65SKazu Hirata     if (llvm::Error error =
845*5cff5142SKazu Hirata             term.SetParityCheck(serial_options.ParityCheck.value()))
84621bb808eSMichał Górny       return std::move(error);
84721bb808eSMichał Górny   }
8484a7b4beaSMichał Górny   if (serial_options.StopBits) {
849*5cff5142SKazu Hirata     if (llvm::Error error = term.SetStopBits(serial_options.StopBits.value()))
850b8c3683dSMichał Górny       return std::move(error);
8514a7b4beaSMichał Górny   }
8524a7b4beaSMichał Górny 
853ea9e9d61SMartin Storsjö   return std::move(out);
8544a7b4beaSMichał Górny }
8554a7b4beaSMichał Górny 
SerialPort(int fd,OpenOptions options,SerialPort::Options serial_options,bool transfer_ownership)8564a7b4beaSMichał Górny SerialPort::SerialPort(int fd, OpenOptions options,
8574a7b4beaSMichał Górny                        SerialPort::Options serial_options,
8584a7b4beaSMichał Górny                        bool transfer_ownership)
8594a7b4beaSMichał Górny     : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
8604a7b4beaSMichał Górny 
Close()8614a7b4beaSMichał Górny Status SerialPort::Close() {
8624a7b4beaSMichał Górny   m_state.Restore();
8634a7b4beaSMichał Górny   return NativeFile::Close();
8644a7b4beaSMichał Górny }
8654a7b4beaSMichał Górny 
866d9b553ecSLawrence D'Anna char File::ID = 0;
867d9b553ecSLawrence D'Anna char NativeFile::ID = 0;
8684a7b4beaSMichał Górny char SerialPort::ID = 0;
869