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