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