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