Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/llvm/lib/Support/Path.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- Path.cpp - Implement OS Path Concept ------------------------------===//
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
//  This file implements the operating system Path API.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/Support/Path.h"
14
#include "llvm/ADT/ArrayRef.h"
15
#include "llvm/Config/llvm-config.h"
16
#include "llvm/Support/Endian.h"
17
#include "llvm/Support/Errc.h"
18
#include "llvm/Support/ErrorHandling.h"
19
#include "llvm/Support/FileSystem.h"
20
#include "llvm/Support/Process.h"
21
#include "llvm/Support/Signals.h"
22
#include <cctype>
23
#include <cstring>
24
25
#if !defined(_MSC_VER) && !defined(__MINGW32__)
26
#include <unistd.h>
27
#else
28
#include <io.h>
29
#endif
30
31
using namespace llvm;
32
using namespace llvm::support::endian;
33
34
namespace {
35
  using llvm::StringRef;
36
  using llvm::sys::path::is_separator;
37
  using llvm::sys::path::Style;
38
39
16
  inline Style real_style(Style style) {
40
#ifdef _WIN32
41
    return (style == Style::posix) ? Style::posix : Style::windows;
42
#else
43
16
    return (style == Style::windows) ? Style::windows : Style::posix;
44
16
#endif
45
16
  }
46
47
2
  inline const char *separators(Style style) {
48
2
    if (real_style(style) == Style::windows)
49
0
      return "\\/";
50
2
    return "/";
51
2
  }
52
53
0
  inline char preferred_separator(Style style) {
54
0
    if (real_style(style) == Style::windows)
55
0
      return '\\';
56
0
    return '/';
57
0
  }
58
59
0
  StringRef find_first_component(StringRef path, Style style) {
60
0
    // Look for this first component in the following order.
61
0
    // * empty (in this case we return an empty string)
62
0
    // * either C: or {//,\\}net.
63
0
    // * {/,\}
64
0
    // * {file,directory}name
65
0
66
0
    if (path.empty())
67
0
      return path;
68
0
69
0
    if (real_style(style) == Style::windows) {
70
0
      // C:
71
0
      if (path.size() >= 2 &&
72
0
          std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
73
0
        return path.substr(0, 2);
74
0
    }
75
0
76
0
    // //net
77
0
    if ((path.size() > 2) && is_separator(path[0], style) &&
78
0
        path[0] == path[1] && !is_separator(path[2], style)) {
79
0
      // Find the next directory separator.
80
0
      size_t end = path.find_first_of(separators(style), 2);
81
0
      return path.substr(0, end);
82
0
    }
83
0
84
0
    // {/,\}
85
0
    if (is_separator(path[0], style))
86
0
      return path.substr(0, 1);
87
0
88
0
    // * {file,directory}name
89
0
    size_t end = path.find_first_of(separators(style));
90
0
    return path.substr(0, end);
91
0
  }
92
93
  // Returns the first character of the filename in str. For paths ending in
94
  // '/', it returns the position of the '/'.
95
2
  size_t filename_pos(StringRef str, Style style) {
96
2
    if (str.size() > 0 && is_separator(str[str.size() - 1], style))
97
0
      return str.size() - 1;
98
2
99
2
    size_t pos = str.find_last_of(separators(style), str.size() - 1);
100
2
101
2
    if (real_style(style) == Style::windows) {
102
0
      if (pos == StringRef::npos)
103
0
        pos = str.find_last_of(':', str.size() - 2);
104
0
    }
105
2
106
2
    if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
107
0
      return 0;
108
2
109
2
    return pos + 1;
110
2
  }
111
112
  // Returns the position of the root directory in str. If there is no root
113
  // directory in str, it returns StringRef::npos.
114
2
  size_t root_dir_start(StringRef str, Style style) {
115
2
    // case "c:/"
116
2
    if (real_style(style) == Style::windows) {
117
0
      if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
118
0
        return 2;
119
2
    }
120
2
121
2
    // case "//net"
122
2
    if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
123
2
        !is_separator(str[2], style)) {
124
0
      return str.find_first_of(separators(style), 2);
125
0
    }
126
2
127
2
    // case "/"
128
2
    if (str.size() > 0 && is_separator(str[0], style))
129
0
      return 0;
130
2
131
2
    return StringRef::npos;
132
2
  }
133
134
  // Returns the position past the end of the "parent path" of path. The parent
135
  // path will not end in '/', unless the parent is the root directory. If the
136
  // path has no parent, 0 is returned.
137
0
  size_t parent_path_end(StringRef path, Style style) {
138
0
    size_t end_pos = filename_pos(path, style);
139
0
140
0
    bool filename_was_sep =
141
0
        path.size() > 0 && is_separator(path[end_pos], style);
142
0
143
0
    // Skip separators until we reach root dir (or the start of the string).
144
0
    size_t root_dir_pos = root_dir_start(path, style);
145
0
    while (end_pos > 0 &&
146
0
           (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
147
0
           is_separator(path[end_pos - 1], style))
148
0
      --end_pos;
149
0
150
0
    if (end_pos == root_dir_pos && !filename_was_sep) {
151
0
      // We've reached the root dir and the input path was *not* ending in a
152
0
      // sequence of slashes. Include the root dir in the parent path.
153
0
      return root_dir_pos + 1;
154
0
    }
155
0
156
0
    // Otherwise, just include before the last slash.
157
0
    return end_pos;
158
0
  }
159
} // end unnamed namespace
160
161
enum FSEntity {
162
  FS_Dir,
163
  FS_File,
164
  FS_Name
165
};
166
167
static std::error_code
168
createUniqueEntity(const Twine &Model, int &ResultFD,
169
                   SmallVectorImpl<char> &ResultPath, bool MakeAbsolute,
170
                   unsigned Mode, FSEntity Type,
171
0
                   sys::fs::OpenFlags Flags = sys::fs::OF_None) {
172
0
173
0
  // Limit the number of attempts we make, so that we don't infinite loop. E.g.
174
0
  // "permission denied" could be for a specific file (so we retry with a
175
0
  // different name) or for the whole directory (retry would always fail).
176
0
  // Checking which is racy, so we try a number of times, then give up.
177
0
  std::error_code EC;
178
0
  for (int Retries = 128; Retries > 0; --Retries) {
179
0
    sys::fs::createUniquePath(Model, ResultPath, MakeAbsolute);
180
0
    // Try to open + create the file.
181
0
    switch (Type) {
182
0
    case FS_File: {
183
0
      EC = sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
184
0
                                         sys::fs::CD_CreateNew, Flags, Mode);
185
0
      if (EC) {
186
0
        // errc::permission_denied happens on Windows when we try to open a file
187
0
        // that has been marked for deletion.
188
0
        if (EC == errc::file_exists || EC == errc::permission_denied)
189
0
          continue;
190
0
        return EC;
191
0
      }
192
0
193
0
      return std::error_code();
194
0
    }
195
0
196
0
    case FS_Name: {
197
0
      EC = sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist);
198
0
      if (EC == errc::no_such_file_or_directory)
199
0
        return std::error_code();
200
0
      if (EC)
201
0
        return EC;
202
0
      continue;
203
0
    }
204
0
205
0
    case FS_Dir: {
206
0
      EC = sys::fs::create_directory(ResultPath.begin(), false);
207
0
      if (EC) {
208
0
        if (EC == errc::file_exists)
209
0
          continue;
210
0
        return EC;
211
0
      }
212
0
      return std::error_code();
213
0
    }
214
0
    }
215
0
    llvm_unreachable("Invalid Type");
216
0
  }
217
0
  return EC;
218
0
}
219
220
namespace llvm {
221
namespace sys  {
222
namespace path {
223
224
0
const_iterator begin(StringRef path, Style style) {
225
0
  const_iterator i;
226
0
  i.Path      = path;
227
0
  i.Component = find_first_component(path, style);
228
0
  i.Position  = 0;
229
0
  i.S = style;
230
0
  return i;
231
0
}
232
233
0
const_iterator end(StringRef path) {
234
0
  const_iterator i;
235
0
  i.Path      = path;
236
0
  i.Position  = path.size();
237
0
  return i;
238
0
}
239
240
0
const_iterator &const_iterator::operator++() {
241
0
  assert(Position < Path.size() && "Tried to increment past end!");
242
0
243
0
  // Increment Position to past the current component
244
0
  Position += Component.size();
245
0
246
0
  // Check for end.
247
0
  if (Position == Path.size()) {
248
0
    Component = StringRef();
249
0
    return *this;
250
0
  }
251
0
252
0
  // Both POSIX and Windows treat paths that begin with exactly two separators
253
0
  // specially.
254
0
  bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
255
0
                 Component[1] == Component[0] && !is_separator(Component[2], S);
256
0
257
0
  // Handle separators.
258
0
  if (is_separator(Path[Position], S)) {
259
0
    // Root dir.
260
0
    if (was_net ||
261
0
        // c:/
262
0
        (real_style(S) == Style::windows && Component.endswith(":"))) {
263
0
      Component = Path.substr(Position, 1);
264
0
      return *this;
265
0
    }
266
0
267
0
    // Skip extra separators.
268
0
    while (Position != Path.size() && is_separator(Path[Position], S)) {
269
0
      ++Position;
270
0
    }
271
0
272
0
    // Treat trailing '/' as a '.', unless it is the root dir.
273
0
    if (Position == Path.size() && Component != "/") {
274
0
      --Position;
275
0
      Component = ".";
276
0
      return *this;
277
0
    }
278
0
  }
279
0
280
0
  // Find next component.
281
0
  size_t end_pos = Path.find_first_of(separators(S), Position);
282
0
  Component = Path.slice(Position, end_pos);
283
0
284
0
  return *this;
285
0
}
286
287
0
bool const_iterator::operator==(const const_iterator &RHS) const {
288
0
  return Path.begin() == RHS.Path.begin() && Position == RHS.Position;
289
0
}
290
291
0
ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
292
0
  return Position - RHS.Position;
293
0
}
294
295
2
reverse_iterator rbegin(StringRef Path, Style style) {
296
2
  reverse_iterator I;
297
2
  I.Path = Path;
298
2
  I.Position = Path.size();
299
2
  I.S = style;
300
2
  ++I;
301
2
  return I;
302
2
}
303
304
0
reverse_iterator rend(StringRef Path) {
305
0
  reverse_iterator I;
306
0
  I.Path = Path;
307
0
  I.Component = Path.substr(0, 0);
308
0
  I.Position = 0;
309
0
  return I;
310
0
}
311
312
2
reverse_iterator &reverse_iterator::operator++() {
313
2
  size_t root_dir_pos = root_dir_start(Path, S);
314
2
315
2
  // Skip separators unless it's the root directory.
316
2
  size_t end_pos = Position;
317
2
  while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
318
2
         is_separator(Path[end_pos - 1], S))
319
0
    --end_pos;
320
2
321
2
  // Treat trailing '/' as a '.', unless it is the root dir.
322
2
  if (Position == Path.size() && !Path.empty() &&
323
2
      is_separator(Path.back(), S) &&
324
2
      (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
325
0
    --Position;
326
0
    Component = ".";
327
0
    return *this;
328
0
  }
329
2
330
2
  // Find next separator.
331
2
  size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
332
2
  Component = Path.slice(start_pos, end_pos);
333
2
  Position = start_pos;
334
2
  return *this;
335
2
}
336
337
0
bool reverse_iterator::operator==(const reverse_iterator &RHS) const {
338
0
  return Path.begin() == RHS.Path.begin() && Component == RHS.Component &&
339
0
         Position == RHS.Position;
340
0
}
341
342
0
ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
343
0
  return Position - RHS.Position;
344
0
}
345
346
0
StringRef root_path(StringRef path, Style style) {
347
0
  const_iterator b = begin(path, style), pos = b, e = end(path);
348
0
  if (b != e) {
349
0
    bool has_net =
350
0
        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
351
0
    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
352
0
353
0
    if (has_net || has_drive) {
354
0
      if ((++pos != e) && is_separator((*pos)[0], style)) {
355
0
        // {C:/,//net/}, so get the first two components.
356
0
        return path.substr(0, b->size() + pos->size());
357
0
      } else {
358
0
        // just {C:,//net}, return the first component.
359
0
        return *b;
360
0
      }
361
0
    }
362
0
363
0
    // POSIX style root directory.
364
0
    if (is_separator((*b)[0], style)) {
365
0
      return *b;
366
0
    }
367
0
  }
368
0
369
0
  return StringRef();
370
0
}
371
372
0
StringRef root_name(StringRef path, Style style) {
373
0
  const_iterator b = begin(path, style), e = end(path);
374
0
  if (b != e) {
375
0
    bool has_net =
376
0
        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
377
0
    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
378
0
379
0
    if (has_net || has_drive) {
380
0
      // just {C:,//net}, return the first component.
381
0
      return *b;
382
0
    }
383
0
  }
384
0
385
0
  // No path or no name.
386
0
  return StringRef();
387
0
}
388
389
0
StringRef root_directory(StringRef path, Style style) {
390
0
  const_iterator b = begin(path, style), pos = b, e = end(path);
391
0
  if (b != e) {
392
0
    bool has_net =
393
0
        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
394
0
    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
395
0
396
0
    if ((has_net || has_drive) &&
397
0
        // {C:,//net}, skip to the next component.
398
0
        (++pos != e) && is_separator((*pos)[0], style)) {
399
0
      return *pos;
400
0
    }
401
0
402
0
    // POSIX style root directory.
403
0
    if (!has_net && is_separator((*b)[0], style)) {
404
0
      return *b;
405
0
    }
406
0
  }
407
0
408
0
  // No path or no root.
409
0
  return StringRef();
410
0
}
411
412
0
StringRef relative_path(StringRef path, Style style) {
413
0
  StringRef root = root_path(path, style);
414
0
  return path.substr(root.size());
415
0
}
416
417
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
418
0
            const Twine &b, const Twine &c, const Twine &d) {
419
0
  SmallString<32> a_storage;
420
0
  SmallString<32> b_storage;
421
0
  SmallString<32> c_storage;
422
0
  SmallString<32> d_storage;
423
0
424
0
  SmallVector<StringRef, 4> components;
425
0
  if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
426
0
  if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
427
0
  if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
428
0
  if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
429
0
430
0
  for (auto &component : components) {
431
0
    bool path_has_sep =
432
0
        !path.empty() && is_separator(path[path.size() - 1], style);
433
0
    if (path_has_sep) {
434
0
      // Strip separators from beginning of component.
435
0
      size_t loc = component.find_first_not_of(separators(style));
436
0
      StringRef c = component.substr(loc);
437
0
438
0
      // Append it.
439
0
      path.append(c.begin(), c.end());
440
0
      continue;
441
0
    }
442
0
443
0
    bool component_has_sep =
444
0
        !component.empty() && is_separator(component[0], style);
445
0
    if (!component_has_sep &&
446
0
        !(path.empty() || has_root_name(component, style))) {
447
0
      // Add a separator.
448
0
      path.push_back(preferred_separator(style));
449
0
    }
450
0
451
0
    path.append(component.begin(), component.end());
452
0
  }
453
0
}
454
455
void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
456
0
            const Twine &c, const Twine &d) {
457
0
  append(path, Style::native, a, b, c, d);
458
0
}
459
460
void append(SmallVectorImpl<char> &path, const_iterator begin,
461
0
            const_iterator end, Style style) {
462
0
  for (; begin != end; ++begin)
463
0
    path::append(path, style, *begin);
464
0
}
465
466
0
StringRef parent_path(StringRef path, Style style) {
467
0
  size_t end_pos = parent_path_end(path, style);
468
0
  if (end_pos == StringRef::npos)
469
0
    return StringRef();
470
0
  else
471
0
    return path.substr(0, end_pos);
472
0
}
473
474
0
void remove_filename(SmallVectorImpl<char> &path, Style style) {
475
0
  size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
476
0
  if (end_pos != StringRef::npos)
477
0
    path.set_size(end_pos);
478
0
}
479
480
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
481
0
                       Style style) {
482
0
  StringRef p(path.begin(), path.size());
483
0
  SmallString<32> ext_storage;
484
0
  StringRef ext = extension.toStringRef(ext_storage);
485
0
486
0
  // Erase existing extension.
487
0
  size_t pos = p.find_last_of('.');
488
0
  if (pos != StringRef::npos && pos >= filename_pos(p, style))
489
0
    path.set_size(pos);
490
0
491
0
  // Append '.' if needed.
492
0
  if (ext.size() > 0 && ext[0] != '.')
493
0
    path.push_back('.');
494
0
495
0
  // Append extension.
496
0
  path.append(ext.begin(), ext.end());
497
0
}
498
499
static bool starts_with(StringRef Path, StringRef Prefix,
500
0
                        Style style = Style::native) {
501
0
  // Windows prefix matching : case and separator insensitive
502
0
  if (real_style(style) == Style::windows) {
503
0
    if (Path.size() < Prefix.size())
504
0
      return false;
505
0
    for (size_t I = 0, E = Prefix.size(); I != E; ++I) {
506
0
      bool SepPath = is_separator(Path[I], style);
507
0
      bool SepPrefix = is_separator(Prefix[I], style);
508
0
      if (SepPath != SepPrefix)
509
0
        return false;
510
0
      if (!SepPath && toLower(Path[I]) != toLower(Prefix[I]))
511
0
        return false;
512
0
    }
513
0
    return true;
514
0
  }
515
0
  return Path.startswith(Prefix);
516
0
}
517
518
bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix,
519
0
                         StringRef NewPrefix, Style style) {
520
0
  if (OldPrefix.empty() && NewPrefix.empty())
521
0
    return false;
522
0
523
0
  StringRef OrigPath(Path.begin(), Path.size());
524
0
  if (!starts_with(OrigPath, OldPrefix, style))
525
0
    return false;
526
0
527
0
  // If prefixes have the same size we can simply copy the new one over.
528
0
  if (OldPrefix.size() == NewPrefix.size()) {
529
0
    llvm::copy(NewPrefix, Path.begin());
530
0
    return true;
531
0
  }
532
0
533
0
  StringRef RelPath = OrigPath.substr(OldPrefix.size());
534
0
  SmallString<256> NewPath;
535
0
  (Twine(NewPrefix) + RelPath).toVector(NewPath);
536
0
  Path.swap(NewPath);
537
0
  return true;
538
0
}
539
540
0
void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
541
0
  assert((!path.isSingleStringRef() ||
542
0
          path.getSingleStringRef().data() != result.data()) &&
543
0
         "path and result are not allowed to overlap!");
544
0
  // Clear result.
545
0
  result.clear();
546
0
  path.toVector(result);
547
0
  native(result, style);
548
0
}
549
550
0
void native(SmallVectorImpl<char> &Path, Style style) {
551
0
  if (Path.empty())
552
0
    return;
553
0
  if (real_style(style) == Style::windows) {
554
0
    std::replace(Path.begin(), Path.end(), '/', '\\');
555
0
    if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
556
0
      SmallString<128> PathHome;
557
0
      home_directory(PathHome);
558
0
      PathHome.append(Path.begin() + 1, Path.end());
559
0
      Path = PathHome;
560
0
    }
561
0
  } else {
562
0
    for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI)
563
0
      if (*PI == '\\')
564
0
        *PI = '/';
565
0
  }
566
0
}
567
568
0
std::string convert_to_slash(StringRef path, Style style) {
569
0
  if (real_style(style) != Style::windows)
570
0
    return std::string(path);
571
0
572
0
  std::string s = path.str();
573
0
  std::replace(s.begin(), s.end(), '\\', '/');
574
0
  return s;
575
0
}
576
577
2
StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
578
579
0
StringRef stem(StringRef path, Style style) {
580
0
  StringRef fname = filename(path, style);
581
0
  size_t pos = fname.find_last_of('.');
582
0
  if (pos == StringRef::npos)
583
0
    return fname;
584
0
  else
585
0
    if ((fname.size() == 1 && fname == ".") ||
586
0
        (fname.size() == 2 && fname == ".."))
587
0
      return fname;
588
0
    else
589
0
      return fname.substr(0, pos);
590
0
}
591
592
0
StringRef extension(StringRef path, Style style) {
593
0
  StringRef fname = filename(path, style);
594
0
  size_t pos = fname.find_last_of('.');
595
0
  if (pos == StringRef::npos)
596
0
    return StringRef();
597
0
  else
598
0
    if ((fname.size() == 1 && fname == ".") ||
599
0
        (fname.size() == 2 && fname == ".."))
600
0
      return StringRef();
601
0
    else
602
0
      return fname.substr(pos);
603
0
}
604
605
10
bool is_separator(char value, Style style) {
606
10
  if (value == '/')
607
0
    return true;
608
10
  if (real_style(style) == Style::windows)
609
0
    return value == '\\';
610
10
  return false;
611
10
}
612
613
0
StringRef get_separator(Style style) {
614
0
  if (real_style(style) == Style::windows)
615
0
    return "\\";
616
0
  return "/";
617
0
}
618
619
0
bool has_root_name(const Twine &path, Style style) {
620
0
  SmallString<128> path_storage;
621
0
  StringRef p = path.toStringRef(path_storage);
622
0
623
0
  return !root_name(p, style).empty();
624
0
}
625
626
0
bool has_root_directory(const Twine &path, Style style) {
627
0
  SmallString<128> path_storage;
628
0
  StringRef p = path.toStringRef(path_storage);
629
0
630
0
  return !root_directory(p, style).empty();
631
0
}
632
633
0
bool has_root_path(const Twine &path, Style style) {
634
0
  SmallString<128> path_storage;
635
0
  StringRef p = path.toStringRef(path_storage);
636
0
637
0
  return !root_path(p, style).empty();
638
0
}
639
640
0
bool has_relative_path(const Twine &path, Style style) {
641
0
  SmallString<128> path_storage;
642
0
  StringRef p = path.toStringRef(path_storage);
643
0
644
0
  return !relative_path(p, style).empty();
645
0
}
646
647
0
bool has_filename(const Twine &path, Style style) {
648
0
  SmallString<128> path_storage;
649
0
  StringRef p = path.toStringRef(path_storage);
650
0
651
0
  return !filename(p, style).empty();
652
0
}
653
654
0
bool has_parent_path(const Twine &path, Style style) {
655
0
  SmallString<128> path_storage;
656
0
  StringRef p = path.toStringRef(path_storage);
657
0
658
0
  return !parent_path(p, style).empty();
659
0
}
660
661
0
bool has_stem(const Twine &path, Style style) {
662
0
  SmallString<128> path_storage;
663
0
  StringRef p = path.toStringRef(path_storage);
664
0
665
0
  return !stem(p, style).empty();
666
0
}
667
668
0
bool has_extension(const Twine &path, Style style) {
669
0
  SmallString<128> path_storage;
670
0
  StringRef p = path.toStringRef(path_storage);
671
0
672
0
  return !extension(p, style).empty();
673
0
}
674
675
0
bool is_absolute(const Twine &path, Style style) {
676
0
  SmallString<128> path_storage;
677
0
  StringRef p = path.toStringRef(path_storage);
678
0
679
0
  bool rootDir = has_root_directory(p, style);
680
0
  bool rootName =
681
0
      (real_style(style) != Style::windows) || has_root_name(p, style);
682
0
683
0
  return rootDir && rootName;
684
0
}
685
686
0
bool is_relative(const Twine &path, Style style) {
687
0
  return !is_absolute(path, style);
688
0
}
689
690
0
StringRef remove_leading_dotslash(StringRef Path, Style style) {
691
0
  // Remove leading "./" (or ".//" or "././" etc.)
692
0
  while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
693
0
    Path = Path.substr(2);
694
0
    while (Path.size() > 0 && is_separator(Path[0], style))
695
0
      Path = Path.substr(1);
696
0
  }
697
0
  return Path;
698
0
}
699
700
// Remove path traversal components ("." and "..") when possible, and
701
// canonicalize slashes.
702
bool remove_dots(SmallVectorImpl<char> &the_path, bool remove_dot_dot,
703
0
                 Style style) {
704
0
  style = real_style(style);
705
0
  StringRef remaining(the_path.data(), the_path.size());
706
0
  bool needs_change = false;
707
0
  SmallVector<StringRef, 16> components;
708
0
709
0
  // Consume the root path, if present.
710
0
  StringRef root = path::root_path(remaining, style);
711
0
  bool absolute = !root.empty();
712
0
  if (absolute)
713
0
    remaining = remaining.drop_front(root.size());
714
0
715
0
  // Loop over path components manually. This makes it easier to detect
716
0
  // non-preferred slashes and double separators that must be canonicalized.
717
0
  while (!remaining.empty()) {
718
0
    size_t next_slash = remaining.find_first_of(separators(style));
719
0
    if (next_slash == StringRef::npos)
720
0
      next_slash = remaining.size();
721
0
    StringRef component = remaining.take_front(next_slash);
722
0
    remaining = remaining.drop_front(next_slash);
723
0
724
0
    // Eat the slash, and check if it is the preferred separator.
725
0
    if (!remaining.empty()) {
726
0
      needs_change |= remaining.front() != preferred_separator(style);
727
0
      remaining = remaining.drop_front();
728
0
      // The path needs to be rewritten if it has a trailing slash.
729
0
      // FIXME: This is emergent behavior that could be removed.
730
0
      needs_change |= remaining.empty();
731
0
    }
732
0
733
0
    // Check for path traversal components or double separators.
734
0
    if (component.empty() || component == ".") {
735
0
      needs_change = true;
736
0
    } else if (remove_dot_dot && component == "..") {
737
0
      needs_change = true;
738
0
      // Do not allow ".." to remove the root component. If this is the
739
0
      // beginning of a relative path, keep the ".." component.
740
0
      if (!components.empty() && components.back() != "..") {
741
0
        components.pop_back();
742
0
      } else if (!absolute) {
743
0
        components.push_back(component);
744
0
      }
745
0
    } else {
746
0
      components.push_back(component);
747
0
    }
748
0
  }
749
0
750
0
  // Avoid rewriting the path unless we have to.
751
0
  if (!needs_change)
752
0
    return false;
753
0
754
0
  SmallString<256> buffer = root;
755
0
  if (!components.empty()) {
756
0
    buffer += components[0];
757
0
    for (StringRef C : makeArrayRef(components).drop_front()) {
758
0
      buffer += preferred_separator(style);
759
0
      buffer += C;
760
0
    }
761
0
  }
762
0
  the_path.swap(buffer);
763
0
  return true;
764
0
}
765
766
} // end namespace path
767
768
namespace fs {
769
770
0
std::error_code getUniqueID(const Twine Path, UniqueID &Result) {
771
0
  file_status Status;
772
0
  std::error_code EC = status(Path, Status);
773
0
  if (EC)
774
0
    return EC;
775
0
  Result = Status.getUniqueID();
776
0
  return std::error_code();
777
0
}
778
779
void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
780
0
                      bool MakeAbsolute) {
781
0
  SmallString<128> ModelStorage;
782
0
  Model.toVector(ModelStorage);
783
0
784
0
  if (MakeAbsolute) {
785
0
    // Make model absolute by prepending a temp directory if it's not already.
786
0
    if (!sys::path::is_absolute(Twine(ModelStorage))) {
787
0
      SmallString<128> TDir;
788
0
      sys::path::system_temp_directory(true, TDir);
789
0
      sys::path::append(TDir, Twine(ModelStorage));
790
0
      ModelStorage.swap(TDir);
791
0
    }
792
0
  }
793
0
794
0
  ResultPath = ModelStorage;
795
0
  ResultPath.push_back(0);
796
0
  ResultPath.pop_back();
797
0
798
0
  // Replace '%' with random chars.
799
0
  for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
800
0
    if (ModelStorage[i] == '%')
801
0
      ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
802
0
  }
803
0
}
804
805
std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
806
                                 SmallVectorImpl<char> &ResultPath,
807
0
                                 unsigned Mode) {
808
0
  return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File);
809
0
}
810
811
static std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
812
                                        SmallVectorImpl<char> &ResultPath,
813
0
                                        unsigned Mode, OpenFlags Flags) {
814
0
  return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File,
815
0
                            Flags);
816
0
}
817
818
std::error_code createUniqueFile(const Twine &Model,
819
                                 SmallVectorImpl<char> &ResultPath,
820
0
                                 unsigned Mode) {
821
0
  int FD;
822
0
  auto EC = createUniqueFile(Model, FD, ResultPath, Mode);
823
0
  if (EC)
824
0
    return EC;
825
0
  // FD is only needed to avoid race conditions. Close it right away.
826
0
  close(FD);
827
0
  return EC;
828
0
}
829
830
static std::error_code
831
createTemporaryFile(const Twine &Model, int &ResultFD,
832
0
                    llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
833
0
  SmallString<128> Storage;
834
0
  StringRef P = Model.toNullTerminatedStringRef(Storage);
835
0
  assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
836
0
         "Model must be a simple filename.");
837
0
  // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
838
0
  return createUniqueEntity(P.begin(), ResultFD, ResultPath, true,
839
0
                            owner_read | owner_write, Type);
840
0
}
841
842
static std::error_code
843
createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
844
0
                    llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
845
0
  const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
846
0
  return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
847
0
                             Type);
848
0
}
849
850
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
851
                                    int &ResultFD,
852
0
                                    SmallVectorImpl<char> &ResultPath) {
853
0
  return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File);
854
0
}
855
856
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
857
0
                                    SmallVectorImpl<char> &ResultPath) {
858
0
  int FD;
859
0
  auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath);
860
0
  if (EC)
861
0
    return EC;
862
0
  // FD is only needed to avoid race conditions. Close it right away.
863
0
  close(FD);
864
0
  return EC;
865
0
}
866
867
868
// This is a mkdtemp with a different pattern. We use createUniqueEntity mostly
869
// for consistency. We should try using mkdtemp.
870
std::error_code createUniqueDirectory(const Twine &Prefix,
871
0
                                      SmallVectorImpl<char> &ResultPath) {
872
0
  int Dummy;
873
0
  return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0,
874
0
                            FS_Dir);
875
0
}
876
877
std::error_code
878
getPotentiallyUniqueFileName(const Twine &Model,
879
0
                             SmallVectorImpl<char> &ResultPath) {
880
0
  int Dummy;
881
0
  return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
882
0
}
883
884
std::error_code
885
getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
886
0
                                 SmallVectorImpl<char> &ResultPath) {
887
0
  int Dummy;
888
0
  return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
889
0
}
890
891
void make_absolute(const Twine &current_directory,
892
0
                   SmallVectorImpl<char> &path) {
893
0
  StringRef p(path.data(), path.size());
894
0
895
0
  bool rootDirectory = path::has_root_directory(p);
896
0
  bool rootName = path::has_root_name(p);
897
0
898
0
  // Already absolute.
899
0
  if ((rootName || real_style(Style::native) != Style::windows) &&
900
0
      rootDirectory)
901
0
    return;
902
0
903
0
  // All of the following conditions will need the current directory.
904
0
  SmallString<128> current_dir;
905
0
  current_directory.toVector(current_dir);
906
0
907
0
  // Relative path. Prepend the current directory.
908
0
  if (!rootName && !rootDirectory) {
909
0
    // Append path to the current directory.
910
0
    path::append(current_dir, p);
911
0
    // Set path to the result.
912
0
    path.swap(current_dir);
913
0
    return;
914
0
  }
915
0
916
0
  if (!rootName && rootDirectory) {
917
0
    StringRef cdrn = path::root_name(current_dir);
918
0
    SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
919
0
    path::append(curDirRootName, p);
920
0
    // Set path to the result.
921
0
    path.swap(curDirRootName);
922
0
    return;
923
0
  }
924
0
925
0
  if (rootName && !rootDirectory) {
926
0
    StringRef pRootName      = path::root_name(p);
927
0
    StringRef bRootDirectory = path::root_directory(current_dir);
928
0
    StringRef bRelativePath  = path::relative_path(current_dir);
929
0
    StringRef pRelativePath  = path::relative_path(p);
930
0
931
0
    SmallString<128> res;
932
0
    path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
933
0
    path.swap(res);
934
0
    return;
935
0
  }
936
0
937
0
  llvm_unreachable("All rootName and rootDirectory combinations should have "
938
0
                   "occurred above!");
939
0
}
940
941
0
std::error_code make_absolute(SmallVectorImpl<char> &path) {
942
0
  if (path::is_absolute(path))
943
0
    return {};
944
0
945
0
  SmallString<128> current_dir;
946
0
  if (std::error_code ec = current_path(current_dir))
947
0
    return ec;
948
0
949
0
  make_absolute(current_dir, path);
950
0
  return {};
951
0
}
952
953
std::error_code create_directories(const Twine &Path, bool IgnoreExisting,
954
0
                                   perms Perms) {
955
0
  SmallString<128> PathStorage;
956
0
  StringRef P = Path.toStringRef(PathStorage);
957
0
958
0
  // Be optimistic and try to create the directory
959
0
  std::error_code EC = create_directory(P, IgnoreExisting, Perms);
960
0
  // If we succeeded, or had any error other than the parent not existing, just
961
0
  // return it.
962
0
  if (EC != errc::no_such_file_or_directory)
963
0
    return EC;
964
0
965
0
  // We failed because of a no_such_file_or_directory, try to create the
966
0
  // parent.
967
0
  StringRef Parent = path::parent_path(P);
968
0
  if (Parent.empty())
969
0
    return EC;
970
0
971
0
  if ((EC = create_directories(Parent, IgnoreExisting, Perms)))
972
0
      return EC;
973
0
974
0
  return create_directory(P, IgnoreExisting, Perms);
975
0
}
976
977
0
static std::error_code copy_file_internal(int ReadFD, int WriteFD) {
978
0
  const size_t BufSize = 4096;
979
0
  char *Buf = new char[BufSize];
980
0
  int BytesRead = 0, BytesWritten = 0;
981
0
  for (;;) {
982
0
    BytesRead = read(ReadFD, Buf, BufSize);
983
0
    if (BytesRead <= 0)
984
0
      break;
985
0
    while (BytesRead) {
986
0
      BytesWritten = write(WriteFD, Buf, BytesRead);
987
0
      if (BytesWritten < 0)
988
0
        break;
989
0
      BytesRead -= BytesWritten;
990
0
    }
991
0
    if (BytesWritten < 0)
992
0
      break;
993
0
  }
994
0
  delete[] Buf;
995
0
996
0
  if (BytesRead < 0 || BytesWritten < 0)
997
0
    return std::error_code(errno, std::generic_category());
998
0
  return std::error_code();
999
0
}
1000
1001
#ifndef __APPLE__
1002
0
std::error_code copy_file(const Twine &From, const Twine &To) {
1003
0
  int ReadFD, WriteFD;
1004
0
  if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
1005
0
    return EC;
1006
0
  if (std::error_code EC =
1007
0
          openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) {
1008
0
    close(ReadFD);
1009
0
    return EC;
1010
0
  }
1011
0
1012
0
  std::error_code EC = copy_file_internal(ReadFD, WriteFD);
1013
0
1014
0
  close(ReadFD);
1015
0
  close(WriteFD);
1016
0
1017
0
  return EC;
1018
0
}
1019
#endif
1020
1021
0
std::error_code copy_file(const Twine &From, int ToFD) {
1022
0
  int ReadFD;
1023
0
  if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
1024
0
    return EC;
1025
0
1026
0
  std::error_code EC = copy_file_internal(ReadFD, ToFD);
1027
0
1028
0
  close(ReadFD);
1029
0
1030
0
  return EC;
1031
0
}
1032
1033
0
ErrorOr<MD5::MD5Result> md5_contents(int FD) {
1034
0
  MD5 Hash;
1035
0
1036
0
  constexpr size_t BufSize = 4096;
1037
0
  std::vector<uint8_t> Buf(BufSize);
1038
0
  int BytesRead = 0;
1039
0
  for (;;) {
1040
0
    BytesRead = read(FD, Buf.data(), BufSize);
1041
0
    if (BytesRead <= 0)
1042
0
      break;
1043
0
    Hash.update(makeArrayRef(Buf.data(), BytesRead));
1044
0
  }
1045
0
1046
0
  if (BytesRead < 0)
1047
0
    return std::error_code(errno, std::generic_category());
1048
0
  MD5::MD5Result Result;
1049
0
  Hash.final(Result);
1050
0
  return Result;
1051
0
}
1052
1053
0
ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
1054
0
  int FD;
1055
0
  if (auto EC = openFileForRead(Path, FD, OF_None))
1056
0
    return EC;
1057
0
1058
0
  auto Result = md5_contents(FD);
1059
0
  close(FD);
1060
0
  return Result;
1061
0
}
1062
1063
0
bool exists(const basic_file_status &status) {
1064
0
  return status_known(status) && status.type() != file_type::file_not_found;
1065
0
}
1066
1067
0
bool status_known(const basic_file_status &s) {
1068
0
  return s.type() != file_type::status_error;
1069
0
}
1070
1071
0
file_type get_file_type(const Twine &Path, bool Follow) {
1072
0
  file_status st;
1073
0
  if (status(Path, st, Follow))
1074
0
    return file_type::status_error;
1075
0
  return st.type();
1076
0
}
1077
1078
0
bool is_directory(const basic_file_status &status) {
1079
0
  return status.type() == file_type::directory_file;
1080
0
}
1081
1082
0
std::error_code is_directory(const Twine &path, bool &result) {
1083
0
  file_status st;
1084
0
  if (std::error_code ec = status(path, st))
1085
0
    return ec;
1086
0
  result = is_directory(st);
1087
0
  return std::error_code();
1088
0
}
1089
1090
0
bool is_regular_file(const basic_file_status &status) {
1091
0
  return status.type() == file_type::regular_file;
1092
0
}
1093
1094
0
std::error_code is_regular_file(const Twine &path, bool &result) {
1095
0
  file_status st;
1096
0
  if (std::error_code ec = status(path, st))
1097
0
    return ec;
1098
0
  result = is_regular_file(st);
1099
0
  return std::error_code();
1100
0
}
1101
1102
0
bool is_symlink_file(const basic_file_status &status) {
1103
0
  return status.type() == file_type::symlink_file;
1104
0
}
1105
1106
0
std::error_code is_symlink_file(const Twine &path, bool &result) {
1107
0
  file_status st;
1108
0
  if (std::error_code ec = status(path, st, false))
1109
0
    return ec;
1110
0
  result = is_symlink_file(st);
1111
0
  return std::error_code();
1112
0
}
1113
1114
0
bool is_other(const basic_file_status &status) {
1115
0
  return exists(status) &&
1116
0
         !is_regular_file(status) &&
1117
0
         !is_directory(status);
1118
0
}
1119
1120
0
std::error_code is_other(const Twine &Path, bool &Result) {
1121
0
  file_status FileStatus;
1122
0
  if (std::error_code EC = status(Path, FileStatus))
1123
0
    return EC;
1124
0
  Result = is_other(FileStatus);
1125
0
  return std::error_code();
1126
0
}
1127
1128
void directory_entry::replace_filename(const Twine &Filename, file_type Type,
1129
0
                                       basic_file_status Status) {
1130
0
  SmallString<128> PathStr = path::parent_path(Path);
1131
0
  path::append(PathStr, Filename);
1132
0
  this->Path = std::string(PathStr.str());
1133
0
  this->Type = Type;
1134
0
  this->Status = Status;
1135
0
}
1136
1137
0
ErrorOr<perms> getPermissions(const Twine &Path) {
1138
0
  file_status Status;
1139
0
  if (std::error_code EC = status(Path, Status))
1140
0
    return EC;
1141
0
1142
0
  return Status.permissions();
1143
0
}
1144
1145
} // end namespace fs
1146
} // end namespace sys
1147
} // end namespace llvm
1148
1149
// Include the truly platform-specific parts.
1150
#if defined(LLVM_ON_UNIX)
1151
#include "Unix/Path.inc"
1152
#endif
1153
#if defined(_WIN32)
1154
#include "Windows/Path.inc"
1155
#endif
1156
1157
namespace llvm {
1158
namespace sys {
1159
namespace fs {
1160
TempFile::TempFile(StringRef Name, int FD)
1161
0
    : TmpName(std::string(Name)), FD(FD) {}
1162
0
TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }
1163
0
TempFile &TempFile::operator=(TempFile &&Other) {
1164
0
  TmpName = std::move(Other.TmpName);
1165
0
  FD = Other.FD;
1166
0
  Other.Done = true;
1167
0
  Other.FD = -1;
1168
0
  return *this;
1169
0
}
1170
1171
0
TempFile::~TempFile() { assert(Done); }
1172
1173
0
Error TempFile::discard() {
1174
0
  Done = true;
1175
0
  if (FD != -1 && close(FD) == -1) {
1176
0
    std::error_code EC = std::error_code(errno, std::generic_category());
1177
0
    return errorCodeToError(EC);
1178
0
  }
1179
0
  FD = -1;
1180
0
1181
#ifdef _WIN32
1182
  // On windows closing will remove the file.
1183
  TmpName = "";
1184
  return Error::success();
1185
#else
1186
  // Always try to close and remove.
1187
0
  std::error_code RemoveEC;
1188
0
  if (!TmpName.empty()) {
1189
0
    RemoveEC = fs::remove(TmpName);
1190
0
    sys::DontRemoveFileOnSignal(TmpName);
1191
0
    if (!RemoveEC)
1192
0
      TmpName = "";
1193
0
  }
1194
0
  return errorCodeToError(RemoveEC);
1195
0
#endif
1196
0
}
1197
1198
0
Error TempFile::keep(const Twine &Name) {
1199
0
  assert(!Done);
1200
0
  Done = true;
1201
0
  // Always try to close and rename.
1202
#ifdef _WIN32
1203
  // If we can't cancel the delete don't rename.
1204
  auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
1205
  std::error_code RenameEC = setDeleteDisposition(H, false);
1206
  if (!RenameEC) {
1207
    RenameEC = rename_fd(FD, Name);
1208
    // If rename failed because it's cross-device, copy instead
1209
    if (RenameEC ==
1210
      std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) {
1211
      RenameEC = copy_file(TmpName, Name);
1212
      setDeleteDisposition(H, true);
1213
    }
1214
  }
1215
1216
  // If we can't rename, discard the temporary file.
1217
  if (RenameEC)
1218
    setDeleteDisposition(H, true);
1219
#else
1220
  std::error_code RenameEC = fs::rename(TmpName, Name);
1221
0
  if (RenameEC) {
1222
0
    // If we can't rename, try to copy to work around cross-device link issues.
1223
0
    RenameEC = sys::fs::copy_file(TmpName, Name);
1224
0
    // If we can't rename or copy, discard the temporary file.
1225
0
    if (RenameEC)
1226
0
      remove(TmpName);
1227
0
  }
1228
0
  sys::DontRemoveFileOnSignal(TmpName);
1229
0
#endif
1230
0
1231
0
  if (!RenameEC)
1232
0
    TmpName = "";
1233
0
1234
0
  if (close(FD) == -1) {
1235
0
    std::error_code EC(errno, std::generic_category());
1236
0
    return errorCodeToError(EC);
1237
0
  }
1238
0
  FD = -1;
1239
0
1240
0
  return errorCodeToError(RenameEC);
1241
0
}
1242
1243
0
Error TempFile::keep() {
1244
0
  assert(!Done);
1245
0
  Done = true;
1246
0
1247
#ifdef _WIN32
1248
  auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
1249
  if (std::error_code EC = setDeleteDisposition(H, false))
1250
    return errorCodeToError(EC);
1251
#else
1252
  sys::DontRemoveFileOnSignal(TmpName);
1253
0
#endif
1254
0
1255
0
  TmpName = "";
1256
0
1257
0
  if (close(FD) == -1) {
1258
0
    std::error_code EC(errno, std::generic_category());
1259
0
    return errorCodeToError(EC);
1260
0
  }
1261
0
  FD = -1;
1262
0
1263
0
  return Error::success();
1264
0
}
1265
1266
0
Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) {
1267
0
  int FD;
1268
0
  SmallString<128> ResultPath;
1269
0
  if (std::error_code EC =
1270
0
          createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete))
1271
0
    return errorCodeToError(EC);
1272
0
1273
0
  TempFile Ret(ResultPath, FD);
1274
0
#ifndef _WIN32
1275
0
  if (sys::RemoveFileOnSignal(ResultPath)) {
1276
0
    // Make sure we delete the file when RemoveFileOnSignal fails.
1277
0
    consumeError(Ret.discard());
1278
0
    std::error_code EC(errc::operation_not_permitted);
1279
0
    return errorCodeToError(EC);
1280
0
  }
1281
0
#endif
1282
0
  return std::move(Ret);
1283
0
}
1284
}
1285
1286
} // end namsspace sys
1287
} // end namespace llvm