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