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 <fcntl.h> 21#include <io.h> 22#include <sys/stat.h> 23#include <sys/types.h> 24 25// These two headers must be included last, and make sure shlobj is required 26// after Windows.h to make sure it picks up our definition of _WIN32_WINNT 27#include "WindowsSupport.h" 28#include <shlobj.h> 29 30#undef max 31 32// MinGW doesn't define this. 33#ifndef _ERRNO_T_DEFINED 34#define _ERRNO_T_DEFINED 35typedef int errno_t; 36#endif 37 38#ifdef _MSC_VER 39# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. 40#endif 41 42using namespace llvm; 43 44using llvm::sys::windows::UTF8ToUTF16; 45using llvm::sys::windows::UTF16ToUTF8; 46 47namespace { 48 error_code TempDir(SmallVectorImpl<wchar_t> &result) { 49 retry_temp_dir: 50 DWORD len = ::GetTempPathW(result.capacity(), result.begin()); 51 52 if (len == 0) 53 return windows_error(::GetLastError()); 54 55 if (len > result.capacity()) { 56 result.reserve(len); 57 goto retry_temp_dir; 58 } 59 60 result.set_size(len); 61 return error_code::success(); 62 } 63 64 bool is_separator(const wchar_t value) { 65 switch (value) { 66 case L'\\': 67 case L'/': 68 return true; 69 default: 70 return false; 71 } 72 } 73} 74 75// FIXME: mode should be used here and default to user r/w only, 76// it currently comes in as a UNIX mode. 77static error_code createUniqueEntity(const Twine &model, int &result_fd, 78 SmallVectorImpl<char> &result_path, 79 bool makeAbsolute, unsigned mode, 80 FSEntity Type) { 81 // Use result_path as temp storage. 82 result_path.set_size(0); 83 StringRef m = model.toStringRef(result_path); 84 85 SmallVector<wchar_t, 128> model_utf16; 86 if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; 87 88 if (makeAbsolute) { 89 // Make model absolute by prepending a temp directory if it's not already. 90 bool absolute = sys::path::is_absolute(m); 91 92 if (!absolute) { 93 SmallVector<wchar_t, 64> temp_dir; 94 if (error_code ec = TempDir(temp_dir)) return ec; 95 // Handle c: by removing it. 96 if (model_utf16.size() > 2 && model_utf16[1] == L':') { 97 model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); 98 } 99 model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); 100 } 101 } 102 103 // Replace '%' with random chars. From here on, DO NOT modify model. It may be 104 // needed if the randomly chosen path already exists. 105 SmallVector<wchar_t, 128> random_path_utf16; 106 107retry_random_path: 108 random_path_utf16.set_size(0); 109 for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), 110 e = model_utf16.end(); 111 i != e; ++i) { 112 if (*i == L'%') { 113 unsigned val = sys::Process::GetRandomNumber(); 114 random_path_utf16.push_back(L"0123456789abcdef"[val & 15]); 115 } 116 else 117 random_path_utf16.push_back(*i); 118 } 119 // Make random_path_utf16 null terminated. 120 random_path_utf16.push_back(0); 121 random_path_utf16.pop_back(); 122 123 HANDLE TempFileHandle = INVALID_HANDLE_VALUE; 124 125 switch (Type) { 126 case FS_File: { 127 // Try to create + open the path. 128 TempFileHandle = 129 ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE, 130 FILE_SHARE_READ, NULL, 131 // Return ERROR_FILE_EXISTS if the file 132 // already exists. 133 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL); 134 if (TempFileHandle == INVALID_HANDLE_VALUE) { 135 // If the file existed, try again, otherwise, error. 136 error_code ec = windows_error(::GetLastError()); 137 if (ec == windows_error::file_exists) 138 goto retry_random_path; 139 140 return ec; 141 } 142 143 // Convert the Windows API file handle into a C-runtime handle. 144 int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); 145 if (fd == -1) { 146 ::CloseHandle(TempFileHandle); 147 ::DeleteFileW(random_path_utf16.begin()); 148 // MSDN doesn't say anything about _open_osfhandle setting errno or 149 // GetLastError(), so just return invalid_handle. 150 return windows_error::invalid_handle; 151 } 152 153 result_fd = fd; 154 break; 155 } 156 157 case FS_Name: { 158 DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin()); 159 if (attributes != INVALID_FILE_ATTRIBUTES) 160 goto retry_random_path; 161 error_code EC = make_error_code(windows_error(::GetLastError())); 162 if (EC != windows_error::file_not_found && 163 EC != windows_error::path_not_found) 164 return EC; 165 break; 166 } 167 168 case FS_Dir: 169 if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) { 170 error_code EC = windows_error(::GetLastError()); 171 if (EC != windows_error::already_exists) 172 return EC; 173 goto retry_random_path; 174 } 175 break; 176 } 177 178 // Set result_path to the utf-8 representation of the path. 179 if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), 180 random_path_utf16.size(), result_path)) { 181 switch (Type) { 182 case FS_File: 183 ::CloseHandle(TempFileHandle); 184 ::DeleteFileW(random_path_utf16.begin()); 185 case FS_Name: 186 break; 187 case FS_Dir: 188 ::RemoveDirectoryW(random_path_utf16.begin()); 189 break; 190 } 191 return ec; 192 } 193 194 return error_code::success(); 195} 196 197namespace llvm { 198namespace sys { 199namespace fs { 200 201std::string getMainExecutable(const char *argv0, void *MainExecAddr) { 202 SmallVector<wchar_t, MAX_PATH> PathName; 203 DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); 204 205 // A zero return value indicates a failure other than insufficient space. 206 if (Size == 0) 207 return ""; 208 209 // Insufficient space is determined by a return value equal to the size of 210 // the buffer passed in. 211 if (Size == PathName.capacity()) 212 return ""; 213 214 // On success, GetModuleFileNameW returns the number of characters written to 215 // the buffer not including the NULL terminator. 216 PathName.set_size(Size); 217 218 // Convert the result from UTF-16 to UTF-8. 219 SmallVector<char, MAX_PATH> PathNameUTF8; 220 if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) 221 return ""; 222 223 return std::string(PathNameUTF8.data()); 224} 225 226UniqueID file_status::getUniqueID() const { 227 // The file is uniquely identified by the volume serial number along 228 // with the 64-bit file identifier. 229 uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | 230 static_cast<uint64_t>(FileIndexLow); 231 232 return UniqueID(VolumeSerialNumber, FileID); 233} 234 235TimeValue file_status::getLastModificationTime() const { 236 ULARGE_INTEGER UI; 237 UI.LowPart = LastWriteTimeLow; 238 UI.HighPart = LastWriteTimeHigh; 239 240 TimeValue Ret; 241 Ret.fromWin32Time(UI.QuadPart); 242 return Ret; 243} 244 245error_code current_path(SmallVectorImpl<char> &result) { 246 SmallVector<wchar_t, MAX_PATH> cur_path; 247 DWORD len = MAX_PATH; 248 249 do { 250 cur_path.reserve(len); 251 len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); 252 253 // A zero return value indicates a failure other than insufficient space. 254 if (len == 0) 255 return windows_error(::GetLastError()); 256 257 // If there's insufficient space, the len returned is larger than the len 258 // given. 259 } while (len > cur_path.capacity()); 260 261 // On success, GetCurrentDirectoryW returns the number of characters not 262 // including the null-terminator. 263 cur_path.set_size(len); 264 return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); 265} 266 267error_code create_directory(const Twine &path, bool &existed) { 268 SmallString<128> path_storage; 269 SmallVector<wchar_t, 128> path_utf16; 270 271 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 272 path_utf16)) 273 return ec; 274 275 if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { 276 error_code ec = windows_error(::GetLastError()); 277 if (ec == windows_error::already_exists) 278 existed = true; 279 else 280 return ec; 281 } else 282 existed = false; 283 284 return error_code::success(); 285} 286 287error_code create_hard_link(const Twine &to, const Twine &from) { 288 // Get arguments. 289 SmallString<128> from_storage; 290 SmallString<128> to_storage; 291 StringRef f = from.toStringRef(from_storage); 292 StringRef t = to.toStringRef(to_storage); 293 294 // Convert to utf-16. 295 SmallVector<wchar_t, 128> wide_from; 296 SmallVector<wchar_t, 128> wide_to; 297 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 298 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 299 300 if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) 301 return windows_error(::GetLastError()); 302 303 return error_code::success(); 304} 305 306error_code remove(const Twine &path, bool &existed) { 307 SmallString<128> path_storage; 308 SmallVector<wchar_t, 128> path_utf16; 309 310 file_status st; 311 error_code EC = status(path, st); 312 if (EC) { 313 if (EC == windows_error::file_not_found || 314 EC == windows_error::path_not_found) { 315 existed = false; 316 return error_code::success(); 317 } 318 return EC; 319 } 320 321 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 322 path_utf16)) 323 return ec; 324 325 if (st.type() == file_type::directory_file) { 326 if (!::RemoveDirectoryW(c_str(path_utf16))) { 327 error_code ec = windows_error(::GetLastError()); 328 if (ec != windows_error::file_not_found) 329 return ec; 330 existed = false; 331 } else 332 existed = true; 333 } else { 334 if (!::DeleteFileW(c_str(path_utf16))) { 335 error_code ec = windows_error(::GetLastError()); 336 if (ec != windows_error::file_not_found) 337 return ec; 338 existed = false; 339 } else 340 existed = true; 341 } 342 343 return error_code::success(); 344} 345 346error_code rename(const Twine &from, const Twine &to) { 347 // Get arguments. 348 SmallString<128> from_storage; 349 SmallString<128> to_storage; 350 StringRef f = from.toStringRef(from_storage); 351 StringRef t = to.toStringRef(to_storage); 352 353 // Convert to utf-16. 354 SmallVector<wchar_t, 128> wide_from; 355 SmallVector<wchar_t, 128> wide_to; 356 if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; 357 if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; 358 359 error_code ec = error_code::success(); 360 for (int i = 0; i < 2000; i++) { 361 if (::MoveFileExW(wide_from.begin(), wide_to.begin(), 362 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 363 return error_code::success(); 364 ec = windows_error(::GetLastError()); 365 if (ec != windows_error::access_denied) 366 break; 367 // Retry MoveFile() at ACCESS_DENIED. 368 // System scanners (eg. indexer) might open the source file when 369 // It is written and closed. 370 ::Sleep(1); 371 } 372 373 return ec; 374} 375 376error_code resize_file(const Twine &path, uint64_t size) { 377 SmallString<128> path_storage; 378 SmallVector<wchar_t, 128> path_utf16; 379 380 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 381 path_utf16)) 382 return ec; 383 384 int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); 385 if (fd == -1) 386 return error_code(errno, generic_category()); 387#ifdef HAVE__CHSIZE_S 388 errno_t error = ::_chsize_s(fd, size); 389#else 390 errno_t error = ::_chsize(fd, size); 391#endif 392 ::close(fd); 393 return error_code(error, generic_category()); 394} 395 396error_code exists(const Twine &path, bool &result) { 397 SmallString<128> path_storage; 398 SmallVector<wchar_t, 128> path_utf16; 399 400 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 401 path_utf16)) 402 return ec; 403 404 DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); 405 406 if (attributes == INVALID_FILE_ATTRIBUTES) { 407 // See if the file didn't actually exist. 408 error_code ec = make_error_code(windows_error(::GetLastError())); 409 if (ec != windows_error::file_not_found && 410 ec != windows_error::path_not_found) 411 return ec; 412 result = false; 413 } else 414 result = true; 415 return error_code::success(); 416} 417 418bool can_write(const Twine &Path) { 419 // FIXME: take security attributes into account. 420 SmallString<128> PathStorage; 421 SmallVector<wchar_t, 128> PathUtf16; 422 423 if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) 424 return false; 425 426 DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); 427 return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); 428} 429 430bool can_execute(const Twine &Path) { 431 SmallString<128> PathStorage; 432 SmallVector<wchar_t, 128> PathUtf16; 433 434 if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) 435 return false; 436 437 DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); 438 return Attr != INVALID_FILE_ATTRIBUTES; 439} 440 441bool equivalent(file_status A, file_status B) { 442 assert(status_known(A) && status_known(B)); 443 return A.FileIndexHigh == B.FileIndexHigh && 444 A.FileIndexLow == B.FileIndexLow && 445 A.FileSizeHigh == B.FileSizeHigh && 446 A.FileSizeLow == B.FileSizeLow && 447 A.LastWriteTimeHigh == B.LastWriteTimeHigh && 448 A.LastWriteTimeLow == B.LastWriteTimeLow && 449 A.VolumeSerialNumber == B.VolumeSerialNumber; 450} 451 452error_code equivalent(const Twine &A, const Twine &B, bool &result) { 453 file_status fsA, fsB; 454 if (error_code ec = status(A, fsA)) return ec; 455 if (error_code ec = status(B, fsB)) return ec; 456 result = equivalent(fsA, fsB); 457 return error_code::success(); 458} 459 460static bool isReservedName(StringRef path) { 461 // This list of reserved names comes from MSDN, at: 462 // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 463 static const char *sReservedNames[] = { "nul", "con", "prn", "aux", 464 "com1", "com2", "com3", "com4", "com5", "com6", 465 "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", 466 "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; 467 468 // First, check to see if this is a device namespace, which always 469 // starts with \\.\, since device namespaces are not legal file paths. 470 if (path.startswith("\\\\.\\")) 471 return true; 472 473 // Then compare against the list of ancient reserved names 474 for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { 475 if (path.equals_lower(sReservedNames[i])) 476 return true; 477 } 478 479 // The path isn't what we consider reserved. 480 return false; 481} 482 483static error_code getStatus(HANDLE FileHandle, file_status &Result) { 484 if (FileHandle == INVALID_HANDLE_VALUE) 485 goto handle_status_error; 486 487 switch (::GetFileType(FileHandle)) { 488 default: 489 llvm_unreachable("Don't know anything about this file type"); 490 case FILE_TYPE_UNKNOWN: { 491 DWORD Err = ::GetLastError(); 492 if (Err != NO_ERROR) 493 return windows_error(Err); 494 Result = file_status(file_type::type_unknown); 495 return error_code::success(); 496 } 497 case FILE_TYPE_DISK: 498 break; 499 case FILE_TYPE_CHAR: 500 Result = file_status(file_type::character_file); 501 return error_code::success(); 502 case FILE_TYPE_PIPE: 503 Result = file_status(file_type::fifo_file); 504 return error_code::success(); 505 } 506 507 BY_HANDLE_FILE_INFORMATION Info; 508 if (!::GetFileInformationByHandle(FileHandle, &Info)) 509 goto handle_status_error; 510 511 { 512 file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 513 ? file_type::directory_file 514 : file_type::regular_file; 515 Result = 516 file_status(Type, Info.ftLastWriteTime.dwHighDateTime, 517 Info.ftLastWriteTime.dwLowDateTime, 518 Info.dwVolumeSerialNumber, Info.nFileSizeHigh, 519 Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); 520 return error_code::success(); 521 } 522 523handle_status_error: 524 error_code EC = windows_error(::GetLastError()); 525 if (EC == windows_error::file_not_found || 526 EC == windows_error::path_not_found) 527 Result = file_status(file_type::file_not_found); 528 else if (EC == windows_error::sharing_violation) 529 Result = file_status(file_type::type_unknown); 530 else 531 Result = file_status(file_type::status_error); 532 return EC; 533} 534 535error_code status(const Twine &path, file_status &result) { 536 SmallString<128> path_storage; 537 SmallVector<wchar_t, 128> path_utf16; 538 539 StringRef path8 = path.toStringRef(path_storage); 540 if (isReservedName(path8)) { 541 result = file_status(file_type::character_file); 542 return error_code::success(); 543 } 544 545 if (error_code ec = UTF8ToUTF16(path8, path_utf16)) 546 return ec; 547 548 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 549 if (attr == INVALID_FILE_ATTRIBUTES) 550 return getStatus(INVALID_HANDLE_VALUE, result); 551 552 // Handle reparse points. 553 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { 554 ScopedFileHandle h( 555 ::CreateFileW(path_utf16.begin(), 556 0, // Attributes only. 557 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 558 NULL, 559 OPEN_EXISTING, 560 FILE_FLAG_BACKUP_SEMANTICS, 561 0)); 562 if (!h) 563 return getStatus(INVALID_HANDLE_VALUE, result); 564 } 565 566 ScopedFileHandle h( 567 ::CreateFileW(path_utf16.begin(), 0, // Attributes only. 568 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 569 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); 570 if (!h) 571 return getStatus(INVALID_HANDLE_VALUE, result); 572 573 return getStatus(h, result); 574} 575 576error_code status(int FD, file_status &Result) { 577 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 578 return getStatus(FileHandle, Result); 579} 580 581error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 582 ULARGE_INTEGER UI; 583 UI.QuadPart = Time.toWin32Time(); 584 FILETIME FT; 585 FT.dwLowDateTime = UI.LowPart; 586 FT.dwHighDateTime = UI.HighPart; 587 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 588 if (!SetFileTime(FileHandle, NULL, &FT, &FT)) 589 return windows_error(::GetLastError()); 590 return error_code::success(); 591} 592 593error_code get_magic(const Twine &path, uint32_t len, 594 SmallVectorImpl<char> &result) { 595 SmallString<128> path_storage; 596 SmallVector<wchar_t, 128> path_utf16; 597 result.set_size(0); 598 599 // Convert path to UTF-16. 600 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), 601 path_utf16)) 602 return ec; 603 604 // Open file. 605 HANDLE file = ::CreateFileW(c_str(path_utf16), 606 GENERIC_READ, 607 FILE_SHARE_READ, 608 NULL, 609 OPEN_EXISTING, 610 FILE_ATTRIBUTE_READONLY, 611 NULL); 612 if (file == INVALID_HANDLE_VALUE) 613 return windows_error(::GetLastError()); 614 615 // Allocate buffer. 616 result.reserve(len); 617 618 // Get magic! 619 DWORD bytes_read = 0; 620 BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); 621 error_code ec = windows_error(::GetLastError()); 622 ::CloseHandle(file); 623 if (!read_success || (bytes_read != len)) { 624 // Set result size to the number of bytes read if it's valid. 625 if (bytes_read <= len) 626 result.set_size(bytes_read); 627 // ERROR_HANDLE_EOF is mapped to errc::value_too_large. 628 return ec; 629 } 630 631 result.set_size(len); 632 return error_code::success(); 633} 634 635error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 636 FileDescriptor = FD; 637 // Make sure that the requested size fits within SIZE_T. 638 if (Size > std::numeric_limits<SIZE_T>::max()) { 639 if (FileDescriptor) { 640 if (CloseFD) 641 _close(FileDescriptor); 642 } else 643 ::CloseHandle(FileHandle); 644 return make_error_code(errc::invalid_argument); 645 } 646 647 DWORD flprotect; 648 switch (Mode) { 649 case readonly: flprotect = PAGE_READONLY; break; 650 case readwrite: flprotect = PAGE_READWRITE; break; 651 case priv: flprotect = PAGE_WRITECOPY; break; 652 } 653 654 FileMappingHandle = 655 ::CreateFileMappingW(FileHandle, 0, flprotect, 656 (Offset + Size) >> 32, 657 (Offset + Size) & 0xffffffff, 658 0); 659 if (FileMappingHandle == NULL) { 660 error_code ec = windows_error(GetLastError()); 661 if (FileDescriptor) { 662 if (CloseFD) 663 _close(FileDescriptor); 664 } else 665 ::CloseHandle(FileHandle); 666 return ec; 667 } 668 669 DWORD dwDesiredAccess; 670 switch (Mode) { 671 case readonly: dwDesiredAccess = FILE_MAP_READ; break; 672 case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; 673 case priv: dwDesiredAccess = FILE_MAP_COPY; break; 674 } 675 Mapping = ::MapViewOfFile(FileMappingHandle, 676 dwDesiredAccess, 677 Offset >> 32, 678 Offset & 0xffffffff, 679 Size); 680 if (Mapping == NULL) { 681 error_code ec = windows_error(GetLastError()); 682 ::CloseHandle(FileMappingHandle); 683 if (FileDescriptor) { 684 if (CloseFD) 685 _close(FileDescriptor); 686 } else 687 ::CloseHandle(FileHandle); 688 return ec; 689 } 690 691 if (Size == 0) { 692 MEMORY_BASIC_INFORMATION mbi; 693 SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); 694 if (Result == 0) { 695 error_code ec = windows_error(GetLastError()); 696 ::UnmapViewOfFile(Mapping); 697 ::CloseHandle(FileMappingHandle); 698 if (FileDescriptor) { 699 if (CloseFD) 700 _close(FileDescriptor); 701 } else 702 ::CloseHandle(FileHandle); 703 return ec; 704 } 705 Size = mbi.RegionSize; 706 } 707 708 // Close all the handles except for the view. It will keep the other handles 709 // alive. 710 ::CloseHandle(FileMappingHandle); 711 if (FileDescriptor) { 712 if (CloseFD) 713 _close(FileDescriptor); // Also closes FileHandle. 714 } else 715 ::CloseHandle(FileHandle); 716 return error_code::success(); 717} 718 719mapped_file_region::mapped_file_region(const Twine &path, 720 mapmode mode, 721 uint64_t length, 722 uint64_t offset, 723 error_code &ec) 724 : Mode(mode) 725 , Size(length) 726 , Mapping() 727 , FileDescriptor() 728 , FileHandle(INVALID_HANDLE_VALUE) 729 , FileMappingHandle() { 730 SmallString<128> path_storage; 731 SmallVector<wchar_t, 128> path_utf16; 732 733 // Convert path to UTF-16. 734 if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) 735 return; 736 737 // Get file handle for creating a file mapping. 738 FileHandle = ::CreateFileW(c_str(path_utf16), 739 Mode == readonly ? GENERIC_READ 740 : GENERIC_READ | GENERIC_WRITE, 741 Mode == readonly ? FILE_SHARE_READ 742 : 0, 743 0, 744 Mode == readonly ? OPEN_EXISTING 745 : OPEN_ALWAYS, 746 Mode == readonly ? FILE_ATTRIBUTE_READONLY 747 : FILE_ATTRIBUTE_NORMAL, 748 0); 749 if (FileHandle == INVALID_HANDLE_VALUE) { 750 ec = windows_error(::GetLastError()); 751 return; 752 } 753 754 FileDescriptor = 0; 755 ec = init(FileDescriptor, true, offset); 756 if (ec) { 757 Mapping = FileMappingHandle = 0; 758 FileHandle = INVALID_HANDLE_VALUE; 759 FileDescriptor = 0; 760 } 761} 762 763mapped_file_region::mapped_file_region(int fd, 764 bool closefd, 765 mapmode mode, 766 uint64_t length, 767 uint64_t offset, 768 error_code &ec) 769 : Mode(mode) 770 , Size(length) 771 , Mapping() 772 , FileDescriptor(fd) 773 , FileHandle(INVALID_HANDLE_VALUE) 774 , FileMappingHandle() { 775 FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); 776 if (FileHandle == INVALID_HANDLE_VALUE) { 777 if (closefd) 778 _close(FileDescriptor); 779 FileDescriptor = 0; 780 ec = make_error_code(errc::bad_file_descriptor); 781 return; 782 } 783 784 ec = init(FileDescriptor, closefd, offset); 785 if (ec) { 786 Mapping = FileMappingHandle = 0; 787 FileHandle = INVALID_HANDLE_VALUE; 788 FileDescriptor = 0; 789 } 790} 791 792mapped_file_region::~mapped_file_region() { 793 if (Mapping) 794 ::UnmapViewOfFile(Mapping); 795} 796 797#if LLVM_HAS_RVALUE_REFERENCES 798mapped_file_region::mapped_file_region(mapped_file_region &&other) 799 : Mode(other.Mode) 800 , Size(other.Size) 801 , Mapping(other.Mapping) 802 , FileDescriptor(other.FileDescriptor) 803 , FileHandle(other.FileHandle) 804 , FileMappingHandle(other.FileMappingHandle) { 805 other.Mapping = other.FileMappingHandle = 0; 806 other.FileHandle = INVALID_HANDLE_VALUE; 807 other.FileDescriptor = 0; 808} 809#endif 810 811mapped_file_region::mapmode mapped_file_region::flags() const { 812 assert(Mapping && "Mapping failed but used anyway!"); 813 return Mode; 814} 815 816uint64_t mapped_file_region::size() const { 817 assert(Mapping && "Mapping failed but used anyway!"); 818 return Size; 819} 820 821char *mapped_file_region::data() const { 822 assert(Mode != readonly && "Cannot get non-const data for readonly mapping!"); 823 assert(Mapping && "Mapping failed but used anyway!"); 824 return reinterpret_cast<char*>(Mapping); 825} 826 827const char *mapped_file_region::const_data() const { 828 assert(Mapping && "Mapping failed but used anyway!"); 829 return reinterpret_cast<const char*>(Mapping); 830} 831 832int mapped_file_region::alignment() { 833 SYSTEM_INFO SysInfo; 834 ::GetSystemInfo(&SysInfo); 835 return SysInfo.dwAllocationGranularity; 836} 837 838error_code detail::directory_iterator_construct(detail::DirIterState &it, 839 StringRef path){ 840 SmallVector<wchar_t, 128> path_utf16; 841 842 if (error_code ec = UTF8ToUTF16(path, 843 path_utf16)) 844 return ec; 845 846 // Convert path to the format that Windows is happy with. 847 if (path_utf16.size() > 0 && 848 !is_separator(path_utf16[path.size() - 1]) && 849 path_utf16[path.size() - 1] != L':') { 850 path_utf16.push_back(L'\\'); 851 path_utf16.push_back(L'*'); 852 } else { 853 path_utf16.push_back(L'*'); 854 } 855 856 // Get the first directory entry. 857 WIN32_FIND_DATAW FirstFind; 858 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 859 if (!FindHandle) 860 return windows_error(::GetLastError()); 861 862 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 863 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 864 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 865 FirstFind.cFileName[1] == L'.')) 866 if (!::FindNextFileW(FindHandle, &FirstFind)) { 867 error_code ec = windows_error(::GetLastError()); 868 // Check for end. 869 if (ec == windows_error::no_more_files) 870 return detail::directory_iterator_destruct(it); 871 return ec; 872 } else 873 FilenameLen = ::wcslen(FirstFind.cFileName); 874 875 // Construct the current directory entry. 876 SmallString<128> directory_entry_name_utf8; 877 if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, 878 ::wcslen(FirstFind.cFileName), 879 directory_entry_name_utf8)) 880 return ec; 881 882 it.IterationHandle = intptr_t(FindHandle.take()); 883 SmallString<128> directory_entry_path(path); 884 path::append(directory_entry_path, directory_entry_name_utf8.str()); 885 it.CurrentEntry = directory_entry(directory_entry_path.str()); 886 887 return error_code::success(); 888} 889 890error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 891 if (it.IterationHandle != 0) 892 // Closes the handle if it's valid. 893 ScopedFindHandle close(HANDLE(it.IterationHandle)); 894 it.IterationHandle = 0; 895 it.CurrentEntry = directory_entry(); 896 return error_code::success(); 897} 898 899error_code detail::directory_iterator_increment(detail::DirIterState &it) { 900 WIN32_FIND_DATAW FindData; 901 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 902 error_code ec = windows_error(::GetLastError()); 903 // Check for end. 904 if (ec == windows_error::no_more_files) 905 return detail::directory_iterator_destruct(it); 906 return ec; 907 } 908 909 size_t FilenameLen = ::wcslen(FindData.cFileName); 910 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 911 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 912 FindData.cFileName[1] == L'.')) 913 return directory_iterator_increment(it); 914 915 SmallString<128> directory_entry_path_utf8; 916 if (error_code ec = UTF16ToUTF8(FindData.cFileName, 917 ::wcslen(FindData.cFileName), 918 directory_entry_path_utf8)) 919 return ec; 920 921 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 922 return error_code::success(); 923} 924 925error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 926 bool map_writable, void *&result) { 927 assert(0 && "NOT IMPLEMENTED"); 928 return windows_error::invalid_function; 929} 930 931error_code unmap_file_pages(void *base, size_t size) { 932 assert(0 && "NOT IMPLEMENTED"); 933 return windows_error::invalid_function; 934} 935 936error_code openFileForRead(const Twine &Name, int &ResultFD) { 937 SmallString<128> PathStorage; 938 SmallVector<wchar_t, 128> PathUTF16; 939 940 if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), 941 PathUTF16)) 942 return EC; 943 944 HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 945 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 946 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 947 if (H == INVALID_HANDLE_VALUE) { 948 error_code EC = windows_error(::GetLastError()); 949 // Provide a better error message when trying to open directories. 950 // This only runs if we failed to open the file, so there is probably 951 // no performances issues. 952 if (EC != windows_error::access_denied) 953 return EC; 954 if (is_directory(Name)) 955 return error_code(errc::is_a_directory, posix_category()); 956 return EC; 957 } 958 959 int FD = ::_open_osfhandle(intptr_t(H), 0); 960 if (FD == -1) { 961 ::CloseHandle(H); 962 return windows_error::invalid_handle; 963 } 964 965 ResultFD = FD; 966 return error_code::success(); 967} 968 969error_code openFileForWrite(const Twine &Name, int &ResultFD, 970 sys::fs::OpenFlags Flags, unsigned Mode) { 971 // Verify that we don't have both "append" and "excl". 972 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 973 "Cannot specify both 'excl' and 'append' file creation flags!"); 974 975 SmallString<128> PathStorage; 976 SmallVector<wchar_t, 128> PathUTF16; 977 978 if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), 979 PathUTF16)) 980 return EC; 981 982 DWORD CreationDisposition; 983 if (Flags & F_Excl) 984 CreationDisposition = CREATE_NEW; 985 else if (Flags & F_Append) 986 CreationDisposition = OPEN_ALWAYS; 987 else 988 CreationDisposition = CREATE_ALWAYS; 989 990 HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE, 991 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 992 CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); 993 994 if (H == INVALID_HANDLE_VALUE) { 995 error_code EC = windows_error(::GetLastError()); 996 // Provide a better error message when trying to open directories. 997 // This only runs if we failed to open the file, so there is probably 998 // no performances issues. 999 if (EC != windows_error::access_denied) 1000 return EC; 1001 if (is_directory(Name)) 1002 return error_code(errc::is_a_directory, posix_category()); 1003 return EC; 1004 } 1005 1006 int OpenFlags = 0; 1007 if (Flags & F_Append) 1008 OpenFlags |= _O_APPEND; 1009 1010 if (!(Flags & F_Binary)) 1011 OpenFlags |= _O_TEXT; 1012 1013 int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); 1014 if (FD == -1) { 1015 ::CloseHandle(H); 1016 return windows_error::invalid_handle; 1017 } 1018 1019 ResultFD = FD; 1020 return error_code::success(); 1021} 1022} // end namespace fs 1023 1024namespace path { 1025 1026bool home_directory(SmallVectorImpl<char> &result) { 1027 wchar_t Path[MAX_PATH]; 1028 if (::SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 1029 /*SHGFP_TYPE_CURRENT*/0, Path) != S_OK) 1030 return false; 1031 1032 if (UTF16ToUTF8(Path, ::wcslen(Path), result)) 1033 return false; 1034 1035 return true; 1036} 1037 1038} // end namespace path 1039 1040namespace windows { 1041llvm::error_code UTF8ToUTF16(llvm::StringRef utf8, 1042 llvm::SmallVectorImpl<wchar_t> &utf16) { 1043 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 1044 utf8.begin(), utf8.size(), 1045 utf16.begin(), 0); 1046 1047 if (len == 0) 1048 return llvm::windows_error(::GetLastError()); 1049 1050 utf16.reserve(len + 1); 1051 utf16.set_size(len); 1052 1053 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, 1054 utf8.begin(), utf8.size(), 1055 utf16.begin(), utf16.size()); 1056 1057 if (len == 0) 1058 return llvm::windows_error(::GetLastError()); 1059 1060 // Make utf16 null terminated. 1061 utf16.push_back(0); 1062 utf16.pop_back(); 1063 1064 return llvm::error_code::success(); 1065} 1066 1067llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 1068 llvm::SmallVectorImpl<char> &utf8) { 1069 // Get length. 1070 int len = ::WideCharToMultiByte(CP_UTF8, 0, 1071 utf16, utf16_len, 1072 utf8.begin(), 0, 1073 NULL, NULL); 1074 1075 if (len == 0) 1076 return llvm::windows_error(::GetLastError()); 1077 1078 utf8.reserve(len); 1079 utf8.set_size(len); 1080 1081 // Now do the actual conversion. 1082 len = ::WideCharToMultiByte(CP_UTF8, 0, 1083 utf16, utf16_len, 1084 utf8.data(), utf8.size(), 1085 NULL, NULL); 1086 1087 if (len == 0) 1088 return llvm::windows_error(::GetLastError()); 1089 1090 // Make utf8 null terminated. 1091 utf8.push_back(0); 1092 utf8.pop_back(); 1093 1094 return llvm::error_code::success(); 1095} 1096} // end namespace windows 1097} // end namespace sys 1098} // end namespace llvm 1099