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