Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/common/File.cpp
Line
Count
Source (jump to first uncovered line)
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
941
File::GetStreamOpenModeFromOptions(File::OpenOptions options) {
46
941
  File::OpenOptions rw =
47
941
      options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
48
941
                 File::eOpenOptionReadWrite);
49
50
941
  if (options & File::eOpenOptionAppend) {
51
0
    if (rw == File::eOpenOptionReadWrite) {
52
0
      if (options & File::eOpenOptionCanCreateNewOnly)
53
0
        return "a+x";
54
0
      else
55
0
        return "a+";
56
0
    } else if (rw == File::eOpenOptionWriteOnly) {
57
0
      if (options & File::eOpenOptionCanCreateNewOnly)
58
0
        return "ax";
59
0
      else
60
0
        return "a";
61
0
    }
62
941
  } else if (rw == File::eOpenOptionReadWrite) {
63
0
    if (options & File::eOpenOptionCanCreate) {
64
0
      if (options & File::eOpenOptionCanCreateNewOnly)
65
0
        return "w+x";
66
0
      else
67
0
        return "w+";
68
0
    } else
69
0
      return "r+";
70
941
  } else if (rw == File::eOpenOptionWriteOnly) {
71
31
    return "w";
72
910
  } else if (rw == File::eOpenOptionReadOnly) {
73
910
    return "r";
74
910
  }
75
0
  return llvm::createStringError(
76
0
      llvm::inconvertibleErrorCode(),
77
0
      "invalid options, cannot convert to mode string");
78
941
}
79
80
19
Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) {
81
19
  OpenOptions opts =
82
19
      llvm::StringSwitch<OpenOptions>(mode)
83
19
          .Cases("r", "rb", eOpenOptionReadOnly)
84
19
          .Cases("w", "wb", eOpenOptionWriteOnly)
85
19
          .Cases("a", "ab",
86
19
                 eOpenOptionWriteOnly | eOpenOptionAppend |
87
19
                 eOpenOptionCanCreate)
88
19
          .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite)
89
19
          .Cases("w+", "wb+", "w+b",
90
19
                 eOpenOptionReadWrite | eOpenOptionCanCreate |
91
19
                 eOpenOptionTruncate)
92
19
          .Cases("a+", "ab+", "a+b",
93
19
                 eOpenOptionReadWrite | eOpenOptionAppend |
94
19
                     eOpenOptionCanCreate)
95
19
          .Default(eOpenOptionInvalid);
96
19
  if (opts != eOpenOptionInvalid)
97
19
    return opts;
98
0
  return llvm::createStringError(
99
0
      llvm::inconvertibleErrorCode(),
100
0
      "invalid mode, cannot convert to File::OpenOptions");
101
19
}
102
103
int File::kInvalidDescriptor = -1;
104
FILE *File::kInvalidStream = nullptr;
105
106
0
Status File::Read(void *buf, size_t &num_bytes) {
107
0
  return std::error_code(ENOTSUP, std::system_category());
108
0
}
109
0
Status File::Write(const void *buf, size_t &num_bytes) {
110
0
  return std::error_code(ENOTSUP, std::system_category());
111
0
}
112
113
0
bool File::IsValid() const { return false; }
114
115
32
Status File::Close() { return Flush(); }
116
117
0
IOObject::WaitableHandle File::GetWaitableHandle() {
118
0
  return IOObject::kInvalidHandleValue;
119
0
}
120
121
0
Status File::GetFileSpec(FileSpec &file_spec) const {
122
0
  file_spec.Clear();
123
0
  return std::error_code(ENOTSUP, std::system_category());
124
0
}
125
126
0
int File::GetDescriptor() const { return kInvalidDescriptor; }
127
128
8
FILE *File::GetStream() { return nullptr; }
129
130
0
off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
131
0
  if (error_ptr)
132
0
    *error_ptr = std::error_code(ENOTSUP, std::system_category());
133
0
  return -1;
134
0
}
135
136
0
off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
137
0
  if (error_ptr)
138
0
    *error_ptr = std::error_code(ENOTSUP, std::system_category());
139
0
  return -1;
140
0
}
141
142
0
off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
143
0
  if (error_ptr)
144
0
    *error_ptr = std::error_code(ENOTSUP, std::system_category());
145
0
  return -1;
146
0
}
147
148
0
Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
149
0
  return std::error_code(ENOTSUP, std::system_category());
150
0
}
151
152
0
Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
153
0
  return std::error_code(ENOTSUP, std::system_category());
154
0
}
155
156
32
Status File::Flush() { return Status(); }
157
158
0
Status File::Sync() { return Flush(); }
159
160
7.69k
void File::CalculateInteractiveAndTerminal() {
161
7.69k
  const int fd = GetDescriptor();
162
7.69k
  if (!DescriptorIsValid(fd)) {
163
3
    m_is_interactive = eLazyBoolNo;
164
3
    m_is_real_terminal = eLazyBoolNo;
165
3
    m_supports_colors = eLazyBoolNo;
166
3
    return;
167
3
  }
168
7.68k
  m_is_interactive = eLazyBoolNo;
169
7.68k
  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
7.68k
  if (isatty(fd)) {
180
31
    m_is_interactive = eLazyBoolYes;
181
31
    struct winsize window_size;
182
31
    if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
183
31
      if (window_size.ws_col > 0) {
184
28
        m_is_real_terminal = eLazyBoolYes;
185
28
        if (llvm::sys::Process::FileDescriptorHasColors(fd))
186
28
          m_supports_colors = eLazyBoolYes;
187
28
      }
188
31
    }
189
31
  }
190
7.68k
#endif
191
7.68k
}
192
193
36.8k
bool File::GetIsInteractive() {
194
36.8k
  if (m_is_interactive == eLazyBoolCalculate)
195
207
    CalculateInteractiveAndTerminal();
196
36.8k
  return m_is_interactive == eLazyBoolYes;
197
36.8k
}
198
199
1.44k
bool File::GetIsRealTerminal() {
200
1.44k
  if (m_is_real_terminal == eLazyBoolCalculate)
201
1.42k
    CalculateInteractiveAndTerminal();
202
1.44k
  return m_is_real_terminal == eLazyBoolYes;
203
1.44k
}
204
205
8.25k
bool File::GetIsTerminalWithColors() {
206
8.25k
  if (m_supports_colors == eLazyBoolCalculate)
207
6.05k
    CalculateInteractiveAndTerminal();
208
8.25k
  return m_supports_colors == eLazyBoolYes;
209
8.25k
}
210
211
1.68k
size_t File::Printf(const char *format, ...) {
212
1.68k
  va_list args;
213
1.68k
  va_start(args, format);
214
1.68k
  size_t result = PrintfVarArg(format, args);
215
1.68k
  va_end(args);
216
1.68k
  return result;
217
1.68k
}
218
219
115
size_t File::PrintfVarArg(const char *format, va_list args) {
220
115
  llvm::SmallString<0> s;
221
115
  if (VASprintf(s, format, args)) {
222
115
    size_t written = s.size();
223
115
    Write(s.data(), written);
224
115
    return written;
225
115
  }
226
0
  return 0;
227
115
}
228
229
0
Expected<File::OpenOptions> File::GetOptions() const {
230
0
  return llvm::createStringError(
231
0
      llvm::inconvertibleErrorCode(),
232
0
      "GetOptions() not implemented for this File class");
233
0
}
234
235
2
uint32_t File::GetPermissions(Status &error) const {
236
2
  int fd = GetDescriptor();
237
2
  if (!DescriptorIsValid(fd)) {
238
0
    error = std::error_code(ENOTSUP, std::system_category());
239
0
    return 0;
240
0
  }
241
2
  struct stat file_stats;
242
2
  if (::fstat(fd, &file_stats) == -1) {
243
0
    error.SetErrorToErrno();
244
0
    return 0;
245
0
  }
246
2
  error.Clear();
247
2
  return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
248
2
}
249
250
1.87M
bool NativeFile::IsValid() const {
251
1.87M
  std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
252
1.87M
  return DescriptorIsValidUnlocked() || 
StreamIsValidUnlocked()495k
;
253
1.87M
}
254
255
18
Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; }
256
257
928k
int NativeFile::GetDescriptor() const {
258
928k
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
259
910k
    return m_descriptor;
260
910k
  }
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
17.5k
  
if (ValueGuard 17.4k
stream_guard17.4k
= StreamIsValid()) {
265
#if defined(_WIN32)
266
    return _fileno(m_stream);
267
#else
268
17.5k
    return fileno(m_stream);
269
17.5k
#endif
270
17.5k
  }
271
272
  // Invalid descriptor and invalid stream, return invalid descriptor.
273
18.4E
  return kInvalidDescriptor;
274
17.4k
}
275
276
898k
IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
277
898k
  return GetDescriptor();
278
898k
}
279
280
13.1k
FILE *NativeFile::GetStream() {
281
13.1k
  ValueGuard stream_guard = StreamIsValid();
282
13.1k
  if (!stream_guard) {
283
924
    if (ValueGuard descriptor_guard = DescriptorIsValid()) {
284
923
      auto mode = GetStreamOpenModeFromOptions(m_options);
285
923
      if (!mode)
286
0
        llvm::consumeError(mode.takeError());
287
923
      else {
288
923
        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
24
          m_descriptor = dup(m_descriptor);
295
24
#endif
296
24
          m_own_descriptor = true;
297
24
        }
298
299
923
        m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor,
300
923
                                               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
923
        if (m_stream) {
306
922
          m_own_stream = true;
307
922
          m_own_descriptor = false;
308
922
        }
309
923
      }
310
923
    }
311
924
  }
312
13.1k
  return m_stream;
313
13.1k
}
314
315
59.2k
Status NativeFile::Close() {
316
59.2k
  std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
317
318
59.2k
  Status error;
319
320
59.2k
  if (StreamIsValidUnlocked()) {
321
20.8k
    if (m_own_stream) {
322
1.52k
      if (::fclose(m_stream) == EOF)
323
127
        error.SetErrorToErrno();
324
19.3k
    } else {
325
19.3k
      File::OpenOptions rw =
326
19.3k
          m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
327
19.3k
                       File::eOpenOptionReadWrite);
328
329
19.3k
      if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) {
330
0
        if (::fflush(m_stream) == EOF)
331
0
          error.SetErrorToErrno();
332
0
      }
333
19.3k
    }
334
20.8k
  }
335
336
59.2k
  if (DescriptorIsValidUnlocked() && 
m_own_descriptor24.9k
) {
337
19.6k
    if (::close(m_descriptor) != 0)
338
0
      error.SetErrorToErrno();
339
19.6k
  }
340
341
59.2k
  m_stream = kInvalidStream;
342
59.2k
  m_own_stream = false;
343
59.2k
  m_descriptor = kInvalidDescriptor;
344
59.2k
  m_own_descriptor = false;
345
59.2k
  m_options = OpenOptions(0);
346
59.2k
  m_is_interactive = eLazyBoolCalculate;
347
59.2k
  m_is_real_terminal = eLazyBoolCalculate;
348
59.2k
  return error;
349
59.2k
}
350
351
0
Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
352
0
  Status error;
353
0
#ifdef F_GETPATH
354
0
  if (IsValid()) {
355
0
    char path[PATH_MAX];
356
0
    if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
357
0
      error.SetErrorToErrno();
358
0
    else
359
0
      file_spec.SetFile(path, FileSpec::Style::native);
360
0
  } else {
361
0
    error.SetErrorString("invalid file handle");
362
0
  }
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
0
  if (error.Fail())
383
0
    file_spec.Clear();
384
0
  return error;
385
0
}
386
387
1
off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
388
1
  off_t result = 0;
389
1
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
390
1
    result = ::lseek(m_descriptor, offset, SEEK_SET);
391
392
1
    if (error_ptr) {
393
1
      if (result == -1)
394
0
        error_ptr->SetErrorToErrno();
395
1
      else
396
1
        error_ptr->Clear();
397
1
    }
398
1
    return result;
399
1
  }
400
401
0
  if (ValueGuard stream_guard = StreamIsValid()) {
402
0
    result = ::fseek(m_stream, offset, SEEK_SET);
403
404
0
    if (error_ptr) {
405
0
      if (result == -1)
406
0
        error_ptr->SetErrorToErrno();
407
0
      else
408
0
        error_ptr->Clear();
409
0
    }
410
0
    return result;
411
0
  }
412
413
0
  if (error_ptr)
414
0
    error_ptr->SetErrorString("invalid file handle");
415
0
  return result;
416
0
}
417
418
0
off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
419
0
  off_t result = -1;
420
0
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
421
0
    result = ::lseek(m_descriptor, offset, SEEK_CUR);
422
423
0
    if (error_ptr) {
424
0
      if (result == -1)
425
0
        error_ptr->SetErrorToErrno();
426
0
      else
427
0
        error_ptr->Clear();
428
0
    }
429
0
    return result;
430
0
  }
431
432
0
  if (ValueGuard stream_guard = StreamIsValid()) {
433
0
    result = ::fseek(m_stream, offset, SEEK_CUR);
434
435
0
    if (error_ptr) {
436
0
      if (result == -1)
437
0
        error_ptr->SetErrorToErrno();
438
0
      else
439
0
        error_ptr->Clear();
440
0
    }
441
0
    return result;
442
0
  }
443
444
0
  if (error_ptr)
445
0
    error_ptr->SetErrorString("invalid file handle");
446
0
  return result;
447
0
}
448
449
0
off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
450
0
  off_t result = -1;
451
0
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
452
0
    result = ::lseek(m_descriptor, offset, SEEK_END);
453
454
0
    if (error_ptr) {
455
0
      if (result == -1)
456
0
        error_ptr->SetErrorToErrno();
457
0
      else
458
0
        error_ptr->Clear();
459
0
    }
460
0
    return result;
461
0
  }
462
463
0
  if (ValueGuard stream_guard = StreamIsValid()) {
464
0
    result = ::fseek(m_stream, offset, SEEK_END);
465
466
0
    if (error_ptr) {
467
0
      if (result == -1)
468
0
        error_ptr->SetErrorToErrno();
469
0
      else
470
0
        error_ptr->Clear();
471
0
    }
472
0
  }
473
474
0
  if (error_ptr)
475
0
    error_ptr->SetErrorString("invalid file handle");
476
0
  return result;
477
0
}
478
479
29.5k
Status NativeFile::Flush() {
480
29.5k
  Status error;
481
29.5k
  if (ValueGuard stream_guard = StreamIsValid()) {
482
18.6k
    if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
483
0
      error.SetErrorToErrno();
484
18.6k
    return error;
485
18.6k
  }
486
487
10.9k
  {
488
10.9k
    ValueGuard descriptor_guard = DescriptorIsValid();
489
10.9k
    if (!descriptor_guard)
490
0
      error.SetErrorString("invalid file handle");
491
10.9k
  }
492
10.9k
  return error;
493
29.5k
}
494
495
0
Status NativeFile::Sync() {
496
0
  Status error;
497
0
  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
0
    if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
504
0
      error.SetErrorToErrno();
505
0
#endif
506
0
  } else {
507
0
    error.SetErrorString("invalid file handle");
508
0
  }
509
0
  return error;
510
0
}
511
512
#if defined(__APPLE__)
513
// Darwin kernels only can read/write <= INT_MAX bytes
514
433k
#define MAX_READ_SIZE INT_MAX
515
371k
#define MAX_WRITE_SIZE INT_MAX
516
#endif
517
518
433k
Status NativeFile::Read(void *buf, size_t &num_bytes) {
519
433k
  Status error;
520
521
433k
#if defined(MAX_READ_SIZE)
522
433k
  if (num_bytes > MAX_READ_SIZE) {
523
0
    uint8_t *p = (uint8_t *)buf;
524
0
    size_t bytes_left = num_bytes;
525
    // Init the num_bytes read to zero
526
0
    num_bytes = 0;
527
528
0
    while (bytes_left > 0) {
529
0
      size_t curr_num_bytes;
530
0
      if (bytes_left > MAX_READ_SIZE)
531
0
        curr_num_bytes = MAX_READ_SIZE;
532
0
      else
533
0
        curr_num_bytes = bytes_left;
534
535
0
      error = Read(p + num_bytes, curr_num_bytes);
536
537
      // Update how many bytes were read
538
0
      num_bytes += curr_num_bytes;
539
0
      if (bytes_left < curr_num_bytes)
540
0
        bytes_left = 0;
541
0
      else
542
0
        bytes_left -= curr_num_bytes;
543
544
0
      if (error.Fail())
545
0
        break;
546
0
    }
547
0
    return error;
548
0
  }
549
433k
#endif
550
551
433k
  ssize_t bytes_read = -1;
552
433k
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
553
433k
    bytes_read =
554
433k
        llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
555
433k
    if (bytes_read == -1) {
556
0
      error.SetErrorToErrno();
557
0
      num_bytes = 0;
558
0
    } else
559
433k
      num_bytes = bytes_read;
560
433k
    return error;
561
433k
  }
562
563
0
  if (ValueGuard file_lock = StreamIsValid()) {
564
0
    bytes_read = ::fread(buf, 1, num_bytes, m_stream);
565
566
0
    if (bytes_read == 0) {
567
0
      if (::feof(m_stream))
568
0
        error.SetErrorString("feof");
569
0
      else if (::ferror(m_stream))
570
0
        error.SetErrorString("ferror");
571
0
      num_bytes = 0;
572
0
    } else
573
0
      num_bytes = bytes_read;
574
0
    return error;
575
0
  }
576
577
0
  num_bytes = 0;
578
0
  error.SetErrorString("invalid file handle");
579
0
  return error;
580
0
}
581
582
371k
Status NativeFile::Write(const void *buf, size_t &num_bytes) {
583
371k
  Status error;
584
585
371k
#if defined(MAX_WRITE_SIZE)
586
371k
  if (num_bytes > MAX_WRITE_SIZE) {
587
0
    const uint8_t *p = (const uint8_t *)buf;
588
0
    size_t bytes_left = num_bytes;
589
    // Init the num_bytes written to zero
590
0
    num_bytes = 0;
591
592
0
    while (bytes_left > 0) {
593
0
      size_t curr_num_bytes;
594
0
      if (bytes_left > MAX_WRITE_SIZE)
595
0
        curr_num_bytes = MAX_WRITE_SIZE;
596
0
      else
597
0
        curr_num_bytes = bytes_left;
598
599
0
      error = Write(p + num_bytes, curr_num_bytes);
600
601
      // Update how many bytes were read
602
0
      num_bytes += curr_num_bytes;
603
0
      if (bytes_left < curr_num_bytes)
604
0
        bytes_left = 0;
605
0
      else
606
0
        bytes_left -= curr_num_bytes;
607
608
0
      if (error.Fail())
609
0
        break;
610
0
    }
611
0
    return error;
612
0
  }
613
371k
#endif
614
615
371k
  ssize_t bytes_written = -1;
616
371k
  if (ValueGuard descriptor_guard = DescriptorIsValid()) {
617
335k
    bytes_written =
618
335k
        llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
619
335k
    if (bytes_written == -1) {
620
224
      error.SetErrorToErrno();
621
224
      num_bytes = 0;
622
224
    } else
623
335k
      num_bytes = bytes_written;
624
335k
    return error;
625
335k
  }
626
627
35.7k
  if (ValueGuard stream_guard = StreamIsValid()) {
628
35.7k
    bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
629
630
35.7k
    if (bytes_written == 0) {
631
782
      if (::feof(m_stream))
632
0
        error.SetErrorString("feof");
633
782
      else if (::ferror(m_stream))
634
0
        error.SetErrorString("ferror");
635
782
      num_bytes = 0;
636
782
    } else
637
34.9k
      num_bytes = bytes_written;
638
35.7k
    return error;
639
35.7k
  }
640
641
0
  num_bytes = 0;
642
0
  error.SetErrorString("invalid file handle");
643
0
  return error;
644
35.7k
}
645
646
0
Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
647
0
  Status error;
648
649
0
#if defined(MAX_READ_SIZE)
650
0
  if (num_bytes > MAX_READ_SIZE) {
651
0
    uint8_t *p = (uint8_t *)buf;
652
0
    size_t bytes_left = num_bytes;
653
    // Init the num_bytes read to zero
654
0
    num_bytes = 0;
655
656
0
    while (bytes_left > 0) {
657
0
      size_t curr_num_bytes;
658
0
      if (bytes_left > MAX_READ_SIZE)
659
0
        curr_num_bytes = MAX_READ_SIZE;
660
0
      else
661
0
        curr_num_bytes = bytes_left;
662
663
0
      error = Read(p + num_bytes, curr_num_bytes, offset);
664
665
      // Update how many bytes were read
666
0
      num_bytes += curr_num_bytes;
667
0
      if (bytes_left < curr_num_bytes)
668
0
        bytes_left = 0;
669
0
      else
670
0
        bytes_left -= curr_num_bytes;
671
672
0
      if (error.Fail())
673
0
        break;
674
0
    }
675
0
    return error;
676
0
  }
677
0
#endif
678
679
0
#ifndef _WIN32
680
0
  int fd = GetDescriptor();
681
0
  if (fd != kInvalidDescriptor) {
682
0
    ssize_t bytes_read =
683
0
        llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
684
0
    if (bytes_read < 0) {
685
0
      num_bytes = 0;
686
0
      error.SetErrorToErrno();
687
0
    } else {
688
0
      offset += bytes_read;
689
0
      num_bytes = bytes_read;
690
0
    }
691
0
  } else {
692
0
    num_bytes = 0;
693
0
    error.SetErrorString("invalid file handle");
694
0
  }
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
0
  return error;
704
0
}
705
706
0
Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
707
0
  Status error;
708
709
0
#if defined(MAX_WRITE_SIZE)
710
0
  if (num_bytes > MAX_WRITE_SIZE) {
711
0
    const uint8_t *p = (const uint8_t *)buf;
712
0
    size_t bytes_left = num_bytes;
713
    // Init the num_bytes written to zero
714
0
    num_bytes = 0;
715
716
0
    while (bytes_left > 0) {
717
0
      size_t curr_num_bytes;
718
0
      if (bytes_left > MAX_WRITE_SIZE)
719
0
        curr_num_bytes = MAX_WRITE_SIZE;
720
0
      else
721
0
        curr_num_bytes = bytes_left;
722
723
0
      error = Write(p + num_bytes, curr_num_bytes, offset);
724
725
      // Update how many bytes were read
726
0
      num_bytes += curr_num_bytes;
727
0
      if (bytes_left < curr_num_bytes)
728
0
        bytes_left = 0;
729
0
      else
730
0
        bytes_left -= curr_num_bytes;
731
732
0
      if (error.Fail())
733
0
        break;
734
0
    }
735
0
    return error;
736
0
  }
737
0
#endif
738
739
0
  int fd = GetDescriptor();
740
0
  if (fd != kInvalidDescriptor) {
741
0
#ifndef _WIN32
742
0
    ssize_t bytes_written =
743
0
        llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
744
0
    if (bytes_written < 0) {
745
0
      num_bytes = 0;
746
0
      error.SetErrorToErrno();
747
0
    } else {
748
0
      offset += bytes_written;
749
0
      num_bytes = bytes_written;
750
0
    }
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
0
  } else {
764
0
    num_bytes = 0;
765
0
    error.SetErrorString("invalid file handle");
766
0
  }
767
0
  return error;
768
0
}
769
770
1.68k
size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
771
1.68k
  if (StreamIsValid()) {
772
1.57k
    return ::vfprintf(m_stream, format, args);
773
1.57k
  } else {
774
114
    return File::PrintfVarArg(format, args);
775
114
  }
776
1.68k
}
777
778
0
mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) {
779
0
  mode_t mode = 0;
780
0
  File::OpenOptions rw =
781
0
      open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
782
0
                      File::eOpenOptionReadWrite);
783
0
  if (rw == eOpenOptionReadWrite)
784
0
    mode |= O_RDWR;
785
0
  else if (rw == eOpenOptionWriteOnly)
786
0
    mode |= O_WRONLY;
787
0
  else if (rw == eOpenOptionReadOnly)
788
0
    mode |= O_RDONLY;
789
790
0
  if (open_options & eOpenOptionAppend)
791
0
    mode |= O_APPEND;
792
793
0
  if (open_options & eOpenOptionTruncate)
794
0
    mode |= O_TRUNC;
795
796
0
  if (open_options & eOpenOptionNonBlocking)
797
0
    mode |= O_NONBLOCK;
798
799
0
  if (open_options & eOpenOptionCanCreateNewOnly)
800
0
    mode |= O_CREAT | O_EXCL;
801
0
  else if (open_options & eOpenOptionCanCreate)
802
0
    mode |= O_CREAT;
803
804
0
  return mode;
805
0
}
806
807
llvm::Expected<SerialPort::Options>
808
3
SerialPort::OptionsFromURL(llvm::StringRef urlqs) {
809
3
  SerialPort::Options serial_options;
810
3
  for (llvm::StringRef x : llvm::split(urlqs, '&')) {
811
2
    if (x.consume_front("baud=")) {
812
1
      unsigned int baud_rate;
813
1
      if (!llvm::to_integer(x, baud_rate, 10))
814
0
        return llvm::createStringError(llvm::inconvertibleErrorCode(),
815
0
                                       "Invalid baud rate: %s",
816
0
                                       x.str().c_str());
817
1
      serial_options.BaudRate = baud_rate;
818
1
    } else if (x.consume_front("parity=")) {
819
0
      serial_options.Parity =
820
0
          llvm::StringSwitch<std::optional<Terminal::Parity>>(x)
821
0
              .Case("no", Terminal::Parity::No)
822
0
              .Case("even", Terminal::Parity::Even)
823
0
              .Case("odd", Terminal::Parity::Odd)
824
0
              .Case("mark", Terminal::Parity::Mark)
825
0
              .Case("space", Terminal::Parity::Space)
826
0
              .Default(std::nullopt);
827
0
      if (!serial_options.Parity)
828
0
        return llvm::createStringError(
829
0
            llvm::inconvertibleErrorCode(),
830
0
            "Invalid parity (must be no, even, odd, mark or space): %s",
831
0
            x.str().c_str());
832
1
    } else if (x.consume_front("parity-check=")) {
833
0
      serial_options.ParityCheck =
834
0
          llvm::StringSwitch<std::optional<Terminal::ParityCheck>>(x)
835
0
              .Case("no", Terminal::ParityCheck::No)
836
0
              .Case("replace", Terminal::ParityCheck::ReplaceWithNUL)
837
0
              .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
0
              .Default(std::nullopt);
842
0
      if (!serial_options.ParityCheck)
843
0
        return llvm::createStringError(
844
0
            llvm::inconvertibleErrorCode(),
845
0
            "Invalid parity-check (must be no, replace, ignore or mark): %s",
846
0
            x.str().c_str());
847
1
    } else if (x.consume_front("stop-bits=")) {
848
1
      unsigned int stop_bits;
849
1
      if (!llvm::to_integer(x, stop_bits, 10) ||
850
1
          (stop_bits != 1 && stop_bits != 2))
851
0
        return llvm::createStringError(
852
0
            llvm::inconvertibleErrorCode(),
853
0
            "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str());
854
1
      serial_options.StopBits = stop_bits;
855
1
    } else
856
0
      return llvm::createStringError(llvm::inconvertibleErrorCode(),
857
0
                                     "Unknown parameter: %s", x.str().c_str());
858
2
  }
859
3
  return serial_options;
860
3
}
861
862
llvm::Expected<std::unique_ptr<SerialPort>>
863
SerialPort::Create(int fd, OpenOptions options, Options serial_options,
864
3
                   bool transfer_ownership) {
865
3
  std::unique_ptr<SerialPort> out{
866
3
      new SerialPort(fd, options, serial_options, transfer_ownership)};
867
868
3
  if (!out->GetIsInteractive())
869
0
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
870
0
                                   "the specified file is not a teletype");
871
872
3
  Terminal term{fd};
873
3
  if (llvm::Error error = term.SetRaw())
874
0
    return std::move(error);
875
3
  if (serial_options.BaudRate) {
876
1
    if (llvm::Error error = term.SetBaudRate(*serial_options.BaudRate))
877
0
      return std::move(error);
878
1
  }
879
3
  if (serial_options.Parity) {
880
0
    if (llvm::Error error = term.SetParity(*serial_options.Parity))
881
0
      return std::move(error);
882
0
  }
883
3
  if (serial_options.ParityCheck) {
884
0
    if (llvm::Error error = term.SetParityCheck(*serial_options.ParityCheck))
885
0
      return std::move(error);
886
0
  }
887
3
  if (serial_options.StopBits) {
888
1
    if (llvm::Error error = term.SetStopBits(*serial_options.StopBits))
889
0
      return std::move(error);
890
1
  }
891
892
3
  return std::move(out);
893
3
}
894
895
SerialPort::SerialPort(int fd, OpenOptions options,
896
                       SerialPort::Options serial_options,
897
                       bool transfer_ownership)
898
3
    : NativeFile(fd, options, transfer_ownership), m_state(fd) {}
899
900
3
Status SerialPort::Close() {
901
3
  m_state.Restore();
902
3
  return NativeFile::Close();
903
3
}
904
905
char File::ID = 0;
906
char NativeFile::ID = 0;
907
char SerialPort::ID = 0;