xref: /src/contrib/llvm-project/lldb/source/Host/common/File.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1cfca06d7SDimitry Andric //===-- File.cpp ----------------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f034231aSEd Maste #include "lldb/Host/File.h"
10f034231aSEd Maste 
11344a3780SDimitry Andric #include <cerrno>
12344a3780SDimitry Andric #include <climits>
13344a3780SDimitry Andric #include <cstdarg>
14344a3780SDimitry Andric #include <cstdio>
15f034231aSEd Maste #include <fcntl.h>
16e3b55780SDimitry Andric #include <optional>
17f034231aSEd Maste 
18f21a844fSEd Maste #ifdef _WIN32
19f21a844fSEd Maste #include "lldb/Host/windows/windows.h"
20866dcdacSEd Maste #else
21866dcdacSEd Maste #include <sys/ioctl.h>
2274a628f7SDimitry Andric #include <sys/stat.h>
2374a628f7SDimitry Andric #include <termios.h>
24a884e649SDimitry Andric #include <unistd.h>
25f21a844fSEd Maste #endif
26f21a844fSEd Maste 
27f034231aSEd Maste #include "lldb/Host/Config.h"
2894994d37SDimitry Andric #include "lldb/Host/FileSystem.h"
29e75e363cSDimitry Andric #include "lldb/Host/Host.h"
3074a628f7SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
3174a628f7SDimitry Andric #include "lldb/Utility/FileSpec.h"
3274a628f7SDimitry Andric #include "lldb/Utility/Log.h"
33145449b1SDimitry Andric #include "lldb/Utility/VASPrintf.h"
347fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
35145449b1SDimitry Andric #include "llvm/Support/ConvertUTF.h"
36145449b1SDimitry Andric #include "llvm/Support/Errno.h"
37145449b1SDimitry Andric #include "llvm/Support/FileSystem.h"
38145449b1SDimitry Andric #include "llvm/Support/Process.h"
39f034231aSEd Maste 
40f034231aSEd Maste using namespace lldb;
41f034231aSEd Maste using namespace lldb_private;
42ead24645SDimitry Andric using llvm::Expected;
43f034231aSEd Maste 
44ead24645SDimitry Andric Expected<const char *>
GetStreamOpenModeFromOptions(File::OpenOptions options)45ead24645SDimitry Andric File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
46c0981da4SDimitry Andric   File::OpenOptions rw =
47c0981da4SDimitry Andric       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
48c0981da4SDimitry Andric                  File::eOpenOptionReadWrite);
49c0981da4SDimitry Andric 
5014f1b3e8SDimitry Andric   if (options & File::eOpenOptionAppend) {
51c0981da4SDimitry Andric     if (rw == File::eOpenOptionReadWrite) {
52f034231aSEd Maste       if (options & File::eOpenOptionCanCreateNewOnly)
53f034231aSEd Maste         return "a+x";
54f034231aSEd Maste       else
55f034231aSEd Maste         return "a+";
56c0981da4SDimitry Andric     } else if (rw == File::eOpenOptionWriteOnly) {
57f034231aSEd Maste       if (options & File::eOpenOptionCanCreateNewOnly)
58f034231aSEd Maste         return "ax";
59f034231aSEd Maste       else
60f034231aSEd Maste         return "a";
61f034231aSEd Maste     }
62c0981da4SDimitry Andric   } else if (rw == File::eOpenOptionReadWrite) {
6314f1b3e8SDimitry Andric     if (options & File::eOpenOptionCanCreate) {
64f034231aSEd Maste       if (options & File::eOpenOptionCanCreateNewOnly)
65f034231aSEd Maste         return "w+x";
66f034231aSEd Maste       else
67f034231aSEd Maste         return "w+";
6814f1b3e8SDimitry Andric     } else
69f034231aSEd Maste       return "r+";
70c0981da4SDimitry Andric   } else if (rw == File::eOpenOptionWriteOnly) {
71f034231aSEd Maste     return "w";
72c0981da4SDimitry Andric   } else if (rw == File::eOpenOptionReadOnly) {
73c0981da4SDimitry Andric     return "r";
74f034231aSEd Maste   }
75ead24645SDimitry Andric   return llvm::createStringError(
76ead24645SDimitry Andric       llvm::inconvertibleErrorCode(),
77ead24645SDimitry Andric       "invalid options, cannot convert to mode string");
78ead24645SDimitry Andric }
79ead24645SDimitry Andric 
GetOptionsFromMode(llvm::StringRef mode)80ead24645SDimitry Andric Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
81ead24645SDimitry Andric   OpenOptions opts =
82ead24645SDimitry Andric       llvm::StringSwitch<OpenOptions>(mode)
83c0981da4SDimitry Andric           .Cases("r", "rb", eOpenOptionReadOnly)
84c0981da4SDimitry Andric           .Cases("w", "wb", eOpenOptionWriteOnly)
85ead24645SDimitry Andric           .Cases("a", "ab",
86c0981da4SDimitry Andric                  eOpenOptionWriteOnly | eOpenOptionAppend |
87c0981da4SDimitry Andric                  eOpenOptionCanCreate)
88c0981da4SDimitry Andric           .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
89ead24645SDimitry Andric           .Cases("w+", "wb+", "w+b",
90c0981da4SDimitry Andric                  eOpenOptionReadWrite | eOpenOptionCanCreate |
91ead24645SDimitry Andric                  eOpenOptionTruncate)
92ead24645SDimitry Andric           .Cases("a+", "ab+", "a+b",
93c0981da4SDimitry Andric                  eOpenOptionReadWrite | eOpenOptionAppend |
94ead24645SDimitry Andric                      eOpenOptionCanCreate)
95c0981da4SDimitry Andric           .Default(eOpenOptionInvalid);
96c0981da4SDimitry Andric   if (opts != eOpenOptionInvalid)
97ead24645SDimitry Andric     return opts;
98ead24645SDimitry Andric   return llvm::createStringError(
99ead24645SDimitry Andric       llvm::inconvertibleErrorCode(),
100ead24645SDimitry Andric       "invalid mode, cannot convert to File::OpenOptions");
101f034231aSEd Maste }
102f034231aSEd Maste 
103f034231aSEd Maste int File::kInvalidDescriptor = -1;
1045f29bb8aSDimitry Andric FILE *File::kInvalidStream = nullptr;
105f034231aSEd Maste 
Read(void * buf,size_t & num_bytes)106ead24645SDimitry Andric Status File::Read(void *buf, size_t &num_bytes) {
107ead24645SDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
108ead24645SDimitry Andric }
Write(const void * buf,size_t & num_bytes)109ead24645SDimitry Andric Status File::Write(const void *buf, size_t &num_bytes) {
110ead24645SDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
111ead24645SDimitry Andric }
112f034231aSEd Maste 
IsValid() const113ead24645SDimitry Andric bool File::IsValid() const { return false; }
114ead24645SDimitry Andric 
Close()115ead24645SDimitry Andric Status File::Close() { return Flush(); }
116ead24645SDimitry Andric 
GetWaitableHandle()117ead24645SDimitry Andric IOObject::WaitableHandle File::GetWaitableHandle() {
118ead24645SDimitry Andric   return IOObject::kInvalidHandleValue;
119ead24645SDimitry Andric }
120ead24645SDimitry Andric 
GetFileSpec(FileSpec & file_spec) const121ead24645SDimitry Andric Status File::GetFileSpec(FileSpec &file_spec) const {
122ead24645SDimitry Andric   file_spec.Clear();
123ead24645SDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
124ead24645SDimitry Andric }
125ead24645SDimitry Andric 
GetDescriptor() const126ead24645SDimitry Andric int File::GetDescriptor() const { return kInvalidDescriptor; }
127ead24645SDimitry Andric 
GetStream()128ead24645SDimitry Andric FILE *File::GetStream() { return nullptr; }
129ead24645SDimitry Andric 
SeekFromStart(off_t offset,Status * error_ptr)130ead24645SDimitry Andric off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
131ead24645SDimitry Andric   if (error_ptr)
132ead24645SDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
133ead24645SDimitry Andric   return -1;
134ead24645SDimitry Andric }
135ead24645SDimitry Andric 
SeekFromCurrent(off_t offset,Status * error_ptr)136ead24645SDimitry Andric off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
137ead24645SDimitry Andric   if (error_ptr)
138ead24645SDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
139ead24645SDimitry Andric   return -1;
140ead24645SDimitry Andric }
141ead24645SDimitry Andric 
SeekFromEnd(off_t offset,Status * error_ptr)142ead24645SDimitry Andric off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
143ead24645SDimitry Andric   if (error_ptr)
144ead24645SDimitry Andric     *error_ptr = std::error_code(ENOTSUP, std::system_category());
145ead24645SDimitry Andric   return -1;
146ead24645SDimitry Andric }
147ead24645SDimitry Andric 
Read(void * dst,size_t & num_bytes,off_t & offset)148ead24645SDimitry Andric Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
149ead24645SDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
150ead24645SDimitry Andric }
151ead24645SDimitry Andric 
Write(const void * src,size_t & num_bytes,off_t & offset)152ead24645SDimitry Andric Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
153ead24645SDimitry Andric   return std::error_code(ENOTSUP, std::system_category());
154ead24645SDimitry Andric }
155ead24645SDimitry Andric 
Flush()156ead24645SDimitry Andric Status File::Flush() { return Status(); }
157ead24645SDimitry Andric 
Sync()158ead24645SDimitry Andric Status File::Sync() { return Flush(); }
159ead24645SDimitry Andric 
CalculateInteractiveAndTerminal()160ead24645SDimitry Andric void File::CalculateInteractiveAndTerminal() {
161ead24645SDimitry Andric   const int fd = GetDescriptor();
162ead24645SDimitry Andric   if (!DescriptorIsValid(fd)) {
163ead24645SDimitry Andric     m_is_interactive = eLazyBoolNo;
164ead24645SDimitry Andric     m_is_real_terminal = eLazyBoolNo;
165ead24645SDimitry Andric     m_supports_colors = eLazyBoolNo;
166ead24645SDimitry Andric     return;
167ead24645SDimitry Andric   }
168ead24645SDimitry Andric   m_is_interactive = eLazyBoolNo;
169ead24645SDimitry Andric   m_is_real_terminal = eLazyBoolNo;
170ead24645SDimitry Andric #if defined(_WIN32)
171ead24645SDimitry Andric   if (_isatty(fd)) {
172ead24645SDimitry Andric     m_is_interactive = eLazyBoolYes;
173ead24645SDimitry Andric     m_is_real_terminal = eLazyBoolYes;
174ead24645SDimitry Andric #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
175ead24645SDimitry Andric     m_supports_colors = eLazyBoolYes;
176ead24645SDimitry Andric #endif
177ead24645SDimitry Andric   }
178ead24645SDimitry Andric #else
179ead24645SDimitry Andric   if (isatty(fd)) {
180ead24645SDimitry Andric     m_is_interactive = eLazyBoolYes;
181ead24645SDimitry Andric     struct winsize window_size;
182ead24645SDimitry Andric     if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
183ead24645SDimitry Andric       if (window_size.ws_col > 0) {
184ead24645SDimitry Andric         m_is_real_terminal = eLazyBoolYes;
185ead24645SDimitry Andric         if (llvm::sys::Process::FileDescriptorHasColors(fd))
186ead24645SDimitry Andric           m_supports_colors = eLazyBoolYes;
187ead24645SDimitry Andric       }
188ead24645SDimitry Andric     }
189ead24645SDimitry Andric   }
190ead24645SDimitry Andric #endif
191ead24645SDimitry Andric }
192ead24645SDimitry Andric 
GetIsInteractive()193ead24645SDimitry Andric bool File::GetIsInteractive() {
194ead24645SDimitry Andric   if (m_is_interactive == eLazyBoolCalculate)
195ead24645SDimitry Andric     CalculateInteractiveAndTerminal();
196ead24645SDimitry Andric   return m_is_interactive == eLazyBoolYes;
197ead24645SDimitry Andric }
198ead24645SDimitry Andric 
GetIsRealTerminal()199ead24645SDimitry Andric bool File::GetIsRealTerminal() {
200ead24645SDimitry Andric   if (m_is_real_terminal == eLazyBoolCalculate)
201ead24645SDimitry Andric     CalculateInteractiveAndTerminal();
202ead24645SDimitry Andric   return m_is_real_terminal == eLazyBoolYes;
203ead24645SDimitry Andric }
204ead24645SDimitry Andric 
GetIsTerminalWithColors()205ead24645SDimitry Andric bool File::GetIsTerminalWithColors() {
206ead24645SDimitry Andric   if (m_supports_colors == eLazyBoolCalculate)
207ead24645SDimitry Andric     CalculateInteractiveAndTerminal();
208ead24645SDimitry Andric   return m_supports_colors == eLazyBoolYes;
209ead24645SDimitry Andric }
210ead24645SDimitry Andric 
Printf(const char * format,...)211ead24645SDimitry Andric size_t File::Printf(const char *format, ...) {
212ead24645SDimitry Andric   va_list args;
213ead24645SDimitry Andric   va_start(args, format);
214ead24645SDimitry Andric   size_t result = PrintfVarArg(format, args);
215ead24645SDimitry Andric   va_end(args);
216ead24645SDimitry Andric   return result;
217ead24645SDimitry Andric }
218ead24645SDimitry Andric 
PrintfVarArg(const char * format,va_list args)219ead24645SDimitry Andric size_t File::PrintfVarArg(const char *format, va_list args) {
220145449b1SDimitry Andric   llvm::SmallString<0> s;
221145449b1SDimitry Andric   if (VASprintf(s, format, args)) {
222b1c73532SDimitry Andric     size_t written = s.size();
223145449b1SDimitry Andric     Write(s.data(), written);
224145449b1SDimitry Andric     return written;
225ead24645SDimitry Andric   }
226145449b1SDimitry Andric   return 0;
227ead24645SDimitry Andric }
228ead24645SDimitry Andric 
GetOptions() const229ead24645SDimitry Andric Expected<File::OpenOptions> File::GetOptions() const {
230ead24645SDimitry Andric   return llvm::createStringError(
231ead24645SDimitry Andric       llvm::inconvertibleErrorCode(),
232ead24645SDimitry Andric       "GetOptions() not implemented for this File class");
233ead24645SDimitry Andric }
234ead24645SDimitry Andric 
GetPermissions(Status & error) const235ead24645SDimitry Andric uint32_t File::GetPermissions(Status &error) const {
236ead24645SDimitry Andric   int fd = GetDescriptor();
237ead24645SDimitry Andric   if (!DescriptorIsValid(fd)) {
238ead24645SDimitry Andric     error = std::error_code(ENOTSUP, std::system_category());
239ead24645SDimitry Andric     return 0;
240ead24645SDimitry Andric   }
241ead24645SDimitry Andric   struct stat file_stats;
242ead24645SDimitry Andric   if (::fstat(fd, &file_stats) == -1) {
243ead24645SDimitry Andric     error.SetErrorToErrno();
244ead24645SDimitry Andric     return 0;
245ead24645SDimitry Andric   }
246ead24645SDimitry Andric   error.Clear();
247ead24645SDimitry Andric   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
248ead24645SDimitry Andric }
249ead24645SDimitry Andric 
IsValid() const250b1c73532SDimitry Andric bool NativeFile::IsValid() const {
251b1c73532SDimitry Andric   std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
252b1c73532SDimitry Andric   return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();
253b1c73532SDimitry Andric }
254b1c73532SDimitry Andric 
GetOptions() const255ead24645SDimitry Andric Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
256ead24645SDimitry Andric 
GetDescriptor() const257ead24645SDimitry Andric int NativeFile::GetDescriptor() const {
258b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
259f034231aSEd Maste     return m_descriptor;
260b1c73532SDimitry Andric   }
261f034231aSEd Maste 
262f034231aSEd Maste   // Don't open the file descriptor if we don't need to, just get it from the
263f034231aSEd Maste   // stream if we have one.
264b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
265f73363f1SDimitry Andric #if defined(_WIN32)
266e81d9d49SDimitry Andric     return _fileno(m_stream);
267e81d9d49SDimitry Andric #else
268f034231aSEd Maste     return fileno(m_stream);
269e81d9d49SDimitry Andric #endif
270e81d9d49SDimitry Andric   }
271f034231aSEd Maste 
272f034231aSEd Maste   // Invalid descriptor and invalid stream, return invalid descriptor.
273f034231aSEd Maste   return kInvalidDescriptor;
274f034231aSEd Maste }
275f034231aSEd Maste 
GetWaitableHandle()276ead24645SDimitry Andric IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
277ead24645SDimitry Andric   return GetDescriptor();
278f034231aSEd Maste }
279f034231aSEd Maste 
GetStream()280ead24645SDimitry Andric FILE *NativeFile::GetStream() {
281b1c73532SDimitry Andric   ValueGuard stream_guard = StreamIsValid();
282b1c73532SDimitry Andric   if (!stream_guard) {
283b1c73532SDimitry Andric     if (ValueGuard descriptor_guard = DescriptorIsValid()) {
284ead24645SDimitry Andric       auto mode = GetStreamOpenModeFromOptions(m_options);
285ead24645SDimitry Andric       if (!mode)
286ead24645SDimitry Andric         llvm::consumeError(mode.takeError());
287ead24645SDimitry Andric       else {
288ead24645SDimitry Andric         if (!m_own_descriptor) {
289f73363f1SDimitry Andric // We must duplicate the file descriptor if we don't own it because when you
290f73363f1SDimitry Andric // call fdopen, the stream will own the fd
291866dcdacSEd Maste #ifdef _WIN32
292b1c73532SDimitry Andric           m_descriptor = ::_dup(m_descriptor);
293866dcdacSEd Maste #else
294b1c73532SDimitry Andric           m_descriptor = dup(m_descriptor);
295866dcdacSEd Maste #endif
296ead24645SDimitry Andric           m_own_descriptor = true;
297866dcdacSEd Maste         }
298866dcdacSEd Maste 
299ead24645SDimitry Andric         m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
300ead24645SDimitry Andric                                                mode.get());
301866dcdacSEd Maste 
302f73363f1SDimitry Andric         // If we got a stream, then we own the stream and should no longer own
303f73363f1SDimitry Andric         // the descriptor because fclose() will close it for us
304866dcdacSEd Maste 
30514f1b3e8SDimitry Andric         if (m_stream) {
306866dcdacSEd Maste           m_own_stream = true;
307ead24645SDimitry Andric           m_own_descriptor = false;
308866dcdacSEd Maste         }
309f034231aSEd Maste       }
310f034231aSEd Maste     }
311f034231aSEd Maste   }
312f034231aSEd Maste   return m_stream;
313f034231aSEd Maste }
314f034231aSEd Maste 
Close()315ead24645SDimitry Andric Status NativeFile::Close() {
316b1c73532SDimitry Andric   std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
317b1c73532SDimitry Andric 
318b76161e4SDimitry Andric   Status error;
319b1c73532SDimitry Andric 
320b1c73532SDimitry Andric   if (StreamIsValidUnlocked()) {
321ead24645SDimitry Andric     if (m_own_stream) {
322f034231aSEd Maste       if (::fclose(m_stream) == EOF)
323f034231aSEd Maste         error.SetErrorToErrno();
324c0981da4SDimitry Andric     } else {
325c0981da4SDimitry Andric       File::OpenOptions rw =
326c0981da4SDimitry Andric           m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
327c0981da4SDimitry Andric                        File::eOpenOptionReadWrite);
328c0981da4SDimitry Andric 
329c0981da4SDimitry Andric       if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
330ead24645SDimitry Andric         if (::fflush(m_stream) == EOF)
331ead24645SDimitry Andric           error.SetErrorToErrno();
332f034231aSEd Maste       }
333ead24645SDimitry Andric     }
334c0981da4SDimitry Andric   }
335b1c73532SDimitry Andric 
336b1c73532SDimitry Andric   if (DescriptorIsValidUnlocked() && m_own_descriptor) {
337f034231aSEd Maste     if (::close(m_descriptor) != 0)
338f034231aSEd Maste       error.SetErrorToErrno();
339f034231aSEd Maste   }
340b1c73532SDimitry Andric 
341f034231aSEd Maste   m_stream = kInvalidStream;
342866dcdacSEd Maste   m_own_stream = false;
343b1c73532SDimitry Andric   m_descriptor = kInvalidDescriptor;
344ead24645SDimitry Andric   m_own_descriptor = false;
345b1c73532SDimitry Andric   m_options = OpenOptions(0);
346866dcdacSEd Maste   m_is_interactive = eLazyBoolCalculate;
347866dcdacSEd Maste   m_is_real_terminal = eLazyBoolCalculate;
348f034231aSEd Maste   return error;
349f034231aSEd Maste }
350f034231aSEd Maste 
GetFileSpec(FileSpec & file_spec) const351ead24645SDimitry Andric Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
352b76161e4SDimitry Andric   Status error;
35374a628f7SDimitry Andric #ifdef F_GETPATH
35414f1b3e8SDimitry Andric   if (IsValid()) {
355f034231aSEd Maste     char path[PATH_MAX];
356f034231aSEd Maste     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
357f034231aSEd Maste       error.SetErrorToErrno();
358f034231aSEd Maste     else
35994994d37SDimitry Andric       file_spec.SetFile(path, FileSpec::Style::native);
36014f1b3e8SDimitry Andric   } else {
361f034231aSEd Maste     error.SetErrorString("invalid file handle");
362f034231aSEd Maste   }
363f034231aSEd Maste #elif defined(__linux__)
364f034231aSEd Maste   char proc[64];
365f034231aSEd Maste   char path[PATH_MAX];
366f034231aSEd Maste   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
367f034231aSEd Maste     error.SetErrorString("cannot resolve file descriptor");
36814f1b3e8SDimitry Andric   else {
369f034231aSEd Maste     ssize_t len;
370f034231aSEd Maste     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
371f034231aSEd Maste       error.SetErrorToErrno();
37214f1b3e8SDimitry Andric     else {
373f034231aSEd Maste       path[len] = '\0';
37494994d37SDimitry Andric       file_spec.SetFile(path, FileSpec::Style::native);
375f034231aSEd Maste     }
376f034231aSEd Maste   }
377f034231aSEd Maste #else
378ead24645SDimitry Andric   error.SetErrorString(
379ead24645SDimitry Andric       "NativeFile::GetFileSpec is not supported on this platform");
380f034231aSEd Maste #endif
381f034231aSEd Maste 
382f034231aSEd Maste   if (error.Fail())
383f034231aSEd Maste     file_spec.Clear();
384f034231aSEd Maste   return error;
385f034231aSEd Maste }
386f034231aSEd Maste 
SeekFromStart(off_t offset,Status * error_ptr)387ead24645SDimitry Andric off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
388f034231aSEd Maste   off_t result = 0;
389b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
390f034231aSEd Maste     result = ::lseek(m_descriptor, offset, SEEK_SET);
391f034231aSEd Maste 
39214f1b3e8SDimitry Andric     if (error_ptr) {
393f034231aSEd Maste       if (result == -1)
394f034231aSEd Maste         error_ptr->SetErrorToErrno();
395f034231aSEd Maste       else
396f034231aSEd Maste         error_ptr->Clear();
397f034231aSEd Maste     }
398b1c73532SDimitry Andric     return result;
399b1c73532SDimitry Andric   }
400b1c73532SDimitry Andric 
401b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
402f034231aSEd Maste     result = ::fseek(m_stream, offset, SEEK_SET);
403f034231aSEd Maste 
40414f1b3e8SDimitry Andric     if (error_ptr) {
405f034231aSEd Maste       if (result == -1)
406f034231aSEd Maste         error_ptr->SetErrorToErrno();
407f034231aSEd Maste       else
408f034231aSEd Maste         error_ptr->Clear();
409f034231aSEd Maste     }
410b1c73532SDimitry Andric     return result;
411f034231aSEd Maste   }
412b1c73532SDimitry Andric 
413b1c73532SDimitry Andric   if (error_ptr)
414b1c73532SDimitry Andric     error_ptr->SetErrorString("invalid file handle");
415f034231aSEd Maste   return result;
416f034231aSEd Maste }
417f034231aSEd Maste 
SeekFromCurrent(off_t offset,Status * error_ptr)418ead24645SDimitry Andric off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
419f034231aSEd Maste   off_t result = -1;
420b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
421f034231aSEd Maste     result = ::lseek(m_descriptor, offset, SEEK_CUR);
422f034231aSEd Maste 
42314f1b3e8SDimitry Andric     if (error_ptr) {
424f034231aSEd Maste       if (result == -1)
425f034231aSEd Maste         error_ptr->SetErrorToErrno();
426f034231aSEd Maste       else
427f034231aSEd Maste         error_ptr->Clear();
428f034231aSEd Maste     }
429b1c73532SDimitry Andric     return result;
430b1c73532SDimitry Andric   }
431b1c73532SDimitry Andric 
432b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
433f034231aSEd Maste     result = ::fseek(m_stream, offset, SEEK_CUR);
434f034231aSEd Maste 
43514f1b3e8SDimitry Andric     if (error_ptr) {
436f034231aSEd Maste       if (result == -1)
437f034231aSEd Maste         error_ptr->SetErrorToErrno();
438f034231aSEd Maste       else
439f034231aSEd Maste         error_ptr->Clear();
440f034231aSEd Maste     }
441b1c73532SDimitry Andric     return result;
442f034231aSEd Maste   }
443b1c73532SDimitry Andric 
444b1c73532SDimitry Andric   if (error_ptr)
445b1c73532SDimitry Andric     error_ptr->SetErrorString("invalid file handle");
446f034231aSEd Maste   return result;
447f034231aSEd Maste }
448f034231aSEd Maste 
SeekFromEnd(off_t offset,Status * error_ptr)449ead24645SDimitry Andric off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
450f034231aSEd Maste   off_t result = -1;
451b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
452f034231aSEd Maste     result = ::lseek(m_descriptor, offset, SEEK_END);
453f034231aSEd Maste 
45414f1b3e8SDimitry Andric     if (error_ptr) {
455f034231aSEd Maste       if (result == -1)
456f034231aSEd Maste         error_ptr->SetErrorToErrno();
457f034231aSEd Maste       else
458f034231aSEd Maste         error_ptr->Clear();
459f034231aSEd Maste     }
460b1c73532SDimitry Andric     return result;
461b1c73532SDimitry Andric   }
462b1c73532SDimitry Andric 
463b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
464f034231aSEd Maste     result = ::fseek(m_stream, offset, SEEK_END);
465f034231aSEd Maste 
46614f1b3e8SDimitry Andric     if (error_ptr) {
467f034231aSEd Maste       if (result == -1)
468f034231aSEd Maste         error_ptr->SetErrorToErrno();
469f034231aSEd Maste       else
470f034231aSEd Maste         error_ptr->Clear();
471f034231aSEd Maste     }
472f034231aSEd Maste   }
473b1c73532SDimitry Andric 
474b1c73532SDimitry Andric   if (error_ptr)
475b1c73532SDimitry Andric     error_ptr->SetErrorString("invalid file handle");
476f034231aSEd Maste   return result;
477f034231aSEd Maste }
478f034231aSEd Maste 
Flush()479ead24645SDimitry Andric Status NativeFile::Flush() {
480b76161e4SDimitry Andric   Status error;
481b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
482e75e363cSDimitry Andric     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
483f034231aSEd Maste       error.SetErrorToErrno();
484b1c73532SDimitry Andric     return error;
485b1c73532SDimitry Andric   }
486b1c73532SDimitry Andric 
487b1c73532SDimitry Andric   {
488b1c73532SDimitry Andric     ValueGuard descriptor_guard = DescriptorIsValid();
489b1c73532SDimitry Andric     if (!descriptor_guard)
490f034231aSEd Maste       error.SetErrorString("invalid file handle");
491f034231aSEd Maste   }
492f034231aSEd Maste   return error;
493f034231aSEd Maste }
494f034231aSEd Maste 
Sync()495ead24645SDimitry Andric Status NativeFile::Sync() {
496b76161e4SDimitry Andric   Status error;
497b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
498f21a844fSEd Maste #ifdef _WIN32
499f21a844fSEd Maste     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
500f21a844fSEd Maste     if (err == 0)
501f21a844fSEd Maste       error.SetErrorToGenericError();
502f21a844fSEd Maste #else
503e75e363cSDimitry Andric     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
504f034231aSEd Maste       error.SetErrorToErrno();
505f21a844fSEd Maste #endif
50614f1b3e8SDimitry Andric   } else {
507f034231aSEd Maste     error.SetErrorString("invalid file handle");
508f034231aSEd Maste   }
509f034231aSEd Maste   return error;
510f034231aSEd Maste }
511f034231aSEd Maste 
5125e95aa85SEd Maste #if defined(__APPLE__)
5135e95aa85SEd Maste // Darwin kernels only can read/write <= INT_MAX bytes
5145e95aa85SEd Maste #define MAX_READ_SIZE INT_MAX
5155e95aa85SEd Maste #define MAX_WRITE_SIZE INT_MAX
5165e95aa85SEd Maste #endif
5175e95aa85SEd Maste 
Read(void * buf,size_t & num_bytes)518ead24645SDimitry Andric Status NativeFile::Read(void *buf, size_t &num_bytes) {
519b76161e4SDimitry Andric   Status error;
5205e95aa85SEd Maste 
5215e95aa85SEd Maste #if defined(MAX_READ_SIZE)
52214f1b3e8SDimitry Andric   if (num_bytes > MAX_READ_SIZE) {
5235e95aa85SEd Maste     uint8_t *p = (uint8_t *)buf;
5245e95aa85SEd Maste     size_t bytes_left = num_bytes;
5255e95aa85SEd Maste     // Init the num_bytes read to zero
5265e95aa85SEd Maste     num_bytes = 0;
5275e95aa85SEd Maste 
52814f1b3e8SDimitry Andric     while (bytes_left > 0) {
5295e95aa85SEd Maste       size_t curr_num_bytes;
5305e95aa85SEd Maste       if (bytes_left > MAX_READ_SIZE)
5315e95aa85SEd Maste         curr_num_bytes = MAX_READ_SIZE;
5325e95aa85SEd Maste       else
5335e95aa85SEd Maste         curr_num_bytes = bytes_left;
5345e95aa85SEd Maste 
5355e95aa85SEd Maste       error = Read(p + num_bytes, curr_num_bytes);
5365e95aa85SEd Maste 
5375e95aa85SEd Maste       // Update how many bytes were read
5385e95aa85SEd Maste       num_bytes += curr_num_bytes;
5395e95aa85SEd Maste       if (bytes_left < curr_num_bytes)
5405e95aa85SEd Maste         bytes_left = 0;
5415e95aa85SEd Maste       else
5425e95aa85SEd Maste         bytes_left -= curr_num_bytes;
5435e95aa85SEd Maste 
5445e95aa85SEd Maste       if (error.Fail())
5455e95aa85SEd Maste         break;
5465e95aa85SEd Maste     }
5475e95aa85SEd Maste     return error;
5485e95aa85SEd Maste   }
5495e95aa85SEd Maste #endif
5505e95aa85SEd Maste 
551f034231aSEd Maste   ssize_t bytes_read = -1;
552b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
553b1c73532SDimitry Andric     bytes_read =
554b1c73532SDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
55514f1b3e8SDimitry Andric     if (bytes_read == -1) {
556f034231aSEd Maste       error.SetErrorToErrno();
557f034231aSEd Maste       num_bytes = 0;
55814f1b3e8SDimitry Andric     } else
559f034231aSEd Maste       num_bytes = bytes_read;
560b1c73532SDimitry Andric     return error;
561b1c73532SDimitry Andric   }
562b1c73532SDimitry Andric 
563b1c73532SDimitry Andric   if (ValueGuard file_lock = StreamIsValid()) {
564f034231aSEd Maste     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
565f034231aSEd Maste 
56614f1b3e8SDimitry Andric     if (bytes_read == 0) {
567f034231aSEd Maste       if (::feof(m_stream))
568f034231aSEd Maste         error.SetErrorString("feof");
569f034231aSEd Maste       else if (::ferror(m_stream))
570f034231aSEd Maste         error.SetErrorString("ferror");
571f034231aSEd Maste       num_bytes = 0;
57214f1b3e8SDimitry Andric     } else
573f034231aSEd Maste       num_bytes = bytes_read;
574b1c73532SDimitry Andric     return error;
575b1c73532SDimitry Andric   }
576b1c73532SDimitry Andric 
577f034231aSEd Maste   num_bytes = 0;
578f034231aSEd Maste   error.SetErrorString("invalid file handle");
579f034231aSEd Maste   return error;
580f034231aSEd Maste }
581f034231aSEd Maste 
Write(const void * buf,size_t & num_bytes)582ead24645SDimitry Andric Status NativeFile::Write(const void *buf, size_t &num_bytes) {
583b76161e4SDimitry Andric   Status error;
5845e95aa85SEd Maste 
5855e95aa85SEd Maste #if defined(MAX_WRITE_SIZE)
58614f1b3e8SDimitry Andric   if (num_bytes > MAX_WRITE_SIZE) {
5875e95aa85SEd Maste     const uint8_t *p = (const uint8_t *)buf;
5885e95aa85SEd Maste     size_t bytes_left = num_bytes;
5895e95aa85SEd Maste     // Init the num_bytes written to zero
5905e95aa85SEd Maste     num_bytes = 0;
5915e95aa85SEd Maste 
59214f1b3e8SDimitry Andric     while (bytes_left > 0) {
5935e95aa85SEd Maste       size_t curr_num_bytes;
5945e95aa85SEd Maste       if (bytes_left > MAX_WRITE_SIZE)
5955e95aa85SEd Maste         curr_num_bytes = MAX_WRITE_SIZE;
5965e95aa85SEd Maste       else
5975e95aa85SEd Maste         curr_num_bytes = bytes_left;
5985e95aa85SEd Maste 
5995e95aa85SEd Maste       error = Write(p + num_bytes, curr_num_bytes);
6005e95aa85SEd Maste 
6015e95aa85SEd Maste       // Update how many bytes were read
6025e95aa85SEd Maste       num_bytes += curr_num_bytes;
6035e95aa85SEd Maste       if (bytes_left < curr_num_bytes)
6045e95aa85SEd Maste         bytes_left = 0;
6055e95aa85SEd Maste       else
6065e95aa85SEd Maste         bytes_left -= curr_num_bytes;
6075e95aa85SEd Maste 
6085e95aa85SEd Maste       if (error.Fail())
6095e95aa85SEd Maste         break;
6105e95aa85SEd Maste     }
6115e95aa85SEd Maste     return error;
6125e95aa85SEd Maste   }
6135e95aa85SEd Maste #endif
6145e95aa85SEd Maste 
615f034231aSEd Maste   ssize_t bytes_written = -1;
616b1c73532SDimitry Andric   if (ValueGuard descriptor_guard = DescriptorIsValid()) {
617e75e363cSDimitry Andric     bytes_written =
618e75e363cSDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
61914f1b3e8SDimitry Andric     if (bytes_written == -1) {
620f034231aSEd Maste       error.SetErrorToErrno();
621f034231aSEd Maste       num_bytes = 0;
62214f1b3e8SDimitry Andric     } else
623f034231aSEd Maste       num_bytes = bytes_written;
624b1c73532SDimitry Andric     return error;
625b1c73532SDimitry Andric   }
626b1c73532SDimitry Andric 
627b1c73532SDimitry Andric   if (ValueGuard stream_guard = StreamIsValid()) {
628f034231aSEd Maste     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
629f034231aSEd Maste 
63014f1b3e8SDimitry Andric     if (bytes_written == 0) {
631f034231aSEd Maste       if (::feof(m_stream))
632f034231aSEd Maste         error.SetErrorString("feof");
633f034231aSEd Maste       else if (::ferror(m_stream))
634f034231aSEd Maste         error.SetErrorString("ferror");
635f034231aSEd Maste       num_bytes = 0;
63614f1b3e8SDimitry Andric     } else
637f034231aSEd Maste       num_bytes = bytes_written;
638b1c73532SDimitry Andric     return error;
639f034231aSEd Maste   }
6400cac4ca3SEd Maste 
641b1c73532SDimitry Andric   num_bytes = 0;
642b1c73532SDimitry Andric   error.SetErrorString("invalid file handle");
643f034231aSEd Maste   return error;
644f034231aSEd Maste }
645f034231aSEd Maste 
Read(void * buf,size_t & num_bytes,off_t & offset)646ead24645SDimitry Andric Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
647b76161e4SDimitry Andric   Status error;
6485e95aa85SEd Maste 
6495e95aa85SEd Maste #if defined(MAX_READ_SIZE)
65014f1b3e8SDimitry Andric   if (num_bytes > MAX_READ_SIZE) {
6515e95aa85SEd Maste     uint8_t *p = (uint8_t *)buf;
6525e95aa85SEd Maste     size_t bytes_left = num_bytes;
6535e95aa85SEd Maste     // Init the num_bytes read to zero
6545e95aa85SEd Maste     num_bytes = 0;
6555e95aa85SEd Maste 
65614f1b3e8SDimitry Andric     while (bytes_left > 0) {
6575e95aa85SEd Maste       size_t curr_num_bytes;
6585e95aa85SEd Maste       if (bytes_left > MAX_READ_SIZE)
6595e95aa85SEd Maste         curr_num_bytes = MAX_READ_SIZE;
6605e95aa85SEd Maste       else
6615e95aa85SEd Maste         curr_num_bytes = bytes_left;
6625e95aa85SEd Maste 
6635e95aa85SEd Maste       error = Read(p + num_bytes, curr_num_bytes, offset);
6645e95aa85SEd Maste 
6655e95aa85SEd Maste       // Update how many bytes were read
6665e95aa85SEd Maste       num_bytes += curr_num_bytes;
6675e95aa85SEd Maste       if (bytes_left < curr_num_bytes)
6685e95aa85SEd Maste         bytes_left = 0;
6695e95aa85SEd Maste       else
6705e95aa85SEd Maste         bytes_left -= curr_num_bytes;
6715e95aa85SEd Maste 
6725e95aa85SEd Maste       if (error.Fail())
6735e95aa85SEd Maste         break;
6745e95aa85SEd Maste     }
6755e95aa85SEd Maste     return error;
6765e95aa85SEd Maste   }
6775e95aa85SEd Maste #endif
6785e95aa85SEd Maste 
6795e95aa85SEd Maste #ifndef _WIN32
680f034231aSEd Maste   int fd = GetDescriptor();
68114f1b3e8SDimitry Andric   if (fd != kInvalidDescriptor) {
682e75e363cSDimitry Andric     ssize_t bytes_read =
683e75e363cSDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
68414f1b3e8SDimitry Andric     if (bytes_read < 0) {
685f034231aSEd Maste       num_bytes = 0;
686f034231aSEd Maste       error.SetErrorToErrno();
68714f1b3e8SDimitry Andric     } else {
688f034231aSEd Maste       offset += bytes_read;
689f034231aSEd Maste       num_bytes = bytes_read;
690f034231aSEd Maste     }
69114f1b3e8SDimitry Andric   } else {
692f034231aSEd Maste     num_bytes = 0;
693f034231aSEd Maste     error.SetErrorString("invalid file handle");
694f034231aSEd Maste   }
695f21a844fSEd Maste #else
6965f29bb8aSDimitry Andric   std::lock_guard<std::mutex> guard(offset_access_mutex);
697f21a844fSEd Maste   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
698f21a844fSEd Maste   SeekFromStart(offset);
6995e95aa85SEd Maste   error = Read(buf, num_bytes);
700f21a844fSEd Maste   if (!error.Fail())
701f21a844fSEd Maste     SeekFromStart(cur);
702f21a844fSEd Maste #endif
7035e95aa85SEd Maste   return error;
704f034231aSEd Maste }
705f034231aSEd Maste 
Write(const void * buf,size_t & num_bytes,off_t & offset)706ead24645SDimitry Andric Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
707b76161e4SDimitry Andric   Status error;
7085e95aa85SEd Maste 
7095e95aa85SEd Maste #if defined(MAX_WRITE_SIZE)
71014f1b3e8SDimitry Andric   if (num_bytes > MAX_WRITE_SIZE) {
7115e95aa85SEd Maste     const uint8_t *p = (const uint8_t *)buf;
7125e95aa85SEd Maste     size_t bytes_left = num_bytes;
7135e95aa85SEd Maste     // Init the num_bytes written to zero
7145e95aa85SEd Maste     num_bytes = 0;
7155e95aa85SEd Maste 
71614f1b3e8SDimitry Andric     while (bytes_left > 0) {
7175e95aa85SEd Maste       size_t curr_num_bytes;
7185e95aa85SEd Maste       if (bytes_left > MAX_WRITE_SIZE)
7195e95aa85SEd Maste         curr_num_bytes = MAX_WRITE_SIZE;
7205e95aa85SEd Maste       else
7215e95aa85SEd Maste         curr_num_bytes = bytes_left;
7225e95aa85SEd Maste 
7235e95aa85SEd Maste       error = Write(p + num_bytes, curr_num_bytes, offset);
7245e95aa85SEd Maste 
7255e95aa85SEd Maste       // Update how many bytes were read
7265e95aa85SEd Maste       num_bytes += curr_num_bytes;
7275e95aa85SEd Maste       if (bytes_left < curr_num_bytes)
7285e95aa85SEd Maste         bytes_left = 0;
7295e95aa85SEd Maste       else
7305e95aa85SEd Maste         bytes_left -= curr_num_bytes;
7315e95aa85SEd Maste 
7325e95aa85SEd Maste       if (error.Fail())
7335e95aa85SEd Maste         break;
7345e95aa85SEd Maste     }
7355e95aa85SEd Maste     return error;
7365e95aa85SEd Maste   }
7375e95aa85SEd Maste #endif
7385e95aa85SEd Maste 
739f034231aSEd Maste   int fd = GetDescriptor();
74014f1b3e8SDimitry Andric   if (fd != kInvalidDescriptor) {
741f21a844fSEd Maste #ifndef _WIN32
742e75e363cSDimitry Andric     ssize_t bytes_written =
743e75e363cSDimitry Andric         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
74414f1b3e8SDimitry Andric     if (bytes_written < 0) {
745f034231aSEd Maste       num_bytes = 0;
746f034231aSEd Maste       error.SetErrorToErrno();
74714f1b3e8SDimitry Andric     } else {
748f034231aSEd Maste       offset += bytes_written;
749f034231aSEd Maste       num_bytes = bytes_written;
750f034231aSEd Maste     }
751f21a844fSEd Maste #else
7525f29bb8aSDimitry Andric     std::lock_guard<std::mutex> guard(offset_access_mutex);
753f21a844fSEd Maste     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
7545f29bb8aSDimitry Andric     SeekFromStart(offset);
755f21a844fSEd Maste     error = Write(buf, num_bytes);
756f21a844fSEd Maste     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
757f21a844fSEd Maste 
758f21a844fSEd Maste     if (!error.Fail())
759f21a844fSEd Maste       SeekFromStart(cur);
760f21a844fSEd Maste 
761f21a844fSEd Maste     offset = after;
762f21a844fSEd Maste #endif
76314f1b3e8SDimitry Andric   } else {
764f034231aSEd Maste     num_bytes = 0;
765f034231aSEd Maste     error.SetErrorString("invalid file handle");
766f034231aSEd Maste   }
767f034231aSEd Maste   return error;
768f034231aSEd Maste }
769f034231aSEd Maste 
PrintfVarArg(const char * format,va_list args)770ead24645SDimitry Andric size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
771ead24645SDimitry Andric   if (StreamIsValid()) {
772ead24645SDimitry Andric     return ::vfprintf(m_stream, format, args);
773ead24645SDimitry Andric   } else {
774ead24645SDimitry Andric     return File::PrintfVarArg(format, args);
775ead24645SDimitry Andric   }
776f034231aSEd Maste }
777f034231aSEd Maste 
ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)778ead24645SDimitry Andric mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
779f21a844fSEd Maste   mode_t mode = 0;
780c0981da4SDimitry Andric   File::OpenOptions rw =
781c0981da4SDimitry Andric       open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
782c0981da4SDimitry Andric                       File::eOpenOptionReadWrite);
783c0981da4SDimitry Andric   if (rw == eOpenOptionReadWrite)
784f21a844fSEd Maste     mode |= O_RDWR;
785c0981da4SDimitry Andric   else if (rw == eOpenOptionWriteOnly)
786f21a844fSEd Maste     mode |= O_WRONLY;
787c0981da4SDimitry Andric   else if (rw == eOpenOptionReadOnly)
788c0981da4SDimitry Andric     mode |= O_RDONLY;
789f21a844fSEd Maste 
790f21a844fSEd Maste   if (open_options & eOpenOptionAppend)
791f21a844fSEd Maste     mode |= O_APPEND;
792f21a844fSEd Maste 
793f21a844fSEd Maste   if (open_options & eOpenOptionTruncate)
794f21a844fSEd Maste     mode |= O_TRUNC;
795f21a844fSEd Maste 
796f21a844fSEd Maste   if (open_options & eOpenOptionNonBlocking)
797f21a844fSEd Maste     mode |= O_NONBLOCK;
798f21a844fSEd Maste 
799f21a844fSEd Maste   if (open_options & eOpenOptionCanCreateNewOnly)
800f21a844fSEd Maste     mode |= O_CREAT | O_EXCL;
801f21a844fSEd Maste   else if (open_options & eOpenOptionCanCreate)
802f21a844fSEd Maste     mode |= O_CREAT;
803f21a844fSEd Maste 
804f21a844fSEd Maste   return mode;
805f21a844fSEd Maste }
806866dcdacSEd Maste 
807c0981da4SDimitry Andric llvm::Expected<SerialPort::Options>
OptionsFromURL(llvm::StringRef urlqs)808c0981da4SDimitry Andric SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
809c0981da4SDimitry Andric   SerialPort::Options serial_options;
810c0981da4SDimitry Andric   for (llvm::StringRef x : llvm::split(urlqs, '&')) {
811c0981da4SDimitry Andric     if (x.consume_front("baud=")) {
812c0981da4SDimitry Andric       unsigned int baud_rate;
813c0981da4SDimitry Andric       if (!llvm::to_integer(x, baud_rate, 10))
814c0981da4SDimitry Andric         return llvm::createStringError(llvm::inconvertibleErrorCode(),
815c0981da4SDimitry Andric                                        "Invalid baud rate: %s",
816c0981da4SDimitry Andric                                        x.str().c_str());
817c0981da4SDimitry Andric       serial_options.BaudRate = baud_rate;
818c0981da4SDimitry Andric     } else if (x.consume_front("parity=")) {
819c0981da4SDimitry Andric       serial_options.Parity =
820e3b55780SDimitry Andric           llvm::StringSwitch<std::optional<Terminal::Parity>>(x)
821c0981da4SDimitry Andric               .Case("no", Terminal::Parity::No)
822c0981da4SDimitry Andric               .Case("even", Terminal::Parity::Even)
823c0981da4SDimitry Andric               .Case("odd", Terminal::Parity::Odd)
824c0981da4SDimitry Andric               .Case("mark", Terminal::Parity::Mark)
825c0981da4SDimitry Andric               .Case("space", Terminal::Parity::Space)
826e3b55780SDimitry Andric               .Default(std::nullopt);
827c0981da4SDimitry Andric       if (!serial_options.Parity)
828c0981da4SDimitry Andric         return llvm::createStringError(
829c0981da4SDimitry Andric             llvm::inconvertibleErrorCode(),
830c0981da4SDimitry Andric             "Invalid parity (must be no, even, odd, mark or space): %s",
831c0981da4SDimitry Andric             x.str().c_str());
832c0981da4SDimitry Andric     } else if (x.consume_front("parity-check=")) {
833c0981da4SDimitry Andric       serial_options.ParityCheck =
834e3b55780SDimitry Andric           llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)
835c0981da4SDimitry Andric               .Case("no", Terminal::ParityCheck::No)
836c0981da4SDimitry Andric               .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
837c0981da4SDimitry Andric               .Case("ignore", Terminal::ParityCheck::Ignore)
838c0981da4SDimitry Andric               // "mark" mode is not currently supported as it requires special
839c0981da4SDimitry Andric               // input processing
840c0981da4SDimitry Andric               // .Case("mark", Terminal::ParityCheck::Mark)
841e3b55780SDimitry Andric               .Default(std::nullopt);
842c0981da4SDimitry Andric       if (!serial_options.ParityCheck)
843c0981da4SDimitry Andric         return llvm::createStringError(
844c0981da4SDimitry Andric             llvm::inconvertibleErrorCode(),
845c0981da4SDimitry Andric             "Invalid parity-check (must be no, replace, ignore or mark): %s",
846c0981da4SDimitry Andric             x.str().c_str());
847c0981da4SDimitry Andric     } else if (x.consume_front("stop-bits=")) {
848c0981da4SDimitry Andric       unsigned int stop_bits;
849c0981da4SDimitry Andric       if (!llvm::to_integer(x, stop_bits, 10) ||
850c0981da4SDimitry Andric           (stop_bits != 1 && stop_bits != 2))
851c0981da4SDimitry Andric         return llvm::createStringError(
852c0981da4SDimitry Andric             llvm::inconvertibleErrorCode(),
853c0981da4SDimitry Andric             "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
854c0981da4SDimitry Andric       serial_options.StopBits = stop_bits;
855c0981da4SDimitry Andric     } else
856c0981da4SDimitry Andric       return llvm::createStringError(llvm::inconvertibleErrorCode(),
857c0981da4SDimitry Andric                                      "Unknown parameter: %s", x.str().c_str());
858c0981da4SDimitry Andric   }
859c0981da4SDimitry Andric   return serial_options;
860c0981da4SDimitry Andric }
861c0981da4SDimitry Andric 
862c0981da4SDimitry Andric llvm::Expected<std::unique_ptr<SerialPort>>
Create(int fd,OpenOptions options,Options serial_options,bool transfer_ownership)863c0981da4SDimitry Andric SerialPort::Create(int fd, OpenOptions options, Options serial_options,
864c0981da4SDimitry Andric                    bool transfer_ownership) {
865c0981da4SDimitry Andric   std::unique_ptr<SerialPort> out{
866c0981da4SDimitry Andric       new SerialPort(fd, options, serial_options, transfer_ownership)};
867c0981da4SDimitry Andric 
868c0981da4SDimitry Andric   if (!out->GetIsInteractive())
869c0981da4SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
870c0981da4SDimitry Andric                                    "the specified file is not a teletype");
871c0981da4SDimitry Andric 
872c0981da4SDimitry Andric   Terminal term{fd};
873c0981da4SDimitry Andric   if (llvm::Error error = term.SetRaw())
874c0981da4SDimitry Andric     return std::move(error);
875c0981da4SDimitry Andric   if (serial_options.BaudRate) {
876e3b55780SDimitry Andric     if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))
877c0981da4SDimitry Andric       return std::move(error);
878c0981da4SDimitry Andric   }
879c0981da4SDimitry Andric   if (serial_options.Parity) {
880e3b55780SDimitry Andric     if (llvm::Error error = term.SetParity(*serial_options.Parity))
881c0981da4SDimitry Andric       return std::move(error);
882c0981da4SDimitry Andric   }
883c0981da4SDimitry Andric   if (serial_options.ParityCheck) {
884e3b55780SDimitry Andric     if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))
885c0981da4SDimitry Andric       return std::move(error);
886c0981da4SDimitry Andric   }
887c0981da4SDimitry Andric   if (serial_options.StopBits) {
888e3b55780SDimitry Andric     if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))
889c0981da4SDimitry Andric       return std::move(error);
890c0981da4SDimitry Andric   }
891c0981da4SDimitry Andric 
892c0981da4SDimitry Andric   return std::move(out);
893c0981da4SDimitry Andric }
894c0981da4SDimitry Andric 
SerialPort(int fd,OpenOptions options,SerialPort::Options serial_options,bool transfer_ownership)895c0981da4SDimitry Andric SerialPort::SerialPort(int fd, OpenOptions options,
896c0981da4SDimitry Andric                        SerialPort::Options serial_options,
897c0981da4SDimitry Andric                        bool transfer_ownership)
898c0981da4SDimitry Andric     : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
899c0981da4SDimitry Andric 
Close()900c0981da4SDimitry Andric Status SerialPort::Close() {
901c0981da4SDimitry Andric   m_state.Restore();
902c0981da4SDimitry Andric   return NativeFile::Close();
903c0981da4SDimitry Andric }
904c0981da4SDimitry Andric 
905ead24645SDimitry Andric char File::ID = 0;
906ead24645SDimitry Andric char NativeFile::ID = 0;
907c0981da4SDimitry Andric char SerialPort::ID = 0;
908