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