Coverage Report

Created: 2022-01-18 06:27

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