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