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