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