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 ¤t_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