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 448error_code status(const Twine &path, file_status &result) { 449 SmallString<128> path_storage; 450 SmallVector<wchar_t, 128> path_utf16; 451 452 StringRef path8 = path.toStringRef(path_storage); 453 // FIXME: We should detect as many "special file name" as possible. 454 if (path8.compare_lower("nul") == 0) { 455 result = file_status(file_type::character_file); 456 return success; 457 } 458 459 if (error_code ec = UTF8ToUTF16(path8, 460 path_utf16)) 461 return ec; 462 463 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 464 if (attr == INVALID_FILE_ATTRIBUTES) 465 goto handle_status_error; 466 467 // Handle reparse points. 468 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { 469 AutoHandle h( 470 ::CreateFileW(path_utf16.begin(), 471 0, // Attributes only. 472 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 473 NULL, 474 OPEN_EXISTING, 475 FILE_FLAG_BACKUP_SEMANTICS, 476 0)); 477 if (h == INVALID_HANDLE_VALUE) 478 goto handle_status_error; 479 } 480 481 if (attr & FILE_ATTRIBUTE_DIRECTORY) 482 result = file_status(file_type::directory_file); 483 else 484 result = file_status(file_type::regular_file); 485 486 return success; 487 488handle_status_error: 489 error_code ec = windows_error(::GetLastError()); 490 if (ec == windows_error::file_not_found || 491 ec == windows_error::path_not_found) 492 result = file_status(file_type::file_not_found); 493 else if (ec == windows_error::sharing_violation) 494 result = file_status(file_type::type_unknown); 495 else { 496 result = file_status(file_type::status_error); 497 return ec; 498 } 499 500 return success; 501} 502 503error_code unique_file(const Twine &model, int &result_fd, 504 SmallVectorImpl<char> &result_path) { 505 // Use result_path as temp storage. 506 result_path.set_size(0); 507 StringRef m = model.toStringRef(result_path); 508 509 SmallVector<wchar_t, 128> model_utf16; 510 if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; 511 512 // Make model absolute by prepending a temp directory if it's not already. 513 bool absolute = path::is_absolute(m); 514 515 if (!absolute) { 516 SmallVector<wchar_t, 64> temp_dir; 517 if (error_code ec = TempDir(temp_dir)) return ec; 518 // Handle c: by removing it. 519 if (model_utf16.size() > 2 && model_utf16[1] == L':') { 520 model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); 521 } 522 model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); 523 } 524 525 // Replace '%' with random chars. From here on, DO NOT modify model. It may be 526 // needed if the randomly chosen path already exists. 527 SmallVector<wchar_t, 128> random_path_utf16; 528 529 // Get a Crypto Provider for CryptGenRandom. 530 HCRYPTPROV HCPC; 531 if (!::CryptAcquireContextW(&HCPC, 532 NULL, 533 NULL, 534 PROV_RSA_FULL, 535 CRYPT_VERIFYCONTEXT)) 536 return windows_error(::GetLastError()); 537 ScopedCryptContext CryptoProvider(HCPC); 538 539retry_random_path: 540 random_path_utf16.set_size(0); 541 for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), 542 e = model_utf16.end(); 543 i != e; ++i) { 544 if (*i == L'%') { 545 BYTE val = 0; 546 if (!::CryptGenRandom(CryptoProvider, 1, &val)) 547 return windows_error(::GetLastError()); 548 random_path_utf16.push_back("0123456789abcdef"[val & 15]); 549 } 550 else 551 random_path_utf16.push_back(*i); 552 } 553 // Make random_path_utf16 null terminated. 554 random_path_utf16.push_back(0); 555 random_path_utf16.pop_back(); 556 557 // Try to create + open the path. 558retry_create_file: 559 HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), 560 GENERIC_READ | GENERIC_WRITE, 561 FILE_SHARE_READ, 562 NULL, 563 // Return ERROR_FILE_EXISTS if the file 564 // already exists. 565 CREATE_NEW, 566 FILE_ATTRIBUTE_TEMPORARY, 567 NULL); 568 if (TempFileHandle == INVALID_HANDLE_VALUE) { 569 // If the file existed, try again, otherwise, error. 570 error_code ec = windows_error(::GetLastError()); 571 if (ec == windows_error::file_exists) 572 goto retry_random_path; 573 // Check for non-existing parent directories. 574 if (ec == windows_error::path_not_found) { 575 // Create the directories using result_path as temp storage. 576 if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), 577 random_path_utf16.size(), result_path)) 578 return ec; 579 StringRef p(result_path.begin(), result_path.size()); 580 SmallString<64> dir_to_create; 581 for (path::const_iterator i = path::begin(p), 582 e = --path::end(p); i != e; ++i) { 583 path::append(dir_to_create, *i); 584 bool Exists; 585 if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; 586 if (!Exists) { 587 // If c: doesn't exist, bail. 588 if (i->endswith(":")) 589 return ec; 590 591 SmallVector<wchar_t, 64> dir_to_create_utf16; 592 if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16)) 593 return ec; 594 595 // Create the directory. 596 if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL)) 597 return windows_error(::GetLastError()); 598 } 599 } 600 goto retry_create_file; 601 } 602 return ec; 603 } 604 605 // Set result_path to the utf-8 representation of the path. 606 if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), 607 random_path_utf16.size(), result_path)) { 608 ::CloseHandle(TempFileHandle); 609 ::DeleteFileW(random_path_utf16.begin()); 610 return ec; 611 } 612 613 // Convert the Windows API file handle into a C-runtime handle. 614 int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); 615 if (fd == -1) { 616 ::CloseHandle(TempFileHandle); 617 ::DeleteFileW(random_path_utf16.begin()); 618 // MSDN doesn't say anything about _open_osfhandle setting errno or 619 // GetLastError(), so just return invalid_handle. 620 return windows_error::invalid_handle; 621 } 622 623 result_fd = fd; 624 return success; 625} 626 627error_code get_magic(const Twine &path, uint32_t len, 628 SmallVectorImpl<char> &result) { 629 SmallString<128> path_storage; 630 SmallVector<wchar_t, 128> path_utf16; 631 result.set_size(0); 632 633 // Convert path to UTF-16. 634 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 635 path_utf16)) 636 return ec; 637 638 // Open file. 639 HANDLE file = ::CreateFileW(c_str(path_utf16), 640 GENERIC_READ, 641 FILE_SHARE_READ, 642 NULL, 643 OPEN_EXISTING, 644 FILE_ATTRIBUTE_READONLY, 645 NULL); 646 if (file == INVALID_HANDLE_VALUE) 647 return windows_error(::GetLastError()); 648 649 // Allocate buffer. 650 result.reserve(len); 651 652 // Get magic! 653 DWORD bytes_read = 0; 654 BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); 655 error_code ec = windows_error(::GetLastError()); 656 ::CloseHandle(file); 657 if (!read_success || (bytes_read != len)) { 658 // Set result size to the number of bytes read if it's valid. 659 if (bytes_read <= len) 660 result.set_size(bytes_read); 661 // ERROR_HANDLE_EOF is mapped to errc::value_too_large. 662 return ec; 663 } 664 665 result.set_size(len); 666 return success; 667} 668 669error_code directory_iterator_construct(directory_iterator &it, StringRef path){ 670 SmallVector<wchar_t, 128> path_utf16; 671 672 if (error_code ec = UTF8ToUTF16(path, 673 path_utf16)) 674 return ec; 675 676 // Convert path to the format that Windows is happy with. 677 if (path_utf16.size() > 0 && 678 !is_separator(path_utf16[path.size() - 1]) && 679 path_utf16[path.size() - 1] != L':') { 680 path_utf16.push_back(L'\\'); 681 path_utf16.push_back(L'*'); 682 } else { 683 path_utf16.push_back(L'*'); 684 } 685 686 // Get the first directory entry. 687 WIN32_FIND_DATAW FirstFind; 688 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 689 if (!FindHandle) 690 return windows_error(::GetLastError()); 691 692 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 693 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 694 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 695 FirstFind.cFileName[1] == L'.')) 696 if (!::FindNextFileW(FindHandle, &FirstFind)) { 697 error_code ec = windows_error(::GetLastError()); 698 // Check for end. 699 if (ec == windows_error::no_more_files) 700 return directory_iterator_destruct(it); 701 return ec; 702 } else 703 FilenameLen = ::wcslen(FirstFind.cFileName); 704 705 // Construct the current directory entry. 706 SmallString<128> directory_entry_name_utf8; 707 if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, 708 ::wcslen(FirstFind.cFileName), 709 directory_entry_name_utf8)) 710 return ec; 711 712 it.IterationHandle = intptr_t(FindHandle.take()); 713 SmallString<128> directory_entry_path(path); 714 path::append(directory_entry_path, directory_entry_name_utf8.str()); 715 it.CurrentEntry = directory_entry(directory_entry_path.str()); 716 717 return success; 718} 719 720error_code directory_iterator_destruct(directory_iterator& it) { 721 if (it.IterationHandle != 0) 722 // Closes the handle if it's valid. 723 ScopedFindHandle close(HANDLE(it.IterationHandle)); 724 it.IterationHandle = 0; 725 it.CurrentEntry = directory_entry(); 726 return success; 727} 728 729error_code directory_iterator_increment(directory_iterator& it) { 730 WIN32_FIND_DATAW FindData; 731 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 732 error_code ec = windows_error(::GetLastError()); 733 // Check for end. 734 if (ec == windows_error::no_more_files) 735 return directory_iterator_destruct(it); 736 return ec; 737 } 738 739 size_t FilenameLen = ::wcslen(FindData.cFileName); 740 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 741 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 742 FindData.cFileName[1] == L'.')) 743 return directory_iterator_increment(it); 744 745 SmallString<128> directory_entry_path_utf8; 746 if (error_code ec = UTF16ToUTF8(FindData.cFileName, 747 ::wcslen(FindData.cFileName), 748 directory_entry_path_utf8)) 749 return ec; 750 751 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 752 return success; 753} 754 755} // end namespace fs 756} // end namespace sys 757} // end namespace llvm 758