1 //===-- File.cpp ----------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Host/File.h"
10 
11 #include <cerrno>
12 #include <climits>
13 #include <cstdarg>
14 #include <cstdio>
15 #include <fcntl.h>
16 #include <optional>
17 
18 #ifdef _WIN32
19 #include "lldb/Host/windows/windows.h"
20 #else
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <unistd.h>
25 #endif
26 
27 #include "lldb/Host/Config.h"
28 #include "lldb/Host/FileSystem.h"
29 #include "lldb/Host/Host.h"
30 #include "lldb/Utility/DataBufferHeap.h"
31 #include "lldb/Utility/FileSpec.h"
32 #include "lldb/Utility/Log.h"
33 #include "lldb/Utility/VASPrintf.h"
34 #include "llvm/ADT/StringExtras.h"
35 #include "llvm/Support/ConvertUTF.h"
36 #include "llvm/Support/Errno.h"
37 #include "llvm/Support/FileSystem.h"
38 #include "llvm/Support/Process.h"
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 using llvm::Expected;
43 
44 Expected<const char *>
45 File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
46   File::OpenOptions rw =
47       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
48                  File::eOpenOptionReadWrite);
49 
50   if (options & File::eOpenOptionAppend) {
51     if (rw == File::eOpenOptionReadWrite) {
52       if (options & File::eOpenOptionCanCreateNewOnly)
53         return "a+x";
54       else
55         return "a+";
56     } else if (rw == File::eOpenOptionWriteOnly) {
57       if (options & File::eOpenOptionCanCreateNewOnly)
58         return "ax";
59       else
60         return "a";
61     }
62   } else if (rw == File::eOpenOptionReadWrite) {
63     if (options & File::eOpenOptionCanCreate) {
64       if (options & File::eOpenOptionCanCreateNewOnly)
65         return "w+x";
66       else
67         return "w+";
68     } else
69       return "r+";
70   } else if (rw == File::eOpenOptionWriteOnly) {
71     return "w";
72   } else if (rw == File::eOpenOptionReadOnly) {
73     return "r";
74   }
75   return llvm::createStringError(
76       llvm::inconvertibleErrorCode(),
77       "invalid options, cannot convert to mode string");
78 }
79 
80 Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
81   OpenOptions opts =
82       llvm::StringSwitch<OpenOptions>(mode)
83           .Cases("r", "rb", eOpenOptionReadOnly)
84           .Cases("w", "wb", eOpenOptionWriteOnly)
85           .Cases("a", "ab",
86                  eOpenOptionWriteOnly | eOpenOptionAppend |
87                  eOpenOptionCanCreate)
88           .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
89           .Cases("w+", "wb+", "w+b",
90                  eOpenOptionReadWrite | eOpenOptionCanCreate |
91                  eOpenOptionTruncate)
92           .Cases("a+", "ab+", "a+b",
93                  eOpenOptionReadWrite | eOpenOptionAppend |
94                      eOpenOptionCanCreate)
95           .Default(eOpenOptionInvalid);
96   if (opts != eOpenOptionInvalid)
97     return opts;
98   return llvm::createStringError(
99       llvm::inconvertibleErrorCode(),
100       "invalid mode, cannot convert to File::OpenOptions");
101 }
102 
103 int File::kInvalidDescriptor = -1;
104 FILE *File::kInvalidStream = nullptr;
105 
106 Status File::Read(void *buf, size_t &num_bytes) {
107   return std::error_code(ENOTSUP, std::system_category());
108 }
109 Status File::Write(const void *buf, size_t &num_bytes) {
110   return std::error_code(ENOTSUP, std::system_category());
111 }
112 
113 bool File::IsValid() const { return false; }
114 
115 Status File::Close() { return Flush(); }
116 
117 IOObject::WaitableHandle File::GetWaitableHandle() {
118   return IOObject::kInvalidHandleValue;
119 }
120 
121 Status File::GetFileSpec(FileSpec &file_spec) const {
122   file_spec.Clear();
123   return std::error_code(ENOTSUP, std::system_category());
124 }
125 
126 int File::GetDescriptor() const { return kInvalidDescriptor; }
127 
128 FILE *File::GetStream() { return nullptr; }
129 
130 off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
131   if (error_ptr)
132     *error_ptr = std::error_code(ENOTSUP, std::system_category());
133   return -1;
134 }
135 
136 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
137   if (error_ptr)
138     *error_ptr = std::error_code(ENOTSUP, std::system_category());
139   return -1;
140 }
141 
142 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
143   if (error_ptr)
144     *error_ptr = std::error_code(ENOTSUP, std::system_category());
145   return -1;
146 }
147 
148 Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
149   return std::error_code(ENOTSUP, std::system_category());
150 }
151 
152 Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
153   return std::error_code(ENOTSUP, std::system_category());
154 }
155 
156 Status File::Flush() { return Status(); }
157 
158 Status File::Sync() { return Flush(); }
159 
160 void File::CalculateInteractiveAndTerminal() {
161   const int fd = GetDescriptor();
162   if (!DescriptorIsValid(fd)) {
163     m_is_interactive = eLazyBoolNo;
164     m_is_real_terminal = eLazyBoolNo;
165     m_supports_colors = eLazyBoolNo;
166     return;
167   }
168   m_is_interactive = eLazyBoolNo;
169   m_is_real_terminal = eLazyBoolNo;
170 #if defined(_WIN32)
171   if (_isatty(fd)) {
172     m_is_interactive = eLazyBoolYes;
173     m_is_real_terminal = eLazyBoolYes;
174 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
175     m_supports_colors = eLazyBoolYes;
176 #endif
177   }
178 #else
179   if (isatty(fd)) {
180     m_is_interactive = eLazyBoolYes;
181     struct winsize window_size;
182     if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
183       if (window_size.ws_col > 0) {
184         m_is_real_terminal = eLazyBoolYes;
185         if (llvm::sys::Process::FileDescriptorHasColors(fd))
186           m_supports_colors = eLazyBoolYes;
187       }
188     }
189   }
190 #endif
191 }
192 
193 bool File::GetIsInteractive() {
194   if (m_is_interactive == eLazyBoolCalculate)
195     CalculateInteractiveAndTerminal();
196   return m_is_interactive == eLazyBoolYes;
197 }
198 
199 bool File::GetIsRealTerminal() {
200   if (m_is_real_terminal == eLazyBoolCalculate)
201     CalculateInteractiveAndTerminal();
202   return m_is_real_terminal == eLazyBoolYes;
203 }
204 
205 bool File::GetIsTerminalWithColors() {
206   if (m_supports_colors == eLazyBoolCalculate)
207     CalculateInteractiveAndTerminal();
208   return m_supports_colors == eLazyBoolYes;
209 }
210 
211 size_t File::Printf(const char *format, ...) {
212   va_list args;
213   va_start(args, format);
214   size_t result = PrintfVarArg(format, args);
215   va_end(args);
216   return result;
217 }
218 
219 size_t File::PrintfVarArg(const char *format, va_list args) {
220   llvm::SmallString<0> s;
221   if (VASprintf(s, format, args)) {
222     size_t written = s.size();;
223     Write(s.data(), written);
224     return written;
225   }
226   return 0;
227 }
228 
229 Expected<File::OpenOptions> File::GetOptions() const {
230   return llvm::createStringError(
231       llvm::inconvertibleErrorCode(),
232       "GetOptions() not implemented for this File class");
233 }
234 
235 uint32_t File::GetPermissions(Status &error) const {
236   int fd = GetDescriptor();
237   if (!DescriptorIsValid(fd)) {
238     error = std::error_code(ENOTSUP, std::system_category());
239     return 0;
240   }
241   struct stat file_stats;
242   if (::fstat(fd, &file_stats) == -1) {
243     error.SetErrorToErrno();
244     return 0;
245   }
246   error.Clear();
247   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
248 }
249 
250 Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
251 
252 int NativeFile::GetDescriptor() const {
253   if (DescriptorIsValid())
254     return m_descriptor;
255 
256   // Don't open the file descriptor if we don't need to, just get it from the
257   // stream if we have one.
258   if (StreamIsValid()) {
259 #if defined(_WIN32)
260     return _fileno(m_stream);
261 #else
262     return fileno(m_stream);
263 #endif
264   }
265 
266   // Invalid descriptor and invalid stream, return invalid descriptor.
267   return kInvalidDescriptor;
268 }
269 
270 IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
271   return GetDescriptor();
272 }
273 
274 FILE *NativeFile::GetStream() {
275   if (!StreamIsValid()) {
276     if (DescriptorIsValid()) {
277       auto mode = GetStreamOpenModeFromOptions(m_options);
278       if (!mode)
279         llvm::consumeError(mode.takeError());
280       else {
281         if (!m_own_descriptor) {
282 // We must duplicate the file descriptor if we don't own it because when you
283 // call fdopen, the stream will own the fd
284 #ifdef _WIN32
285           m_descriptor = ::_dup(GetDescriptor());
286 #else
287           m_descriptor = dup(GetDescriptor());
288 #endif
289           m_own_descriptor = true;
290         }
291 
292         m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
293                                                mode.get());
294 
295         // If we got a stream, then we own the stream and should no longer own
296         // the descriptor because fclose() will close it for us
297 
298         if (m_stream) {
299           m_own_stream = true;
300           m_own_descriptor = false;
301         }
302       }
303     }
304   }
305   return m_stream;
306 }
307 
308 Status NativeFile::Close() {
309   Status error;
310   if (StreamIsValid()) {
311     if (m_own_stream) {
312       if (::fclose(m_stream) == EOF)
313         error.SetErrorToErrno();
314     } else {
315       File::OpenOptions rw =
316           m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
317                        File::eOpenOptionReadWrite);
318 
319       if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
320         if (::fflush(m_stream) == EOF)
321           error.SetErrorToErrno();
322       }
323     }
324   }
325   if (DescriptorIsValid() && m_own_descriptor) {
326     if (::close(m_descriptor) != 0)
327       error.SetErrorToErrno();
328   }
329   m_descriptor = kInvalidDescriptor;
330   m_stream = kInvalidStream;
331   m_options = OpenOptions(0);
332   m_own_stream = false;
333   m_own_descriptor = false;
334   m_is_interactive = eLazyBoolCalculate;
335   m_is_real_terminal = eLazyBoolCalculate;
336   return error;
337 }
338 
339 Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
340   Status error;
341 #ifdef F_GETPATH
342   if (IsValid()) {
343     char path[PATH_MAX];
344     if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
345       error.SetErrorToErrno();
346     else
347       file_spec.SetFile(path, FileSpec::Style::native);
348   } else {
349     error.SetErrorString("invalid file handle");
350   }
351 #elif defined(__linux__)
352   char proc[64];
353   char path[PATH_MAX];
354   if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
355     error.SetErrorString("cannot resolve file descriptor");
356   else {
357     ssize_t len;
358     if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
359       error.SetErrorToErrno();
360     else {
361       path[len] = '\0';
362       file_spec.SetFile(path, FileSpec::Style::native);
363     }
364   }
365 #else
366   error.SetErrorString(
367       "NativeFile::GetFileSpec is not supported on this platform");
368 #endif
369 
370   if (error.Fail())
371     file_spec.Clear();
372   return error;
373 }
374 
375 off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
376   off_t result = 0;
377   if (DescriptorIsValid()) {
378     result = ::lseek(m_descriptor, offset, SEEK_SET);
379 
380     if (error_ptr) {
381       if (result == -1)
382         error_ptr->SetErrorToErrno();
383       else
384         error_ptr->Clear();
385     }
386   } else if (StreamIsValid()) {
387     result = ::fseek(m_stream, offset, SEEK_SET);
388 
389     if (error_ptr) {
390       if (result == -1)
391         error_ptr->SetErrorToErrno();
392       else
393         error_ptr->Clear();
394     }
395   } else if (error_ptr) {
396     error_ptr->SetErrorString("invalid file handle");
397   }
398   return result;
399 }
400 
401 off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
402   off_t result = -1;
403   if (DescriptorIsValid()) {
404     result = ::lseek(m_descriptor, offset, SEEK_CUR);
405 
406     if (error_ptr) {
407       if (result == -1)
408         error_ptr->SetErrorToErrno();
409       else
410         error_ptr->Clear();
411     }
412   } else if (StreamIsValid()) {
413     result = ::fseek(m_stream, offset, SEEK_CUR);
414 
415     if (error_ptr) {
416       if (result == -1)
417         error_ptr->SetErrorToErrno();
418       else
419         error_ptr->Clear();
420     }
421   } else if (error_ptr) {
422     error_ptr->SetErrorString("invalid file handle");
423   }
424   return result;
425 }
426 
427 off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
428   off_t result = -1;
429   if (DescriptorIsValid()) {
430     result = ::lseek(m_descriptor, offset, SEEK_END);
431 
432     if (error_ptr) {
433       if (result == -1)
434         error_ptr->SetErrorToErrno();
435       else
436         error_ptr->Clear();
437     }
438   } else if (StreamIsValid()) {
439     result = ::fseek(m_stream, offset, SEEK_END);
440 
441     if (error_ptr) {
442       if (result == -1)
443         error_ptr->SetErrorToErrno();
444       else
445         error_ptr->Clear();
446     }
447   } else if (error_ptr) {
448     error_ptr->SetErrorString("invalid file handle");
449   }
450   return result;
451 }
452 
453 Status NativeFile::Flush() {
454   Status error;
455   if (StreamIsValid()) {
456     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
457       error.SetErrorToErrno();
458   } else if (!DescriptorIsValid()) {
459     error.SetErrorString("invalid file handle");
460   }
461   return error;
462 }
463 
464 Status NativeFile::Sync() {
465   Status error;
466   if (DescriptorIsValid()) {
467 #ifdef _WIN32
468     int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
469     if (err == 0)
470       error.SetErrorToGenericError();
471 #else
472     if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
473       error.SetErrorToErrno();
474 #endif
475   } else {
476     error.SetErrorString("invalid file handle");
477   }
478   return error;
479 }
480 
481 #if defined(__APPLE__)
482 // Darwin kernels only can read/write <= INT_MAX bytes
483 #define MAX_READ_SIZE INT_MAX
484 #define MAX_WRITE_SIZE INT_MAX
485 #endif
486 
487 Status NativeFile::Read(void *buf, size_t &num_bytes) {
488   Status error;
489 
490 #if defined(MAX_READ_SIZE)
491   if (num_bytes > MAX_READ_SIZE) {
492     uint8_t *p = (uint8_t *)buf;
493     size_t bytes_left = num_bytes;
494     // Init the num_bytes read to zero
495     num_bytes = 0;
496 
497     while (bytes_left > 0) {
498       size_t curr_num_bytes;
499       if (bytes_left > MAX_READ_SIZE)
500         curr_num_bytes = MAX_READ_SIZE;
501       else
502         curr_num_bytes = bytes_left;
503 
504       error = Read(p + num_bytes, curr_num_bytes);
505 
506       // Update how many bytes were read
507       num_bytes += curr_num_bytes;
508       if (bytes_left < curr_num_bytes)
509         bytes_left = 0;
510       else
511         bytes_left -= curr_num_bytes;
512 
513       if (error.Fail())
514         break;
515     }
516     return error;
517   }
518 #endif
519 
520   ssize_t bytes_read = -1;
521   if (DescriptorIsValid()) {
522     bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
523     if (bytes_read == -1) {
524       error.SetErrorToErrno();
525       num_bytes = 0;
526     } else
527       num_bytes = bytes_read;
528   } else if (StreamIsValid()) {
529     bytes_read = ::fread(buf, 1, num_bytes, m_stream);
530 
531     if (bytes_read == 0) {
532       if (::feof(m_stream))
533         error.SetErrorString("feof");
534       else if (::ferror(m_stream))
535         error.SetErrorString("ferror");
536       num_bytes = 0;
537     } else
538       num_bytes = bytes_read;
539   } else {
540     num_bytes = 0;
541     error.SetErrorString("invalid file handle");
542   }
543   return error;
544 }
545 
546 Status NativeFile::Write(const void *buf, size_t &num_bytes) {
547   Status error;
548 
549 #if defined(MAX_WRITE_SIZE)
550   if (num_bytes > MAX_WRITE_SIZE) {
551     const uint8_t *p = (const uint8_t *)buf;
552     size_t bytes_left = num_bytes;
553     // Init the num_bytes written to zero
554     num_bytes = 0;
555 
556     while (bytes_left > 0) {
557       size_t curr_num_bytes;
558       if (bytes_left > MAX_WRITE_SIZE)
559         curr_num_bytes = MAX_WRITE_SIZE;
560       else
561         curr_num_bytes = bytes_left;
562 
563       error = Write(p + num_bytes, curr_num_bytes);
564 
565       // Update how many bytes were read
566       num_bytes += curr_num_bytes;
567       if (bytes_left < curr_num_bytes)
568         bytes_left = 0;
569       else
570         bytes_left -= curr_num_bytes;
571 
572       if (error.Fail())
573         break;
574     }
575     return error;
576   }
577 #endif
578 
579   ssize_t bytes_written = -1;
580   if (DescriptorIsValid()) {
581     bytes_written =
582         llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
583     if (bytes_written == -1) {
584       error.SetErrorToErrno();
585       num_bytes = 0;
586     } else
587       num_bytes = bytes_written;
588   } else if (StreamIsValid()) {
589     bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
590 
591     if (bytes_written == 0) {
592       if (::feof(m_stream))
593         error.SetErrorString("feof");
594       else if (::ferror(m_stream))
595         error.SetErrorString("ferror");
596       num_bytes = 0;
597     } else
598       num_bytes = bytes_written;
599 
600   } else {
601     num_bytes = 0;
602     error.SetErrorString("invalid file handle");
603   }
604 
605   return error;
606 }
607 
608 Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
609   Status error;
610 
611 #if defined(MAX_READ_SIZE)
612   if (num_bytes > MAX_READ_SIZE) {
613     uint8_t *p = (uint8_t *)buf;
614     size_t bytes_left = num_bytes;
615     // Init the num_bytes read to zero
616     num_bytes = 0;
617 
618     while (bytes_left > 0) {
619       size_t curr_num_bytes;
620       if (bytes_left > MAX_READ_SIZE)
621         curr_num_bytes = MAX_READ_SIZE;
622       else
623         curr_num_bytes = bytes_left;
624 
625       error = Read(p + num_bytes, curr_num_bytes, offset);
626 
627       // Update how many bytes were read
628       num_bytes += curr_num_bytes;
629       if (bytes_left < curr_num_bytes)
630         bytes_left = 0;
631       else
632         bytes_left -= curr_num_bytes;
633 
634       if (error.Fail())
635         break;
636     }
637     return error;
638   }
639 #endif
640 
641 #ifndef _WIN32
642   int fd = GetDescriptor();
643   if (fd != kInvalidDescriptor) {
644     ssize_t bytes_read =
645         llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
646     if (bytes_read < 0) {
647       num_bytes = 0;
648       error.SetErrorToErrno();
649     } else {
650       offset += bytes_read;
651       num_bytes = bytes_read;
652     }
653   } else {
654     num_bytes = 0;
655     error.SetErrorString("invalid file handle");
656   }
657 #else
658   std::lock_guard<std::mutex> guard(offset_access_mutex);
659   long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
660   SeekFromStart(offset);
661   error = Read(buf, num_bytes);
662   if (!error.Fail())
663     SeekFromStart(cur);
664 #endif
665   return error;
666 }
667 
668 Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
669   Status error;
670 
671 #if defined(MAX_WRITE_SIZE)
672   if (num_bytes > MAX_WRITE_SIZE) {
673     const uint8_t *p = (const uint8_t *)buf;
674     size_t bytes_left = num_bytes;
675     // Init the num_bytes written to zero
676     num_bytes = 0;
677 
678     while (bytes_left > 0) {
679       size_t curr_num_bytes;
680       if (bytes_left > MAX_WRITE_SIZE)
681         curr_num_bytes = MAX_WRITE_SIZE;
682       else
683         curr_num_bytes = bytes_left;
684 
685       error = Write(p + num_bytes, curr_num_bytes, offset);
686 
687       // Update how many bytes were read
688       num_bytes += curr_num_bytes;
689       if (bytes_left < curr_num_bytes)
690         bytes_left = 0;
691       else
692         bytes_left -= curr_num_bytes;
693 
694       if (error.Fail())
695         break;
696     }
697     return error;
698   }
699 #endif
700 
701   int fd = GetDescriptor();
702   if (fd != kInvalidDescriptor) {
703 #ifndef _WIN32
704     ssize_t bytes_written =
705         llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
706     if (bytes_written < 0) {
707       num_bytes = 0;
708       error.SetErrorToErrno();
709     } else {
710       offset += bytes_written;
711       num_bytes = bytes_written;
712     }
713 #else
714     std::lock_guard<std::mutex> guard(offset_access_mutex);
715     long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
716     SeekFromStart(offset);
717     error = Write(buf, num_bytes);
718     long after = ::lseek(m_descriptor, 0, SEEK_CUR);
719 
720     if (!error.Fail())
721       SeekFromStart(cur);
722 
723     offset = after;
724 #endif
725   } else {
726     num_bytes = 0;
727     error.SetErrorString("invalid file handle");
728   }
729   return error;
730 }
731 
732 size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
733   if (StreamIsValid()) {
734     return ::vfprintf(m_stream, format, args);
735   } else {
736     return File::PrintfVarArg(format, args);
737   }
738 }
739 
740 mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
741   mode_t mode = 0;
742   File::OpenOptions rw =
743       open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
744                       File::eOpenOptionReadWrite);
745   if (rw == eOpenOptionReadWrite)
746     mode |= O_RDWR;
747   else if (rw == eOpenOptionWriteOnly)
748     mode |= O_WRONLY;
749   else if (rw == eOpenOptionReadOnly)
750     mode |= O_RDONLY;
751 
752   if (open_options & eOpenOptionAppend)
753     mode |= O_APPEND;
754 
755   if (open_options & eOpenOptionTruncate)
756     mode |= O_TRUNC;
757 
758   if (open_options & eOpenOptionNonBlocking)
759     mode |= O_NONBLOCK;
760 
761   if (open_options & eOpenOptionCanCreateNewOnly)
762     mode |= O_CREAT | O_EXCL;
763   else if (open_options & eOpenOptionCanCreate)
764     mode |= O_CREAT;
765 
766   return mode;
767 }
768 
769 llvm::Expected<SerialPort::Options>
770 SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
771   SerialPort::Options serial_options;
772   for (llvm::StringRef x : llvm::split(urlqs, '&')) {
773     if (x.consume_front("baud=")) {
774       unsigned int baud_rate;
775       if (!llvm::to_integer(x, baud_rate, 10))
776         return llvm::createStringError(llvm::inconvertibleErrorCode(),
777                                        "Invalid baud rate: %s",
778                                        x.str().c_str());
779       serial_options.BaudRate = baud_rate;
780     } else if (x.consume_front("parity=")) {
781       serial_options.Parity =
782           llvm::StringSwitch<std::optional<Terminal::Parity>>(x)
783               .Case("no", Terminal::Parity::No)
784               .Case("even", Terminal::Parity::Even)
785               .Case("odd", Terminal::Parity::Odd)
786               .Case("mark", Terminal::Parity::Mark)
787               .Case("space", Terminal::Parity::Space)
788               .Default(std::nullopt);
789       if (!serial_options.Parity)
790         return llvm::createStringError(
791             llvm::inconvertibleErrorCode(),
792             "Invalid parity (must be no, even, odd, mark or space): %s",
793             x.str().c_str());
794     } else if (x.consume_front("parity-check=")) {
795       serial_options.ParityCheck =
796           llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)
797               .Case("no", Terminal::ParityCheck::No)
798               .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
799               .Case("ignore", Terminal::ParityCheck::Ignore)
800               // "mark" mode is not currently supported as it requires special
801               // input processing
802               // .Case("mark", Terminal::ParityCheck::Mark)
803               .Default(std::nullopt);
804       if (!serial_options.ParityCheck)
805         return llvm::createStringError(
806             llvm::inconvertibleErrorCode(),
807             "Invalid parity-check (must be no, replace, ignore or mark): %s",
808             x.str().c_str());
809     } else if (x.consume_front("stop-bits=")) {
810       unsigned int stop_bits;
811       if (!llvm::to_integer(x, stop_bits, 10) ||
812           (stop_bits != 1 && stop_bits != 2))
813         return llvm::createStringError(
814             llvm::inconvertibleErrorCode(),
815             "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
816       serial_options.StopBits = stop_bits;
817     } else
818       return llvm::createStringError(llvm::inconvertibleErrorCode(),
819                                      "Unknown parameter: %s", x.str().c_str());
820   }
821   return serial_options;
822 }
823 
824 llvm::Expected<std::unique_ptr<SerialPort>>
825 SerialPort::Create(int fd, OpenOptions options, Options serial_options,
826                    bool transfer_ownership) {
827   std::unique_ptr<SerialPort> out{
828       new SerialPort(fd, options, serial_options, transfer_ownership)};
829 
830   if (!out->GetIsInteractive())
831     return llvm::createStringError(llvm::inconvertibleErrorCode(),
832                                    "the specified file is not a teletype");
833 
834   Terminal term{fd};
835   if (llvm::Error error = term.SetRaw())
836     return std::move(error);
837   if (serial_options.BaudRate) {
838     if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))
839       return std::move(error);
840   }
841   if (serial_options.Parity) {
842     if (llvm::Error error = term.SetParity(*serial_options.Parity))
843       return std::move(error);
844   }
845   if (serial_options.ParityCheck) {
846     if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))
847       return std::move(error);
848   }
849   if (serial_options.StopBits) {
850     if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))
851       return std::move(error);
852   }
853 
854   return std::move(out);
855 }
856 
857 SerialPort::SerialPort(int fd, OpenOptions options,
858                        SerialPort::Options serial_options,
859                        bool transfer_ownership)
860     : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
861 
862 Status SerialPort::Close() {
863   m_state.Restore();
864   return NativeFile::Close();
865 }
866 
867 char File::ID = 0;
868 char NativeFile::ID = 0;
869 char SerialPort::ID = 0;
870