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