/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Support/Path.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- Path.cpp - Implement OS Path Concept ------------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file implements the operating system Path API. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/Support/Path.h" |
15 | | #include "llvm/ADT/ArrayRef.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 <cctype> |
22 | | #include <cstring> |
23 | | |
24 | | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
25 | | #include <unistd.h> |
26 | | #else |
27 | | #include <io.h> |
28 | | #endif |
29 | | |
30 | | using namespace llvm; |
31 | | using namespace llvm::support::endian; |
32 | | |
33 | | namespace { |
34 | | using llvm::StringRef; |
35 | | using llvm::sys::path::is_separator; |
36 | | using llvm::sys::path::Style; |
37 | | |
38 | 109M | inline Style real_style(Style style) { |
39 | | #ifdef LLVM_ON_WIN32 |
40 | | return (style == Style::posix) ? Style::posix : Style::windows; |
41 | | #else |
42 | 109M | return (style == Style::windows) ? Style::windows637 : Style::posix109M ; |
43 | 109M | #endif |
44 | 109M | } |
45 | | |
46 | 16.0M | inline const char *separators(Style style) { |
47 | 16.0M | if (real_style(style) == Style::windows) |
48 | 80 | return "\\/"; |
49 | 16.0M | return "/"; |
50 | 16.0M | } |
51 | | |
52 | 3.35M | inline char preferred_separator(Style style) { |
53 | 3.35M | if (real_style(style) == Style::windows) |
54 | 10 | return '\\'; |
55 | 3.35M | return '/'; |
56 | 3.35M | } |
57 | | |
58 | 9.70M | StringRef find_first_component(StringRef path, Style style) { |
59 | 9.70M | // Look for this first component in the following order. |
60 | 9.70M | // * empty (in this case we return an empty string) |
61 | 9.70M | // * either C: or {//,\\}net. |
62 | 9.70M | // * {/,\} |
63 | 9.70M | // * {file,directory}name |
64 | 9.70M | |
65 | 9.70M | if (path.empty()) |
66 | 395k | return path; |
67 | 9.30M | |
68 | 9.30M | if (9.30M real_style(style) == Style::windows9.30M ) { |
69 | 41 | // C: |
70 | 41 | if (path.size() >= 2 && |
71 | 41 | std::isalpha(static_cast<unsigned char>(path[0]))34 && path[1] == ':'2 ) |
72 | 1 | return path.substr(0, 2); |
73 | 9.30M | } |
74 | 9.30M | |
75 | 9.30M | // //net |
76 | 9.30M | if (9.30M (path.size() > 2) && 9.30M is_separator(path[0], style)9.07M && |
77 | 9.30M | path[0] == path[1]2.74M && !is_separator(path[2], style)824 ) { |
78 | 804 | // Find the next directory separator. |
79 | 804 | size_t end = path.find_first_of(separators(style), 2); |
80 | 804 | return path.substr(0, end); |
81 | 804 | } |
82 | 9.30M | |
83 | 9.30M | // {/,\} |
84 | 9.30M | if (9.30M is_separator(path[0], style)9.30M ) |
85 | 2.74M | return path.substr(0, 1); |
86 | 6.55M | |
87 | 6.55M | // * {file,directory}name |
88 | 6.55M | size_t end = path.find_first_of(separators(style)); |
89 | 6.55M | return path.substr(0, end); |
90 | 6.55M | } |
91 | | |
92 | 6.41M | size_t filename_pos(StringRef str, Style style) { |
93 | 6.41M | if (str.size() == 2 && 6.41M is_separator(str[0], style)65 && str[0] == str[1]14 ) |
94 | 0 | return 0; |
95 | 6.41M | |
96 | 6.41M | if (6.41M str.size() > 0 && 6.41M is_separator(str[str.size() - 1], style)6.38M ) |
97 | 142k | return str.size() - 1; |
98 | 6.27M | |
99 | 6.27M | size_t pos = str.find_last_of(separators(style), str.size() - 1); |
100 | 6.27M | |
101 | 6.27M | if (real_style(style) == Style::windows6.27M ) { |
102 | 9 | if (pos == StringRef::npos) |
103 | 0 | pos = str.find_last_of(':', str.size() - 2); |
104 | 9 | } |
105 | 6.27M | |
106 | 6.27M | if (pos == StringRef::npos || 6.27M (pos == 1 && 6.14M is_separator(str[0], style)10.1k )) |
107 | 122k | return 0; |
108 | 6.14M | |
109 | 6.14M | return pos + 1; |
110 | 6.14M | } |
111 | | |
112 | 6.46M | size_t root_dir_start(StringRef str, Style style) { |
113 | 6.46M | // case "c:/" |
114 | 6.46M | if (real_style(style) == Style::windows6.46M ) { |
115 | 15 | if (str.size() > 2 && 15 str[1] == ':'15 && is_separator(str[2], style)7 ) |
116 | 7 | return 2; |
117 | 6.46M | } |
118 | 6.46M | |
119 | 6.46M | // case "//" |
120 | 6.46M | if (6.46M str.size() == 2 && 6.46M is_separator(str[0], style)10.1k && str[0] == str[1]10 ) |
121 | 0 | return StringRef::npos; |
122 | 6.46M | |
123 | 6.46M | // case "//net" |
124 | 6.46M | if (6.46M str.size() > 3 && 6.46M is_separator(str[0], style)6.28M && str[0] == str[1]5.85M && |
125 | 6.46M | !is_separator(str[2], style)258 ) { |
126 | 226 | return str.find_first_of(separators(style), 2); |
127 | 226 | } |
128 | 6.46M | |
129 | 6.46M | // case "/" |
130 | 6.46M | if (6.46M str.size() > 0 && 6.46M is_separator(str[0], style)6.36M ) |
131 | 5.92M | return 0; |
132 | 536k | |
133 | 536k | return StringRef::npos; |
134 | 536k | } |
135 | | |
136 | 2.74M | size_t parent_path_end(StringRef path, Style style) { |
137 | 2.74M | size_t end_pos = filename_pos(path, style); |
138 | 2.74M | |
139 | 2.74M | bool filename_was_sep = |
140 | 2.73M | path.size() > 0 && is_separator(path[end_pos], style); |
141 | 2.74M | |
142 | 2.74M | // Skip separators except for root dir. |
143 | 2.74M | size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style); |
144 | 2.74M | |
145 | 5.30M | while (end_pos > 0 && 5.30M (end_pos - 1) != root_dir_pos5.23M && |
146 | 5.19M | is_separator(path[end_pos - 1], style)) |
147 | 2.56M | --end_pos; |
148 | 2.74M | |
149 | 2.74M | if (end_pos == 1 && 2.74M root_dir_pos == 043.1k && filename_was_sep33.0k ) |
150 | 0 | return StringRef::npos; |
151 | 2.74M | |
152 | 2.74M | return end_pos; |
153 | 2.74M | } |
154 | | } // end unnamed namespace |
155 | | |
156 | | enum FSEntity { |
157 | | FS_Dir, |
158 | | FS_File, |
159 | | FS_Name |
160 | | }; |
161 | | |
162 | | static std::error_code createUniqueEntity(const Twine &Model, int &ResultFD, |
163 | | SmallVectorImpl<char> &ResultPath, |
164 | | bool MakeAbsolute, unsigned Mode, |
165 | 34.2k | FSEntity Type) { |
166 | 34.2k | SmallString<128> ModelStorage; |
167 | 34.2k | Model.toVector(ModelStorage); |
168 | 34.2k | |
169 | 34.2k | if (MakeAbsolute34.2k ) { |
170 | 6.55k | // Make model absolute by prepending a temp directory if it's not already. |
171 | 6.55k | if (!sys::path::is_absolute(Twine(ModelStorage))6.55k ) { |
172 | 6.55k | SmallString<128> TDir; |
173 | 6.55k | sys::path::system_temp_directory(true, TDir); |
174 | 6.55k | sys::path::append(TDir, Twine(ModelStorage)); |
175 | 6.55k | ModelStorage.swap(TDir); |
176 | 6.55k | } |
177 | 6.55k | } |
178 | 34.2k | |
179 | 34.2k | // From here on, DO NOT modify model. It may be needed if the randomly chosen |
180 | 34.2k | // path already exists. |
181 | 34.2k | ResultPath = ModelStorage; |
182 | 34.2k | // Null terminate. |
183 | 34.2k | ResultPath.push_back(0); |
184 | 34.2k | ResultPath.pop_back(); |
185 | 34.2k | |
186 | 34.2k | retry_random_path: |
187 | 34.2k | // Replace '%' with random chars. |
188 | 3.82M | for (unsigned i = 0, e = ModelStorage.size(); i != e3.82M ; ++i3.78M ) { |
189 | 3.78M | if (ModelStorage[i] == '%') |
190 | 255k | ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; |
191 | 3.78M | } |
192 | 34.2k | |
193 | 34.2k | // Try to open + create the file. |
194 | 34.2k | switch (Type) { |
195 | 27.3k | case FS_File: { |
196 | 27.3k | if (std::error_code EC = |
197 | 27.3k | sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD, |
198 | 73 | sys::fs::F_RW | sys::fs::F_Excl, Mode)) { |
199 | 73 | if (EC == errc::file_exists) |
200 | 0 | goto retry_random_path; |
201 | 73 | return EC; |
202 | 73 | } |
203 | 27.3k | |
204 | 27.3k | return std::error_code(); |
205 | 27.3k | } |
206 | 27.3k | |
207 | 6.82k | case FS_Name: { |
208 | 6.82k | std::error_code EC = |
209 | 6.82k | sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist); |
210 | 6.82k | if (EC == errc::no_such_file_or_directory) |
211 | 6.82k | return std::error_code(); |
212 | 0 | if (0 EC0 ) |
213 | 0 | return EC; |
214 | 0 | goto retry_random_path; |
215 | 0 | } |
216 | 0 |
|
217 | 33 | case FS_Dir: { |
218 | 33 | if (std::error_code EC = |
219 | 0 | sys::fs::create_directory(ResultPath.begin(), false)) { |
220 | 0 | if (EC == errc::file_exists) |
221 | 0 | goto retry_random_path; |
222 | 0 | return EC; |
223 | 0 | } |
224 | 33 | return std::error_code(); |
225 | 33 | } |
226 | 0 | } |
227 | 0 | llvm_unreachable0 ("Invalid Type"); |
228 | 0 | } |
229 | | |
230 | | namespace llvm { |
231 | | namespace sys { |
232 | | namespace path { |
233 | | |
234 | 9.70M | const_iterator begin(StringRef path, Style style) { |
235 | 9.70M | const_iterator i; |
236 | 9.70M | i.Path = path; |
237 | 9.70M | i.Component = find_first_component(path, style); |
238 | 9.70M | i.Position = 0; |
239 | 9.70M | i.S = style; |
240 | 9.70M | return i; |
241 | 9.70M | } |
242 | | |
243 | 9.70M | const_iterator end(StringRef path) { |
244 | 9.70M | const_iterator i; |
245 | 9.70M | i.Path = path; |
246 | 9.70M | i.Position = path.size(); |
247 | 9.70M | return i; |
248 | 9.70M | } |
249 | | |
250 | 4.92M | const_iterator &const_iterator::operator++() { |
251 | 4.92M | assert(Position < Path.size() && "Tried to increment past end!"); |
252 | 4.92M | |
253 | 4.92M | // Increment Position to past the current component |
254 | 4.92M | Position += Component.size(); |
255 | 4.92M | |
256 | 4.92M | // Check for end. |
257 | 4.92M | if (Position == Path.size()4.92M ) { |
258 | 1.91M | Component = StringRef(); |
259 | 1.91M | return *this; |
260 | 1.91M | } |
261 | 3.00M | |
262 | 3.00M | // Both POSIX and Windows treat paths that begin with exactly two separators |
263 | 3.00M | // specially. |
264 | 3.00M | bool was_net = Component.size() > 2 && 3.00M is_separator(Component[0], S)2.89M && |
265 | 3.00M | Component[1] == Component[0]790 && !is_separator(Component[2], S)790 ; |
266 | 3.00M | |
267 | 3.00M | // Handle separators. |
268 | 3.00M | if (is_separator(Path[Position], S)3.00M ) { |
269 | 2.92M | // Root dir. |
270 | 2.92M | if (was_net || |
271 | 2.92M | // c:/ |
272 | 2.92M | (real_style(S) == Style::windows && 2.92M Component.endswith(":")28 )) { |
273 | 791 | Component = Path.substr(Position, 1); |
274 | 791 | return *this; |
275 | 791 | } |
276 | 2.92M | |
277 | 2.92M | // Skip extra separators. |
278 | 5.84M | while (2.92M Position != Path.size() && 5.84M is_separator(Path[Position], S)5.84M ) { |
279 | 2.92M | ++Position; |
280 | 2.92M | } |
281 | 2.92M | |
282 | 2.92M | // Treat trailing '/' as a '.'. |
283 | 2.92M | if (Position == Path.size()2.92M ) { |
284 | 57 | --Position; |
285 | 57 | Component = "."; |
286 | 57 | return *this; |
287 | 57 | } |
288 | 3.00M | } |
289 | 3.00M | |
290 | 3.00M | // Find next component. |
291 | 3.00M | size_t end_pos = Path.find_first_of(separators(S), Position); |
292 | 3.00M | Component = Path.slice(Position, end_pos); |
293 | 3.00M | |
294 | 3.00M | return *this; |
295 | 3.00M | } |
296 | | |
297 | 15.3M | bool const_iterator::operator==(const const_iterator &RHS) const { |
298 | 15.3M | return Path.begin() == RHS.Path.begin() && Position == RHS.Position; |
299 | 15.3M | } |
300 | | |
301 | 240 | ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { |
302 | 240 | return Position - RHS.Position; |
303 | 240 | } |
304 | | |
305 | 1.99M | reverse_iterator rbegin(StringRef Path, Style style) { |
306 | 1.99M | reverse_iterator I; |
307 | 1.99M | I.Path = Path; |
308 | 1.99M | I.Position = Path.size(); |
309 | 1.99M | I.S = style; |
310 | 1.99M | return ++I; |
311 | 1.99M | } |
312 | | |
313 | 831k | reverse_iterator rend(StringRef Path) { |
314 | 831k | reverse_iterator I; |
315 | 831k | I.Path = Path; |
316 | 831k | I.Component = Path.substr(0, 0); |
317 | 831k | I.Position = 0; |
318 | 831k | return I; |
319 | 831k | } |
320 | | |
321 | 3.72M | reverse_iterator &reverse_iterator::operator++() { |
322 | 3.72M | // If we're at the end and the previous char was a '/', return '.' unless |
323 | 3.72M | // we are the root path. |
324 | 3.72M | size_t root_dir_pos = root_dir_start(Path, S); |
325 | 3.72M | if (Position == Path.size() && 3.72M Path.size() > root_dir_pos + 11.99M && |
326 | 3.72M | is_separator(Path[Position - 1], S)1.92M ) { |
327 | 74.7k | --Position; |
328 | 74.7k | Component = "."; |
329 | 74.7k | return *this; |
330 | 74.7k | } |
331 | 3.65M | |
332 | 3.65M | // Skip separators unless it's the root directory. |
333 | 3.65M | size_t end_pos = Position; |
334 | 3.65M | |
335 | 5.38M | while (end_pos > 0 && 5.38M (end_pos - 1) != root_dir_pos5.35M && |
336 | 5.32M | is_separator(Path[end_pos - 1], S)) |
337 | 1.73M | --end_pos; |
338 | 3.72M | |
339 | 3.72M | // Find next separator. |
340 | 3.72M | size_t start_pos = filename_pos(Path.substr(0, end_pos), S); |
341 | 3.72M | Component = Path.slice(start_pos, end_pos); |
342 | 3.72M | Position = start_pos; |
343 | 3.72M | return *this; |
344 | 3.72M | } |
345 | | |
346 | 1.73M | bool reverse_iterator::operator==(const reverse_iterator &RHS) const { |
347 | 1.73M | return Path.begin() == RHS.Path.begin() && Component == RHS.Component && |
348 | 163 | Position == RHS.Position; |
349 | 1.73M | } |
350 | | |
351 | 3 | ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const { |
352 | 3 | return Position - RHS.Position; |
353 | 3 | } |
354 | | |
355 | 3.29M | StringRef root_path(StringRef path, Style style) { |
356 | 3.29M | const_iterator b = begin(path, style), pos = b, e = end(path); |
357 | 3.29M | if (b != e3.29M ) { |
358 | 3.12M | bool has_net = |
359 | 3.12M | b->size() > 2 && is_separator((*b)[0], style)566k && (*b)[1] == (*b)[0]415 ; |
360 | 16 | bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); |
361 | 3.12M | |
362 | 3.12M | if (has_net || 3.12M has_drive3.12M ) { |
363 | 415 | if ((++pos != e) && 415 is_separator((*pos)[0], style)411 ) { |
364 | 411 | // {C:/,//net/}, so get the first two components. |
365 | 411 | return path.substr(0, b->size() + pos->size()); |
366 | 0 | } else { |
367 | 4 | // just {C:,//net}, return the first component. |
368 | 4 | return *b; |
369 | 4 | } |
370 | 3.12M | } |
371 | 3.12M | |
372 | 3.12M | // POSIX style root directory. |
373 | 3.12M | if (3.12M is_separator((*b)[0], style)3.12M ) { |
374 | 2.43M | return *b; |
375 | 2.43M | } |
376 | 859k | } |
377 | 859k | |
378 | 859k | return StringRef(); |
379 | 859k | } |
380 | | |
381 | 3.48M | StringRef root_name(StringRef path, Style style) { |
382 | 3.48M | const_iterator b = begin(path, style), e = end(path); |
383 | 3.48M | if (b != e3.48M ) { |
384 | 3.40M | bool has_net = |
385 | 3.40M | b->size() > 2 && is_separator((*b)[0], style)3.33M && (*b)[1] == (*b)[0]6 ; |
386 | 13 | bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); |
387 | 3.40M | |
388 | 3.40M | if (has_net || 3.40M has_drive3.40M ) { |
389 | 6 | // just {C:,//net}, return the first component. |
390 | 6 | return *b; |
391 | 6 | } |
392 | 3.48M | } |
393 | 3.48M | |
394 | 3.48M | // No path or no name. |
395 | 3.48M | return StringRef(); |
396 | 3.48M | } |
397 | | |
398 | 1.73M | StringRef root_directory(StringRef path, Style style) { |
399 | 1.73M | const_iterator b = begin(path, style), pos = b, e = end(path); |
400 | 1.73M | if (b != e1.73M ) { |
401 | 1.62M | bool has_net = |
402 | 1.62M | b->size() > 2 && is_separator((*b)[0], style)1.32M && (*b)[1] == (*b)[0]277 ; |
403 | 3 | bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); |
404 | 1.62M | |
405 | 1.62M | if ((has_net || 1.62M has_drive1.62M ) && |
406 | 1.62M | // {C:,//net}, skip to the next component. |
407 | 1.62M | (++pos != e)277 && is_separator((*pos)[0], style)270 ) { |
408 | 270 | return *pos; |
409 | 270 | } |
410 | 1.62M | |
411 | 1.62M | // POSIX style root directory. |
412 | 1.62M | if (1.62M !has_net && 1.62M is_separator((*b)[0], style)1.62M ) { |
413 | 228k | return *b; |
414 | 228k | } |
415 | 1.50M | } |
416 | 1.50M | |
417 | 1.50M | // No path or no root. |
418 | 1.50M | return StringRef(); |
419 | 1.50M | } |
420 | | |
421 | 448k | StringRef relative_path(StringRef path, Style style) { |
422 | 448k | StringRef root = root_path(path, style); |
423 | 448k | return path.substr(root.size()); |
424 | 448k | } |
425 | | |
426 | | void append(SmallVectorImpl<char> &path, Style style, const Twine &a, |
427 | 3.59M | const Twine &b, const Twine &c, const Twine &d) { |
428 | 3.59M | SmallString<32> a_storage; |
429 | 3.59M | SmallString<32> b_storage; |
430 | 3.59M | SmallString<32> c_storage; |
431 | 3.59M | SmallString<32> d_storage; |
432 | 3.59M | |
433 | 3.59M | SmallVector<StringRef, 4> components; |
434 | 3.59M | if (!a.isTriviallyEmpty()3.59M ) components.push_back(a.toStringRef(a_storage))3.59M ; |
435 | 3.59M | if (!b.isTriviallyEmpty()3.59M ) components.push_back(b.toStringRef(b_storage))406k ; |
436 | 3.59M | if (!c.isTriviallyEmpty()3.59M ) components.push_back(c.toStringRef(c_storage))361k ; |
437 | 3.59M | if (!d.isTriviallyEmpty()3.59M ) components.push_back(d.toStringRef(d_storage))136k ; |
438 | 3.59M | |
439 | 4.50M | for (auto &component : components) { |
440 | 4.50M | bool path_has_sep = |
441 | 3.69M | !path.empty() && is_separator(path[path.size() - 1], style); |
442 | 4.50M | if (path_has_sep4.50M ) { |
443 | 258k | // Strip separators from beginning of component. |
444 | 258k | size_t loc = component.find_first_not_of(separators(style)); |
445 | 258k | StringRef c = component.substr(loc); |
446 | 258k | |
447 | 258k | // Append it. |
448 | 258k | path.append(c.begin(), c.end()); |
449 | 258k | continue; |
450 | 258k | } |
451 | 4.24M | |
452 | 4.24M | bool component_has_sep = |
453 | 3.84M | !component.empty() && is_separator(component[0], style); |
454 | 4.24M | if (!component_has_sep && |
455 | 4.24M | !(path.empty() || 3.95M has_root_name(component, style)3.35M )) { |
456 | 3.35M | // Add a separator. |
457 | 3.35M | path.push_back(preferred_separator(style)); |
458 | 3.35M | } |
459 | 4.50M | |
460 | 4.50M | path.append(component.begin(), component.end()); |
461 | 4.50M | } |
462 | 3.59M | } |
463 | | |
464 | | void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b, |
465 | 2.91M | const Twine &c, const Twine &d) { |
466 | 2.91M | append(path, Style::native, a, b, c, d); |
467 | 2.91M | } |
468 | | |
469 | | void append(SmallVectorImpl<char> &path, const_iterator begin, |
470 | 38 | const_iterator end, Style style) { |
471 | 329 | for (; begin != end329 ; ++begin291 ) |
472 | 291 | path::append(path, style, *begin); |
473 | 38 | } |
474 | | |
475 | 2.72M | StringRef parent_path(StringRef path, Style style) { |
476 | 2.72M | size_t end_pos = parent_path_end(path, style); |
477 | 2.72M | if (end_pos == StringRef::npos) |
478 | 0 | return StringRef(); |
479 | 2.72M | else |
480 | 2.72M | return path.substr(0, end_pos); |
481 | 0 | } |
482 | | |
483 | 17.4k | void remove_filename(SmallVectorImpl<char> &path, Style style) { |
484 | 17.4k | size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style); |
485 | 17.4k | if (end_pos != StringRef::npos) |
486 | 17.4k | path.set_size(end_pos); |
487 | 17.4k | } |
488 | | |
489 | | void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, |
490 | 22.7k | Style style) { |
491 | 22.7k | StringRef p(path.begin(), path.size()); |
492 | 22.7k | SmallString<32> ext_storage; |
493 | 22.7k | StringRef ext = extension.toStringRef(ext_storage); |
494 | 22.7k | |
495 | 22.7k | // Erase existing extension. |
496 | 22.7k | size_t pos = p.find_last_of('.'); |
497 | 22.7k | if (pos != StringRef::npos && 22.7k pos >= filename_pos(p, style)22.2k ) |
498 | 21.1k | path.set_size(pos); |
499 | 22.7k | |
500 | 22.7k | // Append '.' if needed. |
501 | 22.7k | if (ext.size() > 0 && 22.7k ext[0] != '.'22.0k ) |
502 | 21.4k | path.push_back('.'); |
503 | 22.7k | |
504 | 22.7k | // Append extension. |
505 | 22.7k | path.append(ext.begin(), ext.end()); |
506 | 22.7k | } |
507 | | |
508 | | void replace_path_prefix(SmallVectorImpl<char> &Path, |
509 | | const StringRef &OldPrefix, const StringRef &NewPrefix, |
510 | 18 | Style style) { |
511 | 18 | if (OldPrefix.empty() && 18 NewPrefix.empty()1 ) |
512 | 0 | return; |
513 | 18 | |
514 | 18 | StringRef OrigPath(Path.begin(), Path.size()); |
515 | 18 | if (!OrigPath.startswith(OldPrefix)) |
516 | 3 | return; |
517 | 15 | |
518 | 15 | // If prefixes have the same size we can simply copy the new one over. |
519 | 15 | if (15 OldPrefix.size() == NewPrefix.size()15 ) { |
520 | 2 | std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin()); |
521 | 2 | return; |
522 | 2 | } |
523 | 13 | |
524 | 13 | StringRef RelPath = OrigPath.substr(OldPrefix.size()); |
525 | 13 | SmallString<256> NewPath; |
526 | 13 | path::append(NewPath, style, NewPrefix); |
527 | 13 | path::append(NewPath, style, RelPath); |
528 | 13 | Path.swap(NewPath); |
529 | 13 | } |
530 | | |
531 | 503 | void native(const Twine &path, SmallVectorImpl<char> &result, Style style) { |
532 | 503 | assert((!path.isSingleStringRef() || |
533 | 503 | path.getSingleStringRef().data() != result.data()) && |
534 | 503 | "path and result are not allowed to overlap!"); |
535 | 503 | // Clear result. |
536 | 503 | result.clear(); |
537 | 503 | path.toVector(result); |
538 | 503 | native(result, style); |
539 | 503 | } |
540 | | |
541 | 2.03k | void native(SmallVectorImpl<char> &Path, Style style) { |
542 | 2.03k | if (Path.empty()) |
543 | 1 | return; |
544 | 2.02k | if (2.02k real_style(style) == Style::windows2.02k ) { |
545 | 113 | std::replace(Path.begin(), Path.end(), '/', '\\'); |
546 | 113 | if (Path[0] == '~' && 113 (Path.size() == 1 || 0 is_separator(Path[1], style)0 )) { |
547 | 0 | SmallString<128> PathHome; |
548 | 0 | home_directory(PathHome); |
549 | 0 | PathHome.append(Path.begin() + 1, Path.end()); |
550 | 0 | Path = PathHome; |
551 | 0 | } |
552 | 2.02k | } else { |
553 | 185k | for (auto PI = Path.begin(), PE = Path.end(); PI < PE185k ; ++PI183k ) { |
554 | 183k | if (*PI == '\\'183k ) { |
555 | 20 | auto PN = PI + 1; |
556 | 20 | if (PN < PE && 20 *PN == '\\'16 ) |
557 | 1 | ++PI; // increment once, the for loop will move over the escaped slash |
558 | 20 | else |
559 | 19 | *PI = '/'; |
560 | 20 | } |
561 | 183k | } |
562 | 1.91k | } |
563 | 2.03k | } |
564 | | |
565 | 103 | std::string convert_to_slash(StringRef path, Style style) { |
566 | 103 | if (real_style(style) != Style::windows) |
567 | 103 | return path; |
568 | 0 |
|
569 | 0 | std::string s = path.str(); |
570 | 0 | std::replace(s.begin(), s.end(), '\\', '/'); |
571 | 0 | return s; |
572 | 0 | } |
573 | | |
574 | 1.15M | StringRef filename(StringRef path, Style style) { return *rbegin(path, style); } |
575 | | |
576 | 134k | StringRef stem(StringRef path, Style style) { |
577 | 134k | StringRef fname = filename(path, style); |
578 | 134k | size_t pos = fname.find_last_of('.'); |
579 | 134k | if (pos == StringRef::npos) |
580 | 50.1k | return fname; |
581 | 134k | else |
582 | 84.1k | if (84.1k (fname.size() == 1 && 84.1k fname == "."32 ) || |
583 | 84.0k | (fname.size() == 2 && 84.0k fname == ".."8 )) |
584 | 40 | return fname; |
585 | 84.1k | else |
586 | 84.0k | return fname.substr(0, pos); |
587 | 0 | } |
588 | | |
589 | 519k | StringRef extension(StringRef path, Style style) { |
590 | 519k | StringRef fname = filename(path, style); |
591 | 519k | size_t pos = fname.find_last_of('.'); |
592 | 519k | if (pos == StringRef::npos) |
593 | 361k | return StringRef(); |
594 | 519k | else |
595 | 157k | if (157k (fname.size() == 1 && 157k fname == "."45 ) || |
596 | 157k | (fname.size() == 2 && 157k fname == ".."26 )) |
597 | 71 | return StringRef(); |
598 | 157k | else |
599 | 157k | return fname.substr(pos); |
600 | 0 | } |
601 | | |
602 | 86.5M | bool is_separator(char value, Style style) { |
603 | 86.5M | if (value == '/') |
604 | 30.9M | return true; |
605 | 55.5M | if (55.5M real_style(style) == Style::windows55.5M ) |
606 | 294 | return value == '\\'; |
607 | 55.5M | return false; |
608 | 55.5M | } |
609 | | |
610 | 10.2k | StringRef get_separator(Style style) { |
611 | 10.2k | if (real_style(style) == Style::windows) |
612 | 12 | return "\\"; |
613 | 10.2k | return "/"; |
614 | 10.2k | } |
615 | | |
616 | 3.35M | bool has_root_name(const Twine &path, Style style) { |
617 | 3.35M | SmallString<128> path_storage; |
618 | 3.35M | StringRef p = path.toStringRef(path_storage); |
619 | 3.35M | |
620 | 3.35M | return !root_name(p, style).empty(); |
621 | 3.35M | } |
622 | | |
623 | 1.60M | bool has_root_directory(const Twine &path, Style style) { |
624 | 1.60M | SmallString<128> path_storage; |
625 | 1.60M | StringRef p = path.toStringRef(path_storage); |
626 | 1.60M | |
627 | 1.60M | return !root_directory(p, style).empty(); |
628 | 1.60M | } |
629 | | |
630 | 40 | bool has_root_path(const Twine &path, Style style) { |
631 | 40 | SmallString<128> path_storage; |
632 | 40 | StringRef p = path.toStringRef(path_storage); |
633 | 40 | |
634 | 40 | return !root_path(p, style).empty(); |
635 | 40 | } |
636 | | |
637 | 0 | bool has_relative_path(const Twine &path, Style style) { |
638 | 0 | SmallString<128> path_storage; |
639 | 0 | StringRef p = path.toStringRef(path_storage); |
640 | 0 |
|
641 | 0 | return !relative_path(p, style).empty(); |
642 | 0 | } |
643 | | |
644 | 40 | bool has_filename(const Twine &path, Style style) { |
645 | 40 | SmallString<128> path_storage; |
646 | 40 | StringRef p = path.toStringRef(path_storage); |
647 | 40 | |
648 | 40 | return !filename(p, style).empty(); |
649 | 40 | } |
650 | | |
651 | 1.28k | bool has_parent_path(const Twine &path, Style style) { |
652 | 1.28k | SmallString<128> path_storage; |
653 | 1.28k | StringRef p = path.toStringRef(path_storage); |
654 | 1.28k | |
655 | 1.28k | return !parent_path(p, style).empty(); |
656 | 1.28k | } |
657 | | |
658 | 52 | bool has_stem(const Twine &path, Style style) { |
659 | 52 | SmallString<128> path_storage; |
660 | 52 | StringRef p = path.toStringRef(path_storage); |
661 | 52 | |
662 | 52 | return !stem(p, style).empty(); |
663 | 52 | } |
664 | | |
665 | 414 | bool has_extension(const Twine &path, Style style) { |
666 | 414 | SmallString<128> path_storage; |
667 | 414 | StringRef p = path.toStringRef(path_storage); |
668 | 414 | |
669 | 414 | return !extension(p, style).empty(); |
670 | 414 | } |
671 | | |
672 | 1.45M | bool is_absolute(const Twine &path, Style style) { |
673 | 1.45M | SmallString<128> path_storage; |
674 | 1.45M | StringRef p = path.toStringRef(path_storage); |
675 | 1.45M | |
676 | 1.45M | bool rootDir = has_root_directory(p, style); |
677 | 1.45M | bool rootName = |
678 | 3 | (real_style(style) != Style::windows) || has_root_name(p, style); |
679 | 1.45M | |
680 | 176k | return rootDir && rootName; |
681 | 1.45M | } |
682 | | |
683 | 23.5k | bool is_relative(const Twine &path, Style style) { |
684 | 23.5k | return !is_absolute(path, style); |
685 | 23.5k | } |
686 | | |
687 | 73.2k | StringRef remove_leading_dotslash(StringRef Path, Style style) { |
688 | 73.2k | // Remove leading "./" (or ".//" or "././" etc.) |
689 | 73.2k | while (Path.size() > 2 && 73.2k Path[0] == '.'73.2k && is_separator(Path[1], style)13 ) { |
690 | 13 | Path = Path.substr(2); |
691 | 19 | while (Path.size() > 0 && 19 is_separator(Path[0], style)18 ) |
692 | 6 | Path = Path.substr(1); |
693 | 13 | } |
694 | 73.2k | return Path; |
695 | 73.2k | } |
696 | | |
697 | | static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot, |
698 | 203k | Style style) { |
699 | 203k | SmallVector<StringRef, 16> components; |
700 | 203k | |
701 | 203k | // Skip the root path, then look for traversal in the components. |
702 | 203k | StringRef rel = path::relative_path(path, style); |
703 | 203k | for (StringRef C : |
704 | 712k | llvm::make_range(path::begin(rel, style), path::end(rel))) { |
705 | 712k | if (C == ".") |
706 | 28.2k | continue; |
707 | 684k | // Leading ".." will remain in the path unless it's at the root. |
708 | 684k | if (684k remove_dot_dot && 684k C == ".."430k ) { |
709 | 705 | if (!components.empty() && 705 components.back() != ".."698 ) { |
710 | 696 | components.pop_back(); |
711 | 696 | continue; |
712 | 696 | } |
713 | 9 | if (9 path::is_absolute(path, style)9 ) |
714 | 3 | continue; |
715 | 683k | } |
716 | 683k | components.push_back(C); |
717 | 683k | } |
718 | 203k | |
719 | 203k | SmallString<256> buffer = path::root_path(path, style); |
720 | 203k | for (StringRef C : components) |
721 | 682k | path::append(buffer, style, C); |
722 | 203k | return buffer; |
723 | 203k | } |
724 | | |
725 | | bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot, |
726 | 203k | Style style) { |
727 | 203k | StringRef p(path.data(), path.size()); |
728 | 203k | |
729 | 203k | SmallString<256> result = remove_dots(p, remove_dot_dot, style); |
730 | 203k | if (result == path) |
731 | 175k | return false; |
732 | 28.7k | |
733 | 28.7k | path.swap(result); |
734 | 28.7k | return true; |
735 | 28.7k | } |
736 | | |
737 | | } // end namespace path |
738 | | |
739 | | namespace fs { |
740 | | |
741 | 3.00k | std::error_code getUniqueID(const Twine Path, UniqueID &Result) { |
742 | 3.00k | file_status Status; |
743 | 3.00k | std::error_code EC = status(Path, Status); |
744 | 3.00k | if (EC) |
745 | 0 | return EC; |
746 | 3.00k | Result = Status.getUniqueID(); |
747 | 3.00k | return std::error_code(); |
748 | 3.00k | } |
749 | | |
750 | | std::error_code createUniqueFile(const Twine &Model, int &ResultFd, |
751 | | SmallVectorImpl<char> &ResultPath, |
752 | 27.2k | unsigned Mode) { |
753 | 27.2k | return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); |
754 | 27.2k | } |
755 | | |
756 | | std::error_code createUniqueFile(const Twine &Model, |
757 | 470 | SmallVectorImpl<char> &ResultPath) { |
758 | 470 | int Dummy; |
759 | 470 | return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); |
760 | 470 | } |
761 | | |
762 | | static std::error_code |
763 | | createTemporaryFile(const Twine &Model, int &ResultFD, |
764 | 6.52k | llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { |
765 | 6.52k | SmallString<128> Storage; |
766 | 6.52k | StringRef P = Model.toNullTerminatedStringRef(Storage); |
767 | 6.52k | assert(P.find_first_of(separators(Style::native)) == StringRef::npos && |
768 | 6.52k | "Model must be a simple filename."); |
769 | 6.52k | // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. |
770 | 6.52k | return createUniqueEntity(P.begin(), ResultFD, ResultPath, |
771 | 6.52k | true, owner_read | owner_write, Type); |
772 | 6.52k | } |
773 | | |
774 | | static std::error_code |
775 | | createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, |
776 | 6.52k | llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { |
777 | 6.52k | const char *Middle = Suffix.empty() ? "-%%%%%%"20 : "-%%%%%%."6.50k ; |
778 | 6.52k | return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, |
779 | 6.52k | Type); |
780 | 6.52k | } |
781 | | |
782 | | std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, |
783 | | int &ResultFD, |
784 | 173 | SmallVectorImpl<char> &ResultPath) { |
785 | 173 | return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); |
786 | 173 | } |
787 | | |
788 | | std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, |
789 | 6.35k | SmallVectorImpl<char> &ResultPath) { |
790 | 6.35k | int Dummy; |
791 | 6.35k | return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); |
792 | 6.35k | } |
793 | | |
794 | | |
795 | | // This is a mkdtemp with a different pattern. We use createUniqueEntity mostly |
796 | | // for consistency. We should try using mkdtemp. |
797 | | std::error_code createUniqueDirectory(const Twine &Prefix, |
798 | 33 | SmallVectorImpl<char> &ResultPath) { |
799 | 33 | int Dummy; |
800 | 33 | return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, |
801 | 33 | true, 0, FS_Dir); |
802 | 33 | } |
803 | | |
804 | | static std::error_code make_absolute(const Twine ¤t_directory, |
805 | | SmallVectorImpl<char> &path, |
806 | 152k | bool use_current_directory) { |
807 | 152k | StringRef p(path.data(), path.size()); |
808 | 152k | |
809 | 152k | bool rootDirectory = path::has_root_directory(p); |
810 | 152k | bool rootName = |
811 | 0 | (real_style(Style::native) != Style::windows) || path::has_root_name(p); |
812 | 152k | |
813 | 152k | // Already absolute. |
814 | 152k | if (rootName && 152k rootDirectory152k ) |
815 | 31.1k | return std::error_code(); |
816 | 121k | |
817 | 121k | // All of the following conditions will need the current directory. |
818 | 121k | SmallString<128> current_dir; |
819 | 121k | if (use_current_directory) |
820 | 121k | current_directory.toVector(current_dir); |
821 | 111 | else if (std::error_code 111 ec111 = current_path(current_dir)) |
822 | 0 | return ec; |
823 | 121k | |
824 | 121k | // Relative path. Prepend the current directory. |
825 | 121k | if (121k !rootName && 121k !rootDirectory0 ) { |
826 | 0 | // Append path to the current directory. |
827 | 0 | path::append(current_dir, p); |
828 | 0 | // Set path to the result. |
829 | 0 | path.swap(current_dir); |
830 | 0 | return std::error_code(); |
831 | 0 | } |
832 | 121k | |
833 | 121k | if (121k !rootName && 121k rootDirectory0 ) { |
834 | 0 | StringRef cdrn = path::root_name(current_dir); |
835 | 0 | SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); |
836 | 0 | path::append(curDirRootName, p); |
837 | 0 | // Set path to the result. |
838 | 0 | path.swap(curDirRootName); |
839 | 0 | return std::error_code(); |
840 | 0 | } |
841 | 121k | |
842 | 121k | if (121k rootName && 121k !rootDirectory121k ) { |
843 | 121k | StringRef pRootName = path::root_name(p); |
844 | 121k | StringRef bRootDirectory = path::root_directory(current_dir); |
845 | 121k | StringRef bRelativePath = path::relative_path(current_dir); |
846 | 121k | StringRef pRelativePath = path::relative_path(p); |
847 | 121k | |
848 | 121k | SmallString<128> res; |
849 | 121k | path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); |
850 | 121k | path.swap(res); |
851 | 121k | return std::error_code(); |
852 | 121k | } |
853 | 0 |
|
854 | 0 | llvm_unreachable0 ("All rootName and rootDirectory combinations should have " |
855 | 0 | "occurred above!"); |
856 | 0 | } |
857 | | |
858 | | std::error_code make_absolute(const Twine ¤t_directory, |
859 | 121k | SmallVectorImpl<char> &path) { |
860 | 121k | return make_absolute(current_directory, path, true); |
861 | 121k | } |
862 | | |
863 | 31.2k | std::error_code make_absolute(SmallVectorImpl<char> &path) { |
864 | 31.2k | return make_absolute(Twine(), path, false); |
865 | 31.2k | } |
866 | | |
867 | | std::error_code create_directories(const Twine &Path, bool IgnoreExisting, |
868 | 2.41k | perms Perms) { |
869 | 2.41k | SmallString<128> PathStorage; |
870 | 2.41k | StringRef P = Path.toStringRef(PathStorage); |
871 | 2.41k | |
872 | 2.41k | // Be optimistic and try to create the directory |
873 | 2.41k | std::error_code EC = create_directory(P, IgnoreExisting, Perms); |
874 | 2.41k | // If we succeeded, or had any error other than the parent not existing, just |
875 | 2.41k | // return it. |
876 | 2.41k | if (EC != errc::no_such_file_or_directory) |
877 | 1.80k | return EC; |
878 | 618 | |
879 | 618 | // We failed because of a no_such_file_or_directory, try to create the |
880 | 618 | // parent. |
881 | 618 | StringRef Parent = path::parent_path(P); |
882 | 618 | if (Parent.empty()) |
883 | 0 | return EC; |
884 | 618 | |
885 | 618 | if (618 (EC = create_directories(Parent, IgnoreExisting, Perms))618 ) |
886 | 0 | return EC; |
887 | 618 | |
888 | 618 | return create_directory(P, IgnoreExisting, Perms); |
889 | 618 | } |
890 | | |
891 | 514 | std::error_code copy_file(const Twine &From, const Twine &To) { |
892 | 514 | int ReadFD, WriteFD; |
893 | 514 | if (std::error_code EC = openFileForRead(From, ReadFD)) |
894 | 4 | return EC; |
895 | 510 | if (std::error_code 510 EC510 = openFileForWrite(To, WriteFD, F_None)) { |
896 | 0 | close(ReadFD); |
897 | 0 | return EC; |
898 | 0 | } |
899 | 510 | |
900 | 510 | const size_t BufSize = 4096; |
901 | 510 | char *Buf = new char[BufSize]; |
902 | 510 | int BytesRead = 0, BytesWritten = 0; |
903 | 2.39k | for (;;) { |
904 | 2.39k | BytesRead = read(ReadFD, Buf, BufSize); |
905 | 2.39k | if (BytesRead <= 0) |
906 | 510 | break; |
907 | 3.76k | while (1.88k BytesRead3.76k ) { |
908 | 1.88k | BytesWritten = write(WriteFD, Buf, BytesRead); |
909 | 1.88k | if (BytesWritten < 0) |
910 | 0 | break; |
911 | 1.88k | BytesRead -= BytesWritten; |
912 | 1.88k | } |
913 | 1.88k | if (BytesWritten < 0) |
914 | 0 | break; |
915 | 510 | } |
916 | 510 | close(ReadFD); |
917 | 510 | close(WriteFD); |
918 | 510 | delete[] Buf; |
919 | 510 | |
920 | 510 | if (BytesRead < 0 || 510 BytesWritten < 0510 ) |
921 | 0 | return std::error_code(errno, std::generic_category()); |
922 | 510 | return std::error_code(); |
923 | 510 | } |
924 | | |
925 | 1 | ErrorOr<MD5::MD5Result> md5_contents(int FD) { |
926 | 1 | MD5 Hash; |
927 | 1 | |
928 | 1 | constexpr size_t BufSize = 4096; |
929 | 1 | std::vector<uint8_t> Buf(BufSize); |
930 | 1 | int BytesRead = 0; |
931 | 2 | for (;;) { |
932 | 2 | BytesRead = read(FD, Buf.data(), BufSize); |
933 | 2 | if (BytesRead <= 0) |
934 | 1 | break; |
935 | 1 | Hash.update(makeArrayRef(Buf.data(), BytesRead)); |
936 | 1 | } |
937 | 1 | |
938 | 1 | if (BytesRead < 0) |
939 | 0 | return std::error_code(errno, std::generic_category()); |
940 | 1 | MD5::MD5Result Result; |
941 | 1 | Hash.final(Result); |
942 | 1 | return Result; |
943 | 1 | } |
944 | | |
945 | 0 | ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) { |
946 | 0 | int FD; |
947 | 0 | if (auto EC = openFileForRead(Path, FD)) |
948 | 0 | return EC; |
949 | 0 |
|
950 | 0 | auto Result = md5_contents(FD); |
951 | 0 | close(FD); |
952 | 0 | return Result; |
953 | 0 | } |
954 | | |
955 | 21.1k | bool exists(file_status status) { |
956 | 21.1k | return status_known(status) && status.type() != file_type::file_not_found; |
957 | 21.1k | } |
958 | | |
959 | 21.1k | bool status_known(file_status s) { |
960 | 21.1k | return s.type() != file_type::status_error; |
961 | 21.1k | } |
962 | | |
963 | 0 | file_type get_file_type(const Twine &Path, bool Follow) { |
964 | 0 | file_status st; |
965 | 0 | if (status(Path, st, Follow)) |
966 | 0 | return file_type::status_error; |
967 | 0 | return st.type(); |
968 | 0 | } |
969 | | |
970 | 4.10k | bool is_directory(file_status status) { |
971 | 4.10k | return status.type() == file_type::directory_file; |
972 | 4.10k | } |
973 | | |
974 | 4.31k | std::error_code is_directory(const Twine &path, bool &result) { |
975 | 4.31k | file_status st; |
976 | 4.31k | if (std::error_code ec = status(path, st)) |
977 | 290 | return ec; |
978 | 4.02k | result = is_directory(st); |
979 | 4.02k | return std::error_code(); |
980 | 4.02k | } |
981 | | |
982 | 3.00k | bool is_regular_file(file_status status) { |
983 | 3.00k | return status.type() == file_type::regular_file; |
984 | 3.00k | } |
985 | | |
986 | 2.03k | std::error_code is_regular_file(const Twine &path, bool &result) { |
987 | 2.03k | file_status st; |
988 | 2.03k | if (std::error_code ec = status(path, st)) |
989 | 0 | return ec; |
990 | 2.03k | result = is_regular_file(st); |
991 | 2.03k | return std::error_code(); |
992 | 2.03k | } |
993 | | |
994 | 0 | bool is_symlink_file(file_status status) { |
995 | 0 | return status.type() == file_type::symlink_file; |
996 | 0 | } |
997 | | |
998 | 0 | std::error_code is_symlink_file(const Twine &path, bool &result) { |
999 | 0 | file_status st; |
1000 | 0 | if (std::error_code ec = status(path, st, false)) |
1001 | 0 | return ec; |
1002 | 0 | result = is_symlink_file(st); |
1003 | 0 | return std::error_code(); |
1004 | 0 | } |
1005 | | |
1006 | 0 | bool is_other(file_status status) { |
1007 | 0 | return exists(status) && |
1008 | 0 | !is_regular_file(status) && |
1009 | 0 | !is_directory(status); |
1010 | 0 | } |
1011 | | |
1012 | 0 | std::error_code is_other(const Twine &Path, bool &Result) { |
1013 | 0 | file_status FileStatus; |
1014 | 0 | if (std::error_code EC = status(Path, FileStatus)) |
1015 | 0 | return EC; |
1016 | 0 | Result = is_other(FileStatus); |
1017 | 0 | return std::error_code(); |
1018 | 0 | } |
1019 | | |
1020 | 8.94k | void directory_entry::replace_filename(const Twine &filename, file_status st) { |
1021 | 8.94k | SmallString<128> path = path::parent_path(Path); |
1022 | 8.94k | path::append(path, filename); |
1023 | 8.94k | Path = path.str(); |
1024 | 8.94k | Status = st; |
1025 | 8.94k | } |
1026 | | |
1027 | 6.29k | std::error_code directory_entry::status(file_status &result) const { |
1028 | 6.29k | return fs::status(Path, result, FollowSymlinks); |
1029 | 6.29k | } |
1030 | | |
1031 | 25 | ErrorOr<perms> getPermissions(const Twine &Path) { |
1032 | 25 | file_status Status; |
1033 | 25 | if (std::error_code EC = status(Path, Status)) |
1034 | 0 | return EC; |
1035 | 25 | |
1036 | 25 | return Status.permissions(); |
1037 | 25 | } |
1038 | | |
1039 | | } // end namespace fs |
1040 | | } // end namespace sys |
1041 | | } // end namespace llvm |
1042 | | |
1043 | | // Include the truly platform-specific parts. |
1044 | | #if defined(LLVM_ON_UNIX) |
1045 | | #include "Unix/Path.inc" |
1046 | | #endif |
1047 | | #if defined(LLVM_ON_WIN32) |
1048 | | #include "Windows/Path.inc" |
1049 | | #endif |
1050 | | |
1051 | | namespace llvm { |
1052 | | namespace sys { |
1053 | | namespace path { |
1054 | | |
1055 | | bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1, |
1056 | 4 | const Twine &Path2, const Twine &Path3) { |
1057 | 4 | if (getUserCacheDir(Result)4 ) { |
1058 | 4 | append(Result, Path1, Path2, Path3); |
1059 | 4 | return true; |
1060 | 4 | } |
1061 | 0 | return false; |
1062 | 0 | } |
1063 | | |
1064 | | } // end namespace path |
1065 | | } // end namsspace sys |
1066 | | } // end namespace llvm |