/src/keystone/llvm/lib/Support/Path.cpp
Line | Count | Source |
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/COFF.h" |
15 | | #include "llvm/Support/MachO.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/Path.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_ks; |
31 | | using namespace llvm_ks::support::endian; |
32 | | |
33 | | namespace { |
34 | | using llvm_ks::StringRef; |
35 | | using llvm_ks::sys::path::is_separator; |
36 | | |
37 | | #ifdef LLVM_ON_WIN32 |
38 | | const char *separators = "\\/"; |
39 | | const char preferred_separator = '\\'; |
40 | | #else |
41 | | const char separators = '/'; |
42 | | const char preferred_separator = '/'; |
43 | | #endif |
44 | | |
45 | 117k | StringRef find_first_component(StringRef path) { |
46 | | // Look for this first component in the following order. |
47 | | // * empty (in this case we return an empty string) |
48 | | // * either C: or {//,\\}net. |
49 | | // * {/,\} |
50 | | // * {file,directory}name |
51 | | |
52 | 117k | if (path.empty()) |
53 | 0 | return path; |
54 | | |
55 | | #ifdef LLVM_ON_WIN32 |
56 | | // C: |
57 | | if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) && |
58 | | path[1] == ':') |
59 | | return path.substr(0, 2); |
60 | | #endif |
61 | | |
62 | | // //net |
63 | 117k | if ((path.size() > 2) && |
64 | 117k | is_separator(path[0]) && |
65 | 117k | path[0] == path[1] && |
66 | 0 | !is_separator(path[2])) { |
67 | | // Find the next directory separator. |
68 | 0 | size_t end = path.find_first_of(separators, 2); |
69 | 0 | return path.substr(0, end); |
70 | 0 | } |
71 | | |
72 | | // {/,\} |
73 | 117k | if (is_separator(path[0])) |
74 | 117k | return path.substr(0, 1); |
75 | | |
76 | | // * {file,directory}name |
77 | 0 | size_t end = path.find_first_of(separators); |
78 | 0 | return path.substr(0, end); |
79 | 117k | } |
80 | | |
81 | 0 | size_t filename_pos(StringRef str) { |
82 | 0 | if (str.size() == 2 && |
83 | 0 | is_separator(str[0]) && |
84 | 0 | str[0] == str[1]) |
85 | 0 | return 0; |
86 | | |
87 | 0 | if (str.size() > 0 && is_separator(str[str.size() - 1])) |
88 | 0 | return str.size() - 1; |
89 | | |
90 | 0 | size_t pos = str.find_last_of(separators, str.size() - 1); |
91 | |
|
92 | | #ifdef LLVM_ON_WIN32 |
93 | | if (pos == StringRef::npos) |
94 | | pos = str.find_last_of(':', str.size() - 2); |
95 | | #endif |
96 | |
|
97 | 0 | if (pos == StringRef::npos || |
98 | 0 | (pos == 1 && is_separator(str[0]))) |
99 | 0 | return 0; |
100 | | |
101 | 0 | return pos + 1; |
102 | 0 | } |
103 | | |
104 | 0 | size_t root_dir_start(StringRef str) { |
105 | | // case "c:/" |
106 | | #ifdef LLVM_ON_WIN32 |
107 | | if (str.size() > 2 && |
108 | | str[1] == ':' && |
109 | | is_separator(str[2])) |
110 | | return 2; |
111 | | #endif |
112 | | |
113 | | // case "//" |
114 | 0 | if (str.size() == 2 && |
115 | 0 | is_separator(str[0]) && |
116 | 0 | str[0] == str[1]) |
117 | 0 | return StringRef::npos; |
118 | | |
119 | | // case "//net" |
120 | 0 | if (str.size() > 3 && |
121 | 0 | is_separator(str[0]) && |
122 | 0 | str[0] == str[1] && |
123 | 0 | !is_separator(str[2])) { |
124 | 0 | return str.find_first_of(separators, 2); |
125 | 0 | } |
126 | | |
127 | | // case "/" |
128 | 0 | if (str.size() > 0 && is_separator(str[0])) |
129 | 0 | return 0; |
130 | | |
131 | 0 | return StringRef::npos; |
132 | 0 | } |
133 | | |
134 | 0 | size_t parent_path_end(StringRef path) { |
135 | 0 | size_t end_pos = filename_pos(path); |
136 | |
|
137 | 0 | bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); |
138 | | |
139 | | // Skip separators except for root dir. |
140 | 0 | size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); |
141 | |
|
142 | 0 | while(end_pos > 0 && |
143 | 0 | (end_pos - 1) != root_dir_pos && |
144 | 0 | is_separator(path[end_pos - 1])) |
145 | 0 | --end_pos; |
146 | |
|
147 | 0 | if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) |
148 | 0 | return StringRef::npos; |
149 | | |
150 | 0 | return end_pos; |
151 | 0 | } |
152 | | } // end unnamed namespace |
153 | | |
154 | | enum FSEntity { |
155 | | FS_Dir, |
156 | | FS_File, |
157 | | FS_Name |
158 | | }; |
159 | | |
160 | | static std::error_code createUniqueEntity(const Twine &Model, int &ResultFD, |
161 | | SmallVectorImpl<char> &ResultPath, |
162 | | bool MakeAbsolute, unsigned Mode, |
163 | 0 | FSEntity Type) { |
164 | 0 | SmallString<128> ModelStorage; |
165 | 0 | Model.toVector(ModelStorage); |
166 | |
|
167 | 0 | if (MakeAbsolute) { |
168 | | // Make model absolute by prepending a temp directory if it's not already. |
169 | 0 | if (!sys::path::is_absolute(Twine(ModelStorage))) { |
170 | 0 | SmallString<128> TDir; |
171 | 0 | sys::path::system_temp_directory(true, TDir); |
172 | 0 | sys::path::append(TDir, Twine(ModelStorage)); |
173 | 0 | ModelStorage.swap(TDir); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | // From here on, DO NOT modify model. It may be needed if the randomly chosen |
178 | | // path already exists. |
179 | 0 | ResultPath = ModelStorage; |
180 | | // Null terminate. |
181 | 0 | ResultPath.push_back(0); |
182 | 0 | ResultPath.pop_back(); |
183 | |
|
184 | 0 | retry_random_path: |
185 | | // Replace '%' with random chars. |
186 | 0 | for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { |
187 | 0 | if (ModelStorage[i] == '%') |
188 | 0 | ResultPath[i] = "0123456789abcdef"[8888 & 15]; |
189 | 0 | } |
190 | | |
191 | | // Try to open + create the file. |
192 | 0 | switch (Type) { |
193 | 0 | case FS_File: { |
194 | 0 | if (std::error_code EC = |
195 | 0 | sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD, |
196 | 0 | sys::fs::F_RW | sys::fs::F_Excl, Mode)) { |
197 | 0 | if (EC == errc::file_exists) |
198 | 0 | goto retry_random_path; |
199 | 0 | return EC; |
200 | 0 | } |
201 | | |
202 | 0 | return std::error_code(); |
203 | 0 | } |
204 | | |
205 | 0 | case FS_Name: { |
206 | 0 | std::error_code EC = |
207 | 0 | sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist); |
208 | 0 | if (EC == errc::no_such_file_or_directory) |
209 | 0 | return std::error_code(); |
210 | 0 | if (EC) |
211 | 0 | return EC; |
212 | 0 | goto retry_random_path; |
213 | 0 | } |
214 | | |
215 | 0 | case FS_Dir: { |
216 | 0 | if (std::error_code EC = |
217 | 0 | sys::fs::create_directory(ResultPath.begin(), false)) { |
218 | 0 | if (EC == errc::file_exists) |
219 | 0 | goto retry_random_path; |
220 | 0 | return EC; |
221 | 0 | } |
222 | 0 | return std::error_code(); |
223 | 0 | } |
224 | 0 | } |
225 | 0 | llvm_unreachable("Invalid Type"); |
226 | 0 | } |
227 | | |
228 | | namespace llvm_ks { |
229 | | namespace sys { |
230 | | namespace path { |
231 | | |
232 | 117k | const_iterator begin(StringRef path) { |
233 | 117k | const_iterator i; |
234 | 117k | i.Path = path; |
235 | 117k | i.Component = find_first_component(path); |
236 | 117k | i.Position = 0; |
237 | 117k | return i; |
238 | 117k | } |
239 | | |
240 | 117k | const_iterator end(StringRef path) { |
241 | 117k | const_iterator i; |
242 | 117k | i.Path = path; |
243 | 117k | i.Position = path.size(); |
244 | 117k | return i; |
245 | 117k | } |
246 | | |
247 | 0 | const_iterator &const_iterator::operator++() { |
248 | 0 | assert(Position < Path.size() && "Tried to increment past end!"); |
249 | | |
250 | | // Increment Position to past the current component |
251 | 0 | Position += Component.size(); |
252 | | |
253 | | // Check for end. |
254 | 0 | if (Position == Path.size()) { |
255 | 0 | Component = StringRef(); |
256 | 0 | return *this; |
257 | 0 | } |
258 | | |
259 | | // Both POSIX and Windows treat paths that begin with exactly two separators |
260 | | // specially. |
261 | 0 | bool was_net = Component.size() > 2 && |
262 | 0 | is_separator(Component[0]) && |
263 | 0 | Component[1] == Component[0] && |
264 | 0 | !is_separator(Component[2]); |
265 | | |
266 | | // Handle separators. |
267 | 0 | if (is_separator(Path[Position])) { |
268 | | // Root dir. |
269 | 0 | if (was_net |
270 | | #ifdef LLVM_ON_WIN32 |
271 | | // c:/ |
272 | | || Component.endswith(":") |
273 | | #endif |
274 | 0 | ) { |
275 | 0 | Component = Path.substr(Position, 1); |
276 | 0 | return *this; |
277 | 0 | } |
278 | | |
279 | | // Skip extra separators. |
280 | 0 | while (Position != Path.size() && |
281 | 0 | is_separator(Path[Position])) { |
282 | 0 | ++Position; |
283 | 0 | } |
284 | | |
285 | | // Treat trailing '/' as a '.'. |
286 | 0 | if (Position == Path.size()) { |
287 | 0 | --Position; |
288 | 0 | Component = "."; |
289 | 0 | return *this; |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | | // Find next component. |
294 | 0 | size_t end_pos = Path.find_first_of(separators, Position); |
295 | 0 | Component = Path.slice(Position, end_pos); |
296 | |
|
297 | 0 | return *this; |
298 | 0 | } |
299 | | |
300 | 117k | bool const_iterator::operator==(const const_iterator &RHS) const { |
301 | 117k | return Path.begin() == RHS.Path.begin() && Position == RHS.Position; |
302 | 117k | } |
303 | | |
304 | 0 | ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { |
305 | 0 | return Position - RHS.Position; |
306 | 0 | } |
307 | | |
308 | 0 | reverse_iterator rbegin(StringRef Path) { |
309 | 0 | reverse_iterator I; |
310 | 0 | I.Path = Path; |
311 | 0 | I.Position = Path.size(); |
312 | 0 | return ++I; |
313 | 0 | } |
314 | | |
315 | 0 | reverse_iterator rend(StringRef Path) { |
316 | 0 | reverse_iterator I; |
317 | 0 | I.Path = Path; |
318 | 0 | I.Component = Path.substr(0, 0); |
319 | 0 | I.Position = 0; |
320 | 0 | return I; |
321 | 0 | } |
322 | | |
323 | 0 | reverse_iterator &reverse_iterator::operator++() { |
324 | | // If we're at the end and the previous char was a '/', return '.' unless |
325 | | // we are the root path. |
326 | 0 | size_t root_dir_pos = root_dir_start(Path); |
327 | 0 | if (Position == Path.size() && |
328 | 0 | Path.size() > root_dir_pos + 1 && |
329 | 0 | is_separator(Path[Position - 1])) { |
330 | 0 | --Position; |
331 | 0 | Component = "."; |
332 | 0 | return *this; |
333 | 0 | } |
334 | | |
335 | | // Skip separators unless it's the root directory. |
336 | 0 | size_t end_pos = Position; |
337 | |
|
338 | 0 | while(end_pos > 0 && |
339 | 0 | (end_pos - 1) != root_dir_pos && |
340 | 0 | is_separator(Path[end_pos - 1])) |
341 | 0 | --end_pos; |
342 | | |
343 | | // Find next separator. |
344 | 0 | size_t start_pos = filename_pos(Path.substr(0, end_pos)); |
345 | 0 | Component = Path.slice(start_pos, end_pos); |
346 | 0 | Position = start_pos; |
347 | 0 | return *this; |
348 | 0 | } |
349 | | |
350 | 0 | bool reverse_iterator::operator==(const reverse_iterator &RHS) const { |
351 | 0 | return Path.begin() == RHS.Path.begin() && Component == RHS.Component && |
352 | 0 | Position == RHS.Position; |
353 | 0 | } |
354 | | |
355 | 0 | StringRef root_path(StringRef path) { |
356 | 0 | const_iterator b = begin(path), |
357 | 0 | pos = b, |
358 | 0 | e = end(path); |
359 | 0 | if (b != e) { |
360 | 0 | bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; |
361 | 0 | bool has_drive = |
362 | | #ifdef LLVM_ON_WIN32 |
363 | | b->endswith(":"); |
364 | | #else |
365 | 0 | false; |
366 | 0 | #endif |
367 | |
|
368 | 0 | if (has_net || has_drive) { |
369 | 0 | if ((++pos != e) && is_separator((*pos)[0])) { |
370 | | // {C:/,//net/}, so get the first two components. |
371 | 0 | return path.substr(0, b->size() + pos->size()); |
372 | 0 | } else { |
373 | | // just {C:,//net}, return the first component. |
374 | 0 | return *b; |
375 | 0 | } |
376 | 0 | } |
377 | | |
378 | | // POSIX style root directory. |
379 | 0 | if (is_separator((*b)[0])) { |
380 | 0 | return *b; |
381 | 0 | } |
382 | 0 | } |
383 | | |
384 | 0 | return StringRef(); |
385 | 0 | } |
386 | | |
387 | 0 | StringRef root_name(StringRef path) { |
388 | 0 | const_iterator b = begin(path), |
389 | 0 | e = end(path); |
390 | 0 | if (b != e) { |
391 | 0 | bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; |
392 | 0 | bool has_drive = |
393 | | #ifdef LLVM_ON_WIN32 |
394 | | b->endswith(":"); |
395 | | #else |
396 | 0 | false; |
397 | 0 | #endif |
398 | |
|
399 | 0 | if (has_net || has_drive) { |
400 | | // just {C:,//net}, return the first component. |
401 | 0 | return *b; |
402 | 0 | } |
403 | 0 | } |
404 | | |
405 | | // No path or no name. |
406 | 0 | return StringRef(); |
407 | 0 | } |
408 | | |
409 | 117k | StringRef root_directory(StringRef path) { |
410 | 117k | const_iterator b = begin(path), |
411 | 117k | pos = b, |
412 | 117k | e = end(path); |
413 | 117k | if (b != e) { |
414 | 117k | bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; |
415 | 117k | bool has_drive = |
416 | | #ifdef LLVM_ON_WIN32 |
417 | | b->endswith(":"); |
418 | | #else |
419 | 117k | false; |
420 | 117k | #endif |
421 | | |
422 | 117k | if ((has_net || has_drive) && |
423 | | // {C:,//net}, skip to the next component. |
424 | 0 | (++pos != e) && is_separator((*pos)[0])) { |
425 | 0 | return *pos; |
426 | 0 | } |
427 | | |
428 | | // POSIX style root directory. |
429 | 117k | if (!has_net && is_separator((*b)[0])) { |
430 | 117k | return *b; |
431 | 117k | } |
432 | 117k | } |
433 | | |
434 | | // No path or no root. |
435 | 0 | return StringRef(); |
436 | 117k | } |
437 | | |
438 | 0 | StringRef relative_path(StringRef path) { |
439 | 0 | StringRef root = root_path(path); |
440 | 0 | return path.substr(root.size()); |
441 | 0 | } |
442 | | |
443 | | void append(SmallVectorImpl<char> &path, const Twine &a, |
444 | | const Twine &b, |
445 | | const Twine &c, |
446 | 0 | const Twine &d) { |
447 | 0 | SmallString<32> a_storage; |
448 | 0 | SmallString<32> b_storage; |
449 | 0 | SmallString<32> c_storage; |
450 | 0 | SmallString<32> d_storage; |
451 | |
|
452 | 0 | SmallVector<StringRef, 4> components; |
453 | 0 | if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); |
454 | 0 | if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); |
455 | 0 | if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); |
456 | 0 | if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); |
457 | |
|
458 | 0 | for (auto &component : components) { |
459 | 0 | bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); |
460 | 0 | bool component_has_sep = !component.empty() && is_separator(component[0]); |
461 | 0 | bool is_root_name = has_root_name(component); |
462 | |
|
463 | 0 | if (path_has_sep) { |
464 | | // Strip separators from beginning of component. |
465 | 0 | size_t loc = component.find_first_not_of(separators); |
466 | 0 | StringRef c = component.substr(loc); |
467 | | |
468 | | // Append it. |
469 | 0 | path.append(c.begin(), c.end()); |
470 | 0 | continue; |
471 | 0 | } |
472 | | |
473 | 0 | if (!component_has_sep && !(path.empty() || is_root_name)) { |
474 | | // Add a separator. |
475 | 0 | path.push_back(preferred_separator); |
476 | 0 | } |
477 | |
|
478 | 0 | path.append(component.begin(), component.end()); |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | void append(SmallVectorImpl<char> &path, |
483 | 0 | const_iterator begin, const_iterator end) { |
484 | 0 | for (; begin != end; ++begin) |
485 | 0 | path::append(path, *begin); |
486 | 0 | } |
487 | | |
488 | 0 | StringRef parent_path(StringRef path) { |
489 | 0 | size_t end_pos = parent_path_end(path); |
490 | 0 | if (end_pos == StringRef::npos) |
491 | 0 | return StringRef(); |
492 | 0 | else |
493 | 0 | return path.substr(0, end_pos); |
494 | 0 | } |
495 | | |
496 | 0 | void remove_filename(SmallVectorImpl<char> &path) { |
497 | 0 | size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); |
498 | 0 | if (end_pos != StringRef::npos) |
499 | 0 | path.set_size(end_pos); |
500 | 0 | } |
501 | | |
502 | 0 | void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { |
503 | 0 | StringRef p(path.begin(), path.size()); |
504 | 0 | SmallString<32> ext_storage; |
505 | 0 | StringRef ext = extension.toStringRef(ext_storage); |
506 | | |
507 | | // Erase existing extension. |
508 | 0 | size_t pos = p.find_last_of('.'); |
509 | 0 | if (pos != StringRef::npos && pos >= filename_pos(p)) |
510 | 0 | path.set_size(pos); |
511 | | |
512 | | // Append '.' if needed. |
513 | 0 | if (ext.size() > 0 && ext[0] != '.') |
514 | 0 | path.push_back('.'); |
515 | | |
516 | | // Append extension. |
517 | 0 | path.append(ext.begin(), ext.end()); |
518 | 0 | } |
519 | | |
520 | 0 | void native(const Twine &path, SmallVectorImpl<char> &result) { |
521 | 0 | assert((!path.isSingleStringRef() || |
522 | 0 | path.getSingleStringRef().data() != result.data()) && |
523 | 0 | "path and result are not allowed to overlap!"); |
524 | | // Clear result. |
525 | 0 | result.clear(); |
526 | 0 | path.toVector(result); |
527 | 0 | native(result); |
528 | 0 | } |
529 | | |
530 | 0 | void native(SmallVectorImpl<char> &Path) { |
531 | | #ifdef LLVM_ON_WIN32 |
532 | | std::replace(Path.begin(), Path.end(), '/', '\\'); |
533 | | #else |
534 | 0 | for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) { |
535 | 0 | if (*PI == '\\') { |
536 | 0 | auto PN = PI + 1; |
537 | 0 | if (PN < PE && *PN == '\\') |
538 | 0 | ++PI; // increment once, the for loop will move over the escaped slash |
539 | 0 | else |
540 | 0 | *PI = '/'; |
541 | 0 | } |
542 | 0 | } |
543 | 0 | #endif |
544 | 0 | } |
545 | | |
546 | 0 | StringRef filename(StringRef path) { |
547 | 0 | return *rbegin(path); |
548 | 0 | } |
549 | | |
550 | 0 | StringRef stem(StringRef path) { |
551 | 0 | StringRef fname = filename(path); |
552 | 0 | size_t pos = fname.find_last_of('.'); |
553 | 0 | if (pos == StringRef::npos) |
554 | 0 | return fname; |
555 | 0 | else |
556 | 0 | if ((fname.size() == 1 && fname == ".") || |
557 | 0 | (fname.size() == 2 && fname == "..")) |
558 | 0 | return fname; |
559 | 0 | else |
560 | 0 | return fname.substr(0, pos); |
561 | 0 | } |
562 | | |
563 | 0 | StringRef extension(StringRef path) { |
564 | 0 | StringRef fname = filename(path); |
565 | 0 | size_t pos = fname.find_last_of('.'); |
566 | 0 | if (pos == StringRef::npos) |
567 | 0 | return StringRef(); |
568 | 0 | else |
569 | 0 | if ((fname.size() == 1 && fname == ".") || |
570 | 0 | (fname.size() == 2 && fname == "..")) |
571 | 0 | return StringRef(); |
572 | 0 | else |
573 | 0 | return fname.substr(pos); |
574 | 0 | } |
575 | | |
576 | 351k | bool is_separator(char value) { |
577 | 351k | switch(value) { |
578 | | #ifdef LLVM_ON_WIN32 |
579 | | case '\\': // fall through |
580 | | #endif |
581 | 351k | case '/': return true; |
582 | 0 | default: return false; |
583 | 351k | } |
584 | 351k | } |
585 | | |
586 | | static const char preferred_separator_string[] = { preferred_separator, '\0' }; |
587 | | |
588 | 0 | StringRef get_separator() { |
589 | 0 | return preferred_separator_string; |
590 | 0 | } |
591 | | |
592 | 0 | bool has_root_name(const Twine &path) { |
593 | 0 | SmallString<128> path_storage; |
594 | 0 | StringRef p = path.toStringRef(path_storage); |
595 | |
|
596 | 0 | return !root_name(p).empty(); |
597 | 0 | } |
598 | | |
599 | 117k | bool has_root_directory(const Twine &path) { |
600 | 117k | SmallString<128> path_storage; |
601 | 117k | StringRef p = path.toStringRef(path_storage); |
602 | | |
603 | 117k | return !root_directory(p).empty(); |
604 | 117k | } |
605 | | |
606 | 0 | bool has_root_path(const Twine &path) { |
607 | 0 | SmallString<128> path_storage; |
608 | 0 | StringRef p = path.toStringRef(path_storage); |
609 | |
|
610 | 0 | return !root_path(p).empty(); |
611 | 0 | } |
612 | | |
613 | 0 | bool has_relative_path(const Twine &path) { |
614 | 0 | SmallString<128> path_storage; |
615 | 0 | StringRef p = path.toStringRef(path_storage); |
616 | |
|
617 | 0 | return !relative_path(p).empty(); |
618 | 0 | } |
619 | | |
620 | 0 | bool has_filename(const Twine &path) { |
621 | 0 | SmallString<128> path_storage; |
622 | 0 | StringRef p = path.toStringRef(path_storage); |
623 | |
|
624 | 0 | return !filename(p).empty(); |
625 | 0 | } |
626 | | |
627 | 0 | bool has_parent_path(const Twine &path) { |
628 | 0 | SmallString<128> path_storage; |
629 | 0 | StringRef p = path.toStringRef(path_storage); |
630 | |
|
631 | 0 | return !parent_path(p).empty(); |
632 | 0 | } |
633 | | |
634 | 0 | bool has_stem(const Twine &path) { |
635 | 0 | SmallString<128> path_storage; |
636 | 0 | StringRef p = path.toStringRef(path_storage); |
637 | |
|
638 | 0 | return !stem(p).empty(); |
639 | 0 | } |
640 | | |
641 | 0 | bool has_extension(const Twine &path) { |
642 | 0 | SmallString<128> path_storage; |
643 | 0 | StringRef p = path.toStringRef(path_storage); |
644 | |
|
645 | 0 | return !extension(p).empty(); |
646 | 0 | } |
647 | | |
648 | 117k | bool is_absolute(const Twine &path) { |
649 | 117k | SmallString<128> path_storage; |
650 | 117k | StringRef p = path.toStringRef(path_storage); |
651 | | |
652 | 117k | bool rootDir = has_root_directory(p), |
653 | | #ifdef LLVM_ON_WIN32 |
654 | | rootName = has_root_name(p); |
655 | | #else |
656 | 117k | rootName = true; |
657 | 117k | #endif |
658 | | |
659 | 117k | return rootDir && rootName; |
660 | 117k | } |
661 | | |
662 | 0 | bool is_relative(const Twine &path) { return !is_absolute(path); } |
663 | | |
664 | 0 | StringRef remove_leading_dotslash(StringRef Path) { |
665 | | // Remove leading "./" (or ".//" or "././" etc.) |
666 | 0 | while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) { |
667 | 0 | Path = Path.substr(2); |
668 | 0 | while (Path.size() > 0 && is_separator(Path[0])) |
669 | 0 | Path = Path.substr(1); |
670 | 0 | } |
671 | 0 | return Path; |
672 | 0 | } |
673 | | |
674 | 0 | static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) { |
675 | 0 | SmallVector<StringRef, 16> components; |
676 | | |
677 | | // Skip the root path, then look for traversal in the components. |
678 | 0 | StringRef rel = path::relative_path(path); |
679 | 0 | for (StringRef C : llvm_ks::make_range(path::begin(rel), path::end(rel))) { |
680 | 0 | if (C == ".") |
681 | 0 | continue; |
682 | 0 | if (remove_dot_dot) { |
683 | 0 | if (C == "..") { |
684 | 0 | if (!components.empty()) |
685 | 0 | components.pop_back(); |
686 | 0 | continue; |
687 | 0 | } |
688 | 0 | } |
689 | 0 | components.push_back(C); |
690 | 0 | } |
691 | |
|
692 | 0 | SmallString<256> buffer = path::root_path(path); |
693 | 0 | for (StringRef C : components) |
694 | 0 | path::append(buffer, C); |
695 | 0 | return buffer; |
696 | 0 | } |
697 | | |
698 | 0 | bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) { |
699 | 0 | StringRef p(path.data(), path.size()); |
700 | |
|
701 | 0 | SmallString<256> result = remove_dots(p, remove_dot_dot); |
702 | 0 | if (result == path) |
703 | 0 | return false; |
704 | | |
705 | 0 | path.swap(result); |
706 | 0 | return true; |
707 | 0 | } |
708 | | |
709 | | } // end namespace path |
710 | | |
711 | | namespace fs { |
712 | | |
713 | 0 | std::error_code getUniqueID(const Twine Path, UniqueID &Result) { |
714 | 0 | file_status Status; |
715 | 0 | std::error_code EC = status(Path, Status); |
716 | 0 | if (EC) |
717 | 0 | return EC; |
718 | 0 | Result = Status.getUniqueID(); |
719 | 0 | return std::error_code(); |
720 | 0 | } |
721 | | |
722 | | std::error_code createUniqueFile(const Twine &Model, int &ResultFd, |
723 | | SmallVectorImpl<char> &ResultPath, |
724 | 0 | unsigned Mode) { |
725 | 0 | return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); |
726 | 0 | } |
727 | | |
728 | | std::error_code createUniqueFile(const Twine &Model, |
729 | 0 | SmallVectorImpl<char> &ResultPath) { |
730 | 0 | int Dummy; |
731 | 0 | return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); |
732 | 0 | } |
733 | | |
734 | | static std::error_code |
735 | | createTemporaryFile(const Twine &Model, int &ResultFD, |
736 | 0 | llvm_ks::SmallVectorImpl<char> &ResultPath, FSEntity Type) { |
737 | 0 | SmallString<128> Storage; |
738 | 0 | StringRef P = Model.toNullTerminatedStringRef(Storage); |
739 | 0 | assert(P.find_first_of(separators) == StringRef::npos && |
740 | 0 | "Model must be a simple filename."); |
741 | | // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. |
742 | 0 | return createUniqueEntity(P.begin(), ResultFD, ResultPath, |
743 | 0 | true, owner_read | owner_write, Type); |
744 | 0 | } |
745 | | |
746 | | static std::error_code |
747 | | createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, |
748 | 0 | llvm_ks::SmallVectorImpl<char> &ResultPath, FSEntity Type) { |
749 | 0 | const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%."; |
750 | 0 | return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, |
751 | 0 | Type); |
752 | 0 | } |
753 | | |
754 | | std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, |
755 | | int &ResultFD, |
756 | 0 | SmallVectorImpl<char> &ResultPath) { |
757 | 0 | return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); |
758 | 0 | } |
759 | | |
760 | | std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, |
761 | 0 | SmallVectorImpl<char> &ResultPath) { |
762 | 0 | int Dummy; |
763 | 0 | return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); |
764 | 0 | } |
765 | | |
766 | | |
767 | | // This is a mkdtemp with a different pattern. We use createUniqueEntity mostly |
768 | | // for consistency. We should try using mkdtemp. |
769 | | std::error_code createUniqueDirectory(const Twine &Prefix, |
770 | 0 | SmallVectorImpl<char> &ResultPath) { |
771 | 0 | int Dummy; |
772 | 0 | return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, |
773 | 0 | true, 0, FS_Dir); |
774 | 0 | } |
775 | | |
776 | | static std::error_code make_absolute(const Twine ¤t_directory, |
777 | | SmallVectorImpl<char> &path, |
778 | 0 | bool use_current_directory) { |
779 | 0 | StringRef p(path.data(), path.size()); |
780 | |
|
781 | 0 | bool rootDirectory = path::has_root_directory(p), |
782 | | #ifdef LLVM_ON_WIN32 |
783 | | rootName = path::has_root_name(p); |
784 | | #else |
785 | 0 | rootName = true; |
786 | 0 | #endif |
787 | | |
788 | | // Already absolute. |
789 | 0 | if (rootName && rootDirectory) |
790 | 0 | return std::error_code(); |
791 | | |
792 | | // All of the following conditions will need the current directory. |
793 | 0 | SmallString<128> current_dir; |
794 | 0 | if (use_current_directory) |
795 | 0 | current_directory.toVector(current_dir); |
796 | 0 | else if (std::error_code ec = current_path(current_dir)) |
797 | 0 | return ec; |
798 | | |
799 | | // Relative path. Prepend the current directory. |
800 | 0 | if (!rootName && !rootDirectory) { |
801 | | // Append path to the current directory. |
802 | 0 | path::append(current_dir, p); |
803 | | // Set path to the result. |
804 | 0 | path.swap(current_dir); |
805 | 0 | return std::error_code(); |
806 | 0 | } |
807 | | |
808 | 0 | if (!rootName && rootDirectory) { |
809 | 0 | StringRef cdrn = path::root_name(current_dir); |
810 | 0 | SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); |
811 | 0 | path::append(curDirRootName, p); |
812 | | // Set path to the result. |
813 | 0 | path.swap(curDirRootName); |
814 | 0 | return std::error_code(); |
815 | 0 | } |
816 | | |
817 | 0 | if (rootName && !rootDirectory) { |
818 | 0 | StringRef pRootName = path::root_name(p); |
819 | 0 | StringRef bRootDirectory = path::root_directory(current_dir); |
820 | 0 | StringRef bRelativePath = path::relative_path(current_dir); |
821 | 0 | StringRef pRelativePath = path::relative_path(p); |
822 | |
|
823 | 0 | SmallString<128> res; |
824 | 0 | path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); |
825 | 0 | path.swap(res); |
826 | 0 | return std::error_code(); |
827 | 0 | } |
828 | | |
829 | 0 | llvm_unreachable("All rootName and rootDirectory combinations should have " |
830 | 0 | "occurred above!"); |
831 | 0 | } |
832 | | |
833 | | std::error_code make_absolute(const Twine ¤t_directory, |
834 | 0 | SmallVectorImpl<char> &path) { |
835 | 0 | return make_absolute(current_directory, path, true); |
836 | 0 | } |
837 | | |
838 | 0 | std::error_code make_absolute(SmallVectorImpl<char> &path) { |
839 | 0 | return make_absolute(Twine(), path, false); |
840 | 0 | } |
841 | | |
842 | | std::error_code create_directories(const Twine &Path, bool IgnoreExisting, |
843 | 0 | perms Perms) { |
844 | 0 | SmallString<128> PathStorage; |
845 | 0 | StringRef P = Path.toStringRef(PathStorage); |
846 | | |
847 | | // Be optimistic and try to create the directory |
848 | 0 | std::error_code EC = create_directory(P, IgnoreExisting, Perms); |
849 | | // If we succeeded, or had any error other than the parent not existing, just |
850 | | // return it. |
851 | 0 | if (EC != errc::no_such_file_or_directory) |
852 | 0 | return EC; |
853 | | |
854 | | // We failed because of a no_such_file_or_directory, try to create the |
855 | | // parent. |
856 | 0 | StringRef Parent = path::parent_path(P); |
857 | 0 | if (Parent.empty()) |
858 | 0 | return EC; |
859 | | |
860 | 0 | if ((EC = create_directories(Parent, IgnoreExisting, Perms))) |
861 | 0 | return EC; |
862 | | |
863 | 0 | return create_directory(P, IgnoreExisting, Perms); |
864 | 0 | } |
865 | | |
866 | 0 | std::error_code copy_file(const Twine &From, const Twine &To) { |
867 | 0 | int ReadFD, WriteFD; |
868 | 0 | if (std::error_code EC = openFileForRead(From, ReadFD)) |
869 | 0 | return EC; |
870 | 0 | if (std::error_code EC = openFileForWrite(To, WriteFD, F_None)) { |
871 | 0 | close(ReadFD); |
872 | 0 | return EC; |
873 | 0 | } |
874 | | |
875 | 0 | const size_t BufSize = 4096; |
876 | 0 | char *Buf = new char[BufSize]; |
877 | 0 | int BytesRead = 0, BytesWritten = 0; |
878 | 0 | for (;;) { |
879 | 0 | BytesRead = read(ReadFD, Buf, BufSize); |
880 | 0 | if (BytesRead <= 0) |
881 | 0 | break; |
882 | 0 | while (BytesRead) { |
883 | 0 | BytesWritten = write(WriteFD, Buf, BytesRead); |
884 | 0 | if (BytesWritten < 0) |
885 | 0 | break; |
886 | 0 | BytesRead -= BytesWritten; |
887 | 0 | } |
888 | 0 | if (BytesWritten < 0) |
889 | 0 | break; |
890 | 0 | } |
891 | 0 | close(ReadFD); |
892 | 0 | close(WriteFD); |
893 | 0 | delete[] Buf; |
894 | |
|
895 | 0 | if (BytesRead < 0 || BytesWritten < 0) |
896 | 0 | return std::error_code(errno, std::generic_category()); |
897 | 0 | return std::error_code(); |
898 | 0 | } |
899 | | |
900 | 0 | bool exists(file_status status) { |
901 | 0 | return status_known(status) && status.type() != file_type::file_not_found; |
902 | 0 | } |
903 | | |
904 | 0 | bool status_known(file_status s) { |
905 | 0 | return s.type() != file_type::status_error; |
906 | 0 | } |
907 | | |
908 | 0 | bool is_directory(file_status status) { |
909 | 0 | return status.type() == file_type::directory_file; |
910 | 0 | } |
911 | | |
912 | 0 | std::error_code is_directory(const Twine &path, bool &result) { |
913 | 0 | file_status st; |
914 | 0 | if (std::error_code ec = status(path, st)) |
915 | 0 | return ec; |
916 | 0 | result = is_directory(st); |
917 | 0 | return std::error_code(); |
918 | 0 | } |
919 | | |
920 | 0 | bool is_regular_file(file_status status) { |
921 | 0 | return status.type() == file_type::regular_file; |
922 | 0 | } |
923 | | |
924 | 0 | std::error_code is_regular_file(const Twine &path, bool &result) { |
925 | 0 | file_status st; |
926 | 0 | if (std::error_code ec = status(path, st)) |
927 | 0 | return ec; |
928 | 0 | result = is_regular_file(st); |
929 | 0 | return std::error_code(); |
930 | 0 | } |
931 | | |
932 | 0 | bool is_other(file_status status) { |
933 | 0 | return exists(status) && |
934 | 0 | !is_regular_file(status) && |
935 | 0 | !is_directory(status); |
936 | 0 | } |
937 | | |
938 | 0 | std::error_code is_other(const Twine &Path, bool &Result) { |
939 | 0 | file_status FileStatus; |
940 | 0 | if (std::error_code EC = status(Path, FileStatus)) |
941 | 0 | return EC; |
942 | 0 | Result = is_other(FileStatus); |
943 | 0 | return std::error_code(); |
944 | 0 | } |
945 | | |
946 | 0 | void directory_entry::replace_filename(const Twine &filename, file_status st) { |
947 | 0 | SmallString<128> path = path::parent_path(Path); |
948 | 0 | path::append(path, filename); |
949 | 0 | Path = path.str(); |
950 | 0 | Status = st; |
951 | 0 | } |
952 | | |
953 | | /// @brief Identify the magic in magic. |
954 | 0 | file_magic identify_magic(StringRef Magic) { |
955 | 0 | if (Magic.size() < 4) |
956 | 0 | return file_magic::unknown; |
957 | 0 | switch ((unsigned char)Magic[0]) { |
958 | 0 | case 0x00: { |
959 | | // COFF bigobj or short import library file |
960 | 0 | if (Magic[1] == (char)0x00 && Magic[2] == (char)0xff && |
961 | 0 | Magic[3] == (char)0xff) { |
962 | 0 | size_t MinSize = offsetof(COFF::BigObjHeader, UUID) + sizeof(COFF::BigObjMagic); |
963 | 0 | if (Magic.size() < MinSize) |
964 | 0 | return file_magic::coff_import_library; |
965 | | |
966 | 0 | int BigObjVersion = read16le( |
967 | 0 | Magic.data() + offsetof(COFF::BigObjHeader, Version)); |
968 | 0 | if (BigObjVersion < COFF::BigObjHeader::MinBigObjectVersion) |
969 | 0 | return file_magic::coff_import_library; |
970 | | |
971 | 0 | const char *Start = Magic.data() + offsetof(COFF::BigObjHeader, UUID); |
972 | 0 | if (memcmp(Start, COFF::BigObjMagic, sizeof(COFF::BigObjMagic)) != 0) |
973 | 0 | return file_magic::coff_import_library; |
974 | 0 | return file_magic::coff_object; |
975 | 0 | } |
976 | | // Windows resource file |
977 | 0 | const char Expected[] = { 0, 0, 0, 0, '\x20', 0, 0, 0, '\xff' }; |
978 | 0 | if (Magic.size() >= sizeof(Expected) && |
979 | 0 | memcmp(Magic.data(), Expected, sizeof(Expected)) == 0) |
980 | 0 | return file_magic::windows_resource; |
981 | | // 0x0000 = COFF unknown machine type |
982 | 0 | if (Magic[1] == 0) |
983 | 0 | return file_magic::coff_object; |
984 | 0 | break; |
985 | 0 | } |
986 | 0 | case 0xDE: // 0x0B17C0DE = BC wraper |
987 | 0 | if (Magic[1] == (char)0xC0 && Magic[2] == (char)0x17 && |
988 | 0 | Magic[3] == (char)0x0B) |
989 | 0 | return file_magic::bitcode; |
990 | 0 | break; |
991 | 0 | case 'B': |
992 | 0 | if (Magic[1] == 'C' && Magic[2] == (char)0xC0 && Magic[3] == (char)0xDE) |
993 | 0 | return file_magic::bitcode; |
994 | 0 | break; |
995 | 0 | case '!': |
996 | 0 | if (Magic.size() >= 8) |
997 | 0 | if (memcmp(Magic.data(), "!<arch>\n", 8) == 0 || |
998 | 0 | memcmp(Magic.data(), "!<thin>\n", 8) == 0) |
999 | 0 | return file_magic::archive; |
1000 | 0 | break; |
1001 | | |
1002 | 0 | case '\177': |
1003 | 0 | if (Magic.size() >= 18 && Magic[1] == 'E' && Magic[2] == 'L' && |
1004 | 0 | Magic[3] == 'F') { |
1005 | 0 | bool Data2MSB = Magic[5] == 2; |
1006 | 0 | unsigned high = Data2MSB ? 16 : 17; |
1007 | 0 | unsigned low = Data2MSB ? 17 : 16; |
1008 | 0 | if (Magic[high] == 0) |
1009 | 0 | switch (Magic[low]) { |
1010 | 0 | default: return file_magic::elf; |
1011 | 0 | case 1: return file_magic::elf_relocatable; |
1012 | 0 | case 2: return file_magic::elf_executable; |
1013 | 0 | case 3: return file_magic::elf_shared_object; |
1014 | 0 | case 4: return file_magic::elf_core; |
1015 | 0 | } |
1016 | 0 | else |
1017 | | // It's still some type of ELF file. |
1018 | 0 | return file_magic::elf; |
1019 | 0 | } |
1020 | 0 | break; |
1021 | | |
1022 | 0 | case 0xCA: |
1023 | 0 | if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) && |
1024 | 0 | Magic[3] == char(0xBE)) { |
1025 | | // This is complicated by an overlap with Java class files. |
1026 | | // See the Mach-O section in /usr/share/file/magic for details. |
1027 | 0 | if (Magic.size() >= 8 && Magic[7] < 43) |
1028 | 0 | return file_magic::macho_universal_binary; |
1029 | 0 | } |
1030 | 0 | break; |
1031 | | |
1032 | | // The two magic numbers for mach-o are: |
1033 | | // 0xfeedface - 32-bit mach-o |
1034 | | // 0xfeedfacf - 64-bit mach-o |
1035 | 0 | case 0xFE: |
1036 | 0 | case 0xCE: |
1037 | 0 | case 0xCF: { |
1038 | 0 | uint16_t type = 0; |
1039 | 0 | if (Magic[0] == char(0xFE) && Magic[1] == char(0xED) && |
1040 | 0 | Magic[2] == char(0xFA) && |
1041 | 0 | (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) { |
1042 | | /* Native endian */ |
1043 | 0 | size_t MinSize; |
1044 | 0 | if (Magic[3] == char(0xCE)) |
1045 | 0 | MinSize = sizeof(MachO::mach_header); |
1046 | 0 | else |
1047 | 0 | MinSize = sizeof(MachO::mach_header_64); |
1048 | 0 | if (Magic.size() >= MinSize) |
1049 | 0 | type = Magic[12] << 24 | Magic[13] << 12 | Magic[14] << 8 | Magic[15]; |
1050 | 0 | } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) && |
1051 | 0 | Magic[1] == char(0xFA) && Magic[2] == char(0xED) && |
1052 | 0 | Magic[3] == char(0xFE)) { |
1053 | | /* Reverse endian */ |
1054 | 0 | size_t MinSize; |
1055 | 0 | if (Magic[0] == char(0xCE)) |
1056 | 0 | MinSize = sizeof(MachO::mach_header); |
1057 | 0 | else |
1058 | 0 | MinSize = sizeof(MachO::mach_header_64); |
1059 | 0 | if (Magic.size() >= MinSize) |
1060 | 0 | type = Magic[15] << 24 | Magic[14] << 12 |Magic[13] << 8 | Magic[12]; |
1061 | 0 | } |
1062 | 0 | switch (type) { |
1063 | 0 | default: break; |
1064 | 0 | case 1: return file_magic::macho_object; |
1065 | 0 | case 2: return file_magic::macho_executable; |
1066 | 0 | case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; |
1067 | 0 | case 4: return file_magic::macho_core; |
1068 | 0 | case 5: return file_magic::macho_preload_executable; |
1069 | 0 | case 6: return file_magic::macho_dynamically_linked_shared_lib; |
1070 | 0 | case 7: return file_magic::macho_dynamic_linker; |
1071 | 0 | case 8: return file_magic::macho_bundle; |
1072 | 0 | case 9: return file_magic::macho_dynamically_linked_shared_lib_stub; |
1073 | 0 | case 10: return file_magic::macho_dsym_companion; |
1074 | 0 | case 11: return file_magic::macho_kext_bundle; |
1075 | 0 | } |
1076 | 0 | break; |
1077 | 0 | } |
1078 | 0 | case 0xF0: // PowerPC Windows |
1079 | 0 | case 0x83: // Alpha 32-bit |
1080 | 0 | case 0x84: // Alpha 64-bit |
1081 | 0 | case 0x66: // MPS R4000 Windows |
1082 | 0 | case 0x50: // mc68K |
1083 | 0 | case 0x4c: // 80386 Windows |
1084 | 0 | case 0xc4: // ARMNT Windows |
1085 | 0 | if (Magic[1] == 0x01) |
1086 | 0 | return file_magic::coff_object; |
1087 | | |
1088 | 0 | case 0x90: // PA-RISC Windows |
1089 | 0 | case 0x68: // mc68K Windows |
1090 | 0 | if (Magic[1] == 0x02) |
1091 | 0 | return file_magic::coff_object; |
1092 | 0 | break; |
1093 | | |
1094 | 0 | case 'M': // Possible MS-DOS stub on Windows PE file |
1095 | 0 | if (Magic[1] == 'Z') { |
1096 | 0 | uint32_t off = read32le(Magic.data() + 0x3c); |
1097 | | // PE/COFF file, either EXE or DLL. |
1098 | 0 | if (off < Magic.size() && |
1099 | 0 | memcmp(Magic.data()+off, COFF::PEMagic, sizeof(COFF::PEMagic)) == 0) |
1100 | 0 | return file_magic::pecoff_executable; |
1101 | 0 | } |
1102 | 0 | break; |
1103 | | |
1104 | 0 | case 0x64: // x86-64 Windows. |
1105 | 0 | if (Magic[1] == char(0x86)) |
1106 | 0 | return file_magic::coff_object; |
1107 | 0 | break; |
1108 | | |
1109 | 0 | default: |
1110 | 0 | break; |
1111 | 0 | } |
1112 | 0 | return file_magic::unknown; |
1113 | 0 | } |
1114 | | |
1115 | 0 | std::error_code identify_magic(const Twine &Path, file_magic &Result) { |
1116 | 0 | int FD; |
1117 | 0 | if (std::error_code EC = openFileForRead(Path, FD)) |
1118 | 0 | return EC; |
1119 | | |
1120 | 0 | char Buffer[32]; |
1121 | 0 | int Length = read(FD, Buffer, sizeof(Buffer)); |
1122 | 0 | if (close(FD) != 0 || Length < 0) |
1123 | 0 | return std::error_code(errno, std::generic_category()); |
1124 | | |
1125 | 0 | Result = identify_magic(StringRef(Buffer, Length)); |
1126 | 0 | return std::error_code(); |
1127 | 0 | } |
1128 | | |
1129 | 0 | std::error_code directory_entry::status(file_status &result) const { |
1130 | 0 | return fs::status(Path, result); |
1131 | 0 | } |
1132 | | |
1133 | | } // end namespace fs |
1134 | | } // end namespace sys |
1135 | | } // end namespace llvm_ks |
1136 | | |
1137 | | // Include the truly platform-specific parts. |
1138 | | #if defined(LLVM_ON_UNIX) |
1139 | | #include "Unix/Path.inc" |
1140 | | #endif |
1141 | | #if defined(LLVM_ON_WIN32) |
1142 | | #include "Windows/Path.inc" |
1143 | | #endif |
1144 | | |
1145 | | namespace llvm_ks { |
1146 | | namespace sys { |
1147 | | namespace path { |
1148 | | |
1149 | | bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1, |
1150 | 0 | const Twine &Path2, const Twine &Path3) { |
1151 | 0 | if (getUserCacheDir(Result)) { |
1152 | 0 | append(Result, Path1, Path2, Path3); |
1153 | 0 | return true; |
1154 | 0 | } |
1155 | 0 | return false; |
1156 | 0 | } |
1157 | | |
1158 | | } // end namespace path |
1159 | | } // end namsspace sys |
1160 | | } // end namespace llvm_ks |