xref: /src/contrib/llvm-project/llvm/lib/Support/Path.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1f8af5cf6SDimitry Andric //===-- Path.cpp - Implement OS Path Concept ------------------------------===//
2cf099d11SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cf099d11SDimitry Andric //
7cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
8cf099d11SDimitry Andric //
9f8af5cf6SDimitry Andric //  This file implements the operating system Path API.
10cf099d11SDimitry Andric //
11cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
12cf099d11SDimitry Andric 
1371d5a254SDimitry Andric #include "llvm/Support/Path.h"
1471d5a254SDimitry Andric #include "llvm/ADT/ArrayRef.h"
156f8fc217SDimitry Andric #include "llvm/ADT/ScopeExit.h"
167fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
17c0981da4SDimitry Andric #include "llvm/Config/config.h"
18eb11fae6SDimitry Andric #include "llvm/Config/llvm-config.h"
196b943ff3SDimitry Andric #include "llvm/Support/Endian.h"
2067c32a98SDimitry Andric #include "llvm/Support/Errc.h"
21f8af5cf6SDimitry Andric #include "llvm/Support/ErrorHandling.h"
224a16efa3SDimitry Andric #include "llvm/Support/FileSystem.h"
235ca98fd9SDimitry Andric #include "llvm/Support/Process.h"
24044eb2f6SDimitry Andric #include "llvm/Support/Signals.h"
25f8af5cf6SDimitry Andric #include <cctype>
26f8af5cf6SDimitry Andric 
27f8af5cf6SDimitry Andric #if !defined(_MSC_VER) && !defined(__MINGW32__)
28f8af5cf6SDimitry Andric #include <unistd.h>
29f8af5cf6SDimitry Andric #else
30f8af5cf6SDimitry Andric #include <io.h>
31f8af5cf6SDimitry Andric #endif
32f8af5cf6SDimitry Andric 
335ca98fd9SDimitry Andric using namespace llvm;
345a5ac124SDimitry Andric using namespace llvm::support::endian;
355ca98fd9SDimitry Andric 
366b943ff3SDimitry Andric namespace {
37f8af5cf6SDimitry Andric   using llvm::StringRef;
38f8af5cf6SDimitry Andric   using llvm::sys::path::is_separator;
3971d5a254SDimitry Andric   using llvm::sys::path::Style;
40f8af5cf6SDimitry Andric 
real_style(Style style)4171d5a254SDimitry Andric   inline Style real_style(Style style) {
42c0981da4SDimitry Andric     if (style != Style::native)
43c0981da4SDimitry Andric       return style;
44c0981da4SDimitry Andric     if (is_style_posix(style))
45c0981da4SDimitry Andric       return Style::posix;
46c0981da4SDimitry Andric     return LLVM_WINDOWS_PREFER_FORWARD_SLASH ? Style::windows_slash
47c0981da4SDimitry Andric                                              : Style::windows_backslash;
4871d5a254SDimitry Andric   }
49f8af5cf6SDimitry Andric 
separators(Style style)5071d5a254SDimitry Andric   inline const char *separators(Style style) {
51c0981da4SDimitry Andric     if (is_style_windows(style))
5271d5a254SDimitry Andric       return "\\/";
5371d5a254SDimitry Andric     return "/";
5471d5a254SDimitry Andric   }
5571d5a254SDimitry Andric 
preferred_separator(Style style)5671d5a254SDimitry Andric   inline char preferred_separator(Style style) {
5771d5a254SDimitry Andric     if (real_style(style) == Style::windows)
5871d5a254SDimitry Andric       return '\\';
5971d5a254SDimitry Andric     return '/';
6071d5a254SDimitry Andric   }
6171d5a254SDimitry Andric 
find_first_component(StringRef path,Style style)6271d5a254SDimitry Andric   StringRef find_first_component(StringRef path, Style style) {
63f8af5cf6SDimitry Andric     // Look for this first component in the following order.
64f8af5cf6SDimitry Andric     // * empty (in this case we return an empty string)
65f8af5cf6SDimitry Andric     // * either C: or {//,\\}net.
66f8af5cf6SDimitry Andric     // * {/,\}
67f8af5cf6SDimitry Andric     // * {file,directory}name
68f8af5cf6SDimitry Andric 
69f8af5cf6SDimitry Andric     if (path.empty())
70f8af5cf6SDimitry Andric       return path;
71f8af5cf6SDimitry Andric 
72c0981da4SDimitry Andric     if (is_style_windows(style)) {
73f8af5cf6SDimitry Andric       // C:
7471d5a254SDimitry Andric       if (path.size() >= 2 &&
7571d5a254SDimitry Andric           std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
76f8af5cf6SDimitry Andric         return path.substr(0, 2);
7771d5a254SDimitry Andric     }
78f8af5cf6SDimitry Andric 
79f8af5cf6SDimitry Andric     // //net
8071d5a254SDimitry Andric     if ((path.size() > 2) && is_separator(path[0], style) &&
8171d5a254SDimitry Andric         path[0] == path[1] && !is_separator(path[2], style)) {
82f8af5cf6SDimitry Andric       // Find the next directory separator.
8371d5a254SDimitry Andric       size_t end = path.find_first_of(separators(style), 2);
84f8af5cf6SDimitry Andric       return path.substr(0, end);
856b943ff3SDimitry Andric     }
86cf099d11SDimitry Andric 
87f8af5cf6SDimitry Andric     // {/,\}
8871d5a254SDimitry Andric     if (is_separator(path[0], style))
89f8af5cf6SDimitry Andric       return path.substr(0, 1);
90cf099d11SDimitry Andric 
91f8af5cf6SDimitry Andric     // * {file,directory}name
9271d5a254SDimitry Andric     size_t end = path.find_first_of(separators(style));
93f8af5cf6SDimitry Andric     return path.substr(0, end);
94cf099d11SDimitry Andric   }
95cf099d11SDimitry Andric 
96eb11fae6SDimitry Andric   // Returns the first character of the filename in str. For paths ending in
97eb11fae6SDimitry Andric   // '/', it returns the position of the '/'.
filename_pos(StringRef str,Style style)9871d5a254SDimitry Andric   size_t filename_pos(StringRef str, Style style) {
9971d5a254SDimitry Andric     if (str.size() > 0 && is_separator(str[str.size() - 1], style))
100f8af5cf6SDimitry Andric       return str.size() - 1;
101f8af5cf6SDimitry Andric 
10271d5a254SDimitry Andric     size_t pos = str.find_last_of(separators(style), str.size() - 1);
103f8af5cf6SDimitry Andric 
104c0981da4SDimitry Andric     if (is_style_windows(style)) {
105f8af5cf6SDimitry Andric       if (pos == StringRef::npos)
1064df029ccSDimitry Andric         pos = str.find_last_of(':', str.size() - 1);
10771d5a254SDimitry Andric     }
108f8af5cf6SDimitry Andric 
10971d5a254SDimitry Andric     if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
110f8af5cf6SDimitry Andric       return 0;
111f8af5cf6SDimitry Andric 
112f8af5cf6SDimitry Andric     return pos + 1;
113cf099d11SDimitry Andric   }
114cf099d11SDimitry Andric 
115eb11fae6SDimitry Andric   // Returns the position of the root directory in str. If there is no root
116eb11fae6SDimitry Andric   // directory in str, it returns StringRef::npos.
root_dir_start(StringRef str,Style style)11771d5a254SDimitry Andric   size_t root_dir_start(StringRef str, Style style) {
118f8af5cf6SDimitry Andric     // case "c:/"
119c0981da4SDimitry Andric     if (is_style_windows(style)) {
12071d5a254SDimitry Andric       if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
121f8af5cf6SDimitry Andric         return 2;
12271d5a254SDimitry Andric     }
123f8af5cf6SDimitry Andric 
124f8af5cf6SDimitry Andric     // case "//net"
12571d5a254SDimitry Andric     if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
12671d5a254SDimitry Andric         !is_separator(str[2], style)) {
12771d5a254SDimitry Andric       return str.find_first_of(separators(style), 2);
128f8af5cf6SDimitry Andric     }
129f8af5cf6SDimitry Andric 
130f8af5cf6SDimitry Andric     // case "/"
13171d5a254SDimitry Andric     if (str.size() > 0 && is_separator(str[0], style))
132f8af5cf6SDimitry Andric       return 0;
133f8af5cf6SDimitry Andric 
134f8af5cf6SDimitry Andric     return StringRef::npos;
135f8af5cf6SDimitry Andric   }
136f8af5cf6SDimitry Andric 
137eb11fae6SDimitry Andric   // Returns the position past the end of the "parent path" of path. The parent
138eb11fae6SDimitry Andric   // path will not end in '/', unless the parent is the root directory. If the
139eb11fae6SDimitry Andric   // path has no parent, 0 is returned.
parent_path_end(StringRef path,Style style)14071d5a254SDimitry Andric   size_t parent_path_end(StringRef path, Style style) {
14171d5a254SDimitry Andric     size_t end_pos = filename_pos(path, style);
142f8af5cf6SDimitry Andric 
14371d5a254SDimitry Andric     bool filename_was_sep =
14471d5a254SDimitry Andric         path.size() > 0 && is_separator(path[end_pos], style);
145f8af5cf6SDimitry Andric 
146eb11fae6SDimitry Andric     // Skip separators until we reach root dir (or the start of the string).
147eb11fae6SDimitry Andric     size_t root_dir_pos = root_dir_start(path, style);
148eb11fae6SDimitry Andric     while (end_pos > 0 &&
149eb11fae6SDimitry Andric            (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
15071d5a254SDimitry Andric            is_separator(path[end_pos - 1], style))
151f8af5cf6SDimitry Andric       --end_pos;
152f8af5cf6SDimitry Andric 
153eb11fae6SDimitry Andric     if (end_pos == root_dir_pos && !filename_was_sep) {
154eb11fae6SDimitry Andric       // We've reached the root dir and the input path was *not* ending in a
155eb11fae6SDimitry Andric       // sequence of slashes. Include the root dir in the parent path.
156eb11fae6SDimitry Andric       return root_dir_pos + 1;
157eb11fae6SDimitry Andric     }
158f8af5cf6SDimitry Andric 
159eb11fae6SDimitry Andric     // Otherwise, just include before the last slash.
160f8af5cf6SDimitry Andric     return end_pos;
161f8af5cf6SDimitry Andric   }
162f8af5cf6SDimitry Andric } // end unnamed namespace
163f8af5cf6SDimitry Andric 
164f8af5cf6SDimitry Andric enum FSEntity {
165f8af5cf6SDimitry Andric   FS_Dir,
166f8af5cf6SDimitry Andric   FS_File,
167f8af5cf6SDimitry Andric   FS_Name
168f8af5cf6SDimitry Andric };
169f8af5cf6SDimitry Andric 
170044eb2f6SDimitry Andric static std::error_code
createUniqueEntity(const Twine & Model,int & ResultFD,SmallVectorImpl<char> & ResultPath,bool MakeAbsolute,FSEntity Type,sys::fs::OpenFlags Flags=sys::fs::OF_None,unsigned Mode=0)171044eb2f6SDimitry Andric createUniqueEntity(const Twine &Model, int &ResultFD,
172044eb2f6SDimitry Andric                    SmallVectorImpl<char> &ResultPath, bool MakeAbsolute,
173344a3780SDimitry Andric                    FSEntity Type, sys::fs::OpenFlags Flags = sys::fs::OF_None,
174344a3780SDimitry Andric                    unsigned Mode = 0) {
1755ca98fd9SDimitry Andric 
176d8e91e46SDimitry Andric   // Limit the number of attempts we make, so that we don't infinite loop. E.g.
177d8e91e46SDimitry Andric   // "permission denied" could be for a specific file (so we retry with a
178d8e91e46SDimitry Andric   // different name) or for the whole directory (retry would always fail).
179d8e91e46SDimitry Andric   // Checking which is racy, so we try a number of times, then give up.
180d8e91e46SDimitry Andric   std::error_code EC;
181d8e91e46SDimitry Andric   for (int Retries = 128; Retries > 0; --Retries) {
182e6d15924SDimitry Andric     sys::fs::createUniquePath(Model, ResultPath, MakeAbsolute);
1835ca98fd9SDimitry Andric     // Try to open + create the file.
1845ca98fd9SDimitry Andric     switch (Type) {
1855ca98fd9SDimitry Andric     case FS_File: {
186d8e91e46SDimitry Andric       EC = sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
187d8e91e46SDimitry Andric                                          sys::fs::CD_CreateNew, Flags, Mode);
188d8e91e46SDimitry Andric       if (EC) {
189d8e91e46SDimitry Andric         // errc::permission_denied happens on Windows when we try to open a file
190d8e91e46SDimitry Andric         // that has been marked for deletion.
191d8e91e46SDimitry Andric         if (EC == errc::file_exists || EC == errc::permission_denied)
192d8e91e46SDimitry Andric           continue;
1935ca98fd9SDimitry Andric         return EC;
1945ca98fd9SDimitry Andric       }
1955ca98fd9SDimitry Andric 
1965ca98fd9SDimitry Andric       return std::error_code();
1975ca98fd9SDimitry Andric     }
1985ca98fd9SDimitry Andric 
1995ca98fd9SDimitry Andric     case FS_Name: {
200d8e91e46SDimitry Andric       EC = sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist);
20167c32a98SDimitry Andric       if (EC == errc::no_such_file_or_directory)
20267c32a98SDimitry Andric         return std::error_code();
2035ca98fd9SDimitry Andric       if (EC)
2045ca98fd9SDimitry Andric         return EC;
205d8e91e46SDimitry Andric       continue;
2065ca98fd9SDimitry Andric     }
2075ca98fd9SDimitry Andric 
2085ca98fd9SDimitry Andric     case FS_Dir: {
209d8e91e46SDimitry Andric       EC = sys::fs::create_directory(ResultPath.begin(), false);
210d8e91e46SDimitry Andric       if (EC) {
2115ca98fd9SDimitry Andric         if (EC == errc::file_exists)
212d8e91e46SDimitry Andric           continue;
2135ca98fd9SDimitry Andric         return EC;
2145ca98fd9SDimitry Andric       }
2155ca98fd9SDimitry Andric       return std::error_code();
2165ca98fd9SDimitry Andric     }
2175ca98fd9SDimitry Andric     }
2185ca98fd9SDimitry Andric     llvm_unreachable("Invalid Type");
2195ca98fd9SDimitry Andric   }
220d8e91e46SDimitry Andric   return EC;
221d8e91e46SDimitry Andric }
222f8af5cf6SDimitry Andric 
223f8af5cf6SDimitry Andric namespace llvm {
224f8af5cf6SDimitry Andric namespace sys  {
225f8af5cf6SDimitry Andric namespace path {
226f8af5cf6SDimitry Andric 
begin(StringRef path,Style style)22771d5a254SDimitry Andric const_iterator begin(StringRef path, Style style) {
228f8af5cf6SDimitry Andric   const_iterator i;
229f8af5cf6SDimitry Andric   i.Path      = path;
23071d5a254SDimitry Andric   i.Component = find_first_component(path, style);
231f8af5cf6SDimitry Andric   i.Position  = 0;
23271d5a254SDimitry Andric   i.S = style;
233f8af5cf6SDimitry Andric   return i;
234f8af5cf6SDimitry Andric }
235f8af5cf6SDimitry Andric 
end(StringRef path)236f8af5cf6SDimitry Andric const_iterator end(StringRef path) {
237f8af5cf6SDimitry Andric   const_iterator i;
238f8af5cf6SDimitry Andric   i.Path      = path;
239f8af5cf6SDimitry Andric   i.Position  = path.size();
240f8af5cf6SDimitry Andric   return i;
241f8af5cf6SDimitry Andric }
242f8af5cf6SDimitry Andric 
operator ++()243f8af5cf6SDimitry Andric const_iterator &const_iterator::operator++() {
244f8af5cf6SDimitry Andric   assert(Position < Path.size() && "Tried to increment past end!");
245f8af5cf6SDimitry Andric 
246f8af5cf6SDimitry Andric   // Increment Position to past the current component
247f8af5cf6SDimitry Andric   Position += Component.size();
248f8af5cf6SDimitry Andric 
249f8af5cf6SDimitry Andric   // Check for end.
250f8af5cf6SDimitry Andric   if (Position == Path.size()) {
251f8af5cf6SDimitry Andric     Component = StringRef();
252f8af5cf6SDimitry Andric     return *this;
253f8af5cf6SDimitry Andric   }
254f8af5cf6SDimitry Andric 
255f8af5cf6SDimitry Andric   // Both POSIX and Windows treat paths that begin with exactly two separators
256f8af5cf6SDimitry Andric   // specially.
25771d5a254SDimitry Andric   bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
25871d5a254SDimitry Andric                  Component[1] == Component[0] && !is_separator(Component[2], S);
259f8af5cf6SDimitry Andric 
260f8af5cf6SDimitry Andric   // Handle separators.
26171d5a254SDimitry Andric   if (is_separator(Path[Position], S)) {
262f8af5cf6SDimitry Andric     // Root dir.
26371d5a254SDimitry Andric     if (was_net ||
264f8af5cf6SDimitry Andric         // c:/
265b1c73532SDimitry Andric         (is_style_windows(S) && Component.ends_with(":"))) {
266f8af5cf6SDimitry Andric       Component = Path.substr(Position, 1);
267f8af5cf6SDimitry Andric       return *this;
268f8af5cf6SDimitry Andric     }
269f8af5cf6SDimitry Andric 
270f8af5cf6SDimitry Andric     // Skip extra separators.
27171d5a254SDimitry Andric     while (Position != Path.size() && is_separator(Path[Position], S)) {
272f8af5cf6SDimitry Andric       ++Position;
273f8af5cf6SDimitry Andric     }
274f8af5cf6SDimitry Andric 
275eb11fae6SDimitry Andric     // Treat trailing '/' as a '.', unless it is the root dir.
276eb11fae6SDimitry Andric     if (Position == Path.size() && Component != "/") {
277f8af5cf6SDimitry Andric       --Position;
278f8af5cf6SDimitry Andric       Component = ".";
279f8af5cf6SDimitry Andric       return *this;
280f8af5cf6SDimitry Andric     }
281f8af5cf6SDimitry Andric   }
282f8af5cf6SDimitry Andric 
283f8af5cf6SDimitry Andric   // Find next component.
28471d5a254SDimitry Andric   size_t end_pos = Path.find_first_of(separators(S), Position);
285f8af5cf6SDimitry Andric   Component = Path.slice(Position, end_pos);
286f8af5cf6SDimitry Andric 
287f8af5cf6SDimitry Andric   return *this;
288f8af5cf6SDimitry Andric }
289f8af5cf6SDimitry Andric 
operator ==(const const_iterator & RHS) const29067c32a98SDimitry Andric bool const_iterator::operator==(const const_iterator &RHS) const {
29167c32a98SDimitry Andric   return Path.begin() == RHS.Path.begin() && Position == RHS.Position;
29267c32a98SDimitry Andric }
29367c32a98SDimitry Andric 
operator -(const const_iterator & RHS) const29467c32a98SDimitry Andric ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
29567c32a98SDimitry Andric   return Position - RHS.Position;
29667c32a98SDimitry Andric }
29767c32a98SDimitry Andric 
rbegin(StringRef Path,Style style)29871d5a254SDimitry Andric reverse_iterator rbegin(StringRef Path, Style style) {
29967c32a98SDimitry Andric   reverse_iterator I;
30067c32a98SDimitry Andric   I.Path = Path;
30167c32a98SDimitry Andric   I.Position = Path.size();
30271d5a254SDimitry Andric   I.S = style;
303e6d15924SDimitry Andric   ++I;
304e6d15924SDimitry Andric   return I;
30567c32a98SDimitry Andric }
30667c32a98SDimitry Andric 
rend(StringRef Path)30767c32a98SDimitry Andric reverse_iterator rend(StringRef Path) {
30867c32a98SDimitry Andric   reverse_iterator I;
30967c32a98SDimitry Andric   I.Path = Path;
31067c32a98SDimitry Andric   I.Component = Path.substr(0, 0);
31167c32a98SDimitry Andric   I.Position = 0;
31267c32a98SDimitry Andric   return I;
31367c32a98SDimitry Andric }
31467c32a98SDimitry Andric 
operator ++()31567c32a98SDimitry Andric reverse_iterator &reverse_iterator::operator++() {
31671d5a254SDimitry Andric   size_t root_dir_pos = root_dir_start(Path, S);
317eb11fae6SDimitry Andric 
318eb11fae6SDimitry Andric   // Skip separators unless it's the root directory.
319eb11fae6SDimitry Andric   size_t end_pos = Position;
320eb11fae6SDimitry Andric   while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
321eb11fae6SDimitry Andric          is_separator(Path[end_pos - 1], S))
322eb11fae6SDimitry Andric     --end_pos;
323eb11fae6SDimitry Andric 
324eb11fae6SDimitry Andric   // Treat trailing '/' as a '.', unless it is the root dir.
325eb11fae6SDimitry Andric   if (Position == Path.size() && !Path.empty() &&
326eb11fae6SDimitry Andric       is_separator(Path.back(), S) &&
327eb11fae6SDimitry Andric       (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
328f8af5cf6SDimitry Andric     --Position;
329f8af5cf6SDimitry Andric     Component = ".";
330f8af5cf6SDimitry Andric     return *this;
331f8af5cf6SDimitry Andric   }
332f8af5cf6SDimitry Andric 
333f8af5cf6SDimitry Andric   // Find next separator.
33471d5a254SDimitry Andric   size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
335f8af5cf6SDimitry Andric   Component = Path.slice(start_pos, end_pos);
336f8af5cf6SDimitry Andric   Position = start_pos;
337f8af5cf6SDimitry Andric   return *this;
338f8af5cf6SDimitry Andric }
339f8af5cf6SDimitry Andric 
operator ==(const reverse_iterator & RHS) const34067c32a98SDimitry Andric bool reverse_iterator::operator==(const reverse_iterator &RHS) const {
34167c32a98SDimitry Andric   return Path.begin() == RHS.Path.begin() && Component == RHS.Component &&
342f8af5cf6SDimitry Andric          Position == RHS.Position;
343f8af5cf6SDimitry Andric }
344f8af5cf6SDimitry Andric 
operator -(const reverse_iterator & RHS) const34501095a5dSDimitry Andric ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
34601095a5dSDimitry Andric   return Position - RHS.Position;
34701095a5dSDimitry Andric }
34801095a5dSDimitry Andric 
root_path(StringRef path,Style style)34971d5a254SDimitry Andric StringRef root_path(StringRef path, Style style) {
35071d5a254SDimitry Andric   const_iterator b = begin(path, style), pos = b, e = end(path);
351f8af5cf6SDimitry Andric   if (b != e) {
35271d5a254SDimitry Andric     bool has_net =
35371d5a254SDimitry Andric         b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
354b1c73532SDimitry Andric     bool has_drive = is_style_windows(style) && b->ends_with(":");
355f8af5cf6SDimitry Andric 
356f8af5cf6SDimitry Andric     if (has_net || has_drive) {
35771d5a254SDimitry Andric       if ((++pos != e) && is_separator((*pos)[0], style)) {
358f8af5cf6SDimitry Andric         // {C:/,//net/}, so get the first two components.
359f8af5cf6SDimitry Andric         return path.substr(0, b->size() + pos->size());
360b60736ecSDimitry Andric       }
361f8af5cf6SDimitry Andric       // just {C:,//net}, return the first component.
362f8af5cf6SDimitry Andric       return *b;
363f8af5cf6SDimitry Andric     }
364f8af5cf6SDimitry Andric 
365f8af5cf6SDimitry Andric     // POSIX style root directory.
36671d5a254SDimitry Andric     if (is_separator((*b)[0], style)) {
367f8af5cf6SDimitry Andric       return *b;
368f8af5cf6SDimitry Andric     }
369f8af5cf6SDimitry Andric   }
370f8af5cf6SDimitry Andric 
371f8af5cf6SDimitry Andric   return StringRef();
372f8af5cf6SDimitry Andric }
373f8af5cf6SDimitry Andric 
root_name(StringRef path,Style style)37471d5a254SDimitry Andric StringRef root_name(StringRef path, Style style) {
37571d5a254SDimitry Andric   const_iterator b = begin(path, style), e = end(path);
376f8af5cf6SDimitry Andric   if (b != e) {
37771d5a254SDimitry Andric     bool has_net =
37871d5a254SDimitry Andric         b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
379b1c73532SDimitry Andric     bool has_drive = is_style_windows(style) && b->ends_with(":");
380f8af5cf6SDimitry Andric 
381f8af5cf6SDimitry Andric     if (has_net || has_drive) {
382f8af5cf6SDimitry Andric       // just {C:,//net}, return the first component.
383f8af5cf6SDimitry Andric       return *b;
384f8af5cf6SDimitry Andric     }
385f8af5cf6SDimitry Andric   }
386f8af5cf6SDimitry Andric 
387f8af5cf6SDimitry Andric   // No path or no name.
388f8af5cf6SDimitry Andric   return StringRef();
389f8af5cf6SDimitry Andric }
390f8af5cf6SDimitry Andric 
root_directory(StringRef path,Style style)39171d5a254SDimitry Andric StringRef root_directory(StringRef path, Style style) {
39271d5a254SDimitry Andric   const_iterator b = begin(path, style), pos = b, e = end(path);
393f8af5cf6SDimitry Andric   if (b != e) {
39471d5a254SDimitry Andric     bool has_net =
39571d5a254SDimitry Andric         b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
396b1c73532SDimitry Andric     bool has_drive = is_style_windows(style) && b->ends_with(":");
397f8af5cf6SDimitry Andric 
398f8af5cf6SDimitry Andric     if ((has_net || has_drive) &&
399f8af5cf6SDimitry Andric         // {C:,//net}, skip to the next component.
40071d5a254SDimitry Andric         (++pos != e) && is_separator((*pos)[0], style)) {
401f8af5cf6SDimitry Andric       return *pos;
402f8af5cf6SDimitry Andric     }
403f8af5cf6SDimitry Andric 
404f8af5cf6SDimitry Andric     // POSIX style root directory.
40571d5a254SDimitry Andric     if (!has_net && is_separator((*b)[0], style)) {
406f8af5cf6SDimitry Andric       return *b;
407f8af5cf6SDimitry Andric     }
408f8af5cf6SDimitry Andric   }
409f8af5cf6SDimitry Andric 
410f8af5cf6SDimitry Andric   // No path or no root.
411f8af5cf6SDimitry Andric   return StringRef();
412f8af5cf6SDimitry Andric }
413f8af5cf6SDimitry Andric 
relative_path(StringRef path,Style style)41471d5a254SDimitry Andric StringRef relative_path(StringRef path, Style style) {
41571d5a254SDimitry Andric   StringRef root = root_path(path, style);
416f8af5cf6SDimitry Andric   return path.substr(root.size());
417f8af5cf6SDimitry Andric }
418f8af5cf6SDimitry Andric 
append(SmallVectorImpl<char> & path,Style style,const Twine & a,const Twine & b,const Twine & c,const Twine & d)41971d5a254SDimitry Andric void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
42071d5a254SDimitry Andric             const Twine &b, const Twine &c, const Twine &d) {
421f8af5cf6SDimitry Andric   SmallString<32> a_storage;
422f8af5cf6SDimitry Andric   SmallString<32> b_storage;
423f8af5cf6SDimitry Andric   SmallString<32> c_storage;
424f8af5cf6SDimitry Andric   SmallString<32> d_storage;
425f8af5cf6SDimitry Andric 
426f8af5cf6SDimitry Andric   SmallVector<StringRef, 4> components;
427f8af5cf6SDimitry Andric   if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
428f8af5cf6SDimitry Andric   if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
429f8af5cf6SDimitry Andric   if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
430f8af5cf6SDimitry Andric   if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
431f8af5cf6SDimitry Andric 
432dd58ef01SDimitry Andric   for (auto &component : components) {
43371d5a254SDimitry Andric     bool path_has_sep =
43471d5a254SDimitry Andric         !path.empty() && is_separator(path[path.size() - 1], style);
435f8af5cf6SDimitry Andric     if (path_has_sep) {
436f8af5cf6SDimitry Andric       // Strip separators from beginning of component.
43771d5a254SDimitry Andric       size_t loc = component.find_first_not_of(separators(style));
438dd58ef01SDimitry Andric       StringRef c = component.substr(loc);
439f8af5cf6SDimitry Andric 
440f8af5cf6SDimitry Andric       // Append it.
441f8af5cf6SDimitry Andric       path.append(c.begin(), c.end());
442f8af5cf6SDimitry Andric       continue;
443f8af5cf6SDimitry Andric     }
444f8af5cf6SDimitry Andric 
445044eb2f6SDimitry Andric     bool component_has_sep =
446044eb2f6SDimitry Andric         !component.empty() && is_separator(component[0], style);
447044eb2f6SDimitry Andric     if (!component_has_sep &&
448044eb2f6SDimitry Andric         !(path.empty() || has_root_name(component, style))) {
449f8af5cf6SDimitry Andric       // Add a separator.
45071d5a254SDimitry Andric       path.push_back(preferred_separator(style));
451f8af5cf6SDimitry Andric     }
452f8af5cf6SDimitry Andric 
453dd58ef01SDimitry Andric     path.append(component.begin(), component.end());
454f8af5cf6SDimitry Andric   }
455f8af5cf6SDimitry Andric }
456f8af5cf6SDimitry Andric 
append(SmallVectorImpl<char> & path,const Twine & a,const Twine & b,const Twine & c,const Twine & d)45771d5a254SDimitry Andric void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
45871d5a254SDimitry Andric             const Twine &c, const Twine &d) {
45971d5a254SDimitry Andric   append(path, Style::native, a, b, c, d);
460f8af5cf6SDimitry Andric }
461f8af5cf6SDimitry Andric 
append(SmallVectorImpl<char> & path,const_iterator begin,const_iterator end,Style style)46271d5a254SDimitry Andric void append(SmallVectorImpl<char> &path, const_iterator begin,
46371d5a254SDimitry Andric             const_iterator end, Style style) {
46471d5a254SDimitry Andric   for (; begin != end; ++begin)
46571d5a254SDimitry Andric     path::append(path, style, *begin);
46671d5a254SDimitry Andric }
46771d5a254SDimitry Andric 
parent_path(StringRef path,Style style)46871d5a254SDimitry Andric StringRef parent_path(StringRef path, Style style) {
46971d5a254SDimitry Andric   size_t end_pos = parent_path_end(path, style);
470f8af5cf6SDimitry Andric   if (end_pos == StringRef::npos)
471f8af5cf6SDimitry Andric     return StringRef();
472f8af5cf6SDimitry Andric   return path.substr(0, end_pos);
473f8af5cf6SDimitry Andric }
474f8af5cf6SDimitry Andric 
remove_filename(SmallVectorImpl<char> & path,Style style)47571d5a254SDimitry Andric void remove_filename(SmallVectorImpl<char> &path, Style style) {
47671d5a254SDimitry Andric   size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
477f8af5cf6SDimitry Andric   if (end_pos != StringRef::npos)
47877fc4c14SDimitry Andric     path.truncate(end_pos);
479f8af5cf6SDimitry Andric }
480f8af5cf6SDimitry Andric 
replace_extension(SmallVectorImpl<char> & path,const Twine & extension,Style style)48171d5a254SDimitry Andric void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
48271d5a254SDimitry Andric                        Style style) {
483f8af5cf6SDimitry Andric   StringRef p(path.begin(), path.size());
484f8af5cf6SDimitry Andric   SmallString<32> ext_storage;
485f8af5cf6SDimitry Andric   StringRef ext = extension.toStringRef(ext_storage);
486f8af5cf6SDimitry Andric 
487f8af5cf6SDimitry Andric   // Erase existing extension.
488f8af5cf6SDimitry Andric   size_t pos = p.find_last_of('.');
48971d5a254SDimitry Andric   if (pos != StringRef::npos && pos >= filename_pos(p, style))
49077fc4c14SDimitry Andric     path.truncate(pos);
491f8af5cf6SDimitry Andric 
492f8af5cf6SDimitry Andric   // Append '.' if needed.
493f8af5cf6SDimitry Andric   if (ext.size() > 0 && ext[0] != '.')
494f8af5cf6SDimitry Andric     path.push_back('.');
495f8af5cf6SDimitry Andric 
496f8af5cf6SDimitry Andric   // Append extension.
497f8af5cf6SDimitry Andric   path.append(ext.begin(), ext.end());
498f8af5cf6SDimitry Andric }
499f8af5cf6SDimitry Andric 
starts_with(StringRef Path,StringRef Prefix,Style style=Style::native)500cfca06d7SDimitry Andric static bool starts_with(StringRef Path, StringRef Prefix,
501cfca06d7SDimitry Andric                         Style style = Style::native) {
502cfca06d7SDimitry Andric   // Windows prefix matching : case and separator insensitive
503c0981da4SDimitry Andric   if (is_style_windows(style)) {
504cfca06d7SDimitry Andric     if (Path.size() < Prefix.size())
505cfca06d7SDimitry Andric       return false;
506cfca06d7SDimitry Andric     for (size_t I = 0, E = Prefix.size(); I != E; ++I) {
507cfca06d7SDimitry Andric       bool SepPath = is_separator(Path[I], style);
508cfca06d7SDimitry Andric       bool SepPrefix = is_separator(Prefix[I], style);
509cfca06d7SDimitry Andric       if (SepPath != SepPrefix)
510cfca06d7SDimitry Andric         return false;
511cfca06d7SDimitry Andric       if (!SepPath && toLower(Path[I]) != toLower(Prefix[I]))
512cfca06d7SDimitry Andric         return false;
513cfca06d7SDimitry Andric     }
514cfca06d7SDimitry Andric     return true;
515cfca06d7SDimitry Andric   }
516b1c73532SDimitry Andric   return Path.starts_with(Prefix);
517cfca06d7SDimitry Andric }
518cfca06d7SDimitry Andric 
replace_path_prefix(SmallVectorImpl<char> & Path,StringRef OldPrefix,StringRef NewPrefix,Style style)519cfca06d7SDimitry Andric bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix,
520cfca06d7SDimitry Andric                          StringRef NewPrefix, Style style) {
52101095a5dSDimitry Andric   if (OldPrefix.empty() && NewPrefix.empty())
522706b4fc4SDimitry Andric     return false;
52301095a5dSDimitry Andric 
52401095a5dSDimitry Andric   StringRef OrigPath(Path.begin(), Path.size());
525cfca06d7SDimitry Andric   if (!starts_with(OrigPath, OldPrefix, style))
526706b4fc4SDimitry Andric     return false;
52701095a5dSDimitry Andric 
52801095a5dSDimitry Andric   // If prefixes have the same size we can simply copy the new one over.
529cfca06d7SDimitry Andric   if (OldPrefix.size() == NewPrefix.size()) {
530d8e91e46SDimitry Andric     llvm::copy(NewPrefix, Path.begin());
531706b4fc4SDimitry Andric     return true;
53201095a5dSDimitry Andric   }
53301095a5dSDimitry Andric 
534cfca06d7SDimitry Andric   StringRef RelPath = OrigPath.substr(OldPrefix.size());
53501095a5dSDimitry Andric   SmallString<256> NewPath;
536cfca06d7SDimitry Andric   (Twine(NewPrefix) + RelPath).toVector(NewPath);
53701095a5dSDimitry Andric   Path.swap(NewPath);
538706b4fc4SDimitry Andric   return true;
53901095a5dSDimitry Andric }
54001095a5dSDimitry Andric 
native(const Twine & path,SmallVectorImpl<char> & result,Style style)54171d5a254SDimitry Andric void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
542f8af5cf6SDimitry Andric   assert((!path.isSingleStringRef() ||
543f8af5cf6SDimitry Andric           path.getSingleStringRef().data() != result.data()) &&
544f8af5cf6SDimitry Andric          "path and result are not allowed to overlap!");
545f8af5cf6SDimitry Andric   // Clear result.
546f8af5cf6SDimitry Andric   result.clear();
547f8af5cf6SDimitry Andric   path.toVector(result);
54871d5a254SDimitry Andric   native(result, style);
549f8af5cf6SDimitry Andric }
550f8af5cf6SDimitry Andric 
native(SmallVectorImpl<char> & Path,Style style)55171d5a254SDimitry Andric void native(SmallVectorImpl<char> &Path, Style style) {
55271d5a254SDimitry Andric   if (Path.empty())
55371d5a254SDimitry Andric     return;
554c0981da4SDimitry Andric   if (is_style_windows(style)) {
555c0981da4SDimitry Andric     for (char &Ch : Path)
556c0981da4SDimitry Andric       if (is_separator(Ch, style))
557c0981da4SDimitry Andric         Ch = preferred_separator(style);
55871d5a254SDimitry Andric     if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
55971d5a254SDimitry Andric       SmallString<128> PathHome;
56071d5a254SDimitry Andric       home_directory(PathHome);
56171d5a254SDimitry Andric       PathHome.append(Path.begin() + 1, Path.end());
56271d5a254SDimitry Andric       Path = PathHome;
56371d5a254SDimitry Andric     }
56471d5a254SDimitry Andric   } else {
565c0981da4SDimitry Andric     std::replace(Path.begin(), Path.end(), '\\', '/');
56667c32a98SDimitry Andric   }
56767c32a98SDimitry Andric }
568f8af5cf6SDimitry Andric 
convert_to_slash(StringRef path,Style style)56971d5a254SDimitry Andric std::string convert_to_slash(StringRef path, Style style) {
570c0981da4SDimitry Andric   if (is_style_posix(style))
571cfca06d7SDimitry Andric     return std::string(path);
57271d5a254SDimitry Andric 
573909545a8SDimitry Andric   std::string s = path.str();
574909545a8SDimitry Andric   std::replace(s.begin(), s.end(), '\\', '/');
575909545a8SDimitry Andric   return s;
576909545a8SDimitry Andric }
577909545a8SDimitry Andric 
filename(StringRef path,Style style)57871d5a254SDimitry Andric StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
579f8af5cf6SDimitry Andric 
stem(StringRef path,Style style)58071d5a254SDimitry Andric StringRef stem(StringRef path, Style style) {
58171d5a254SDimitry Andric   StringRef fname = filename(path, style);
582f8af5cf6SDimitry Andric   size_t pos = fname.find_last_of('.');
583f8af5cf6SDimitry Andric   if (pos == StringRef::npos)
584f8af5cf6SDimitry Andric     return fname;
585f8af5cf6SDimitry Andric   if ((fname.size() == 1 && fname == ".") ||
586f8af5cf6SDimitry Andric       (fname.size() == 2 && fname == ".."))
587f8af5cf6SDimitry Andric     return fname;
588f8af5cf6SDimitry Andric   return fname.substr(0, pos);
589f8af5cf6SDimitry Andric }
590f8af5cf6SDimitry Andric 
extension(StringRef path,Style style)59171d5a254SDimitry Andric StringRef extension(StringRef path, Style style) {
59271d5a254SDimitry Andric   StringRef fname = filename(path, style);
593f8af5cf6SDimitry Andric   size_t pos = fname.find_last_of('.');
594f8af5cf6SDimitry Andric   if (pos == StringRef::npos)
595f8af5cf6SDimitry Andric     return StringRef();
596f8af5cf6SDimitry Andric   if ((fname.size() == 1 && fname == ".") ||
597f8af5cf6SDimitry Andric       (fname.size() == 2 && fname == ".."))
598f8af5cf6SDimitry Andric     return StringRef();
599f8af5cf6SDimitry Andric   return fname.substr(pos);
600f8af5cf6SDimitry Andric }
601f8af5cf6SDimitry Andric 
is_separator(char value,Style style)60271d5a254SDimitry Andric bool is_separator(char value, Style style) {
60371d5a254SDimitry Andric   if (value == '/')
60471d5a254SDimitry Andric     return true;
605c0981da4SDimitry Andric   if (is_style_windows(style))
60671d5a254SDimitry Andric     return value == '\\';
60771d5a254SDimitry Andric   return false;
608f8af5cf6SDimitry Andric }
609f8af5cf6SDimitry Andric 
get_separator(Style style)61071d5a254SDimitry Andric StringRef get_separator(Style style) {
61171d5a254SDimitry Andric   if (real_style(style) == Style::windows)
61271d5a254SDimitry Andric     return "\\";
61371d5a254SDimitry Andric   return "/";
6145ca98fd9SDimitry Andric }
6155ca98fd9SDimitry Andric 
has_root_name(const Twine & path,Style style)61671d5a254SDimitry Andric bool has_root_name(const Twine &path, Style style) {
617f8af5cf6SDimitry Andric   SmallString<128> path_storage;
618f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
619f8af5cf6SDimitry Andric 
62071d5a254SDimitry Andric   return !root_name(p, style).empty();
621f8af5cf6SDimitry Andric }
622f8af5cf6SDimitry Andric 
has_root_directory(const Twine & path,Style style)62371d5a254SDimitry Andric bool has_root_directory(const Twine &path, Style style) {
624f8af5cf6SDimitry Andric   SmallString<128> path_storage;
625f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
626f8af5cf6SDimitry Andric 
62771d5a254SDimitry Andric   return !root_directory(p, style).empty();
628f8af5cf6SDimitry Andric }
629f8af5cf6SDimitry Andric 
has_root_path(const Twine & path,Style style)63071d5a254SDimitry Andric bool has_root_path(const Twine &path, Style style) {
631f8af5cf6SDimitry Andric   SmallString<128> path_storage;
632f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
633f8af5cf6SDimitry Andric 
63471d5a254SDimitry Andric   return !root_path(p, style).empty();
635f8af5cf6SDimitry Andric }
636f8af5cf6SDimitry Andric 
has_relative_path(const Twine & path,Style style)63771d5a254SDimitry Andric bool has_relative_path(const Twine &path, Style style) {
638f8af5cf6SDimitry Andric   SmallString<128> path_storage;
639f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
640f8af5cf6SDimitry Andric 
64171d5a254SDimitry Andric   return !relative_path(p, style).empty();
642f8af5cf6SDimitry Andric }
643f8af5cf6SDimitry Andric 
has_filename(const Twine & path,Style style)64471d5a254SDimitry Andric bool has_filename(const Twine &path, Style style) {
645f8af5cf6SDimitry Andric   SmallString<128> path_storage;
646f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
647f8af5cf6SDimitry Andric 
64871d5a254SDimitry Andric   return !filename(p, style).empty();
649f8af5cf6SDimitry Andric }
650f8af5cf6SDimitry Andric 
has_parent_path(const Twine & path,Style style)65171d5a254SDimitry Andric bool has_parent_path(const Twine &path, Style style) {
652f8af5cf6SDimitry Andric   SmallString<128> path_storage;
653f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
654f8af5cf6SDimitry Andric 
65571d5a254SDimitry Andric   return !parent_path(p, style).empty();
656f8af5cf6SDimitry Andric }
657f8af5cf6SDimitry Andric 
has_stem(const Twine & path,Style style)65871d5a254SDimitry Andric bool has_stem(const Twine &path, Style style) {
659f8af5cf6SDimitry Andric   SmallString<128> path_storage;
660f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
661f8af5cf6SDimitry Andric 
66271d5a254SDimitry Andric   return !stem(p, style).empty();
663f8af5cf6SDimitry Andric }
664f8af5cf6SDimitry Andric 
has_extension(const Twine & path,Style style)66571d5a254SDimitry Andric bool has_extension(const Twine &path, Style style) {
666f8af5cf6SDimitry Andric   SmallString<128> path_storage;
667f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
668f8af5cf6SDimitry Andric 
66971d5a254SDimitry Andric   return !extension(p, style).empty();
670f8af5cf6SDimitry Andric }
671f8af5cf6SDimitry Andric 
is_absolute(const Twine & path,Style style)67271d5a254SDimitry Andric bool is_absolute(const Twine &path, Style style) {
673f8af5cf6SDimitry Andric   SmallString<128> path_storage;
674f8af5cf6SDimitry Andric   StringRef p = path.toStringRef(path_storage);
675f8af5cf6SDimitry Andric 
67671d5a254SDimitry Andric   bool rootDir = has_root_directory(p, style);
677c0981da4SDimitry Andric   bool rootName = is_style_posix(style) || has_root_name(p, style);
678f8af5cf6SDimitry Andric 
679f8af5cf6SDimitry Andric   return rootDir && rootName;
680f8af5cf6SDimitry Andric }
681f8af5cf6SDimitry Andric 
is_absolute_gnu(const Twine & path,Style style)682b60736ecSDimitry Andric bool is_absolute_gnu(const Twine &path, Style style) {
683b60736ecSDimitry Andric   SmallString<128> path_storage;
684b60736ecSDimitry Andric   StringRef p = path.toStringRef(path_storage);
685b60736ecSDimitry Andric 
686b60736ecSDimitry Andric   // Handle '/' which is absolute for both Windows and POSIX systems.
687b60736ecSDimitry Andric   // Handle '\\' on Windows.
688b60736ecSDimitry Andric   if (!p.empty() && is_separator(p.front(), style))
689b60736ecSDimitry Andric     return true;
690b60736ecSDimitry Andric 
691c0981da4SDimitry Andric   if (is_style_windows(style)) {
692b60736ecSDimitry Andric     // Handle drive letter pattern (a character followed by ':') on Windows.
693b60736ecSDimitry Andric     if (p.size() >= 2 && (p[0] && p[1] == ':'))
694b60736ecSDimitry Andric       return true;
695b60736ecSDimitry Andric   }
696b60736ecSDimitry Andric 
697b60736ecSDimitry Andric   return false;
698b60736ecSDimitry Andric }
699b60736ecSDimitry Andric 
is_relative(const Twine & path,Style style)70071d5a254SDimitry Andric bool is_relative(const Twine &path, Style style) {
70171d5a254SDimitry Andric   return !is_absolute(path, style);
70271d5a254SDimitry Andric }
703dd58ef01SDimitry Andric 
remove_leading_dotslash(StringRef Path,Style style)70471d5a254SDimitry Andric StringRef remove_leading_dotslash(StringRef Path, Style style) {
705dd58ef01SDimitry Andric   // Remove leading "./" (or ".//" or "././" etc.)
70671d5a254SDimitry Andric   while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
707dd58ef01SDimitry Andric     Path = Path.substr(2);
70871d5a254SDimitry Andric     while (Path.size() > 0 && is_separator(Path[0], style))
709dd58ef01SDimitry Andric       Path = Path.substr(1);
710dd58ef01SDimitry Andric   }
711dd58ef01SDimitry Andric   return Path;
712dd58ef01SDimitry Andric }
713dd58ef01SDimitry Andric 
714cfca06d7SDimitry Andric // Remove path traversal components ("." and "..") when possible, and
715cfca06d7SDimitry Andric // canonicalize slashes.
remove_dots(SmallVectorImpl<char> & the_path,bool remove_dot_dot,Style style)716cfca06d7SDimitry Andric bool remove_dots(SmallVectorImpl<char> &the_path, bool remove_dot_dot,
71771d5a254SDimitry Andric                  Style style) {
718cfca06d7SDimitry Andric   style = real_style(style);
719cfca06d7SDimitry Andric   StringRef remaining(the_path.data(), the_path.size());
720cfca06d7SDimitry Andric   bool needs_change = false;
721dd58ef01SDimitry Andric   SmallVector<StringRef, 16> components;
722dd58ef01SDimitry Andric 
723cfca06d7SDimitry Andric   // Consume the root path, if present.
724cfca06d7SDimitry Andric   StringRef root = path::root_path(remaining, style);
725cfca06d7SDimitry Andric   bool absolute = !root.empty();
726cfca06d7SDimitry Andric   if (absolute)
727cfca06d7SDimitry Andric     remaining = remaining.drop_front(root.size());
728cfca06d7SDimitry Andric 
729cfca06d7SDimitry Andric   // Loop over path components manually. This makes it easier to detect
730cfca06d7SDimitry Andric   // non-preferred slashes and double separators that must be canonicalized.
731cfca06d7SDimitry Andric   while (!remaining.empty()) {
732cfca06d7SDimitry Andric     size_t next_slash = remaining.find_first_of(separators(style));
733cfca06d7SDimitry Andric     if (next_slash == StringRef::npos)
734cfca06d7SDimitry Andric       next_slash = remaining.size();
735cfca06d7SDimitry Andric     StringRef component = remaining.take_front(next_slash);
736cfca06d7SDimitry Andric     remaining = remaining.drop_front(next_slash);
737cfca06d7SDimitry Andric 
738cfca06d7SDimitry Andric     // Eat the slash, and check if it is the preferred separator.
739cfca06d7SDimitry Andric     if (!remaining.empty()) {
740cfca06d7SDimitry Andric       needs_change |= remaining.front() != preferred_separator(style);
741cfca06d7SDimitry Andric       remaining = remaining.drop_front();
742cfca06d7SDimitry Andric       // The path needs to be rewritten if it has a trailing slash.
743cfca06d7SDimitry Andric       // FIXME: This is emergent behavior that could be removed.
744cfca06d7SDimitry Andric       needs_change |= remaining.empty();
745cfca06d7SDimitry Andric     }
746cfca06d7SDimitry Andric 
747cfca06d7SDimitry Andric     // Check for path traversal components or double separators.
748cfca06d7SDimitry Andric     if (component.empty() || component == ".") {
749cfca06d7SDimitry Andric       needs_change = true;
750cfca06d7SDimitry Andric     } else if (remove_dot_dot && component == "..") {
751cfca06d7SDimitry Andric       needs_change = true;
752cfca06d7SDimitry Andric       // Do not allow ".." to remove the root component. If this is the
753cfca06d7SDimitry Andric       // beginning of a relative path, keep the ".." component.
754b915e9e0SDimitry Andric       if (!components.empty() && components.back() != "..") {
755dd58ef01SDimitry Andric         components.pop_back();
756cfca06d7SDimitry Andric       } else if (!absolute) {
757cfca06d7SDimitry Andric         components.push_back(component);
758dd58ef01SDimitry Andric       }
759cfca06d7SDimitry Andric     } else {
760cfca06d7SDimitry Andric       components.push_back(component);
761dd58ef01SDimitry Andric     }
762dd58ef01SDimitry Andric   }
763dd58ef01SDimitry Andric 
764145449b1SDimitry Andric   SmallString<256> buffer = root;
765145449b1SDimitry Andric   // "root" could be "/", which may need to be translated into "\".
766145449b1SDimitry Andric   make_preferred(buffer, style);
767145449b1SDimitry Andric   needs_change |= root != buffer;
768145449b1SDimitry Andric 
769cfca06d7SDimitry Andric   // Avoid rewriting the path unless we have to.
770cfca06d7SDimitry Andric   if (!needs_change)
771dd58ef01SDimitry Andric     return false;
772dd58ef01SDimitry Andric 
773cfca06d7SDimitry Andric   if (!components.empty()) {
774cfca06d7SDimitry Andric     buffer += components[0];
775e3b55780SDimitry Andric     for (StringRef C : ArrayRef(components).drop_front()) {
776cfca06d7SDimitry Andric       buffer += preferred_separator(style);
777cfca06d7SDimitry Andric       buffer += C;
778cfca06d7SDimitry Andric     }
779cfca06d7SDimitry Andric   }
780cfca06d7SDimitry Andric   the_path.swap(buffer);
781dd58ef01SDimitry Andric   return true;
782f8af5cf6SDimitry Andric }
783f8af5cf6SDimitry Andric 
784f8af5cf6SDimitry Andric } // end namespace path
785f8af5cf6SDimitry Andric 
786f8af5cf6SDimitry Andric namespace fs {
787f8af5cf6SDimitry Andric 
getUniqueID(const Twine Path,UniqueID & Result)7885ca98fd9SDimitry Andric std::error_code getUniqueID(const Twine Path, UniqueID &Result) {
789f8af5cf6SDimitry Andric   file_status Status;
7905ca98fd9SDimitry Andric   std::error_code EC = status(Path, Status);
791f8af5cf6SDimitry Andric   if (EC)
792f8af5cf6SDimitry Andric     return EC;
793f8af5cf6SDimitry Andric   Result = Status.getUniqueID();
7945ca98fd9SDimitry Andric   return std::error_code();
795f8af5cf6SDimitry Andric }
796f8af5cf6SDimitry Andric 
createUniquePath(const Twine & Model,SmallVectorImpl<char> & ResultPath,bool MakeAbsolute)797e6d15924SDimitry Andric void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
798e6d15924SDimitry Andric                       bool MakeAbsolute) {
799e6d15924SDimitry Andric   SmallString<128> ModelStorage;
800e6d15924SDimitry Andric   Model.toVector(ModelStorage);
801e6d15924SDimitry Andric 
802e6d15924SDimitry Andric   if (MakeAbsolute) {
803e6d15924SDimitry Andric     // Make model absolute by prepending a temp directory if it's not already.
804e6d15924SDimitry Andric     if (!sys::path::is_absolute(Twine(ModelStorage))) {
805e6d15924SDimitry Andric       SmallString<128> TDir;
806e6d15924SDimitry Andric       sys::path::system_temp_directory(true, TDir);
807e6d15924SDimitry Andric       sys::path::append(TDir, Twine(ModelStorage));
808e6d15924SDimitry Andric       ModelStorage.swap(TDir);
809e6d15924SDimitry Andric     }
810e6d15924SDimitry Andric   }
811e6d15924SDimitry Andric 
812e6d15924SDimitry Andric   ResultPath = ModelStorage;
813e6d15924SDimitry Andric   ResultPath.push_back(0);
814e6d15924SDimitry Andric   ResultPath.pop_back();
815e6d15924SDimitry Andric 
816e6d15924SDimitry Andric   // Replace '%' with random chars.
817e6d15924SDimitry Andric   for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
818e6d15924SDimitry Andric     if (ModelStorage[i] == '%')
819e6d15924SDimitry Andric       ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
820e6d15924SDimitry Andric   }
821e6d15924SDimitry Andric }
822e6d15924SDimitry Andric 
createUniqueFile(const Twine & Model,int & ResultFd,SmallVectorImpl<char> & ResultPath,OpenFlags Flags,unsigned Mode)8235ca98fd9SDimitry Andric std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
8245ca98fd9SDimitry Andric                                  SmallVectorImpl<char> &ResultPath,
825344a3780SDimitry Andric                                  OpenFlags Flags, unsigned Mode) {
826344a3780SDimitry Andric   return createUniqueEntity(Model, ResultFd, ResultPath, false, FS_File, Flags,
827344a3780SDimitry Andric                             Mode);
828f8af5cf6SDimitry Andric }
829f8af5cf6SDimitry Andric 
createUniqueFile(const Twine & Model,SmallVectorImpl<char> & ResultPath,unsigned Mode)8305ca98fd9SDimitry Andric std::error_code createUniqueFile(const Twine &Model,
831eb11fae6SDimitry Andric                                  SmallVectorImpl<char> &ResultPath,
832eb11fae6SDimitry Andric                                  unsigned Mode) {
833eb11fae6SDimitry Andric   int FD;
834344a3780SDimitry Andric   auto EC = createUniqueFile(Model, FD, ResultPath, OF_None, Mode);
835eb11fae6SDimitry Andric   if (EC)
836eb11fae6SDimitry Andric     return EC;
837eb11fae6SDimitry Andric   // FD is only needed to avoid race conditions. Close it right away.
838eb11fae6SDimitry Andric   close(FD);
839eb11fae6SDimitry Andric   return EC;
840f8af5cf6SDimitry Andric }
841f8af5cf6SDimitry Andric 
8425ca98fd9SDimitry Andric static std::error_code
createTemporaryFile(const Twine & Model,int & ResultFD,llvm::SmallVectorImpl<char> & ResultPath,FSEntity Type,sys::fs::OpenFlags Flags=sys::fs::OF_None)8435ca98fd9SDimitry Andric createTemporaryFile(const Twine &Model, int &ResultFD,
844344a3780SDimitry Andric                     llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
845344a3780SDimitry Andric                     sys::fs::OpenFlags Flags = sys::fs::OF_None) {
846f8af5cf6SDimitry Andric   SmallString<128> Storage;
847f8af5cf6SDimitry Andric   StringRef P = Model.toNullTerminatedStringRef(Storage);
84871d5a254SDimitry Andric   assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
849f8af5cf6SDimitry Andric          "Model must be a simple filename.");
850f8af5cf6SDimitry Andric   // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
851344a3780SDimitry Andric   return createUniqueEntity(P.begin(), ResultFD, ResultPath, true, Type, Flags,
852ac9a064cSDimitry Andric                             all_read | all_write);
853f8af5cf6SDimitry Andric }
854f8af5cf6SDimitry Andric 
8555ca98fd9SDimitry Andric static std::error_code
createTemporaryFile(const Twine & Prefix,StringRef Suffix,int & ResultFD,llvm::SmallVectorImpl<char> & ResultPath,FSEntity Type,sys::fs::OpenFlags Flags=sys::fs::OF_None)856f8af5cf6SDimitry Andric createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
857344a3780SDimitry Andric                     llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
858344a3780SDimitry Andric                     sys::fs::OpenFlags Flags = sys::fs::OF_None) {
859f8af5cf6SDimitry Andric   const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
860f8af5cf6SDimitry Andric   return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
861344a3780SDimitry Andric                              Type, Flags);
862f8af5cf6SDimitry Andric }
863f8af5cf6SDimitry Andric 
createTemporaryFile(const Twine & Prefix,StringRef Suffix,int & ResultFD,SmallVectorImpl<char> & ResultPath,sys::fs::OpenFlags Flags)8645ca98fd9SDimitry Andric std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
865f8af5cf6SDimitry Andric                                     int &ResultFD,
866344a3780SDimitry Andric                                     SmallVectorImpl<char> &ResultPath,
867344a3780SDimitry Andric                                     sys::fs::OpenFlags Flags) {
868344a3780SDimitry Andric   return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File,
869344a3780SDimitry Andric                              Flags);
870f8af5cf6SDimitry Andric }
871f8af5cf6SDimitry Andric 
createTemporaryFile(const Twine & Prefix,StringRef Suffix,SmallVectorImpl<char> & ResultPath,sys::fs::OpenFlags Flags)8725ca98fd9SDimitry Andric std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
873344a3780SDimitry Andric                                     SmallVectorImpl<char> &ResultPath,
874344a3780SDimitry Andric                                     sys::fs::OpenFlags Flags) {
875eb11fae6SDimitry Andric   int FD;
876344a3780SDimitry Andric   auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath, Flags);
877eb11fae6SDimitry Andric   if (EC)
878eb11fae6SDimitry Andric     return EC;
879eb11fae6SDimitry Andric   // FD is only needed to avoid race conditions. Close it right away.
880eb11fae6SDimitry Andric   close(FD);
881eb11fae6SDimitry Andric   return EC;
882f8af5cf6SDimitry Andric }
883f8af5cf6SDimitry Andric 
884f8af5cf6SDimitry Andric // This is a mkdtemp with a different pattern. We use createUniqueEntity mostly
885f8af5cf6SDimitry Andric // for consistency. We should try using mkdtemp.
createUniqueDirectory(const Twine & Prefix,SmallVectorImpl<char> & ResultPath)8865ca98fd9SDimitry Andric std::error_code createUniqueDirectory(const Twine &Prefix,
887f8af5cf6SDimitry Andric                                       SmallVectorImpl<char> &ResultPath) {
888f8af5cf6SDimitry Andric   int Dummy;
889344a3780SDimitry Andric   return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true,
890eb11fae6SDimitry Andric                             FS_Dir);
891eb11fae6SDimitry Andric }
892eb11fae6SDimitry Andric 
893eb11fae6SDimitry Andric std::error_code
getPotentiallyUniqueFileName(const Twine & Model,SmallVectorImpl<char> & ResultPath)894eb11fae6SDimitry Andric getPotentiallyUniqueFileName(const Twine &Model,
895eb11fae6SDimitry Andric                              SmallVectorImpl<char> &ResultPath) {
896eb11fae6SDimitry Andric   int Dummy;
897344a3780SDimitry Andric   return createUniqueEntity(Model, Dummy, ResultPath, false, FS_Name);
898eb11fae6SDimitry Andric }
899eb11fae6SDimitry Andric 
900eb11fae6SDimitry Andric std::error_code
getPotentiallyUniqueTempFileName(const Twine & Prefix,StringRef Suffix,SmallVectorImpl<char> & ResultPath)901eb11fae6SDimitry Andric getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
902eb11fae6SDimitry Andric                                  SmallVectorImpl<char> &ResultPath) {
903eb11fae6SDimitry Andric   int Dummy;
904eb11fae6SDimitry Andric   return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
905f8af5cf6SDimitry Andric }
906f8af5cf6SDimitry Andric 
make_absolute(const Twine & current_directory,SmallVectorImpl<char> & path)907d8e91e46SDimitry Andric void make_absolute(const Twine &current_directory,
908d8e91e46SDimitry Andric                    SmallVectorImpl<char> &path) {
909f8af5cf6SDimitry Andric   StringRef p(path.data(), path.size());
910f8af5cf6SDimitry Andric 
91171d5a254SDimitry Andric   bool rootDirectory = path::has_root_directory(p);
9121d5ae102SDimitry Andric   bool rootName = path::has_root_name(p);
913f8af5cf6SDimitry Andric 
914f8af5cf6SDimitry Andric   // Already absolute.
915c0981da4SDimitry Andric   if ((rootName || is_style_posix(Style::native)) && rootDirectory)
916d8e91e46SDimitry Andric     return;
917f8af5cf6SDimitry Andric 
918f8af5cf6SDimitry Andric   // All of the following conditions will need the current directory.
919f8af5cf6SDimitry Andric   SmallString<128> current_dir;
920dd58ef01SDimitry Andric   current_directory.toVector(current_dir);
921f8af5cf6SDimitry Andric 
922f8af5cf6SDimitry Andric   // Relative path. Prepend the current directory.
923f8af5cf6SDimitry Andric   if (!rootName && !rootDirectory) {
924f8af5cf6SDimitry Andric     // Append path to the current directory.
925f8af5cf6SDimitry Andric     path::append(current_dir, p);
926f8af5cf6SDimitry Andric     // Set path to the result.
927f8af5cf6SDimitry Andric     path.swap(current_dir);
928d8e91e46SDimitry Andric     return;
929f8af5cf6SDimitry Andric   }
930f8af5cf6SDimitry Andric 
931f8af5cf6SDimitry Andric   if (!rootName && rootDirectory) {
932f8af5cf6SDimitry Andric     StringRef cdrn = path::root_name(current_dir);
933f8af5cf6SDimitry Andric     SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
934f8af5cf6SDimitry Andric     path::append(curDirRootName, p);
935f8af5cf6SDimitry Andric     // Set path to the result.
936f8af5cf6SDimitry Andric     path.swap(curDirRootName);
937d8e91e46SDimitry Andric     return;
938f8af5cf6SDimitry Andric   }
939f8af5cf6SDimitry Andric 
940f8af5cf6SDimitry Andric   if (rootName && !rootDirectory) {
941f8af5cf6SDimitry Andric     StringRef pRootName      = path::root_name(p);
942f8af5cf6SDimitry Andric     StringRef bRootDirectory = path::root_directory(current_dir);
943f8af5cf6SDimitry Andric     StringRef bRelativePath  = path::relative_path(current_dir);
944f8af5cf6SDimitry Andric     StringRef pRelativePath  = path::relative_path(p);
945f8af5cf6SDimitry Andric 
946f8af5cf6SDimitry Andric     SmallString<128> res;
947f8af5cf6SDimitry Andric     path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
948f8af5cf6SDimitry Andric     path.swap(res);
949d8e91e46SDimitry Andric     return;
950f8af5cf6SDimitry Andric   }
951f8af5cf6SDimitry Andric 
952f8af5cf6SDimitry Andric   llvm_unreachable("All rootName and rootDirectory combinations should have "
953f8af5cf6SDimitry Andric                    "occurred above!");
954f8af5cf6SDimitry Andric }
955f8af5cf6SDimitry Andric 
make_absolute(SmallVectorImpl<char> & path)956dd58ef01SDimitry Andric std::error_code make_absolute(SmallVectorImpl<char> &path) {
957d8e91e46SDimitry Andric   if (path::is_absolute(path))
958d8e91e46SDimitry Andric     return {};
959d8e91e46SDimitry Andric 
960d8e91e46SDimitry Andric   SmallString<128> current_dir;
961d8e91e46SDimitry Andric   if (std::error_code ec = current_path(current_dir))
962d8e91e46SDimitry Andric     return ec;
963d8e91e46SDimitry Andric 
964d8e91e46SDimitry Andric   make_absolute(current_dir, path);
965d8e91e46SDimitry Andric   return {};
966dd58ef01SDimitry Andric }
967dd58ef01SDimitry Andric 
create_directories(const Twine & Path,bool IgnoreExisting,perms Perms)968dd58ef01SDimitry Andric std::error_code create_directories(const Twine &Path, bool IgnoreExisting,
969dd58ef01SDimitry Andric                                    perms Perms) {
9705ca98fd9SDimitry Andric   SmallString<128> PathStorage;
9715ca98fd9SDimitry Andric   StringRef P = Path.toStringRef(PathStorage);
972f8af5cf6SDimitry Andric 
9735ca98fd9SDimitry Andric   // Be optimistic and try to create the directory
974dd58ef01SDimitry Andric   std::error_code EC = create_directory(P, IgnoreExisting, Perms);
9755ca98fd9SDimitry Andric   // If we succeeded, or had any error other than the parent not existing, just
9765ca98fd9SDimitry Andric   // return it.
9775ca98fd9SDimitry Andric   if (EC != errc::no_such_file_or_directory)
9785ca98fd9SDimitry Andric     return EC;
979f8af5cf6SDimitry Andric 
9805ca98fd9SDimitry Andric   // We failed because of a no_such_file_or_directory, try to create the
9815ca98fd9SDimitry Andric   // parent.
9825ca98fd9SDimitry Andric   StringRef Parent = path::parent_path(P);
9835ca98fd9SDimitry Andric   if (Parent.empty())
9845ca98fd9SDimitry Andric     return EC;
9855ca98fd9SDimitry Andric 
986dd58ef01SDimitry Andric   if ((EC = create_directories(Parent, IgnoreExisting, Perms)))
9875ca98fd9SDimitry Andric       return EC;
9885ca98fd9SDimitry Andric 
989dd58ef01SDimitry Andric   return create_directory(P, IgnoreExisting, Perms);
990f8af5cf6SDimitry Andric }
991f8af5cf6SDimitry Andric 
copy_file_internal(int ReadFD,int WriteFD)992eb11fae6SDimitry Andric static std::error_code copy_file_internal(int ReadFD, int WriteFD) {
9935ca98fd9SDimitry Andric   const size_t BufSize = 4096;
9945ca98fd9SDimitry Andric   char *Buf = new char[BufSize];
9955ca98fd9SDimitry Andric   int BytesRead = 0, BytesWritten = 0;
9965ca98fd9SDimitry Andric   for (;;) {
9975ca98fd9SDimitry Andric     BytesRead = read(ReadFD, Buf, BufSize);
9985ca98fd9SDimitry Andric     if (BytesRead <= 0)
9995ca98fd9SDimitry Andric       break;
10005ca98fd9SDimitry Andric     while (BytesRead) {
10015ca98fd9SDimitry Andric       BytesWritten = write(WriteFD, Buf, BytesRead);
10025ca98fd9SDimitry Andric       if (BytesWritten < 0)
10035ca98fd9SDimitry Andric         break;
10045ca98fd9SDimitry Andric       BytesRead -= BytesWritten;
10055ca98fd9SDimitry Andric     }
10065ca98fd9SDimitry Andric     if (BytesWritten < 0)
10075ca98fd9SDimitry Andric       break;
10085ca98fd9SDimitry Andric   }
10095ca98fd9SDimitry Andric   delete[] Buf;
10105ca98fd9SDimitry Andric 
10115ca98fd9SDimitry Andric   if (BytesRead < 0 || BytesWritten < 0)
1012ac9a064cSDimitry Andric     return errnoAsErrorCode();
10135ca98fd9SDimitry Andric   return std::error_code();
1014f8af5cf6SDimitry Andric }
1015f8af5cf6SDimitry Andric 
1016e6d15924SDimitry Andric #ifndef __APPLE__
copy_file(const Twine & From,const Twine & To)1017eb11fae6SDimitry Andric std::error_code copy_file(const Twine &From, const Twine &To) {
1018eb11fae6SDimitry Andric   int ReadFD, WriteFD;
1019eb11fae6SDimitry Andric   if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
1020eb11fae6SDimitry Andric     return EC;
1021eb11fae6SDimitry Andric   if (std::error_code EC =
1022eb11fae6SDimitry Andric           openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) {
1023eb11fae6SDimitry Andric     close(ReadFD);
1024eb11fae6SDimitry Andric     return EC;
1025eb11fae6SDimitry Andric   }
1026eb11fae6SDimitry Andric 
1027eb11fae6SDimitry Andric   std::error_code EC = copy_file_internal(ReadFD, WriteFD);
1028eb11fae6SDimitry Andric 
1029eb11fae6SDimitry Andric   close(ReadFD);
1030eb11fae6SDimitry Andric   close(WriteFD);
1031eb11fae6SDimitry Andric 
1032eb11fae6SDimitry Andric   return EC;
1033eb11fae6SDimitry Andric }
1034e6d15924SDimitry Andric #endif
1035eb11fae6SDimitry Andric 
copy_file(const Twine & From,int ToFD)1036eb11fae6SDimitry Andric std::error_code copy_file(const Twine &From, int ToFD) {
1037eb11fae6SDimitry Andric   int ReadFD;
1038eb11fae6SDimitry Andric   if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
1039eb11fae6SDimitry Andric     return EC;
1040eb11fae6SDimitry Andric 
1041eb11fae6SDimitry Andric   std::error_code EC = copy_file_internal(ReadFD, ToFD);
1042eb11fae6SDimitry Andric 
1043eb11fae6SDimitry Andric   close(ReadFD);
1044eb11fae6SDimitry Andric 
1045eb11fae6SDimitry Andric   return EC;
1046eb11fae6SDimitry Andric }
1047eb11fae6SDimitry Andric 
md5_contents(int FD)104871d5a254SDimitry Andric ErrorOr<MD5::MD5Result> md5_contents(int FD) {
104971d5a254SDimitry Andric   MD5 Hash;
105071d5a254SDimitry Andric 
105171d5a254SDimitry Andric   constexpr size_t BufSize = 4096;
105271d5a254SDimitry Andric   std::vector<uint8_t> Buf(BufSize);
105371d5a254SDimitry Andric   int BytesRead = 0;
105471d5a254SDimitry Andric   for (;;) {
105571d5a254SDimitry Andric     BytesRead = read(FD, Buf.data(), BufSize);
105671d5a254SDimitry Andric     if (BytesRead <= 0)
105771d5a254SDimitry Andric       break;
1058e3b55780SDimitry Andric     Hash.update(ArrayRef(Buf.data(), BytesRead));
105971d5a254SDimitry Andric   }
106071d5a254SDimitry Andric 
106171d5a254SDimitry Andric   if (BytesRead < 0)
1062ac9a064cSDimitry Andric     return errnoAsErrorCode();
106371d5a254SDimitry Andric   MD5::MD5Result Result;
106471d5a254SDimitry Andric   Hash.final(Result);
106571d5a254SDimitry Andric   return Result;
106671d5a254SDimitry Andric }
106771d5a254SDimitry Andric 
md5_contents(const Twine & Path)106871d5a254SDimitry Andric ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
106971d5a254SDimitry Andric   int FD;
1070eb11fae6SDimitry Andric   if (auto EC = openFileForRead(Path, FD, OF_None))
107171d5a254SDimitry Andric     return EC;
107271d5a254SDimitry Andric 
107371d5a254SDimitry Andric   auto Result = md5_contents(FD);
107471d5a254SDimitry Andric   close(FD);
107571d5a254SDimitry Andric   return Result;
107671d5a254SDimitry Andric }
107771d5a254SDimitry Andric 
exists(const basic_file_status & status)1078044eb2f6SDimitry Andric bool exists(const basic_file_status &status) {
1079f8af5cf6SDimitry Andric   return status_known(status) && status.type() != file_type::file_not_found;
1080f8af5cf6SDimitry Andric }
1081f8af5cf6SDimitry Andric 
status_known(const basic_file_status & s)1082044eb2f6SDimitry Andric bool status_known(const basic_file_status &s) {
1083f8af5cf6SDimitry Andric   return s.type() != file_type::status_error;
1084f8af5cf6SDimitry Andric }
1085f8af5cf6SDimitry Andric 
get_file_type(const Twine & Path,bool Follow)108671d5a254SDimitry Andric file_type get_file_type(const Twine &Path, bool Follow) {
108771d5a254SDimitry Andric   file_status st;
108871d5a254SDimitry Andric   if (status(Path, st, Follow))
108971d5a254SDimitry Andric     return file_type::status_error;
109071d5a254SDimitry Andric   return st.type();
109171d5a254SDimitry Andric }
109271d5a254SDimitry Andric 
is_directory(const basic_file_status & status)1093044eb2f6SDimitry Andric bool is_directory(const basic_file_status &status) {
1094f8af5cf6SDimitry Andric   return status.type() == file_type::directory_file;
1095f8af5cf6SDimitry Andric }
1096f8af5cf6SDimitry Andric 
is_directory(const Twine & path,bool & result)10975ca98fd9SDimitry Andric std::error_code is_directory(const Twine &path, bool &result) {
1098f8af5cf6SDimitry Andric   file_status st;
10995ca98fd9SDimitry Andric   if (std::error_code ec = status(path, st))
1100f8af5cf6SDimitry Andric     return ec;
1101f8af5cf6SDimitry Andric   result = is_directory(st);
11025ca98fd9SDimitry Andric   return std::error_code();
1103f8af5cf6SDimitry Andric }
1104f8af5cf6SDimitry Andric 
is_regular_file(const basic_file_status & status)1105044eb2f6SDimitry Andric bool is_regular_file(const basic_file_status &status) {
1106f8af5cf6SDimitry Andric   return status.type() == file_type::regular_file;
1107f8af5cf6SDimitry Andric }
1108f8af5cf6SDimitry Andric 
is_regular_file(const Twine & path,bool & result)11095ca98fd9SDimitry Andric std::error_code is_regular_file(const Twine &path, bool &result) {
1110f8af5cf6SDimitry Andric   file_status st;
11115ca98fd9SDimitry Andric   if (std::error_code ec = status(path, st))
1112f8af5cf6SDimitry Andric     return ec;
1113f8af5cf6SDimitry Andric   result = is_regular_file(st);
11145ca98fd9SDimitry Andric   return std::error_code();
1115f8af5cf6SDimitry Andric }
1116f8af5cf6SDimitry Andric 
is_symlink_file(const basic_file_status & status)1117044eb2f6SDimitry Andric bool is_symlink_file(const basic_file_status &status) {
111871d5a254SDimitry Andric   return status.type() == file_type::symlink_file;
111971d5a254SDimitry Andric }
112071d5a254SDimitry Andric 
is_symlink_file(const Twine & path,bool & result)112171d5a254SDimitry Andric std::error_code is_symlink_file(const Twine &path, bool &result) {
112271d5a254SDimitry Andric   file_status st;
112371d5a254SDimitry Andric   if (std::error_code ec = status(path, st, false))
112471d5a254SDimitry Andric     return ec;
112571d5a254SDimitry Andric   result = is_symlink_file(st);
112671d5a254SDimitry Andric   return std::error_code();
112771d5a254SDimitry Andric }
112871d5a254SDimitry Andric 
is_other(const basic_file_status & status)1129044eb2f6SDimitry Andric bool is_other(const basic_file_status &status) {
1130f8af5cf6SDimitry Andric   return exists(status) &&
1131f8af5cf6SDimitry Andric          !is_regular_file(status) &&
11325ca98fd9SDimitry Andric          !is_directory(status);
1133f8af5cf6SDimitry Andric }
1134f8af5cf6SDimitry Andric 
is_other(const Twine & Path,bool & Result)113567c32a98SDimitry Andric std::error_code is_other(const Twine &Path, bool &Result) {
113667c32a98SDimitry Andric   file_status FileStatus;
113767c32a98SDimitry Andric   if (std::error_code EC = status(Path, FileStatus))
113867c32a98SDimitry Andric     return EC;
113967c32a98SDimitry Andric   Result = is_other(FileStatus);
114067c32a98SDimitry Andric   return std::error_code();
114167c32a98SDimitry Andric }
114267c32a98SDimitry Andric 
replace_filename(const Twine & Filename,file_type Type,basic_file_status Status)1143d8e91e46SDimitry Andric void directory_entry::replace_filename(const Twine &Filename, file_type Type,
1144d8e91e46SDimitry Andric                                        basic_file_status Status) {
1145d8e91e46SDimitry Andric   SmallString<128> PathStr = path::parent_path(Path);
1146d8e91e46SDimitry Andric   path::append(PathStr, Filename);
11474df029ccSDimitry Andric   this->Path = std::string(PathStr);
1148d8e91e46SDimitry Andric   this->Type = Type;
1149d8e91e46SDimitry Andric   this->Status = Status;
1150f8af5cf6SDimitry Andric }
1151f8af5cf6SDimitry Andric 
getPermissions(const Twine & Path)115271d5a254SDimitry Andric ErrorOr<perms> getPermissions(const Twine &Path) {
115371d5a254SDimitry Andric   file_status Status;
115471d5a254SDimitry Andric   if (std::error_code EC = status(Path, Status))
115571d5a254SDimitry Andric     return EC;
115671d5a254SDimitry Andric 
115771d5a254SDimitry Andric   return Status.permissions();
1158cf099d11SDimitry Andric }
1159cf099d11SDimitry Andric 
size() const1160344a3780SDimitry Andric size_t mapped_file_region::size() const {
1161344a3780SDimitry Andric   assert(Mapping && "Mapping failed but used anyway!");
1162344a3780SDimitry Andric   return Size;
1163344a3780SDimitry Andric }
1164344a3780SDimitry Andric 
data() const1165344a3780SDimitry Andric char *mapped_file_region::data() const {
1166344a3780SDimitry Andric   assert(Mapping && "Mapping failed but used anyway!");
1167344a3780SDimitry Andric   return reinterpret_cast<char *>(Mapping);
1168344a3780SDimitry Andric }
1169344a3780SDimitry Andric 
const_data() const1170344a3780SDimitry Andric const char *mapped_file_region::const_data() const {
1171344a3780SDimitry Andric   assert(Mapping && "Mapping failed but used anyway!");
1172344a3780SDimitry Andric   return reinterpret_cast<const char *>(Mapping);
1173344a3780SDimitry Andric }
1174344a3780SDimitry Andric 
readNativeFileToEOF(file_t FileHandle,SmallVectorImpl<char> & Buffer,ssize_t ChunkSize)11756f8fc217SDimitry Andric Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl<char> &Buffer,
11766f8fc217SDimitry Andric                           ssize_t ChunkSize) {
11776f8fc217SDimitry Andric   // Install a handler to truncate the buffer to the correct size on exit.
11786f8fc217SDimitry Andric   size_t Size = Buffer.size();
11796f8fc217SDimitry Andric   auto TruncateOnExit = make_scope_exit([&]() { Buffer.truncate(Size); });
11806f8fc217SDimitry Andric 
11816f8fc217SDimitry Andric   // Read into Buffer until we hit EOF.
11826f8fc217SDimitry Andric   for (;;) {
11836f8fc217SDimitry Andric     Buffer.resize_for_overwrite(Size + ChunkSize);
11846f8fc217SDimitry Andric     Expected<size_t> ReadBytes = readNativeFile(
1185e3b55780SDimitry Andric         FileHandle, MutableArrayRef(Buffer.begin() + Size, ChunkSize));
11866f8fc217SDimitry Andric     if (!ReadBytes)
11876f8fc217SDimitry Andric       return ReadBytes.takeError();
11886f8fc217SDimitry Andric     if (*ReadBytes == 0)
11896f8fc217SDimitry Andric       return Error::success();
11906f8fc217SDimitry Andric     Size += *ReadBytes;
11916f8fc217SDimitry Andric   }
11926f8fc217SDimitry Andric }
11936f8fc217SDimitry Andric 
1194f8af5cf6SDimitry Andric } // end namespace fs
1195f8af5cf6SDimitry Andric } // end namespace sys
1196f8af5cf6SDimitry Andric } // end namespace llvm
1197cf099d11SDimitry Andric 
1198f8af5cf6SDimitry Andric // Include the truly platform-specific parts.
1199cf099d11SDimitry Andric #if defined(LLVM_ON_UNIX)
1200cf099d11SDimitry Andric #include "Unix/Path.inc"
1201cf099d11SDimitry Andric #endif
1202eb11fae6SDimitry Andric #if defined(_WIN32)
1203cf099d11SDimitry Andric #include "Windows/Path.inc"
1204cf099d11SDimitry Andric #endif
1205dd58ef01SDimitry Andric 
1206dd58ef01SDimitry Andric namespace llvm {
1207dd58ef01SDimitry Andric namespace sys {
1208044eb2f6SDimitry Andric namespace fs {
1209145449b1SDimitry Andric 
TempFile(StringRef Name,int FD)1210cfca06d7SDimitry Andric TempFile::TempFile(StringRef Name, int FD)
1211cfca06d7SDimitry Andric     : TmpName(std::string(Name)), FD(FD) {}
TempFile(TempFile && Other)1212044eb2f6SDimitry Andric TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }
operator =(TempFile && Other)1213044eb2f6SDimitry Andric TempFile &TempFile::operator=(TempFile &&Other) {
1214044eb2f6SDimitry Andric   TmpName = std::move(Other.TmpName);
1215044eb2f6SDimitry Andric   FD = Other.FD;
1216044eb2f6SDimitry Andric   Other.Done = true;
1217e6d15924SDimitry Andric   Other.FD = -1;
1218c0981da4SDimitry Andric #ifdef _WIN32
1219c0981da4SDimitry Andric   RemoveOnClose = Other.RemoveOnClose;
1220c0981da4SDimitry Andric   Other.RemoveOnClose = false;
1221c0981da4SDimitry Andric #endif
1222044eb2f6SDimitry Andric   return *this;
1223044eb2f6SDimitry Andric }
1224044eb2f6SDimitry Andric 
~TempFile()1225044eb2f6SDimitry Andric TempFile::~TempFile() { assert(Done); }
1226044eb2f6SDimitry Andric 
discard()1227044eb2f6SDimitry Andric Error TempFile::discard() {
1228044eb2f6SDimitry Andric   Done = true;
1229044eb2f6SDimitry Andric   if (FD != -1 && close(FD) == -1) {
1230ac9a064cSDimitry Andric     std::error_code EC = errnoAsErrorCode();
1231044eb2f6SDimitry Andric     return errorCodeToError(EC);
1232044eb2f6SDimitry Andric   }
1233044eb2f6SDimitry Andric   FD = -1;
1234044eb2f6SDimitry Andric 
1235e6d15924SDimitry Andric #ifdef _WIN32
1236c0981da4SDimitry Andric   // On Windows, closing will remove the file, if we set the delete
1237c0981da4SDimitry Andric   // disposition. If not, remove it manually.
1238c0981da4SDimitry Andric   bool Remove = RemoveOnClose;
1239e6d15924SDimitry Andric #else
1240c0981da4SDimitry Andric   // Always try to remove the file.
1241c0981da4SDimitry Andric   bool Remove = true;
1242c0981da4SDimitry Andric #endif
1243e6d15924SDimitry Andric   std::error_code RemoveEC;
1244c0981da4SDimitry Andric   if (Remove && !TmpName.empty()) {
1245e6d15924SDimitry Andric     RemoveEC = fs::remove(TmpName);
1246e6d15924SDimitry Andric     sys::DontRemoveFileOnSignal(TmpName);
1247e6d15924SDimitry Andric     if (!RemoveEC)
1248e6d15924SDimitry Andric       TmpName = "";
1249c0981da4SDimitry Andric   } else {
1250c0981da4SDimitry Andric     TmpName = "";
1251e6d15924SDimitry Andric   }
1252044eb2f6SDimitry Andric   return errorCodeToError(RemoveEC);
1253044eb2f6SDimitry Andric }
1254044eb2f6SDimitry Andric 
keep(const Twine & Name)1255044eb2f6SDimitry Andric Error TempFile::keep(const Twine &Name) {
1256044eb2f6SDimitry Andric   assert(!Done);
1257044eb2f6SDimitry Andric   Done = true;
1258044eb2f6SDimitry Andric   // Always try to close and rename.
1259eb11fae6SDimitry Andric #ifdef _WIN32
1260eb11fae6SDimitry Andric   // If we can't cancel the delete don't rename.
1261eb11fae6SDimitry Andric   auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
12626f8fc217SDimitry Andric   std::error_code RenameEC =
12636f8fc217SDimitry Andric       RemoveOnClose ? std::error_code() : setDeleteDisposition(H, false);
1264c0981da4SDimitry Andric   bool ShouldDelete = false;
1265d8e91e46SDimitry Andric   if (!RenameEC) {
1266344a3780SDimitry Andric     RenameEC = rename_handle(H, Name);
1267d8e91e46SDimitry Andric     // If rename failed because it's cross-device, copy instead
1268d8e91e46SDimitry Andric     if (RenameEC ==
1269d8e91e46SDimitry Andric       std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) {
1270d8e91e46SDimitry Andric       RenameEC = copy_file(TmpName, Name);
1271c0981da4SDimitry Andric       ShouldDelete = true;
1272d8e91e46SDimitry Andric     }
1273d8e91e46SDimitry Andric   }
1274d8e91e46SDimitry Andric 
1275c0981da4SDimitry Andric   // If we can't rename or copy, discard the temporary file.
1276044eb2f6SDimitry Andric   if (RenameEC)
1277c0981da4SDimitry Andric     ShouldDelete = true;
1278c0981da4SDimitry Andric   if (ShouldDelete) {
1279c0981da4SDimitry Andric     if (!RemoveOnClose)
1280eb11fae6SDimitry Andric       setDeleteDisposition(H, true);
1281c0981da4SDimitry Andric     else
1282c0981da4SDimitry Andric       remove(TmpName);
1283c0981da4SDimitry Andric   }
1284044eb2f6SDimitry Andric #else
1285044eb2f6SDimitry Andric   std::error_code RenameEC = fs::rename(TmpName, Name);
1286b7eb8e35SDimitry Andric   if (RenameEC) {
1287b7eb8e35SDimitry Andric     // If we can't rename, try to copy to work around cross-device link issues.
1288b7eb8e35SDimitry Andric     RenameEC = sys::fs::copy_file(TmpName, Name);
1289b7eb8e35SDimitry Andric     // If we can't rename or copy, discard the temporary file.
1290044eb2f6SDimitry Andric     if (RenameEC)
1291044eb2f6SDimitry Andric       remove(TmpName);
1292b7eb8e35SDimitry Andric   }
1293044eb2f6SDimitry Andric #endif
1294c0981da4SDimitry Andric   sys::DontRemoveFileOnSignal(TmpName);
1295044eb2f6SDimitry Andric 
1296044eb2f6SDimitry Andric   if (!RenameEC)
1297044eb2f6SDimitry Andric     TmpName = "";
1298044eb2f6SDimitry Andric 
1299ac9a064cSDimitry Andric   if (close(FD) == -1)
1300ac9a064cSDimitry Andric     return errorCodeToError(errnoAsErrorCode());
1301044eb2f6SDimitry Andric   FD = -1;
1302044eb2f6SDimitry Andric 
1303044eb2f6SDimitry Andric   return errorCodeToError(RenameEC);
1304044eb2f6SDimitry Andric }
1305044eb2f6SDimitry Andric 
keep()1306044eb2f6SDimitry Andric Error TempFile::keep() {
1307044eb2f6SDimitry Andric   assert(!Done);
1308044eb2f6SDimitry Andric   Done = true;
1309044eb2f6SDimitry Andric 
1310eb11fae6SDimitry Andric #ifdef _WIN32
1311eb11fae6SDimitry Andric   auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
1312eb11fae6SDimitry Andric   if (std::error_code EC = setDeleteDisposition(H, false))
1313044eb2f6SDimitry Andric     return errorCodeToError(EC);
1314044eb2f6SDimitry Andric #endif
1315c0981da4SDimitry Andric   sys::DontRemoveFileOnSignal(TmpName);
1316044eb2f6SDimitry Andric 
1317044eb2f6SDimitry Andric   TmpName = "";
1318044eb2f6SDimitry Andric 
1319ac9a064cSDimitry Andric   if (close(FD) == -1)
1320ac9a064cSDimitry Andric     return errorCodeToError(errnoAsErrorCode());
1321044eb2f6SDimitry Andric   FD = -1;
1322044eb2f6SDimitry Andric 
1323044eb2f6SDimitry Andric   return Error::success();
1324044eb2f6SDimitry Andric }
1325044eb2f6SDimitry Andric 
create(const Twine & Model,unsigned Mode,OpenFlags ExtraFlags)1326344a3780SDimitry Andric Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode,
1327344a3780SDimitry Andric                                     OpenFlags ExtraFlags) {
1328044eb2f6SDimitry Andric   int FD;
1329044eb2f6SDimitry Andric   SmallString<128> ResultPath;
1330eb11fae6SDimitry Andric   if (std::error_code EC =
1331344a3780SDimitry Andric           createUniqueFile(Model, FD, ResultPath, OF_Delete | ExtraFlags, Mode))
1332044eb2f6SDimitry Andric     return errorCodeToError(EC);
1333044eb2f6SDimitry Andric 
1334044eb2f6SDimitry Andric   TempFile Ret(ResultPath, FD);
1335c0981da4SDimitry Andric #ifdef _WIN32
1336c0981da4SDimitry Andric   auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
1337c0981da4SDimitry Andric   bool SetSignalHandler = false;
1338c0981da4SDimitry Andric   if (std::error_code EC = setDeleteDisposition(H, true)) {
1339c0981da4SDimitry Andric     Ret.RemoveOnClose = true;
1340c0981da4SDimitry Andric     SetSignalHandler = true;
1341c0981da4SDimitry Andric   }
1342c0981da4SDimitry Andric #else
1343c0981da4SDimitry Andric   bool SetSignalHandler = true;
1344c0981da4SDimitry Andric #endif
1345c0981da4SDimitry Andric   if (SetSignalHandler && sys::RemoveFileOnSignal(ResultPath)) {
1346044eb2f6SDimitry Andric     // Make sure we delete the file when RemoveFileOnSignal fails.
1347044eb2f6SDimitry Andric     consumeError(Ret.discard());
1348044eb2f6SDimitry Andric     std::error_code EC(errc::operation_not_permitted);
1349044eb2f6SDimitry Andric     return errorCodeToError(EC);
1350044eb2f6SDimitry Andric   }
1351044eb2f6SDimitry Andric   return std::move(Ret);
1352044eb2f6SDimitry Andric }
1353b60736ecSDimitry Andric } // namespace fs
1354044eb2f6SDimitry Andric 
1355b60736ecSDimitry Andric } // namespace sys
1356b60736ecSDimitry Andric } // namespace llvm
1357