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 <shellapi.h> 30#include <shlobj.h> 31 32#undef max 33 34// MinGW doesn't define this. 35#ifndef _ERRNO_T_DEFINED 36#define _ERRNO_T_DEFINED 37typedef int errno_t; 38#endif 39 40#ifdef _MSC_VER 41# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. 42# pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree 43#endif 44 45using namespace llvm; 46 47using llvm::sys::windows::UTF8ToUTF16; 48using llvm::sys::windows::UTF16ToUTF8; 49using llvm::sys::path::widenPath; 50 51static bool is_separator(const wchar_t value) { 52 switch (value) { 53 case L'\\': 54 case L'/': 55 return true; 56 default: 57 return false; 58 } 59} 60 61namespace llvm { 62namespace sys { 63namespace path { 64 65// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the 66// path is longer than CreateDirectory can tolerate, make it absolute and 67// prefixed by '\\?\'. 68std::error_code widenPath(const Twine &Path8, 69 SmallVectorImpl<wchar_t> &Path16) { 70 const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. 71 72 // Several operations would convert Path8 to SmallString; more efficient to 73 // do it once up front. 74 SmallString<128> Path8Str; 75 Path8.toVector(Path8Str); 76 77 // If we made this path absolute, how much longer would it get? 78 size_t CurPathLen; 79 if (llvm::sys::path::is_absolute(Twine(Path8Str))) 80 CurPathLen = 0; // No contribution from current_path needed. 81 else { 82 CurPathLen = ::GetCurrentDirectoryW(0, NULL); 83 if (CurPathLen == 0) 84 return mapWindowsError(::GetLastError()); 85 } 86 87 // Would the absolute path be longer than our limit? 88 if ((Path8Str.size() + CurPathLen) >= MaxDirLen && 89 !Path8Str.startswith("\\\\?\\")) { 90 SmallString<2*MAX_PATH> FullPath("\\\\?\\"); 91 if (CurPathLen) { 92 SmallString<80> CurPath; 93 if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) 94 return EC; 95 FullPath.append(CurPath); 96 } 97 // Traverse the requested path, canonicalizing . and .. (because the \\?\ 98 // prefix is documented to treat them as real components). Ignore 99 // separators, which can be returned from the iterator if the path has a 100 // drive name. We don't need to call native() on the result since append() 101 // always attaches preferred_separator. 102 for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), 103 E = llvm::sys::path::end(Path8Str); 104 I != E; ++I) { 105 if (I->size() == 1 && is_separator((*I)[0])) 106 continue; 107 if (I->size() == 1 && *I == ".") 108 continue; 109 if (I->size() == 2 && *I == "..") 110 llvm::sys::path::remove_filename(FullPath); 111 else 112 llvm::sys::path::append(FullPath, *I); 113 } 114 return UTF8ToUTF16(FullPath, Path16); 115 } 116 117 // Just use the caller's original path. 118 return UTF8ToUTF16(Path8Str, Path16); 119} 120} // end namespace path 121 122namespace fs { 123 124std::string getMainExecutable(const char *argv0, void *MainExecAddr) { 125 SmallVector<wchar_t, MAX_PATH> PathName; 126 DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); 127 128 // A zero return value indicates a failure other than insufficient space. 129 if (Size == 0) 130 return ""; 131 132 // Insufficient space is determined by a return value equal to the size of 133 // the buffer passed in. 134 if (Size == PathName.capacity()) 135 return ""; 136 137 // On success, GetModuleFileNameW returns the number of characters written to 138 // the buffer not including the NULL terminator. 139 PathName.set_size(Size); 140 141 // Convert the result from UTF-16 to UTF-8. 142 SmallVector<char, MAX_PATH> PathNameUTF8; 143 if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) 144 return ""; 145 146 return std::string(PathNameUTF8.data()); 147} 148 149UniqueID file_status::getUniqueID() const { 150 // The file is uniquely identified by the volume serial number along 151 // with the 64-bit file identifier. 152 uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | 153 static_cast<uint64_t>(FileIndexLow); 154 155 return UniqueID(VolumeSerialNumber, FileID); 156} 157 158ErrorOr<space_info> disk_space(const Twine &Path) { 159 ULARGE_INTEGER Avail, Total, Free; 160 if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) 161 return mapWindowsError(::GetLastError()); 162 space_info SpaceInfo; 163 SpaceInfo.capacity = 164 (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart; 165 SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart; 166 SpaceInfo.available = 167 (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart; 168 return SpaceInfo; 169} 170 171TimePoint<> file_status::getLastAccessedTime() const { 172 FILETIME Time; 173 Time.dwLowDateTime = LastAccessedTimeLow; 174 Time.dwHighDateTime = LastAccessedTimeHigh; 175 return toTimePoint(Time); 176} 177 178TimePoint<> file_status::getLastModificationTime() const { 179 FILETIME Time; 180 Time.dwLowDateTime = LastWriteTimeLow; 181 Time.dwHighDateTime = LastWriteTimeHigh; 182 return toTimePoint(Time); 183} 184 185uint32_t file_status::getLinkCount() const { 186 return NumLinks; 187} 188 189std::error_code current_path(SmallVectorImpl<char> &result) { 190 SmallVector<wchar_t, MAX_PATH> cur_path; 191 DWORD len = MAX_PATH; 192 193 do { 194 cur_path.reserve(len); 195 len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); 196 197 // A zero return value indicates a failure other than insufficient space. 198 if (len == 0) 199 return mapWindowsError(::GetLastError()); 200 201 // If there's insufficient space, the len returned is larger than the len 202 // given. 203 } while (len > cur_path.capacity()); 204 205 // On success, GetCurrentDirectoryW returns the number of characters not 206 // including the null-terminator. 207 cur_path.set_size(len); 208 return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); 209} 210 211std::error_code set_current_path(const Twine &path) { 212 // Convert to utf-16. 213 SmallVector<wchar_t, 128> wide_path; 214 if (std::error_code ec = widenPath(path, wide_path)) 215 return ec; 216 217 if (!::SetCurrentDirectoryW(wide_path.begin())) 218 return mapWindowsError(::GetLastError()); 219 220 return std::error_code(); 221} 222 223std::error_code create_directory(const Twine &path, bool IgnoreExisting, 224 perms Perms) { 225 SmallVector<wchar_t, 128> path_utf16; 226 227 if (std::error_code ec = widenPath(path, path_utf16)) 228 return ec; 229 230 if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { 231 DWORD LastError = ::GetLastError(); 232 if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) 233 return mapWindowsError(LastError); 234 } 235 236 return std::error_code(); 237} 238 239// We can't use symbolic links for windows. 240std::error_code create_link(const Twine &to, const Twine &from) { 241 // Convert to utf-16. 242 SmallVector<wchar_t, 128> wide_from; 243 SmallVector<wchar_t, 128> wide_to; 244 if (std::error_code ec = widenPath(from, wide_from)) 245 return ec; 246 if (std::error_code ec = widenPath(to, wide_to)) 247 return ec; 248 249 if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) 250 return mapWindowsError(::GetLastError()); 251 252 return std::error_code(); 253} 254 255std::error_code create_hard_link(const Twine &to, const Twine &from) { 256 return create_link(to, from); 257} 258 259std::error_code remove(const Twine &path, bool IgnoreNonExisting) { 260 SmallVector<wchar_t, 128> path_utf16; 261 262 file_status ST; 263 if (std::error_code EC = status(path, ST)) { 264 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 265 return EC; 266 return std::error_code(); 267 } 268 269 if (std::error_code ec = widenPath(path, path_utf16)) 270 return ec; 271 272 if (ST.type() == file_type::directory_file) { 273 if (!::RemoveDirectoryW(c_str(path_utf16))) { 274 std::error_code EC = mapWindowsError(::GetLastError()); 275 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 276 return EC; 277 } 278 return std::error_code(); 279 } 280 if (!::DeleteFileW(c_str(path_utf16))) { 281 std::error_code EC = mapWindowsError(::GetLastError()); 282 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 283 return EC; 284 } 285 return std::error_code(); 286} 287 288static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, 289 bool &Result) { 290 SmallVector<wchar_t, 128> VolumePath; 291 size_t Len = 128; 292 while (true) { 293 VolumePath.resize(Len); 294 BOOL Success = 295 ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); 296 297 if (Success) 298 break; 299 300 DWORD Err = ::GetLastError(); 301 if (Err != ERROR_INSUFFICIENT_BUFFER) 302 return mapWindowsError(Err); 303 304 Len *= 2; 305 } 306 // If the output buffer has exactly enough space for the path name, but not 307 // the null terminator, it will leave the output unterminated. Push a null 308 // terminator onto the end to ensure that this never happens. 309 VolumePath.push_back(L'\0'); 310 VolumePath.set_size(wcslen(VolumePath.data())); 311 const wchar_t *P = VolumePath.data(); 312 313 UINT Type = ::GetDriveTypeW(P); 314 switch (Type) { 315 case DRIVE_FIXED: 316 Result = true; 317 return std::error_code(); 318 case DRIVE_REMOTE: 319 case DRIVE_CDROM: 320 case DRIVE_RAMDISK: 321 case DRIVE_REMOVABLE: 322 Result = false; 323 return std::error_code(); 324 default: 325 return make_error_code(errc::no_such_file_or_directory); 326 } 327 llvm_unreachable("Unreachable!"); 328} 329 330std::error_code is_local(const Twine &path, bool &result) { 331 if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) 332 return make_error_code(errc::no_such_file_or_directory); 333 334 SmallString<128> Storage; 335 StringRef P = path.toStringRef(Storage); 336 337 // Convert to utf-16. 338 SmallVector<wchar_t, 128> WidePath; 339 if (std::error_code ec = widenPath(P, WidePath)) 340 return ec; 341 return is_local_internal(WidePath, result); 342} 343 344std::error_code is_local(int FD, bool &Result) { 345 SmallVector<wchar_t, 128> FinalPath; 346 HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 347 348 size_t Len = 128; 349 do { 350 FinalPath.reserve(Len); 351 Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), 352 FinalPath.capacity() - 1, VOLUME_NAME_NT); 353 if (Len == 0) 354 return mapWindowsError(::GetLastError()); 355 } while (Len > FinalPath.capacity()); 356 357 FinalPath.set_size(Len); 358 359 return is_local_internal(FinalPath, Result); 360} 361 362std::error_code rename(const Twine &from, const Twine &to) { 363 // Convert to utf-16. 364 SmallVector<wchar_t, 128> wide_from; 365 SmallVector<wchar_t, 128> wide_to; 366 if (std::error_code ec = widenPath(from, wide_from)) 367 return ec; 368 if (std::error_code ec = widenPath(to, wide_to)) 369 return ec; 370 371 std::error_code ec = std::error_code(); 372 373 // Retry while we see recoverable errors. 374 // System scanners (eg. indexer) might open the source file when it is written 375 // and closed. 376 377 bool TryReplace = true; 378 379 for (int i = 0; i < 2000; i++) { 380 if (i > 0) 381 ::Sleep(1); 382 383 if (TryReplace) { 384 // Try ReplaceFile first, as it is able to associate a new data stream 385 // with the destination even if the destination file is currently open. 386 if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) 387 return std::error_code(); 388 389 DWORD ReplaceError = ::GetLastError(); 390 ec = mapWindowsError(ReplaceError); 391 392 // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or 393 // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). 394 if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || 395 ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { 396 TryReplace = false; 397 continue; 398 } 399 // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry 400 // using ReplaceFileW(). 401 if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) 402 continue; 403 // We get ERROR_FILE_NOT_FOUND if the destination file is missing. 404 // MoveFileEx can handle this case. 405 if (ReplaceError != ERROR_ACCESS_DENIED && 406 ReplaceError != ERROR_FILE_NOT_FOUND && 407 ReplaceError != ERROR_SHARING_VIOLATION) 408 break; 409 } 410 411 if (::MoveFileExW(wide_from.begin(), wide_to.begin(), 412 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 413 return std::error_code(); 414 415 DWORD MoveError = ::GetLastError(); 416 ec = mapWindowsError(MoveError); 417 if (MoveError != ERROR_ACCESS_DENIED) break; 418 } 419 420 return ec; 421} 422 423std::error_code resize_file(int FD, uint64_t Size) { 424#ifdef HAVE__CHSIZE_S 425 errno_t error = ::_chsize_s(FD, Size); 426#else 427 errno_t error = ::_chsize(FD, Size); 428#endif 429 return std::error_code(error, std::generic_category()); 430} 431 432std::error_code access(const Twine &Path, AccessMode Mode) { 433 SmallVector<wchar_t, 128> PathUtf16; 434 435 if (std::error_code EC = widenPath(Path, PathUtf16)) 436 return EC; 437 438 DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); 439 440 if (Attributes == INVALID_FILE_ATTRIBUTES) { 441 // See if the file didn't actually exist. 442 DWORD LastError = ::GetLastError(); 443 if (LastError != ERROR_FILE_NOT_FOUND && 444 LastError != ERROR_PATH_NOT_FOUND) 445 return mapWindowsError(LastError); 446 return errc::no_such_file_or_directory; 447 } 448 449 if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) 450 return errc::permission_denied; 451 452 return std::error_code(); 453} 454 455bool can_execute(const Twine &Path) { 456 return !access(Path, AccessMode::Execute) || 457 !access(Path + ".exe", AccessMode::Execute); 458} 459 460bool equivalent(file_status A, file_status B) { 461 assert(status_known(A) && status_known(B)); 462 return A.FileIndexHigh == B.FileIndexHigh && 463 A.FileIndexLow == B.FileIndexLow && 464 A.FileSizeHigh == B.FileSizeHigh && 465 A.FileSizeLow == B.FileSizeLow && 466 A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && 467 A.LastAccessedTimeLow == B.LastAccessedTimeLow && 468 A.LastWriteTimeHigh == B.LastWriteTimeHigh && 469 A.LastWriteTimeLow == B.LastWriteTimeLow && 470 A.VolumeSerialNumber == B.VolumeSerialNumber; 471} 472 473std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { 474 file_status fsA, fsB; 475 if (std::error_code ec = status(A, fsA)) 476 return ec; 477 if (std::error_code ec = status(B, fsB)) 478 return ec; 479 result = equivalent(fsA, fsB); 480 return std::error_code(); 481} 482 483static bool isReservedName(StringRef path) { 484 // This list of reserved names comes from MSDN, at: 485 // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 486 static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", 487 "com1", "com2", "com3", "com4", 488 "com5", "com6", "com7", "com8", 489 "com9", "lpt1", "lpt2", "lpt3", 490 "lpt4", "lpt5", "lpt6", "lpt7", 491 "lpt8", "lpt9" }; 492 493 // First, check to see if this is a device namespace, which always 494 // starts with \\.\, since device namespaces are not legal file paths. 495 if (path.startswith("\\\\.\\")) 496 return true; 497 498 // Then compare against the list of ancient reserved names. 499 for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { 500 if (path.equals_lower(sReservedNames[i])) 501 return true; 502 } 503 504 // The path isn't what we consider reserved. 505 return false; 506} 507 508static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { 509 if (FileHandle == INVALID_HANDLE_VALUE) 510 goto handle_status_error; 511 512 switch (::GetFileType(FileHandle)) { 513 default: 514 llvm_unreachable("Don't know anything about this file type"); 515 case FILE_TYPE_UNKNOWN: { 516 DWORD Err = ::GetLastError(); 517 if (Err != NO_ERROR) 518 return mapWindowsError(Err); 519 Result = file_status(file_type::type_unknown); 520 return std::error_code(); 521 } 522 case FILE_TYPE_DISK: 523 break; 524 case FILE_TYPE_CHAR: 525 Result = file_status(file_type::character_file); 526 return std::error_code(); 527 case FILE_TYPE_PIPE: 528 Result = file_status(file_type::fifo_file); 529 return std::error_code(); 530 } 531 532 BY_HANDLE_FILE_INFORMATION Info; 533 if (!::GetFileInformationByHandle(FileHandle, &Info)) 534 goto handle_status_error; 535 536 { 537 file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 538 ? file_type::directory_file 539 : file_type::regular_file; 540 perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 541 ? (all_read | all_exe) 542 : all_all; 543 Result = file_status( 544 Type, Permissions, Info.nNumberOfLinks, 545 Info.ftLastAccessTime.dwHighDateTime, 546 Info.ftLastAccessTime.dwLowDateTime, 547 Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, 548 Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, 549 Info.nFileIndexHigh, Info.nFileIndexLow); 550 return std::error_code(); 551 } 552 553handle_status_error: 554 DWORD LastError = ::GetLastError(); 555 if (LastError == ERROR_FILE_NOT_FOUND || 556 LastError == ERROR_PATH_NOT_FOUND) 557 Result = file_status(file_type::file_not_found); 558 else if (LastError == ERROR_SHARING_VIOLATION) 559 Result = file_status(file_type::type_unknown); 560 else 561 Result = file_status(file_type::status_error); 562 return mapWindowsError(LastError); 563} 564 565std::error_code status(const Twine &path, file_status &result, bool Follow) { 566 SmallString<128> path_storage; 567 SmallVector<wchar_t, 128> path_utf16; 568 569 StringRef path8 = path.toStringRef(path_storage); 570 if (isReservedName(path8)) { 571 result = file_status(file_type::character_file); 572 return std::error_code(); 573 } 574 575 if (std::error_code ec = widenPath(path8, path_utf16)) 576 return ec; 577 578 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 579 if (attr == INVALID_FILE_ATTRIBUTES) 580 return getStatus(INVALID_HANDLE_VALUE, result); 581 582 DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; 583 // Handle reparse points. 584 if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) 585 Flags |= FILE_FLAG_OPEN_REPARSE_POINT; 586 587 ScopedFileHandle h( 588 ::CreateFileW(path_utf16.begin(), 0, // Attributes only. 589 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 590 NULL, OPEN_EXISTING, Flags, 0)); 591 if (!h) 592 return getStatus(INVALID_HANDLE_VALUE, result); 593 594 return getStatus(h, result); 595} 596 597std::error_code status(int FD, file_status &Result) { 598 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 599 return getStatus(FileHandle, Result); 600} 601 602std::error_code setPermissions(const Twine &Path, perms Permissions) { 603 SmallVector<wchar_t, 128> PathUTF16; 604 if (std::error_code EC = widenPath(Path, PathUTF16)) 605 return EC; 606 607 DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); 608 if (Attributes == INVALID_FILE_ATTRIBUTES) 609 return mapWindowsError(GetLastError()); 610 611 // There are many Windows file attributes that are not to do with the file 612 // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve 613 // them. 614 if (Permissions & all_write) { 615 Attributes &= ~FILE_ATTRIBUTE_READONLY; 616 if (Attributes == 0) 617 // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. 618 Attributes |= FILE_ATTRIBUTE_NORMAL; 619 } 620 else { 621 Attributes |= FILE_ATTRIBUTE_READONLY; 622 // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so 623 // remove it, if it is present. 624 Attributes &= ~FILE_ATTRIBUTE_NORMAL; 625 } 626 627 if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) 628 return mapWindowsError(GetLastError()); 629 630 return std::error_code(); 631} 632 633std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { 634 FILETIME FT = toFILETIME(Time); 635 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 636 if (!SetFileTime(FileHandle, NULL, &FT, &FT)) 637 return mapWindowsError(::GetLastError()); 638 return std::error_code(); 639} 640 641std::error_code mapped_file_region::init(int FD, uint64_t Offset, 642 mapmode Mode) { 643 // Make sure that the requested size fits within SIZE_T. 644 if (Size > std::numeric_limits<SIZE_T>::max()) 645 return make_error_code(errc::invalid_argument); 646 647 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 648 if (FileHandle == INVALID_HANDLE_VALUE) 649 return make_error_code(errc::bad_file_descriptor); 650 651 DWORD flprotect; 652 switch (Mode) { 653 case readonly: flprotect = PAGE_READONLY; break; 654 case readwrite: flprotect = PAGE_READWRITE; break; 655 case priv: flprotect = PAGE_WRITECOPY; break; 656 } 657 658 HANDLE FileMappingHandle = 659 ::CreateFileMappingW(FileHandle, 0, flprotect, 660 (Offset + Size) >> 32, 661 (Offset + Size) & 0xffffffff, 662 0); 663 if (FileMappingHandle == NULL) { 664 std::error_code ec = mapWindowsError(GetLastError()); 665 return ec; 666 } 667 668 DWORD dwDesiredAccess; 669 switch (Mode) { 670 case readonly: dwDesiredAccess = FILE_MAP_READ; break; 671 case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; 672 case priv: dwDesiredAccess = FILE_MAP_COPY; break; 673 } 674 Mapping = ::MapViewOfFile(FileMappingHandle, 675 dwDesiredAccess, 676 Offset >> 32, 677 Offset & 0xffffffff, 678 Size); 679 if (Mapping == NULL) { 680 std::error_code ec = mapWindowsError(GetLastError()); 681 ::CloseHandle(FileMappingHandle); 682 return ec; 683 } 684 685 if (Size == 0) { 686 MEMORY_BASIC_INFORMATION mbi; 687 SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); 688 if (Result == 0) { 689 std::error_code ec = mapWindowsError(GetLastError()); 690 ::UnmapViewOfFile(Mapping); 691 ::CloseHandle(FileMappingHandle); 692 return ec; 693 } 694 Size = mbi.RegionSize; 695 } 696 697 // Close all the handles except for the view. It will keep the other handles 698 // alive. 699 ::CloseHandle(FileMappingHandle); 700 return std::error_code(); 701} 702 703mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, 704 uint64_t offset, std::error_code &ec) 705 : Size(length), Mapping() { 706 ec = init(fd, offset, mode); 707 if (ec) 708 Mapping = 0; 709} 710 711mapped_file_region::~mapped_file_region() { 712 if (Mapping) 713 ::UnmapViewOfFile(Mapping); 714} 715 716size_t mapped_file_region::size() const { 717 assert(Mapping && "Mapping failed but used anyway!"); 718 return Size; 719} 720 721char *mapped_file_region::data() const { 722 assert(Mapping && "Mapping failed but used anyway!"); 723 return reinterpret_cast<char*>(Mapping); 724} 725 726const char *mapped_file_region::const_data() const { 727 assert(Mapping && "Mapping failed but used anyway!"); 728 return reinterpret_cast<const char*>(Mapping); 729} 730 731int mapped_file_region::alignment() { 732 SYSTEM_INFO SysInfo; 733 ::GetSystemInfo(&SysInfo); 734 return SysInfo.dwAllocationGranularity; 735} 736 737std::error_code detail::directory_iterator_construct(detail::DirIterState &it, 738 StringRef path, 739 bool follow_symlinks) { 740 SmallVector<wchar_t, 128> path_utf16; 741 742 if (std::error_code ec = widenPath(path, path_utf16)) 743 return ec; 744 745 // Convert path to the format that Windows is happy with. 746 if (path_utf16.size() > 0 && 747 !is_separator(path_utf16[path.size() - 1]) && 748 path_utf16[path.size() - 1] != L':') { 749 path_utf16.push_back(L'\\'); 750 path_utf16.push_back(L'*'); 751 } else { 752 path_utf16.push_back(L'*'); 753 } 754 755 // Get the first directory entry. 756 WIN32_FIND_DATAW FirstFind; 757 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 758 if (!FindHandle) 759 return mapWindowsError(::GetLastError()); 760 761 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 762 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 763 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 764 FirstFind.cFileName[1] == L'.')) 765 if (!::FindNextFileW(FindHandle, &FirstFind)) { 766 DWORD LastError = ::GetLastError(); 767 // Check for end. 768 if (LastError == ERROR_NO_MORE_FILES) 769 return detail::directory_iterator_destruct(it); 770 return mapWindowsError(LastError); 771 } else 772 FilenameLen = ::wcslen(FirstFind.cFileName); 773 774 // Construct the current directory entry. 775 SmallString<128> directory_entry_name_utf8; 776 if (std::error_code ec = 777 UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), 778 directory_entry_name_utf8)) 779 return ec; 780 781 it.IterationHandle = intptr_t(FindHandle.take()); 782 SmallString<128> directory_entry_path(path); 783 path::append(directory_entry_path, directory_entry_name_utf8); 784 it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks); 785 786 return std::error_code(); 787} 788 789std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 790 if (it.IterationHandle != 0) 791 // Closes the handle if it's valid. 792 ScopedFindHandle close(HANDLE(it.IterationHandle)); 793 it.IterationHandle = 0; 794 it.CurrentEntry = directory_entry(); 795 return std::error_code(); 796} 797 798std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { 799 WIN32_FIND_DATAW FindData; 800 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 801 DWORD LastError = ::GetLastError(); 802 // Check for end. 803 if (LastError == ERROR_NO_MORE_FILES) 804 return detail::directory_iterator_destruct(it); 805 return mapWindowsError(LastError); 806 } 807 808 size_t FilenameLen = ::wcslen(FindData.cFileName); 809 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 810 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 811 FindData.cFileName[1] == L'.')) 812 return directory_iterator_increment(it); 813 814 SmallString<128> directory_entry_path_utf8; 815 if (std::error_code ec = 816 UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), 817 directory_entry_path_utf8)) 818 return ec; 819 820 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 821 return std::error_code(); 822} 823 824static std::error_code realPathFromHandle(HANDLE H, 825 SmallVectorImpl<char> &RealPath) { 826 RealPath.clear(); 827 llvm::SmallVector<wchar_t, MAX_PATH> Buffer; 828 DWORD CountChars = ::GetFinalPathNameByHandleW( 829 H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); 830 if (CountChars > Buffer.capacity()) { 831 // The buffer wasn't big enough, try again. In this case the return value 832 // *does* indicate the size of the null terminator. 833 Buffer.reserve(CountChars); 834 CountChars = ::GetFinalPathNameByHandleW( 835 H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); 836 } 837 if (CountChars == 0) 838 return mapWindowsError(GetLastError()); 839 840 const wchar_t *Data = Buffer.data(); 841 if (CountChars >= 4) { 842 if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { 843 CountChars -= 4; 844 Data += 4; 845 } 846 } 847 848 // Convert the result from UTF-16 to UTF-8. 849 return UTF16ToUTF8(Data, CountChars, RealPath); 850} 851 852static std::error_code directoryRealPath(const Twine &Name, 853 SmallVectorImpl<char> &RealPath) { 854 SmallVector<wchar_t, 128> PathUTF16; 855 856 if (std::error_code EC = widenPath(Name, PathUTF16)) 857 return EC; 858 859 HANDLE H = 860 ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 861 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 862 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 863 if (H == INVALID_HANDLE_VALUE) 864 return mapWindowsError(GetLastError()); 865 std::error_code EC = realPathFromHandle(H, RealPath); 866 ::CloseHandle(H); 867 return EC; 868} 869 870std::error_code openFileForRead(const Twine &Name, int &ResultFD, 871 SmallVectorImpl<char> *RealPath) { 872 SmallVector<wchar_t, 128> PathUTF16; 873 874 if (std::error_code EC = widenPath(Name, PathUTF16)) 875 return EC; 876 877 HANDLE H = 878 ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 879 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 880 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 881 if (H == INVALID_HANDLE_VALUE) { 882 DWORD LastError = ::GetLastError(); 883 std::error_code EC = mapWindowsError(LastError); 884 // Provide a better error message when trying to open directories. 885 // This only runs if we failed to open the file, so there is probably 886 // no performances issues. 887 if (LastError != ERROR_ACCESS_DENIED) 888 return EC; 889 if (is_directory(Name)) 890 return make_error_code(errc::is_a_directory); 891 return EC; 892 } 893 894 int FD = ::_open_osfhandle(intptr_t(H), 0); 895 if (FD == -1) { 896 ::CloseHandle(H); 897 return mapWindowsError(ERROR_INVALID_HANDLE); 898 } 899 900 // Fetch the real name of the file, if the user asked 901 if (RealPath) 902 realPathFromHandle(H, *RealPath); 903 904 ResultFD = FD; 905 return std::error_code(); 906} 907 908std::error_code openFileForWrite(const Twine &Name, int &ResultFD, 909 sys::fs::OpenFlags Flags, unsigned Mode) { 910 // Verify that we don't have both "append" and "excl". 911 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 912 "Cannot specify both 'excl' and 'append' file creation flags!"); 913 914 SmallVector<wchar_t, 128> PathUTF16; 915 916 if (std::error_code EC = widenPath(Name, PathUTF16)) 917 return EC; 918 919 DWORD CreationDisposition; 920 if (Flags & F_Excl) 921 CreationDisposition = CREATE_NEW; 922 else if (Flags & F_Append) 923 CreationDisposition = OPEN_ALWAYS; 924 else 925 CreationDisposition = CREATE_ALWAYS; 926 927 DWORD Access = GENERIC_WRITE; 928 if (Flags & F_RW) 929 Access |= GENERIC_READ; 930 931 HANDLE H = 932 ::CreateFileW(PathUTF16.begin(), Access, 933 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 934 NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); 935 936 if (H == INVALID_HANDLE_VALUE) { 937 DWORD LastError = ::GetLastError(); 938 std::error_code EC = mapWindowsError(LastError); 939 // Provide a better error message when trying to open directories. 940 // This only runs if we failed to open the file, so there is probably 941 // no performances issues. 942 if (LastError != ERROR_ACCESS_DENIED) 943 return EC; 944 if (is_directory(Name)) 945 return make_error_code(errc::is_a_directory); 946 return EC; 947 } 948 949 int OpenFlags = 0; 950 if (Flags & F_Append) 951 OpenFlags |= _O_APPEND; 952 953 if (Flags & F_Text) 954 OpenFlags |= _O_TEXT; 955 956 int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); 957 if (FD == -1) { 958 ::CloseHandle(H); 959 return mapWindowsError(ERROR_INVALID_HANDLE); 960 } 961 962 ResultFD = FD; 963 return std::error_code(); 964} 965 966std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { 967 // Convert to utf-16. 968 SmallVector<wchar_t, 128> Path16; 969 std::error_code EC = widenPath(path, Path16); 970 if (EC && !IgnoreErrors) 971 return EC; 972 973 // SHFileOperation() accepts a list of paths, and so must be double null- 974 // terminated to indicate the end of the list. The buffer is already null 975 // terminated, but since that null character is not considered part of the 976 // vector's size, pushing another one will just consume that byte. So we 977 // need to push 2 null terminators. 978 Path16.push_back(0); 979 Path16.push_back(0); 980 981 SHFILEOPSTRUCTW shfos = {}; 982 shfos.wFunc = FO_DELETE; 983 shfos.pFrom = Path16.data(); 984 shfos.fFlags = FOF_NO_UI; 985 986 int result = ::SHFileOperationW(&shfos); 987 if (result != 0 && !IgnoreErrors) 988 return mapWindowsError(result); 989 return std::error_code(); 990} 991 992static void expandTildeExpr(SmallVectorImpl<char> &Path) { 993 // Path does not begin with a tilde expression. 994 if (Path.empty() || Path[0] != '~') 995 return; 996 997 StringRef PathStr(Path.begin(), Path.size()); 998 PathStr = PathStr.drop_front(); 999 StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); 1000 1001 if (!Expr.empty()) { 1002 // This is probably a ~username/ expression. Don't support this on Windows. 1003 return; 1004 } 1005 1006 SmallString<128> HomeDir; 1007 if (!path::home_directory(HomeDir)) { 1008 // For some reason we couldn't get the home directory. Just exit. 1009 return; 1010 } 1011 1012 // Overwrite the first character and insert the rest. 1013 Path[0] = HomeDir[0]; 1014 Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); 1015} 1016 1017std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, 1018 bool expand_tilde) { 1019 dest.clear(); 1020 if (path.isTriviallyEmpty()) 1021 return std::error_code(); 1022 1023 if (expand_tilde) { 1024 SmallString<128> Storage; 1025 path.toVector(Storage); 1026 expandTildeExpr(Storage); 1027 return real_path(Storage, dest, false); 1028 } 1029 1030 if (is_directory(path)) 1031 return directoryRealPath(path, dest); 1032 1033 int fd; 1034 if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest)) 1035 return EC; 1036 ::close(fd); 1037 return std::error_code(); 1038} 1039 1040} // end namespace fs 1041 1042namespace path { 1043static bool getKnownFolderPath(KNOWNFOLDERID folderId, 1044 SmallVectorImpl<char> &result) { 1045 wchar_t *path = nullptr; 1046 if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) 1047 return false; 1048 1049 bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); 1050 ::CoTaskMemFree(path); 1051 return ok; 1052} 1053 1054bool getUserCacheDir(SmallVectorImpl<char> &Result) { 1055 return getKnownFolderPath(FOLDERID_LocalAppData, Result); 1056} 1057 1058bool home_directory(SmallVectorImpl<char> &result) { 1059 return getKnownFolderPath(FOLDERID_Profile, result); 1060} 1061 1062static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) { 1063 SmallVector<wchar_t, 1024> Buf; 1064 size_t Size = 1024; 1065 do { 1066 Buf.reserve(Size); 1067 Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); 1068 if (Size == 0) 1069 return false; 1070 1071 // Try again with larger buffer. 1072 } while (Size > Buf.capacity()); 1073 Buf.set_size(Size); 1074 1075 return !windows::UTF16ToUTF8(Buf.data(), Size, Res); 1076} 1077 1078static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { 1079 const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; 1080 for (auto *Env : EnvironmentVariables) { 1081 if (getTempDirEnvVar(Env, Res)) 1082 return true; 1083 } 1084 return false; 1085} 1086 1087void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { 1088 (void)ErasedOnReboot; 1089 Result.clear(); 1090 1091 // Check whether the temporary directory is specified by an environment var. 1092 // This matches GetTempPath logic to some degree. GetTempPath is not used 1093 // directly as it cannot handle evn var longer than 130 chars on Windows 7 1094 // (fixed on Windows 8). 1095 if (getTempDirEnvVar(Result)) { 1096 assert(!Result.empty() && "Unexpected empty path"); 1097 native(Result); // Some Unix-like shells use Unix path separator in $TMP. 1098 fs::make_absolute(Result); // Make it absolute if not already. 1099 return; 1100 } 1101 1102 // Fall back to a system default. 1103 const char *DefaultResult = "C:\\Temp"; 1104 Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); 1105} 1106} // end namespace path 1107 1108namespace windows { 1109std::error_code UTF8ToUTF16(llvm::StringRef utf8, 1110 llvm::SmallVectorImpl<wchar_t> &utf16) { 1111 if (!utf8.empty()) { 1112 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 1113 utf8.size(), utf16.begin(), 0); 1114 1115 if (len == 0) 1116 return mapWindowsError(::GetLastError()); 1117 1118 utf16.reserve(len + 1); 1119 utf16.set_size(len); 1120 1121 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 1122 utf8.size(), utf16.begin(), utf16.size()); 1123 1124 if (len == 0) 1125 return mapWindowsError(::GetLastError()); 1126 } 1127 1128 // Make utf16 null terminated. 1129 utf16.push_back(0); 1130 utf16.pop_back(); 1131 1132 return std::error_code(); 1133} 1134 1135static 1136std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, 1137 size_t utf16_len, 1138 llvm::SmallVectorImpl<char> &utf8) { 1139 if (utf16_len) { 1140 // Get length. 1141 int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), 1142 0, NULL, NULL); 1143 1144 if (len == 0) 1145 return mapWindowsError(::GetLastError()); 1146 1147 utf8.reserve(len); 1148 utf8.set_size(len); 1149 1150 // Now do the actual conversion. 1151 len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), 1152 utf8.size(), NULL, NULL); 1153 1154 if (len == 0) 1155 return mapWindowsError(::GetLastError()); 1156 } 1157 1158 // Make utf8 null terminated. 1159 utf8.push_back(0); 1160 utf8.pop_back(); 1161 1162 return std::error_code(); 1163} 1164 1165std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 1166 llvm::SmallVectorImpl<char> &utf8) { 1167 return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); 1168} 1169 1170std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, 1171 llvm::SmallVectorImpl<char> &utf8) { 1172 return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); 1173} 1174 1175} // end namespace windows 1176} // end namespace sys 1177} // end namespace llvm 1178