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 *>
GetStreamOpenModeFromOptions(File::OpenOptions options)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
GetOptionsFromMode(llvm::StringRef mode)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
Read(void * buf,size_t & num_bytes)104 Status File::Read(void *buf, size_t &num_bytes) {
105 return std::error_code(ENOTSUP, std::system_category());
106 }
Write(const void * buf,size_t & num_bytes)107 Status File::Write(const void *buf, size_t &num_bytes) {
108 return std::error_code(ENOTSUP, std::system_category());
109 }
110
IsValid() const111 bool File::IsValid() const { return false; }
112
Close()113 Status File::Close() { return Flush(); }
114
GetWaitableHandle()115 IOObject::WaitableHandle File::GetWaitableHandle() {
116 return IOObject::kInvalidHandleValue;
117 }
118
GetFileSpec(FileSpec & file_spec) const119 Status File::GetFileSpec(FileSpec &file_spec) const {
120 file_spec.Clear();
121 return std::error_code(ENOTSUP, std::system_category());
122 }
123
GetDescriptor() const124 int File::GetDescriptor() const { return kInvalidDescriptor; }
125
GetStream()126 FILE *File::GetStream() { return nullptr; }
127
SeekFromStart(off_t offset,Status * error_ptr)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
SeekFromCurrent(off_t offset,Status * error_ptr)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
SeekFromEnd(off_t offset,Status * error_ptr)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
Read(void * dst,size_t & num_bytes,off_t & offset)146 Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
147 return std::error_code(ENOTSUP, std::system_category());
148 }
149
Write(const void * src,size_t & num_bytes,off_t & offset)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
Flush()154 Status File::Flush() { return Status(); }
155
Sync()156 Status File::Sync() { return Flush(); }
157
CalculateInteractiveAndTerminal()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
GetIsInteractive()191 bool File::GetIsInteractive() {
192 if (m_is_interactive == eLazyBoolCalculate)
193 CalculateInteractiveAndTerminal();
194 return m_is_interactive == eLazyBoolYes;
195 }
196
GetIsRealTerminal()197 bool File::GetIsRealTerminal() {
198 if (m_is_real_terminal == eLazyBoolCalculate)
199 CalculateInteractiveAndTerminal();
200 return m_is_real_terminal == eLazyBoolYes;
201 }
202
GetIsTerminalWithColors()203 bool File::GetIsTerminalWithColors() {
204 if (m_supports_colors == eLazyBoolCalculate)
205 CalculateInteractiveAndTerminal();
206 return m_supports_colors == eLazyBoolYes;
207 }
208
Printf(const char * format,...)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
PrintfVarArg(const char * format,va_list args)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
GetOptions() const227 Expected<File::OpenOptions> File::GetOptions() const {
228 return llvm::createStringError(
229 llvm::inconvertibleErrorCode(),
230 "GetOptions() not implemented for this File class");
231 }
232
GetPermissions(Status & error) const233 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
GetOptions() const248 Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
249
GetDescriptor() const250 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
GetWaitableHandle()268 IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
269 return GetDescriptor();
270 }
271
GetStream()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
Close()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
GetFileSpec(FileSpec & file_spec) const337 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
SeekFromStart(off_t offset,Status * error_ptr)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
SeekFromCurrent(off_t offset,Status * error_ptr)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
SeekFromEnd(off_t offset,Status * error_ptr)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
Flush()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
Sync()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
Read(void * buf,size_t & num_bytes)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
Write(const void * buf,size_t & num_bytes)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
Read(void * buf,size_t & num_bytes,off_t & offset)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
Write(const void * buf,size_t & num_bytes,off_t & offset)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
PrintfVarArg(const char * format,va_list args)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
ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options)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>
OptionsFromURL(llvm::StringRef urlqs)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>>
Create(int fd,OpenOptions options,Options serial_options,bool transfer_ownership)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
SerialPort(int fd,OpenOptions options,SerialPort::Options serial_options,bool transfer_ownership)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
Close()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