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