1//===- llvm/Support/Windows/Path.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 Path 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 "llvm/ADT/STLExtras.h" 20#include "llvm/Support/WindowsError.h" 21#include <fcntl.h> 22#include <io.h> 23#include <sys/stat.h> 24#include <sys/types.h> 25 26// These two headers must be included last, and make sure shlobj is required 27// after Windows.h to make sure it picks up our definition of _WIN32_WINNT 28#include "WindowsSupport.h" 29#include <shlobj.h> 30 31#undef max 32 33// MinGW doesn't define this. 34#ifndef _ERRNO_T_DEFINED 35#define _ERRNO_T_DEFINED 36typedef int errno_t; 37#endif 38 39#ifdef _MSC_VER 40# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. 41#endif 42 43using namespace llvm; 44 45using llvm::sys::windows::UTF8ToUTF16; 46using llvm::sys::windows::UTF16ToUTF8; 47 48static std::error_code windows_error(DWORD E) { 49 return mapWindowsError(E); 50} 51 52static std::error_code TempDir(SmallVectorImpl<char> &Result) { 53 SmallVector<wchar_t, 64> Res; 54retry_temp_dir: 55 DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); 56 57 if (Len == 0) 58 return windows_error(::GetLastError()); 59 60 if (Len > Res.capacity()) { 61 Res.reserve(Len); 62 goto retry_temp_dir; 63 } 64 65 Res.set_size(Len); 66 return UTF16ToUTF8(Res.begin(), Res.size(), Result); 67} 68 69static bool is_separator(const wchar_t value) { 70 switch (value) { 71 case L'\\': 72 case L'/': 73 return true; 74 default: 75 return false; 76 } 77} 78 79namespace llvm { 80namespace sys { 81namespace fs { 82 83std::string getMainExecutable(const char *argv0, void *MainExecAddr) { 84 SmallVector<wchar_t, MAX_PATH> PathName; 85 DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); 86 87 // A zero return value indicates a failure other than insufficient space. 88 if (Size == 0) 89 return ""; 90 91 // Insufficient space is determined by a return value equal to the size of 92 // the buffer passed in. 93 if (Size == PathName.capacity()) 94 return ""; 95 96 // On success, GetModuleFileNameW returns the number of characters written to 97 // the buffer not including the NULL terminator. 98 PathName.set_size(Size); 99 100 // Convert the result from UTF-16 to UTF-8. 101 SmallVector<char, MAX_PATH> PathNameUTF8; 102 if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) 103 return ""; 104 105 return std::string(PathNameUTF8.data()); 106} 107 108UniqueID file_status::getUniqueID() const { 109 // The file is uniquely identified by the volume serial number along 110 // with the 64-bit file identifier. 111 uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | 112 static_cast<uint64_t>(FileIndexLow); 113 114 return UniqueID(VolumeSerialNumber, FileID); 115} 116 117TimeValue file_status::getLastModificationTime() const { 118 ULARGE_INTEGER UI; 119 UI.LowPart = LastWriteTimeLow; 120 UI.HighPart = LastWriteTimeHigh; 121 122 TimeValue Ret; 123 Ret.fromWin32Time(UI.QuadPart); 124 return Ret; 125} 126 127std::error_code current_path(SmallVectorImpl<char> &result) { 128 SmallVector<wchar_t, MAX_PATH> cur_path; 129 DWORD len = MAX_PATH; 130 131 do { 132 cur_path.reserve(len); 133 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 } while (len > cur_path.capacity()); 142 143 // On success, GetCurrentDirectoryW returns the number of characters not 144 // including the null-terminator. 145 cur_path.set_size(len); 146 return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); 147} 148 149std::error_code create_directory(const Twine &path, bool IgnoreExisting) { 150 SmallString<128> path_storage; 151 SmallVector<wchar_t, 128> path_utf16; 152 153 if (std::error_code ec = 154 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 155 return ec; 156 157 if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { 158 DWORD LastError = ::GetLastError(); 159 if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) 160 return windows_error(LastError); 161 } 162 163 return std::error_code(); 164} 165 166// We can't use symbolic links for windows. 167std::error_code create_link(const Twine &to, const Twine &from) { 168 // Get arguments. 169 SmallString<128> from_storage; 170 SmallString<128> to_storage; 171 StringRef f = from.toStringRef(from_storage); 172 StringRef t = to.toStringRef(to_storage); 173 174 // Convert to utf-16. 175 SmallVector<wchar_t, 128> wide_from; 176 SmallVector<wchar_t, 128> wide_to; 177 if (std::error_code ec = UTF8ToUTF16(f, wide_from)) 178 return ec; 179 if (std::error_code ec = UTF8ToUTF16(t, wide_to)) 180 return ec; 181 182 if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) 183 return windows_error(::GetLastError()); 184 185 return std::error_code(); 186} 187 188std::error_code remove(const Twine &path, bool IgnoreNonExisting) { 189 SmallString<128> path_storage; 190 SmallVector<wchar_t, 128> path_utf16; 191 192 file_status ST; 193 if (std::error_code EC = status(path, ST)) { 194 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 195 return EC; 196 return std::error_code(); 197 } 198 199 if (std::error_code ec = 200 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 201 return ec; 202 203 if (ST.type() == file_type::directory_file) { 204 if (!::RemoveDirectoryW(c_str(path_utf16))) { 205 std::error_code EC = windows_error(::GetLastError()); 206 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 207 return EC; 208 } 209 return std::error_code(); 210 } 211 if (!::DeleteFileW(c_str(path_utf16))) { 212 std::error_code EC = windows_error(::GetLastError()); 213 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 214 return EC; 215 } 216 return std::error_code(); 217} 218 219std::error_code rename(const Twine &from, const Twine &to) { 220 // Get arguments. 221 SmallString<128> from_storage; 222 SmallString<128> to_storage; 223 StringRef f = from.toStringRef(from_storage); 224 StringRef t = to.toStringRef(to_storage); 225 226 // Convert to utf-16. 227 SmallVector<wchar_t, 128> wide_from; 228 SmallVector<wchar_t, 128> wide_to; 229 if (std::error_code ec = UTF8ToUTF16(f, wide_from)) 230 return ec; 231 if (std::error_code ec = UTF8ToUTF16(t, wide_to)) 232 return ec; 233 234 std::error_code ec = std::error_code(); 235 for (int i = 0; i < 2000; i++) { 236 if (::MoveFileExW(wide_from.begin(), wide_to.begin(), 237 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 238 return std::error_code(); 239 DWORD LastError = ::GetLastError(); 240 if (LastError != ERROR_ACCESS_DENIED) 241 break; 242 // Retry MoveFile() at ACCESS_DENIED. 243 // System scanners (eg. indexer) might open the source file when 244 // It is written and closed. 245 ::Sleep(1); 246 } 247 248 return ec; 249} 250 251std::error_code resize_file(const Twine &path, uint64_t size) { 252 SmallString<128> path_storage; 253 SmallVector<wchar_t, 128> path_utf16; 254 255 if (std::error_code ec = 256 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 257 return ec; 258 259 int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); 260 if (fd == -1) 261 return std::error_code(errno, std::generic_category()); 262#ifdef HAVE__CHSIZE_S 263 errno_t error = ::_chsize_s(fd, size); 264#else 265 errno_t error = ::_chsize(fd, size); 266#endif 267 ::close(fd); 268 return std::error_code(error, std::generic_category()); 269} 270 271std::error_code exists(const Twine &path, bool &result) { 272 SmallString<128> path_storage; 273 SmallVector<wchar_t, 128> path_utf16; 274 275 if (std::error_code ec = 276 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 277 return ec; 278 279 DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); 280 281 if (attributes == INVALID_FILE_ATTRIBUTES) { 282 // See if the file didn't actually exist. 283 DWORD LastError = ::GetLastError(); 284 if (LastError != ERROR_FILE_NOT_FOUND && 285 LastError != ERROR_PATH_NOT_FOUND) 286 return windows_error(LastError); 287 result = false; 288 } else 289 result = true; 290 return std::error_code(); 291} 292 293bool can_write(const Twine &Path) { 294 // FIXME: take security attributes into account. 295 SmallString<128> PathStorage; 296 SmallVector<wchar_t, 128> PathUtf16; 297 298 if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) 299 return false; 300 301 DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); 302 return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); 303} 304 305bool can_execute(const Twine &Path) { 306 SmallString<128> PathStorage; 307 SmallVector<wchar_t, 128> PathUtf16; 308 309 if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) 310 return false; 311 312 DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); 313 return Attr != INVALID_FILE_ATTRIBUTES; 314} 315 316bool equivalent(file_status A, file_status B) { 317 assert(status_known(A) && status_known(B)); 318 return A.FileIndexHigh == B.FileIndexHigh && 319 A.FileIndexLow == B.FileIndexLow && 320 A.FileSizeHigh == B.FileSizeHigh && 321 A.FileSizeLow == B.FileSizeLow && 322 A.LastWriteTimeHigh == B.LastWriteTimeHigh && 323 A.LastWriteTimeLow == B.LastWriteTimeLow && 324 A.VolumeSerialNumber == B.VolumeSerialNumber; 325} 326 327std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { 328 file_status fsA, fsB; 329 if (std::error_code ec = status(A, fsA)) 330 return ec; 331 if (std::error_code ec = status(B, fsB)) 332 return ec; 333 result = equivalent(fsA, fsB); 334 return std::error_code(); 335} 336 337static bool isReservedName(StringRef path) { 338 // This list of reserved names comes from MSDN, at: 339 // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 340 static const char *sReservedNames[] = { "nul", "con", "prn", "aux", 341 "com1", "com2", "com3", "com4", "com5", "com6", 342 "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", 343 "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; 344 345 // First, check to see if this is a device namespace, which always 346 // starts with \\.\, since device namespaces are not legal file paths. 347 if (path.startswith("\\\\.\\")) 348 return true; 349 350 // Then compare against the list of ancient reserved names 351 for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { 352 if (path.equals_lower(sReservedNames[i])) 353 return true; 354 } 355 356 // The path isn't what we consider reserved. 357 return false; 358} 359 360static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { 361 if (FileHandle == INVALID_HANDLE_VALUE) 362 goto handle_status_error; 363 364 switch (::GetFileType(FileHandle)) { 365 default: 366 llvm_unreachable("Don't know anything about this file type"); 367 case FILE_TYPE_UNKNOWN: { 368 DWORD Err = ::GetLastError(); 369 if (Err != NO_ERROR) 370 return windows_error(Err); 371 Result = file_status(file_type::type_unknown); 372 return std::error_code(); 373 } 374 case FILE_TYPE_DISK: 375 break; 376 case FILE_TYPE_CHAR: 377 Result = file_status(file_type::character_file); 378 return std::error_code(); 379 case FILE_TYPE_PIPE: 380 Result = file_status(file_type::fifo_file); 381 return std::error_code(); 382 } 383 384 BY_HANDLE_FILE_INFORMATION Info; 385 if (!::GetFileInformationByHandle(FileHandle, &Info)) 386 goto handle_status_error; 387 388 { 389 file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 390 ? file_type::directory_file 391 : file_type::regular_file; 392 Result = 393 file_status(Type, Info.ftLastWriteTime.dwHighDateTime, 394 Info.ftLastWriteTime.dwLowDateTime, 395 Info.dwVolumeSerialNumber, Info.nFileSizeHigh, 396 Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); 397 return std::error_code(); 398 } 399 400handle_status_error: 401 DWORD LastError = ::GetLastError(); 402 if (LastError == ERROR_FILE_NOT_FOUND || 403 LastError == ERROR_PATH_NOT_FOUND) 404 Result = file_status(file_type::file_not_found); 405 else if (LastError == ERROR_SHARING_VIOLATION) 406 Result = file_status(file_type::type_unknown); 407 else 408 Result = file_status(file_type::status_error); 409 return windows_error(LastError); 410} 411 412std::error_code status(const Twine &path, file_status &result) { 413 SmallString<128> path_storage; 414 SmallVector<wchar_t, 128> path_utf16; 415 416 StringRef path8 = path.toStringRef(path_storage); 417 if (isReservedName(path8)) { 418 result = file_status(file_type::character_file); 419 return std::error_code(); 420 } 421 422 if (std::error_code ec = UTF8ToUTF16(path8, path_utf16)) 423 return ec; 424 425 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 426 if (attr == INVALID_FILE_ATTRIBUTES) 427 return getStatus(INVALID_HANDLE_VALUE, result); 428 429 // Handle reparse points. 430 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { 431 ScopedFileHandle h( 432 ::CreateFileW(path_utf16.begin(), 433 0, // Attributes only. 434 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 435 NULL, 436 OPEN_EXISTING, 437 FILE_FLAG_BACKUP_SEMANTICS, 438 0)); 439 if (!h) 440 return getStatus(INVALID_HANDLE_VALUE, result); 441 } 442 443 ScopedFileHandle h( 444 ::CreateFileW(path_utf16.begin(), 0, // Attributes only. 445 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 446 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); 447 if (!h) 448 return getStatus(INVALID_HANDLE_VALUE, result); 449 450 return getStatus(h, result); 451} 452 453std::error_code status(int FD, file_status &Result) { 454 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 455 return getStatus(FileHandle, Result); 456} 457 458std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 459 ULARGE_INTEGER UI; 460 UI.QuadPart = Time.toWin32Time(); 461 FILETIME FT; 462 FT.dwLowDateTime = UI.LowPart; 463 FT.dwHighDateTime = UI.HighPart; 464 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 465 if (!SetFileTime(FileHandle, NULL, &FT, &FT)) 466 return windows_error(::GetLastError()); 467 return std::error_code(); 468} 469 470std::error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 471 FileDescriptor = FD; 472 // Make sure that the requested size fits within SIZE_T. 473 if (Size > std::numeric_limits<SIZE_T>::max()) { 474 if (FileDescriptor) { 475 if (CloseFD) 476 _close(FileDescriptor); 477 } else 478 ::CloseHandle(FileHandle); 479 return make_error_code(errc::invalid_argument); 480 } 481 482 DWORD flprotect; 483 switch (Mode) { 484 case readonly: flprotect = PAGE_READONLY; break; 485 case readwrite: flprotect = PAGE_READWRITE; break; 486 case priv: flprotect = PAGE_WRITECOPY; break; 487 } 488 489 FileMappingHandle = 490 ::CreateFileMappingW(FileHandle, 0, flprotect, 491 (Offset + Size) >> 32, 492 (Offset + Size) & 0xffffffff, 493 0); 494 if (FileMappingHandle == NULL) { 495 std::error_code ec = windows_error(GetLastError()); 496 if (FileDescriptor) { 497 if (CloseFD) 498 _close(FileDescriptor); 499 } else 500 ::CloseHandle(FileHandle); 501 return ec; 502 } 503 504 DWORD dwDesiredAccess; 505 switch (Mode) { 506 case readonly: dwDesiredAccess = FILE_MAP_READ; break; 507 case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; 508 case priv: dwDesiredAccess = FILE_MAP_COPY; break; 509 } 510 Mapping = ::MapViewOfFile(FileMappingHandle, 511 dwDesiredAccess, 512 Offset >> 32, 513 Offset & 0xffffffff, 514 Size); 515 if (Mapping == NULL) { 516 std::error_code ec = windows_error(GetLastError()); 517 ::CloseHandle(FileMappingHandle); 518 if (FileDescriptor) { 519 if (CloseFD) 520 _close(FileDescriptor); 521 } else 522 ::CloseHandle(FileHandle); 523 return ec; 524 } 525 526 if (Size == 0) { 527 MEMORY_BASIC_INFORMATION mbi; 528 SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); 529 if (Result == 0) { 530 std::error_code ec = windows_error(GetLastError()); 531 ::UnmapViewOfFile(Mapping); 532 ::CloseHandle(FileMappingHandle); 533 if (FileDescriptor) { 534 if (CloseFD) 535 _close(FileDescriptor); 536 } else 537 ::CloseHandle(FileHandle); 538 return ec; 539 } 540 Size = mbi.RegionSize; 541 } 542 543 // Close all the handles except for the view. It will keep the other handles 544 // alive. 545 ::CloseHandle(FileMappingHandle); 546 if (FileDescriptor) { 547 if (CloseFD) 548 _close(FileDescriptor); // Also closes FileHandle. 549 } else 550 ::CloseHandle(FileHandle); 551 return std::error_code(); 552} 553 554mapped_file_region::mapped_file_region(const Twine &path, 555 mapmode mode, 556 uint64_t length, 557 uint64_t offset, 558 std::error_code &ec) 559 : Mode(mode) 560 , Size(length) 561 , Mapping() 562 , FileDescriptor() 563 , FileHandle(INVALID_HANDLE_VALUE) 564 , FileMappingHandle() { 565 SmallString<128> path_storage; 566 SmallVector<wchar_t, 128> path_utf16; 567 568 // Convert path to UTF-16. 569 if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) 570 return; 571 572 // Get file handle for creating a file mapping. 573 FileHandle = ::CreateFileW(c_str(path_utf16), 574 Mode == readonly ? GENERIC_READ 575 : GENERIC_READ | GENERIC_WRITE, 576 Mode == readonly ? FILE_SHARE_READ 577 : 0, 578 0, 579 Mode == readonly ? OPEN_EXISTING 580 : OPEN_ALWAYS, 581 Mode == readonly ? FILE_ATTRIBUTE_READONLY 582 : FILE_ATTRIBUTE_NORMAL, 583 0); 584 if (FileHandle == INVALID_HANDLE_VALUE) { 585 ec = windows_error(::GetLastError()); 586 return; 587 } 588 589 FileDescriptor = 0; 590 ec = init(FileDescriptor, true, offset); 591 if (ec) { 592 Mapping = FileMappingHandle = 0; 593 FileHandle = INVALID_HANDLE_VALUE; 594 FileDescriptor = 0; 595 } 596} 597 598mapped_file_region::mapped_file_region(int fd, 599 bool closefd, 600 mapmode mode, 601 uint64_t length, 602 uint64_t offset, 603 std::error_code &ec) 604 : Mode(mode) 605 , Size(length) 606 , Mapping() 607 , FileDescriptor(fd) 608 , FileHandle(INVALID_HANDLE_VALUE) 609 , FileMappingHandle() { 610 FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); 611 if (FileHandle == INVALID_HANDLE_VALUE) { 612 if (closefd) 613 _close(FileDescriptor); 614 FileDescriptor = 0; 615 ec = make_error_code(errc::bad_file_descriptor); 616 return; 617 } 618 619 ec = init(FileDescriptor, closefd, offset); 620 if (ec) { 621 Mapping = FileMappingHandle = 0; 622 FileHandle = INVALID_HANDLE_VALUE; 623 FileDescriptor = 0; 624 } 625} 626 627mapped_file_region::~mapped_file_region() { 628 if (Mapping) 629 ::UnmapViewOfFile(Mapping); 630} 631 632mapped_file_region::mapped_file_region(mapped_file_region &&other) 633 : Mode(other.Mode) 634 , Size(other.Size) 635 , Mapping(other.Mapping) 636 , FileDescriptor(other.FileDescriptor) 637 , FileHandle(other.FileHandle) 638 , FileMappingHandle(other.FileMappingHandle) { 639 other.Mapping = other.FileMappingHandle = 0; 640 other.FileHandle = INVALID_HANDLE_VALUE; 641 other.FileDescriptor = 0; 642} 643 644mapped_file_region::mapmode mapped_file_region::flags() const { 645 assert(Mapping && "Mapping failed but used anyway!"); 646 return Mode; 647} 648 649uint64_t mapped_file_region::size() const { 650 assert(Mapping && "Mapping failed but used anyway!"); 651 return Size; 652} 653 654char *mapped_file_region::data() const { 655 assert(Mode != readonly && "Cannot get non-const data for readonly mapping!"); 656 assert(Mapping && "Mapping failed but used anyway!"); 657 return reinterpret_cast<char*>(Mapping); 658} 659 660const char *mapped_file_region::const_data() const { 661 assert(Mapping && "Mapping failed but used anyway!"); 662 return reinterpret_cast<const char*>(Mapping); 663} 664 665int mapped_file_region::alignment() { 666 SYSTEM_INFO SysInfo; 667 ::GetSystemInfo(&SysInfo); 668 return SysInfo.dwAllocationGranularity; 669} 670 671std::error_code detail::directory_iterator_construct(detail::DirIterState &it, 672 StringRef path){ 673 SmallVector<wchar_t, 128> path_utf16; 674 675 if (std::error_code ec = UTF8ToUTF16(path, path_utf16)) 676 return ec; 677 678 // Convert path to the format that Windows is happy with. 679 if (path_utf16.size() > 0 && 680 !is_separator(path_utf16[path.size() - 1]) && 681 path_utf16[path.size() - 1] != L':') { 682 path_utf16.push_back(L'\\'); 683 path_utf16.push_back(L'*'); 684 } else { 685 path_utf16.push_back(L'*'); 686 } 687 688 // Get the first directory entry. 689 WIN32_FIND_DATAW FirstFind; 690 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 691 if (!FindHandle) 692 return windows_error(::GetLastError()); 693 694 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 695 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 696 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 697 FirstFind.cFileName[1] == L'.')) 698 if (!::FindNextFileW(FindHandle, &FirstFind)) { 699 DWORD LastError = ::GetLastError(); 700 // Check for end. 701 if (LastError == ERROR_NO_MORE_FILES) 702 return detail::directory_iterator_destruct(it); 703 return windows_error(LastError); 704 } else 705 FilenameLen = ::wcslen(FirstFind.cFileName); 706 707 // Construct the current directory entry. 708 SmallString<128> directory_entry_name_utf8; 709 if (std::error_code ec = 710 UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), 711 directory_entry_name_utf8)) 712 return ec; 713 714 it.IterationHandle = intptr_t(FindHandle.take()); 715 SmallString<128> directory_entry_path(path); 716 path::append(directory_entry_path, directory_entry_name_utf8.str()); 717 it.CurrentEntry = directory_entry(directory_entry_path.str()); 718 719 return std::error_code(); 720} 721 722std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 723 if (it.IterationHandle != 0) 724 // Closes the handle if it's valid. 725 ScopedFindHandle close(HANDLE(it.IterationHandle)); 726 it.IterationHandle = 0; 727 it.CurrentEntry = directory_entry(); 728 return std::error_code(); 729} 730 731std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { 732 WIN32_FIND_DATAW FindData; 733 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 734 DWORD LastError = ::GetLastError(); 735 // Check for end. 736 if (LastError == ERROR_NO_MORE_FILES) 737 return detail::directory_iterator_destruct(it); 738 return windows_error(LastError); 739 } 740 741 size_t FilenameLen = ::wcslen(FindData.cFileName); 742 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 743 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 744 FindData.cFileName[1] == L'.')) 745 return directory_iterator_increment(it); 746 747 SmallString<128> directory_entry_path_utf8; 748 if (std::error_code ec = 749 UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), 750 directory_entry_path_utf8)) 751 return ec; 752 753 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 754 return std::error_code(); 755} 756 757std::error_code openFileForRead(const Twine &Name, int &ResultFD) { 758 SmallString<128> PathStorage; 759 SmallVector<wchar_t, 128> PathUTF16; 760 761 if (std::error_code EC = 762 UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) 763 return EC; 764 765 HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 766 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 767 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 768 if (H == INVALID_HANDLE_VALUE) { 769 DWORD LastError = ::GetLastError(); 770 std::error_code EC = windows_error(LastError); 771 // Provide a better error message when trying to open directories. 772 // This only runs if we failed to open the file, so there is probably 773 // no performances issues. 774 if (LastError != ERROR_ACCESS_DENIED) 775 return EC; 776 if (is_directory(Name)) 777 return make_error_code(errc::is_a_directory); 778 return EC; 779 } 780 781 int FD = ::_open_osfhandle(intptr_t(H), 0); 782 if (FD == -1) { 783 ::CloseHandle(H); 784 return windows_error(ERROR_INVALID_HANDLE); 785 } 786 787 ResultFD = FD; 788 return std::error_code(); 789} 790 791std::error_code openFileForWrite(const Twine &Name, int &ResultFD, 792 sys::fs::OpenFlags Flags, unsigned Mode) { 793 // Verify that we don't have both "append" and "excl". 794 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 795 "Cannot specify both 'excl' and 'append' file creation flags!"); 796 797 SmallString<128> PathStorage; 798 SmallVector<wchar_t, 128> PathUTF16; 799 800 if (std::error_code EC = 801 UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) 802 return EC; 803 804 DWORD CreationDisposition; 805 if (Flags & F_Excl) 806 CreationDisposition = CREATE_NEW; 807 else if (Flags & F_Append) 808 CreationDisposition = OPEN_ALWAYS; 809 else 810 CreationDisposition = CREATE_ALWAYS; 811 812 DWORD Access = GENERIC_WRITE; 813 if (Flags & F_RW) 814 Access |= GENERIC_READ; 815 816 HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, 817 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 818 CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); 819 820 if (H == INVALID_HANDLE_VALUE) { 821 DWORD LastError = ::GetLastError(); 822 std::error_code EC = windows_error(LastError); 823 // Provide a better error message when trying to open directories. 824 // This only runs if we failed to open the file, so there is probably 825 // no performances issues. 826 if (LastError != ERROR_ACCESS_DENIED) 827 return EC; 828 if (is_directory(Name)) 829 return make_error_code(errc::is_a_directory); 830 return EC; 831 } 832 833 int OpenFlags = 0; 834 if (Flags & F_Append) 835 OpenFlags |= _O_APPEND; 836 837 if (Flags & F_Text) 838 OpenFlags |= _O_TEXT; 839 840 int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); 841 if (FD == -1) { 842 ::CloseHandle(H); 843 return windows_error(ERROR_INVALID_HANDLE); 844 } 845 846 ResultFD = FD; 847 return std::error_code(); 848} 849} // end namespace fs 850 851namespace path { 852 853bool home_directory(SmallVectorImpl<char> &result) { 854 wchar_t Path[MAX_PATH]; 855 if (::SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 856 /*SHGFP_TYPE_CURRENT*/0, Path) != S_OK) 857 return false; 858 859 if (UTF16ToUTF8(Path, ::wcslen(Path), result)) 860 return false; 861 862 return true; 863} 864 865} // end namespace path 866 867namespace windows { 868std::error_code UTF8ToUTF16(llvm::StringRef utf8, 869 llvm::SmallVectorImpl<wchar_t> &utf16) { 870 if (!utf8.empty()) { 871 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 872 utf8.size(), utf16.begin(), 0); 873 874 if (len == 0) 875 return windows_error(::GetLastError()); 876 877 utf16.reserve(len + 1); 878 utf16.set_size(len); 879 880 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 881 utf8.size(), utf16.begin(), utf16.size()); 882 883 if (len == 0) 884 return windows_error(::GetLastError()); 885 } 886 887 // Make utf16 null terminated. 888 utf16.push_back(0); 889 utf16.pop_back(); 890 891 return std::error_code(); 892} 893 894std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 895 llvm::SmallVectorImpl<char> &utf8) { 896 if (utf16_len) { 897 // Get length. 898 int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(), 899 0, NULL, NULL); 900 901 if (len == 0) 902 return windows_error(::GetLastError()); 903 904 utf8.reserve(len); 905 utf8.set_size(len); 906 907 // Now do the actual conversion. 908 len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(), 909 utf8.size(), NULL, NULL); 910 911 if (len == 0) 912 return windows_error(::GetLastError()); 913 } 914 915 // Make utf8 null terminated. 916 utf8.push_back(0); 917 utf8.pop_back(); 918 919 return std::error_code(); 920} 921} // end namespace windows 922} // end namespace sys 923} // end namespace llvm 924