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