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