1//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===// 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 Windows specific implementation of the PathV2 API. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15//=== WARNING: Implementation here must contain only generic Windows code that 16//=== is guaranteed to work on *all* Windows variants. 17//===----------------------------------------------------------------------===// 18 19#include "Windows.h" 20#include <wincrypt.h> 21#include <fcntl.h> 22#include <io.h> 23#include <sys/stat.h> 24#include <sys/types.h> 25 26// MinGW doesn't define this. 27#ifndef _ERRNO_T_DEFINED 28#define _ERRNO_T_DEFINED 29typedef int errno_t; 30#endif 31 32using namespace llvm; 33 34namespace { 35 typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( 36 /*__in*/ LPCWSTR lpSymlinkFileName, 37 /*__in*/ LPCWSTR lpTargetFileName, 38 /*__in*/ DWORD dwFlags); 39 40 PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( 41 ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), 42 "CreateSymbolicLinkW")); 43 44 error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) { 45 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 46 utf8.begin(), utf8.size(), 47 utf16.begin(), 0); 48 49 if (len == 0) 50 return windows_error(::GetLastError()); 51 52 utf16.reserve(len + 1); 53 utf16.set_size(len); 54 55 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 56 utf8.begin(), utf8.size(), 57 utf16.begin(), utf16.size()); 58 59 if (len == 0) 60 return windows_error(::GetLastError()); 61 62 // Make utf16 null terminated. 63 utf16.push_back(0); 64 utf16.pop_back(); 65 66 return success; 67 } 68 69 error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 70 SmallVectorImpl<char> &utf8) { 71 // Get length. 72 int len = ::WideCharToMultiByte(CP_UTF8, 0, 73 utf16, utf16_len, 74 utf8.begin(), 0, 75 NULL, NULL); 76 77 if (len == 0) 78 return windows_error(::GetLastError()); 79 80 utf8.reserve(len); 81 utf8.set_size(len); 82 83 // Now do the actual conversion. 84 len = ::WideCharToMultiByte(CP_UTF8, 0, 85 utf16, utf16_len, 86 utf8.data(), utf8.size(), 87 NULL, NULL); 88 89 if (len == 0) 90 return windows_error(::GetLastError()); 91 92 // Make utf8 null terminated. 93 utf8.push_back(0); 94 utf8.pop_back(); 95 96 return success; 97 } 98 99 error_code TempDir(SmallVectorImpl<wchar_t> &result) { 100 retry_temp_dir: 101 DWORD len = ::GetTempPathW(result.capacity(), result.begin()); 102 103 if (len == 0) 104 return windows_error(::GetLastError()); 105 106 if (len > result.capacity()) { 107 result.reserve(len); 108 goto retry_temp_dir; 109 } 110 111 result.set_size(len); 112 return success; 113 } 114 115 // Forwarder for ScopedHandle. 116 BOOL WINAPI CryptReleaseContext(HCRYPTPROV Provider) { 117 return ::CryptReleaseContext(Provider, 0); 118 } 119 120 typedef ScopedHandle<HCRYPTPROV, uintptr_t(-1), 121 BOOL (WINAPI*)(HCRYPTPROV), CryptReleaseContext> 122 ScopedCryptContext; 123 bool is_separator(const wchar_t value) { 124 switch (value) { 125 case L'\\': 126 case L'/': 127 return true; 128 default: 129 return false; 130 } 131 } 132} 133 134namespace llvm { 135namespace sys { 136namespace fs { 137 138error_code current_path(SmallVectorImpl<char> &result) { 139 SmallVector<wchar_t, 128> cur_path; 140 cur_path.reserve(128); 141retry_cur_dir: 142 DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); 143 144 // A zero return value indicates a failure other than insufficient space. 145 if (len == 0) 146 return windows_error(::GetLastError()); 147 148 // If there's insufficient space, the len returned is larger than the len 149 // given. 150 if (len > cur_path.capacity()) { 151 cur_path.reserve(len); 152 goto retry_cur_dir; 153 } 154 155 cur_path.set_size(len); 156 // cur_path now holds the current directory in utf-16. Convert to utf-8. 157 158 // Find out how much space we need. Sadly, this function doesn't return the 159 // size needed unless you tell it the result size is 0, which means you 160 // _always_ have to call it twice. 161 len = ::WideCharToMultiByte(CP_UTF8, 0, 162 cur_path.data(), cur_path.size(), 163 result.data(), 0, 164 NULL, NULL); 165 166 if (len == 0) 167 return make_error_code(windows_error(::GetLastError())); 168 169 result.reserve(len); 170 result.set_size(len); 171 // Now do the actual conversion. 172 len = ::WideCharToMultiByte(CP_UTF8, 0, 173 cur_path.data(), cur_path.size(), 174 result.data(), result.size(), 175 NULL, NULL); 176 if (len == 0) 177 return windows_error(::GetLastError()); 178 179 return success; 180} 181 182error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { 183 // Get arguments. 184 SmallString<128> from_storage; 185 SmallString<128> to_storage; 186 StringRef f = from.toStringRef(from_storage); 187 StringRef t = to.toStringRef(to_storage); 188 189 // Convert to utf-16. 190 SmallVector<wchar_t, 128> wide_from; 191 SmallVector<wchar_t, 128> wide_to; 192 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 193 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 194 195 // Copy the file. 196 BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(), 197 copt != copy_option::overwrite_if_exists); 198 199 if (res == 0) 200 return windows_error(::GetLastError()); 201 202 return success; 203} 204 205error_code create_directory(const Twine &path, bool &existed) { 206 SmallString<128> path_storage; 207 SmallVector<wchar_t, 128> path_utf16; 208 209 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 210 path_utf16)) 211 return ec; 212 213 if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { 214 error_code ec = windows_error(::GetLastError()); 215 if (ec == windows_error::already_exists) 216 existed = true; 217 else 218 return ec; 219 } else 220 existed = false; 221 222 return success; 223} 224 225error_code create_hard_link(const Twine &to, const Twine &from) { 226 // Get arguments. 227 SmallString<128> from_storage; 228 SmallString<128> to_storage; 229 StringRef f = from.toStringRef(from_storage); 230 StringRef t = to.toStringRef(to_storage); 231 232 // Convert to utf-16. 233 SmallVector<wchar_t, 128> wide_from; 234 SmallVector<wchar_t, 128> wide_to; 235 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 236 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 237 238 if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) 239 return windows_error(::GetLastError()); 240 241 return success; 242} 243 244error_code create_symlink(const Twine &to, const Twine &from) { 245 // Only do it if the function is available at runtime. 246 if (!create_symbolic_link_api) 247 return make_error_code(errc::function_not_supported); 248 249 // Get arguments. 250 SmallString<128> from_storage; 251 SmallString<128> to_storage; 252 StringRef f = from.toStringRef(from_storage); 253 StringRef t = to.toStringRef(to_storage); 254 255 // Convert to utf-16. 256 SmallVector<wchar_t, 128> wide_from; 257 SmallVector<wchar_t, 128> wide_to; 258 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 259 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 260 261 if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) 262 return windows_error(::GetLastError()); 263 264 return success; 265} 266 267error_code remove(const Twine &path, bool &existed) { 268 SmallString<128> path_storage; 269 SmallVector<wchar_t, 128> path_utf16; 270 271 file_status st; 272 if (error_code ec = status(path, st)) 273 return ec; 274 275 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 276 path_utf16)) 277 return ec; 278 279 if (st.type() == file_type::directory_file) { 280 if (!::RemoveDirectoryW(c_str(path_utf16))) { 281 error_code ec = windows_error(::GetLastError()); 282 if (ec != windows_error::file_not_found) 283 return ec; 284 existed = false; 285 } else 286 existed = true; 287 } else { 288 if (!::DeleteFileW(c_str(path_utf16))) { 289 error_code ec = windows_error(::GetLastError()); 290 if (ec != windows_error::file_not_found) 291 return ec; 292 existed = false; 293 } else 294 existed = true; 295 } 296 297 return success; 298} 299 300error_code rename(const Twine &from, const Twine &to) { 301 // Get arguments. 302 SmallString<128> from_storage; 303 SmallString<128> to_storage; 304 StringRef f = from.toStringRef(from_storage); 305 StringRef t = to.toStringRef(to_storage); 306 307 // Convert to utf-16. 308 SmallVector<wchar_t, 128> wide_from; 309 SmallVector<wchar_t, 128> wide_to; 310 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 311 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 312 313 if (!::MoveFileExW(wide_from.begin(), wide_to.begin(), 314 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 315 return windows_error(::GetLastError()); 316 317 return success; 318} 319 320error_code resize_file(const Twine &path, uint64_t size) { 321 SmallString<128> path_storage; 322 SmallVector<wchar_t, 128> path_utf16; 323 324 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 325 path_utf16)) 326 return ec; 327 328 int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE); 329 if (fd == -1) 330 return error_code(errno, generic_category()); 331#ifdef HAVE__CHSIZE_S 332 errno_t error = ::_chsize_s(fd, size); 333#else 334 errno_t error = ::_chsize(fd, size); 335#endif 336 ::close(fd); 337 return error_code(error, generic_category()); 338} 339 340error_code exists(const Twine &path, bool &result) { 341 SmallString<128> path_storage; 342 SmallVector<wchar_t, 128> path_utf16; 343 344 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 345 path_utf16)) 346 return ec; 347 348 DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); 349 350 if (attributes == INVALID_FILE_ATTRIBUTES) { 351 // See if the file didn't actually exist. 352 error_code ec = make_error_code(windows_error(::GetLastError())); 353 if (ec != windows_error::file_not_found && 354 ec != windows_error::path_not_found) 355 return ec; 356 result = false; 357 } else 358 result = true; 359 return success; 360} 361 362error_code equivalent(const Twine &A, const Twine &B, bool &result) { 363 // Get arguments. 364 SmallString<128> a_storage; 365 SmallString<128> b_storage; 366 StringRef a = A.toStringRef(a_storage); 367 StringRef b = B.toStringRef(b_storage); 368 369 // Convert to utf-16. 370 SmallVector<wchar_t, 128> wide_a; 371 SmallVector<wchar_t, 128> wide_b; 372 if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec; 373 if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec; 374 375 AutoHandle HandleB( 376 ::CreateFileW(wide_b.begin(), 377 0, 378 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 379 0, 380 OPEN_EXISTING, 381 FILE_FLAG_BACKUP_SEMANTICS, 382 0)); 383 384 AutoHandle HandleA( 385 ::CreateFileW(wide_a.begin(), 386 0, 387 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 388 0, 389 OPEN_EXISTING, 390 FILE_FLAG_BACKUP_SEMANTICS, 391 0)); 392 393 // If both handles are invalid, it's an error. 394 if (HandleA == INVALID_HANDLE_VALUE && 395 HandleB == INVALID_HANDLE_VALUE) 396 return windows_error(::GetLastError()); 397 398 // If only one is invalid, it's false. 399 if (HandleA == INVALID_HANDLE_VALUE && 400 HandleB == INVALID_HANDLE_VALUE) { 401 result = false; 402 return success; 403 } 404 405 // Get file information. 406 BY_HANDLE_FILE_INFORMATION InfoA, InfoB; 407 if (!::GetFileInformationByHandle(HandleA, &InfoA)) 408 return windows_error(::GetLastError()); 409 if (!::GetFileInformationByHandle(HandleB, &InfoB)) 410 return windows_error(::GetLastError()); 411 412 // See if it's all the same. 413 result = 414 InfoA.dwVolumeSerialNumber == InfoB.dwVolumeSerialNumber && 415 InfoA.nFileIndexHigh == InfoB.nFileIndexHigh && 416 InfoA.nFileIndexLow == InfoB.nFileIndexLow && 417 InfoA.nFileSizeHigh == InfoB.nFileSizeHigh && 418 InfoA.nFileSizeLow == InfoB.nFileSizeLow && 419 InfoA.ftLastWriteTime.dwLowDateTime == 420 InfoB.ftLastWriteTime.dwLowDateTime && 421 InfoA.ftLastWriteTime.dwHighDateTime == 422 InfoB.ftLastWriteTime.dwHighDateTime; 423 424 return success; 425} 426 427error_code file_size(const Twine &path, uint64_t &result) { 428 SmallString<128> path_storage; 429 SmallVector<wchar_t, 128> path_utf16; 430 431 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 432 path_utf16)) 433 return ec; 434 435 WIN32_FILE_ATTRIBUTE_DATA FileData; 436 if (!::GetFileAttributesExW(path_utf16.begin(), 437 ::GetFileExInfoStandard, 438 &FileData)) 439 return windows_error(::GetLastError()); 440 441 result = 442 (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8)) 443 + FileData.nFileSizeLow; 444 445 return success; 446} 447 448static bool isReservedName(StringRef path) { 449 // This list of reserved names comes from MSDN, at: 450 // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 451 static const char *sReservedNames[] = { "nul", "con", "prn", "aux", 452 "com1", "com2", "com3", "com4", "com5", "com6", 453 "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", 454 "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; 455 456 // First, check to see if this is a device namespace, which always 457 // starts with \\.\, since device namespaces are not legal file paths. 458 if (path.startswith("\\\\.\\")) 459 return true; 460 461 // Then compare against the list of ancient reserved names 462 for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) { 463 if (path.equals_lower(sReservedNames[i])) 464 return true; 465 } 466 467 // The path isn't what we consider reserved. 468 return false; 469} 470 471error_code status(const Twine &path, file_status &result) { 472 SmallString<128> path_storage; 473 SmallVector<wchar_t, 128> path_utf16; 474 475 StringRef path8 = path.toStringRef(path_storage); 476 if (isReservedName(path8)) { 477 result = file_status(file_type::character_file); 478 return success; 479 } 480 481 if (error_code ec = UTF8ToUTF16(path8, 482 path_utf16)) 483 return ec; 484 485 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 486 if (attr == INVALID_FILE_ATTRIBUTES) 487 goto handle_status_error; 488 489 // Handle reparse points. 490 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { 491 AutoHandle h( 492 ::CreateFileW(path_utf16.begin(), 493 0, // Attributes only. 494 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 495 NULL, 496 OPEN_EXISTING, 497 FILE_FLAG_BACKUP_SEMANTICS, 498 0)); 499 if (h == INVALID_HANDLE_VALUE) 500 goto handle_status_error; 501 } 502 503 if (attr & FILE_ATTRIBUTE_DIRECTORY) 504 result = file_status(file_type::directory_file); 505 else 506 result = file_status(file_type::regular_file); 507 508 return success; 509 510handle_status_error: 511 error_code ec = windows_error(::GetLastError()); 512 if (ec == windows_error::file_not_found || 513 ec == windows_error::path_not_found) 514 result = file_status(file_type::file_not_found); 515 else if (ec == windows_error::sharing_violation) 516 result = file_status(file_type::type_unknown); 517 else { 518 result = file_status(file_type::status_error); 519 return ec; 520 } 521 522 return success; 523} 524 525error_code unique_file(const Twine &model, int &result_fd, 526 SmallVectorImpl<char> &result_path, 527 bool makeAbsolute) { 528 // Use result_path as temp storage. 529 result_path.set_size(0); 530 StringRef m = model.toStringRef(result_path); 531 532 SmallVector<wchar_t, 128> model_utf16; 533 if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; 534 535 if (makeAbsolute) { 536 // Make model absolute by prepending a temp directory if it's not already. 537 bool absolute = path::is_absolute(m); 538 539 if (!absolute) { 540 SmallVector<wchar_t, 64> temp_dir; 541 if (error_code ec = TempDir(temp_dir)) return ec; 542 // Handle c: by removing it. 543 if (model_utf16.size() > 2 && model_utf16[1] == L':') { 544 model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); 545 } 546 model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); 547 } 548 } 549 550 // Replace '%' with random chars. From here on, DO NOT modify model. It may be 551 // needed if the randomly chosen path already exists. 552 SmallVector<wchar_t, 128> random_path_utf16; 553 554 // Get a Crypto Provider for CryptGenRandom. 555 HCRYPTPROV HCPC; 556 if (!::CryptAcquireContextW(&HCPC, 557 NULL, 558 NULL, 559 PROV_RSA_FULL, 560 CRYPT_VERIFYCONTEXT)) 561 return windows_error(::GetLastError()); 562 ScopedCryptContext CryptoProvider(HCPC); 563 564retry_random_path: 565 random_path_utf16.set_size(0); 566 for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), 567 e = model_utf16.end(); 568 i != e; ++i) { 569 if (*i == L'%') { 570 BYTE val = 0; 571 if (!::CryptGenRandom(CryptoProvider, 1, &val)) 572 return windows_error(::GetLastError()); 573 random_path_utf16.push_back("0123456789abcdef"[val & 15]); 574 } 575 else 576 random_path_utf16.push_back(*i); 577 } 578 // Make random_path_utf16 null terminated. 579 random_path_utf16.push_back(0); 580 random_path_utf16.pop_back(); 581 582 // Try to create + open the path. 583retry_create_file: 584 HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), 585 GENERIC_READ | GENERIC_WRITE, 586 FILE_SHARE_READ, 587 NULL, 588 // Return ERROR_FILE_EXISTS if the file 589 // already exists. 590 CREATE_NEW, 591 FILE_ATTRIBUTE_TEMPORARY, 592 NULL); 593 if (TempFileHandle == INVALID_HANDLE_VALUE) { 594 // If the file existed, try again, otherwise, error. 595 error_code ec = windows_error(::GetLastError()); 596 if (ec == windows_error::file_exists) 597 goto retry_random_path; 598 // Check for non-existing parent directories. 599 if (ec == windows_error::path_not_found) { 600 // Create the directories using result_path as temp storage. 601 if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), 602 random_path_utf16.size(), result_path)) 603 return ec; 604 StringRef p(result_path.begin(), result_path.size()); 605 SmallString<64> dir_to_create; 606 for (path::const_iterator i = path::begin(p), 607 e = --path::end(p); i != e; ++i) { 608 path::append(dir_to_create, *i); 609 bool Exists; 610 if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; 611 if (!Exists) { 612 // If c: doesn't exist, bail. 613 if (i->endswith(":")) 614 return ec; 615 616 SmallVector<wchar_t, 64> dir_to_create_utf16; 617 if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16)) 618 return ec; 619 620 // Create the directory. 621 if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL)) 622 return windows_error(::GetLastError()); 623 } 624 } 625 goto retry_create_file; 626 } 627 return ec; 628 } 629 630 // Set result_path to the utf-8 representation of the path. 631 if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), 632 random_path_utf16.size(), result_path)) { 633 ::CloseHandle(TempFileHandle); 634 ::DeleteFileW(random_path_utf16.begin()); 635 return ec; 636 } 637 638 // Convert the Windows API file handle into a C-runtime handle. 639 int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); 640 if (fd == -1) { 641 ::CloseHandle(TempFileHandle); 642 ::DeleteFileW(random_path_utf16.begin()); 643 // MSDN doesn't say anything about _open_osfhandle setting errno or 644 // GetLastError(), so just return invalid_handle. 645 return windows_error::invalid_handle; 646 } 647 648 result_fd = fd; 649 return success; 650} 651 652error_code get_magic(const Twine &path, uint32_t len, 653 SmallVectorImpl<char> &result) { 654 SmallString<128> path_storage; 655 SmallVector<wchar_t, 128> path_utf16; 656 result.set_size(0); 657 658 // Convert path to UTF-16. 659 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 660 path_utf16)) 661 return ec; 662 663 // Open file. 664 HANDLE file = ::CreateFileW(c_str(path_utf16), 665 GENERIC_READ, 666 FILE_SHARE_READ, 667 NULL, 668 OPEN_EXISTING, 669 FILE_ATTRIBUTE_READONLY, 670 NULL); 671 if (file == INVALID_HANDLE_VALUE) 672 return windows_error(::GetLastError()); 673 674 // Allocate buffer. 675 result.reserve(len); 676 677 // Get magic! 678 DWORD bytes_read = 0; 679 BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); 680 error_code ec = windows_error(::GetLastError()); 681 ::CloseHandle(file); 682 if (!read_success || (bytes_read != len)) { 683 // Set result size to the number of bytes read if it's valid. 684 if (bytes_read <= len) 685 result.set_size(bytes_read); 686 // ERROR_HANDLE_EOF is mapped to errc::value_too_large. 687 return ec; 688 } 689 690 result.set_size(len); 691 return success; 692} 693 694error_code directory_iterator_construct(directory_iterator &it, StringRef path){ 695 SmallVector<wchar_t, 128> path_utf16; 696 697 if (error_code ec = UTF8ToUTF16(path, 698 path_utf16)) 699 return ec; 700 701 // Convert path to the format that Windows is happy with. 702 if (path_utf16.size() > 0 && 703 !is_separator(path_utf16[path.size() - 1]) && 704 path_utf16[path.size() - 1] != L':') { 705 path_utf16.push_back(L'\\'); 706 path_utf16.push_back(L'*'); 707 } else { 708 path_utf16.push_back(L'*'); 709 } 710 711 // Get the first directory entry. 712 WIN32_FIND_DATAW FirstFind; 713 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 714 if (!FindHandle) 715 return windows_error(::GetLastError()); 716 717 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 718 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 719 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 720 FirstFind.cFileName[1] == L'.')) 721 if (!::FindNextFileW(FindHandle, &FirstFind)) { 722 error_code ec = windows_error(::GetLastError()); 723 // Check for end. 724 if (ec == windows_error::no_more_files) 725 return directory_iterator_destruct(it); 726 return ec; 727 } else 728 FilenameLen = ::wcslen(FirstFind.cFileName); 729 730 // Construct the current directory entry. 731 SmallString<128> directory_entry_name_utf8; 732 if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, 733 ::wcslen(FirstFind.cFileName), 734 directory_entry_name_utf8)) 735 return ec; 736 737 it.IterationHandle = intptr_t(FindHandle.take()); 738 SmallString<128> directory_entry_path(path); 739 path::append(directory_entry_path, directory_entry_name_utf8.str()); 740 it.CurrentEntry = directory_entry(directory_entry_path.str()); 741 742 return success; 743} 744 745error_code directory_iterator_destruct(directory_iterator& it) { 746 if (it.IterationHandle != 0) 747 // Closes the handle if it's valid. 748 ScopedFindHandle close(HANDLE(it.IterationHandle)); 749 it.IterationHandle = 0; 750 it.CurrentEntry = directory_entry(); 751 return success; 752} 753 754error_code directory_iterator_increment(directory_iterator& it) { 755 WIN32_FIND_DATAW FindData; 756 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 757 error_code ec = windows_error(::GetLastError()); 758 // Check for end. 759 if (ec == windows_error::no_more_files) 760 return directory_iterator_destruct(it); 761 return ec; 762 } 763 764 size_t FilenameLen = ::wcslen(FindData.cFileName); 765 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 766 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 767 FindData.cFileName[1] == L'.')) 768 return directory_iterator_increment(it); 769 770 SmallString<128> directory_entry_path_utf8; 771 if (error_code ec = UTF16ToUTF8(FindData.cFileName, 772 ::wcslen(FindData.cFileName), 773 directory_entry_path_utf8)) 774 return ec; 775 776 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 777 return success; 778} 779 780} // end namespace fs 781} // end namespace sys 782} // end namespace llvm 783