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